2

upd: https://docs.solana.com/developing/programming-model/transactions#instruction-data here, my task is to decode this data using js

I tried to solve the issue with this post How to get Solana instruction data from transaction object but never got around to it. that's why I'm here.

I am listening to events token program at address TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA. i am getting data within which there are transactions, there are instructions in the messages. an example of an instruction is shown below. The question is how to decode them

how to decode data received from token program instructions ?

{
  accounts: [ 0, 1 ],
  data: '3ipZWiVHsLw9kjb4qJon6pADjViJNbKrcEVtxfZZWdkbq8KMxZegM1ecZbkz6VGvYVdH8BjqSy69GfVjCkGto52xTgtJhLygZeRAuVdThpvb5mbfFC2GjAUCYD8MAWKn1Ri6FH5JknmM2qBncCykyDsDqbjeNhNpEoYR4WNw2',
  programIdIndex: 4
}

or

{ accounts: [], data: 'JzwPro', programIdIndex: 3 }

or

{
  accounts: [
     0,  8, 11,  6, 16,  9,  4,
    10,  2,  3,  1,  5,  7, 17,
    15, 14, 12, 21, 19, 20
  ],
  data: '5k2cQw4xSusHX5',
  programIdIndex: 18
}

I realized that I need to have a scheme for decoding. Since I get the data when I monitor the token program at the address TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA. Then I assume that there is already a working decoder for this program. But I tried using decodeTransfer from the @solana/web3.js package. As a result I get TypeError: Cannot read properties of undefined (reading 'equals'). I have not found a solution for this error. So, how to decode the data correctly?

I also found this json file, for spl tokens. But I didn't understand how to use it to decode data https://github.com/acheroncrypto/native-to-anchor/blob/master/client/packages/spl-token/idl.json maybe you know how to use this json to decode the instructions?

please give me an example for decoding data with js.

and raw data looks like this

{
  blockTime: number,
  indexWithinBlock: number,
  meta: {
    err: null,
    fee: 15000,
    innerInstructions: [],
    loadedAddresses: { readonly: [], writable: [] },
    logMessages: [],
    postBalances: [],
    postTokenBalances: [],
    preBalances: [],
    preTokenBalances: [],
    rewards: []
  },
  slot: 242069085,
  transaction: {
    message: {
      accountKeys: [Array],
      addressTableLookups: null,
      header: [Object],
      instructions: [Array],
      recentBlockhash: string
    },
    signatures: [string]
  },
  version: 'legacy'
}

from this data, I'm pulling instructions

4 Answers 4

3

The data you are trying to decode is for a Magic Eden program instruction. You will need to get the IDL with the following command.

anchor idl fetch --provider.cluster mainnet M2mx93ekt1fmXSVkTrUL9xVFHkmME8HTUi5Cyc5aF7K

If you want to decode the instruction data using TypeScript,you can use the borsh npm package, and make a schema. You can find the "args" field of the instruction named "buyV2" in the IDL, and adapt this to a schema. You will need to remember to add 8 bytes at the beginning for the instruction discriminator that anchor automatically adds.

Here is what the args look like in the IDL:

      "args": [
        {
          "name": "buyerPrice",
          "type": "u64"
        },
        {
          "name": "tokenSize",
          "type": "u64"
        },
        {
          "name": "buyerStateExpiry",
          "type": "i64"
        },
        {
          "name": "buyerCreatorRoyaltyBp",
          "type": "u16"
        },
        {
          "name": "extraArgs",
          "type": "bytes"
        }
      ]

You can create a schema and decode like this:

import * as borsh from 'borsh';
import bs58  from "bs58";
const schema = { 'struct': { 'discriminator': 'u64', 'buyerPrice': 'u64', 'tokenSize': 'u64', 'buyerStateExpiry': 'i64', 'buyerCreatorRoyaltyBp': 'u16', 'extraArgs': {'array': {'type':'u8'}} } };
const data = "UEVYJrzmev2UQ1cVQ8mBufZjnj8LT83s1ukeQvg1kERm5M7F3oaX";
const decoded = borsh.deserialize(schema, Buffer.from(bs58.decode(data)));
console.log(decoded);

The instruction data wasn't shown in your console.log above, but you should be able to find it in the instructions array. I pulled it from SolScan in base58 based on the signature.

You can take this approach to decode any instruction data for a program that has published IDL.

2
  • Thanks, I figured out how to decode if there is an open idl. But unfortunately, in my task, there is no idl. there is only a json file github.com/acheroncrypto/native-to-anchor/blob/master/client/…. How can I use it to decode the data? I understand correctly that this file should be suitable to decode the data that comes when I listen to the events of the token program at the address TokenkegQfeZyiNwAJbNbNbGKPFXCWuBvf9Ss623VQ5DA
    – slntrx
    Commented Jan 16 at 9:32
  • 1
    The file you linked is an IDL. With this interface you can decode Accounts with the Anchor library using the IDL, but I don't think you can decode the instruction data. github.com/coral-xyz/anchor/blob/master/ts/packages/anchor/src/… To use the borsh library directly for SPL Token program you can implement what I have above. The discriminator would only be one byte, matching the instruction enum. You can use that to determine which schema to use. Hopefully someone will answer with something off the shelf I don't know about.
    – Fuzzy Yeti
    Commented Jan 16 at 16:19
3

more easier solution

to import the borsh decode from [email protected] (guess has similar solution for other anchor version)

import { BorshInstructionCoder } from "@coral-xyz/anchor";
let coder = new BorshInstructionCoder(idl);
let args = coder.decode(ix.data, "base58");
console.log(args);

it prints out the followings

{
  data: {
    arg1: xxxx...,
    arg2: xxxx...,
  },
  name: 'ix_name'
}
0

code for calc discriminator: fn get_disc(prefix: &str, name: &str) -> Vec { use sha2::{Digest, Sha256}; let mut hasher = Sha256::new(); hasher.update(prefix); hasher.update(b":"); hasher.update(name); hasher.finalize()[..8].into() }

when function: discriminator: get_disc("global", &name), when Anchor Account: discriminator: get_disc("account", &value.name), when event: discriminator: get_disc("event", &value.name),

Good luck. Notice: SHA256 is SHA2-256.

0

i try above two methods, but fail.

Method 1

import * as borsh from 'borsh';
import bs58  from "bs58";

    const schema = { 'struct': { 'discriminator': 'u64' } };
    const data = "UEVYJrzmev2UQ1cVQ8mBufZjnj8LT83s1ukeQvg1kERm5M7F3oaX";
    const decoded = borsh.deserialize(schema, Buffer.from(bs58.decode(data)));
    console.log(decoded);
    TypeError: schema.get is not a function
      at deserializeStruct (node_modules/borsh/lib/index.js:403:33)
      at Object.deserialize (node_modules/borsh/lib/index.js:428:20)
      at /mnt/sdd1/sbw/svm/hello/tests/hello.ts:34:27
      at Generator.next (<anonymous>)
      at fulfilled (tests/hello.ts:28:58)
      at processTicksAndRejections (node:internal/process/task_queues:95:5)

Method 2

import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { Hello } from "../target/types/hello";
import * as borsh from 'borsh';
import bs58  from "bs58";
import { BorshInstructionCoder } from "@coral-xyz/anchor";
import IDL from '../target/idl/hello.json';



describe("hello", () => {
  // Configure the client to use the local cluster.
  anchor.setProvider(anchor.AnchorProvider.env());

  const program = anchor.workspace.Hello as Program<Hello>;

  it("Is initialized!", async () => {
    // Add your test here.
    const tx = await program.methods.initialize().rpc();
    console.log("Your transaction signature", tx);

    await program.provider.connection.confirmTransaction(tx, "confirmed");

    const txDetails = await program.provider.connection.getTransaction(tx, {
      maxSupportedTransactionVersion: 0,
      commitment: "confirmed",
    });
    console.log("txDetails",txDetails)

    let coder = new BorshInstructionCoder(IDL);
    let args = coder.decode(txDetails.transaction.message.instructions, "base58");
    console.log("args",args);

  });
});

The value of args is null

args null

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.