168 lines
4.6 KiB
TypeScript
168 lines
4.6 KiB
TypeScript
import {
|
|
clusterApiUrl,
|
|
sendAndConfirmTransaction,
|
|
Connection,
|
|
Keypair,
|
|
SystemProgram,
|
|
Transaction,
|
|
LAMPORTS_PER_SOL,
|
|
} from '@solana/web3.js';
|
|
|
|
import {
|
|
ExtensionType,
|
|
createInitializeMintInstruction,
|
|
mintTo,
|
|
createAccount,
|
|
getMintLen,
|
|
getTransferFeeAmount,
|
|
unpackAccount,
|
|
TOKEN_2022_PROGRAM_ID,
|
|
} from '../src';
|
|
|
|
import {
|
|
createInitializeTransferFeeConfigInstruction,
|
|
harvestWithheldTokensToMint,
|
|
transferCheckedWithFee,
|
|
withdrawWithheldTokensFromAccounts,
|
|
withdrawWithheldTokensFromMint,
|
|
} from '../src/extensions/transferFee/index';
|
|
|
|
(async () => {
|
|
const payer = Keypair.generate();
|
|
|
|
const mintAuthority = Keypair.generate();
|
|
const mintKeypair = Keypair.generate();
|
|
const mint = mintKeypair.publicKey;
|
|
const transferFeeConfigAuthority = Keypair.generate();
|
|
const withdrawWithheldAuthority = Keypair.generate();
|
|
|
|
const extensions = [ExtensionType.TransferFeeConfig];
|
|
|
|
const mintLen = getMintLen(extensions);
|
|
const decimals = 9;
|
|
const feeBasisPoints = 50;
|
|
const maxFee = BigInt(5_000);
|
|
|
|
const connection = new Connection(clusterApiUrl('devnet'), 'confirmed');
|
|
|
|
const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL);
|
|
await connection.confirmTransaction({ signature: airdropSignature, ...(await connection.getLatestBlockhash()) });
|
|
|
|
const mintLamports = await connection.getMinimumBalanceForRentExemption(mintLen);
|
|
const mintTransaction = new Transaction().add(
|
|
SystemProgram.createAccount({
|
|
fromPubkey: payer.publicKey,
|
|
newAccountPubkey: mint,
|
|
space: mintLen,
|
|
lamports: mintLamports,
|
|
programId: TOKEN_2022_PROGRAM_ID,
|
|
}),
|
|
createInitializeTransferFeeConfigInstruction(
|
|
mint,
|
|
transferFeeConfigAuthority.publicKey,
|
|
withdrawWithheldAuthority.publicKey,
|
|
feeBasisPoints,
|
|
maxFee,
|
|
TOKEN_2022_PROGRAM_ID
|
|
),
|
|
createInitializeMintInstruction(mint, decimals, mintAuthority.publicKey, null, TOKEN_2022_PROGRAM_ID)
|
|
);
|
|
await sendAndConfirmTransaction(connection, mintTransaction, [payer, mintKeypair], undefined);
|
|
|
|
const mintAmount = BigInt(1_000_000_000);
|
|
const owner = Keypair.generate();
|
|
const sourceAccount = await createAccount(
|
|
connection,
|
|
payer,
|
|
mint,
|
|
owner.publicKey,
|
|
undefined,
|
|
undefined,
|
|
TOKEN_2022_PROGRAM_ID
|
|
);
|
|
await mintTo(
|
|
connection,
|
|
payer,
|
|
mint,
|
|
sourceAccount,
|
|
mintAuthority,
|
|
mintAmount,
|
|
[],
|
|
undefined,
|
|
TOKEN_2022_PROGRAM_ID
|
|
);
|
|
|
|
const accountKeypair = Keypair.generate();
|
|
const destinationAccount = await createAccount(
|
|
connection,
|
|
payer,
|
|
mint,
|
|
owner.publicKey,
|
|
accountKeypair,
|
|
undefined,
|
|
TOKEN_2022_PROGRAM_ID
|
|
);
|
|
|
|
const transferAmount = BigInt(1_000_000);
|
|
const fee = (transferAmount * BigInt(feeBasisPoints)) / BigInt(10_000);
|
|
await transferCheckedWithFee(
|
|
connection,
|
|
payer,
|
|
sourceAccount,
|
|
mint,
|
|
destinationAccount,
|
|
owner,
|
|
transferAmount,
|
|
decimals,
|
|
fee,
|
|
[],
|
|
undefined,
|
|
TOKEN_2022_PROGRAM_ID
|
|
);
|
|
|
|
const allAccounts = await connection.getProgramAccounts(TOKEN_2022_PROGRAM_ID, {
|
|
commitment: 'confirmed',
|
|
filters: [
|
|
{
|
|
memcmp: {
|
|
offset: 0,
|
|
bytes: mint.toString(),
|
|
},
|
|
},
|
|
],
|
|
});
|
|
const accountsToWithdrawFrom = [];
|
|
for (const accountInfo of allAccounts) {
|
|
const account = unpackAccount(accountInfo.pubkey, accountInfo.account, TOKEN_2022_PROGRAM_ID);
|
|
const transferFeeAmount = getTransferFeeAmount(account);
|
|
if (transferFeeAmount !== null && transferFeeAmount.withheldAmount > BigInt(0)) {
|
|
accountsToWithdrawFrom.push(accountInfo.pubkey);
|
|
}
|
|
}
|
|
|
|
await withdrawWithheldTokensFromAccounts(
|
|
connection,
|
|
payer,
|
|
mint,
|
|
destinationAccount,
|
|
withdrawWithheldAuthority,
|
|
[],
|
|
accountsToWithdrawFrom,
|
|
undefined,
|
|
TOKEN_2022_PROGRAM_ID
|
|
);
|
|
|
|
await harvestWithheldTokensToMint(connection, payer, mint, [destinationAccount], undefined, TOKEN_2022_PROGRAM_ID);
|
|
|
|
await withdrawWithheldTokensFromMint(
|
|
connection,
|
|
payer,
|
|
mint,
|
|
destinationAccount,
|
|
withdrawWithheldAuthority,
|
|
[],
|
|
undefined,
|
|
TOKEN_2022_PROGRAM_ID
|
|
);
|
|
})();
|