Importing Accounts
You can import state from anywhere including mainnet
Import State Directly from Mainnet
Use this endpoint to load account state directly from mainnet with only the account addresses.
Coming Soon: You will be able to upload a token mint, and update it's mint authority to whatever account you like, being able to mint from that account at will
import * as dotenv from 'dotenv';
dotenv.config();
interface RequestBody {
accounts: string[];
}
async function setMainnetAccountState(blockchainID: string, accounts: string[]): Promise<void> {
const mirrorApiKey = process.env.MIRROR_API_KEY;
if (!mirrorApiKey) {
throw new Error('MIRROR_API_KEY is not defined in the environment variables');
}
const requestBody: RequestBody = {
accounts: accounts,
};
try {
const response = await fetch(`https://api.mirror.ad/blockchains/${blockchainID}/accounts/mainnet`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'api_key': mirrorApiKey,
},
body: JSON.stringify(requestBody),
});
if (response.status !== 200) {
throw new Error(`Error getting RPC URL: ${response.status}`);
}
} catch (error) {
throw new Error(`Request failed: ${error.message}`);
}
}
use reqwest::blocking::Client;
use reqwest::header::HeaderMap;
use serde::Serialize;
use std::env;
use uuid::Uuid;
#[derive(Serialize)]
struct RequestBody {
accounts: Vec<String>,
}
fn set_mainnet_account_state(blockchain_id: Uuid, accounts: Vec<String>) -> Result<(), Box<dyn std::error::Error>> {
dotenv::dotenv().ok();
let mirror_api_key = env::var("MIRROR_API_KEY")?;
let request_body = RequestBody { accounts };
let json_data = serde_json::to_string(&request_body)?;
let client = Client::new();
let mut headers = HeaderMap::new();
headers.insert("api_key", mirror_api_key.parse()?);
let resp = client
.post(&format!("https://api.mirror.ad/blockchains/{:?}/accounts/mainnet", blockchain_id))
.headers(headers)
.body(json_data)
.send()?;
if resp.status() != 200 {
return Err(format!("error getting RPC URL: {}", resp.status()).into());
}
Ok(())
}
func SetMainnetAccountState(blockchainID uuid.UUID, accounts []string) error {
godotenv.Load()
mirrorApiKey := os.Getenv("MIRROR_API_KEY")
type RequestBody struct {
Accounts []string `json:"accounts"`
}
requestBody := RequestBody{
Accounts: accounts,
}
jsonData, err := json.Marshal(requestBody)
if err != nil {
return err
}
req, err := http.NewRequest("POST", fmt.Sprintf("https://api.mirror.ad/blockchains/%s/accounts/mainnet", blockchainID), bytes.NewBuffer(jsonData))
if err != nil {
return err
}
req.Header.Set("api_key", mirrorApiKey)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return fmt.Errorf("error getting RPC URL: %s", resp.Status)
}
return nil
}
Directly Import State
You can also upload state directly.
For use cases where you have a subset of PDAs from say Jupiter, you can upload these direclty to your chain. We are working on providing environments with these PDAs pre-loaded, so if that would benefit you, please reach out and let us know!
interface SolanaAccount {
address: string;
lamports: number;
data: Uint8Array;
owner: string;
executable: boolean;
rentEpoch: number;
}
interface SetBlockchainRequest {
address: string;
lamports: number;
data: string;
owner: string;
rentEpoch: number;
label?: string;
executable: boolean;
}
async function setAccounts(blockchainID: string, accounts: SolanaAccount[], label?: string): Promise<void> {
const reqBody: SetBlockchainRequest[] = accounts.map(account => ({
address: account.address,
lamports: account.lamports,
data: btoa(String.fromCharCode(...account.data)),
owner: account.owner,
rentEpoch: account.rentEpoch,
label: label,
executable: account.executable,
}));
const reqBytes = JSON.stringify(reqBody);
try {
const response = await fetch(`https://engine.mirror.ad/accounts/${blockchainID}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: reqBytes,
});
if (response.status !== 200) {
const body = await response.text();
console.error('error response', response.status, body);
throw new Error('HTTP request failed');
}
} catch (error) {
console.error('error sending request', error);
throw new Error('HTTP request failed');
}
}
use reqwest::blocking::Client;
use reqwest::header::HeaderMap;
use serde::{Serialize, Deserialize};
use std::env;
use uuid::Uuid;
use base64;
use std::error::Error;
#[derive(Serialize, Deserialize)]
struct SolanaAccount {
address: String,
lamports: u64,
data: Vec<u8>,
owner: String,
executable: bool,
rent_epoch: u64,
}
#[derive(Serialize)]
struct SetBlockchainRequest {
address: String,
lamports: u64,
data: String,
owner: String,
rent_epoch: u64,
label: Option<String>,
executable: bool,
}
fn set_accounts(blockchain_id: Uuid, accounts: Vec<SolanaAccount>, label: Option<String>) -> Result<(), Box<dyn Error>> {
dotenv::dotenv().ok();
let mirror_api_key = env::var("MIRROR_API_KEY")?;
let mut req_body: Vec<SetBlockchainRequest> = Vec::new();
for account in accounts {
let encoded_data = base64::encode(&account.data);
req_body.push(SetBlockchainRequest {
address: account.address,
lamports: account.lamports,
data: encoded_data,
owner: account.owner,
rent_epoch: account.rent_epoch,
label: label.clone(),
executable: account.executable,
});
}
let json_data = serde_json::to_string(&req_body)?;
let client = Client::new();
let mut headers = HeaderMap::new();
headers.insert("Content-Type", "application/json".parse()?);
headers.insert("Accept", "application/json".parse()?);
headers.insert("api_key", mirror_api_key.parse()?);
let resp = client
.put(&format!("https://engine.mirror.ad/accounts/{}", blockchain_id))
.headers(headers)
.body(json_data)
.send()?;
if resp.status() != 200 {
return Err(format!("error response: {}", resp.status()).into());
}
Ok(())
}
type SolanaAccount struct {
Address string `json:"address"`
Lamports uint `json:"lamports"`
Data []byte `json:"data"`
Owner string `json:"owner"`
Executable bool `json:"executable"`
RentEpoch uint `json:"rentEpoch"`
}
SetAccounts(ctx context.Context, blockchainID uuid.UUID, accounts []SolanaAccount, label *string) error {
var reqBody []setBlockchainRequest
for _, account := range accounts {
encodedData := base64.StdEncoding.EncodeToString([]byte(account.Data))
reqBody = append(reqBody, setBlockchainRequest{
Address: account.Address,
Lamports: account.Lamports,
Data: encodedData,
Owner: account.Owner,
RentEpoch: account.RentEpoch,
Label: label,
Executable: account.Executable,
})
}
reqBytes, err := json.Marshal(reqBody)
if err != nil {
log.Println("error marshalling request", err)
return pkg.ErrHttpRequest
}
r, err := http.NewRequest(http.MethodPut, fmt.Sprintf("https://engine.mirror.ad/accounts/%s",blockchainID.String()), bytes.NewReader(reqBytes))
if err != nil {
log.Println("error creating request", err)
return pkg.ErrHttpRequest
}
r.Header.Set("Content-Type", "application/json")
r.Header.Set("Accept", "application/json")
client := &http.Client{}
resp, err := client.Do(r)
if err != nil {
log.Println("error sending request", err)
return pkg.ErrHttpRequest
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Println("error response", resp.StatusCode)
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Println("error reading response body", err)
return pkg.ErrHttpRequest
}
log.Println("error unmarshalling error", err, string(body))
return pkg.ErrHttpRequest
}
return nil
}
Last updated