> For the complete documentation index, see [llms.txt](https://wiki.solaxy.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wiki.solaxy.io/using-custom-code/minting-+-burning-spl-tokens.md).

# 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

  <pre class="language-rust" data-overflow="wrap"><code class="lang-rust">pub(crate) async fn create_mint(client: &#x26;TestClient, payer: &#x26;Keypair) -> anyhow::Result&#x3C;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(
          &#x26;payer.pubkey(),
          &#x26;mint_account.pubkey(),
          rent_balance,
          Mint::LEN as u64,
          &#x26;spl_token::id(),
      );

      let initialize_mint = spl_token::instruction::initialize_mint(
          &#x26;spl_token::id(),
          &#x26;mint_account.pubkey(),
          &#x26;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(
          &#x26;[create_mint_account, initialize_mint],
          Some(&#x26;payer.pubkey()),
          &#x26;[payer, &#x26;mint_account],
          latest_blockhash,
      );

      let tx_hash = client
          .svm_send_transaction(&#x26;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(&#x26;mint_acc_info.data)
          .map_err(|e| anyhow!("Failed to unpack mint account data: {e}"))?;

      Ok(mint_account)
  }
  </code></pre>
* Create Associated Token Account

  <pre class="language-rust" data-overflow="wrap"><code class="lang-rust">pub(crate) async fn create_associated_token_account(
      client: &#x26;TestClient,
      payer: &#x26;Keypair,
      target_account_pubkey: &#x26;Pubkey,
      mint_account_pubkey: &#x26;Pubkey,
  ) -> anyhow::Result&#x3C;()> {
      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(
          &#x26;payer.pubkey(),
          target_account_pubkey,
          mint_account_pubkey,
          &#x26;spl_token::id(),
      );

      let create_ata_tx = Transaction::new_signed_with_payer(
          &#x26;[create_ata],
          Some(&#x26;payer.pubkey()),
          &#x26;[&#x26;payer],
          latest_blockhash,
      );

      let tx_hash = client
          .svm_send_transaction(&#x26;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,
          &#x26;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(())
  }
  </code></pre>
* Mint Tokens

  <pre class="language-rust" data-overflow="wrap"><code class="lang-rust">pub(crate) async fn transfer_tokens(
      client: &#x26;TestClient,
      payer: &#x26;Keypair,
      sender: &#x26;Keypair,
      receiver_account_pubkey: &#x26;Pubkey,
      mint_account_pubkey: &#x26;Pubkey,
      amount: u64,
  ) -> anyhow::Result&#x3C;()> {
      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(
          &#x26;sender_key,
          mint_account_pubkey,
          &#x26;spl_token::id(),
      );

      let receiver_ata_pubkey = get_associated_token_address_with_program_id(
          receiver_account_pubkey,
          mint_account_pubkey,
          &#x26;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(&#x26;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(&#x26;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(
          &#x26;spl_token::id(),
          &#x26;sender_ata_pubkey,
          mint_account_pubkey,
          &#x26;receiver_ata_pubkey,
          &#x26;sender_key,
          &#x26;[],
          amount,
          0,
      )
      .map_err(|e| anyhow!("Failed to create transfer checked instruction: {e}"))?;

      let transfer_tx = Transaction::new_signed_with_payer(
          &#x26;[transfer],
          Some(&#x26;payer.pubkey()),
          &#x26;[&#x26;payer, &#x26;sender],
          latest_blockhash,
      );

      let tx_hash = client
          .svm_send_transaction(&#x26;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(&#x26;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(&#x26;receiver_acc_info.data)
          .map_err(|e| anyhow!("Failed to unpack receiver's token account data: {e}"))?;

      Ok(())
  }
  </code></pre>
* Transfer Tokens

  <pre class="language-rust" data-overflow="wrap"><code class="lang-rust">pub(crate) async fn transfer_tokens(
      client: &#x26;TestClient,
      payer: &#x26;Keypair,
      sender: &#x26;Keypair,
      receiver_account_pubkey: &#x26;Pubkey,
      mint_account_pubkey: &#x26;Pubkey,
      amount: u64,
  ) -> anyhow::Result&#x3C;()> {
      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(
          &#x26;sender_key,
          mint_account_pubkey,
          &#x26;spl_token::id(),
      );

      let receiver_ata_pubkey = get_associated_token_address_with_program_id(
          receiver_account_pubkey,
          mint_account_pubkey,
          &#x26;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(&#x26;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(&#x26;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(
          &#x26;spl_token::id(),
          &#x26;sender_ata_pubkey,
          mint_account_pubkey,
          &#x26;receiver_ata_pubkey,
          &#x26;sender_key,
          &#x26;[],
          amount,
          0,
      )
      .map_err(|e| anyhow!("Failed to create transfer checked instruction: {e}"))?;

      let transfer_tx = Transaction::new_signed_with_payer(
          &#x26;[transfer],
          Some(&#x26;payer.pubkey()),
          &#x26;[&#x26;payer, &#x26;sender],
          latest_blockhash,
      );

      let tx_hash = client
          .svm_send_transaction(&#x26;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(&#x26;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(&#x26;receiver_acc_info.data)
          .map_err(|e| anyhow!("Failed to unpack receiver's token account data: {e}"))?;

      Ok(())
  }
  </code></pre>
* Burn Tokens

  <pre class="language-rust" data-overflow="wrap"><code class="lang-rust">pub(crate) async fn burn_tokens(
      client: &#x26;TestClient,
      payer: &#x26;Keypair,
      target_account: &#x26;Keypair,
      mint_account_pubkey: &#x26;Pubkey,
      amount: u64,
  ) -> anyhow::Result&#x3C;()> {
      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(
          &#x26;target_key,
          mint_account_pubkey,
          &#x26;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(&#x26;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(
          &#x26;spl_token::id(),
          &#x26;target_ata_pubkey,
          mint_account_pubkey,
          &#x26;target_key,
          &#x26;[],
          amount,
          0,
      )
      .map_err(|e| anyhow!("Failed to create burn tx: {e}"))?;

      let burn_tx = Transaction::new_signed_with_payer(
          &#x26;[burn],
          Some(&#x26;payer.pubkey()),
          &#x26;[&#x26;payer, &#x26;target_account],
          latest_blockhash,
      );

      let tx_hash = client
          .svm_send_transaction(&#x26;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(&#x26;target_acc_info.data)
          .map_err(|e| anyhow!("Failed to unpack token account data: {e}"))?;

      Ok(())
  }
  </code></pre>
