jito-foundation / jito-programs

49 stars 12 forks source link

Decode TipDistributionAccount data - help needed #121

Closed mbaranovski closed 3 weeks ago

mbaranovski commented 3 weeks ago

Hi, I'm aware this might not be an ideal repo to create this issue on, however it's closely related to JITO nevertheless. I'm trying to decode the TipDistributionAccount data using Node.js and I'm getting different results compared to the data presented on Solscan.

Account data in Solscan: https://solscan.io/account/YnhGiadNZaZmmhSzGPf4wRMg9dvDT6AazZQ1JbgtHTh#data Base64 encoded account info:

{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "apiVersion": "1.18.22",
      "slot": 290212683
    },
    "value": {
      "data": [
 "VUBxxupeeHtgY99Q26/kUg6yDG7Wym/FWGWGpmsjYkm6NSf9QxLHQec6dtyoGE/4fGD1LOjCSB3QZCKS5gmdzp15dvGkSylEAX1iCPbiZePC+f2ZsnETVueBrwvn9UK/ChOMqj+e5RSTv640SQEAAABzBQAAAAAAADusNEkBAAAASgUAAAAAAACeAgAAAAAAAOgDqAIAAAAAAAD7AAAAAAAAAAAAAAAA",
        "base64"
      ],
      "executable": false,
      "lamports": 2060804,
      "owner": "4R3gSG8BpU4t19KYj8CfnbtRpnT8gtk4dvTHxVRwc2r7",
      "rentEpoch": 18446744073709551615,
      "space": 168
    }
  },
  "id": "1234"
}

For simplicity let's say we want to decode only first 2 fields: validatorVoteAccount and merkleRootUploadAuthority. My attempt:

const tipDistributionAccountDecoder: Decoder < TipDistributionAccount > = getStructDecoder([
  [
    "validatorVoteAccount", getAddressDecoder()
  ],
  [
    "merkleRootUploadAuthority", getAddressDecoder()
  ]
]);
const decodedAccount = decodeAccount(accountInfo, tipDistributionAccountDecoder);

Result:

{
  executable: false,
  lamports: 2060804n,
  programAddress: '4R3gSG8BpU4t19KYj8CfnbtRpnT8gtk4dvTHxVRwc2r7',
  address: 'YnhGiadNZaZmmhSzGPf4wRMg9dvDT6AazZQ1JbgtHTh',
  data: {
    validatorVoteAccount: '6jnefFJgMP6b3uiJhiSa2W1rw4CcQzhA2kYKcYotoRj6', // Should be `7VGU4ZwR1e1AFekqbqv2gvjeg47e1PwMPm4BfLt6rxNk` based on Solscan
    merkleRootUploadAuthority: 'DXsqvDAc5sEAaudp1w775xmGnvX6bpNE9rGf49DNJv77' // Should be `GZctHpWXmsZC1YHACTGGcHhYxjdRqQvTpYkb9LMvxDib` based on Solscan
  },
  exists: true
}

In order to verify if I'm not making any mistakes I cross-checked it with online SOL / Borsh Decoder and the result is similar to mine: CleanShot 2024-09-17 at 01 10 00@2x

Any hints appreciated!

mbaranovski commented 3 weeks ago

All right, answering to myself. Apparently Anchor uses first 8 bytes of the data for the discriminator (sha256 hash of the account’s Rust identifier) so I needed to padLeft by 8 bytes.

Hint found in this article: https://blog.chalda.cz/posts/decoding-solana-data

Solution:

getStructDecoder([
    ["validatorVoteAccount", padLeftDecoder(getAddressDecoder(), 8)],
    ["merkleRootUploadAuthority", getAddressDecoder()],
])