> 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>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wiki.solaxy.io/using-custom-code/minting-+-burning-spl-tokens.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
