├── .gitignore ├── .prettierrc.json ├── README.md ├── address-lookup-tables ├── package.json └── tests │ ├── test.ts │ ├── tsconfig.json │ └── util.ts ├── basics ├── change-ownership │ ├── package.json │ └── tests │ │ ├── test.ts │ │ ├── tsconfig.json │ │ └── util.ts └── transfer-sol │ ├── package.json │ └── tests │ ├── test.ts │ └── tsconfig.json └── tokens ├── .assets ├── nft.json └── spl-token.json ├── create-token ├── README.md ├── package.json ├── src │ ├── main.ts │ ├── tokens.ts │ └── util.ts └── tsconfig.json ├── freezing-tokens └── README.md ├── metaplex-expanded └── README.md ├── nft-minter ├── README.md ├── package.json ├── src │ ├── main.ts │ ├── tokens.ts │ └── util.ts └── tsconfig.json ├── spl-token-minter ├── README.md ├── package.json ├── src │ ├── main.ts │ ├── tokens.ts │ └── util.ts └── tsconfig.json ├── token-2022 ├── README.md ├── close-authority │ ├── README.md │ ├── package.json │ ├── src │ │ └── main.ts │ └── tsconfig.json ├── create-account-with-memo-on-transfer │ ├── README.MD │ ├── package.json │ ├── src │ │ └── main.ts │ └── tsconfig.json ├── default-account-state │ ├── README.md │ ├── package.json │ ├── src │ │ └── main.ts │ └── tsconfig.json ├── immutable-owner │ ├── README.md │ ├── package.json │ ├── src │ │ └── main.ts │ └── tsconfig.json ├── interest-bearing │ ├── README.md │ ├── package.json │ ├── src │ │ └── main.ts │ └── tsconfig.json ├── non-transferable-token │ ├── README.MD │ ├── package.json │ ├── src │ │ └── main.ts │ └── tsconfig.json ├── reallocate-space-example │ ├── README.MD │ ├── package.json │ ├── src │ │ └── main.ts │ └── tsconfig.json └── transfer-fee │ ├── README.md │ ├── package.json │ ├── src │ └── main.ts │ └── tsconfig.json ├── token-lending └── README.md ├── transfer-tokens ├── README.md ├── package.json ├── src │ ├── main.ts │ ├── tokens.ts │ └── util.ts └── tsconfig.json └── wrapping-sol ├── README.md ├── package-lock.json ├── package.json ├── src └── main.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | test-ledger/ 2 | */**/test-ledger/ 3 | */**/node_modules/ 4 | */**/yarn.lock 5 | */**/package-lock.json 6 | */**/yarn-error.log -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "tabWidth": 2, 4 | "useTabs": true, 5 | "semi": true, 6 | "singleQuote": false, 7 | "proseWrap": "always", 8 | "printWidth": 80 9 | } 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Web3 Examples 2 | 3 | ### :space_invader: Welcome, Solana Developer. :space_invader: 4 | 5 | Are you just starting out on Solana? Stuck on something? 6 | 7 | Or maybe you're in a hackathon right now, building an absolutely _epic_ dApp. 8 | 9 | Take a look at this awesome collection of examples in Typescript using Solana's 10 | `web3.js` (and Anchor); for your cloning & running pleasure. 11 | 12 | ### :large_blue_diamond: TypeScript. :large_orange_diamond: JavaScript. :cyclone: Web3. 13 | 14 | ## Examples We'd Love to See! 15 | 16 | 💡 You can write any example using Solana's `web3.js`, `anchor`, `solanapy`, `anchorpy`, or `solana_sdk`. 17 | 18 | 19 | * All existing examples (or new ones) for: 20 | * `anchor`: TypeScript 21 | * `solanapy`: Python 22 | * `anchorpy`: Python 23 | * `solana_sdk`: Rust 24 | * New examples needed for all: 25 | * OpenBook 26 | -------------------------------------------------------------------------------- /address-lookup-tables/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "test": "yarn run ts-mocha -p ./tests/tsconfig.json -t 1000000 ./tests/test.ts" 4 | }, 5 | "license": "MIT", 6 | "dependencies": { 7 | "@solana/web3.js": "1.63.1" 8 | }, 9 | "devDependencies": { 10 | "@types/chai": "^4.3.3", 11 | "@types/mocha": "^9.1.1", 12 | "chai": "^4.3.6", 13 | "mocha": "^10.0.0", 14 | "ts-mocha": "^10.0.0", 15 | "typescript": "^4.8.3" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /address-lookup-tables/tests/test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AddressLookupTableProgram, 3 | Connection, 4 | Keypair, 5 | PublicKey, 6 | SystemProgram, 7 | TransactionInstruction, 8 | } from "@solana/web3.js"; 9 | import { 10 | createKeypairFromFile, 11 | printAddressLookupTable, 12 | printBalances, 13 | sendTransactionV0, 14 | sendTransactionV0WithLookupTable, 15 | } from "./util"; 16 | 17 | describe("Address Lookup Tables!", () => { 18 | const connection = new Connection( 19 | `https://api.devnet.solana.com`, 20 | "confirmed", 21 | ); 22 | const payer = createKeypairFromFile( 23 | require("os").homedir() + "/.config/solana/id.json", 24 | ); 25 | 26 | let lookupTablePubkey: PublicKey; 27 | const testAccountOne = Keypair.generate(); 28 | const testAccountTwo = Keypair.generate(); 29 | 30 | it("Create an Address Lookup Table", async () => { 31 | let ix: TransactionInstruction; 32 | [ix, lookupTablePubkey] = AddressLookupTableProgram.createLookupTable({ 33 | authority: payer.publicKey, 34 | payer: payer.publicKey, 35 | recentSlot: await connection.getSlot(), 36 | }); 37 | 38 | await sendTransactionV0(connection, [ix], payer); 39 | 40 | console.log("Pubkeys from generated keypairs:"); 41 | console.log(` Test Account #1: ${testAccountOne.publicKey}`); 42 | console.log(` Test Account #2: ${testAccountTwo.publicKey}`); 43 | await printAddressLookupTable(connection, lookupTablePubkey); 44 | }); 45 | 46 | it("Add some addresses to the ALT", async () => { 47 | const ix = AddressLookupTableProgram.extendLookupTable({ 48 | addresses: [testAccountOne.publicKey, testAccountTwo.publicKey], 49 | authority: payer.publicKey, 50 | lookupTable: lookupTablePubkey, 51 | payer: payer.publicKey, 52 | }); 53 | 54 | await sendTransactionV0(connection, [ix], payer); 55 | 56 | await printAddressLookupTable(connection, lookupTablePubkey); 57 | }); 58 | 59 | it("Fund the first test account", async () => { 60 | const ix = SystemProgram.transfer({ 61 | fromPubkey: payer.publicKey, 62 | toPubkey: testAccountOne.publicKey, 63 | lamports: 100000000, 64 | }); 65 | 66 | await sendTransactionV0(connection, [ix], payer); 67 | 68 | await printBalances( 69 | connection, 70 | "After", 71 | testAccountOne.publicKey, 72 | testAccountTwo.publicKey, 73 | ); 74 | }); 75 | 76 | it("Send a transaction WITHOUT using the ALT", async () => { 77 | await printBalances( 78 | connection, 79 | "Before", 80 | testAccountOne.publicKey, 81 | testAccountTwo.publicKey, 82 | ); 83 | 84 | const ix = SystemProgram.transfer({ 85 | fromPubkey: testAccountOne.publicKey, 86 | toPubkey: testAccountTwo.publicKey, 87 | lamports: 20000000, 88 | }); 89 | 90 | await sendTransactionV0(connection, [ix], testAccountOne); 91 | 92 | await printBalances( 93 | connection, 94 | "After", 95 | testAccountOne.publicKey, 96 | testAccountTwo.publicKey, 97 | ); 98 | }); 99 | 100 | it("Now send that same transaction using the ALT", async () => { 101 | await printBalances( 102 | connection, 103 | "Before", 104 | payer.publicKey, 105 | testAccountOne.publicKey, 106 | ); 107 | 108 | const ix = SystemProgram.transfer({ 109 | fromPubkey: testAccountOne.publicKey, 110 | toPubkey: testAccountTwo.publicKey, 111 | lamports: 20000000, 112 | }); 113 | 114 | await sendTransactionV0WithLookupTable( 115 | connection, 116 | [ix], 117 | testAccountOne, 118 | lookupTablePubkey, 119 | ); 120 | 121 | await printBalances( 122 | connection, 123 | "After", 124 | testAccountOne.publicKey, 125 | testAccountTwo.publicKey, 126 | ); 127 | }); 128 | }); 129 | -------------------------------------------------------------------------------- /address-lookup-tables/tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015"], 4 | "module": "commonjs", 5 | "target": "es6", 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /address-lookup-tables/tests/util.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Connection, 3 | Keypair, 4 | PublicKey, 5 | TransactionInstruction, 6 | VersionedTransaction, 7 | TransactionMessage, 8 | } from "@solana/web3.js"; 9 | 10 | export function createKeypairFromFile(path: string): Keypair { 11 | return Keypair.fromSecretKey( 12 | Buffer.from(JSON.parse(require("fs").readFileSync(path, "utf-8"))), 13 | ); 14 | } 15 | 16 | export async function sendTransactionV0( 17 | connection: Connection, 18 | instructions: TransactionInstruction[], 19 | payer: Keypair, 20 | ): Promise { 21 | let blockhash = await connection 22 | .getLatestBlockhash() 23 | .then((res) => res.blockhash); 24 | 25 | const messageV0 = new TransactionMessage({ 26 | payerKey: payer.publicKey, 27 | recentBlockhash: blockhash, 28 | instructions, 29 | }).compileToV0Message(); 30 | 31 | const tx = new VersionedTransaction(messageV0); 32 | tx.sign([payer]); 33 | const sx = await connection.sendTransaction(tx); 34 | 35 | console.log(`** -- Signature: ${sx}`); 36 | } 37 | 38 | export async function sendTransactionV0WithLookupTable( 39 | connection: Connection, 40 | instructions: TransactionInstruction[], 41 | payer: Keypair, 42 | lookupTablePubkey: PublicKey, 43 | ): Promise { 44 | const lookupTableAccount = await connection 45 | .getAddressLookupTable(lookupTablePubkey) 46 | .then((res) => res.value); 47 | 48 | let blockhash = await connection 49 | .getLatestBlockhash() 50 | .then((res) => res.blockhash); 51 | 52 | const messageV0 = new TransactionMessage({ 53 | payerKey: payer.publicKey, 54 | recentBlockhash: blockhash, 55 | instructions, 56 | }).compileToV0Message([lookupTableAccount]); 57 | 58 | const tx = new VersionedTransaction(messageV0); 59 | tx.sign([payer]); 60 | const sx = await connection.sendTransaction(tx); 61 | 62 | console.log(`** -- Signature: ${sx}`); 63 | } 64 | 65 | export async function printAddressLookupTable( 66 | connection: Connection, 67 | lookupTablePubkey: PublicKey, 68 | ): Promise { 69 | await delay(2); 70 | const lookupTableAccount = await connection 71 | .getAddressLookupTable(lookupTablePubkey) 72 | .then((res) => res.value); 73 | console.log(`Lookup Table: ${lookupTablePubkey}`); 74 | for (let i = 0; i < lookupTableAccount.state.addresses.length; i++) { 75 | const address = lookupTableAccount.state.addresses[i]; 76 | console.log(` Index: ${i} Address: ${address.toBase58()}`); 77 | } 78 | } 79 | 80 | export async function printBalances( 81 | connection: Connection, 82 | timeframe: string, 83 | pubkeyOne: PublicKey, 84 | pubkeyTwo: PublicKey, 85 | ): Promise { 86 | console.log(`${timeframe}:`); 87 | console.log( 88 | ` Test Account #1 balance : ${await connection.getBalance(pubkeyOne)}`, 89 | ); 90 | console.log( 91 | ` Test Account #2 balance : ${await connection.getBalance(pubkeyTwo)}`, 92 | ); 93 | } 94 | 95 | function delay(s: number) { 96 | return new Promise((resolve) => setTimeout(resolve, s * 1000)); 97 | } 98 | -------------------------------------------------------------------------------- /basics/change-ownership/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "test": "yarn run ts-mocha -p ./tests/tsconfig.json -t 1000000 ./tests/test.ts" 4 | }, 5 | "license": "MIT", 6 | "dependencies": { 7 | "@solana/web3.js": "1.63.1" 8 | }, 9 | "devDependencies": { 10 | "@types/chai": "^4.3.3", 11 | "@types/mocha": "^9.1.1", 12 | "chai": "^4.3.6", 13 | "mocha": "^10.0.0", 14 | "ts-mocha": "^10.0.0", 15 | "typescript": "^4.8.3" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /basics/change-ownership/tests/test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Connection, 3 | Keypair, 4 | LAMPORTS_PER_SOL, 5 | PublicKey, 6 | sendAndConfirmTransaction, 7 | SystemProgram, 8 | Transaction, 9 | } from "@solana/web3.js"; 10 | 11 | function createKeypairFromFile(path: string): Keypair { 12 | return Keypair.fromSecretKey( 13 | Buffer.from(JSON.parse(require("fs").readFileSync(path, "utf-8"))), 14 | ); 15 | } 16 | 17 | describe("Change an account's owner", async () => { 18 | const connection = new Connection( 19 | `https://api.devnet.solana.com`, 20 | "confirmed", 21 | ); 22 | const payer = createKeypairFromFile( 23 | require("os").homedir() + "/.config/solana/id.json", 24 | ); 25 | 26 | const PROGRAM_ID: PublicKey = new PublicKey( 27 | "Au21huMZuDQrbzu2Ec5ohpW5CKRqhcGV6qLawfydStGs", 28 | ); // This is just an arbitrary Program ID for example 29 | 30 | const newKeypair = Keypair.generate(); 31 | 32 | it("Create the account", async () => { 33 | let ix = SystemProgram.createAccount({ 34 | fromPubkey: payer.publicKey, 35 | newAccountPubkey: newKeypair.publicKey, 36 | lamports: 1 * LAMPORTS_PER_SOL, 37 | space: 0, 38 | programId: SystemProgram.programId, 39 | }); 40 | 41 | await sendAndConfirmTransaction(connection, new Transaction().add(ix), [ 42 | payer, 43 | newKeypair, 44 | ]); 45 | }); 46 | 47 | it("Change ownership for the account", async () => { 48 | let ix = SystemProgram.assign({ 49 | accountPubkey: newKeypair.publicKey, 50 | programId: PROGRAM_ID, 51 | }); 52 | 53 | await sendAndConfirmTransaction(connection, new Transaction().add(ix), [ 54 | payer, 55 | newKeypair, 56 | ]); 57 | }); 58 | 59 | it("Try to change it again using the System Program", async () => { 60 | let ix = SystemProgram.assign({ 61 | accountPubkey: newKeypair.publicKey, 62 | programId: SystemProgram.programId, 63 | }); 64 | 65 | try { 66 | await sendAndConfirmTransaction(connection, new Transaction().add(ix), [ 67 | payer, 68 | newKeypair, 69 | ]); 70 | } catch (e) { 71 | console.log(e); 72 | } 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /basics/change-ownership/tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015"], 4 | "module": "commonjs", 5 | "target": "es6", 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /basics/change-ownership/tests/util.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Connection, 3 | Keypair, 4 | PublicKey, 5 | TransactionInstruction, 6 | VersionedTransaction, 7 | TransactionMessage, 8 | } from "@solana/web3.js"; 9 | 10 | export function createKeypairFromFile(path: string): Keypair { 11 | return Keypair.fromSecretKey( 12 | Buffer.from(JSON.parse(require("fs").readFileSync(path, "utf-8"))), 13 | ); 14 | } 15 | 16 | export async function sendTransactionV0( 17 | connection: Connection, 18 | instructions: TransactionInstruction[], 19 | payer: Keypair, 20 | ): Promise { 21 | let blockhash = await connection 22 | .getLatestBlockhash() 23 | .then((res) => res.blockhash); 24 | 25 | const messageV0 = new TransactionMessage({ 26 | payerKey: payer.publicKey, 27 | recentBlockhash: blockhash, 28 | instructions, 29 | }).compileToV0Message(); 30 | 31 | const tx = new VersionedTransaction(messageV0); 32 | tx.sign([payer]); 33 | const sx = await connection.sendTransaction(tx); 34 | 35 | console.log(`** -- Signature: ${sx}`); 36 | } 37 | 38 | export async function sendTransactionV0WithLookupTable( 39 | connection: Connection, 40 | instructions: TransactionInstruction[], 41 | payer: Keypair, 42 | lookupTablePubkey: PublicKey, 43 | ): Promise { 44 | const lookupTableAccount = await connection 45 | .getAddressLookupTable(lookupTablePubkey) 46 | .then((res) => res.value); 47 | 48 | let blockhash = await connection 49 | .getLatestBlockhash() 50 | .then((res) => res.blockhash); 51 | 52 | const messageV0 = new TransactionMessage({ 53 | payerKey: payer.publicKey, 54 | recentBlockhash: blockhash, 55 | instructions, 56 | }).compileToV0Message([lookupTableAccount]); 57 | 58 | const tx = new VersionedTransaction(messageV0); 59 | tx.sign([payer]); 60 | const sx = await connection.sendTransaction(tx); 61 | 62 | console.log(`** -- Signature: ${sx}`); 63 | } 64 | 65 | export async function printAddressLookupTable( 66 | connection: Connection, 67 | lookupTablePubkey: PublicKey, 68 | ): Promise { 69 | await delay(2); 70 | const lookupTableAccount = await connection 71 | .getAddressLookupTable(lookupTablePubkey) 72 | .then((res) => res.value); 73 | console.log(`Lookup Table: ${lookupTablePubkey}`); 74 | for (let i = 0; i < lookupTableAccount.state.addresses.length; i++) { 75 | const address = lookupTableAccount.state.addresses[i]; 76 | console.log(` Index: ${i} Address: ${address.toBase58()}`); 77 | } 78 | } 79 | 80 | export async function printBalances( 81 | connection: Connection, 82 | timeframe: string, 83 | pubkeyOne: PublicKey, 84 | pubkeyTwo: PublicKey, 85 | ): Promise { 86 | console.log(`${timeframe}:`); 87 | console.log( 88 | ` Test Account #1 balance : ${await connection.getBalance(pubkeyOne)}`, 89 | ); 90 | console.log( 91 | ` Test Account #2 balance : ${await connection.getBalance(pubkeyTwo)}`, 92 | ); 93 | } 94 | 95 | function delay(s: number) { 96 | return new Promise((resolve) => setTimeout(resolve, s * 1000)); 97 | } 98 | -------------------------------------------------------------------------------- /basics/transfer-sol/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "test": "yarn run ts-mocha -p ./tests/tsconfig.json -t 1000000 ./tests/test.ts" 4 | }, 5 | "license": "MIT", 6 | "dependencies": { 7 | "@solana/web3.js": "^1.62.1" 8 | }, 9 | "devDependencies": { 10 | "@types/chai": "^4.3.3", 11 | "@types/mocha": "^9.1.1", 12 | "chai": "^4.3.6", 13 | "mocha": "^10.0.0", 14 | "ts-mocha": "^10.0.0", 15 | "typescript": "^4.8.3" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /basics/transfer-sol/tests/test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Connection, 3 | Keypair, 4 | LAMPORTS_PER_SOL, 5 | PublicKey, 6 | sendAndConfirmTransaction, 7 | SystemProgram, 8 | Transaction, 9 | } from "@solana/web3.js"; 10 | 11 | function createKeypairFromFile(path: string): Keypair { 12 | return Keypair.fromSecretKey( 13 | Buffer.from(JSON.parse(require("fs").readFileSync(path, "utf-8"))), 14 | ); 15 | } 16 | 17 | describe("transfer SOL from client side", () => { 18 | async function getBalances( 19 | payerPubkey: PublicKey, 20 | recipientPubkey: PublicKey, 21 | timeframe: string, 22 | ) { 23 | let payerBalance = await connection.getBalance(payerPubkey); 24 | let recipientBalance = await connection.getBalance(recipientPubkey); 25 | console.log(`${timeframe} balances:`); 26 | console.log(` Payer: ${payerBalance}`); 27 | console.log(` Recipient: ${recipientBalance}`); 28 | } 29 | 30 | const connection = new Connection(`http://127.0.0.1:8899`, "confirmed"); 31 | const payer = createKeypairFromFile( 32 | require("os").homedir() + "/.config/solana/id.json", 33 | ); 34 | 35 | it("Transfer some SOL", async () => { 36 | let recipientKeypair = Keypair.generate(); 37 | let transferAmount = 1 * LAMPORTS_PER_SOL; 38 | 39 | await getBalances(payer.publicKey, recipientKeypair.publicKey, "Beginning"); 40 | 41 | let ix = SystemProgram.transfer({ 42 | fromPubkey: payer.publicKey, 43 | toPubkey: recipientKeypair.publicKey, 44 | lamports: transferAmount, 45 | }); 46 | 47 | await sendAndConfirmTransaction(connection, new Transaction().add(ix), [ 48 | payer, 49 | ]); 50 | 51 | await getBalances(payer.publicKey, recipientKeypair.publicKey, "Resulting"); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /basics/transfer-sol/tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015"], 4 | "module": "commonjs", 5 | "target": "es6", 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tokens/.assets/nft.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Homer NFT", 3 | "symbol": "HOMR", 4 | "description": "An NFT of Homer Simpson", 5 | "image": "https://static.onecms.io/wp-content/uploads/sites/6/2018/08/simp_homersingle08_f_hires2-2000.jpg" 6 | } -------------------------------------------------------------------------------- /tokens/.assets/spl-token.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Solana Gold", 3 | "symbol": "GOLDSOL", 4 | "description": "A gold Solana SPL token :)", 5 | "image": "https://w7.pngwing.com/pngs/153/594/png-transparent-solana-coin-sign-icon-shiny-golden-symmetric-geometrical-design.png" 6 | } -------------------------------------------------------------------------------- /tokens/create-token/README.md: -------------------------------------------------------------------------------- 1 | # Create an SPL Token 2 | 3 | This example demonstrates how to create an SPL Token on Solana with some 4 | metadata such as a token symbol and icon. 5 | 6 | --- 7 | 8 | All tokens - including Non-Fungible Tokens (NFTs) are SPL Tokens on Solana. 9 | 10 | They follow the SPL Token standard (similar to ERC-20). 11 | 12 | ```text 13 | Default SPL Tokens : 9 decimals 14 | NFTs : 0 decimals 15 | ``` 16 | 17 | ### How Decimals Work 18 | 19 | ```text 20 | Consider token JOE with 9 decimals: 21 | 22 | 1 JOE = quantity * 10 ^ (-1 * decimals) = 1 * 10 ^ (-1 * 9) = 0.000000001 23 | ``` 24 | 25 | ### Mint & Metadata 26 | 27 | SPL Tokens on Solana are referred to as a Mint. 28 | 29 | A Mint is defined by a specific type of account on Solana that describes 30 | information about a token: 31 | 32 | ```TypeScript 33 | { 34 | isInitialized, 35 | supply, // The current supply of this token mint on Solana 36 | decimals, // The number of decimals this mint breaks down to 37 | mintAuthority, // The account who can authorize minting of new tokens 38 | freezeAuthority, // The account who can authorize freezing of tokens 39 | } 40 | ``` 41 | 42 | Any metadata about this Mint - such as a nickname, symbol, or image - is stored 43 | in a **separate** account called a Metadata Account: 44 | 45 | ```TypeScript 46 | { 47 | title, 48 | symbol, 49 | uri, // The URI to the hosted image 50 | } 51 | ``` 52 | 53 | > Project Metaplex is the standard for SPL Token metadata on Solana 54 | > You can use [Metaplex's Token Metadata Program](https://docs.metaplex.com/) to 55 | > create metadata for your token. 56 | 57 | ### Steps to Create an SPL Token 58 | 59 | 1. Create an account for the Mint. 60 | 2. Initialize that account as a Mint Account. 61 | 3. Create a metadata account associated with that Mint Account. 62 | -------------------------------------------------------------------------------- /tokens/create-token/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "main": "yarn run ts-node ./src/main.ts" 4 | }, 5 | "license": "MIT", 6 | "dependencies": { 7 | "@metaplex-foundation/mpl-token-metadata": "^2.5.2", 8 | "@solana/spl-token": "^0.3.7", 9 | "@solana/web3.js": "^1.73.0", 10 | "ts-node": "^10.9.1", 11 | "typescript": "^4.9.4" 12 | }, 13 | "devDependencies": { 14 | "@types/node": "^18.11.18" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tokens/create-token/src/main.ts: -------------------------------------------------------------------------------- 1 | import { Keypair } from "@solana/web3.js"; 2 | import { createAccount, createToken } from "./tokens"; 3 | import { loadKeypairFromFile } from "./util"; 4 | 5 | const payer = loadKeypairFromFile( 6 | require("os").homedir() + "/.config/solana/id.json", 7 | ); 8 | 9 | const testUserKeypair1 = Keypair.generate(); 10 | const testUserKeypair2 = Keypair.generate(); 11 | 12 | const tokenMintKeypair = Keypair.generate(); 13 | const nftMintKeypair = Keypair.generate(); 14 | 15 | async function tokensScript() { 16 | await createAccount("Test User Keypair #1", testUserKeypair1, payer); 17 | await createAccount("Test User Keypair #2", testUserKeypair2, payer); 18 | 19 | // SPL Token 20 | await createToken( 21 | tokenMintKeypair, 22 | payer, 23 | "Solana Gold", 24 | "GOLDSOL", 25 | "https://raw.githubusercontent.com/solana-developers/web3-examples/new-examples/tokens/tokens/.assets/spl-token.json", 26 | 9, 27 | ); 28 | // NFT 29 | await createToken( 30 | nftMintKeypair, 31 | payer, 32 | "Homer NFT", 33 | "HOMR", 34 | "https://raw.githubusercontent.com/solana-developers/web3-examples/new-examples/tokens/tokens/.assets/nft.json", 35 | 0, 36 | ); 37 | } 38 | 39 | tokensScript(); 40 | -------------------------------------------------------------------------------- /tokens/create-token/src/tokens.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createCreateMetadataAccountV3Instruction, 3 | PROGRAM_ID, 4 | } from "@metaplex-foundation/mpl-token-metadata"; 5 | import { 6 | createInitializeMintInstruction, 7 | MINT_SIZE, 8 | TOKEN_PROGRAM_ID, 9 | } from "@solana/spl-token"; 10 | import { Connection, Keypair, PublicKey, SystemProgram } from "@solana/web3.js"; 11 | import { 12 | buildTransaction, 13 | logBalance, 14 | logNewKeypair, 15 | logNewMint, 16 | logTransaction, 17 | newLogSection, 18 | } from "./util"; 19 | 20 | const connection = new Connection("https://api.devnet.solana.com", { 21 | commitment: "confirmed", 22 | confirmTransactionInitialTimeout: 60000, 23 | }); 24 | 25 | export async function createAccount( 26 | accountName: string, 27 | newAccountKeypair: Keypair, 28 | payerKeypair: Keypair, 29 | ) { 30 | const lamports = await connection.getMinimumBalanceForRentExemption(0); 31 | const createAccountInstruction = SystemProgram.createAccount({ 32 | fromPubkey: payerKeypair.publicKey, 33 | newAccountPubkey: newAccountKeypair.publicKey, 34 | lamports, 35 | space: 0, 36 | programId: SystemProgram.programId, 37 | }); 38 | const createAccountTransaction = await buildTransaction( 39 | connection, 40 | payerKeypair.publicKey, 41 | [payerKeypair, newAccountKeypair], 42 | [createAccountInstruction], 43 | ); 44 | const signature = await connection.sendTransaction(createAccountTransaction); 45 | 46 | newLogSection(); 47 | logNewKeypair(newAccountKeypair); 48 | await logTransaction(connection, signature); 49 | await logBalance(accountName, connection, newAccountKeypair.publicKey); 50 | } 51 | 52 | export async function createToken( 53 | mintKeypair: Keypair, 54 | payerKeypair: Keypair, 55 | tokenName: string, 56 | tokenSymbol: string, 57 | tokenUri: string, 58 | decimals: number, 59 | ) { 60 | // Create the account for the Mint 61 | const createMintAccountInstruction = SystemProgram.createAccount({ 62 | fromPubkey: payerKeypair.publicKey, 63 | newAccountPubkey: mintKeypair.publicKey, 64 | lamports: await connection.getMinimumBalanceForRentExemption(MINT_SIZE), 65 | space: MINT_SIZE, 66 | programId: TOKEN_PROGRAM_ID, 67 | }); 68 | // Initialize that account as a Mint 69 | const initializeMintInstruction = createInitializeMintInstruction( 70 | mintKeypair.publicKey, 71 | decimals, 72 | payerKeypair.publicKey, 73 | payerKeypair.publicKey, 74 | ); 75 | // Create the Metadata account for the Mint 76 | const createMetadataInstruction = createCreateMetadataAccountV3Instruction( 77 | { 78 | metadata: PublicKey.findProgramAddressSync( 79 | [ 80 | Buffer.from("metadata"), 81 | PROGRAM_ID.toBuffer(), 82 | mintKeypair.publicKey.toBuffer(), 83 | ], 84 | PROGRAM_ID, 85 | )[0], 86 | mint: mintKeypair.publicKey, 87 | mintAuthority: payerKeypair.publicKey, 88 | payer: payerKeypair.publicKey, 89 | updateAuthority: payerKeypair.publicKey, 90 | }, 91 | { 92 | createMetadataAccountArgsV3: { 93 | data: { 94 | name: tokenName, 95 | symbol: tokenSymbol, 96 | uri: tokenUri, 97 | creators: null, 98 | sellerFeeBasisPoints: 0, 99 | uses: null, 100 | collection: null, 101 | }, 102 | isMutable: false, 103 | collectionDetails: null, 104 | }, 105 | }, 106 | ); 107 | const tx = await buildTransaction( 108 | connection, 109 | payerKeypair.publicKey, 110 | [payerKeypair, mintKeypair], 111 | [ 112 | createMintAccountInstruction, 113 | initializeMintInstruction, 114 | createMetadataInstruction, 115 | ], 116 | ); 117 | const signature = await connection.sendTransaction(tx); 118 | 119 | newLogSection(); 120 | await logTransaction(connection, signature); 121 | logNewMint(mintKeypair.publicKey, decimals); 122 | } 123 | -------------------------------------------------------------------------------- /tokens/create-token/src/util.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Connection, 3 | Keypair, 4 | PublicKey, 5 | TransactionInstruction, 6 | VersionedTransaction, 7 | TransactionMessage, 8 | AccountInfo, 9 | LAMPORTS_PER_SOL, 10 | } from "@solana/web3.js"; 11 | 12 | export function loadKeypairFromFile(path: string): Keypair { 13 | return Keypair.fromSecretKey( 14 | Buffer.from(JSON.parse(require("fs").readFileSync(path, "utf-8"))), 15 | ); 16 | } 17 | 18 | export function newLogSection() { 19 | console.log("-----------------------------------------------------"); 20 | } 21 | 22 | export async function logAccountInfo(accountInfo: AccountInfo | null) { 23 | console.log("Account Info:"); 24 | console.log(accountInfo); 25 | } 26 | 27 | export function logNewKeypair(keypair: Keypair) { 28 | console.log("Created a new keypair."); 29 | console.log(` New account Public Key: ${keypair.publicKey}`); 30 | } 31 | 32 | export async function logTransaction( 33 | connection: Connection, 34 | signature: string, 35 | ) { 36 | await connection.confirmTransaction(signature); 37 | console.log("Transaction successful."); 38 | console.log(` Transaction signature: ${signature}`); 39 | } 40 | 41 | export async function logBalance( 42 | accountName: string, 43 | connection: Connection, 44 | pubkey: PublicKey, 45 | ) { 46 | const balance = await connection.getBalance(pubkey); 47 | console.log(` ${accountName}:`); 48 | console.log(` Account Pubkey: ${pubkey.toString()} SOL`); 49 | console.log(` Account Balance: ${balance / LAMPORTS_PER_SOL} SOL`); 50 | } 51 | 52 | export function logNewMint(mintPubkey: PublicKey, decimals: number) { 53 | console.log("Created a new mint."); 54 | console.log(` New mint Public Key: ${mintPubkey}`); 55 | console.log(` Mint type: ${decimals === 0 ? "NFT" : "SPL Token"}`); 56 | } 57 | 58 | export async function buildTransaction( 59 | connection: Connection, 60 | payer: PublicKey, 61 | signers: Keypair[], 62 | instructions: TransactionInstruction[], 63 | ): Promise { 64 | let blockhash = await connection 65 | .getLatestBlockhash() 66 | .then((res) => res.blockhash); 67 | 68 | const messageV0 = new TransactionMessage({ 69 | payerKey: payer, 70 | recentBlockhash: blockhash, 71 | instructions, 72 | }).compileToV0Message(); 73 | 74 | const tx = new VersionedTransaction(messageV0); 75 | 76 | signers.forEach((s) => tx.sign([s])); 77 | 78 | return tx; 79 | } 80 | -------------------------------------------------------------------------------- /tokens/create-token/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015"], 4 | "module": "commonjs", 5 | "target": "es6", 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tokens/freezing-tokens/README.md: -------------------------------------------------------------------------------- 1 | # Mint & Freeze Authorities 2 | 3 | > Coming soon! 4 | -------------------------------------------------------------------------------- /tokens/metaplex-expanded/README.md: -------------------------------------------------------------------------------- 1 | # Metaplex Metadata Expanded 2 | 3 | > Coming soon! 4 | -------------------------------------------------------------------------------- /tokens/nft-minter/README.md: -------------------------------------------------------------------------------- 1 | # NFT Minter 2 | 3 | Minting NFTs is exactly the same as 4 | [minting any SPL Token on Solana](../spl-token-minter/), except for immediately 5 | after the actual minting has occurred. 6 | 7 | What does this mean? Well, when you mint SPL Tokens, you can attach a fixed 8 | supply, but in most cases you can continue to mint new tokens at will - 9 | increasing the supply of that token. 10 | 11 | With an NFT, you're supposed to only have **one**. 12 | 13 | So, how do we ensure only one single token can be minted for any NFT? 14 | 15 | --- 16 | 17 | We have to disable minting by changing the Mint Authority on the Mint. 18 | 19 | > The Mint Authority is the account that is permitted to mint new tokens into 20 | > supply. 21 | 22 | If we remove this authority - effectively setting it to `null` - we can disable 23 | minting of new tokens for this Mint. 24 | 25 | > By design, **this is irreversible**. 26 | 27 | --- 28 | 29 | Although we can set this authority to `null` manually, we can also make use of 30 | Metaplex again, this time to mark our NFT as Limited Edition. 31 | 32 | When we use an Edition - such as a Master Edition - for our NFT, we get some 33 | extra metadata associated with our NFT and we also get our Mint Authority 34 | deactivated by delegating this authority to the Master Edition account. 35 | 36 | This will effectively disable future minting, but make sure you understand the 37 | ramifications of having the Master Edition account be the Mint Authority - 38 | rather than setting it permanently to `null`. 39 | -------------------------------------------------------------------------------- /tokens/nft-minter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "main": "yarn run ts-node ./src/main.ts" 4 | }, 5 | "license": "MIT", 6 | "dependencies": { 7 | "@metaplex-foundation/mpl-token-metadata": "^2.5.2", 8 | "@solana/spl-token": "^0.3.7", 9 | "@solana/web3.js": "^1.73.0", 10 | "ts-node": "^10.9.1", 11 | "typescript": "^4.9.4" 12 | }, 13 | "devDependencies": { 14 | "@types/node": "^18.11.18" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tokens/nft-minter/src/main.ts: -------------------------------------------------------------------------------- 1 | import { Keypair } from "@solana/web3.js"; 2 | import { createAccount, createNft, mintNft } from "./tokens"; 3 | import { loadKeypairFromFile } from "./util"; 4 | 5 | const payer = loadKeypairFromFile( 6 | require("os").homedir() + "/.config/solana/id.json", 7 | ); 8 | 9 | const testUserKeypair1 = Keypair.generate(); 10 | const tokenMintKeypair = Keypair.generate(); 11 | 12 | async function tokensScript() { 13 | await createAccount("Test User Keypair #1", testUserKeypair1, payer); 14 | 15 | // NFT 16 | await createNft( 17 | tokenMintKeypair, 18 | payer, 19 | "Homer NFT", 20 | "HOMR", 21 | "https://raw.githubusercontent.com/solana-developers/web3-examples/new-examples/tokens/tokens/.assets/nft.json", 22 | ); 23 | 24 | await mintNft( 25 | tokenMintKeypair.publicKey, 26 | payer, 27 | payer, 28 | testUserKeypair1.publicKey, 29 | ); 30 | } 31 | 32 | tokensScript(); 33 | -------------------------------------------------------------------------------- /tokens/nft-minter/src/tokens.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createCreateMetadataAccountV3Instruction, 3 | createCreateMasterEditionV3Instruction, 4 | PROGRAM_ID, 5 | } from "@metaplex-foundation/mpl-token-metadata"; 6 | import { 7 | AuthorityType, 8 | createAssociatedTokenAccountInstruction, 9 | createInitializeMintInstruction, 10 | createMintToInstruction, 11 | createSetAuthorityInstruction, 12 | getAssociatedTokenAddressSync, 13 | MINT_SIZE, 14 | TOKEN_PROGRAM_ID, 15 | } from "@solana/spl-token"; 16 | import { 17 | Connection, 18 | Keypair, 19 | PublicKey, 20 | SystemProgram, 21 | TransactionInstruction, 22 | } from "@solana/web3.js"; 23 | import { 24 | buildTransaction, 25 | logBalance, 26 | logNewKeypair, 27 | logNewMint, 28 | logTransaction, 29 | newLogSection, 30 | } from "./util"; 31 | 32 | const connection = new Connection("https://api.devnet.solana.com", { 33 | commitment: "confirmed", 34 | confirmTransactionInitialTimeout: 60000, 35 | }); 36 | 37 | export async function createAccount( 38 | accountName: string, 39 | newAccountKeypair: Keypair, 40 | payerKeypair: Keypair, 41 | ) { 42 | const lamports = await connection.getMinimumBalanceForRentExemption(0); 43 | const createAccountInstruction = SystemProgram.createAccount({ 44 | fromPubkey: payerKeypair.publicKey, 45 | newAccountPubkey: newAccountKeypair.publicKey, 46 | lamports, 47 | space: 0, 48 | programId: SystemProgram.programId, 49 | }); 50 | const createAccountTransaction = await buildTransaction( 51 | connection, 52 | payerKeypair.publicKey, 53 | [payerKeypair, newAccountKeypair], 54 | [createAccountInstruction], 55 | ); 56 | const signature = await connection.sendTransaction(createAccountTransaction); 57 | 58 | newLogSection(); 59 | logNewKeypair(newAccountKeypair); 60 | await logTransaction(connection, signature); 61 | await logBalance(accountName, connection, newAccountKeypair.publicKey); 62 | } 63 | 64 | export async function createNft( 65 | mintKeypair: Keypair, 66 | payerKeypair: Keypair, 67 | tokenName: string, 68 | tokenSymbol: string, 69 | tokenUri: string, 70 | ) { 71 | // Create the account for the Mint 72 | const createMintAccountInstruction = SystemProgram.createAccount({ 73 | fromPubkey: payerKeypair.publicKey, 74 | newAccountPubkey: mintKeypair.publicKey, 75 | lamports: await connection.getMinimumBalanceForRentExemption(MINT_SIZE), 76 | space: MINT_SIZE, 77 | programId: TOKEN_PROGRAM_ID, 78 | }); 79 | // Initialize that account as a Mint 80 | const initializeMintInstruction = createInitializeMintInstruction( 81 | mintKeypair.publicKey, 82 | 0, 83 | payerKeypair.publicKey, 84 | payerKeypair.publicKey, 85 | ); 86 | // Create the Metadata account for the Mint 87 | const createMetadataInstruction = createCreateMetadataAccountV3Instruction( 88 | { 89 | metadata: PublicKey.findProgramAddressSync( 90 | [ 91 | Buffer.from("metadata"), 92 | PROGRAM_ID.toBuffer(), 93 | mintKeypair.publicKey.toBuffer(), 94 | ], 95 | PROGRAM_ID, 96 | )[0], 97 | mint: mintKeypair.publicKey, 98 | mintAuthority: payerKeypair.publicKey, 99 | payer: payerKeypair.publicKey, 100 | updateAuthority: payerKeypair.publicKey, 101 | }, 102 | { 103 | createMetadataAccountArgsV3: { 104 | data: { 105 | name: tokenName, 106 | symbol: tokenSymbol, 107 | uri: tokenUri, 108 | creators: null, 109 | sellerFeeBasisPoints: 0, 110 | uses: null, 111 | collection: null, 112 | }, 113 | isMutable: false, 114 | collectionDetails: null, 115 | }, 116 | }, 117 | ); 118 | const tx = await buildTransaction( 119 | connection, 120 | payerKeypair.publicKey, 121 | [payerKeypair, mintKeypair], 122 | [ 123 | createMintAccountInstruction, 124 | initializeMintInstruction, 125 | createMetadataInstruction, 126 | ], 127 | ); 128 | const signature = await connection.sendTransaction(tx); 129 | 130 | newLogSection(); 131 | await logTransaction(connection, signature); 132 | logNewMint(mintKeypair.publicKey, 0); 133 | } 134 | 135 | export async function mintNft( 136 | mintPublicKey: PublicKey, 137 | mintAuthority: Keypair, 138 | payerKeypair: Keypair, 139 | recipientPublicKey: PublicKey, 140 | ) { 141 | newLogSection(); 142 | console.log(`Minting NFT to recipient: ${recipientPublicKey}`); 143 | 144 | // Check to see if their Associated Token Account exists 145 | // If not, create it 146 | // -> Can also use `getOrCreateAssociatedTokenAccount()` 147 | // 148 | const ixList: TransactionInstruction[] = []; 149 | const associatedTokenAddress = getAssociatedTokenAddressSync( 150 | mintPublicKey, 151 | recipientPublicKey, 152 | ); 153 | console.log( 154 | ` Recipient Associated Token Address: ${associatedTokenAddress}`, 155 | ); 156 | const associatedTokenAccountInfo = await connection.getAccountInfo( 157 | associatedTokenAddress, 158 | ); 159 | if ( 160 | !associatedTokenAccountInfo || 161 | associatedTokenAccountInfo.lamports === 0 162 | ) { 163 | ixList.push( 164 | createAssociatedTokenAccountInstruction( 165 | payerKeypair.publicKey, 166 | associatedTokenAddress, 167 | recipientPublicKey, 168 | mintPublicKey, 169 | ), 170 | ); 171 | } 172 | 173 | // Now mint to the recipient's Associated Token Account 174 | // 175 | ixList.push( 176 | createMintToInstruction( 177 | mintPublicKey, 178 | associatedTokenAddress, 179 | mintAuthority.publicKey, 180 | 1, 181 | ), 182 | ); 183 | 184 | // We can make this a Limited Edition NFT through Metaplex, 185 | // which will disable minting by setting the Mint & Freeze Authorities to the 186 | // Edition Account. 187 | // 188 | ixList.push( 189 | createCreateMasterEditionV3Instruction( 190 | { 191 | edition: PublicKey.findProgramAddressSync( 192 | [ 193 | Buffer.from("metadata"), 194 | PROGRAM_ID.toBuffer(), 195 | mintPublicKey.toBuffer(), 196 | Buffer.from("edition"), 197 | ], 198 | PROGRAM_ID, 199 | )[0], 200 | metadata: PublicKey.findProgramAddressSync( 201 | [ 202 | Buffer.from("metadata"), 203 | PROGRAM_ID.toBuffer(), 204 | mintPublicKey.toBuffer(), 205 | ], 206 | PROGRAM_ID, 207 | )[0], 208 | mint: mintPublicKey, 209 | mintAuthority: payerKeypair.publicKey, 210 | payer: payerKeypair.publicKey, 211 | updateAuthority: payerKeypair.publicKey, 212 | }, 213 | { 214 | createMasterEditionArgs: { maxSupply: 1 }, 215 | }, 216 | ), 217 | ); 218 | 219 | // If we don't use Metaplex Editions, we must disable minting manually 220 | // 221 | // ------------------------------------------------------------------- 222 | // ixList.push( 223 | // createSetAuthorityInstruction( 224 | // mintPublicKey, 225 | // mintAuthority.publicKey, 226 | // AuthorityType.MintTokens, 227 | // null, 228 | // ) 229 | // ) 230 | // ixList.push( 231 | // createSetAuthorityInstruction( 232 | // mintPublicKey, 233 | // mintAuthority.publicKey, 234 | // AuthorityType.FreezeAccount, 235 | // null, 236 | // ) 237 | // ) 238 | 239 | const tx = await buildTransaction( 240 | connection, 241 | payerKeypair.publicKey, 242 | [mintAuthority, payerKeypair], 243 | ixList, 244 | ); 245 | const signature = await connection.sendTransaction(tx); 246 | await logTransaction(connection, signature); 247 | } 248 | -------------------------------------------------------------------------------- /tokens/nft-minter/src/util.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Connection, 3 | Keypair, 4 | PublicKey, 5 | TransactionInstruction, 6 | VersionedTransaction, 7 | TransactionMessage, 8 | AccountInfo, 9 | LAMPORTS_PER_SOL, 10 | } from "@solana/web3.js"; 11 | 12 | export function loadKeypairFromFile(path: string): Keypair { 13 | return Keypair.fromSecretKey( 14 | Buffer.from(JSON.parse(require("fs").readFileSync(path, "utf-8"))), 15 | ); 16 | } 17 | 18 | export function newLogSection() { 19 | console.log("-----------------------------------------------------"); 20 | } 21 | 22 | export async function logAccountInfo(accountInfo: AccountInfo | null) { 23 | console.log("Account Info:"); 24 | console.log(accountInfo); 25 | } 26 | 27 | export function logNewKeypair(keypair: Keypair) { 28 | console.log("Created a new keypair."); 29 | console.log(` New account Public Key: ${keypair.publicKey}`); 30 | } 31 | 32 | export async function logTransaction( 33 | connection: Connection, 34 | signature: string, 35 | ) { 36 | await connection.confirmTransaction(signature); 37 | console.log("Transaction successful."); 38 | console.log(` Transaction signature: ${signature}`); 39 | } 40 | 41 | export async function logBalance( 42 | accountName: string, 43 | connection: Connection, 44 | pubkey: PublicKey, 45 | ) { 46 | const balance = await connection.getBalance(pubkey); 47 | console.log(` ${accountName}:`); 48 | console.log(` Account Pubkey: ${pubkey.toString()} SOL`); 49 | console.log(` Account Balance: ${balance / LAMPORTS_PER_SOL} SOL`); 50 | } 51 | 52 | export function logNewMint(mintPubkey: PublicKey, decimals: number) { 53 | console.log("Created a new mint."); 54 | console.log(` New mint Public Key: ${mintPubkey}`); 55 | console.log(` Mint type: ${decimals === 0 ? "NFT" : "SPL Token"}`); 56 | } 57 | 58 | export async function buildTransaction( 59 | connection: Connection, 60 | payer: PublicKey, 61 | signers: Keypair[], 62 | instructions: TransactionInstruction[], 63 | ): Promise { 64 | let blockhash = await connection 65 | .getLatestBlockhash() 66 | .then((res) => res.blockhash); 67 | 68 | const messageV0 = new TransactionMessage({ 69 | payerKey: payer, 70 | recentBlockhash: blockhash, 71 | instructions, 72 | }).compileToV0Message(); 73 | 74 | const tx = new VersionedTransaction(messageV0); 75 | 76 | signers.forEach((s) => tx.sign([s])); 77 | 78 | return tx; 79 | } 80 | -------------------------------------------------------------------------------- /tokens/nft-minter/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015"], 4 | "module": "commonjs", 5 | "target": "es6", 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tokens/spl-token-minter/README.md: -------------------------------------------------------------------------------- 1 | # SPL Token Minter 2 | -------------------------------------------------------------------------------- /tokens/spl-token-minter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "main": "yarn run ts-node ./src/main.ts" 4 | }, 5 | "license": "MIT", 6 | "dependencies": { 7 | "@metaplex-foundation/mpl-token-metadata": "^2.5.2", 8 | "@solana/spl-token": "^0.3.7", 9 | "@solana/web3.js": "^1.73.0", 10 | "ts-node": "^10.9.1", 11 | "typescript": "^4.9.4" 12 | }, 13 | "devDependencies": { 14 | "@types/node": "^18.11.18" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tokens/spl-token-minter/src/main.ts: -------------------------------------------------------------------------------- 1 | import { Keypair } from "@solana/web3.js"; 2 | import { createAccount, createSplToken, mintSplTokens } from "./tokens"; 3 | import { loadKeypairFromFile } from "./util"; 4 | 5 | const payer = loadKeypairFromFile( 6 | require("os").homedir() + "/.config/solana/id.json", 7 | ); 8 | 9 | const testUserKeypair1 = Keypair.generate(); 10 | const tokenMintKeypair = Keypair.generate(); 11 | 12 | async function tokensScript() { 13 | await createAccount("Test User Keypair #1", testUserKeypair1, payer); 14 | 15 | // SPL Token 16 | await createSplToken( 17 | tokenMintKeypair, 18 | payer, 19 | "Solana Gold", 20 | "GOLDSOL", 21 | "https://raw.githubusercontent.com/solana-developers/web3-examples/new-examples/tokens/tokens/.assets/spl-token.json", 22 | ); 23 | 24 | await mintSplTokens( 25 | tokenMintKeypair.publicKey, 26 | payer, 27 | payer, 28 | testUserKeypair1.publicKey, 29 | 40, 30 | ); 31 | await mintSplTokens( 32 | tokenMintKeypair.publicKey, 33 | payer, 34 | payer, 35 | testUserKeypair1.publicKey, 36 | 30, 37 | ); 38 | } 39 | 40 | tokensScript(); 41 | -------------------------------------------------------------------------------- /tokens/spl-token-minter/src/tokens.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createCreateMetadataAccountV3Instruction, 3 | PROGRAM_ID, 4 | } from "@metaplex-foundation/mpl-token-metadata"; 5 | import { 6 | createAssociatedTokenAccountInstruction, 7 | createInitializeMintInstruction, 8 | createMintToInstruction, 9 | getAssociatedTokenAddressSync, 10 | MINT_SIZE, 11 | TOKEN_PROGRAM_ID, 12 | } from "@solana/spl-token"; 13 | import { 14 | Connection, 15 | Keypair, 16 | PublicKey, 17 | SystemProgram, 18 | TransactionInstruction, 19 | } from "@solana/web3.js"; 20 | import { 21 | buildTransaction, 22 | logBalance, 23 | logNewKeypair, 24 | logNewMint, 25 | logTransaction, 26 | newLogSection, 27 | } from "./util"; 28 | 29 | const connection = new Connection("https://api.devnet.solana.com", { 30 | commitment: "confirmed", 31 | confirmTransactionInitialTimeout: 60000, 32 | }); 33 | 34 | export async function createAccount( 35 | accountName: string, 36 | newAccountKeypair: Keypair, 37 | payerKeypair: Keypair, 38 | ) { 39 | const lamports = await connection.getMinimumBalanceForRentExemption(0); 40 | const createAccountInstruction = SystemProgram.createAccount({ 41 | fromPubkey: payerKeypair.publicKey, 42 | newAccountPubkey: newAccountKeypair.publicKey, 43 | lamports, 44 | space: 0, 45 | programId: SystemProgram.programId, 46 | }); 47 | const createAccountTransaction = await buildTransaction( 48 | connection, 49 | payerKeypair.publicKey, 50 | [payerKeypair, newAccountKeypair], 51 | [createAccountInstruction], 52 | ); 53 | const signature = await connection.sendTransaction(createAccountTransaction); 54 | 55 | newLogSection(); 56 | logNewKeypair(newAccountKeypair); 57 | await logTransaction(connection, signature); 58 | await logBalance(accountName, connection, newAccountKeypair.publicKey); 59 | } 60 | 61 | export async function createSplToken( 62 | mintKeypair: Keypair, 63 | payerKeypair: Keypair, 64 | tokenName: string, 65 | tokenSymbol: string, 66 | tokenUri: string, 67 | ) { 68 | // Create the account for the Mint 69 | const createMintAccountInstruction = SystemProgram.createAccount({ 70 | fromPubkey: payerKeypair.publicKey, 71 | newAccountPubkey: mintKeypair.publicKey, 72 | lamports: await connection.getMinimumBalanceForRentExemption(MINT_SIZE), 73 | space: MINT_SIZE, 74 | programId: TOKEN_PROGRAM_ID, 75 | }); 76 | // Initialize that account as a Mint 77 | const initializeMintInstruction = createInitializeMintInstruction( 78 | mintKeypair.publicKey, 79 | 9, 80 | payerKeypair.publicKey, 81 | payerKeypair.publicKey, 82 | ); 83 | // Create the Metadata account for the Mint 84 | const createMetadataInstruction = createCreateMetadataAccountV3Instruction( 85 | { 86 | metadata: PublicKey.findProgramAddressSync( 87 | [ 88 | Buffer.from("metadata"), 89 | PROGRAM_ID.toBuffer(), 90 | mintKeypair.publicKey.toBuffer(), 91 | ], 92 | PROGRAM_ID, 93 | )[0], 94 | mint: mintKeypair.publicKey, 95 | mintAuthority: payerKeypair.publicKey, 96 | payer: payerKeypair.publicKey, 97 | updateAuthority: payerKeypair.publicKey, 98 | }, 99 | { 100 | createMetadataAccountArgsV3: { 101 | data: { 102 | name: tokenName, 103 | symbol: tokenSymbol, 104 | uri: tokenUri, 105 | creators: null, 106 | sellerFeeBasisPoints: 0, 107 | uses: null, 108 | collection: null, 109 | }, 110 | isMutable: false, 111 | collectionDetails: null, 112 | }, 113 | }, 114 | ); 115 | const tx = await buildTransaction( 116 | connection, 117 | payerKeypair.publicKey, 118 | [payerKeypair, mintKeypair], 119 | [ 120 | createMintAccountInstruction, 121 | initializeMintInstruction, 122 | createMetadataInstruction, 123 | ], 124 | ); 125 | const signature = await connection.sendTransaction(tx); 126 | 127 | newLogSection(); 128 | await logTransaction(connection, signature); 129 | logNewMint(mintKeypair.publicKey, 9); 130 | } 131 | 132 | export async function mintSplTokens( 133 | mintPublicKey: PublicKey, 134 | mintAuthority: Keypair, 135 | payerKeypair: Keypair, 136 | recipientPublicKey: PublicKey, 137 | quantity: number, 138 | ) { 139 | newLogSection(); 140 | console.log(`Minting ${quantity} tokens to recipient: ${recipientPublicKey}`); 141 | 142 | // Check to see if their Associated Token Account exists 143 | // If not, create it 144 | // -> Can also use `getOrCreateAssociatedTokenAccount()` 145 | // 146 | const ixList: TransactionInstruction[] = []; 147 | const associatedTokenAddress = getAssociatedTokenAddressSync( 148 | mintPublicKey, 149 | recipientPublicKey, 150 | ); 151 | console.log( 152 | ` Recipient Associated Token Address: ${associatedTokenAddress}`, 153 | ); 154 | const associatedTokenAccountInfo = await connection.getAccountInfo( 155 | associatedTokenAddress, 156 | ); 157 | if ( 158 | !associatedTokenAccountInfo || 159 | associatedTokenAccountInfo.lamports === 0 160 | ) { 161 | ixList.push( 162 | createAssociatedTokenAccountInstruction( 163 | payerKeypair.publicKey, 164 | associatedTokenAddress, 165 | recipientPublicKey, 166 | mintPublicKey, 167 | ), 168 | ); 169 | } 170 | 171 | // Now mint to the recipient's Associated Token Account 172 | // 173 | ixList.push( 174 | createMintToInstruction( 175 | mintPublicKey, 176 | associatedTokenAddress, 177 | mintAuthority.publicKey, 178 | quantity, 179 | ), 180 | ); 181 | 182 | const tx = await buildTransaction( 183 | connection, 184 | payerKeypair.publicKey, 185 | [mintAuthority, payerKeypair], 186 | ixList, 187 | ); 188 | const signature = await connection.sendTransaction(tx); 189 | await logTransaction(connection, signature); 190 | } 191 | -------------------------------------------------------------------------------- /tokens/spl-token-minter/src/util.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Connection, 3 | Keypair, 4 | PublicKey, 5 | TransactionInstruction, 6 | VersionedTransaction, 7 | TransactionMessage, 8 | AccountInfo, 9 | LAMPORTS_PER_SOL, 10 | } from "@solana/web3.js"; 11 | 12 | export function loadKeypairFromFile(path: string): Keypair { 13 | return Keypair.fromSecretKey( 14 | Buffer.from(JSON.parse(require("fs").readFileSync(path, "utf-8"))), 15 | ); 16 | } 17 | 18 | export function newLogSection() { 19 | console.log("-----------------------------------------------------"); 20 | } 21 | 22 | export async function logAccountInfo(accountInfo: AccountInfo | null) { 23 | console.log("Account Info:"); 24 | console.log(accountInfo); 25 | } 26 | 27 | export function logNewKeypair(keypair: Keypair) { 28 | console.log("Created a new keypair."); 29 | console.log(` New account Public Key: ${keypair.publicKey}`); 30 | } 31 | 32 | export async function logTransaction( 33 | connection: Connection, 34 | signature: string, 35 | ) { 36 | await connection.confirmTransaction(signature); 37 | console.log("Transaction successful."); 38 | console.log(` Transaction signature: ${signature}`); 39 | } 40 | 41 | export async function logBalance( 42 | accountName: string, 43 | connection: Connection, 44 | pubkey: PublicKey, 45 | ) { 46 | const balance = await connection.getBalance(pubkey); 47 | console.log(` ${accountName}:`); 48 | console.log(` Account Pubkey: ${pubkey.toString()} SOL`); 49 | console.log(` Account Balance: ${balance / LAMPORTS_PER_SOL} SOL`); 50 | } 51 | 52 | export function logNewMint(mintPubkey: PublicKey, decimals: number) { 53 | console.log("Created a new mint."); 54 | console.log(` New mint Public Key: ${mintPubkey}`); 55 | console.log(` Mint type: ${decimals === 0 ? "NFT" : "SPL Token"}`); 56 | } 57 | 58 | export async function buildTransaction( 59 | connection: Connection, 60 | payer: PublicKey, 61 | signers: Keypair[], 62 | instructions: TransactionInstruction[], 63 | ): Promise { 64 | let blockhash = await connection 65 | .getLatestBlockhash() 66 | .then((res) => res.blockhash); 67 | 68 | const messageV0 = new TransactionMessage({ 69 | payerKey: payer, 70 | recentBlockhash: blockhash, 71 | instructions, 72 | }).compileToV0Message(); 73 | 74 | const tx = new VersionedTransaction(messageV0); 75 | 76 | signers.forEach((s) => tx.sign([s])); 77 | 78 | return tx; 79 | } 80 | -------------------------------------------------------------------------------- /tokens/spl-token-minter/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015"], 4 | "module": "commonjs", 5 | "target": "es6", 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tokens/token-2022/README.md: -------------------------------------------------------------------------------- 1 | # Token 2022 2 | 3 | See the documentation here: 4 | [Solana Token 2022](https://spl.solana.com/token-2022) 5 | 6 | - Token with Transfer Fees. 7 | - Interest bearing Tokens 8 | -------------------------------------------------------------------------------- /tokens/token-2022/close-authority/README.md: -------------------------------------------------------------------------------- 1 | ## Token with mint close authority 2 | 3 | Creates a Token 2022 Token with an authority to close a mint. `yarn main` or 4 | `npm run main` 5 | -------------------------------------------------------------------------------- /tokens/token-2022/close-authority/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "main": "yarn run ts-node ./src/main.ts" 4 | }, 5 | "license": "MIT", 6 | "dependencies": { 7 | "@metaplex-foundation/mpl-token-metadata": "^2.5.2", 8 | "@solana/spl-token": "^0.3.7", 9 | "@solana/web3.js": "^1.73.0", 10 | "ts-node": "^10.9.1", 11 | "typescript": "^4.9.4" 12 | }, 13 | "devDependencies": { 14 | "@types/node": "^18.11.18" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tokens/token-2022/close-authority/src/main.ts: -------------------------------------------------------------------------------- 1 | import { 2 | closeAccount, 3 | createInitializeMintInstruction, 4 | createInitializeMintCloseAuthorityInstruction, 5 | getMintLen, 6 | ExtensionType, 7 | TOKEN_2022_PROGRAM_ID, 8 | } from "@solana/spl-token"; 9 | import { 10 | clusterApiUrl, 11 | sendAndConfirmTransaction, 12 | Connection, 13 | Keypair, 14 | SystemProgram, 15 | Transaction, 16 | LAMPORTS_PER_SOL, 17 | } from "@solana/web3.js"; 18 | 19 | (async () => { 20 | const payer = Keypair.generate(); 21 | 22 | const mintKeypair = Keypair.generate(); 23 | const mint = mintKeypair.publicKey; 24 | const mintAuthority = Keypair.generate(); 25 | const freezeAuthority = Keypair.generate(); 26 | const closeAuthority = Keypair.generate(); 27 | 28 | const connection = new Connection(clusterApiUrl("devnet"), "confirmed"); 29 | 30 | const airdropSignature = await connection.requestAirdrop( 31 | payer.publicKey, 32 | 2 * LAMPORTS_PER_SOL, 33 | ); 34 | await connection.confirmTransaction({ 35 | signature: airdropSignature, 36 | ...(await connection.getLatestBlockhash()), 37 | }); 38 | 39 | const extensions = [ExtensionType.MintCloseAuthority]; 40 | const mintLen = getMintLen(extensions); 41 | const lamports = await connection.getMinimumBalanceForRentExemption(mintLen); 42 | 43 | const transaction = new Transaction().add( 44 | SystemProgram.createAccount({ 45 | fromPubkey: payer.publicKey, 46 | newAccountPubkey: mint, 47 | space: mintLen, 48 | lamports, 49 | programId: TOKEN_2022_PROGRAM_ID, 50 | }), 51 | createInitializeMintCloseAuthorityInstruction( 52 | mint, 53 | closeAuthority.publicKey, 54 | TOKEN_2022_PROGRAM_ID, 55 | ), 56 | createInitializeMintInstruction( 57 | mint, 58 | 9, 59 | mintAuthority.publicKey, 60 | freezeAuthority.publicKey, 61 | TOKEN_2022_PROGRAM_ID, 62 | ), 63 | ); 64 | const tx = await sendAndConfirmTransaction(connection, transaction, [ 65 | payer, 66 | mintKeypair, 67 | ]); 68 | console.log("Your transaction signature: ", tx); 69 | console.log("Mint Keypair: ", mint.toBase58()); 70 | })(); 71 | -------------------------------------------------------------------------------- /tokens/token-2022/close-authority/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015"], 4 | "module": "commonjs", 5 | "target": "es6", 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tokens/token-2022/create-account-with-memo-on-transfer/README.MD: -------------------------------------------------------------------------------- 1 | ## Token example for Required Memo on Transfer 2 | 3 | Create a Token 2022 example for (Required Memo on Transfer). `yarn main` or 4 | `npm run main` 5 | -------------------------------------------------------------------------------- /tokens/token-2022/create-account-with-memo-on-transfer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "main": "ts-node ./src/main.ts" 4 | }, 5 | "license": "MIT", 6 | "dependencies": { 7 | "@metaplex-foundation/mpl-token-metadata": "^2.5.2", 8 | "@solana/spl-token": "^0.3.7", 9 | "@solana/web3.js": "^1.73.0", 10 | "typescript": "^4.9.4" 11 | }, 12 | "devDependencies": { 13 | "@types/node": "^18.11.18", 14 | "ts-node": "^10.9.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tokens/token-2022/create-account-with-memo-on-transfer/src/main.ts: -------------------------------------------------------------------------------- 1 | import { 2 | clusterApiUrl, 3 | sendAndConfirmTransaction, 4 | Connection, 5 | Keypair, 6 | SystemProgram, 7 | Transaction, 8 | LAMPORTS_PER_SOL, 9 | } from "@solana/web3.js"; 10 | import { 11 | createMint, 12 | createEnableRequiredMemoTransfersInstruction, 13 | createInitializeAccountInstruction, 14 | disableRequiredMemoTransfers, 15 | enableRequiredMemoTransfers, 16 | getAccountLen, 17 | ExtensionType, 18 | TOKEN_2022_PROGRAM_ID, 19 | } from "@solana/spl-token"; 20 | 21 | (async () => { 22 | const connection = new Connection(clusterApiUrl("devnet"), "confirmed"); 23 | 24 | const payer = Keypair.generate(); 25 | const airdropSignature = await connection.requestAirdrop( 26 | payer.publicKey, 27 | 2 * LAMPORTS_PER_SOL, 28 | ); 29 | await connection.confirmTransaction({ 30 | signature: airdropSignature, 31 | ...(await connection.getLatestBlockhash()), 32 | }); 33 | 34 | const mintAuthority = Keypair.generate(); 35 | const decimals = 9; 36 | const mint = await createMint( 37 | connection, 38 | payer, 39 | mintAuthority.publicKey, 40 | mintAuthority.publicKey, 41 | decimals, 42 | undefined, 43 | undefined, 44 | TOKEN_2022_PROGRAM_ID, 45 | ); 46 | 47 | const accountLen = getAccountLen([ExtensionType.MemoTransfer]); 48 | const lamports = await connection.getMinimumBalanceForRentExemption( 49 | accountLen, 50 | ); 51 | const owner = Keypair.generate(); 52 | const destinationKeypair = Keypair.generate(); 53 | const destination = destinationKeypair.publicKey; 54 | 55 | const transaction = new Transaction().add( 56 | SystemProgram.createAccount({ 57 | fromPubkey: payer.publicKey, 58 | newAccountPubkey: destination, 59 | space: accountLen, 60 | lamports, 61 | programId: TOKEN_2022_PROGRAM_ID, 62 | }), 63 | // Create account with required memo transfers 64 | createInitializeAccountInstruction( 65 | destination, 66 | mint, 67 | owner.publicKey, 68 | TOKEN_2022_PROGRAM_ID, 69 | ), 70 | // enable memo instruction after creating account instruction 71 | createEnableRequiredMemoTransfersInstruction( 72 | destination, 73 | owner.publicKey, 74 | [], 75 | TOKEN_2022_PROGRAM_ID, 76 | ), 77 | ); 78 | 79 | const signature = await sendAndConfirmTransaction( 80 | connection, 81 | transaction, 82 | [payer, owner, destinationKeypair], 83 | undefined, 84 | ); 85 | console.log("transaction signature key:", signature); 86 | 87 | //Enabling required memo transfers 88 | const enableRequiredMemoSignature = await enableRequiredMemoTransfers( 89 | connection, 90 | payer, 91 | destination, 92 | owner, 93 | [], 94 | undefined, 95 | TOKEN_2022_PROGRAM_ID, 96 | ); 97 | console.log("enableRequiredMemoSignature key:", enableRequiredMemoSignature); 98 | //disabling required memo transfers 99 | const disableRequiredMemoSignature = await disableRequiredMemoTransfers( 100 | connection, 101 | payer, 102 | destination, 103 | owner, 104 | [], 105 | undefined, 106 | TOKEN_2022_PROGRAM_ID, 107 | ); 108 | console.log( 109 | "disableRequiredMemoSignature key:", 110 | disableRequiredMemoSignature, 111 | ); 112 | })(); 113 | -------------------------------------------------------------------------------- /tokens/token-2022/create-account-with-memo-on-transfer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015"], 4 | "module": "CommonJS", 5 | "target": "es6", 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tokens/token-2022/default-account-state/README.md: -------------------------------------------------------------------------------- 1 | ## Token with default account state 2 | 3 | Creates a Token 2022 Token with default account state, meaning all Token 4 | accounts can be frozen by default. This enables a restricted usage for your 5 | token. `yarn main` or `npm run main` 6 | -------------------------------------------------------------------------------- /tokens/token-2022/default-account-state/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "main": "yarn run ts-node ./src/main.ts" 4 | }, 5 | "license": "MIT", 6 | "dependencies": { 7 | "@metaplex-foundation/mpl-token-metadata": "^2.5.2", 8 | "@solana/spl-token": "^0.3.7", 9 | "@solana/web3.js": "^1.73.0", 10 | "ts-node": "^10.9.1", 11 | "typescript": "^4.9.4" 12 | }, 13 | "devDependencies": { 14 | "@types/node": "^18.11.18" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tokens/token-2022/default-account-state/src/main.ts: -------------------------------------------------------------------------------- 1 | import { 2 | clusterApiUrl, 3 | sendAndConfirmTransaction, 4 | Connection, 5 | Keypair, 6 | SystemProgram, 7 | Transaction, 8 | LAMPORTS_PER_SOL, 9 | } from "@solana/web3.js"; 10 | import { 11 | AccountState, 12 | createInitializeMintInstruction, 13 | createInitializeDefaultAccountStateInstruction, 14 | getMintLen, 15 | updateDefaultAccountState, 16 | ExtensionType, 17 | TOKEN_2022_PROGRAM_ID, 18 | } from "@solana/spl-token"; 19 | 20 | (async () => { 21 | const payer = Keypair.generate(); 22 | 23 | const mintAuthority = Keypair.generate(); 24 | const freezeAuthority = Keypair.generate(); 25 | const mintKeypair = Keypair.generate(); 26 | const mint = mintKeypair.publicKey; 27 | 28 | const extensions = [ExtensionType.DefaultAccountState]; 29 | const mintLen = getMintLen(extensions); 30 | const decimals = 9; 31 | 32 | const connection = new Connection(clusterApiUrl("devnet"), "confirmed"); 33 | 34 | const airdropSignature = await connection.requestAirdrop( 35 | payer.publicKey, 36 | 2 * LAMPORTS_PER_SOL, 37 | ); 38 | await connection.confirmTransaction({ 39 | signature: airdropSignature, 40 | ...(await connection.getLatestBlockhash()), 41 | }); 42 | 43 | const defaultState = AccountState.Frozen; 44 | 45 | const lamports = await connection.getMinimumBalanceForRentExemption(mintLen); 46 | const transaction = new Transaction().add( 47 | SystemProgram.createAccount({ 48 | fromPubkey: payer.publicKey, 49 | newAccountPubkey: mint, 50 | space: mintLen, 51 | lamports, 52 | programId: TOKEN_2022_PROGRAM_ID, 53 | }), 54 | createInitializeDefaultAccountStateInstruction( 55 | mint, 56 | defaultState, 57 | TOKEN_2022_PROGRAM_ID, 58 | ), 59 | createInitializeMintInstruction( 60 | mint, 61 | decimals, 62 | mintAuthority.publicKey, 63 | freezeAuthority.publicKey, 64 | TOKEN_2022_PROGRAM_ID, 65 | ), 66 | ); 67 | const signature = await sendAndConfirmTransaction(connection, transaction, [ 68 | payer, 69 | mintKeypair, 70 | ]); 71 | console.log("Your creation transaction signature: ", signature); 72 | console.log("Your mint: ", mint.toBase58()); 73 | 74 | // Update the default account state 75 | const signature2 = await updateDefaultAccountState( 76 | connection, 77 | payer, 78 | mint, 79 | AccountState.Initialized, 80 | freezeAuthority, 81 | [], 82 | undefined, 83 | TOKEN_2022_PROGRAM_ID, 84 | ); 85 | console.log("Your update account state transaction signature: ", signature2); 86 | })(); 87 | -------------------------------------------------------------------------------- /tokens/token-2022/default-account-state/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015"], 4 | "module": "commonjs", 5 | "target": "es6", 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tokens/token-2022/immutable-owner/README.md: -------------------------------------------------------------------------------- 1 | ## Token with immutable owner 2 | 3 | Creates a Token 2022 Token with an Immutable owner `yarn main` or `npm run main` 4 | -------------------------------------------------------------------------------- /tokens/token-2022/immutable-owner/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "main": "yarn run ts-node ./src/main.ts" 4 | }, 5 | "license": "MIT", 6 | "dependencies": { 7 | "@metaplex-foundation/mpl-token-metadata": "^2.5.2", 8 | "@solana/spl-token": "^0.3.7", 9 | "@solana/web3.js": "^1.73.0", 10 | "ts-node": "^10.9.1", 11 | "typescript": "^4.9.4" 12 | }, 13 | "devDependencies": { 14 | "@types/node": "^18.11.18" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tokens/token-2022/immutable-owner/src/main.ts: -------------------------------------------------------------------------------- 1 | import { 2 | clusterApiUrl, 3 | sendAndConfirmTransaction, 4 | Connection, 5 | Keypair, 6 | SystemProgram, 7 | Transaction, 8 | LAMPORTS_PER_SOL, 9 | } from "@solana/web3.js"; 10 | import { 11 | createAccount, 12 | createMint, 13 | createInitializeImmutableOwnerInstruction, 14 | createInitializeAccountInstruction, 15 | getAccountLen, 16 | ExtensionType, 17 | TOKEN_2022_PROGRAM_ID, 18 | } from "@solana/spl-token"; 19 | 20 | (async () => { 21 | const connection = new Connection(clusterApiUrl("devnet"), "confirmed"); 22 | 23 | const payer = Keypair.generate(); 24 | const airdropSignature = await connection.requestAirdrop( 25 | payer.publicKey, 26 | 2 * LAMPORTS_PER_SOL, 27 | ); 28 | await connection.confirmTransaction({ 29 | signature: airdropSignature, 30 | ...(await connection.getLatestBlockhash()), 31 | }); 32 | 33 | const mintAuthority = Keypair.generate(); 34 | const decimals = 9; 35 | const mint = await createMint( 36 | connection, 37 | payer, 38 | mintAuthority.publicKey, 39 | mintAuthority.publicKey, 40 | decimals, 41 | undefined, 42 | undefined, 43 | TOKEN_2022_PROGRAM_ID, 44 | ); 45 | 46 | const accountLen = getAccountLen([ExtensionType.ImmutableOwner]); 47 | const lamports = await connection.getMinimumBalanceForRentExemption( 48 | accountLen, 49 | ); 50 | 51 | const owner = Keypair.generate(); 52 | const accountKeypair = Keypair.generate(); 53 | const account = accountKeypair.publicKey; 54 | const transaction = new Transaction().add( 55 | SystemProgram.createAccount({ 56 | fromPubkey: payer.publicKey, 57 | newAccountPubkey: account, 58 | space: accountLen, 59 | lamports, 60 | programId: TOKEN_2022_PROGRAM_ID, 61 | }), 62 | createInitializeImmutableOwnerInstruction(account, TOKEN_2022_PROGRAM_ID), 63 | createInitializeAccountInstruction( 64 | account, 65 | mint, 66 | owner.publicKey, 67 | TOKEN_2022_PROGRAM_ID, 68 | ), 69 | ); 70 | const signature = await sendAndConfirmTransaction(connection, transaction, [ 71 | payer, 72 | accountKeypair, 73 | ]); 74 | 75 | console.log("Your transaction signature: ", signature); 76 | console.log("Your mint: ", mint.toBase58()); 77 | 78 | // Create ATA with immutable owner 79 | const newATA = await createAccount( 80 | connection, 81 | payer, 82 | mint, 83 | owner.publicKey, 84 | undefined, 85 | undefined, 86 | TOKEN_2022_PROGRAM_ID, 87 | ); 88 | console.log("New ATA Adress: ", newATA.toBase58()); 89 | })(); 90 | -------------------------------------------------------------------------------- /tokens/token-2022/immutable-owner/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015"], 4 | "module": "commonjs", 5 | "target": "es6", 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tokens/token-2022/interest-bearing/README.md: -------------------------------------------------------------------------------- 1 | ## Interest Bearing Token 2 | 3 | Creates an Interest Bearing Token 2022 Token `yarn main` or `npm run main` 4 | -------------------------------------------------------------------------------- /tokens/token-2022/interest-bearing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "main": "yarn run ts-node ./src/main.ts" 4 | }, 5 | "license": "MIT", 6 | "dependencies": { 7 | "@metaplex-foundation/mpl-token-metadata": "^2.5.2", 8 | "@solana/spl-token": "^0.3.7", 9 | "@solana/web3.js": "^1.73.0", 10 | "ts-node": "^10.9.1", 11 | "typescript": "^4.9.4" 12 | }, 13 | "devDependencies": { 14 | "@types/node": "^18.11.18" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tokens/token-2022/interest-bearing/src/main.ts: -------------------------------------------------------------------------------- 1 | import { 2 | clusterApiUrl, 3 | Connection, 4 | Keypair, 5 | LAMPORTS_PER_SOL, 6 | } from "@solana/web3.js"; 7 | import { 8 | createInterestBearingMint, 9 | updateRateInterestBearingMint, 10 | TOKEN_2022_PROGRAM_ID, 11 | } from "@solana/spl-token"; 12 | 13 | (async () => { 14 | const connection = new Connection(clusterApiUrl("devnet"), "confirmed"); 15 | 16 | const payer = Keypair.generate(); 17 | const airdropSignature = await connection.requestAirdrop( 18 | payer.publicKey, 19 | 2 * LAMPORTS_PER_SOL, 20 | ); 21 | await connection.confirmTransaction({ 22 | signature: airdropSignature, 23 | ...(await connection.getLatestBlockhash()), 24 | }); 25 | 26 | const mintAuthority = Keypair.generate(); 27 | const freezeAuthority = Keypair.generate(); 28 | const rateAuthority = Keypair.generate(); 29 | const mintKeypair = Keypair.generate(); 30 | const rate = 10; 31 | const decimals = 9; 32 | const mint = await createInterestBearingMint( 33 | connection, 34 | payer, 35 | mintAuthority.publicKey, 36 | freezeAuthority.publicKey, 37 | rateAuthority.publicKey, 38 | rate, 39 | decimals, 40 | mintKeypair, 41 | undefined, 42 | TOKEN_2022_PROGRAM_ID, 43 | ); 44 | 45 | // Update rate 46 | const updatedRate = 50; 47 | const updatedMint = await updateRateInterestBearingMint( 48 | connection, 49 | payer, 50 | mint, 51 | rateAuthority, 52 | updatedRate, 53 | [], 54 | undefined, 55 | TOKEN_2022_PROGRAM_ID, 56 | ); 57 | console.log( 58 | "Your transaction signature for updating the Token Rate", 59 | updatedMint, 60 | ); 61 | 62 | console.log("Your Token mint PublicKey", mintKeypair.publicKey.toBase58()); 63 | })(); 64 | -------------------------------------------------------------------------------- /tokens/token-2022/interest-bearing/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015"], 4 | "module": "commonjs", 5 | "target": "es6", 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tokens/token-2022/non-transferable-token/README.MD: -------------------------------------------------------------------------------- 1 | ## Non transferable Token example 2 | 3 | Create a Token 2022 example for (Non transferable Token). `yarn main` or 4 | `npm run main` 5 | -------------------------------------------------------------------------------- /tokens/token-2022/non-transferable-token/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "main": "ts-node ./src/main.ts" 4 | }, 5 | "license": "MIT", 6 | "dependencies": { 7 | "@metaplex-foundation/mpl-token-metadata": "^2.5.2", 8 | "@solana/spl-token": "^0.3.7", 9 | "@solana/web3.js": "^1.73.0", 10 | "typescript": "^4.9.4" 11 | }, 12 | "devDependencies": { 13 | "@types/node": "^18.11.18", 14 | "ts-node": "^10.9.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tokens/token-2022/non-transferable-token/src/main.ts: -------------------------------------------------------------------------------- 1 | import { 2 | clusterApiUrl, 3 | sendAndConfirmTransaction, 4 | Connection, 5 | Keypair, 6 | SystemProgram, 7 | Transaction, 8 | LAMPORTS_PER_SOL, 9 | } from "@solana/web3.js"; 10 | import { 11 | createInitializeNonTransferableMintInstruction, 12 | createInitializeMintInstruction, 13 | getMintLen, 14 | ExtensionType, 15 | TOKEN_2022_PROGRAM_ID, 16 | } from "@solana/spl-token"; 17 | 18 | (async () => { 19 | const connection = new Connection(clusterApiUrl("devnet"), "confirmed"); 20 | 21 | const payer = Keypair.generate(); 22 | const airdropSignature = await connection.requestAirdrop( 23 | payer.publicKey, 24 | 2 * LAMPORTS_PER_SOL, 25 | ); 26 | await connection.confirmTransaction({ 27 | signature: airdropSignature, 28 | ...(await connection.getLatestBlockhash()), 29 | }); 30 | 31 | const mintAuthority = Keypair.generate(); 32 | const decimals = 9; 33 | 34 | const mintKeypair = Keypair.generate(); 35 | const mint = mintKeypair.publicKey; 36 | 37 | //one time issuing token for use, frezze and burn 38 | const mintLen = getMintLen([ExtensionType.NonTransferable]); 39 | 40 | const lamports = await connection.getMinimumBalanceForRentExemption(mintLen); 41 | 42 | const transaction = new Transaction().add( 43 | SystemProgram.createAccount({ 44 | fromPubkey: payer.publicKey, 45 | newAccountPubkey: mint, 46 | space: mintLen, 47 | lamports, 48 | programId: TOKEN_2022_PROGRAM_ID, 49 | }), 50 | createInitializeNonTransferableMintInstruction(mint, TOKEN_2022_PROGRAM_ID), 51 | createInitializeMintInstruction( 52 | mint, 53 | decimals, 54 | mintAuthority.publicKey, 55 | null, 56 | TOKEN_2022_PROGRAM_ID, 57 | ), 58 | ); 59 | const signature = await sendAndConfirmTransaction( 60 | connection, 61 | transaction, 62 | [payer, mintKeypair], 63 | undefined, 64 | ); 65 | console.log("transaction signature key:", signature); 66 | console.log("mint key:", mint.toBase58()); 67 | })(); 68 | -------------------------------------------------------------------------------- /tokens/token-2022/non-transferable-token/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015"], 4 | "module": "CommonJS", 5 | "target": "es6", 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tokens/token-2022/reallocate-space-example/README.MD: -------------------------------------------------------------------------------- 1 | ## Reallocate space example for Token 2022 2 | 3 | Create a Token 2022 example for (Reallocate space example). `yarn main` or 4 | `npm run main` 5 | -------------------------------------------------------------------------------- /tokens/token-2022/reallocate-space-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "main": "ts-node ./src/main.ts" 4 | }, 5 | "license": "MIT", 6 | "dependencies": { 7 | "@metaplex-foundation/mpl-token-metadata": "^2.5.2", 8 | "@solana/spl-token": "^0.3.7", 9 | "@solana/web3.js": "^1.73.0", 10 | "typescript": "^4.9.4" 11 | }, 12 | "devDependencies": { 13 | "@types/node": "^18.11.18", 14 | "ts-node": "^10.9.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tokens/token-2022/reallocate-space-example/src/main.ts: -------------------------------------------------------------------------------- 1 | import { 2 | clusterApiUrl, 3 | sendAndConfirmTransaction, 4 | Connection, 5 | Keypair, 6 | Transaction, 7 | LAMPORTS_PER_SOL, 8 | } from "@solana/web3.js"; 9 | import { 10 | createAccount, 11 | createMint, 12 | createEnableRequiredMemoTransfersInstruction, 13 | createReallocateInstruction, 14 | ExtensionType, 15 | TOKEN_2022_PROGRAM_ID, 16 | } from "@solana/spl-token"; 17 | 18 | (async () => { 19 | const connection = new Connection(clusterApiUrl("devnet"), "confirmed"); 20 | 21 | const payer = Keypair.generate(); 22 | const airdropSignature = await connection.requestAirdrop( 23 | payer.publicKey, 24 | 2 * LAMPORTS_PER_SOL, 25 | ); 26 | await connection.confirmTransaction({ 27 | signature: airdropSignature, 28 | ...(await connection.getLatestBlockhash()), 29 | }); 30 | 31 | const mintAuthority = Keypair.generate(); 32 | const decimals = 9; 33 | const mint = await createMint( 34 | connection, 35 | payer, 36 | mintAuthority.publicKey, 37 | mintAuthority.publicKey, 38 | decimals, 39 | undefined, 40 | undefined, 41 | TOKEN_2022_PROGRAM_ID, 42 | ); 43 | 44 | const owner = Keypair.generate(); 45 | const account = await createAccount( 46 | connection, 47 | payer, 48 | mint, 49 | owner.publicKey, 50 | undefined, 51 | undefined, 52 | TOKEN_2022_PROGRAM_ID, 53 | ); 54 | 55 | const extensions = [ExtensionType.MemoTransfer]; 56 | const transaction = new Transaction().add( 57 | createReallocateInstruction( 58 | account, 59 | payer.publicKey, 60 | extensions, 61 | owner.publicKey, 62 | undefined, 63 | TOKEN_2022_PROGRAM_ID, 64 | ), 65 | createEnableRequiredMemoTransfersInstruction( 66 | account, 67 | owner.publicKey, 68 | [], 69 | TOKEN_2022_PROGRAM_ID, 70 | ), 71 | ); 72 | const signature = await sendAndConfirmTransaction( 73 | connection, 74 | transaction, 75 | [payer, owner], 76 | undefined, 77 | ); 78 | console.log("transaction signature key:", signature); 79 | console.log("mint key:", mint.toBase58()); 80 | })(); 81 | -------------------------------------------------------------------------------- /tokens/token-2022/reallocate-space-example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015"], 4 | "module": "CommonJS", 5 | "target": "es6", 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tokens/token-2022/transfer-fee/README.md: -------------------------------------------------------------------------------- 1 | ## Token with transfer fees 2 | 3 | Creates a Token 2022 Token with Transfer fees. `yarn main` or `npm run main` 4 | -------------------------------------------------------------------------------- /tokens/token-2022/transfer-fee/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "main": "yarn run ts-node ./src/main.ts" 4 | }, 5 | "license": "MIT", 6 | "dependencies": { 7 | "@metaplex-foundation/mpl-token-metadata": "^2.5.2", 8 | "@solana/spl-token": "^0.3.7", 9 | "@solana/web3.js": "^1.73.0", 10 | "ts-node": "^10.9.1", 11 | "typescript": "^4.9.4" 12 | }, 13 | "devDependencies": { 14 | "@types/node": "^18.11.18" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tokens/token-2022/transfer-fee/src/main.ts: -------------------------------------------------------------------------------- 1 | import { 2 | clusterApiUrl, 3 | sendAndConfirmTransaction, 4 | Connection, 5 | Keypair, 6 | SystemProgram, 7 | Transaction, 8 | LAMPORTS_PER_SOL, 9 | } from "@solana/web3.js"; 10 | 11 | import { 12 | ExtensionType, 13 | createInitializeMintInstruction, 14 | getMintLen, 15 | TOKEN_2022_PROGRAM_ID, 16 | } from "@solana/spl-token"; 17 | 18 | import { createInitializeTransferFeeConfigInstruction } from "@solana/spl-token"; 19 | 20 | (async () => { 21 | const payer = Keypair.generate(); 22 | 23 | const mintAuthority = Keypair.generate(); 24 | const mintKeypair = Keypair.generate(); 25 | const mint = mintKeypair.publicKey; 26 | const transferFeeConfigAuthority = Keypair.generate(); 27 | const withdrawWithheldAuthority = Keypair.generate(); 28 | 29 | const extensions = [ExtensionType.TransferFeeConfig]; 30 | 31 | const mintLen = getMintLen(extensions); 32 | const decimals = 9; 33 | const feeBasisPoints = 50; 34 | const maxFee = BigInt(5_000); 35 | 36 | const connection = new Connection(clusterApiUrl("devnet"), "confirmed"); 37 | 38 | const airdropSignature = await connection.requestAirdrop( 39 | payer.publicKey, 40 | 2 * LAMPORTS_PER_SOL, 41 | ); 42 | await connection.confirmTransaction({ 43 | signature: airdropSignature, 44 | ...(await connection.getLatestBlockhash()), 45 | }); 46 | 47 | const mintLamports = await connection.getMinimumBalanceForRentExemption( 48 | mintLen, 49 | ); 50 | const mintTransaction = new Transaction().add( 51 | SystemProgram.createAccount({ 52 | fromPubkey: payer.publicKey, 53 | newAccountPubkey: mint, 54 | space: mintLen, 55 | lamports: mintLamports, 56 | programId: TOKEN_2022_PROGRAM_ID, 57 | }), 58 | createInitializeTransferFeeConfigInstruction( 59 | mint, 60 | transferFeeConfigAuthority.publicKey, 61 | withdrawWithheldAuthority.publicKey, 62 | feeBasisPoints, 63 | maxFee, 64 | TOKEN_2022_PROGRAM_ID, 65 | ), 66 | createInitializeMintInstruction( 67 | mint, 68 | decimals, 69 | mintAuthority.publicKey, 70 | null, 71 | TOKEN_2022_PROGRAM_ID, 72 | ), 73 | ); 74 | const signature = await sendAndConfirmTransaction( 75 | connection, 76 | mintTransaction, 77 | [payer, mintKeypair], 78 | ); 79 | console.log("Your transaction PublicKey:", signature); 80 | console.log("Your mint PublicKey:", mint.toBase58()); 81 | })(); 82 | -------------------------------------------------------------------------------- /tokens/token-2022/transfer-fee/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015"], 4 | "module": "commonjs", 5 | "target": "es6", 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tokens/token-lending/README.md: -------------------------------------------------------------------------------- 1 | # Token Lending Example 2 | 3 | > Coming soon! 4 | -------------------------------------------------------------------------------- /tokens/transfer-tokens/README.md: -------------------------------------------------------------------------------- 1 | # Transfer Tokens 2 | 3 | Just like with minting, transfers of SPL Tokens are conducted between Associated 4 | Token Accounts. 5 | 6 | You can use the `transfer()` function provided by the SPL Token Program to 7 | conduct a transfer of any SPL Token with the appropriate permissions. 8 | 9 | Check out [SPL Token Minter](../spl-token-minter) or [NFT Minter](../nft-minter) 10 | to learn more about Associated Token Accounts. 11 | -------------------------------------------------------------------------------- /tokens/transfer-tokens/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "main": "yarn run ts-node ./src/main.ts" 4 | }, 5 | "license": "MIT", 6 | "dependencies": { 7 | "@metaplex-foundation/mpl-token-metadata": "^2.5.2", 8 | "@solana/spl-token": "^0.3.7", 9 | "@solana/web3.js": "^1.73.0", 10 | "ts-node": "^10.9.1", 11 | "typescript": "^4.9.4" 12 | }, 13 | "devDependencies": { 14 | "@types/node": "^18.11.18" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tokens/transfer-tokens/src/main.ts: -------------------------------------------------------------------------------- 1 | import { Keypair } from "@solana/web3.js"; 2 | import { 3 | createAccount, 4 | createNft, 5 | createSplToken, 6 | mintNft, 7 | mintSplTokens, 8 | transferTokens, 9 | } from "./tokens"; 10 | import { loadKeypairFromFile } from "./util"; 11 | 12 | const payer = loadKeypairFromFile( 13 | require("os").homedir() + "/.config/solana/id.json", 14 | ); 15 | 16 | const testUserKeypair1 = Keypair.generate(); 17 | const testUserKeypair2 = Keypair.generate(); 18 | 19 | const tokenMintKeypair = Keypair.generate(); 20 | const nftMintKeypair = Keypair.generate(); 21 | 22 | async function tokensScript() { 23 | await createAccount("Test User Keypair #1", testUserKeypair1, payer); 24 | await createAccount("Test User Keypair #2", testUserKeypair2, payer); 25 | 26 | // SPL Token 27 | await createSplToken( 28 | tokenMintKeypair, 29 | payer, 30 | "Solana Gold", 31 | "GOLDSOL", 32 | "https://raw.githubusercontent.com/solana-developers/web3-examples/new-examples/tokens/tokens/.assets/spl-token.json", 33 | ); 34 | // NFT 35 | await createNft( 36 | nftMintKeypair, 37 | payer, 38 | "Homer NFT", 39 | "HOMR", 40 | "https://raw.githubusercontent.com/solana-developers/web3-examples/new-examples/tokens/tokens/.assets/nft.json", 41 | ); 42 | 43 | await mintSplTokens( 44 | tokenMintKeypair.publicKey, 45 | payer, 46 | payer, 47 | testUserKeypair1.publicKey, 48 | 40, 49 | ); 50 | await mintNft( 51 | nftMintKeypair.publicKey, 52 | payer, 53 | payer, 54 | testUserKeypair1.publicKey, 55 | ); 56 | 57 | await transferTokens( 58 | tokenMintKeypair.publicKey, 59 | payer, 60 | testUserKeypair1, 61 | testUserKeypair2.publicKey, 62 | 10, 63 | ); 64 | await transferTokens( 65 | nftMintKeypair.publicKey, 66 | payer, 67 | testUserKeypair1, 68 | testUserKeypair2.publicKey, 69 | 1, 70 | ); 71 | } 72 | 73 | tokensScript(); 74 | -------------------------------------------------------------------------------- /tokens/transfer-tokens/src/tokens.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createCreateMasterEditionV3Instruction, 3 | createCreateMetadataAccountV3Instruction, 4 | PROGRAM_ID, 5 | } from "@metaplex-foundation/mpl-token-metadata"; 6 | import { 7 | createAssociatedTokenAccountInstruction, 8 | createInitializeMintInstruction, 9 | createMintToInstruction, 10 | getAssociatedTokenAddressSync, 11 | MINT_SIZE, 12 | TOKEN_PROGRAM_ID, 13 | transfer, 14 | } from "@solana/spl-token"; 15 | import { 16 | Connection, 17 | Keypair, 18 | PublicKey, 19 | SystemProgram, 20 | TransactionInstruction, 21 | } from "@solana/web3.js"; 22 | import { 23 | buildTransaction, 24 | logBalance, 25 | logNewKeypair, 26 | logNewMint, 27 | logTransaction, 28 | newLogSection, 29 | } from "./util"; 30 | 31 | const connection = new Connection("https://api.devnet.solana.com", { 32 | commitment: "confirmed", 33 | confirmTransactionInitialTimeout: 60000, 34 | }); 35 | 36 | export async function createAccount( 37 | accountName: string, 38 | newAccountKeypair: Keypair, 39 | payerKeypair: Keypair, 40 | ) { 41 | const lamports = await connection.getMinimumBalanceForRentExemption(0); 42 | const createAccountInstruction = SystemProgram.createAccount({ 43 | fromPubkey: payerKeypair.publicKey, 44 | newAccountPubkey: newAccountKeypair.publicKey, 45 | lamports, 46 | space: 0, 47 | programId: SystemProgram.programId, 48 | }); 49 | const createAccountTransaction = await buildTransaction( 50 | connection, 51 | payerKeypair.publicKey, 52 | [payerKeypair, newAccountKeypair], 53 | [createAccountInstruction], 54 | ); 55 | const signature = await connection.sendTransaction(createAccountTransaction); 56 | 57 | newLogSection(); 58 | logNewKeypair(newAccountKeypair); 59 | await logTransaction(connection, signature); 60 | await logBalance(accountName, connection, newAccountKeypair.publicKey); 61 | } 62 | 63 | export async function createSplToken( 64 | mintKeypair: Keypair, 65 | payerKeypair: Keypair, 66 | tokenName: string, 67 | tokenSymbol: string, 68 | tokenUri: string, 69 | ) { 70 | // Create the account for the Mint 71 | const createMintAccountInstruction = SystemProgram.createAccount({ 72 | fromPubkey: payerKeypair.publicKey, 73 | newAccountPubkey: mintKeypair.publicKey, 74 | lamports: await connection.getMinimumBalanceForRentExemption(MINT_SIZE), 75 | space: MINT_SIZE, 76 | programId: TOKEN_PROGRAM_ID, 77 | }); 78 | // Initialize that account as a Mint 79 | const initializeMintInstruction = createInitializeMintInstruction( 80 | mintKeypair.publicKey, 81 | 9, 82 | payerKeypair.publicKey, 83 | payerKeypair.publicKey, 84 | ); 85 | // Create the Metadata account for the Mint 86 | const createMetadataInstruction = createCreateMetadataAccountV3Instruction( 87 | { 88 | metadata: PublicKey.findProgramAddressSync( 89 | [ 90 | Buffer.from("metadata"), 91 | PROGRAM_ID.toBuffer(), 92 | mintKeypair.publicKey.toBuffer(), 93 | ], 94 | PROGRAM_ID, 95 | )[0], 96 | mint: mintKeypair.publicKey, 97 | mintAuthority: payerKeypair.publicKey, 98 | payer: payerKeypair.publicKey, 99 | updateAuthority: payerKeypair.publicKey, 100 | }, 101 | { 102 | createMetadataAccountArgsV3: { 103 | data: { 104 | name: tokenName, 105 | symbol: tokenSymbol, 106 | uri: tokenUri, 107 | creators: null, 108 | sellerFeeBasisPoints: 0, 109 | uses: null, 110 | collection: null, 111 | }, 112 | isMutable: false, 113 | collectionDetails: null, 114 | }, 115 | }, 116 | ); 117 | const tx = await buildTransaction( 118 | connection, 119 | payerKeypair.publicKey, 120 | [payerKeypair, mintKeypair], 121 | [ 122 | createMintAccountInstruction, 123 | initializeMintInstruction, 124 | createMetadataInstruction, 125 | ], 126 | ); 127 | const signature = await connection.sendTransaction(tx); 128 | 129 | newLogSection(); 130 | await logTransaction(connection, signature); 131 | logNewMint(mintKeypair.publicKey, 9); 132 | } 133 | 134 | export async function createNft( 135 | mintKeypair: Keypair, 136 | payerKeypair: Keypair, 137 | tokenName: string, 138 | tokenSymbol: string, 139 | tokenUri: string, 140 | ) { 141 | // Create the account for the Mint 142 | const createMintAccountInstruction = SystemProgram.createAccount({ 143 | fromPubkey: payerKeypair.publicKey, 144 | newAccountPubkey: mintKeypair.publicKey, 145 | lamports: await connection.getMinimumBalanceForRentExemption(MINT_SIZE), 146 | space: MINT_SIZE, 147 | programId: TOKEN_PROGRAM_ID, 148 | }); 149 | // Initialize that account as a Mint 150 | const initializeMintInstruction = createInitializeMintInstruction( 151 | mintKeypair.publicKey, 152 | 0, 153 | payerKeypair.publicKey, 154 | payerKeypair.publicKey, 155 | ); 156 | // Create the Metadata account for the Mint 157 | const createMetadataInstruction = createCreateMetadataAccountV3Instruction( 158 | { 159 | metadata: PublicKey.findProgramAddressSync( 160 | [ 161 | Buffer.from("metadata"), 162 | PROGRAM_ID.toBuffer(), 163 | mintKeypair.publicKey.toBuffer(), 164 | ], 165 | PROGRAM_ID, 166 | )[0], 167 | mint: mintKeypair.publicKey, 168 | mintAuthority: payerKeypair.publicKey, 169 | payer: payerKeypair.publicKey, 170 | updateAuthority: payerKeypair.publicKey, 171 | }, 172 | { 173 | createMetadataAccountArgsV3: { 174 | data: { 175 | name: tokenName, 176 | symbol: tokenSymbol, 177 | uri: tokenUri, 178 | creators: null, 179 | sellerFeeBasisPoints: 0, 180 | uses: null, 181 | collection: null, 182 | }, 183 | isMutable: false, 184 | collectionDetails: null, 185 | }, 186 | }, 187 | ); 188 | const tx = await buildTransaction( 189 | connection, 190 | payerKeypair.publicKey, 191 | [payerKeypair, mintKeypair], 192 | [ 193 | createMintAccountInstruction, 194 | initializeMintInstruction, 195 | createMetadataInstruction, 196 | ], 197 | ); 198 | const signature = await connection.sendTransaction(tx); 199 | 200 | newLogSection(); 201 | await logTransaction(connection, signature); 202 | logNewMint(mintKeypair.publicKey, 0); 203 | } 204 | 205 | export async function mintSplTokens( 206 | mintPublicKey: PublicKey, 207 | mintAuthority: Keypair, 208 | payerKeypair: Keypair, 209 | recipientPublicKey: PublicKey, 210 | quantity: number, 211 | ) { 212 | newLogSection(); 213 | console.log(`Minting ${quantity} tokens to recipient: ${recipientPublicKey}`); 214 | 215 | // Check to see if their Associated Token Account exists 216 | // If not, create it 217 | // -> Can also use `getOrCreateAssociatedTokenAccount()` 218 | // 219 | const ixList: TransactionInstruction[] = []; 220 | const associatedTokenAddress = getAssociatedTokenAddressSync( 221 | mintPublicKey, 222 | recipientPublicKey, 223 | ); 224 | console.log( 225 | ` Recipient Associated Token Address: ${associatedTokenAddress}`, 226 | ); 227 | const associatedTokenAccountInfo = await connection.getAccountInfo( 228 | associatedTokenAddress, 229 | ); 230 | if ( 231 | !associatedTokenAccountInfo || 232 | associatedTokenAccountInfo.lamports === 0 233 | ) { 234 | ixList.push( 235 | createAssociatedTokenAccountInstruction( 236 | payerKeypair.publicKey, 237 | associatedTokenAddress, 238 | recipientPublicKey, 239 | mintPublicKey, 240 | ), 241 | ); 242 | } 243 | 244 | // Now mint to the recipient's Associated Token Account 245 | // 246 | ixList.push( 247 | createMintToInstruction( 248 | mintPublicKey, 249 | associatedTokenAddress, 250 | mintAuthority.publicKey, 251 | quantity, 252 | ), 253 | ); 254 | 255 | const tx = await buildTransaction( 256 | connection, 257 | payerKeypair.publicKey, 258 | [mintAuthority, payerKeypair], 259 | ixList, 260 | ); 261 | const signature = await connection.sendTransaction(tx); 262 | await logTransaction(connection, signature); 263 | } 264 | 265 | export async function mintNft( 266 | mintPublicKey: PublicKey, 267 | mintAuthority: Keypair, 268 | payerKeypair: Keypair, 269 | recipientPublicKey: PublicKey, 270 | ) { 271 | newLogSection(); 272 | console.log(`Minting NFT to recipient: ${recipientPublicKey}`); 273 | 274 | // Check to see if their Associated Token Account exists 275 | // If not, create it 276 | // -> Can also use `getOrCreateAssociatedTokenAccount()` 277 | // 278 | const ixList: TransactionInstruction[] = []; 279 | const associatedTokenAddress = getAssociatedTokenAddressSync( 280 | mintPublicKey, 281 | recipientPublicKey, 282 | ); 283 | console.log( 284 | ` Recipient Associated Token Address: ${associatedTokenAddress}`, 285 | ); 286 | const associatedTokenAccountInfo = await connection.getAccountInfo( 287 | associatedTokenAddress, 288 | ); 289 | if ( 290 | !associatedTokenAccountInfo || 291 | associatedTokenAccountInfo.lamports === 0 292 | ) { 293 | ixList.push( 294 | createAssociatedTokenAccountInstruction( 295 | payerKeypair.publicKey, 296 | associatedTokenAddress, 297 | recipientPublicKey, 298 | mintPublicKey, 299 | ), 300 | ); 301 | } 302 | 303 | // Now mint to the recipient's Associated Token Account 304 | // 305 | ixList.push( 306 | createMintToInstruction( 307 | mintPublicKey, 308 | associatedTokenAddress, 309 | mintAuthority.publicKey, 310 | 1, 311 | ), 312 | ); 313 | 314 | // We can make this a Limited Edition NFT through Metaplex, 315 | // which will disable minting by setting the Mint & Freeze Authorities to the 316 | // Edition Account. 317 | // 318 | ixList.push( 319 | createCreateMasterEditionV3Instruction( 320 | { 321 | edition: PublicKey.findProgramAddressSync( 322 | [ 323 | Buffer.from("metadata"), 324 | PROGRAM_ID.toBuffer(), 325 | mintPublicKey.toBuffer(), 326 | Buffer.from("edition"), 327 | ], 328 | PROGRAM_ID, 329 | )[0], 330 | metadata: PublicKey.findProgramAddressSync( 331 | [ 332 | Buffer.from("metadata"), 333 | PROGRAM_ID.toBuffer(), 334 | mintPublicKey.toBuffer(), 335 | ], 336 | PROGRAM_ID, 337 | )[0], 338 | mint: mintPublicKey, 339 | mintAuthority: payerKeypair.publicKey, 340 | payer: payerKeypair.publicKey, 341 | updateAuthority: payerKeypair.publicKey, 342 | }, 343 | { 344 | createMasterEditionArgs: { maxSupply: 1 }, 345 | }, 346 | ), 347 | ); 348 | 349 | // If we don't use Metaplex Editions, we must disable minting manually 350 | // 351 | // ------------------------------------------------------------------- 352 | // ixList.push( 353 | // createSetAuthorityInstruction( 354 | // mintPublicKey, 355 | // mintAuthority.publicKey, 356 | // AuthorityType.MintTokens, 357 | // null, 358 | // ) 359 | // ) 360 | // ixList.push( 361 | // createSetAuthorityInstruction( 362 | // mintPublicKey, 363 | // mintAuthority.publicKey, 364 | // AuthorityType.FreezeAccount, 365 | // null, 366 | // ) 367 | // ) 368 | 369 | const tx = await buildTransaction( 370 | connection, 371 | payerKeypair.publicKey, 372 | [mintAuthority, payerKeypair], 373 | ixList, 374 | ); 375 | const signature = await connection.sendTransaction(tx); 376 | await logTransaction(connection, signature); 377 | } 378 | 379 | export async function transferTokens( 380 | mintPublicKey: PublicKey, 381 | payerKeypair: Keypair, 382 | fromKeypair: Keypair, 383 | toPublicKey: PublicKey, 384 | quantity: number, 385 | ) { 386 | const ixList: TransactionInstruction[] = []; 387 | 388 | // Again, we're just checking to see if the Associated Token Account exists 389 | // If not, we need to create it so we can use it in the transfer 390 | async function checkAndAddAssociatedTokenAccountInstruction( 391 | owner: PublicKey, 392 | ): Promise { 393 | const associatedTokenAddress = getAssociatedTokenAddressSync( 394 | mintPublicKey, 395 | fromKeypair.publicKey, 396 | ); 397 | const associatedTokenAccountInfo = await connection.getAccountInfo( 398 | associatedTokenAddress, 399 | ); 400 | if ( 401 | !associatedTokenAccountInfo || 402 | associatedTokenAccountInfo.lamports === 0 403 | ) { 404 | ixList.push( 405 | createAssociatedTokenAccountInstruction( 406 | payerKeypair.publicKey, 407 | associatedTokenAddress, 408 | owner, 409 | mintPublicKey, 410 | ), 411 | ); 412 | } 413 | return associatedTokenAddress; 414 | } 415 | const fromAtaAddress = await checkAndAddAssociatedTokenAccountInstruction( 416 | fromKeypair.publicKey, 417 | ); 418 | const toAtaAddress = await checkAndAddAssociatedTokenAccountInstruction( 419 | toPublicKey, 420 | ); 421 | 422 | // Transfer the tokens 423 | const signature = await transfer( 424 | connection, 425 | payerKeypair, 426 | fromAtaAddress, 427 | toAtaAddress, 428 | fromKeypair, 429 | quantity, 430 | ); 431 | newLogSection(); 432 | await logTransaction(connection, signature); 433 | } 434 | -------------------------------------------------------------------------------- /tokens/transfer-tokens/src/util.ts: -------------------------------------------------------------------------------- 1 | import { Account } from "@solana/spl-token"; 2 | import { 3 | Connection, 4 | Keypair, 5 | PublicKey, 6 | TransactionInstruction, 7 | VersionedTransaction, 8 | TransactionMessage, 9 | AccountInfo, 10 | LAMPORTS_PER_SOL, 11 | } from "@solana/web3.js"; 12 | 13 | export function loadKeypairFromFile(path: string): Keypair { 14 | return Keypair.fromSecretKey( 15 | Buffer.from(JSON.parse(require("fs").readFileSync(path, "utf-8"))), 16 | ); 17 | } 18 | 19 | export function newLogSection() { 20 | console.log("-----------------------------------------------------"); 21 | } 22 | 23 | export async function logAccountInfo(accountInfo: AccountInfo | null) { 24 | console.log("Account Info:"); 25 | console.log(accountInfo); 26 | } 27 | 28 | export function logNewKeypair(keypair: Keypair) { 29 | console.log("Created a new keypair."); 30 | console.log(` New account Public Key: ${keypair.publicKey}`); 31 | } 32 | 33 | export async function logTransaction( 34 | connection: Connection, 35 | signature: string, 36 | ) { 37 | await connection.confirmTransaction(signature); 38 | console.log("Transaction successful."); 39 | console.log(` Transaction signature: ${signature}`); 40 | } 41 | 42 | export async function logBalance( 43 | accountName: string, 44 | connection: Connection, 45 | pubkey: PublicKey, 46 | ) { 47 | const balance = await connection.getBalance(pubkey); 48 | console.log(` ${accountName}:`); 49 | console.log(` Account Pubkey: ${pubkey.toString()} SOL`); 50 | console.log(` Account Balance: ${balance / LAMPORTS_PER_SOL} SOL`); 51 | } 52 | 53 | export function logNewMint(mintPubkey: PublicKey, decimals: number) { 54 | console.log("Created a new mint."); 55 | console.log(` New mint Public Key: ${mintPubkey}`); 56 | console.log(` Mint type: ${decimals === 0 ? "NFT" : "SPL Token"}`); 57 | } 58 | 59 | export async function buildTransaction( 60 | connection: Connection, 61 | payer: PublicKey, 62 | signers: Keypair[], 63 | instructions: TransactionInstruction[], 64 | ): Promise { 65 | let blockhash = await connection 66 | .getLatestBlockhash() 67 | .then((res) => res.blockhash); 68 | 69 | const messageV0 = new TransactionMessage({ 70 | payerKey: payer, 71 | recentBlockhash: blockhash, 72 | instructions, 73 | }).compileToV0Message(); 74 | 75 | const tx = new VersionedTransaction(messageV0); 76 | 77 | signers.forEach((s) => tx.sign([s])); 78 | 79 | return tx; 80 | } 81 | -------------------------------------------------------------------------------- /tokens/transfer-tokens/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015"], 4 | "module": "commonjs", 5 | "target": "es6", 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tokens/wrapping-sol/README.md: -------------------------------------------------------------------------------- 1 | # Wrapped tokens 2 | 3 | Create a Wrapped Token example for (Wrapping sol). 4 | `yarn main` or `npm run main` 5 | 6 | ## What is a Wrapped Token? 7 | 8 | Wrapped tokens are digital assets that represent the value of an original cryptocurrency from a different blockchain or adhere to a different token standard on the current blockchain. They serve as bridges between different blockchain ecosystems, enabling cross-chain compatibility and expanding the utility of native assets. 9 | 10 | ## Wrapped SOL (wSOL) 11 | 12 | Wrapped SOL, also known as wSOL, is a tokenized representation of Solana's native token, SOL. Each wSOL token is designed to maintain a 1:1 peg with SOL, meaning that one wSOL is always equal to one SOL. wSOL was specifically created to allow users to utilize SOL on blockchain platforms that support the ERC-20 token standard, such as Ethereum. This compatibility enables SOL holders to access decentralized finance (DeFi) protocols and non-fungible token (NFT) markets on these alternative chains. 13 | 14 | ## Creating and Retrieving wSOL 15 | 16 | When you want to wrap SOL, you need to send SOL to an associated token account on the native mint and call syncNative. syncNative updates the amount field on the token account to match the amount of wrapped SOL available. 17 | 18 | 1. Getting associatedTokenAccount address 19 | 20 | The associated token account is where the wrapped SOL tokens will be stored. 21 | Use the getAssociatedTokenAddress function to retrieve the associated token account address, providing the native mint (SOL) and the wallet's public key. 22 | 23 | ```TypeScript 24 | const associatedTokenAccount = await getAssociatedTokenAddress( 25 | NATIVE_MINT, // native mint 26 | wallet.publicKey // the wallet where we want to send sol 27 | ) 28 | ``` 29 | 30 | 2. Creating associated token account 31 | 32 | Build a transaction (ataTransaction) that includes the createAssociatedTokenAccountInstruction to create the associated token account. 33 | Specify the payer, associated token account address, owner, and the native mint (SOL). 34 | 35 | ```TypeScript 36 | const ataTransaction = new Transaction() 37 | .add( 38 | createAssociatedTokenAccountInstruction( 39 | wallet.publicKey, // payer 40 | associatedTokenAccount, //associatedToken address 41 | wallet.publicKey, // owner 42 | NATIVE_MINT // native mint 43 | ) 44 | ) 45 | ``` 46 | 47 | 3. Transferring sol to associated token account 48 | 49 | Construct a transaction (solTransferTransaction) that transfers SOL from the sender's address to the associated token account. 50 | Include the SystemProgram.transfer instruction to initiate the transfer. 51 | Add the createSyncNativeInstruction to update the amount field on the token account to match the wrapped SOL amount. 52 | 53 | ```TypeScript 54 | const solTransferTransaction = new Transaction() 55 | .add( 56 | SystemProgram.transfer({ 57 | fromPubkey: wallet.publicKey, // sending from 58 | toPubkey: associatedTokenAccount, // receiving to 59 | lamports: LAMPORTS_PER_SOL // amount 60 | }), 61 | createSyncNativeInstruction( // syncNative instruction 62 | associatedTokenAccount 63 | ) 64 | ) 65 | ``` 66 | 67 | 4. To retrieve the wrapped SOL tokens, close the associated token account and send the corresponding SOL amount to the desired address (in this case, the wallet address). 68 | 69 | ```TypeScript 70 | await closeAccount(connection, wallet, associatedTokenAccount, wallet.publicKey, wallet); 71 | ``` 72 | 73 | 5. Here we are checking amount of sol after unwrapping 74 | 75 | Verify the wallet's SOL balance post-unwrapping by using the getBalance function with the wallet's public key. 76 | 77 | ```TypeScript 78 | const walletBalancePostClose = await connection.getBalance(wallet.publicKey); 79 | ``` 80 | -------------------------------------------------------------------------------- /tokens/wrapping-sol/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wrapping-sol", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "@metaplex-foundation/mpl-token-metadata": "^2.5.2", 9 | "@solana/spl-token": "^0.3.7", 10 | "@solana/web3.js": "^1.73.0", 11 | "ts-node": "^10.9.1", 12 | "typescript": "^4.9.4" 13 | }, 14 | "devDependencies": { 15 | "@types/node": "^18.11.18" 16 | } 17 | }, 18 | "node_modules/@babel/runtime": { 19 | "version": "7.22.3", 20 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.3.tgz", 21 | "integrity": "sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==", 22 | "dependencies": { 23 | "regenerator-runtime": "^0.13.11" 24 | }, 25 | "engines": { 26 | "node": ">=6.9.0" 27 | } 28 | }, 29 | "node_modules/@cspotcode/source-map-support": { 30 | "version": "0.8.1", 31 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 32 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 33 | "dependencies": { 34 | "@jridgewell/trace-mapping": "0.3.9" 35 | }, 36 | "engines": { 37 | "node": ">=12" 38 | } 39 | }, 40 | "node_modules/@jridgewell/resolve-uri": { 41 | "version": "3.1.1", 42 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 43 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", 44 | "engines": { 45 | "node": ">=6.0.0" 46 | } 47 | }, 48 | "node_modules/@jridgewell/sourcemap-codec": { 49 | "version": "1.4.15", 50 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 51 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" 52 | }, 53 | "node_modules/@jridgewell/trace-mapping": { 54 | "version": "0.3.9", 55 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 56 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 57 | "dependencies": { 58 | "@jridgewell/resolve-uri": "^3.0.3", 59 | "@jridgewell/sourcemap-codec": "^1.4.10" 60 | } 61 | }, 62 | "node_modules/@metaplex-foundation/beet": { 63 | "version": "0.7.1", 64 | "resolved": "https://registry.npmjs.org/@metaplex-foundation/beet/-/beet-0.7.1.tgz", 65 | "integrity": "sha512-hNCEnS2WyCiYyko82rwuISsBY3KYpe828ubsd2ckeqZr7tl0WVLivGkoyA/qdiaaHEBGdGl71OpfWa2rqL3DiA==", 66 | "dependencies": { 67 | "ansicolors": "^0.3.2", 68 | "bn.js": "^5.2.0", 69 | "debug": "^4.3.3" 70 | } 71 | }, 72 | "node_modules/@metaplex-foundation/beet-solana": { 73 | "version": "0.4.0", 74 | "resolved": "https://registry.npmjs.org/@metaplex-foundation/beet-solana/-/beet-solana-0.4.0.tgz", 75 | "integrity": "sha512-B1L94N3ZGMo53b0uOSoznbuM5GBNJ8LwSeznxBxJ+OThvfHQ4B5oMUqb+0zdLRfkKGS7Q6tpHK9P+QK0j3w2cQ==", 76 | "dependencies": { 77 | "@metaplex-foundation/beet": ">=0.1.0", 78 | "@solana/web3.js": "^1.56.2", 79 | "bs58": "^5.0.0", 80 | "debug": "^4.3.4" 81 | } 82 | }, 83 | "node_modules/@metaplex-foundation/cusper": { 84 | "version": "0.0.2", 85 | "resolved": "https://registry.npmjs.org/@metaplex-foundation/cusper/-/cusper-0.0.2.tgz", 86 | "integrity": "sha512-S9RulC2fFCFOQraz61bij+5YCHhSO9llJegK8c8Y6731fSi6snUSQJdCUqYS8AIgR0TKbQvdvgSyIIdbDFZbBA==" 87 | }, 88 | "node_modules/@metaplex-foundation/mpl-token-metadata": { 89 | "version": "2.12.0", 90 | "resolved": "https://registry.npmjs.org/@metaplex-foundation/mpl-token-metadata/-/mpl-token-metadata-2.12.0.tgz", 91 | "integrity": "sha512-DetC2F5MwMRt4TmLXwj8PJ8nClRYGMecSQ4pr9iKKa+rWertHgKoJHl2XhheRa084GtL7i0ssOKbX2gfYFosuQ==", 92 | "dependencies": { 93 | "@metaplex-foundation/beet": "^0.7.1", 94 | "@metaplex-foundation/beet-solana": "^0.4.0", 95 | "@metaplex-foundation/cusper": "^0.0.2", 96 | "@solana/spl-token": "^0.3.6", 97 | "@solana/web3.js": "^1.66.2", 98 | "bn.js": "^5.2.0", 99 | "debug": "^4.3.4" 100 | } 101 | }, 102 | "node_modules/@noble/curves": { 103 | "version": "1.0.0", 104 | "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.0.0.tgz", 105 | "integrity": "sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw==", 106 | "funding": [ 107 | { 108 | "type": "individual", 109 | "url": "https://paulmillr.com/funding/" 110 | } 111 | ], 112 | "dependencies": { 113 | "@noble/hashes": "1.3.0" 114 | } 115 | }, 116 | "node_modules/@noble/hashes": { 117 | "version": "1.3.0", 118 | "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz", 119 | "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==", 120 | "funding": [ 121 | { 122 | "type": "individual", 123 | "url": "https://paulmillr.com/funding/" 124 | } 125 | ] 126 | }, 127 | "node_modules/@solana/buffer-layout": { 128 | "version": "4.0.1", 129 | "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", 130 | "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", 131 | "dependencies": { 132 | "buffer": "~6.0.3" 133 | }, 134 | "engines": { 135 | "node": ">=5.10" 136 | } 137 | }, 138 | "node_modules/@solana/buffer-layout-utils": { 139 | "version": "0.2.0", 140 | "resolved": "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz", 141 | "integrity": "sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==", 142 | "dependencies": { 143 | "@solana/buffer-layout": "^4.0.0", 144 | "@solana/web3.js": "^1.32.0", 145 | "bigint-buffer": "^1.1.5", 146 | "bignumber.js": "^9.0.1" 147 | }, 148 | "engines": { 149 | "node": ">= 10" 150 | } 151 | }, 152 | "node_modules/@solana/spl-token": { 153 | "version": "0.3.8", 154 | "resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.3.8.tgz", 155 | "integrity": "sha512-ogwGDcunP9Lkj+9CODOWMiVJEdRtqHAtX2rWF62KxnnSWtMZtV9rDhTrZFshiyJmxDnRL/1nKE1yJHg4jjs3gg==", 156 | "dependencies": { 157 | "@solana/buffer-layout": "^4.0.0", 158 | "@solana/buffer-layout-utils": "^0.2.0", 159 | "buffer": "^6.0.3" 160 | }, 161 | "engines": { 162 | "node": ">=16" 163 | }, 164 | "peerDependencies": { 165 | "@solana/web3.js": "^1.47.4" 166 | } 167 | }, 168 | "node_modules/@solana/web3.js": { 169 | "version": "1.77.3", 170 | "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.77.3.tgz", 171 | "integrity": "sha512-PHaO0BdoiQRPpieC1p31wJsBaxwIOWLh8j2ocXNKX8boCQVldt26Jqm2tZE4KlrvnCIV78owPLv1pEUgqhxZ3w==", 172 | "dependencies": { 173 | "@babel/runtime": "^7.12.5", 174 | "@noble/curves": "^1.0.0", 175 | "@noble/hashes": "^1.3.0", 176 | "@solana/buffer-layout": "^4.0.0", 177 | "agentkeepalive": "^4.2.1", 178 | "bigint-buffer": "^1.1.5", 179 | "bn.js": "^5.0.0", 180 | "borsh": "^0.7.0", 181 | "bs58": "^4.0.1", 182 | "buffer": "6.0.3", 183 | "fast-stable-stringify": "^1.0.0", 184 | "jayson": "^4.1.0", 185 | "node-fetch": "^2.6.7", 186 | "rpc-websockets": "^7.5.1", 187 | "superstruct": "^0.14.2" 188 | } 189 | }, 190 | "node_modules/@solana/web3.js/node_modules/base-x": { 191 | "version": "3.0.9", 192 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", 193 | "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", 194 | "dependencies": { 195 | "safe-buffer": "^5.0.1" 196 | } 197 | }, 198 | "node_modules/@solana/web3.js/node_modules/bs58": { 199 | "version": "4.0.1", 200 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", 201 | "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", 202 | "dependencies": { 203 | "base-x": "^3.0.2" 204 | } 205 | }, 206 | "node_modules/@tsconfig/node10": { 207 | "version": "1.0.9", 208 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", 209 | "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" 210 | }, 211 | "node_modules/@tsconfig/node12": { 212 | "version": "1.0.11", 213 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 214 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" 215 | }, 216 | "node_modules/@tsconfig/node14": { 217 | "version": "1.0.3", 218 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 219 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" 220 | }, 221 | "node_modules/@tsconfig/node16": { 222 | "version": "1.0.4", 223 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", 224 | "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" 225 | }, 226 | "node_modules/@types/connect": { 227 | "version": "3.4.35", 228 | "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", 229 | "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", 230 | "dependencies": { 231 | "@types/node": "*" 232 | } 233 | }, 234 | "node_modules/@types/node": { 235 | "version": "18.16.16", 236 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.16.tgz", 237 | "integrity": "sha512-NpaM49IGQQAUlBhHMF82QH80J08os4ZmyF9MkpCzWAGuOHqE4gTEbhzd7L3l5LmWuZ6E0OiC1FweQ4tsiW35+g==" 238 | }, 239 | "node_modules/@types/ws": { 240 | "version": "7.4.7", 241 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", 242 | "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", 243 | "dependencies": { 244 | "@types/node": "*" 245 | } 246 | }, 247 | "node_modules/acorn": { 248 | "version": "8.8.2", 249 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", 250 | "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", 251 | "bin": { 252 | "acorn": "bin/acorn" 253 | }, 254 | "engines": { 255 | "node": ">=0.4.0" 256 | } 257 | }, 258 | "node_modules/acorn-walk": { 259 | "version": "8.2.0", 260 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 261 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", 262 | "engines": { 263 | "node": ">=0.4.0" 264 | } 265 | }, 266 | "node_modules/agentkeepalive": { 267 | "version": "4.3.0", 268 | "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", 269 | "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", 270 | "dependencies": { 271 | "debug": "^4.1.0", 272 | "depd": "^2.0.0", 273 | "humanize-ms": "^1.2.1" 274 | }, 275 | "engines": { 276 | "node": ">= 8.0.0" 277 | } 278 | }, 279 | "node_modules/ansicolors": { 280 | "version": "0.3.2", 281 | "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", 282 | "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==" 283 | }, 284 | "node_modules/arg": { 285 | "version": "4.1.3", 286 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 287 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" 288 | }, 289 | "node_modules/base-x": { 290 | "version": "4.0.0", 291 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", 292 | "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" 293 | }, 294 | "node_modules/base64-js": { 295 | "version": "1.5.1", 296 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 297 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 298 | "funding": [ 299 | { 300 | "type": "github", 301 | "url": "https://github.com/sponsors/feross" 302 | }, 303 | { 304 | "type": "patreon", 305 | "url": "https://www.patreon.com/feross" 306 | }, 307 | { 308 | "type": "consulting", 309 | "url": "https://feross.org/support" 310 | } 311 | ] 312 | }, 313 | "node_modules/bigint-buffer": { 314 | "version": "1.1.5", 315 | "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz", 316 | "integrity": "sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==", 317 | "hasInstallScript": true, 318 | "dependencies": { 319 | "bindings": "^1.3.0" 320 | }, 321 | "engines": { 322 | "node": ">= 10.0.0" 323 | } 324 | }, 325 | "node_modules/bignumber.js": { 326 | "version": "9.1.1", 327 | "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", 328 | "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", 329 | "engines": { 330 | "node": "*" 331 | } 332 | }, 333 | "node_modules/bindings": { 334 | "version": "1.5.0", 335 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", 336 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", 337 | "dependencies": { 338 | "file-uri-to-path": "1.0.0" 339 | } 340 | }, 341 | "node_modules/bn.js": { 342 | "version": "5.2.1", 343 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", 344 | "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" 345 | }, 346 | "node_modules/borsh": { 347 | "version": "0.7.0", 348 | "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", 349 | "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", 350 | "dependencies": { 351 | "bn.js": "^5.2.0", 352 | "bs58": "^4.0.0", 353 | "text-encoding-utf-8": "^1.0.2" 354 | } 355 | }, 356 | "node_modules/borsh/node_modules/base-x": { 357 | "version": "3.0.9", 358 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", 359 | "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", 360 | "dependencies": { 361 | "safe-buffer": "^5.0.1" 362 | } 363 | }, 364 | "node_modules/borsh/node_modules/bs58": { 365 | "version": "4.0.1", 366 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", 367 | "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", 368 | "dependencies": { 369 | "base-x": "^3.0.2" 370 | } 371 | }, 372 | "node_modules/bs58": { 373 | "version": "5.0.0", 374 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", 375 | "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", 376 | "dependencies": { 377 | "base-x": "^4.0.0" 378 | } 379 | }, 380 | "node_modules/buffer": { 381 | "version": "6.0.3", 382 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", 383 | "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", 384 | "funding": [ 385 | { 386 | "type": "github", 387 | "url": "https://github.com/sponsors/feross" 388 | }, 389 | { 390 | "type": "patreon", 391 | "url": "https://www.patreon.com/feross" 392 | }, 393 | { 394 | "type": "consulting", 395 | "url": "https://feross.org/support" 396 | } 397 | ], 398 | "dependencies": { 399 | "base64-js": "^1.3.1", 400 | "ieee754": "^1.2.1" 401 | } 402 | }, 403 | "node_modules/bufferutil": { 404 | "version": "4.0.7", 405 | "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", 406 | "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", 407 | "hasInstallScript": true, 408 | "optional": true, 409 | "dependencies": { 410 | "node-gyp-build": "^4.3.0" 411 | }, 412 | "engines": { 413 | "node": ">=6.14.2" 414 | } 415 | }, 416 | "node_modules/commander": { 417 | "version": "2.20.3", 418 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 419 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" 420 | }, 421 | "node_modules/create-require": { 422 | "version": "1.1.1", 423 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 424 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" 425 | }, 426 | "node_modules/debug": { 427 | "version": "4.3.4", 428 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 429 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 430 | "dependencies": { 431 | "ms": "2.1.2" 432 | }, 433 | "engines": { 434 | "node": ">=6.0" 435 | }, 436 | "peerDependenciesMeta": { 437 | "supports-color": { 438 | "optional": true 439 | } 440 | } 441 | }, 442 | "node_modules/delay": { 443 | "version": "5.0.0", 444 | "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", 445 | "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", 446 | "engines": { 447 | "node": ">=10" 448 | }, 449 | "funding": { 450 | "url": "https://github.com/sponsors/sindresorhus" 451 | } 452 | }, 453 | "node_modules/depd": { 454 | "version": "2.0.0", 455 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 456 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 457 | "engines": { 458 | "node": ">= 0.8" 459 | } 460 | }, 461 | "node_modules/diff": { 462 | "version": "4.0.2", 463 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 464 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 465 | "engines": { 466 | "node": ">=0.3.1" 467 | } 468 | }, 469 | "node_modules/es6-promise": { 470 | "version": "4.2.8", 471 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", 472 | "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" 473 | }, 474 | "node_modules/es6-promisify": { 475 | "version": "5.0.0", 476 | "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", 477 | "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", 478 | "dependencies": { 479 | "es6-promise": "^4.0.3" 480 | } 481 | }, 482 | "node_modules/eventemitter3": { 483 | "version": "4.0.7", 484 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", 485 | "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" 486 | }, 487 | "node_modules/eyes": { 488 | "version": "0.1.8", 489 | "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", 490 | "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", 491 | "engines": { 492 | "node": "> 0.1.90" 493 | } 494 | }, 495 | "node_modules/fast-stable-stringify": { 496 | "version": "1.0.0", 497 | "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", 498 | "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==" 499 | }, 500 | "node_modules/file-uri-to-path": { 501 | "version": "1.0.0", 502 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", 503 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" 504 | }, 505 | "node_modules/humanize-ms": { 506 | "version": "1.2.1", 507 | "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", 508 | "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", 509 | "dependencies": { 510 | "ms": "^2.0.0" 511 | } 512 | }, 513 | "node_modules/ieee754": { 514 | "version": "1.2.1", 515 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 516 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 517 | "funding": [ 518 | { 519 | "type": "github", 520 | "url": "https://github.com/sponsors/feross" 521 | }, 522 | { 523 | "type": "patreon", 524 | "url": "https://www.patreon.com/feross" 525 | }, 526 | { 527 | "type": "consulting", 528 | "url": "https://feross.org/support" 529 | } 530 | ] 531 | }, 532 | "node_modules/isomorphic-ws": { 533 | "version": "4.0.1", 534 | "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", 535 | "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", 536 | "peerDependencies": { 537 | "ws": "*" 538 | } 539 | }, 540 | "node_modules/jayson": { 541 | "version": "4.1.0", 542 | "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.1.0.tgz", 543 | "integrity": "sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A==", 544 | "dependencies": { 545 | "@types/connect": "^3.4.33", 546 | "@types/node": "^12.12.54", 547 | "@types/ws": "^7.4.4", 548 | "commander": "^2.20.3", 549 | "delay": "^5.0.0", 550 | "es6-promisify": "^5.0.0", 551 | "eyes": "^0.1.8", 552 | "isomorphic-ws": "^4.0.1", 553 | "json-stringify-safe": "^5.0.1", 554 | "JSONStream": "^1.3.5", 555 | "uuid": "^8.3.2", 556 | "ws": "^7.4.5" 557 | }, 558 | "bin": { 559 | "jayson": "bin/jayson.js" 560 | }, 561 | "engines": { 562 | "node": ">=8" 563 | } 564 | }, 565 | "node_modules/jayson/node_modules/@types/node": { 566 | "version": "12.20.55", 567 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", 568 | "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" 569 | }, 570 | "node_modules/json-stringify-safe": { 571 | "version": "5.0.1", 572 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 573 | "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" 574 | }, 575 | "node_modules/jsonparse": { 576 | "version": "1.3.1", 577 | "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", 578 | "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", 579 | "engines": [ 580 | "node >= 0.2.0" 581 | ] 582 | }, 583 | "node_modules/JSONStream": { 584 | "version": "1.3.5", 585 | "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", 586 | "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", 587 | "dependencies": { 588 | "jsonparse": "^1.2.0", 589 | "through": ">=2.2.7 <3" 590 | }, 591 | "bin": { 592 | "JSONStream": "bin.js" 593 | }, 594 | "engines": { 595 | "node": "*" 596 | } 597 | }, 598 | "node_modules/make-error": { 599 | "version": "1.3.6", 600 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 601 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" 602 | }, 603 | "node_modules/ms": { 604 | "version": "2.1.2", 605 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 606 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 607 | }, 608 | "node_modules/node-fetch": { 609 | "version": "2.6.11", 610 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", 611 | "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", 612 | "dependencies": { 613 | "whatwg-url": "^5.0.0" 614 | }, 615 | "engines": { 616 | "node": "4.x || >=6.0.0" 617 | }, 618 | "peerDependencies": { 619 | "encoding": "^0.1.0" 620 | }, 621 | "peerDependenciesMeta": { 622 | "encoding": { 623 | "optional": true 624 | } 625 | } 626 | }, 627 | "node_modules/node-gyp-build": { 628 | "version": "4.6.0", 629 | "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", 630 | "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", 631 | "optional": true, 632 | "bin": { 633 | "node-gyp-build": "bin.js", 634 | "node-gyp-build-optional": "optional.js", 635 | "node-gyp-build-test": "build-test.js" 636 | } 637 | }, 638 | "node_modules/regenerator-runtime": { 639 | "version": "0.13.11", 640 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", 641 | "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" 642 | }, 643 | "node_modules/rpc-websockets": { 644 | "version": "7.5.1", 645 | "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.5.1.tgz", 646 | "integrity": "sha512-kGFkeTsmd37pHPMaHIgN1LVKXMi0JD782v4Ds9ZKtLlwdTKjn+CxM9A9/gLT2LaOuEcEFGL98h1QWQtlOIdW0w==", 647 | "dependencies": { 648 | "@babel/runtime": "^7.17.2", 649 | "eventemitter3": "^4.0.7", 650 | "uuid": "^8.3.2", 651 | "ws": "^8.5.0" 652 | }, 653 | "funding": { 654 | "type": "paypal", 655 | "url": "https://paypal.me/kozjak" 656 | }, 657 | "optionalDependencies": { 658 | "bufferutil": "^4.0.1", 659 | "utf-8-validate": "^5.0.2" 660 | } 661 | }, 662 | "node_modules/rpc-websockets/node_modules/ws": { 663 | "version": "8.13.0", 664 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", 665 | "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", 666 | "engines": { 667 | "node": ">=10.0.0" 668 | }, 669 | "peerDependencies": { 670 | "bufferutil": "^4.0.1", 671 | "utf-8-validate": ">=5.0.2" 672 | }, 673 | "peerDependenciesMeta": { 674 | "bufferutil": { 675 | "optional": true 676 | }, 677 | "utf-8-validate": { 678 | "optional": true 679 | } 680 | } 681 | }, 682 | "node_modules/safe-buffer": { 683 | "version": "5.2.1", 684 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 685 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 686 | "funding": [ 687 | { 688 | "type": "github", 689 | "url": "https://github.com/sponsors/feross" 690 | }, 691 | { 692 | "type": "patreon", 693 | "url": "https://www.patreon.com/feross" 694 | }, 695 | { 696 | "type": "consulting", 697 | "url": "https://feross.org/support" 698 | } 699 | ] 700 | }, 701 | "node_modules/superstruct": { 702 | "version": "0.14.2", 703 | "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.14.2.tgz", 704 | "integrity": "sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==" 705 | }, 706 | "node_modules/text-encoding-utf-8": { 707 | "version": "1.0.2", 708 | "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", 709 | "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" 710 | }, 711 | "node_modules/through": { 712 | "version": "2.3.8", 713 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 714 | "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" 715 | }, 716 | "node_modules/tr46": { 717 | "version": "0.0.3", 718 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 719 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" 720 | }, 721 | "node_modules/ts-node": { 722 | "version": "10.9.1", 723 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", 724 | "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", 725 | "dependencies": { 726 | "@cspotcode/source-map-support": "^0.8.0", 727 | "@tsconfig/node10": "^1.0.7", 728 | "@tsconfig/node12": "^1.0.7", 729 | "@tsconfig/node14": "^1.0.0", 730 | "@tsconfig/node16": "^1.0.2", 731 | "acorn": "^8.4.1", 732 | "acorn-walk": "^8.1.1", 733 | "arg": "^4.1.0", 734 | "create-require": "^1.1.0", 735 | "diff": "^4.0.1", 736 | "make-error": "^1.1.1", 737 | "v8-compile-cache-lib": "^3.0.1", 738 | "yn": "3.1.1" 739 | }, 740 | "bin": { 741 | "ts-node": "dist/bin.js", 742 | "ts-node-cwd": "dist/bin-cwd.js", 743 | "ts-node-esm": "dist/bin-esm.js", 744 | "ts-node-script": "dist/bin-script.js", 745 | "ts-node-transpile-only": "dist/bin-transpile.js", 746 | "ts-script": "dist/bin-script-deprecated.js" 747 | }, 748 | "peerDependencies": { 749 | "@swc/core": ">=1.2.50", 750 | "@swc/wasm": ">=1.2.50", 751 | "@types/node": "*", 752 | "typescript": ">=2.7" 753 | }, 754 | "peerDependenciesMeta": { 755 | "@swc/core": { 756 | "optional": true 757 | }, 758 | "@swc/wasm": { 759 | "optional": true 760 | } 761 | } 762 | }, 763 | "node_modules/typescript": { 764 | "version": "4.9.5", 765 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", 766 | "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", 767 | "bin": { 768 | "tsc": "bin/tsc", 769 | "tsserver": "bin/tsserver" 770 | }, 771 | "engines": { 772 | "node": ">=4.2.0" 773 | } 774 | }, 775 | "node_modules/utf-8-validate": { 776 | "version": "5.0.10", 777 | "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", 778 | "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", 779 | "hasInstallScript": true, 780 | "optional": true, 781 | "dependencies": { 782 | "node-gyp-build": "^4.3.0" 783 | }, 784 | "engines": { 785 | "node": ">=6.14.2" 786 | } 787 | }, 788 | "node_modules/uuid": { 789 | "version": "8.3.2", 790 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", 791 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", 792 | "bin": { 793 | "uuid": "dist/bin/uuid" 794 | } 795 | }, 796 | "node_modules/v8-compile-cache-lib": { 797 | "version": "3.0.1", 798 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 799 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" 800 | }, 801 | "node_modules/webidl-conversions": { 802 | "version": "3.0.1", 803 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 804 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" 805 | }, 806 | "node_modules/whatwg-url": { 807 | "version": "5.0.0", 808 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 809 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 810 | "dependencies": { 811 | "tr46": "~0.0.3", 812 | "webidl-conversions": "^3.0.0" 813 | } 814 | }, 815 | "node_modules/ws": { 816 | "version": "7.5.9", 817 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", 818 | "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", 819 | "engines": { 820 | "node": ">=8.3.0" 821 | }, 822 | "peerDependencies": { 823 | "bufferutil": "^4.0.1", 824 | "utf-8-validate": "^5.0.2" 825 | }, 826 | "peerDependenciesMeta": { 827 | "bufferutil": { 828 | "optional": true 829 | }, 830 | "utf-8-validate": { 831 | "optional": true 832 | } 833 | } 834 | }, 835 | "node_modules/yn": { 836 | "version": "3.1.1", 837 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 838 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 839 | "engines": { 840 | "node": ">=6" 841 | } 842 | } 843 | } 844 | } 845 | -------------------------------------------------------------------------------- /tokens/wrapping-sol/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "main": "yarn run ts-node ./src/main.ts" 4 | }, 5 | "dependencies": { 6 | "@metaplex-foundation/mpl-token-metadata": "^2.5.2", 7 | "@solana/spl-token": "^0.3.7", 8 | "@solana/web3.js": "^1.73.0", 9 | "ts-node": "^10.9.1", 10 | "typescript": "^4.9.4" 11 | }, 12 | "devDependencies": { 13 | "@types/node": "^18.11.18" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tokens/wrapping-sol/src/main.ts: -------------------------------------------------------------------------------- 1 | import { NATIVE_MINT, createAssociatedTokenAccountInstruction, getAssociatedTokenAddress, createSyncNativeInstruction, getAccount, closeAccount } from "@solana/spl-token"; 2 | import { clusterApiUrl, Connection, Keypair, LAMPORTS_PER_SOL, SystemProgram, Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; 3 | 4 | (async () => { 5 | 6 | // setting up devnet connection 7 | 8 | const connection = new Connection( 9 | clusterApiUrl('devnet'), 10 | 'confirmed' 11 | ) 12 | const wallet = Keypair.generate(); 13 | 14 | // airdropping sol to wallet 15 | 16 | const airdropSignature = await connection.requestAirdrop( 17 | wallet.publicKey, 18 | 2 * LAMPORTS_PER_SOL, 19 | ); 20 | 21 | await connection.confirmTransaction(airdropSignature); 22 | 23 | // getting associatedTokenAccount address with native mint 24 | 25 | const associatedTokenAccount = await getAssociatedTokenAddress( 26 | NATIVE_MINT, 27 | wallet.publicKey 28 | ) 29 | 30 | // Create associated token account to hold your wrapped SOL 31 | 32 | const ataTransaction = new Transaction() 33 | .add( 34 | createAssociatedTokenAccountInstruction( 35 | wallet.publicKey, 36 | associatedTokenAccount, 37 | wallet.publicKey, 38 | NATIVE_MINT 39 | ) 40 | ); 41 | 42 | await sendAndConfirmTransaction(connection, ataTransaction, [wallet]); 43 | 44 | // Transfer SOL to associated token account and use SyncNative to update wrapped SOL balance 45 | 46 | const solTransferTransaction = new Transaction() 47 | .add( 48 | SystemProgram.transfer({ 49 | fromPubkey: wallet.publicKey, 50 | toPubkey: associatedTokenAccount, 51 | lamports: LAMPORTS_PER_SOL 52 | }), 53 | createSyncNativeInstruction( 54 | associatedTokenAccount 55 | ) 56 | ) 57 | 58 | // transaction for sending sol 59 | const tx = await sendAndConfirmTransaction(connection, solTransferTransaction, [wallet]); 60 | console.log(`tx signature: ${tx}`) 61 | // getting account information 62 | const accountInfo = await getAccount(connection, associatedTokenAccount); 63 | console.log(`Native: ${accountInfo.isNative}, Lamports: ${accountInfo.amount}`); 64 | const walletBalance = await connection.getBalance(wallet.publicKey); 65 | console.log(`Balance before unwrapping 1 WSOL: ${walletBalance}`) 66 | 67 | // retrieving WSOL and send tokens to wallet 68 | await closeAccount(connection, wallet, associatedTokenAccount, wallet.publicKey, wallet); 69 | const walletBalancePostClose = await connection.getBalance(wallet.publicKey); 70 | console.log(`Balance after unwrapping 1 WSOL: ${walletBalancePostClose}`) 71 | 72 | })(); -------------------------------------------------------------------------------- /tokens/wrapping-sol/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": ["node"], 4 | "typeRoots": ["./node_modules/@types"], 5 | "lib": ["es2015"], 6 | "module": "commonjs", 7 | "target": "es6", 8 | "esModuleInterop": true 9 | } 10 | } 11 | --------------------------------------------------------------------------------