Browse Source

add transferhook constraint to example

John 1 year ago
parent
commit
f3f119f019

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

@@ -1,11 +1,11 @@
 [toolchain]
 
 [features]
-seeds = false
+resolution = true
 skip-lint = false
 
 [programs.localnet]
-transfer_hook = "DrWbQtYJGtsoRwzKqAbHKHKsCJJfpysudF39GBVFSxub"
+transfer_hook = "jY5DfVksJT8Le38LCaQhz5USeiGu4rUeVSS8QRAMoba"
 
 [registry]
 url = "https://api.apr.dev"
@@ -17,8 +17,16 @@ wallet = "~/.config/solana/id.json"
 [scripts]
 test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
 
+[test]
+startup_wait = 5000
+shutdown_wait = 2000
+upgradeable = false
+
 [test.validator]
+bind_address = "0.0.0.0"
 url = "https://api.devnet.solana.com"
+ledger = ".anchor/test-ledger"
+rpc_port = 8899
 
 [[test.validator.clone]]
-address = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
+address = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"

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

@@ -1,16 +1,32 @@
 use anchor_lang::prelude::*;
 use anchor_spl::{
-    associated_token::AssociatedToken, token_2022::Token2022, token_interface::{Mint, TokenAccount}
+    associated_token::AssociatedToken, token_interface::{
+        spl_pod::optional_keys::OptionalNonZeroPubkey,
+        spl_token_2022::{
+            extension::{
+                transfer_hook::TransferHook as TransferHookExtension, BaseStateWithExtensions,
+                StateWithExtensions,
+            },
+            state::Mint as MintState,
+        },
+        Mint, Token2022, TokenAccount
+    },
 };
 use spl_tlv_account_resolution::{account::ExtraAccountMeta, state::ExtraAccountMetaList};
 use spl_transfer_hook_interface::instruction::ExecuteInstruction;
 
-declare_id!("DrWbQtYJGtsoRwzKqAbHKHKsCJJfpysudF39GBVFSxub");
+declare_id!("jY5DfVksJT8Le38LCaQhz5USeiGu4rUeVSS8QRAMoba");
 
 #[program]
 pub mod transfer_hook {
     use super::*;
 
+    // create a mint account that specifies this program as the transfer hook program
+    pub fn initialize(ctx: Context<Initialize>, _decimals: u8) -> Result<()> {
+        ctx.accounts.check_mint_data()?;
+        Ok(())
+    }
+
     #[interface(spl_transfer_hook_interface::initialize_extra_account_meta_list)]
     pub fn initialize_extra_account_meta_list(
         ctx: Context<InitializeExtraAccountMetaList>,
@@ -36,6 +52,49 @@ pub mod transfer_hook {
     }
 }
 
+#[derive(Accounts)]
+#[instruction(_decimals: u8)]
+pub struct Initialize<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+
+    #[account(
+        init,
+        payer = payer,
+        mint::decimals = _decimals,
+        mint::authority = payer,
+        extensions::transfer_hook::authority = payer,
+        extensions::transfer_hook::program_id = crate::ID,
+    )]
+    pub mint_account: InterfaceAccount<'info, Mint>,
+    pub token_program: Program<'info, Token2022>,
+    pub system_program: Program<'info, System>,
+}
+
+// helper to check mint data, and demonstrate how to read mint extension data within a program
+impl<'info> Initialize<'info> {
+    pub fn check_mint_data(&self) -> Result<()> {
+        let mint = &self.mint_account.to_account_info();
+        let mint_data = mint.data.borrow();
+        let mint_with_extension = StateWithExtensions::<MintState>::unpack(&mint_data)?;
+        let extension_data = mint_with_extension.get_extension::<TransferHookExtension>()?;
+
+        assert_eq!(
+            extension_data.authority,
+            OptionalNonZeroPubkey::try_from(Some(self.payer.key()))?
+        );
+
+        assert_eq!(
+            extension_data.program_id,
+            OptionalNonZeroPubkey::try_from(Some(crate::ID))?
+        );
+
+        msg!("{:?}", extension_data);
+        Ok(())
+    }
+}
+
+
 #[derive(Accounts)]
 pub struct InitializeExtraAccountMetaList<'info> {
     #[account(mut)]

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

@@ -2,17 +2,12 @@ import * as anchor from "@coral-xyz/anchor";
 import { Program } from "@coral-xyz/anchor";
 import { TransferHook } from "../target/types/transfer_hook";
 import {
-  SystemProgram,
   Transaction,
   sendAndConfirmTransaction,
   Keypair,
 } from "@solana/web3.js";
 import {
-  ExtensionType,
   TOKEN_2022_PROGRAM_ID,
-  getMintLen,
-  createInitializeMintInstruction,
-  createInitializeTransferHookInstruction,
   ASSOCIATED_TOKEN_PROGRAM_ID,
   createAssociatedTokenAccountInstruction,
   createMintToInstruction,
@@ -31,7 +26,7 @@ describe("transfer-hook", () => {
 
   // Generate keypair to use as address for the transfer-hook enabled mint
   const mint = new Keypair();
-  const decimals = 9;
+  const decimals = 2;
 
   // Sender token account address
   const sourceTokenAccount = getAssociatedTokenAddressSync(
@@ -52,41 +47,13 @@ describe("transfer-hook", () => {
     ASSOCIATED_TOKEN_PROGRAM_ID
   );
 
-  it("Create Mint Account with Transfer Hook Extension", async () => {
-    const extensions = [ExtensionType.TransferHook];
-    const mintLen = getMintLen(extensions);
-    const lamports =
-      await provider.connection.getMinimumBalanceForRentExemption(mintLen);
-
-    const transaction = new Transaction().add(
-      SystemProgram.createAccount({
-        fromPubkey: wallet.publicKey,
-        newAccountPubkey: mint.publicKey,
-        space: mintLen,
-        lamports: lamports,
-        programId: TOKEN_2022_PROGRAM_ID,
-      }),
-      createInitializeTransferHookInstruction(
-        mint.publicKey,
-        wallet.publicKey,
-        program.programId, // Transfer Hook Program ID
-        TOKEN_2022_PROGRAM_ID
-      ),
-      createInitializeMintInstruction(
-        mint.publicKey,
-        decimals,
-        wallet.publicKey,
-        null,
-        TOKEN_2022_PROGRAM_ID
-      )
-    );
-
-    const txSig = await sendAndConfirmTransaction(
-      provider.connection,
-      transaction,
-      [wallet.payer, mint]
-    );
-    console.log(`Transaction Signature: ${txSig}`);
+  it("Create Mint with Transfer Hook Extension", async () => {
+    const transactionSignature = await program.methods
+      .initialize(decimals)
+      .accounts({ mintAccount: mint.publicKey })
+      .signers([mint])
+      .rpc({ skipPreflight: true });
+    console.log("Your transaction signature", transactionSignature);
   });
 
   // Create the two token accounts for the transfer-hook enabled mint