Skip to content

Commit f3f119f

Browse files
committed
add transferhook constraint to example
1 parent 80aae87 commit f3f119f

File tree

3 files changed

+80
-46
lines changed

3 files changed

+80
-46
lines changed

tokens/token-2022/transfer-hook/anchor/TransferHookHelloWorld/Anchor.toml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
[toolchain]
22

33
[features]
4-
seeds = false
4+
resolution = true
55
skip-lint = false
66

77
[programs.localnet]
8-
transfer_hook = "DrWbQtYJGtsoRwzKqAbHKHKsCJJfpysudF39GBVFSxub"
8+
transfer_hook = "jY5DfVksJT8Le38LCaQhz5USeiGu4rUeVSS8QRAMoba"
99

1010
[registry]
1111
url = "https://api.apr.dev"
@@ -17,8 +17,16 @@ wallet = "~/.config/solana/id.json"
1717
[scripts]
1818
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
1919

20+
[test]
21+
startup_wait = 5000
22+
shutdown_wait = 2000
23+
upgradeable = false
24+
2025
[test.validator]
26+
bind_address = "0.0.0.0"
2127
url = "https://api.devnet.solana.com"
28+
ledger = ".anchor/test-ledger"
29+
rpc_port = 8899
2230

2331
[[test.validator.clone]]
24-
address = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
32+
address = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"

tokens/token-2022/transfer-hook/anchor/TransferHookHelloWorld/programs/transfer-hook/src/lib.rs

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,32 @@
11
use anchor_lang::prelude::*;
22
use anchor_spl::{
3-
associated_token::AssociatedToken, token_2022::Token2022, token_interface::{Mint, TokenAccount}
3+
associated_token::AssociatedToken, token_interface::{
4+
spl_pod::optional_keys::OptionalNonZeroPubkey,
5+
spl_token_2022::{
6+
extension::{
7+
transfer_hook::TransferHook as TransferHookExtension, BaseStateWithExtensions,
8+
StateWithExtensions,
9+
},
10+
state::Mint as MintState,
11+
},
12+
Mint, Token2022, TokenAccount
13+
},
414
};
515
use spl_tlv_account_resolution::{account::ExtraAccountMeta, state::ExtraAccountMetaList};
616
use spl_transfer_hook_interface::instruction::ExecuteInstruction;
717

8-
declare_id!("DrWbQtYJGtsoRwzKqAbHKHKsCJJfpysudF39GBVFSxub");
18+
declare_id!("jY5DfVksJT8Le38LCaQhz5USeiGu4rUeVSS8QRAMoba");
919

1020
#[program]
1121
pub mod transfer_hook {
1222
use super::*;
1323

24+
// create a mint account that specifies this program as the transfer hook program
25+
pub fn initialize(ctx: Context<Initialize>, _decimals: u8) -> Result<()> {
26+
ctx.accounts.check_mint_data()?;
27+
Ok(())
28+
}
29+
1430
#[interface(spl_transfer_hook_interface::initialize_extra_account_meta_list)]
1531
pub fn initialize_extra_account_meta_list(
1632
ctx: Context<InitializeExtraAccountMetaList>,
@@ -36,6 +52,49 @@ pub mod transfer_hook {
3652
}
3753
}
3854

55+
#[derive(Accounts)]
56+
#[instruction(_decimals: u8)]
57+
pub struct Initialize<'info> {
58+
#[account(mut)]
59+
pub payer: Signer<'info>,
60+
61+
#[account(
62+
init,
63+
payer = payer,
64+
mint::decimals = _decimals,
65+
mint::authority = payer,
66+
extensions::transfer_hook::authority = payer,
67+
extensions::transfer_hook::program_id = crate::ID,
68+
)]
69+
pub mint_account: InterfaceAccount<'info, Mint>,
70+
pub token_program: Program<'info, Token2022>,
71+
pub system_program: Program<'info, System>,
72+
}
73+
74+
// helper to check mint data, and demonstrate how to read mint extension data within a program
75+
impl<'info> Initialize<'info> {
76+
pub fn check_mint_data(&self) -> Result<()> {
77+
let mint = &self.mint_account.to_account_info();
78+
let mint_data = mint.data.borrow();
79+
let mint_with_extension = StateWithExtensions::<MintState>::unpack(&mint_data)?;
80+
let extension_data = mint_with_extension.get_extension::<TransferHookExtension>()?;
81+
82+
assert_eq!(
83+
extension_data.authority,
84+
OptionalNonZeroPubkey::try_from(Some(self.payer.key()))?
85+
);
86+
87+
assert_eq!(
88+
extension_data.program_id,
89+
OptionalNonZeroPubkey::try_from(Some(crate::ID))?
90+
);
91+
92+
msg!("{:?}", extension_data);
93+
Ok(())
94+
}
95+
}
96+
97+
3998
#[derive(Accounts)]
4099
pub struct InitializeExtraAccountMetaList<'info> {
41100
#[account(mut)]

tokens/token-2022/transfer-hook/anchor/TransferHookHelloWorld/tests/transfer-hook.ts

Lines changed: 8 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,12 @@ import * as anchor from "@coral-xyz/anchor";
22
import { Program } from "@coral-xyz/anchor";
33
import { TransferHook } from "../target/types/transfer_hook";
44
import {
5-
SystemProgram,
65
Transaction,
76
sendAndConfirmTransaction,
87
Keypair,
98
} from "@solana/web3.js";
109
import {
11-
ExtensionType,
1210
TOKEN_2022_PROGRAM_ID,
13-
getMintLen,
14-
createInitializeMintInstruction,
15-
createInitializeTransferHookInstruction,
1611
ASSOCIATED_TOKEN_PROGRAM_ID,
1712
createAssociatedTokenAccountInstruction,
1813
createMintToInstruction,
@@ -31,7 +26,7 @@ describe("transfer-hook", () => {
3126

3227
// Generate keypair to use as address for the transfer-hook enabled mint
3328
const mint = new Keypair();
34-
const decimals = 9;
29+
const decimals = 2;
3530

3631
// Sender token account address
3732
const sourceTokenAccount = getAssociatedTokenAddressSync(
@@ -52,41 +47,13 @@ describe("transfer-hook", () => {
5247
ASSOCIATED_TOKEN_PROGRAM_ID
5348
);
5449

55-
it("Create Mint Account with Transfer Hook Extension", async () => {
56-
const extensions = [ExtensionType.TransferHook];
57-
const mintLen = getMintLen(extensions);
58-
const lamports =
59-
await provider.connection.getMinimumBalanceForRentExemption(mintLen);
60-
61-
const transaction = new Transaction().add(
62-
SystemProgram.createAccount({
63-
fromPubkey: wallet.publicKey,
64-
newAccountPubkey: mint.publicKey,
65-
space: mintLen,
66-
lamports: lamports,
67-
programId: TOKEN_2022_PROGRAM_ID,
68-
}),
69-
createInitializeTransferHookInstruction(
70-
mint.publicKey,
71-
wallet.publicKey,
72-
program.programId, // Transfer Hook Program ID
73-
TOKEN_2022_PROGRAM_ID
74-
),
75-
createInitializeMintInstruction(
76-
mint.publicKey,
77-
decimals,
78-
wallet.publicKey,
79-
null,
80-
TOKEN_2022_PROGRAM_ID
81-
)
82-
);
83-
84-
const txSig = await sendAndConfirmTransaction(
85-
provider.connection,
86-
transaction,
87-
[wallet.payer, mint]
88-
);
89-
console.log(`Transaction Signature: ${txSig}`);
50+
it("Create Mint with Transfer Hook Extension", async () => {
51+
const transactionSignature = await program.methods
52+
.initialize(decimals)
53+
.accounts({ mintAccount: mint.publicKey })
54+
.signers([mint])
55+
.rpc({ skipPreflight: true });
56+
console.log("Your transaction signature", transactionSignature);
9057
});
9158

9259
// Create the two token accounts for the transfer-hook enabled mint

0 commit comments

Comments
 (0)