Beginner
How to write Token Program on Solana Blockchain
This tutorial will guide you on how to write a token program on the Solana blockchain. Solana’s programming model and terminology are explained in the background section, and instructions on how to set up and configure the necessary tools using JavaScript are provided. The tutorial then goes on to show examples of creating fungible and non-fungible tokens, as well as transferring, approving, and freezing tokens. Finally, the tutorial explains how to create and manage non-fungible tokens using the NFT program provided in the spl-token library.
Background
Solana’s programming model and the definitions of the Solana terms used in this document are available at:
Setup with JavaScript
Yarn
yarn add @solana/spl-token
npm
npm install @solana/spl-token
Configuration
You can connect to different clusters using Connection in @solana/web3.js
const web3 = require('@solana/web3.js'); const connection = new web3.Connection(web3.clusterApiUrl('devnet'), 'confirmed');
Keypair
You can either get your keypair using Keypair from @solana/web3.js, or let the user’s wallet handle the keypair and use sendTransaction from wallet-adapter
Airdrop SOL
Creating tokens and accounts requires SOL for account rent deposits and transaction fees. If the cluster you are targeting offers a faucet, you can get a little SOL for testing:
- CLI
- JS
import { clusterApiUrl, Connection, Keypair, LAMPORTS_PER_SOL } from '@solana/web3.js'; const payer = Keypair.generate(); const connection = new Connection( clusterApiUrl('devnet'), 'confirmed' ); const airdropSignature = await connection.requestAirdrop( payer.publicKey, LAMPORTS_PER_SOL, ); await connection.confirmTransaction(airdropSignature);
By using console you can see airdrop Signature as sown below q3BJjy2mA5F5HWXDsoF1Kwo58EF6Drqjz2XbZhpZqTAfEP5Gpi2F1XSvYqW87ut3G7XdWJRQuztiqK86MErbfHB
Below are the examples of creating fungible tokens and view tokens.
import { createMint } from '@solana/spl-token'; import { clusterApiUrl, Connection, Keypair, LAMPORTS_PER_SOL } from '@solana/web3.js'; const payer = Keypair.generate(); const mintAuthority = Keypair.generate(); const freezeAuthority = Keypair.generate(); const connection = new Connection( clusterApiUrl('devnet'), 'confirmed' ); const mint = await createMint( connection, payer, mintAuthority.publicKey, freezeAuthority.publicKey, 9 // We are using 9 to match the CLI decimal default exactly ); console.log(mint.toBase58());
The unique identifier of the token is AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM.
Tokens when initially created by spl-token have no supply.
Use below function to check the supply
const mintInfo = await getMint( connection, mint ) console.log(mintInfo.supply); // 0
Let’s mint some. First create an account to hold a balance of the new AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
token:const tokenAccount = await getOrCreateAssociatedTokenAccount( connection, payer, mint, payer.publicKey ) console.log(tokenAccount.address.toBase58()); // 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi is now an empty account: const tokenAccountInfo = await getAccount( connection, tokenAccount.address ) console.log(tokenAccountInfo.amount); // 0
Mint 100 tokens into the account:
await mintTo( connection, payer, mint, tokenAccount.address, mintAuthority, 100000000000 // because decimals for the mint are set to 9 )
The token supply and account balance now reflect the result of minting:
const mintInfo = await getMint( connection, mint ) console.log(mintInfo.supply); // 100 const tokenAccountInfo = await getAccount( connection, tokenAccount.address ) console.log(tokenAccountInfo.amount); // 100
Example: View all Tokens that you own
import {AccountLayout, TOKEN_PROGRAM_ID} from "@solana/spl-token"; import {clusterApiUrl, Connection, PublicKey} from "@solana/web3.js"; (async () => { const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); const tokenAccounts = await connection.getTokenAccountsByOwner( new PublicKey('8YLKoCu7NwqHNS8GzuvA2ibsvLrsg22YMfMDafxh1B15'), { programId: TOKEN_PROGRAM_ID, } ); console.log("Token Balance"); console.log("------------------------------------------------------------"); tokenAccounts.value.forEach((tokenAccount) => { const accountData = AccountLayout.decode(tokenAccount.account.data); console.log(`${new PublicKey(accountData.mint)} ${accountData.amount}`); }) })();
By running above code you can see the token you own and its informtion below you can see
Token Balance ------------------------------------------------------------ 7e2X5oeAAJyUTi4PfSGXFLGhyPw2H8oELm1mx87ZCgwF 84 AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 100 AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 0 AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 1
Congratulations You have done workshop-2 successfully