3

Have a question related to custom program development. I've testing this program

pub mod fluxtility {
    use super::*;

    pub fn buy_ticket(ctx: Context<Initialize>, lamports: u64) -> Result<()> {
        buy_ticket::process_instructions(ctx, lamports)
    }
}

How can I call this specific function from nodejs side? Have this code but throwing error -

const buyTicketInstructionData = struct([
    u8("instruction"),
    u64("lamports")
]);

const data = Buffer.alloc(buyTicketInstructionData.span);
buyTicketInstructionData.encode({
    instruction: "buy_ticket",
    lamports: BigInt(LAMPORTS_PER_SOL)
}, data);

const buyTicketInstruction = new TransactionInstruction({
    programId,
    keys: [
        {
            pubkey: ownerWallet.publicKey,
            isSigner: true,
            isWritable: false
        },
        {
            pubkey: discordWallet.publicKey,
            isSigner: false,
            isWritable: false
        },
        {
            pubkey: SystemProgram.programId,
            isSigner: false,
            isWritable: false
        }
    ],
    data: data
});

const transaction = new Transaction().add(buyTicketInstruction);
const tx = await sendAndConfirmTransaction(connection, transaction, [ ownerWallet ]);

console.log(tx);

And the error is -

logs: [
    'Program FLUXGWc3HLGHt7AKHGJLohWYzQJrVpihhkzxXXZM38cm invoke [1]',
    'Program log: AnchorError occurred. Error Code: InstructionFallbackNotFound. Error Number: 101. Error Message: Fallback functions are not supported.',
    'Program FLUXGWc3HLGHt7AKHGJLohWYzQJrVpihhkzxXXZM38cm consumed 2865 of 200000 compute units',
    'Program FLUXGWc3HLGHt7AKHGJLohWYzQJrVpihhkzxXXZM38cm failed: custom program error: 0x65'
  ]

3 Answers 3

3

You can only conveniently access code written in Anchor with the interface Anchor provides through its ts package.

This is because the entrypoint to an Anchor program first attempts to strip any instruction data(a &[u8] slice) it receives of the first 8 bytes and parse those bytes. Anchor does this because those bytes make up the method identifier which Anchor uses internally to decide which of your anchor-defined instructions to call before it then dispatches execution to the solana_program entrypoint.

When you use Anchor's interface (i.e program.methods), the Anchor-client pads(at the front) your instruction data with a method_identifier generated from the IDL. It knows the Anchor program expects that.

In the above code we're skipping that step. Therefore, when Anchor tries to parse what it thinks is the method identifier it can't find one that matches any of the identifiers it expects, and so it fails.

1
  • That was helpful! I ended up using anchor ts lib to build the instruction. But if there's any way possible I would really like to build the instruction the way tried in above code. Commented Feb 20, 2023 at 15:55
2

You have to provide the instruction discriminator to the data of your transaction like Ademola have mentioned.

What you can do is fetch the instruction discriminator then append it to your data in the first 8 bytes.

Fetch Instruction Discriminator in Rust

pub fn sighash(namespace: &str, name: &str) -> [u8; 8] {
    let preimage = format!("{}:{}", namespace, name);

    let mut sighash = [0u8; 8];
    sighash.copy_from_slice(
        &anchor_client::anchor_lang::solana_program::hash::hash(preimage.as_bytes()).to_bytes()
            [..8],
    );
    sighash
}

println!("{:?}", sighash("global", "initialize"));

Fetch Discriminator Instruction In typescript

function sighash(nameSpace: string, ixName: string): Buffer {
  let name = snakeCase(ixName);
  let preimage = `${nameSpace}:${name}`;
  return Buffer.from(sha256.digest(preimage)).slice(0, 8);
}

namespace should be global

Here is an example in Typescript

// Craft the InstructionBuffer
const ixBuffer = sighash('global','initialize');

const instructionBuffer = Buffer.concat([
   ixBuffer,            // namespace+method_name
   OtherBuffer,         // Other Data that you want to pass to the instruction.
])


// Craft the Instruction
const transactionInstruction = new TransactionInstruction({
  programId: programAddress,
  data: instructionBuffer,
  keys : [
    ...
  ]
})
0

Just as an FYI, this error can also come about if you have a program deployed already and update it and simply run anchor build without running anchor deploy to upgrade the program on-chain. I just ran into this myself after doing that. I had the updated IDL, but I was trying to use a new instruction on the old program deployment which doesn't work lol.

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.