feat: add transfer hook helpers to the JS client#1232
Conversation
Port the legacy client's extra-account-meta resolution to @solana/kit: ExtraAccountMeta codecs, getExtraAccountMetaAddress, resolveExtraAccountMeta, addExtraAccountMetasForExecute, and async transferChecked / transferCheckedWithFee builders that resolve and append the accounts required by a mint's transfer hook. Closes solana-program#736
amilz
left a comment
There was a problem hiding this comment.
Looking good. I'm just wondering if some of this should get generated from the idl (IDK...just has me thinking)
Yeah, I'll post as a comment as well on the pr itself, but token-2022 is not the program that has the types |
Use kit role helpers in roleFromFlags and deEscalateAccountMeta, thread an optional FetchAccountConfig through all RPC-taking functions, expose Execute instruction data codecs and getExecuteDiscriminatorBytes, let the transfer builders' return types be inferred, and add a privilege de-escalation test.
Summary
Adds transfer hook support to the kit-based JS client as hand-written helpers in
clients/js/src, porting the extra-account-meta resolution that previously only existed inclients/js-legacy. Closes #736.ExtraAccountMetaandExtraAccountMetaAccountData(with anArgstype for encoding), plusEXECUTE_DISCRIMINATOR.decodeExtraAccountMetaList,fetchExtraAccountMetaList,fetchMaybeExtraAccountMetaListandfindExtraAccountMetasPda.resolveExtraAccountMetacovering every address config — literal key, hook-program PDA, pubkey data (from instruction or account data) and external-program PDA — and every seed type (literal, instruction data, account key, account data);getExtraAccountMetasForExecuteandaddExtraAccountMetasForExecute, including the legacy client's privilege de-escalation.getExecuteInstruction,getTransferCheckedWithTransferHookInstructionAsyncandgetTransferCheckedWithFeeAndTransferHookInstructionAsync, which fetch the mint, resolve the hook's extra accounts and append them (plus hook program and validation account) to the generated instruction.getTransferHookProgramIdexposes the mint's active hook.Behavior:
programIdunset), build the plain transfer instruction with no extra RPC calls.SOLANA_ERROR__ACCOUNTS__ACCOUNT_NOT_FOUND, matching the Rust offchain helper. (The legacy JS client silently returns the instruction unchanged, which fails on-chain later.)Tests
test/extensions/transferHook/resolveExtraAccountMetas.test.ts— mock-RPC unit tests: validation account fetch/decode round-trip, every address-config discriminator including a chained external PDA, the with-fee builder, missing required account, missing validation account, invalid discriminator and truncated seed config.test/extensions/transferHook/transferCheckedWithTransferHook.test.ts— e2e against the test validator'sspl-transfer-hook-examplefixture: the builder resolves a fixed extra account and a seed-derived PDA, the transfer succeeds with the hook executing, and a transfer without the forwarded hook accounts fails withSOLANA_ERROR__INSTRUCTION_ERROR__MISSING_ACCOUNT.pnpm test(tsc + ava, 140 tests) passes against the local test validator;eslintandprettierclean.