diff --git a/solana/programs/dummy-transfer-hook/src/lib.rs b/solana/programs/dummy-transfer-hook/src/lib.rs index 86d3f3b8e..a49720bdf 100644 --- a/solana/programs/dummy-transfer-hook/src/lib.rs +++ b/solana/programs/dummy-transfer-hook/src/lib.rs @@ -17,7 +17,7 @@ pub const DESTINATION_TOKEN_ACCOUNT_INDEX: u8 = 2; pub const AUTHORITY_ACCOUNT_INDEX: u8 = 3; /// Number of extra accounts in the ExtraAccountMetaList account -pub const EXTRA_ACCOUNTS_LEN: u8 = 1; +pub const EXTRA_ACCOUNTS_LEN: u8 = 2; #[program] pub mod dummy_transfer_hook { @@ -31,21 +31,30 @@ pub mod dummy_transfer_hook { pub fn initialize_extra_account_meta_list( ctx: Context, ) -> Result<()> { - let account_metas = vec![ExtraAccountMeta::new_with_seeds( - &[ - Seed::Literal { - bytes: "dummy_account".as_bytes().to_vec(), - }, - // owner field of the sender token account - Seed::AccountData { - account_index: SENDER_TOKEN_ACCOUNT_INDEX, - data_index: 32, - length: 32, - }, - ], - false, // is_signer - false, // is_writable - )?]; + let account_metas = vec![ + ExtraAccountMeta::new_with_seeds( + &[ + Seed::Literal { + bytes: "dummy_account".as_bytes().to_vec(), + }, + // owner field of the sender token account + Seed::AccountData { + account_index: SENDER_TOKEN_ACCOUNT_INDEX, + data_index: 32, + length: 32, + }, + ], + false, // is_signer + false, // is_writable + )?, + ExtraAccountMeta::new_with_seeds( + &[Seed::Literal { + bytes: "counter".as_bytes().to_vec(), + }], + false, // is_signer + true, // is_writable + )?, + ]; assert_eq!(EXTRA_ACCOUNTS_LEN as usize, account_metas.len()); @@ -58,8 +67,8 @@ pub mod dummy_transfer_hook { Ok(()) } - pub fn transfer_hook(_ctx: Context, _amount: u64) -> Result<()> { - // NOTE: for now, the account constraints implement all the restrictions. + pub fn transfer_hook(ctx: Context, _amount: u64) -> Result<()> { + ctx.accounts.counter.count += 1; Ok(()) } @@ -87,6 +96,12 @@ pub mod dummy_transfer_hook { } } +#[account] +#[derive(InitSpace)] +pub struct Counter { + pub count: u64, +} + #[derive(Accounts)] pub struct InitializeExtraAccountMetaList<'info> { #[account(mut)] @@ -104,6 +119,16 @@ pub struct InitializeExtraAccountMetaList<'info> { pub mint: InterfaceAccount<'info, Mint>, pub token_program: Interface<'info, TokenInterface>, pub associated_token_program: Program<'info, AssociatedToken>, + + #[account( + init, + payer = payer, + space = 8 + Counter::INIT_SPACE, + seeds = [b"counter"], + bump + )] + pub counter: Account<'info, Counter>, + pub system_program: Program<'info, System>, } @@ -136,4 +161,11 @@ pub struct TransferHook<'info> { /// CHECK: dummy account. It just tests that the off-chain code correctly /// computes and the on-chain code correctly passes on the PDA. pub dummy_account: AccountInfo<'info>, + + #[account( + mut, + seeds = [b"counter"], + bump + )] + pub counter: Account<'info, Counter>, } diff --git a/solana/tests/example-native-token-transfer.ts b/solana/tests/example-native-token-transfer.ts index 95939cb8f..4221419e6 100644 --- a/solana/tests/example-native-token-transfer.ts +++ b/solana/tests/example-native-token-transfer.ts @@ -61,6 +61,16 @@ describe("example-native-token-transfers", () => { dummyTransferHook.programId ); + const [counterPDA] = PublicKey.findProgramAddressSync( + [Buffer.from("counter")], + dummyTransferHook.programId + ); + + async function counterValue(): Promise { + const counter = await dummyTransferHook.account.counter.fetch(counterPDA); + return counter.count + } + it("Initialize mint", async () => { const extensions = [spl.ExtensionType.TransferHook]; const mintLen = spl.getMintLen(extensions); @@ -128,6 +138,7 @@ describe("example-native-token-transfers", () => { .accountsStrict({ payer: payer.publicKey, mint: mint.publicKey, + counter: counterPDA, extraAccountMetaList: extraAccountMetaListPDA, tokenProgram: spl.TOKEN_2022_PROGRAM_ID, associatedTokenProgram: spl.ASSOCIATED_TOKEN_PROGRAM_ID, @@ -243,6 +254,7 @@ describe("example-native-token-transfers", () => { // TODO: assert other stuff in the message // console.log(nttManagerMessage); + expect((await counterValue()).toString()).to.be.eq("1") }); it("Can receive tokens", async () => { @@ -300,6 +312,8 @@ describe("example-native-token-transfers", () => { }); expect(released).to.equal(true); + + expect((await counterValue()).toString()).to.be.eq("2") }); });