From cf608162e2b68d447c1c61442bc5bcc6a3ef0685 Mon Sep 17 00:00:00 2001 From: Swenschaeferjohann Date: Fri, 13 Feb 2026 07:23:28 +0000 Subject: [PATCH 1/3] upd js --- .../comparison-spl-light.md | 85 +++++++++---------- toolkits/payments-and-wallets/get-balance.ts | 14 +-- toolkits/payments-and-wallets/get-history.ts | 12 +-- .../payments-and-wallets/send-and-receive.ts | 12 +-- .../actions/transfer-interface.ts | 13 +-- .../instructions/transfer-interface.ts | 16 ++-- 6 files changed, 74 insertions(+), 78 deletions(-) diff --git a/toolkits/payments-and-wallets/comparison-spl-light.md b/toolkits/payments-and-wallets/comparison-spl-light.md index 113dffa..ed0a7ef 100644 --- a/toolkits/payments-and-wallets/comparison-spl-light.md +++ b/toolkits/payments-and-wallets/comparison-spl-light.md @@ -46,7 +46,7 @@ const ata = await getOrCreateAssociatedTokenAccount( connection, payer, mint, - recipient, + recipient ); // Share ata.address with sender @@ -70,8 +70,8 @@ const tx = new Transaction().add( payer.publicKey, ata, recipient, - mint, - ), + mint + ) ); ``` @@ -102,15 +102,15 @@ const tx = new Transaction().add( ata, recipient, mint, - LIGHT_TOKEN_PROGRAM_ID, + LIGHT_TOKEN_PROGRAM_ID ), ...(await createLoadAtaInstructions( rpc, ata, recipient, mint, - payer.publicKey, - )), + payer.publicKey + )) ); ``` @@ -134,7 +134,7 @@ await transfer( destinationAta, owner, amount, - decimals, + decimals ); ``` @@ -156,8 +156,8 @@ const tx = new Transaction().add( sourceAta, destinationAta, owner.publicKey, - amount, - ), + amount + ) ); ``` @@ -165,46 +165,41 @@ const tx = new Transaction().add( ```typescript const sourceAta = getAssociatedTokenAddressInterface(mint, owner.publicKey); -const destinationAta = getAssociatedTokenAddressInterface(mint, recipient); -await transferInterface( - rpc, - payer, - sourceAta, - mint, - destinationAta, - owner, - amount, -); +await transferInterface(rpc, payer, sourceAta, mint, recipient, owner, amount); ``` -**Light:** +**Light (instruction-level):** ```typescript +import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js"; import { - createLoadAtaInstructions, - createTransferInterfaceInstruction, - getAssociatedTokenAddressInterface, + createTransferInterfaceInstructions, + sliceLast, } from "@lightprotocol/compressed-token/unified"; -const sourceAta = getAssociatedTokenAddressInterface(mint, owner.publicKey); -const destinationAta = getAssociatedTokenAddressInterface(mint, recipient); - -const tx = new Transaction().add( - ...(await createLoadAtaInstructions( - rpc, - sourceAta, - owner.publicKey, - mint, - payer.publicKey, - )), - createTransferInterfaceInstruction( - sourceAta, - destinationAta, - owner.publicKey, - amount, - ), +const batches = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + amount, + owner.publicKey, + recipient +); +const { rest: loadBatches, last: transferBatch } = sliceLast(batches); + +await Promise.all( + loadBatches.map((batch) => + sendAndConfirmTransaction(rpc, new Transaction().add(...batch), [ + payer, + owner, + ]) + ) ); +await sendAndConfirmTransaction(rpc, new Transaction().add(...transferBatch), [ + payer, + owner, +]); ``` To ensure your recipient's ATA exists you can prepend an idempotent creation instruction in the same atomic transaction: @@ -222,7 +217,7 @@ const createAtaIx = createAssociatedTokenAccountIdempotentInstruction( payer.publicKey, destinationAta, recipient, - mint, + mint ); new Transaction().add(createAtaIx, transferIx); @@ -243,7 +238,7 @@ const createAtaIx = createAssociatedTokenAccountInterfaceIdempotentInstruction( destinationAta, recipient, mint, - LIGHT_TOKEN_PROGRAM_ID, + LIGHT_TOKEN_PROGRAM_ID ); new Transaction().add(createAtaIx, transferIx); @@ -342,7 +337,7 @@ const tx = new Transaction().add( lightTokenAta, owner.publicKey, mint, - payer.publicKey, + payer.publicKey )), createUnwrapInstruction( lightTokenAta, @@ -350,7 +345,7 @@ const tx = new Transaction().add( owner.publicKey, mint, amount, - splInterfaceInfo, - ), + splInterfaceInfo + ) ); ``` diff --git a/toolkits/payments-and-wallets/get-balance.ts b/toolkits/payments-and-wallets/get-balance.ts index d125c6f..0bc1fa2 100644 --- a/toolkits/payments-and-wallets/get-balance.ts +++ b/toolkits/payments-and-wallets/get-balance.ts @@ -19,8 +19,8 @@ const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { @@ -32,7 +32,7 @@ const payer = Keypair.fromSecretKey( rpc, payer, mint, - payer, + payer ); // 3. Mint to payer's ATA @@ -44,7 +44,7 @@ const payer = Keypair.fromSecretKey( rpc, payer, mint, - recipient, + recipient ); // 5. Transfer from payer to recipient @@ -53,9 +53,9 @@ const payer = Keypair.fromSecretKey( payer, sourceAta.address, mint, - recipientAta.address, + recipient.publicKey, payer, - bn(100), + bn(100) ); // 6. Get recipient's balance after transfer @@ -63,7 +63,7 @@ const payer = Keypair.fromSecretKey( rpc, recipientAta.address, recipient.publicKey, - mint, + mint ); console.log("Recipient's balance:", account.amount); })(); diff --git a/toolkits/payments-and-wallets/get-history.ts b/toolkits/payments-and-wallets/get-history.ts index 5bb1ae7..3517c9a 100644 --- a/toolkits/payments-and-wallets/get-history.ts +++ b/toolkits/payments-and-wallets/get-history.ts @@ -18,8 +18,8 @@ const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { @@ -31,7 +31,7 @@ const payer = Keypair.fromSecretKey( rpc, payer, mint, - payer, + payer ); // 3. Mint to payer's ATA @@ -43,7 +43,7 @@ const payer = Keypair.fromSecretKey( rpc, payer, mint, - recipient, + recipient ); // 5. Transfer from payer to recipient @@ -52,9 +52,9 @@ const payer = Keypair.fromSecretKey( payer, sourceAta.address, mint, - recipientAta.address, + recipient.publicKey, payer, - bn(100), + bn(100) ); // 6. Get transaction history diff --git a/toolkits/payments-and-wallets/send-and-receive.ts b/toolkits/payments-and-wallets/send-and-receive.ts index 43d410f..bba65fa 100644 --- a/toolkits/payments-and-wallets/send-and-receive.ts +++ b/toolkits/payments-and-wallets/send-and-receive.ts @@ -18,8 +18,8 @@ const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { @@ -31,7 +31,7 @@ const payer = Keypair.fromSecretKey( rpc, payer, mint, - payer, + payer ); // 3. Mint to payer's ATA @@ -43,7 +43,7 @@ const payer = Keypair.fromSecretKey( rpc, payer, mint, - recipient, + recipient ); // 5. Transfer from payer to recipient @@ -52,9 +52,9 @@ const payer = Keypair.fromSecretKey( payer, sourceAta.address, mint, - recipientAta.address, + recipient.publicKey, payer, - bn(100), + bn(100) ); console.log("Tx:", txId); diff --git a/typescript-client/actions/transfer-interface.ts b/typescript-client/actions/transfer-interface.ts index 7c3bf56..71bce5b 100644 --- a/typescript-client/actions/transfer-interface.ts +++ b/typescript-client/actions/transfer-interface.ts @@ -19,8 +19,8 @@ const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { @@ -30,7 +30,7 @@ const payer = Keypair.fromSecretKey( await createAtaInterface(rpc, payer, mint, sender.publicKey); const senderAta = getAssociatedTokenAddressInterface( mint, - sender.publicKey, + sender.publicKey ); await mintToInterface(rpc, payer, mint, senderAta, payer, 1_000_000_000); @@ -38,18 +38,19 @@ const payer = Keypair.fromSecretKey( await createAtaInterface(rpc, payer, mint, recipient.publicKey); const recipientAta = getAssociatedTokenAddressInterface( mint, - recipient.publicKey, + recipient.publicKey ); // Transfer tokens between light-token associated token accounts + // destination is recipient wallet; transferInterface creates recipient ATA idempotently const tx = await transferInterface( rpc, payer, senderAta, mint, - recipientAta, + recipient.publicKey, sender, - 500_000_000, + 500_000_000 ); console.log("Tx:", tx); diff --git a/typescript-client/instructions/transfer-interface.ts b/typescript-client/instructions/transfer-interface.ts index d1a07d9..5324596 100644 --- a/typescript-client/instructions/transfer-interface.ts +++ b/typescript-client/instructions/transfer-interface.ts @@ -1,7 +1,6 @@ import "dotenv/config"; import { Keypair, - ComputeBudgetProgram, Transaction, sendAndConfirmTransaction, } from "@solana/web3.js"; @@ -10,7 +9,7 @@ import { createMintInterface, createAtaInterface, mintToInterface, - createTransferInterfaceInstruction, + createLightTokenTransferInstruction, getAssociatedTokenAddressInterface, } from "@lightprotocol/compressed-token"; import { homedir } from "os"; @@ -24,8 +23,8 @@ const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { @@ -35,7 +34,7 @@ const payer = Keypair.fromSecretKey( await createAtaInterface(rpc, payer, mint, sender.publicKey); const senderAta = getAssociatedTokenAddressInterface( mint, - sender.publicKey, + sender.publicKey ); await mintToInterface(rpc, payer, mint, senderAta, payer, 1_000_000_000); @@ -43,15 +42,16 @@ const payer = Keypair.fromSecretKey( await createAtaInterface(rpc, payer, mint, recipient.publicKey); const recipientAta = getAssociatedTokenAddressInterface( mint, - recipient.publicKey, + recipient.publicKey ); // Transfer tokens between light-token associate token accounts - const ix = createTransferInterfaceInstruction( + // Hot sender only; for cold balance use createTransferInterfaceInstructions + sliceLast + const ix = createLightTokenTransferInstruction( senderAta, recipientAta, sender.publicKey, - 500_000_000, + 500_000_000 ); const tx = new Transaction().add(ix); From 90c7d723af51993b676ca20a50655fbdc8d9f98e Mon Sep 17 00:00:00 2001 From: Swenschaeferjohann Date: Fri, 13 Feb 2026 14:32:53 +0000 Subject: [PATCH 2/3] bump to use spl interface --- .../instructions/create-spl-interface.ts | 6 ++--- .../instructions/create-spl-mint.ts | 24 ++++++++++--------- .../instructions/create-t22-mint.ts | 24 ++++++++++--------- .../instructions/create-token-pool.ts | 6 ++--- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/typescript-client/instructions/create-spl-interface.ts b/typescript-client/instructions/create-spl-interface.ts index 8fee304..99e90e3 100644 --- a/typescript-client/instructions/create-spl-interface.ts +++ b/typescript-client/instructions/create-spl-interface.ts @@ -19,15 +19,15 @@ const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { const existingMint = new PublicKey("YOUR_EXISTING_MINT_ADDRESS"); // Register SPL interface PDA to enable interop with Light Tokens - const ix = await CompressedTokenProgram.createTokenPool({ + const ix = await CompressedTokenProgram.createSplInterface({ feePayer: payer.publicKey, mint: existingMint, tokenProgramId: TOKEN_PROGRAM_ID, diff --git a/typescript-client/instructions/create-spl-mint.ts b/typescript-client/instructions/create-spl-mint.ts index e906f5c..4cf107a 100644 --- a/typescript-client/instructions/create-spl-mint.ts +++ b/typescript-client/instructions/create-spl-mint.ts @@ -23,8 +23,8 @@ const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { @@ -32,8 +32,9 @@ const payer = Keypair.fromSecretKey( const decimals = 9; // Get rent for mint account - const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(MINT_SIZE); + const rentExemptBalance = await rpc.getMinimumBalanceForRentExemption( + MINT_SIZE + ); // Instruction 1: Create mint account const createMintAccountIx = SystemProgram.createAccount({ @@ -50,21 +51,22 @@ const payer = Keypair.fromSecretKey( decimals, payer.publicKey, // mint authority null, // freeze authority - TOKEN_PROGRAM_ID, + TOKEN_PROGRAM_ID ); // Instruction 3: Create SPL interface PDA // Holds SPL tokens when wrapped to light-token - const createSplInterfaceIx = await CompressedTokenProgram.createTokenPool({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_PROGRAM_ID, - }); + const createSplInterfaceIx = + await CompressedTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_PROGRAM_ID, + }); const tx = new Transaction().add( createMintAccountIx, initializeMintIx, - createSplInterfaceIx, + createSplInterfaceIx ); const signature = await sendAndConfirmTransaction(rpc, tx, [ diff --git a/typescript-client/instructions/create-t22-mint.ts b/typescript-client/instructions/create-t22-mint.ts index 0bcdd24..c0875ea 100644 --- a/typescript-client/instructions/create-t22-mint.ts +++ b/typescript-client/instructions/create-t22-mint.ts @@ -23,8 +23,8 @@ const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { @@ -32,8 +32,9 @@ const payer = Keypair.fromSecretKey( const decimals = 9; // Get rent for mint account - const rentExemptBalance = - await rpc.getMinimumBalanceForRentExemption(MINT_SIZE); + const rentExemptBalance = await rpc.getMinimumBalanceForRentExemption( + MINT_SIZE + ); // Instruction 1: Create mint account const createMintAccountIx = SystemProgram.createAccount({ @@ -50,21 +51,22 @@ const payer = Keypair.fromSecretKey( decimals, payer.publicKey, // mint authority null, // freeze authority - TOKEN_2022_PROGRAM_ID, + TOKEN_2022_PROGRAM_ID ); // Instruction 3: Create SPL interface PDA // Holds Token-2022 tokens when wrapped to light-token - const createSplInterfaceIx = await CompressedTokenProgram.createTokenPool({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, - }); + const createSplInterfaceIx = + await CompressedTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, + }); const tx = new Transaction().add( createMintAccountIx, initializeMintIx, - createSplInterfaceIx, + createSplInterfaceIx ); const signature = await sendAndConfirmTransaction(rpc, tx, [ diff --git a/typescript-client/instructions/create-token-pool.ts b/typescript-client/instructions/create-token-pool.ts index a0bcdf7..4ce6679 100644 --- a/typescript-client/instructions/create-token-pool.ts +++ b/typescript-client/instructions/create-token-pool.ts @@ -19,14 +19,14 @@ const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { const existingMint = new PublicKey("YOUR_EXISTING_MINT_ADDRESS"); - const ix = await CompressedTokenProgram.createTokenPool({ + const ix = await CompressedTokenProgram.createSplInterface({ feePayer: payer.publicKey, mint: existingMint, tokenProgramId: TOKEN_PROGRAM_ID, From c71d200c531d27f625735a20c79086e7830a9409 Mon Sep 17 00:00:00 2001 From: Swenschaeferjohann Date: Fri, 13 Feb 2026 17:35:23 +0000 Subject: [PATCH 3/3] update --- .../comparison-spl-light.md | 40 ++++------ toolkits/payments-and-wallets/package.json | 4 + toolkits/payments-and-wallets/receive.ts | 78 +++++++++++++++++++ .../payments-and-wallets/register-spl-mint.ts | 43 ++++++++++ toolkits/payments-and-wallets/send-action.ts | 72 +++++++++++++++++ .../payments-and-wallets/send-instruction.ts | 75 ++++++++++++++++++ .../instructions/create-spl-interface.ts | 4 +- .../instructions/create-spl-mint.ts | 13 ++-- .../instructions/create-t22-mint.ts | 13 ++-- .../instructions/create-token-pool.ts | 4 +- typescript-client/instructions/unwrap.ts | 50 +++++------- 11 files changed, 322 insertions(+), 74 deletions(-) create mode 100644 toolkits/payments-and-wallets/receive.ts create mode 100644 toolkits/payments-and-wallets/register-spl-mint.ts create mode 100644 toolkits/payments-and-wallets/send-action.ts create mode 100644 toolkits/payments-and-wallets/send-instruction.ts diff --git a/toolkits/payments-and-wallets/comparison-spl-light.md b/toolkits/payments-and-wallets/comparison-spl-light.md index ed0a7ef..f1f4493 100644 --- a/toolkits/payments-and-wallets/comparison-spl-light.md +++ b/toolkits/payments-and-wallets/comparison-spl-light.md @@ -318,34 +318,22 @@ await unwrap(rpc, payer, splAta, owner, mint, amount); ```typescript import { getAssociatedTokenAddressSync } from "@solana/spl-token"; -import { - createLoadAtaInstructions, - createUnwrapInstruction, - getAssociatedTokenAddressInterface, -} from "@lightprotocol/compressed-token/unified"; -import { getSplInterfaceInfos } from "@lightprotocol/compressed-token"; +import { createUnwrapInstructions } from "@lightprotocol/compressed-token/unified"; -const lightTokenAta = getAssociatedTokenAddressInterface(mint, owner.publicKey); const splAta = getAssociatedTokenAddressSync(mint, owner.publicKey); -const splInterfaceInfos = await getSplInterfaceInfos(rpc, mint); -const splInterfaceInfo = splInterfaceInfos.find((i) => i.isInitialized); - -const tx = new Transaction().add( - ...(await createLoadAtaInstructions( - rpc, - lightTokenAta, - owner.publicKey, - mint, - payer.publicKey - )), - createUnwrapInstruction( - lightTokenAta, - splAta, - owner.publicKey, - mint, - amount, - splInterfaceInfo - ) +// Handles loading cold state + unwrapping in one go. +const instructions = await createUnwrapInstructions( + rpc, + splAta, + owner.publicKey, + mint, + amount, + payer.publicKey ); + +for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer, owner]); +} ``` diff --git a/toolkits/payments-and-wallets/package.json b/toolkits/payments-and-wallets/package.json index c9b4294..2c06afc 100644 --- a/toolkits/payments-and-wallets/package.json +++ b/toolkits/payments-and-wallets/package.json @@ -4,6 +4,10 @@ "description": "Light Token Payments Toolkit Examples", "type": "module", "scripts": { + "register-spl-mint": "tsx register-spl-mint.ts", + "receive": "tsx receive.ts", + "send-instruction": "tsx send-instruction.ts", + "send-action": "tsx send-action.ts", "send-and-receive": "tsx send-and-receive.ts", "get-balance": "tsx get-balance.ts", "get-history": "tsx get-history.ts", diff --git a/toolkits/payments-and-wallets/receive.ts b/toolkits/payments-and-wallets/receive.ts new file mode 100644 index 0000000..66fa87c --- /dev/null +++ b/toolkits/payments-and-wallets/receive.ts @@ -0,0 +1,78 @@ +import "dotenv/config"; +import { + Keypair, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc, bn } from "@lightprotocol/stateless.js"; +import { + createMintInterface, + mintToInterface, + getOrCreateAtaInterface, + createLoadAtaInstructions, + getAssociatedTokenAddressInterface, +} from "@lightprotocol/compressed-token/unified"; +import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; +import { homedir } from "os"; +import { readFileSync } from "fs"; + +// devnet: +// const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; +// const rpc = createRpc(RPC_URL); +// localnet: +const rpc = createRpc(); + +const payer = Keypair.fromSecretKey( + new Uint8Array( + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) +); + +(async function () { + // Setup: Create SPL mint with interface, fund an ATA + const { mint } = await createMintInterface( + rpc, + payer, + payer, + null, + 9, + undefined, + undefined, + TOKEN_PROGRAM_ID + ); + const { parsed: sourceAta } = await getOrCreateAtaInterface( + rpc, + payer, + mint, + payer + ); + await mintToInterface( + rpc, + payer, + mint, + sourceAta.address, + payer, + bn(1_000_000) + ); + + // Receive: Load creates the ATA if needed and pulls any cold state to hot. + const recipient = Keypair.generate(); + const ata = getAssociatedTokenAddressInterface(mint, recipient.publicKey); + + // Returns TransactionInstruction[][]. Each inner array is one txn. + // Almost always one. Empty = noop. + const instructions = await createLoadAtaInstructions( + rpc, + ata, + recipient.publicKey, + mint, + payer.publicKey + ); + + for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + await sendAndConfirmTransaction(rpc, tx, [payer]); + } + + console.log("Recipient ATA:", ata.toBase58()); +})(); diff --git a/toolkits/payments-and-wallets/register-spl-mint.ts b/toolkits/payments-and-wallets/register-spl-mint.ts new file mode 100644 index 0000000..7309a9e --- /dev/null +++ b/toolkits/payments-and-wallets/register-spl-mint.ts @@ -0,0 +1,43 @@ +import "dotenv/config"; +import { + Keypair, + PublicKey, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc } from "@lightprotocol/stateless.js"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; +import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; +import { homedir } from "os"; +import { readFileSync } from "fs"; + +// devnet: +// const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; +// const rpc = createRpc(RPC_URL); +// localnet: +const rpc = createRpc(); + +const payer = Keypair.fromSecretKey( + new Uint8Array( + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) +); + +(async function () { + // Replace with your existing SPL mint (e.g. USDC) + const mint = new PublicKey("YOUR_EXISTING_MINT_ADDRESS"); + + // One-time: Register the SPL interface PDA for this mint. + // This creates the omnibus account that holds SPL tokens when wrapped to light-token. + const ix = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint, + tokenProgramId: TOKEN_PROGRAM_ID, + }); + + const tx = new Transaction().add(ix); + const signature = await sendAndConfirmTransaction(rpc, tx, [payer]); + + console.log("Mint:", mint.toBase58()); + console.log("Tx:", signature); +})(); diff --git a/toolkits/payments-and-wallets/send-action.ts b/toolkits/payments-and-wallets/send-action.ts new file mode 100644 index 0000000..47b6736 --- /dev/null +++ b/toolkits/payments-and-wallets/send-action.ts @@ -0,0 +1,72 @@ +import "dotenv/config"; +import { Keypair } from "@solana/web3.js"; +import { createRpc, bn } from "@lightprotocol/stateless.js"; +import { + createMintInterface, + mintToInterface, + getOrCreateAtaInterface, + getAssociatedTokenAddressInterface, + transferInterface, +} from "@lightprotocol/compressed-token/unified"; +import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; +import { homedir } from "os"; +import { readFileSync } from "fs"; + +// devnet: +// const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; +// const rpc = createRpc(RPC_URL); +// localnet: +const rpc = createRpc(); + +const payer = Keypair.fromSecretKey( + new Uint8Array( + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) +); + +(async function () { + // Setup: Create SPL mint with interface, fund an ATA + const { mint } = await createMintInterface( + rpc, + payer, + payer, + null, + 9, + undefined, + undefined, + TOKEN_PROGRAM_ID + ); + const { parsed: sourceAta } = await getOrCreateAtaInterface( + rpc, + payer, + mint, + payer + ); + await mintToInterface( + rpc, + payer, + mint, + sourceAta.address, + payer, + bn(1_000_000) + ); + + const recipient = Keypair.generate(); + const sourceAtaAddress = getAssociatedTokenAddressInterface( + mint, + payer.publicKey + ); + + // Loads cold balances, creates recipient ATA, transfers. + const sig = await transferInterface( + rpc, + payer, + sourceAtaAddress, + mint, + recipient.publicKey, + payer, + bn(100) + ); + + console.log("Tx:", sig); +})(); diff --git a/toolkits/payments-and-wallets/send-instruction.ts b/toolkits/payments-and-wallets/send-instruction.ts new file mode 100644 index 0000000..f369f1d --- /dev/null +++ b/toolkits/payments-and-wallets/send-instruction.ts @@ -0,0 +1,75 @@ +import "dotenv/config"; +import { + Keypair, + Transaction, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import { createRpc, bn } from "@lightprotocol/stateless.js"; +import { + createMintInterface, + mintToInterface, + getOrCreateAtaInterface, + createTransferInterfaceInstructions, +} from "@lightprotocol/compressed-token/unified"; +import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; +import { homedir } from "os"; +import { readFileSync } from "fs"; + +// devnet: +// const RPC_URL = `https://devnet.helius-rpc.com?api-key=${process.env.API_KEY!}`; +// const rpc = createRpc(RPC_URL); +// localnet: +const rpc = createRpc(); + +const payer = Keypair.fromSecretKey( + new Uint8Array( + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) +); + +(async function () { + // Setup: Create SPL mint with interface, fund an ATA + const { mint } = await createMintInterface( + rpc, + payer, + payer, + null, + 9, + undefined, + undefined, + TOKEN_PROGRAM_ID + ); + const { parsed: sourceAta } = await getOrCreateAtaInterface( + rpc, + payer, + mint, + payer + ); + await mintToInterface( + rpc, + payer, + mint, + sourceAta.address, + payer, + bn(1_000_000) + ); + + const recipient = Keypair.generate(); + + // Returns TransactionInstruction[][]. Each inner array is one txn. + // Almost always this returns one atomic transaction. + const instructions = await createTransferInterfaceInstructions( + rpc, + payer.publicKey, + mint, + bn(100), + payer.publicKey, + recipient.publicKey + ); + + for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + const sig = await sendAndConfirmTransaction(rpc, tx, [payer]); + console.log("Tx:", sig); + } +})(); diff --git a/typescript-client/instructions/create-spl-interface.ts b/typescript-client/instructions/create-spl-interface.ts index 99e90e3..7a6736d 100644 --- a/typescript-client/instructions/create-spl-interface.ts +++ b/typescript-client/instructions/create-spl-interface.ts @@ -6,7 +6,7 @@ import { sendAndConfirmTransaction, } from "@solana/web3.js"; import { createRpc } from "@lightprotocol/stateless.js"; -import { CompressedTokenProgram } from "@lightprotocol/compressed-token"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; import { homedir } from "os"; import { readFileSync } from "fs"; @@ -27,7 +27,7 @@ const payer = Keypair.fromSecretKey( const existingMint = new PublicKey("YOUR_EXISTING_MINT_ADDRESS"); // Register SPL interface PDA to enable interop with Light Tokens - const ix = await CompressedTokenProgram.createSplInterface({ + const ix = await LightTokenProgram.createSplInterface({ feePayer: payer.publicKey, mint: existingMint, tokenProgramId: TOKEN_PROGRAM_ID, diff --git a/typescript-client/instructions/create-spl-mint.ts b/typescript-client/instructions/create-spl-mint.ts index 4cf107a..9a8e68f 100644 --- a/typescript-client/instructions/create-spl-mint.ts +++ b/typescript-client/instructions/create-spl-mint.ts @@ -6,7 +6,7 @@ import { sendAndConfirmTransaction, } from "@solana/web3.js"; import { createRpc } from "@lightprotocol/stateless.js"; -import { CompressedTokenProgram } from "@lightprotocol/compressed-token"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; import { MINT_SIZE, TOKEN_PROGRAM_ID, @@ -56,12 +56,11 @@ const payer = Keypair.fromSecretKey( // Instruction 3: Create SPL interface PDA // Holds SPL tokens when wrapped to light-token - const createSplInterfaceIx = - await CompressedTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_PROGRAM_ID, - }); + const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_PROGRAM_ID, + }); const tx = new Transaction().add( createMintAccountIx, diff --git a/typescript-client/instructions/create-t22-mint.ts b/typescript-client/instructions/create-t22-mint.ts index c0875ea..10bf770 100644 --- a/typescript-client/instructions/create-t22-mint.ts +++ b/typescript-client/instructions/create-t22-mint.ts @@ -6,7 +6,7 @@ import { sendAndConfirmTransaction, } from "@solana/web3.js"; import { createRpc } from "@lightprotocol/stateless.js"; -import { CompressedTokenProgram } from "@lightprotocol/compressed-token"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; import { MINT_SIZE, TOKEN_2022_PROGRAM_ID, @@ -56,12 +56,11 @@ const payer = Keypair.fromSecretKey( // Instruction 3: Create SPL interface PDA // Holds Token-2022 tokens when wrapped to light-token - const createSplInterfaceIx = - await CompressedTokenProgram.createSplInterface({ - feePayer: payer.publicKey, - mint: mintKeypair.publicKey, - tokenProgramId: TOKEN_2022_PROGRAM_ID, - }); + const createSplInterfaceIx = await LightTokenProgram.createSplInterface({ + feePayer: payer.publicKey, + mint: mintKeypair.publicKey, + tokenProgramId: TOKEN_2022_PROGRAM_ID, + }); const tx = new Transaction().add( createMintAccountIx, diff --git a/typescript-client/instructions/create-token-pool.ts b/typescript-client/instructions/create-token-pool.ts index 4ce6679..7f37570 100644 --- a/typescript-client/instructions/create-token-pool.ts +++ b/typescript-client/instructions/create-token-pool.ts @@ -6,7 +6,7 @@ import { sendAndConfirmTransaction, } from "@solana/web3.js"; import { createRpc } from "@lightprotocol/stateless.js"; -import { CompressedTokenProgram } from "@lightprotocol/compressed-token"; +import { LightTokenProgram } from "@lightprotocol/compressed-token"; import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; import { homedir } from "os"; import { readFileSync } from "fs"; @@ -26,7 +26,7 @@ const payer = Keypair.fromSecretKey( (async function () { const existingMint = new PublicKey("YOUR_EXISTING_MINT_ADDRESS"); - const ix = await CompressedTokenProgram.createSplInterface({ + const ix = await LightTokenProgram.createSplInterface({ feePayer: payer.publicKey, mint: existingMint, tokenProgramId: TOKEN_PROGRAM_ID, diff --git a/typescript-client/instructions/unwrap.ts b/typescript-client/instructions/unwrap.ts index 9a9598f..342f333 100644 --- a/typescript-client/instructions/unwrap.ts +++ b/typescript-client/instructions/unwrap.ts @@ -1,7 +1,6 @@ import "dotenv/config"; import { Keypair, - ComputeBudgetProgram, Transaction, sendAndConfirmTransaction, } from "@solana/web3.js"; @@ -11,9 +10,8 @@ import { createAtaInterface, mintToInterface, getAssociatedTokenAddressInterface, - getSplInterfaceInfos, -} from "@lightprotocol/compressed-token"; -import { createUnwrapInstruction } from "@lightprotocol/compressed-token/unified"; + createUnwrapInstructions, +} from "@lightprotocol/compressed-token/unified"; import { createAssociatedTokenAccount, TOKEN_2022_PROGRAM_ID, @@ -29,52 +27,44 @@ const rpc = createRpc(); const payer = Keypair.fromSecretKey( new Uint8Array( - JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")), - ), + JSON.parse(readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")) + ) ); (async function () { // Setup: Create and mint tokens to light-token associated token account const { mint } = await createMintInterface(rpc, payer, payer, null, 9); await createAtaInterface(rpc, payer, mint, payer.publicKey); - const destination = getAssociatedTokenAddressInterface(mint, payer.publicKey); + const destination = getAssociatedTokenAddressInterface( + mint, + payer.publicKey + ); await mintToInterface(rpc, payer, mint, destination, payer, 1000); - // Unwrap light-token to SPL associated token account - const lightTokenAta = getAssociatedTokenAddressInterface(mint, payer.publicKey); - + // Create destination SPL ATA const splAta = await createAssociatedTokenAccount( rpc, payer, mint, payer.publicKey, undefined, - TOKEN_2022_PROGRAM_ID, - ); - - const splInterfaceInfos = await getSplInterfaceInfos(rpc, mint); - const splInterfaceInfo = splInterfaceInfos.find( - (info) => info.isInitialized, + TOKEN_2022_PROGRAM_ID ); - if (!splInterfaceInfo) throw new Error("No SPL interface found"); - - const ix = createUnwrapInstruction( - lightTokenAta, + // Returns TransactionInstruction[][]. Each inner array is one txn. + // Handles loading cold state + unwrapping in one go. + const instructions = await createUnwrapInstructions( + rpc, splAta, payer.publicKey, mint, 500, - splInterfaceInfo, - 9, // decimals - must match the mint decimals - payer.publicKey, - ); - - const tx = new Transaction().add( - ComputeBudgetProgram.setComputeUnitLimit({ units: 200_000 }), - ix, + payer.publicKey ); - const signature = await sendAndConfirmTransaction(rpc, tx, [payer]); - console.log("Tx:", signature); + for (const ixs of instructions) { + const tx = new Transaction().add(...ixs); + const signature = await sendAndConfirmTransaction(rpc, tx, [payer]); + console.log("Tx:", signature); + } })();