2

I am trying to test the transfer-hook extension by creating and minting a token using the example transfer-hook program. I have successfully deployed the program, created the token with the transfer-hook program, and minted the token. I have also initialized the extra account metas using the provided cli.

$ spl-transfer-hook create-extra-metas <PROGRAM_ID> <MINT_ID> [<ACCOUNT_PUBKEY>:<ROLE> ...]

However, I am not sure what minimum number of accounts if any should be written into the extra metas account.

I then try to initiate the transfer using:

spl-token transfer [FLAGS] [OPTIONS] <TOKEN_MINT_ADDRESS> <TOKEN_AMOUNT> <RECIPIENT_WALLET_ADDRESS or RECIPIENT_TOKEN_ACCOUNT_ADDRESS> --transfer-hook-accounts [<ACCOUNT_PUBKEY>:<ROLE> ...]

I understand that I need to provide all the accounts required to execute the transfer hook at some point and in some place but I do not know where. I have tried many variations, such as providing the program data account in the extra metas account then providing the program account and extra metas account when transferring. No combination I have tried has worked so far.

What am I missing here? In my understanding the way it should work is, there should be some set of minimum accounts that the user must provide at the time of transfer. Such as the transfer hook program, or the extra metas account. Then the rest of the needed accounts could be read by either deriving the extra metas account from the mint and the program id, or just directly reading from the extra metas account if provided. This is done on the client side using spl-transfer-hook-interface::offchain. Then you should have every account needed to transfer. It looks like the spl-token cli does try this resolve_extra_account_transfer() at some point if the extra-account-metas are not provided, but how would it know the program id?

Any help would be appreciated, and I understand this is bleeding edge and even subject to change! Thank you!

2 Answers 2

3

For what needs to be written into the extra account metas account, the program_id, source, mint, destination, and authority are passed into your transfer hook program automatically by the Token 2022 transfer instruction. The extra account metas account describes the additional accounts you are expecting for your specific program.

All of these accounts need to be passed into the top level transfer, and I think that the spl-token CLI program handles this without you needing to specify any accounts in the --transfer-hook-account option during the transfer.

I tried this on solana-test-validator with 1.17.0:

  1. Build and deploy transfer hook example
  2. Create a mint using the deployed example
  3. Use the spl-transfer-hook cli and add an extra account
./spl-transfer-hook create-extra-metas <exampleProgramId> <mint> CaCGk7xhfT2AYGu4PnHK8uSZN3GZKVHrvgYmH2s9kJeD:readonly
  1. Create ATAs for the sender and receiver then mint tokens
  2. Send using the spl-token CLI
spl-token transfer <mint> 1 <receiver> --allow-unfunded-recipient

Using the transfer command without the --transfer-hook--account option, I was able to verify in the explorer that the account I specified in step three was sent to the CPI call into the example program.

When I tried adding the --transfer-hook--account option I get an unknown error from the Token 2022 program. My guess is that the CLI is resolving the extra account metas from the account created in Step 3, and the option is not needed.

6
  • What account are you adding to the extra metas account?
    – tonton
    Dec 31, 2023 at 1:23
  • I just tried with an initialized account metas account that is empty and the transfer worked. I think the extra account metas account just needs to be created. I believe the it fails on the client side if it has not been created.
    – tonton
    Dec 31, 2023 at 2:08
  • Essentially if --transfer-hook-account is not provided, the client will attempt to resolve the extra account metas from the program_id and mint and fail if the extra metas was not initialized. If --transfer-hook-account is provided, the client just appends the provided accounts to the list of accounts in the instruction.
    – tonton
    Dec 31, 2023 at 2:33
  • @tonton I added a randomly generated uninitialized account CaCGk7xhfT2AYGu4PnHK8uSZN3GZKVHrvgYmH2s9kJeD to the extra account metas account using the spl-transfer-hook CLI. Your explanation about how the options works makes sense. Did you get it to work manually passing in the accounts?
    – Fuzzy Yeti
    Dec 31, 2023 at 2:41
  • Yes! So I looked at how resolve_extra_account_metas() works and it first derives the extra account metas account, reads the accounts it has and adds to the instruction. It then adds the extra account metas and program ID to the instruction aswell. So If your extra account metas is empty. You at minimum need to provide the program ID and extra account metas account if you use the --transfer-hook-account flag. If you populated the extra account metas you must provide those too. So in your case you need to provide 3 accounts with the flag.
    – tonton
    Dec 31, 2023 at 2:55
1

Not sure how it would work using the CLI. However, when building the instruction using JS, I had to manually add the AccountMetas for all the extra accounts to the transferChecked instruction.

Additionally, I had to also include the addresses for both the ExtraAccountMeta account and the Program ID of the custom transfer-hook program

    const [extraAccountMetaListPDA] = PublicKey.findProgramAddressSync(
      [Buffer.from("extra-account-metas"), mint.publicKey.toBuffer()],
      program.programId
    );

    ... 
    // This is the normal transferChecked instruction
    const transferInstruction = createTransferCheckedInstruction(
      sourceTokenAccount,
      mint.publicKey,
      destinationTokenAccount,
      wallet.publicKey,
      amount,
      decimals,
      [],
      TOKEN_2022_PROGRAM_ID
    );
    
    // Then manually add all the additional AccountMetas to the instruction
    transferInstruction.keys.push(
      {
        pubkey: program.programId, // Address of the Transfer-hook program
        isSigner: false,
        isWritable: false,
      },
      {
        pubkey: extraAccountMetaListPDA, // Address of the ExtraAccountMeta account
        isSigner: false,
        isWritable: false,
      },
      // Add AccountMeta for all accounts listed on the ExtraAccountMeta Account
    );

@solana/spl-token includes a addExtraAccountsToInstruction helper function to automatically "resolve" the accounts from the ExtraAccountMeta account, but it doesn't seem to work correctly if the seed for a PDA is also an addess stored on the ExtraAccountMeta account.

Here's the example program on Solana Playground. Its a transfer-hook program built using Anchor where the custom transfer-hook instruction requires a WSOL transfer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.