Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 51 additions & 68 deletions toolkits/payments-and-wallets/comparison-spl-light.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const ata = await getOrCreateAssociatedTokenAccount(
connection,
payer,
mint,
recipient,
recipient
);
// Share ata.address with sender

Expand All @@ -70,8 +70,8 @@ const tx = new Transaction().add(
payer.publicKey,
ata,
recipient,
mint,
),
mint
)
);
```

Expand Down Expand Up @@ -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
))
);
```

Expand All @@ -134,7 +134,7 @@ await transfer(
destinationAta,
owner,
amount,
decimals,
decimals
);
```

Expand All @@ -156,55 +156,50 @@ const tx = new Transaction().add(
sourceAta,
destinationAta,
owner.publicKey,
amount,
),
amount
)
);
```

**Light:**

```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:
Expand All @@ -222,7 +217,7 @@ const createAtaIx = createAssociatedTokenAccountIdempotentInstruction(
payer.publicKey,
destinationAta,
recipient,
mint,
mint
);

new Transaction().add(createAtaIx, transferIx);
Expand All @@ -243,7 +238,7 @@ const createAtaIx = createAssociatedTokenAccountInterfaceIdempotentInstruction(
destinationAta,
recipient,
mint,
LIGHT_TOKEN_PROGRAM_ID,
LIGHT_TOKEN_PROGRAM_ID
);

new Transaction().add(createAtaIx, transferIx);
Expand Down Expand Up @@ -323,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]);
}
```
14 changes: 7 additions & 7 deletions toolkits/payments-and-wallets/get-balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand All @@ -32,7 +32,7 @@ const payer = Keypair.fromSecretKey(
rpc,
payer,
mint,
payer,
payer
);

// 3. Mint to payer's ATA
Expand All @@ -44,7 +44,7 @@ const payer = Keypair.fromSecretKey(
rpc,
payer,
mint,
recipient,
recipient
);

// 5. Transfer from payer to recipient
Expand All @@ -53,17 +53,17 @@ const payer = Keypair.fromSecretKey(
payer,
sourceAta.address,
mint,
recipientAta.address,
recipient.publicKey,
payer,
bn(100),
bn(100)
);

// 6. Get recipient's balance after transfer
const { parsed: account } = await getAtaInterface(
rpc,
recipientAta.address,
recipient.publicKey,
mint,
mint
);
console.log("Recipient's balance:", account.amount);
})();
12 changes: 6 additions & 6 deletions toolkits/payments-and-wallets/get-history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand All @@ -31,7 +31,7 @@ const payer = Keypair.fromSecretKey(
rpc,
payer,
mint,
payer,
payer
);

// 3. Mint to payer's ATA
Expand All @@ -43,7 +43,7 @@ const payer = Keypair.fromSecretKey(
rpc,
payer,
mint,
recipient,
recipient
);

// 5. Transfer from payer to recipient
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions toolkits/payments-and-wallets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
78 changes: 78 additions & 0 deletions toolkits/payments-and-wallets/receive.ts
Original file line number Diff line number Diff line change
@@ -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());
})();
Loading
Loading