diff --git a/token/js/examples/cpiGuard.ts b/token/js/examples/cpiGuard.ts index 5b05adc9..9158d321 100644 --- a/token/js/examples/cpiGuard.ts +++ b/token/js/examples/cpiGuard.ts @@ -1 +1,64 @@ -// XXX TODO HANA +import { + clusterApiUrl, + sendAndConfirmTransaction, + Connection, + Keypair, + SystemProgram, + Transaction, + LAMPORTS_PER_SOL, +} from '@solana/web3.js'; +import { + createMint, + createEnableCpiGuardInstruction, + createInitializeAccountInstruction, + disableCpiGuard, + enableCpiGuard, + getAccountLen, + ExtensionType, + TOKEN_2022_PROGRAM_ID, +} from '../src'; + +(async () => { + const connection = new Connection(clusterApiUrl('devnet'), 'confirmed'); + + const payer = Keypair.generate(); + const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL); + await connection.confirmTransaction({ signature: airdropSignature, ...(await connection.getLatestBlockhash()) }); + + const mintAuthority = Keypair.generate(); + const decimals = 9; + const mint = await createMint( + connection, + payer, + mintAuthority.publicKey, + mintAuthority.publicKey, + decimals, + undefined, + undefined, + TOKEN_2022_PROGRAM_ID + ); + + const accountLen = getAccountLen([ExtensionType.CpiGuard]); + const lamports = await connection.getMinimumBalanceForRentExemption(accountLen); + + const owner = Keypair.generate(); + const destinationKeypair = Keypair.generate(); + const destination = destinationKeypair.publicKey; + const transaction = new Transaction().add( + SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + newAccountPubkey: destination, + space: accountLen, + lamports, + programId: TOKEN_2022_PROGRAM_ID, + }), + createInitializeAccountInstruction(destination, mint, owner.publicKey, TOKEN_2022_PROGRAM_ID), + createEnableCpiGuardInstruction(destination, owner.publicKey, [], TOKEN_2022_PROGRAM_ID) + ); + + await sendAndConfirmTransaction(connection, transaction, [payer, owner, destinationKeypair], undefined); + + await disableCpiGuard(connection, payer, destination, owner, [], undefined, TOKEN_2022_PROGRAM_ID); + + await enableCpiGuard(connection, payer, destination, owner, [], undefined, TOKEN_2022_PROGRAM_ID); +})(); diff --git a/token/js/test/e2e-2022/cpiGuard.test.ts b/token/js/test/e2e-2022/cpiGuard.test.ts index 5b05adc9..4772b97b 100644 --- a/token/js/test/e2e-2022/cpiGuard.test.ts +++ b/token/js/test/e2e-2022/cpiGuard.test.ts @@ -1 +1,123 @@ -// XXX TODO HANA +import chai, { expect } from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +chai.use(chaiAsPromised); + +import type { Connection, PublicKey, Signer } from '@solana/web3.js'; +import { sendAndConfirmTransaction, Keypair, SystemProgram, Transaction } from '@solana/web3.js'; +import { + createAccount, + createMint, + createEnableCpiGuardInstruction, + createDisableCpiGuardInstruction, + createInitializeAccountInstruction, + getAccount, + getCpiGuard, + enableCpiGuard, + disableCpiGuard, + getAccountLen, + ExtensionType, +} from '../../src'; +import { TEST_PROGRAM_ID, newAccountWithLamports, getConnection } from '../common'; + +const TEST_TOKEN_DECIMALS = 2; +const TRANSFER_AMOUNT = 1_000; +const EXTENSIONS = [ExtensionType.CpiGuard]; +describe('cpiGuard', () => { + let connection: Connection; + let payer: Signer; + let owner: Keypair; + let account: PublicKey; + + before(async () => { + connection = await getConnection(); + payer = await newAccountWithLamports(connection, 1000000000); + owner = Keypair.generate(); + }); + + beforeEach(async () => { + const mintKeypair = Keypair.generate(); + const mintAuthority = Keypair.generate(); + const accountKeypair = Keypair.generate(); + account = accountKeypair.publicKey; + const accountLen = getAccountLen(EXTENSIONS); + const lamports = await connection.getMinimumBalanceForRentExemption(accountLen); + + const mint = await createMint( + connection, + payer, + mintAuthority.publicKey, + mintAuthority.publicKey, + TEST_TOKEN_DECIMALS, + mintKeypair, + undefined, + TEST_PROGRAM_ID + ); + + const transaction = new Transaction().add( + SystemProgram.createAccount({ + fromPubkey: payer.publicKey, + newAccountPubkey: account, + space: accountLen, + lamports, + programId: TEST_PROGRAM_ID, + }), + createInitializeAccountInstruction(account, mint, owner.publicKey, TEST_PROGRAM_ID) + ); + + await sendAndConfirmTransaction(connection, transaction, [payer, accountKeypair], undefined); + }); + + it('enable/disable via instruction', async () => { + let accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); + + let transaction = new Transaction().add( + createEnableCpiGuardInstruction(account, owner.publicKey, [], TEST_PROGRAM_ID) + ); + await sendAndConfirmTransaction(connection, transaction, [payer, owner], undefined); + + accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); + let cpiGuard = getCpiGuard(accountInfo); + + expect(cpiGuard).to.not.be.null; + if (cpiGuard !== null) { + expect(cpiGuard.lockCpi).to.be.true; + } + + transaction = new Transaction().add( + createDisableCpiGuardInstruction(account, owner.publicKey, [], TEST_PROGRAM_ID) + ); + await sendAndConfirmTransaction(connection, transaction, [payer, owner], undefined); + + accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); + cpiGuard = getCpiGuard(accountInfo); + + expect(cpiGuard).to.not.be.null; + if (cpiGuard !== null) { + expect(cpiGuard.lockCpi).to.be.false; + } + }); + + it('enable/disable via command', async () => { + let accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); + + await enableCpiGuard(connection, payer, account, owner, [], undefined, TEST_PROGRAM_ID); + + accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); + let cpiGuard = getCpiGuard(accountInfo); + + expect(cpiGuard).to.not.be.null; + if (cpiGuard !== null) { + expect(cpiGuard.lockCpi).to.be.true; + } + + await disableCpiGuard(connection, payer, account, owner, [], undefined, TEST_PROGRAM_ID); + + accountInfo = await getAccount(connection, account, undefined, TEST_PROGRAM_ID); + cpiGuard = getCpiGuard(accountInfo); + + expect(cpiGuard).to.not.be.null; + if (cpiGuard !== null) { + expect(cpiGuard.lockCpi).to.be.false; + } + }); +}); diff --git a/token/js/test/unit/programId.test.ts b/token/js/test/unit/programId.test.ts index 1de7ec0f..b192792a 100644 --- a/token/js/test/unit/programId.test.ts +++ b/token/js/test/unit/programId.test.ts @@ -15,7 +15,7 @@ import { TOKEN_2022_PROGRAM_ID, TokenUnsupportedInstructionError, createInitializePermanentDelegateInstruction, - // XXX TODO HANA + createEnableCpiGuardInstruction, } from '../../src'; chai.use(chaiAsPromised); @@ -80,5 +80,12 @@ describe('unsupported extensions in spl-token', () => { createInitializePermanentDelegateInstruction(mint, null, TOKEN_2022_PROGRAM_ID); }).to.not.throw(TokenUnsupportedInstructionError); }); - // XXX TODO HANA + it('cpiGuard', () => { + expect(function () { + createEnableCpiGuardInstruction(account, authority, [], TOKEN_PROGRAM_ID); + }).to.throw(TokenUnsupportedInstructionError); + expect(function () { + createEnableCpiGuardInstruction(account, authority, [], TOKEN_2022_PROGRAM_ID); + }).to.not.throw(TokenUnsupportedInstructionError); + }); });