diff --git a/docs/content/docs/token-wrap.mdx b/docs/content/docs/token-wrap.mdx
index e80584a..5ee90cd 100644
--- a/docs/content/docs/token-wrap.mdx
+++ b/docs/content/docs/token-wrap.mdx
@@ -31,7 +31,7 @@ address of the original *unwrapped* token mint. This allows anyone to easily det
corresponding to a wrapped token, facilitating unwrapping.
2. **`Wrap`:** This operation accepts deposits of unwrapped tokens and mints wrapped tokens.
- * Unwrapped tokens are transferred from the user's account to an escrow account owned by the wrapped mint authority (different for every mint). Any unwrapped token account whose owner is a PDA controlled by the Token Wrap program can be used.
+ * Unwrapped tokens are transferred from the user's account to a specific escrow Associated Token Account (ATA). This ATA is for the unwrapped mint, and its authority is a Program Derived Address (PDA) controlled by the Token Wrap program (unique for each wrapped mint).
* An equivalent amount of wrapped tokens is minted to the user's wrapped token account.
3. **`Unwrap`:** This operation burns wrapped tokens and releases unwrapped token deposits.
@@ -136,15 +136,20 @@ To create a new wrapped token mint, first you need to identify the unwrapped tok
```typescript
import {
address,
+ appendTransactionMessageInstructions,
createKeyPairSignerFromBytes,
createSolanaRpc,
createSolanaRpcSubscriptions,
+ createTransactionMessage,
getSignatureFromTransaction,
+ pipe,
sendAndConfirmTransactionFactory,
+ setTransactionMessageFeePayerSigner,
+ setTransactionMessageLifetimeUsingBlockhash,
signTransactionMessageWithSigners,
} from '@solana/kit';
import { TOKEN_2022_PROGRAM_ADDRESS } from '@solana-program/token-2022';
- import { createMintTx } from '@solana-program/token-wrap';
+ import { createMint } from '@solana-program/token-wrap';
// Replace these consts with your own
const PRIVATE_KEY_PAIR = new Uint8Array([242, 30, 38, 177, 152, 71, ... ]);
@@ -158,28 +163,32 @@ To create a new wrapped token mint, first you need to identify the unwrapped tok
const payer = await createKeyPairSignerFromBytes(PRIVATE_KEY_PAIR);
const { value: blockhash } = await rpc.getLatestBlockhash().send();
- const createMintMessage = await createMintTx({
+ const createMintHelper = await createMint({
rpc,
- blockhash,
unwrappedMint: UNWRAPPED_MINT_ADDRESS,
wrappedTokenProgram: TOKEN_2022_PROGRAM_ADDRESS,
payer,
idempotent: true,
});
- const signedCreateMintTx = await signTransactionMessageWithSigners(createMintMessage.tx);
- await sendAndConfirm(signedCreateMintTx, { commitment: 'confirmed' });
- const createMintSignature = getSignatureFromTransaction(signedCreateMintTx);
+ const createMintTx = await pipe(
+ createTransactionMessage({ version: 0 }),
+ tx => setTransactionMessageFeePayerSigner(payer, tx),
+ tx => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),
+ tx => appendTransactionMessageInstructions(createMintHelper.ixs, tx),
+ tx => signTransactionMessageWithSigners(tx),
+ );
+ await sendAndConfirm(createMintTx, { commitment: 'confirmed' });
+ const createMintSignature = getSignatureFromTransaction(createMintTx);
console.log('======== Create Mint Successful ========');
- console.log('Wrapped Mint:', createMintMessage.wrappedMint);
- console.log('Backpointer:', createMintMessage.backpointer);
- console.log('Funded wrapped mint lamports:', createMintMessage.fundedWrappedMintLamports);
- console.log('Funded backpointer lamports:', createMintMessage.fundedBackpointerLamports);
+ console.log('Wrapped Mint:', createMintHelper.wrappedMint);
+ console.log('Backpointer:', createMintHelper.backpointer);
+ console.log('Funded wrapped mint lamports:', createMintHelper.fundedWrappedMintLamports);
+ console.log('Funded backpointer lamports:', createMintHelper.fundedBackpointerLamports);
console.log('Signature:', createMintSignature);
}
void main();
-
```
@@ -199,6 +208,7 @@ To interact with wrapped tokens, you need to know the PDAs (Program Derived Addr
Wrapped mint address: B8HbxGU4npjgjMX5xJFR2FYkgvAHdZqyVb8MyFvdsuNM
Wrapped mint authority: 8WdYPmtq8c6ZfmHMZUwCQL2E8qVHEV8rG9MXkyax3joR
Wrapped backpointer address: CNjr898vsBdzWxrJApMSAQac4A7o7qLRcSseTb56X7C9
+ Unwrapped escrow address: QrzXtFZedQmg8AGu6AnUkPgmsLnR9ErsjNRLdCrRVWw
```
@@ -210,7 +220,8 @@ To interact with wrapped tokens, you need to know the PDAs (Program Derived Addr
findWrappedMintAuthorityPda,
findWrappedMintPda,
} from '@solana-program/token-wrap';
- import { TOKEN_2022_PROGRAM_ADDRESS } from '@solana-program/token-2022';
+ import { findAssociatedTokenPda, TOKEN_2022_PROGRAM_ADDRESS } from '@solana-program/token-2022';
+ import { TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';
const UNWRAPPED_MINT_ADDRESS = address('5StBUZ2w8ShDN9iF7NkGpDNNH2wv9jK7zhArmVRpwrCt');
@@ -222,9 +233,16 @@ To interact with wrapped tokens, you need to know the PDAs (Program Derived Addr
const [backpointer] = await findBackpointerPda({ wrappedMint });
const [wrappedMintAuthority] = await findWrappedMintAuthorityPda({ wrappedMint });
+ const [escrowAccount] = await findAssociatedTokenPda({
+ owner: wrappedMintAuthority,
+ mint: UNWRAPPED_MINT_ADDRESS,
+ tokenProgram: TOKEN_PROGRAM_ADDRESS, // unwrapped token program address
+ });
+
console.log('WRAPPED_MINT_ADDRESS', wrappedMint);
console.log('BACKPOINTER', backpointer);
console.log('WRAPPED_MINT_AUTHORITY', wrappedMintAuthority);
+ console.log('ESCROW_ACCOUNT', escrowAccount);
}
void main();
@@ -234,7 +252,8 @@ To interact with wrapped tokens, you need to know the PDAs (Program Derived Addr
### Create escrow account
-Before wrapping tokens, you need to create an account to hold the unwrapped tokens. The escrow account's owner must be the correct PDA (see `find-pdas` command above). There is also a helper to create this account:
+Before wrapping tokens, if you are the first to do so for this wrapped mint, you may need to initialize the escrow account to custody the unwrapped tokens.
+The account must be an ATA whose owner is the mint authority PDA (see `find-pdas` command above). There is also a helper to initialize this account:
@@ -256,18 +275,24 @@ Before wrapping tokens, you need to create an account to hold the unwrapped toke
```typescript
import {
address,
+ appendTransactionMessageInstructions,
createKeyPairSignerFromBytes,
createSolanaRpc,
createSolanaRpcSubscriptions,
+ createTransactionMessage,
+ getSignatureFromTransaction,
+ pipe,
sendAndConfirmTransactionFactory,
+ setTransactionMessageFeePayerSigner,
+ setTransactionMessageLifetimeUsingBlockhash,
signTransactionMessageWithSigners,
} from '@solana/kit';
import { TOKEN_2022_PROGRAM_ADDRESS } from '@solana-program/token-2022';
- import { createEscrowAccountTx } from '@solana-program/token-wrap';
+ import { createEscrowAccount } from '@solana-program/token-wrap';
// Replace these consts with your own
const PRIVATE_KEY_PAIR = new Uint8Array([242, 30, 38, 177, 152, 71, ... ]);
- const UNWRAPPED_MINT_ADDRESS = address('Cp3dvsXSiWJiA5AyfNdDdJ1Drw91yWdQwx5nnmcHKVi6');
+ const UNWRAPPED_MINT_ADDRESS = address('FAbYm8kdDsyc6csvTXPMBwCJDjTVkZcvrnyVVTSF74hU');
async function main() {
const rpc = createSolanaRpc('http://127.0.0.1:8899');
@@ -277,22 +302,34 @@ Before wrapping tokens, you need to create an account to hold the unwrapped toke
const payer = await createKeyPairSignerFromBytes(PRIVATE_KEY_PAIR);
const { value: blockhash } = await rpc.getLatestBlockhash().send();
- const createEscrowMessage = await createEscrowAccountTx({
+ // Create escrow account that with hold unwrapped tokens
+ const createEscrowHelper = await createEscrowAccount({
rpc,
- blockhash,
payer,
unwrappedMint: UNWRAPPED_MINT_ADDRESS,
wrappedTokenProgram: TOKEN_2022_PROGRAM_ADDRESS,
});
- const signedCreateEscrowTx = await signTransactionMessageWithSigners(createEscrowMessage.tx);
- await sendAndConfirm(signedCreateEscrowTx, { commitment: 'confirmed' });
-
- console.log('ESCROW_ADDRESS', createEscrowMessage.keyPair.address);
+ if (createEscrowHelper.kind === 'instructions_to_create') {
+ const createEscrowTx = await pipe(
+ createTransactionMessage({ version: 0 }),
+ tx => setTransactionMessageFeePayerSigner(payer, tx),
+ tx => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),
+ tx => appendTransactionMessageInstructions(createEscrowHelper.ixs, tx),
+ tx => signTransactionMessageWithSigners(tx),
+ );
+ await sendAndConfirm(createEscrowTx, { commitment: 'confirmed' });
+ const createEscrowSignature = getSignatureFromTransaction(createEscrowTx);
+
+ console.log('======== Create Escrow Successful ========');
+ console.log('Escrow address:', createEscrowHelper.address);
+ console.log('Signature:', createEscrowSignature);
+ } else {
+ console.log('======== Escrow already exists, skipping creation ========');
+ }
}
void main();
```
-
@@ -304,10 +341,9 @@ Escrows unwrapped tokens and mints wrapped tokens to recipient account.
```console
$ UNWRAPPED_TOKEN_ACCOUNT=DKFjYKEFS4tkXjamwkuiGf555Lww3eRSWwNTbue9x14
- $ ESCROW_ACCOUNT=4NoeQJKuH8fu1Pqk5k8BJpNu4wA7T8K6QABJxjTWoHs3
$ WRAPPED_TOKEN_PROGRAM=TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
- $ spl-token-wrap wrap $UNWRAPPED_TOKEN_ACCOUNT $ESCROW_ACCOUNT $WRAPPED_TOKEN_PROGRAM 100
+ $ spl-token-wrap wrap $UNWRAPPED_TOKEN_ACCOUNT $WRAPPED_TOKEN_PROGRAM 100
Wrapping 100 tokens from mint BVpjjYmSgSPZbFGTXe52NYXApsDNQJRe2qQF1hQft85e
Unwrapped mint address: BVpjjYmSgSPZbFGTXe52NYXApsDNQJRe2qQF1hQft85e
@@ -323,7 +359,7 @@ Escrows unwrapped tokens and mints wrapped tokens to recipient account.
You can specify a recipient token account with the `--recipient-token-account` option. If not provided, the associated token account of the fee payer will be used or created if it doesn't exist.
```console
- $ spl-token-wrap wrap $UNWRAPPED_TOKEN_ACCOUNT $ESCROW_ACCOUNT $WRAPPED_TOKEN_PROGRAM 100 \
+ $ spl-token-wrap wrap $UNWRAPPED_TOKEN_ACCOUNT $WRAPPED_TOKEN_PROGRAM 100 \
--recipient-token-account $RECIPIENT_WRAPPED_TOKEN_ACCOUNT
```
@@ -332,21 +368,26 @@ Escrows unwrapped tokens and mints wrapped tokens to recipient account.
```typescript
import {
address,
+ appendTransactionMessageInstructions,
createKeyPairSignerFromBytes,
createSolanaRpc,
createSolanaRpcSubscriptions,
+ createTransactionMessage,
getSignatureFromTransaction,
+ pipe,
sendAndConfirmTransactionFactory,
+ setTransactionMessageFeePayerSigner,
+ setTransactionMessageLifetimeUsingBlockhash,
signTransactionMessageWithSigners,
} from '@solana/kit';
import { TOKEN_2022_PROGRAM_ADDRESS } from '@solana-program/token-2022';
- import { singleSignerWrapTx } from '@solana-program/token-wrap';
+ import { singleSignerWrap } from '@solana-program/token-wrap';
// Replace these consts with your own
const PRIVATE_KEY_PAIR = new Uint8Array([242, 30, 38, 177, 152, 71, ... ]);
- const ESCROW_ACCOUNT = address('4NoeQJKuH8fu1Pqk5k8BJpNu4wA7T8K6QABJxjTWoHs3');
- const UNWRAPPED_TOKEN_ACCOUNT = address('CbuRmvG3frMoPFnsKfC2t8jTUHFjtnrKZBt2aqdqH4PG');
- const RECIPIENT = address('HKHfad5Rx7Vv1iWzPiQhx3cnXpbVfDonYRRo1e16x5Bt');
+ const UNWRAPPED_MINT_ADDRESS = address('FAbYm8kdDsyc6csvTXPMBwCJDjTVkZcvrnyVVTSF74hU');
+ const UNWRAPPED_TOKEN_ACCOUNT = address('4dSPDdFuTbKTuJDDtTd8SUdbH6QY42hpTPRi6RRzzsPF');
+ const RECIPIENT_WRAPPED_TOKEN_ACCOUNT = address('BJYNChMx8tfc3wjUmSXWYJDe55QsgHUXFfL9PbgV6wa9');
const AMOUNT_TO_WRAP = 100n;
async function main() {
@@ -357,25 +398,31 @@ Escrows unwrapped tokens and mints wrapped tokens to recipient account.
const payer = await createKeyPairSignerFromBytes(PRIVATE_KEY_PAIR);
const { value: blockhash } = await rpc.getLatestBlockhash().send();
- const wrapMessage = await singleSignerWrapTx({
+ // Execute wrap
+ const wrapHelper = await singleSignerWrap({
rpc,
- blockhash,
payer,
unwrappedTokenAccount: UNWRAPPED_TOKEN_ACCOUNT,
- escrowAccount: ESCROW_ACCOUNT,
wrappedTokenProgram: TOKEN_2022_PROGRAM_ADDRESS,
- recipientWrappedTokenAccount: RECIPIENT,
amount: AMOUNT_TO_WRAP,
+ unwrappedMint: UNWRAPPED_MINT_ADDRESS,
+ recipientWrappedTokenAccount: RECIPIENT_WRAPPED_TOKEN_ACCOUNT,
});
- const signedWrapTx = await signTransactionMessageWithSigners(wrapMessage.tx);
- await sendAndConfirm(signedWrapTx, { commitment: 'confirmed' });
- const wrapSignature = getSignatureFromTransaction(signedWrapTx);
+ const wrapTx = await pipe(
+ createTransactionMessage({ version: 0 }),
+ tx => setTransactionMessageFeePayerSigner(payer, tx),
+ tx => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),
+ tx => appendTransactionMessageInstructions(wrapHelper.ixs, tx),
+ tx => signTransactionMessageWithSigners(tx),
+ );
+ await sendAndConfirm(wrapTx, { commitment: 'confirmed' });
+ const wrapSignature = getSignatureFromTransaction(wrapTx);
console.log('======== Wrap Successful ========');
- console.log('Wrap amount:', wrapMessage.amount);
- console.log('Recipient account:', wrapMessage.recipientWrappedTokenAccount);
- console.log('Escrow Account:', wrapMessage.escrowAccount);
+ console.log('Wrap amount:', wrapHelper.amount);
+ console.log('Recipient account:', wrapHelper.recipientWrappedTokenAccount);
+ console.log('Escrow Account:', wrapHelper.escrowAccount);
console.log('Signature:', wrapSignature);
}
@@ -416,11 +463,10 @@ An example wrapping tokens whose origin is a token account owned by an SPL Token
$ MULTISIG_ADDRESS=mgnqjedikMKaRtS5wrhVttuA12JaPXiqY619Gfef5eh
$ RECIPIENT_ACCOUNT=HKHfad5Rx7Vv1iWzPiQhx3cnXpbVfDonYRRo1e16x5Bt
$ UNWRAPPED_MINT=BVpjjYmSgSPZbFGTXe52NYXApsDNQJRe2qQF1hQft85e
- $ ESCROW_ACCOUNT=4NoeQJKuH8fu1Pqk5k8BJpNu4wA7T8K6QABJxjTWoHs3
$ UNWRAPPED_TOKEN_PROGRAM=TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
$ WRAPPED_TOKEN_PROGRAM=TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
- $ spl-token-wrap wrap $UNWRAPPED_TOKEN_ACCOUNT $ESCROW_ACCOUNT $WRAPPED_TOKEN_PROGRAM 23 \
+ $ spl-token-wrap wrap $UNWRAPPED_TOKEN_ACCOUNT $WRAPPED_TOKEN_PROGRAM 23 \
--transfer-authority $MULTISIG_ADDRESS \
--recipient-token-account $RECIPIENT_ACCOUNT \
--unwrapped-mint $UNWRAPPED_MINT \
@@ -451,11 +497,10 @@ An example wrapping tokens whose origin is a token account owned by an SPL Token
$ MULTISIG_ADDRESS=mgnqjedikMKaRtS5wrhVttuA12JaPXiqY619Gfef5eh
$ RECIPIENT_ACCOUNT=HKHfad5Rx7Vv1iWzPiQhx3cnXpbVfDonYRRo1e16x5Bt
$ UNWRAPPED_MINT=BVpjjYmSgSPZbFGTXe52NYXApsDNQJRe2qQF1hQft85e
- $ ESCROW_ACCOUNT=4NoeQJKuH8fu1Pqk5k8BJpNu4wA7T8K6QABJxjTWoHs3
$ UNWRAPPED_TOKEN_PROGRAM=TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
$ WRAPPED_TOKEN_PROGRAM=TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
- $ spl-token-wrap wrap $UNWRAPPED_TOKEN_ACCOUNT $ESCROW_ACCOUNT $WRAPPED_TOKEN_PROGRAM 23 \
+ $ spl-token-wrap wrap $UNWRAPPED_TOKEN_ACCOUNT $WRAPPED_TOKEN_PROGRAM 23 \
--transfer-authority $MULTISIG_ADDRESS \
--recipient-token-account $RECIPIENT_ACCOUNT \
--unwrapped-mint $UNWRAPPED_MINT \
@@ -487,11 +532,10 @@ An example wrapping tokens whose origin is a token account owned by an SPL Token
$ MULTISIG_ADDRESS=mgnqjedikMKaRtS5wrhVttuA12JaPXiqY619Gfef5eh
$ RECIPIENT_ACCOUNT=HKHfad5Rx7Vv1iWzPiQhx3cnXpbVfDonYRRo1e16x5Bt
$ UNWRAPPED_MINT=BVpjjYmSgSPZbFGTXe52NYXApsDNQJRe2qQF1hQft85e
- $ ESCROW_ACCOUNT=4NoeQJKuH8fu1Pqk5k8BJpNu4wA7T8K6QABJxjTWoHs3
$ UNWRAPPED_TOKEN_PROGRAM=TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
$ WRAPPED_TOKEN_PROGRAM=TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
- $ spl-token-wrap wrap $UNWRAPPED_TOKEN_ACCOUNT $ESCROW_ACCOUNT $WRAPPED_TOKEN_PROGRAM 23 \
+ $ spl-token-wrap wrap $UNWRAPPED_TOKEN_ACCOUNT $WRAPPED_TOKEN_PROGRAM 23 \
--transfer-authority $MULTISIG_ADDRESS \
--recipient-token-account $RECIPIENT_ACCOUNT \
--unwrapped-mint $UNWRAPPED_MINT \
@@ -533,21 +577,23 @@ An example wrapping tokens whose origin is a token account owned by an SPL Token
} from '@solana/kit';
import { TOKEN_2022_PROGRAM_ADDRESS } from '@solana-program/token-2022';
import {
- findWrappedMintAuthorityPda,
- multisigOfflineSignWrapTx,
combinedMultisigTx,
+ findWrappedMintAuthorityPda,
+ findWrappedMintPda,
+ multisigOfflineSignWrap,
} from '@solana-program/token-wrap';
+ import { TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';
// Replace these consts with your own
const PAYER_KEYPAIR_BYTES = new Uint8Array([242, 30, 38, 177, 152, 71, ... ]);
+
+ // Create using CLI: spl-token create-multisig 2 $SIGNER_1_PUBKEY $SIGNER_2_PUBKEY
const MULTISIG_SPL_TOKEN = address('2XBevFsu4pnZpB9PewYKAJHNyx9dFQf3MaiGBszF5fm8');
const SIGNER_A_KEYPAIR_BYTES = new Uint8Array([210, 190, 232, 169, 113, 107, ... ]);
const SIGNER_B_KEYPAIR_BYTES = new Uint8Array([37, 161, 191, 225, 59, 192, ... ]);
- const WRAPPED_MINT_ADDRESS = address('B8HbxGU4npjgjMX5xJFR2FYkgvAHdZqyVb8MyFvdsuNM');
- const UNWRAPPED_MINT_ADDRESS = address('E8r9ixwg7QYr6xCh4tSdHErZ6CUxQhVGHqF5bRoZXyyV');
- const UNWRAPPED_TOKEN_ACCOUNT = address('DGNyuKAWP3susy6XMbVsYHy2AMrrKmh8pXM3WpQUeyL2'); // Must be owned by multisig account
- const UNWRAPPED_TOKEN_PROGRAM = address('TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb');
- const ESCROW = address('4NoeQJKuH8fu1Pqk5k8BJpNu4wA7T8K6QABJxjTWoHs3');
+
+ const UNWRAPPED_MINT_ADDRESS = address('F2qGWupzMUQnGfX8e25XZps8d9AGdVde8hLQT2pxsb4M');
+ const UNWRAPPED_TOKEN_ACCOUNT = address('94Y9pxekEm59b67PQQwvjb7wbwz689wDZ3dAwhCtJpPS'); // Must be owned by MULTISIG_SPL_TOKEN
const RECIPIENT = address('HKHfad5Rx7Vv1iWzPiQhx3cnXpbVfDonYRRo1e16x5Bt');
const AMOUNT_TO_WRAP = 100n;
@@ -559,59 +605,60 @@ An example wrapping tokens whose origin is a token account owned by an SPL Token
const payer = await createKeyPairSignerFromBytes(PAYER_KEYPAIR_BYTES);
const { value: blockhash } = await rpc.getLatestBlockhash().send();
- const [wrappedMintAuthority] = await findWrappedMintAuthorityPda({ wrappedMint: WRAPPED_MINT_ADDRESS });
+ const [wrappedMint] = await findWrappedMintPda({
+ unwrappedMint: UNWRAPPED_MINT_ADDRESS,
+ wrappedTokenProgram: TOKEN_2022_PROGRAM_ADDRESS,
+ });
+ const [wrappedMintAuthority] = await findWrappedMintAuthorityPda({ wrappedMint });
const signerA = await createKeyPairSignerFromBytes(SIGNER_A_KEYPAIR_BYTES);
const signerB = await createKeyPairSignerFromBytes(SIGNER_B_KEYPAIR_BYTES);
// Two signers and the payer sign the transaction independently
- const wrapTxA = multisigOfflineSignWrapTx({
+ const wrapTxA = await multisigOfflineSignWrap({
payer: createNoopSigner(payer.address),
unwrappedTokenAccount: UNWRAPPED_TOKEN_ACCOUNT,
- escrowAccount: ESCROW,
wrappedTokenProgram: TOKEN_2022_PROGRAM_ADDRESS,
amount: AMOUNT_TO_WRAP,
unwrappedMint: UNWRAPPED_MINT_ADDRESS,
recipientWrappedTokenAccount: RECIPIENT,
transferAuthority: MULTISIG_SPL_TOKEN,
- wrappedMint: WRAPPED_MINT_ADDRESS,
+ wrappedMint,
wrappedMintAuthority,
- unwrappedTokenProgram: UNWRAPPED_TOKEN_PROGRAM,
+ unwrappedTokenProgram: TOKEN_PROGRAM_ADDRESS,
multiSigners: [signerA, createNoopSigner(signerB.address)],
blockhash,
});
const signedWrapTxA = await partiallySignTransactionMessageWithSigners(wrapTxA);
- const wrapTxB = multisigOfflineSignWrapTx({
+ const wrapTxB = await multisigOfflineSignWrap({
payer: createNoopSigner(payer.address),
unwrappedTokenAccount: UNWRAPPED_TOKEN_ACCOUNT,
- escrowAccount: ESCROW,
wrappedTokenProgram: TOKEN_2022_PROGRAM_ADDRESS,
amount: AMOUNT_TO_WRAP,
unwrappedMint: UNWRAPPED_MINT_ADDRESS,
recipientWrappedTokenAccount: RECIPIENT,
transferAuthority: MULTISIG_SPL_TOKEN,
- wrappedMint: WRAPPED_MINT_ADDRESS,
+ wrappedMint,
wrappedMintAuthority,
- unwrappedTokenProgram: UNWRAPPED_TOKEN_PROGRAM,
+ unwrappedTokenProgram: TOKEN_PROGRAM_ADDRESS,
multiSigners: [createNoopSigner(signerA.address), signerB],
blockhash,
});
const signedWrapTxB = await partiallySignTransactionMessageWithSigners(wrapTxB);
- const wrapTxC = multisigOfflineSignWrapTx({
+ const wrapTxC = await multisigOfflineSignWrap({
payer,
unwrappedTokenAccount: UNWRAPPED_TOKEN_ACCOUNT,
- escrowAccount: ESCROW,
wrappedTokenProgram: TOKEN_2022_PROGRAM_ADDRESS,
amount: AMOUNT_TO_WRAP,
unwrappedMint: UNWRAPPED_MINT_ADDRESS,
recipientWrappedTokenAccount: RECIPIENT,
transferAuthority: MULTISIG_SPL_TOKEN,
- wrappedMint: WRAPPED_MINT_ADDRESS,
+ wrappedMint,
wrappedMintAuthority,
- unwrappedTokenProgram: UNWRAPPED_TOKEN_PROGRAM,
+ unwrappedTokenProgram: TOKEN_PROGRAM_ADDRESS,
multiSigners: [createNoopSigner(signerA.address), createNoopSigner(signerB.address)],
blockhash,
});
@@ -647,11 +694,10 @@ Burns wrapped tokens and releases unwrapped tokens from escrow.
```console
- $ ESCROW_ACCOUNT=4NoeQJKuH8fu1Pqk5k8BJpNu4wA7T8K6QABJxjTWoHs3
$ WRAPPED_TOKEN_ACCOUNT=HKHfad5Rx7Vv1iWzPiQhx3cnXpbVfDonYRRo1e16x5Bt
$ UNWRAPPED_TOKEN_RECIPIENT=DKFjYKEFS4tkXjamwkuiGf555Lww3eRSWwNTbue9x14
- $ spl-token-wrap unwrap $WRAPPED_TOKEN_ACCOUNT $ESCROW_ACCOUNT $UNWRAPPED_TOKEN_RECIPIENT 50
+ $ spl-token-wrap unwrap $WRAPPED_TOKEN_ACCOUNT $UNWRAPPED_TOKEN_RECIPIENT 50
Unwrapping 50 tokens from mint BVpjjYmSgSPZbFGTXe52NYXApsDNQJRe2qQF1hQft85e
Unwrapped token program: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
@@ -667,20 +713,24 @@ Burns wrapped tokens and releases unwrapped tokens from escrow.
```typescript
import {
address,
+ appendTransactionMessageInstructions,
createKeyPairSignerFromBytes,
createSolanaRpc,
createSolanaRpcSubscriptions,
+ createTransactionMessage,
getSignatureFromTransaction,
+ pipe,
sendAndConfirmTransactionFactory,
+ setTransactionMessageFeePayerSigner,
+ setTransactionMessageLifetimeUsingBlockhash,
signTransactionMessageWithSigners,
} from '@solana/kit';
- import { singleSignerUnwrapTx } from '@solana-program/token-wrap';
+ import { singleSignerUnwrap } from '@solana-program/token-wrap';
// Replace these consts with your own
const PRIVATE_KEY_PAIR = new Uint8Array([242, 30, 38, 177, 152, 71, ... ]);
- const WRAPPED_TOKEN_ACCOUNT = address('HKHfad5Rx7Vv1iWzPiQhx3cnXpbVfDonYRRo1e16x5Bt');
- const ESCROW = address('4NoeQJKuH8fu1Pqk5k8BJpNu4wA7T8K6QABJxjTWoHs3');
- const RECIPIENT = address('DKFjYKEFS4tkXjamwkuiGf555Lww3eRSWwNTbue9x14');
+ const UNWRAPPED_TOKEN_ACCOUNT = address('4dSPDdFuTbKTuJDDtTd8SUdbH6QY42hpTPRi6RRzzsPF');
+ const UNWRAP_SOURCE = address('BJYNChMx8tfc3wjUmSXWYJDe55QsgHUXFfL9PbgV6wa9');
const AMOUNT_TO_WRAP = 100n;
async function main() {
@@ -691,23 +741,27 @@ Burns wrapped tokens and releases unwrapped tokens from escrow.
const payer = await createKeyPairSignerFromBytes(PRIVATE_KEY_PAIR);
const { value: blockhash } = await rpc.getLatestBlockhash().send();
- const unwrapMessage = await singleSignerUnwrapTx({
+ const unwrapHelper = await singleSignerUnwrap({
rpc,
- blockhash,
payer,
- wrappedTokenAccount: WRAPPED_TOKEN_ACCOUNT,
- unwrappedEscrow: ESCROW,
+ wrappedTokenAccount: UNWRAP_SOURCE,
amount: AMOUNT_TO_WRAP,
- recipientUnwrappedToken: RECIPIENT,
+ recipientUnwrappedToken: UNWRAPPED_TOKEN_ACCOUNT,
});
- const signedUnwrapTx = await signTransactionMessageWithSigners(unwrapMessage.tx);
- await sendAndConfirm(signedUnwrapTx, { commitment: 'confirmed' });
- const unwrapSignature = getSignatureFromTransaction(signedUnwrapTx);
+ const unwrapTx = await pipe(
+ createTransactionMessage({ version: 0 }),
+ tx => setTransactionMessageFeePayerSigner(payer, tx),
+ tx => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),
+ tx => appendTransactionMessageInstructions(unwrapHelper.ixs, tx),
+ tx => signTransactionMessageWithSigners(tx),
+ );
+ await sendAndConfirm(unwrapTx, { commitment: 'confirmed' });
+ const unwrapSignature = getSignatureFromTransaction(unwrapTx);
console.log('======== Unwrap Successful ========');
- console.log('Unwrapped amount:', unwrapMessage.amount);
- console.log('Recipient account:', unwrapMessage.recipientUnwrappedToken);
+ console.log('Unwrapped amount:', unwrapHelper.amount);
+ console.log('Recipient account:', unwrapHelper.recipientUnwrappedToken);
console.log('Signature:', unwrapSignature);
}
@@ -748,11 +802,10 @@ An example unwrapping tokens whose origin is a token account owned by an SPL Tok
$ MULTISIG_ADDRESS=FFQvYvhaWnHeGsCMfixccUMdnXPgDrkG3KkGzpfBHFPb # note this should have the same program-id as wrapped token account
$ UNWRAPPED_TOKEN_RECIPIENT=DKFjYKEFS4tkXjamwkuiGf555Lww3eRSWwNTbue9x14
$ UNWRAPPED_MINT=BVpjjYmSgSPZbFGTXe52NYXApsDNQJRe2qQF1hQft85e
- $ ESCROW_ACCOUNT=4NoeQJKuH8fu1Pqk5k8BJpNu4wA7T8K6QABJxjTWoHs3
$ UNWRAPPED_TOKEN_PROGRAM=TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
$ WRAPPED_TOKEN_PROGRAM=TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
- $ spl-token-wrap unwrap $WRAPPED_TOKEN_ACCOUNT $ESCROW_ACCOUNT $UNWRAPPED_TOKEN_RECIPIENT 5 \
+ $ spl-token-wrap unwrap $WRAPPED_TOKEN_ACCOUNT $UNWRAPPED_TOKEN_RECIPIENT 5 \
--transfer-authority $MULTISIG_ADDRESS \
--fee-payer $FEE_PAYER \
--unwrapped-mint $UNWRAPPED_MINT \
@@ -777,11 +830,10 @@ An example unwrapping tokens whose origin is a token account owned by an SPL Tok
$ MULTISIG_ADDRESS=FFQvYvhaWnHeGsCMfixccUMdnXPgDrkG3KkGzpfBHFPb
$ UNWRAPPED_TOKEN_RECIPIENT=DKFjYKEFS4tkXjamwkuiGf555Lww3eRSWwNTbue9x14
$ UNWRAPPED_MINT=BVpjjYmSgSPZbFGTXe52NYXApsDNQJRe2qQF1hQft85e
- $ ESCROW_ACCOUNT=4NoeQJKuH8fu1Pqk5k8BJpNu4wA7T8K6QABJxjTWoHs3
$ UNWRAPPED_TOKEN_PROGRAM=TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
$ WRAPPED_TOKEN_PROGRAM=TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
- $ spl-token-wrap unwrap $WRAPPED_TOKEN_ACCOUNT $ESCROW_ACCOUNT $UNWRAPPED_TOKEN_RECIPIENT 5 \
+ $ spl-token-wrap unwrap $WRAPPED_TOKEN_ACCOUNT $UNWRAPPED_TOKEN_RECIPIENT 5 \
--transfer-authority $MULTISIG_ADDRESS \
--fee-payer $FEE_PAYER \
--unwrapped-mint $UNWRAPPED_MINT \
@@ -807,11 +859,10 @@ An example unwrapping tokens whose origin is a token account owned by an SPL Tok
$ MULTISIG_ADDRESS=FFQvYvhaWnHeGsCMfixccUMdnXPgDrkG3KkGzpfBHFPb
$ UNWRAPPED_TOKEN_RECIPIENT=DKFjYKEFS4tkXjamwkuiGf555Lww3eRSWwNTbue9x14
$ UNWRAPPED_MINT=BVpjjYmSgSPZbFGTXe52NYXApsDNQJRe2qQF1hQft85e
- $ ESCROW_ACCOUNT=4NoeQJKuH8fu1Pqk5k8BJpNu4wA7T8K6QABJxjTWoHs3
$ UNWRAPPED_TOKEN_PROGRAM=TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
$ WRAPPED_TOKEN_PROGRAM=TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
- $ spl-token-wrap unwrap $WRAPPED_TOKEN_ACCOUNT $ESCROW_ACCOUNT $UNWRAPPED_TOKEN_RECIPIENT 5 \
+ $ spl-token-wrap unwrap $WRAPPED_TOKEN_ACCOUNT $UNWRAPPED_TOKEN_RECIPIENT 5 \
--transfer-authority $MULTISIG_ADDRESS \
--fee-payer $FEE_PAYER \
--unwrapped-mint $UNWRAPPED_MINT \
@@ -851,22 +902,25 @@ An example unwrapping tokens whose origin is a token account owned by an SPL Tok
} from '@solana/kit';
import { TOKEN_2022_PROGRAM_ADDRESS } from '@solana-program/token-2022';
import {
- findWrappedMintAuthorityPda,
combinedMultisigTx,
- multisigOfflineSignUnwrap
+ findWrappedMintAuthorityPda,
+ findWrappedMintPda,
+ multisigOfflineSignUnwrap,
} from '@solana-program/token-wrap';
+ import { TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';
// Replace these consts with your own
const PAYER_KEYPAIR_BYTES = new Uint8Array([242, 30, 38, 177, 152, 71, ... ]);
+
+ const MULTISIG_SPL_TOKEN = address('2XBevFsu4pnZpB9PewYKAJHNyx9dFQf3MaiGBszF5fm8');
const MULTISIG_SPL_TOKEN_2022 = address('BSdexGFqwmDGeXe4pBXVbQnqrEH5trmo9W3wqoXUQY5Y');
+
const SIGNER_A_KEYPAIR_BYTES = new Uint8Array([210, 190, 232, 169, 113, 107, ... ]);
const SIGNER_B_KEYPAIR_BYTES = new Uint8Array([37, 161, 191, 225, 59, 192, ... ]);
- const WRAPPED_MINT_ADDRESS = address('B8HbxGU4npjgjMX5xJFR2FYkgvAHdZqyVb8MyFvdsuNM');
- const UNWRAPPED_MINT_ADDRESS = address('E8r9ixwg7QYr6xCh4tSdHErZ6CUxQhVGHqF5bRoZXyyV');
- const UNWRAPPED_TOKEN_ACCOUNT = address('DGNyuKAWP3susy6XMbVsYHy2AMrrKmh8pXM3WpQUeyL2'); // Must be owned by multisig account
- const UNWRAPPED_TOKEN_PROGRAM = address('TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb');
- const ESCROW = address('4NoeQJKuH8fu1Pqk5k8BJpNu4wA7T8K6QABJxjTWoHs3');
- const RECIPIENT = address('HKHfad5Rx7Vv1iWzPiQhx3cnXpbVfDonYRRo1e16x5Bt');
+
+ const UNWRAPPED_MINT_ADDRESS = address('F2qGWupzMUQnGfX8e25XZps8d9AGdVde8hLQT2pxsb4M');
+ const UNWRAPPED_TOKEN_ACCOUNT = address('94Y9pxekEm59b67PQQwvjb7wbwz689wDZ3dAwhCtJpPS'); // Must be owned by MULTISIG_SPL_TOKEN
+ const WRAPPED_TOKEN_ACCOUNT = address('HKHfad5Rx7Vv1iWzPiQhx3cnXpbVfDonYRRo1e16x5Bt');
const AMOUNT_TO_WRAP = 100n;
async function main() {
@@ -877,61 +931,62 @@ An example unwrapping tokens whose origin is a token account owned by an SPL Tok
const payer = await createKeyPairSignerFromBytes(PAYER_KEYPAIR_BYTES);
const { value: blockhash } = await rpc.getLatestBlockhash().send();
- const [wrappedMintAuthority] = await findWrappedMintAuthorityPda({ wrappedMint: WRAPPED_MINT_ADDRESS });
+ const [wrappedMint] = await findWrappedMintPda({
+ unwrappedMint: UNWRAPPED_MINT_ADDRESS,
+ wrappedTokenProgram: TOKEN_2022_PROGRAM_ADDRESS,
+ });
+ const [wrappedMintAuthority] = await findWrappedMintAuthorityPda({ wrappedMint });
const signerA = await createKeyPairSignerFromBytes(SIGNER_A_KEYPAIR_BYTES);
const signerB = await createKeyPairSignerFromBytes(SIGNER_B_KEYPAIR_BYTES);
- const { value: unwrapBlockhash } = await rpc.getLatestBlockhash().send();
+ // Two signers and the payer sign the transaction independently
- const unwrapTxA = multisigOfflineSignUnwrap({
+ const unwrapTxA = await multisigOfflineSignUnwrap({
payer: createNoopSigner(payer.address),
- unwrappedEscrow: ESCROW,
wrappedTokenProgram: TOKEN_2022_PROGRAM_ADDRESS,
amount: AMOUNT_TO_WRAP,
unwrappedMint: UNWRAPPED_MINT_ADDRESS,
- wrappedTokenAccount: RECIPIENT,
+ wrappedTokenAccount: WRAPPED_TOKEN_ACCOUNT,
recipientUnwrappedToken: UNWRAPPED_TOKEN_ACCOUNT,
transferAuthority: MULTISIG_SPL_TOKEN_2022,
- wrappedMint: WRAPPED_MINT_ADDRESS,
+ wrappedMint,
wrappedMintAuthority,
- unwrappedTokenProgram: UNWRAPPED_TOKEN_PROGRAM,
+ unwrappedTokenProgram: TOKEN_PROGRAM_ADDRESS,
multiSigners: [signerA, createNoopSigner(signerB.address)],
- blockhash: unwrapBlockhash,
+ blockhash,
});
const signedUnwrapTxA = await partiallySignTransactionMessageWithSigners(unwrapTxA);
- const unwrapTxB = multisigOfflineSignUnwrap({
+ const unwrapTxB = await multisigOfflineSignUnwrap({
payer: createNoopSigner(payer.address),
- unwrappedEscrow: ESCROW,
wrappedTokenProgram: TOKEN_2022_PROGRAM_ADDRESS,
amount: AMOUNT_TO_WRAP,
unwrappedMint: UNWRAPPED_MINT_ADDRESS,
- wrappedTokenAccount: RECIPIENT,
+ wrappedTokenAccount: WRAPPED_TOKEN_ACCOUNT,
recipientUnwrappedToken: UNWRAPPED_TOKEN_ACCOUNT,
transferAuthority: MULTISIG_SPL_TOKEN_2022,
- wrappedMint: WRAPPED_MINT_ADDRESS,
+ wrappedMint,
wrappedMintAuthority,
- unwrappedTokenProgram: UNWRAPPED_TOKEN_PROGRAM,
+ unwrappedTokenProgram: TOKEN_PROGRAM_ADDRESS,
multiSigners: [createNoopSigner(signerA.address), signerB],
- blockhash: unwrapBlockhash,
+ blockhash,
});
const signedUnwrapTxB = await partiallySignTransactionMessageWithSigners(unwrapTxB);
- const unwrapTxC = multisigOfflineSignUnwrap({
- payer: payer,
- unwrappedEscrow: ESCROW,
+ const unwrapTxC = await multisigOfflineSignUnwrap({
+ payer,
wrappedTokenProgram: TOKEN_2022_PROGRAM_ADDRESS,
amount: AMOUNT_TO_WRAP,
unwrappedMint: UNWRAPPED_MINT_ADDRESS,
- wrappedTokenAccount: RECIPIENT,
+ wrappedTokenAccount: WRAPPED_TOKEN_ACCOUNT,
recipientUnwrappedToken: UNWRAPPED_TOKEN_ACCOUNT,
transferAuthority: MULTISIG_SPL_TOKEN_2022,
- wrappedMint: WRAPPED_MINT_ADDRESS,
+ wrappedMint,
wrappedMintAuthority,
- unwrappedTokenProgram: UNWRAPPED_TOKEN_PROGRAM,
+ unwrappedTokenProgram: TOKEN_PROGRAM_ADDRESS,
multiSigners: [createNoopSigner(signerA.address), createNoopSigner(signerB.address)],
- blockhash: unwrapBlockhash,
+ blockhash,
});
const signedUnwrapTxC = await partiallySignTransactionMessageWithSigners(unwrapTxC);