Token Program | Solana Program Library Docs (2024)

A Token program on the Solana blockchain.

This program defines a common implementation for Fungible and Non Fungible tokens.

Background

Solana's programming model and the definitions of the Solana terms used in thisdocument are available at:

  • https://docs.solana.com/apps
  • https://docs.solana.com/terminology

Source

The Token Program's source is available onGitHub

Interface

The Token Program is written in Rust and available on crates.io and docs.rs.

Auto-generated C bindings are also availablehere

JavaScriptbindingsare available that support loading the Token Program on to a chain and issueinstructions.

See the SPL Associated Token Account program forconvention around wallet address to token account mapping and funding.

Status

The SPL Token program is considered complete, and there are no plans to add newfunctionality. There may be changes to fix important or breaking bugs.

Reference Guide

Setup

  • CLI
  • JS

The spl-token command-line utility can be used to experiment with SPLtokens. Once you have Rust installed, run:

$ cargo install spl-token-cli

Run spl-token --help for a full description of available commands.

Configuration

The spl-token configuration is shared with the solana command-line tool.

Current Configuration

$ solana config get
Config File: ${HOME}/.config/solana/cli/config.yml
RPC URL: https://api.mainnet-beta.solana.com
WebSocket URL: wss://api.mainnet-beta.solana.com/ (computed)
Keypair Path: ${HOME}/.config/solana/id.json

Cluster RPC URL

See Solana clusters for cluster-specific RPC URLs

$ solana config set --url https://api.devnet.solana.com

Default Keypair

See Keypair conventionsfor information on how to setup a keypair if you don't already have one.

Keypair File

$ solana config set --keypair ${HOME}/new-keypair.json

Hardware Wallet URL (See URL spec)

$ solana config set --keypair usb://ledger/

Airdrop SOL

Creating tokens and accounts requires SOL for account rent deposits andtransaction fees. If the cluster you are targeting offers a faucet, you can geta little SOL for testing:

  • CLI
  • JS
$ solana airdrop 1

Example: Creating your own fungible token

  • CLI
  • JS
$ spl-token create-token
Creating token AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
Signature: 47hsLFxWRCg8azaZZPSnQR8DNTRsGyPNf*ck7jqyzgt7wf9eag3nSnewqoZrVZHKm8zt3B6gzxhr91gdQ5qYrsRG4

The unique identifier of the token is AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM.

Tokens when initially created by spl-token have no supply:

  • CLI
  • JS
$ spl-token supply AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
0

Let's mint some. First create an account to hold a balance of the newAQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM token:

  • CLI
  • JS
$ spl-token create-account AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
Creating account 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
Signature: 42Sa5eK9dMEQyvD9GMHuKxXf55WLZ7tfjabUKDhNoZRAxj9MsnN7omriWMEHXLea3aYpjZ862qocRLVikvkHkyfy

7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi is now an empty account:

  • CLI
  • JS
$ spl-token balance AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
0

Mint 100 tokens into the account:

  • CLI
  • JS
$ spl-token mint AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 100
Minting 100 tokens
Token: AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
Recipient: 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
Signature: 41mARH42fPkbYn1mvQ6hYLjmJtjW98NXwd6pHqEYg9p8RnuoUsMxVd16RkStDHEzcS2sfpSEpFscrJQn3HkHzLaa

The token supply and account balance now reflect the result of minting:

  • CLI
  • JS
$ spl-token supply AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
100
$ spl-token balance AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
100

Example: View all Tokens that you own

  • CLI
  • JS
$ spl-token accounts
Token Balance
------------------------------------------------------------
7e2X5oeAAJyUTi4PfSGXFLGhyPw2H8oELm1mx87ZCgwF 84
AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 100
AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 0 (Aux-1*)
AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 1 (Aux-2*)

Example: Wrapping SOL in a Token

When you want to wrap SOL, you can send SOL to an associated token accounton the native mint and call syncNative. syncNative updates the amountfield on the token account to match the amount of wrapped SOL available.That SOL is only retrievable by closing the token account and choosingthe desired address to send the token account's lamports.

  • CLI
  • JS
$ spl-token wrap 1
Wrapping 1 SOL into GJTxcnA5Sydy8YRhqvHxbQ5QNsPyRKvzguodQEaShJje
Signature: 4f4s5QVMKisLS6ihZcXXPbiBAzjnvkBcp2A7KKER7k9DwJ4qjbVsQBKv2rAyBumXC1gLn8EJQhwWkybE4yJGnw2Y

To unwrap the Token back to SOL:

  • CLI
  • JS
$ spl-token unwrap GJTxcnA5Sydy8YRhqvHxbQ5QNsPyRKvzguodQEaShJje
Unwrapping GJTxcnA5Sydy8YRhqvHxbQ5QNsPyRKvzguodQEaShJje
Amount: 1 SOL
Recipient: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
Signature: f7opZ86ZHKGvkJBQsJ8Pk81v8F3v1VUfyd4kFs4CABmfTnSZK5BffETznUU3tEWvzibgKJASCf7TUpDmwGi8Rmh

Example: Transferring tokens to another user

First the receiver uses spl-token create-account to create their associatedtoken account for the Token type. Then the receiver obtains their walletaddress by running solana address and provides it to the sender.

The sender then runs:

  • CLI
  • JS
$ spl-token transfer AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 50 vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
Transfer 50 tokens
Sender: 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
Recipient: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
Recipient associated token account: F59618aQB8r6asXeMcB9jWuY6NEx1VduT9yFo1GTi1ks

Signature: 5a3qbvoJQnTAxGPHCugibZTbSu7xuTgkxvF4EJupRjRXGgZZrnWFmKzfEzcqKF2ogCaF4QKVbAtuFx7xGwrDUcGd

Example: Transferring tokens to another user, with sender-funding

If the receiver does not yet have an associated token account, the sender maychoose to fund the receiver's account.

The receiver obtains their wallet address by running solana address and provides it to the sender.

The sender then runs to fund the receiver's associated token account, at thesender's expense, and then transfers 50 tokens into it:

  • CLI
  • JS
$ spl-token transfer --fund-recipient AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 50 vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
Transfer 50 tokens
Sender: 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
Recipient: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
Recipient associated token account: F59618aQB8r6asXeMcB9jWuY6NEx1VduT9yFo1GTi1ks
Funding recipient: F59618aQB8r6asXeMcB9jWuY6NEx1VduT9yFo1GTi1ks (0.00203928 SOL)

Signature: 5a3qbvoJQnTAxGPHCugibZTbSu7xuTgkxvF4EJupRjRXGgZZrnWFmKzfEzcqKF2ogCaF4QKVbAtuFx7xGwrDUcGd

Example: Transferring tokens to an explicit recipient token account

Tokens may be transferred to a specific recipient token account. The recipienttoken account must already exist and be of the same Token type.

  • CLI
  • JS
$ spl-token create-account AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM /path/to/auxiliary_keypair.json
Creating account CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ
Signature: 4yPWj22mbyLu5mhfZ5WATNfYzTt5EQ7LGzryxM7Ufu7QCVjTE7czZdEBqdKR7vjKsfAqsBdjU58NJvXrTqCXvfWW
$ spl-token accounts AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM -v
Account Token Balance
--------------------------------------------------------------------------------------------------------
7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 100
CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 0 (Aux-1*)
$ spl-token transfer AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 50 CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ
Transfer 50 tokens
Sender: 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
Recipient: CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ

Signature: 5a3qbvoJQnTAxGPHCugibZTbSu7xuTgkxvF4EJupRjRXGgZZrnWFmKzfEzcqKF2ogCaF4QKVbAtuFx7xGwrDUcGd
$ spl-token accounts AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM -v
Account Token Balance
--------------------------------------------------------------------------------------------------------
7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 50
CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 50 (Aux-1*)

Example: Create a non-fungible token

Create the token type with zero decimal place,

  • CLI
  • JS
$ spl-token create-token --decimals 0
Creating token 559u4Tdr9umKwft3yHMsnAxohhzkFnUBPAFtibwuZD9z
Signature: 4kz82JUey1B9ki1McPW7NYv1NqPKCod6WNptSkYqtuiEsQb9exHaktSAHJJsm4YxuGNW4NugPJMFX9ee6WA2dXts

then create an account to hold tokens of this new type:

  • CLI
  • JS
$ spl-token create-account 559u4Tdr9umKwft3yHMsnAxohhzkFnUBPAFtibwuZD9z
Creating account 7KqpRwzkkeweW5jQoETyLzhvs9rcCj9dVQ1MnzudirsM
Signature: sjChze6ecaRtvuQVZuwURyg6teYeiH8ZwT6UTuFNKjrdayQQ3KNdPB7d2DtUZ6McafBfEefejHkJ6MWQEfVHLtC

Now mint only one token into the account,

  • CLI
  • JS
$ spl-token mint 559u4Tdr9umKwft3yHMsnAxohhzkFnUBPAFtibwuZD9z 1 7KqpRwzkkeweW5jQoETyLzhvs9rcCj9dVQ1MnzudirsM
Minting 1 tokens
Token: 559u4Tdr9umKwft3yHMsnAxohhzkFnUBPAFtibwuZD9z
Recipient: 7KqpRwzkkeweW5jQoETyLzhvs9rcCj9dVQ1MnzudirsM
Signature: 2Kzg6ZArQRCRvco*kSiievYy3sfPqGV91Whnz6SeimhJQXKBTYQf3E54tWg3zPpYLbcDexxyTxnj4QF69ucswfdY

and disable future minting:

  • CLI
  • JS
$ spl-token authorize 559u4Tdr9umKwft3yHMsnAxohhzkFnUBPAFtibwuZD9z mint --disable
Updating 559u4Tdr9umKwft3yHMsnAxohhzkFnUBPAFtibwuZD9z
Current mint authority: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
New mint authority: disabled
Signature: 5QpykLzZsceoKcVRRFow9QCdae4Dp2zQAcjebyEWoezPFg2Np73gHKWQicHG1mqRdXu3yiZbrft3Q8JmqNRNqhwU

Now the 7KqpRwzkkeweW5jQoETyLzhvs9rcCj9dVQ1MnzudirsM account holds theone and only 559u4Tdr9umKwft3yHMsnAxohhzkFnUBPAFtibwuZD9z token:

  • CLI
  • JS
$ spl-token account-info 559u4Tdr9umKwft3yHMsnAxohhzkFnUBPAFtibwuZD9z

Address: 7KqpRwzkkeweW5jQoETyLzhvs9rcCj9dVQ1MnzudirsM
Balance: 1
Mint: 559u4Tdr9umKwft3yHMsnAxohhzkFnUBPAFtibwuZD9z
Owner: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
State: Initialized
Delegation: (not set)
Close authority: (not set)
$ spl-token supply 559u4Tdr9umKwft3yHMsnAxohhzkFnUBPAFtibwuZD9z
1

Multisig usage

  • CLI
  • JS

The main difference in spl-token command line usage when referencing multisigaccounts is in specifying the --owner argument. Typically the signer specifiedby this argument directly provides a signature granting its authority, but inthe multisig case it just points to the address of the multisig account.Signatures are then provided by the multisig signer-set members specified by the--multisig-signer argument.

Multisig accounts can be used for any authority on an SPL Token mint or tokenaccount.

  • Mint account mint authority:spl-token mint ...,spl-token authorize ... mint ...
  • Mint account freeze authority:spl-token freeze ...,spl-token thaw ...,spl-token authorize ... freeze ...
  • Token account owner authority:spl-token transfer ...,spl-token approve ...,spl-token revoke ...,spl-token burn ...,spl-token wrap ...,spl-token unwrap ...,spl-token authorize ... owner ...
  • Token account close authority:spl-token close ...,spl-token authorize ... close ...

Example: Mint with multisig authority

First create keypairs to act as the multisig signer-set. In reality, these canbe any supported signer, like: a Ledger hardware wallet, a keypair file, ora paper wallet. For convenience, generated keypairs will be used in this example.

  • CLI
  • JS
$ for i in $(seq 3); do solana-keygen new --no-passphrase -so "signer-${i}.json"; done
Wrote new keypair to signer-1.json
Wrote new keypair to signer-2.json
Wrote new keypair to signer-3.json

In order to create the multisig account, the public keys of the signer-set mustbe collected.

  • CLI
  • JS
$ for i in $(seq 3); do SIGNER="signer-${i}.json"; echo "$SIGNER: $(solana-keygen pubkey "$SIGNER")"; done
signer-1.json: BzWpkuRrwXHq4SSSFHa8FJf6DRQy4TaeoXnkA89vTgHZ
signer-2.json: DhkUfKgfZ8CF6PAGKwdABRL1VqkeNrTSRx8LZfpPFVNY
signer-3.json: D7ssXHrZJjfpZXsmDf8RwfPxe1BMMMmP1CtmX3WojPmG

Now the multisig account can be created with the spl-token create-multisigsubcommand. Its first positional argument is the minimum number of signers (M)that must sign a transaction affecting a token/mint account that is controlledby this multisig account. The remaining positional arguments are the public keysof all keypairs allowed (N) to sign for the multisig account. This examplewill use a "2 of 3" multisig account. That is, two of the three allowed keypairsmust sign all transactions.

NOTE: SPL Token Multisig accounts are limited to a signer-set of eleven signers(1 <= N <= 11) and minimum signers must be no more than N (1 <= M <= N)

  • CLI
  • JS
$ spl-token create-multisig 2 BzWpkuRrwXHq4SSSFHa8FJf6DRQy4TaeoXnkA89vTgHZ \
DhkUfKgfZ8CF6PAGKwdABRL1VqkeNrTSRx8LZfpPFVNY D7ssXHrZJjfpZXsmDf8RwfPxe1BMMMmP1CtmX3WojPmG
Creating 2/3 multisig 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re
Signature: 2FN4KXnczAz33SAxwsuevqrD1BvikP6LUhLie5Lz4ETt594X8R7yvMZzZW2zjmFLPsLQNHsRuhQeumExHbnUGC9A

Next create the token mint and receiving accountsas previously describedand set the mint account's minting authority to the multisig account

  • CLI
  • JS
$ spl-token create-token
Creating token 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o
Signature: 3n6zmw3hS5Hyo5duuhnNvwjAbjzC42uzCA3TTsrgr9htUonzDUXdK1d8b8J77XoeSherqWQM8mD8E1TMYCpksS2r

$ spl-token create-account 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o
Creating account EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC
Signature: 5mVes7wjE7avuFqzrmSCWneKBQyPAjasCLYZPNSkmqmk2YFosYWAP9hYSiZ7b7NKpV866x5gwyKbbppX3d8PcE9s

$ spl-token authorize 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o mint 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re
Updating 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o
Current mint authority: 5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE
New mint authority: 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re
Signature: yy7dJiTx1t7jvLPCRX5RQWxNRNtFwvARSfbMJG94QKEiNS4uZcp3GhhjnMgZ1CaWMWe4jVEMy9zQBoUhzomMaxC

To demonstrate that the mint account is now under control of the multisigaccount, attempting to mint with one multisig signer fails

  • CLI
  • JS
$ spl-token mint 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o 1 EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC \
--owner 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re \
--multisig-signer signer-1.json
Minting 1 tokens
Token: 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o
Recipient: EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC
RPC response error -32002: Transaction simulation failed: Error processing Instruction 0: missing required signature for instruction

But repeating with a second multisig signer, succeeds

  • CLI
  • JS
$ spl-token mint 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o 1 EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC \
--owner 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re \
--multisig-signer signer-1.json \
--multisig-signer signer-2.json
Minting 1 tokens
Token: 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o
Recipient: EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC
Signature: 2ubqWqZb3ooDuc8FLaBkqZwzguhtMgQpgMAHhKsWcUzjy61qtJ7cZ1bfmYktKUfnbMYWTC1S8zdKgU6m4THsgspT

Example: Offline signing with multisig

Sometimes online signing is not possible or desirable. Such is the case for example when signers are not in the same geographic locationor when they use air-gapped devices not connected to the network. In this case, we use offline signing which combines theprevious examples of multisig with offline signingand a nonce account.

This example will use the same mint account, token account, multisig account,and multisig signer-set keypair filenames as the online example, as well as a nonceaccount that we create here:

  • CLI
  • JS
$ solana-keygen new -o nonce-keypair.json
...
======================================================================
pubkey: Fjyud2VXixk2vCs4DkBpfpsq48d81rbEzh6deKt7WvPj
======================================================================
$ solana create-nonce-account nonce-keypair.json 1
Signature: 3DALwrAAmCDxqeb4qXZ44WjpFcwVtgmJKhV4MW5qLJVtWeZ288j6Pzz1F4BmyPpnGLfx2P8MEJXmqPchX5y2Lf3r
$ solana nonce-account Fjyud2VXixk2vCs4DkBpfpsq48d81rbEzh6deKt7WvPj
Balance: 0.01 SOL
Minimum Balance Required: 0.00144768 SOL
Nonce blockhash: 6DPt2TfFBG7sR4Hqu16fbMXPj8ddHKkbU4Y3EEEWrC2E
Fee: 5000 lamports per signature
Authority: 5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE

For the fee-payer and nonce-authority roles, a local hot wallet at5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE will be used.

  • CLI
  • JS

First a template command is built by specifying all signers by their publickey. Upon running this command, all signers will be listed as "Absent Signers"in the output. This command will be run by each offline signer to generate thecorresponding signature.

NOTE: The argument to the --blockhash parameter is the "Nonce blockhash:" field fromthe designated durable nonce account.

$ spl-token mint 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o 1 EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC \
--owner 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re \
--multisig-signer BzWpkuRrwXHq4SSSFHa8FJf6DRQy4TaeoXnkA89vTgHZ \
--multisig-signer DhkUfKgfZ8CF6PAGKwdABRL1VqkeNrTSRx8LZfpPFVNY \
--blockhash 6DPt2TfFBG7sR4Hqu16fbMXPj8ddHKkbU4Y3EEEWrC2E \
--fee-payer 5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE \
--nonce Fjyud2VXixk2vCs4DkBpfpsq48d81rbEzh6deKt7WvPj \
--nonce-authority 5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE \
--sign-only \
--mint-decimals 9
Minting 1 tokens
Token: 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o
Recipient: EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC

Blockhash: 6DPt2TfFBG7sR4Hqu16fbMXPj8ddHKkbU4Y3EEEWrC2E
Absent Signers (Pubkey):
5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE
BzWpkuRrwXHq4SSSFHa8FJf6DRQy4TaeoXnkA89vTgHZ
DhkUfKgfZ8CF6PAGKwdABRL1VqkeNrTSRx8LZfpPFVNY

Next each offline signer executes the template command, replacing each instanceof their public key with the corresponding keypair.

$ spl-token mint 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o 1 EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC \
--owner 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re \
--multisig-signer signer-1.json \
--multisig-signer DhkUfKgfZ8CF6PAGKwdABRL1VqkeNrTSRx8LZfpPFVNY \
--blockhash 6DPt2TfFBG7sR4Hqu16fbMXPj8ddHKkbU4Y3EEEWrC2E \
--fee-payer 5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE \
--nonce Fjyud2VXixk2vCs4DkBpfpsq48d81rbEzh6deKt7WvPj \
--nonce-authority 5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE \
--sign-only \
--mint-decimals 9
Minting 1 tokens
Token: 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o
Recipient: EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC

Blockhash: 6DPt2TfFBG7sR4Hqu16fbMXPj8ddHKkbU4Y3EEEWrC2E
Signers (Pubkey=Signature):
BzWpkuRrwXHq4SSSFHa8FJf6DRQy4TaeoXnkA89vTgHZ=2QVah9XtvPAuhDB2QwE7gNaY962DhrGP6uy9zeN4sTWvY2xDUUzce6zkQeuT3xg44wsgtUw2H5Rf8pEArPSzJvHX
Absent Signers (Pubkey):
5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE
DhkUfKgfZ8CF6PAGKwdABRL1VqkeNrTSRx8LZfpPFVNY
$ spl-token mint 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o 1 EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC \
--owner 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re \
--multisig-signer BzWpkuRrwXHq4SSSFHa8FJf6DRQy4TaeoXnkA89vTgHZ \
--multisig-signer signer-2.json \
--blockhash 6DPt2TfFBG7sR4Hqu16fbMXPj8ddHKkbU4Y3EEEWrC2E \
--fee-payer 5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE \
--nonce Fjyud2VXixk2vCs4DkBpfpsq48d81rbEzh6deKt7WvPj \
--nonce-authority 5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE \
--sign-only \
--mint-decimals 9
Minting 1 tokens
Token: 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o
Recipient: EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC

Blockhash: 6DPt2TfFBG7sR4Hqu16fbMXPj8ddHKkbU4Y3EEEWrC2E
Signers (Pubkey=Signature):
DhkUfKgfZ8CF6PAGKwdABRL1VqkeNrTSRx8LZfpPFVNY=2brZbTiCfyVYSCp6vZE3p7qCDeFf3z1JFmJHPBrz8SnWSDZPjbpjsW2kxFHkktTNkhES3y6UULqS4eaWztLW7FrU
Absent Signers (Pubkey):
5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE
BzWpkuRrwXHq4SSSFHa8FJf6DRQy4TaeoXnkA89vTgHZ

Finally, the offline signers communicate the Pubkey=Signature pair from theoutput of their command to the party who will broadcast the transaction to thecluster. The broadcasting party then runs the template command after modifyingit as follows:

  1. Replaces any corresponding public keys with their keypair (--fee-payer ...and --nonce-authority ... in this example)
  2. Removes the --sign-only argument, and in the case of the mint subcommand,the --mint-decimals ... argument as it will be queried from the cluster
  3. Adds the offline signatures to the template command via the --signer argument
$ spl-token mint 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o 1 EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC \
--owner 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re \
--multisig-signer BzWpkuRrwXHq4SSSFHa8FJf6DRQy4TaeoXnkA89vTgHZ \
--multisig-signer DhkUfKgfZ8CF6PAGKwdABRL1VqkeNrTSRx8LZfpPFVNY \
--blockhash 6DPt2TfFBG7sR4Hqu16fbMXPj8ddHKkbU4Y3EEEWrC2E \
--fee-payer hot-wallet.json \
--nonce Fjyud2VXixk2vCs4DkBpfpsq48d81rbEzh6deKt7WvPj \
--nonce-authority hot-wallet.json \
--signer BzWpkuRrwXHq4SSSFHa8FJf6DRQy4TaeoXnkA89vTgHZ=2QVah9XtvPAuhDB2QwE7gNaY962DhrGP6uy9zeN4sTWvY2xDUUzce6zkQeuT3xg44wsgtUw2H5Rf8pEArPSzJvHX \
--signer DhkUfKgfZ8CF6PAGKwdABRL1VqkeNrTSRx8LZfpPFVNY=2brZbTiCfyVYSCp6vZE3p7qCDeFf3z1JFmJHPBrz8SnWSDZPjbpjsW2kxFHkktTNkhES3y6UULqS4eaWztLW7FrU
Minting 1 tokens
Token: 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o
Recipient: EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC
Signature: 2AhZXVPDBVBxTQLJohyH1wAhkkSuxRiYKomSSXtwhPL9AdF3wmhrrJGD7WgvZjBPLZUFqWrockzPp9S3fvzbgicy

JSON RPC methods

There is a rich set of JSON RPC methods available for use with SPL Token:

  • getTokenAccountBalance
  • getTokenAccountsByDelegate
  • getTokenAccountsByOwner
  • getTokenLargestAccounts
  • getTokenSupply

See https://docs.solana.com/apps/jsonrpc-api for more details.

Additionally the versatile getProgramAccounts JSON RPC method can be employed in various ways to fetch SPL Token accounts of interest.

Finding all token accounts for a specific mint

To find all token accounts for the TESTpKgj42ya3st2SQTKiANjTBmncQSCqLAZGcSPLGM mint:

curl http://api.mainnet-beta.solana.com -X POST -H "Content-Type: application/json" -d '
{
"jsonrpc": "2.0",
"id": 1,
"method": "getProgramAccounts",
"params": [
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
{
"encoding": "jsonParsed",
"filters": [
{
"dataSize": 165
},
{
"memcmp": {
"offset": 0,
"bytes": "TESTpKgj42ya3st2SQTKiANjTBmncQSCqLAZGcSPLGM"
}
}
]
}
]
}
'

The "dataSize": 165 filter selects all TokenAccounts,and then the "memcmp": ... filter selects based on themintaddress within each token account.

Finding all token accounts for a wallet

Find all token accounts owned by the vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg user:

curl http://api.mainnet-beta.solana.com -X POST -H "Content-Type: application/json" -d '
{
"jsonrpc": "2.0",
"id": 1,
"method": "getProgramAccounts",
"params": [
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
{
"encoding": "jsonParsed",
"filters": [
{
"dataSize": 165
},
{
"memcmp": {
"offset": 32,
"bytes": "vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg"
}
}
]
}
]
}
'

The "dataSize": 165 filter selects all TokenAccounts,and then the "memcmp": ... filter selects based on theowneraddress within each token account.

Operational overview

Creating a new token type

A new token type can be created by initializing a new Mint with theInitializeMint instruction. The Mint is used to create or "mint" new tokens,and these tokens are stored in Accounts. A Mint is associated with eachAccount, which means that the total supply of a particular token type is equalto the balances of all the associated Accounts.

It's important to note that the InitializeMint instruction does not requirethe Solana account being initialized also be a signer. The InitializeMintinstruction should be atomically processed with the system instruction thatcreates the Solana account by including both instructions in the sametransaction.

Once a Mint is initialized, the mint_authority can create new tokens using theMintTo instruction. As long as a Mint contains a valid mint_authority, theMint is considered to have a non-fixed supply, and the mint_authority cancreate new tokens with the MintTo instruction at any time. The SetAuthorityinstruction can be used to irreversibly set the Mint's authority to None,rendering the Mint's supply fixed. No further tokens can ever be Minted.

Token supply can be reduced at any time by issuing a Burn instruction whichremoves and discards tokens from an Account.

Creating accounts

Accounts hold token balances and are created using the InitializeAccountinstruction. Each Account has an owner who must be present as a signer in someinstructions.

An Account's owner may transfer ownership of an account to another using theSetAuthority instruction.

It's important to note that the InitializeAccount instruction does not requirethe Solana account being initialized also be a signer. The InitializeAccountinstruction should be atomically processed with the system instruction thatcreates the Solana account by including both instructions in the sametransaction.

Transferring tokens

Balances can be transferred between Accounts using the Transfer instruction.The owner of the source Account must be present as a signer in the Transferinstruction when the source and destination accounts are different.

It's important to note that when the source and destination of a Transfer arethe same, the Transfer will always succeed. Therefore, a successful Transferdoes not necessarily imply that the involved Accounts were valid SPL Tokenaccounts, that any tokens were moved, or that the source Account was present asa signer. We strongly recommend that developers are careful about checking thatthe source and destination are different before invoking a Transferinstruction from within their program.

Burning

The Burn instruction decreases an Account's token balance without transferringto another Account, effectively removing the token from circulation permanently.

There is no other way to reduce supply on chain. This is similar to transferringto an account with unknown private key or destroying a private key. But the actof burning by using Burn instructions is more explicit and can be confirmed onchain by any parties.

Authority delegation

Account owners may delegate authority over some or all of their token balanceusing the Approve instruction. Delegated authorities may transfer or burn upto the amount they've been delegated. Authority delegation may be revoked by theAccount's owner via the Revoke instruction.

Multisignatures

M of N multisignatures are supported and can be used in place of Mintauthorities or Account owners or delegates. Multisignature authorities must beinitialized with the InitializeMultisig instruction. Initialization specifiesthe set of N public keys that are valid and the number M of those N that must bepresent as instruction signers for the authority to be legitimate.

It's important to note that the InitializeMultisig instruction does notrequire the Solana account being initialized also be a signer. TheInitializeMultisig instruction should be atomically processed with the systeminstruction that creates the Solana account by including both instructions inthe same transaction.

Freezing accounts

The Mint may also contain a freeze_authority which can be used to issueFreezeAccount instructions that will render an Account unusable. Tokeninstructions that include a frozen account will fail until the Account is thawedusing the ThawAccount instruction. The SetAuthority instruction can be usedto change a Mint's freeze_authority. If a Mint's freeze_authority is set toNone then account freezing and thawing is permanently disabled and allcurrently frozen accounts will also stay frozen permanently.

Wrapping SOL

The Token Program can be used to wrap native SOL. Doing so allows native SOL tobe treated like any other Token program token type and can be useful when beingcalled from other programs that interact with the Token Program's interface.

Accounts containing wrapped SOL are associated with a specific Mint called the"Native Mint" using the public keySo11111111111111111111111111111111111111112.

These accounts have a few unique behaviors

  • InitializeAccount sets the balance of the initialized Account to the SOLbalance of the Solana account being initialized, resulting in a token balanceequal to the SOL balance.
  • Transfers to and from not only modify the token balance but also transfer anequal amount of SOL from the source account to the destination account.
  • Burning is not supported
  • When closing an Account the balance may be non-zero.

The Native Mint supply will always report 0, regardless of how much SOL is currently wrapped.

Rent-exemption

To ensure a reliable calculation of supply, a consistency valid Mint, andconsistently valid Multisig accounts all Solana accounts holding an Account,Mint, or Multisig must contain enough SOL to be considered rentexempt

Closing accounts

An account may be closed using the CloseAccount instruction. When closing anAccount, all remaining SOL will be transferred to another Solana account(doesn't have to be associated with the Token Program). Non-native Accounts musthave a balance of zero to be closed.

Non-Fungible tokens

An NFT is simply a token type where only a single token has been minted.

Wallet Integration Guide

This section describes how to integrate SPL Token support into an existingwallet supporting native SOL. It assumes a model whereby the user has a singlesystem account as their main wallet address that they send and receive SOLfrom.

Although all SPL Token accounts do have their own address on-chain, there's noneed to surface these additional addresses to the user.

There are two programs that are used by the wallet:

  • SPL Token program: generic program that is used by all SPL Tokens
  • SPL Associated Token Account program: definesthe convention and provides the mechanism for mapping the user's walletaddress to the associated token accounts they hold.

How to fetch and display token holdings

The getTokenAccountsByOwnerJSON RPC method can be used to fetch all token accounts for a wallet address.

For each token mint, the wallet could have multiple token accounts: theassociated token account and/or other ancillary token accounts

By convention it is suggested that wallets roll up the balances from all tokenaccounts of the same token mint into a single balance for the user to shield theuser from this complexity.

See the Garbage Collecting Ancillary Token Accountssection for suggestions on how the wallet should clean up ancillary token accounts on the user's behalf.

Associated Token Account

Before the user can receive tokens, their associated token account must be createdon-chain, requiring a small amount of SOL to mark the account as rent-exempt.

There's no restriction on who can create a user's associated token account. Itcould either be created by the wallet on behalf of the user or funded by a 3rdparty through an airdrop campaign.

The creation process is described here.

It's highly recommended that the wallet create the associated token account fora given SPL Token itself before indicating to the user that they are able toreceive that SPL Tokens type (typically done by showing the user their receivingaddress). A wallet that chooses to not perform this step may limit its user's abilityto receive SPL Tokens from other wallets.

Sample "Add Token" workflow

The user should first fund their associated token account when they want toreceive SPL Tokens of a certain type to:

  1. Maximize interoperability with other wallet implementations
  2. Avoid pushing the cost of creating their associated token account on the first sender

The wallet should provide a UI that allow the users to "add a token".The user selects the kind of token, and is presented with information about howmuch SOL it will cost to add the token.

Upon confirmation, the wallet creates the associated token type as the describedhere.

Sample "Airdrop campaign" workflow

For each recipient wallet addresses, send a transaction containing:

  1. Create the associated token account on the recipient's behalf.
  2. Use TokenInstruction::Transfer to complete the transfer

Associated Token Account Ownership

⚠️ The wallet should never use TokenInstruction::SetAuthority to set theAccountOwner authority of the associated token account to another address.

Ancillary Token Accounts

At any time ownership of an existing SPL Token account may be assigned to theuser. One way to accomplish this is with thespl-token authorize <TOKEN_ADDRESS> owner <USER_ADDRESS> command. Walletsshould be prepared to gracefully manage token accounts that they themselves didnot create for the user.

Transferring Tokens Between Wallets

The preferred method of transferring tokens between wallets is to transfer intoassociated token account of the recipient.

The recipient must provide their main wallet address to the sender. The senderthen:

  1. Derives the associated token account for the recipient
  2. Fetches the recipient's associated token account over RPC and checks that it exists
  3. If the recipient's associated token account does not yet exist, the senderwallet should create the recipient's associated token account as describedhere.The sender's wallet may choose to inform the user that as a result of accountcreation the transfer will require more SOL than normal.However a wallet that chooses to not support creating the recipient'sassociated token account at this time should present a message to the user with enoughinformation to find a workaround to accomplish their goal
  4. Use TokenInstruction::Transfer to complete the transfer

The sender's wallet must not require that the recipient's main wallet addresshold a balance before allowing the transfer.

Registry for token details

At the moment there exist a few solutions for Token Mint registries:

A decentralized solution is in progress.

Garbage Collecting Ancillary Token Accounts

Wallets should empty ancillary token accounts as quickly as practical bytransferring into the user's associated token account. This effort serves twopurposes:

  • If the user is the close authority for the ancillary account, the wallet canreclaim SOL for the user by closing the account.
  • If the ancillary account was funded by a 3rd party, once the account isemptied that 3rd party may close the account and reclaim the SOL.

One natural time to garbage collect ancillary token accounts is when the usernext sends tokens. The additional instructions to do so can be added to theexisting transaction, and will not require an additional fee.

Cleanup Pseudo Steps:

  1. For all non-empty ancillary token accounts, add aTokenInstruction::Transfer instruction to the transfer the full tokenamount to the user's associated token account.
  2. For all empty ancillary token accounts where the user is the close authority,add a TokenInstruction::CloseAccount instruction

If adding one or more of clean up instructions cause the transaction to exceedthe maximum allowed transaction size, remove those extra clean up instructions.They can be cleaned up during the next send operation.

The spl-token gc command provides an example implementation of this cleanup process.

Token Vesting

There are currently two solutions available for vesting SPL tokens:

1) Bonfida token-vesting

This program allows you to lock arbitrary SPL tokens and release the locked tokens with a determined unlock schedule. An unlock schedule is made of a unix timestamp and a token amount, when initializing a vesting contract, the creator can pass an array of unlock schedule with an arbitrary size giving the creator of the contract complete control of how the tokens unlock over time.

Unlocking works by pushing a permissionless crank on the contract that moves the tokens to the pre-specified address. The recipient address of a vesting contract can be modified by the owner of the current recipient key, meaning that vesting contract locked tokens can be traded.

2) Streamflow Timelock

Enables creation, withdrawal, cancellation and transfer of token vesting contracts using time-based lock and escrow accounts.Contracts are by default cancelable by the creator and transferable by the recipient.

Vesting contract creator chooses various options upon creation, such as:

  • SPL token and amount to be vested
  • recipient
  • exact start and end date
  • (optional) cliff date and amount
  • (optional) release frequency

Coming soon:

  • whether or not a contract is transferable by creator/recipient
  • whether or not a contract is cancelable by creator/recipient
  • subject/memo

Resources:

Token Program | Solana Program Library Docs (2024)
Top Articles
FDIC Insurance Information | Main Street Bank Community Bank
What to do when a house sale falls through before exchange - TIC Finance
Chris Provost Daughter Addie
Jackerman Mothers Warmth Part 3
Tyson Employee Paperless
Falgout Funeral Home Obituaries Houma
Kobold Beast Tribe Guide and Rewards
Find All Subdomains
Mndot Road Closures
Bernie Platt, former Cherry Hill mayor and funeral home magnate, has died at 90
Uhcs Patient Wallet
Missed Connections Dayton Ohio
Spectrum Field Tech Salary
Everything We Know About Gladiator 2
Itziar Atienza Bikini
Equibase | International Results
V-Pay: Sicherheit, Kosten und Alternativen - BankingGeek
Amih Stocktwits
How to Download and Play Ultra Panda on PC ?
Seeking Arrangements Boston
Filthy Rich Boys (Rich Boys Of Burberry Prep #1) - C.M. Stunich [PDF] | Online Book Share
Foolproof Module 6 Test Answers
10 Best Places to Go and Things to Know for a Trip to the Hickory M...
208000 Yen To Usd
Craigslist Comes Clean: No More 'Adult Services,' Ever
Federal Express Drop Off Center Near Me
Kids and Adult Dinosaur Costume
Att U Verse Outage Map
Save on Games, Flamingo, Toys Games & Novelties
Lake Dunson Robertson Funeral Home Lagrange Georgia Obituary
Workday Latech Edu
Devin Mansen Obituary
Closest 24 Hour Walmart
Ludvigsen Mortuary Fremont Nebraska
Myql Loan Login
2023 Nickstory
Suffix With Pent Crossword Clue
Questions answered? Ducks say so in rivalry rout
The Largest Banks - ​​How to Transfer Money With Only Card Number and CVV (2024)
062203010
Vindy.com Obituaries
The Attleboro Sun Chronicle Obituaries
Chase Bank Zip Code
Centimeters to Feet conversion: cm to ft calculator
Borat: An Iconic Character Who Became More than Just a Film
Unit 11 Homework 3 Area Of Composite Figures
Tyco Forums
Bank Of America Appointments Near Me
Pas Bcbs Prefix
Is Chanel West Coast Pregnant Due Date
Latest Posts
Article information

Author: Mr. See Jast

Last Updated:

Views: 5868

Rating: 4.4 / 5 (55 voted)

Reviews: 86% of readers found this page helpful

Author information

Name: Mr. See Jast

Birthday: 1999-07-30

Address: 8409 Megan Mountain, New Mathew, MT 44997-8193

Phone: +5023589614038

Job: Chief Executive

Hobby: Leather crafting, Flag Football, Candle making, Flying, Poi, Gunsmithing, Swimming

Introduction: My name is Mr. See Jast, I am a open, jolly, gorgeous, courageous, inexpensive, friendly, homely person who loves writing and wants to share my knowledge and understanding with you.