Minting + Burning SPL Tokens
SPL tokens are Solana’s fungible token standard, and they can be thought of as the equivalent of ERC20s in Ethereum.
Create Mint
pub(crate) async fn create_mint(client: &TestClient, payer: &Keypair) -> anyhow::Result<Keypair> { let mint_account = Keypair::new(); let latest_blockhash = client .svm_get_latest_blockhash() .await .map_err(|e| anyhow!("Failed to retrieve the latest blockhash: {e}"))?; let rent_balance = client .get_minimum_balance_for_rent_exemption(Mint::LEN) .await .map_err(|e| anyhow!("Failed to get a rent exempt balance: {e}"))?; let create_mint_account = solana_sdk::system_instruction::create_account( &payer.pubkey(), &mint_account.pubkey(), rent_balance, Mint::LEN as u64, &spl_token::id(), ); let initialize_mint = spl_token::instruction::initialize_mint( &spl_token::id(), &mint_account.pubkey(), &payer.pubkey(), // mint authority None, 0, ) .map_err(|e| anyhow!("Failed to create initialize mint instruction: {e}"))?; let create_mint_tx = Transaction::new_signed_with_payer( &[create_mint_account, initialize_mint], Some(&payer.pubkey()), &[payer, &mint_account], latest_blockhash, ); let tx_hash = client .svm_send_transaction(&create_mint_tx) .await .map_err(|e| anyhow!("Failed to send a transaction: {e}"))? .to_string(); sleep(Duration::from_secs(SLEEP_DURATION_SECONDS)).await; let mint_acc_info = client .svm_get_account_info(mint_account.pubkey()) .await .map_err(|e| anyhow!("Mint account should exist after transaction: {e}"))?; // Deserialize the mint account data let mint_data = Mint::unpack(&mint_acc_info.data) .map_err(|e| anyhow!("Failed to unpack mint account data: {e}"))?; Ok(mint_account) }
Create Associated Token Account
pub(crate) async fn create_associated_token_account( client: &TestClient, payer: &Keypair, target_account_pubkey: &Pubkey, mint_account_pubkey: &Pubkey, ) -> anyhow::Result<()> { let latest_blockhash = client .svm_get_latest_blockhash() .await .map_err(|e| anyhow!("Failed to retrieve the latest blockhash: {e}"))?; let create_ata = spl_associated_token_account::instruction::create_associated_token_account( &payer.pubkey(), target_account_pubkey, mint_account_pubkey, &spl_token::id(), ); let create_ata_tx = Transaction::new_signed_with_payer( &[create_ata], Some(&payer.pubkey()), &[&payer], latest_blockhash, ); let tx_hash = client .svm_send_transaction(&create_ata_tx) .await .map_err(|e| anyhow!("Failed to send a transaction: {e}"))? .to_string(); sleep(Duration::from_secs(SLEEP_DURATION_SECONDS)).await; let ata_pubkey = get_associated_token_address_with_program_id( target_account_pubkey, mint_account_pubkey, &spl_token::id(), ); let ata_acc_info = client.svm_get_account_info(ata_pubkey).await.map_err(|e| { anyhow!("Failed to retrieve associated token account after transaction: {e}") })?; Ok(()) }
Mint Tokens
pub(crate) async fn transfer_tokens( client: &TestClient, payer: &Keypair, sender: &Keypair, receiver_account_pubkey: &Pubkey, mint_account_pubkey: &Pubkey, amount: u64, ) -> anyhow::Result<()> { let sender_key = sender.pubkey(); let latest_blockhash = client .svm_get_latest_blockhash() .await .map_err(|e| anyhow!("Failed to retrieve the latest blockhash: {e}"))?; let sender_ata_pubkey = get_associated_token_address_with_program_id( &sender_key, mint_account_pubkey, &spl_token::id(), ); let receiver_ata_pubkey = get_associated_token_address_with_program_id( receiver_account_pubkey, mint_account_pubkey, &spl_token::id(), ); let sender_ata_acc_info = client .svm_get_account_info(sender_ata_pubkey) .await .map_err(|e| anyhow!("Failed to retrieve account {sender_ata_pubkey}: {e}"))?; let sender_token_account_data = TokenAccount::unpack(&sender_ata_acc_info.data) .map_err(|e| anyhow!("Failed to unpack sender's token account data: {e}"))?; let receiver_ata_acc_info = client .svm_get_account_info(receiver_ata_pubkey) .await .map_err(|e| anyhow!("failed to retrieve account {receiver_ata_pubkey}: {e}"))?; let receiver_token_account_data = TokenAccount::unpack(&receiver_ata_acc_info.data) .map_err(|e| anyhow!("Failed to unpack receiver's token account data: {e}"))?; // Get initial balances for tests let initial_sender_tokens = sender_token_account_data.amount; let initial_receiver_tokens = receiver_token_account_data.amount; let transfer = spl_token::instruction::transfer_checked( &spl_token::id(), &sender_ata_pubkey, mint_account_pubkey, &receiver_ata_pubkey, &sender_key, &[], amount, 0, ) .map_err(|e| anyhow!("Failed to create transfer checked instruction: {e}"))?; let transfer_tx = Transaction::new_signed_with_payer( &[transfer], Some(&payer.pubkey()), &[&payer, &sender], latest_blockhash, ); let tx_hash = client .svm_send_transaction(&transfer_tx) .await .map_err(|e| anyhow!("Failed to send a transaction: {e}"))? .to_string(); sleep(Duration::from_secs(SLEEP_DURATION_SECONDS)).await; let sender_acc_info = client .svm_get_account_info(sender_ata_pubkey) .await .map_err(|e| anyhow!("Failed to retrieve account {sender_ata_pubkey}: {e}"))?; let sender_token_account_data = TokenAccount::unpack(&sender_acc_info.data) .map_err(|e| anyhow!("Failed to unpack sender's token account data: {e}"))?; let receiver_acc_info = client .svm_get_account_info(receiver_ata_pubkey) .await .map_err(|e| anyhow!("Failed to retrieve account {receiver_ata_pubkey}: {e}"))?; let receiver_token_account_data = TokenAccount::unpack(&receiver_acc_info.data) .map_err(|e| anyhow!("Failed to unpack receiver's token account data: {e}"))?; Ok(()) }
Transfer Tokens
pub(crate) async fn transfer_tokens( client: &TestClient, payer: &Keypair, sender: &Keypair, receiver_account_pubkey: &Pubkey, mint_account_pubkey: &Pubkey, amount: u64, ) -> anyhow::Result<()> { let sender_key = sender.pubkey(); let latest_blockhash = client .svm_get_latest_blockhash() .await .map_err(|e| anyhow!("Failed to retrieve the latest blockhash: {e}"))?; let sender_ata_pubkey = get_associated_token_address_with_program_id( &sender_key, mint_account_pubkey, &spl_token::id(), ); let receiver_ata_pubkey = get_associated_token_address_with_program_id( receiver_account_pubkey, mint_account_pubkey, &spl_token::id(), ); let sender_ata_acc_info = client .svm_get_account_info(sender_ata_pubkey) .await .map_err(|e| anyhow!("Failed to retrieve account {sender_ata_pubkey}: {e}"))?; let sender_token_account_data = TokenAccount::unpack(&sender_ata_acc_info.data) .map_err(|e| anyhow!("Failed to unpack sender's token account data: {e}"))?; debug!("Sender's token account data:: {sender_token_account_data:?}"); let receiver_ata_acc_info = client .svm_get_account_info(receiver_ata_pubkey) .await .map_err(|e| anyhow!("failed to retrieve account {receiver_ata_pubkey}: {e}"))?; let receiver_token_account_data = TokenAccount::unpack(&receiver_ata_acc_info.data) .map_err(|e| anyhow!("Failed to unpack receiver's token account data: {e}"))?; debug!("Receiver's token account data: {receiver_token_account_data:?}"); // Get initial balances for tests let initial_sender_tokens = sender_token_account_data.amount; let initial_receiver_tokens = receiver_token_account_data.amount; let transfer = spl_token::instruction::transfer_checked( &spl_token::id(), &sender_ata_pubkey, mint_account_pubkey, &receiver_ata_pubkey, &sender_key, &[], amount, 0, ) .map_err(|e| anyhow!("Failed to create transfer checked instruction: {e}"))?; let transfer_tx = Transaction::new_signed_with_payer( &[transfer], Some(&payer.pubkey()), &[&payer, &sender], latest_blockhash, ); let tx_hash = client .svm_send_transaction(&transfer_tx) .await .map_err(|e| anyhow!("Failed to send a transaction: {e}"))? .to_string(); sleep(Duration::from_secs(SLEEP_DURATION_SECONDS)).await; let sender_acc_info = client .svm_get_account_info(sender_ata_pubkey) .await .map_err(|e| anyhow!("Failed to retrieve account {sender_ata_pubkey}: {e}"))?; let sender_token_account_data = TokenAccount::unpack(&sender_acc_info.data) .map_err(|e| anyhow!("Failed to unpack sender's token account data: {e}"))?; let receiver_acc_info = client .svm_get_account_info(receiver_ata_pubkey) .await .map_err(|e| anyhow!("Failed to retrieve account {receiver_ata_pubkey}: {e}"))?; let receiver_token_account_data = TokenAccount::unpack(&receiver_acc_info.data) .map_err(|e| anyhow!("Failed to unpack receiver's token account data: {e}"))?; Ok(()) }
Burn Tokens
pub(crate) async fn burn_tokens( client: &TestClient, payer: &Keypair, target_account: &Keypair, mint_account_pubkey: &Pubkey, amount: u64, ) -> anyhow::Result<()> { let target_key = target_account.pubkey(); let latest_blockhash = client .svm_get_latest_blockhash() .await .map_err(|e| anyhow!("Failed to retrieve the latest blockhash: {e}"))?; let target_ata_pubkey = get_associated_token_address_with_program_id( &target_key, mint_account_pubkey, &spl_token::id(), ); let target_acc_info = client .svm_get_account_info(target_ata_pubkey) .await .map_err(|e| anyhow!("failed to retrieve account {target_ata_pubkey}: {e}"))?; let target_token_account_data = TokenAccount::unpack(&target_acc_info.data) .map_err(|e| anyhow!("Failed to unpack token account data: {e}"))?; debug!("Target's token account data:: {target_token_account_data:?}"); let initial_target_tokens = target_token_account_data.amount; let burn = spl_token::instruction::burn_checked( &spl_token::id(), &target_ata_pubkey, mint_account_pubkey, &target_key, &[], amount, 0, ) .map_err(|e| anyhow!("Failed to create burn tx: {e}"))?; let burn_tx = Transaction::new_signed_with_payer( &[burn], Some(&payer.pubkey()), &[&payer, &target_account], latest_blockhash, ); let tx_hash = client .svm_send_transaction(&burn_tx) .await .map_err(|e| anyhow!("Failed to send a transaction: {e}"))? .to_string(); sleep(Duration::from_secs(SLEEP_DURATION_SECONDS)).await; let target_acc_info = client .svm_get_account_info(target_ata_pubkey) .await .map_err(|e| anyhow!("failed to retrieve account {target_ata_pubkey}: {e}"))?; let target_token_account_data = TokenAccount::unpack(&target_acc_info.data) .map_err(|e| anyhow!("Failed to unpack token account data: {e}"))?; Ok(()) }
Last updated
Was this helpful?