Here are two references of transfer hook programs built using Anchor!
https://github.com/0ximalice/spl-token-2022-transfer-hook-anchor
https://github.com/TeamRaccoons/raccoons-program-library/tree/main/permissioned-token
It looks like the solution is to use the a fallback
instruction in Anchor to work around the instruction discriminator.
Here's the fallback instructions for the two references:
// Sha256(spl-transfer-hook-interface:execute)[..8]
pub const EXECUTE_IX_TAG_LE: [u8; 8] = [105, 37, 101, 197, 75, 251, 102, 26];
...
pub fn fallback(program_id: &Pubkey, accounts: &[AccountInfo], ix_data: &[u8]) -> Result<()> {
let mut ix_data: &[u8] = ix_data;
let sighash: [u8; 8] = {
let mut sighash: [u8; 8] = [0; 8];
sighash.copy_from_slice(&ix_data[..8]);
ix_data = &ix_data[8..];
sighash
};
match sighash {
EXECUTE_IX_TAG_LE => {__private::__global::transfer_hook(program_id, accounts, ix_data)},
_ => Err(ProgramError::InvalidInstructionData.into()),
}
}
/// The fallback allows routing methods to match the transfer hook interface
pub fn fallback(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> Result<()> {
if let Err(error) = processor::process(program_id, accounts, instruction_data) {
// catch the error so we can print it
error.print::<TransferHookError>();
return Err(error.into());
}
Ok(())
}
}