1

in the package @solana/web3.js there is such type AccountMeta

/**
 * Account metadata used to define instructions
 */
type AccountMeta = {
    /** An account's public key */
    pubkey: PublicKey;
    /** True if an instruction requires a transaction signature matching `pubkey` */
    isSigner: boolean;
    /** True if the `pubkey` can be loaded as a read-write account. */
    isWritable: boolean;
};

I use this type to decode the data. I get the data from transactions. After poking around in this data, I can't find any information about isSigner and isWritable. Where to get them?

raw data looks like this

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

I'm taking the data from all the keys.

tx.transaction.message.accountKeys => [
  '9iGipTrLnL8qWWUPoBBxiktcdfDPUJRKAv2xeCG1K7UU',
  '5jjxRiSnBPTE8WDCBnGRw4n9zXcpgXYowyGVN2JVuQ3E',
  '73p6jUhJ1iRB2Prc5qEfserpFprFs5QhwqYfNzjXeATQ',
  'ComputeBudget111111111111111111111111111111',
  '11111111111111111111111111111111',
  'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
  'So11111111111111111111111111111111111111112',
  '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'
]

taking instructions

tx.transaction.message.instructions => { accounts: [ 1, 6, 0, 19 ], data: '2', programIdIndex: 5 }

the numbers in accounts accounts: [ 1, 6, 0, 19 ] are indices from the AccountsKeys array? How to work with them? Where do they refer to? because I get Error TokenInvalidInstructionKeysError when decoding.

decode with decodeInstruction from @solana/spl-token

For the decodeInstruction function from @solana/spl-token you need to provide an array of keys. which will have values matching the AccountMeta type. But I did not find information about isSigner and isWritable in the transaction data. Where to get them?

So, two questions. Where to get information about isSigner and isWritable? from the raw data I showed you above. I want to provide this information to the decodeInstruction function

second question, what do these numbers in the accounts field indicate? I don't think they are indexes, because index number 19, from accounts: [1, 6, 0, 19] would be undefined, since accountKeys doesn't have that many keys.

if they are indices, it means that there are missing keys in the accountKeys data array. Is this even possible?

update.

Thanks for your comments, it helped me. i want to make sure i understand the situation correctly. Since my headers are different. Could you please give me an example based on this data.

accountKeys: [
  'DG5Ba67Ys5U5JcrMjcE3urmorYErguhuViLg7CuZy4Nq',
  'EUUpDKRbWWFtA8SrKgiEMBvvsG3YST7bWHo4nJVimV2Q',
  'E6TsJB737Mm85VaJtQJSoMkZS619UU6qLLUx3qDSevZx',
  '6vLZ6Kz46rRsC9EsRwYP1C2Cqwfq4jA9SMjVzK1MmoQ5',
  '9DCxsMizn3H1hprZ7xWe6LDzeUeZBksYFpBWBtSf1PQX',
  '6Hqq4Zxdqj6HzLS11y5vEnCd2qxT1gQtG4NjCJ3D8CGu',
  'EP6kxz5emawLyZ1MrwZsejcZ3YjvLwxJheriUwAQyJJV',
  'Eo1HHS36tkXAmWtr9a6vWAqL9WnZGiFzmCwd6r1Ayaqv',
  'HX9RH6AXiwjZbrzp2aaBw7vVTqJL6qP4XAgxH9bTP9rK',
  'A5aZrtA7MQZ1W31Dew2rEw2gBboVPR7XZeQ24QaGpzzW',
  '5BHWbF5cbAPb6CgrqNoFHme1a7QDqcV1NGqbpyTe7ywz',
  '3GAjr3LTaP4VAYv1eiSTFoGYkrmGwmaEebdbya8K38Qq',
  '4NFdKk5up2xAmQKRUwrcFPKp77tw8HXRxKPh52HgRat3',
  'B7fmLgen6Rniq8EBgPrT4HSzPrfe4JTMSJxALuRNB31B',
  'K1LRSA1DSoKBtC5DkcvnermRQ62YxogWSCZZPWQrdG5',
  'ComputeBudget111111111111111111111111111111',
  '11111111111111111111111111111111',
  'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
  'So11111111111111111111111111111111111111112',
  '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',
  '5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1',
  '2ws3teGMs2Z9PhVLZjPnfPxU7zFdT7jTSojXRVe1Ctjs'
]

headers: {
  numReadonlySignedAccounts: 0,
  numReadonlyUnsignedAccounts: 7,
  numRequiredSignatures: 1
} 

insturction: { accounts: [ 1, 18, 0, 22 ], data: '2', programIdIndex: 17 }

1 Answer 1

3

The information about isSigner and isWritable comes from the header field of the transaction. It contains this data:

numReadonlyUnsignedAccounts: number;
numReadonlySignedAccounts: number;
numRequiredSignatures: number;

The accounts are ordered, with writable signers first, then read-only signers, then writable accounts, then read-only. I'll ignore address table lookups for now, but they go after all these.

So, let's say numRequiredSignatures was 2. That would mean that the first two accounts, 9iGipTrLnL8qWWUPoBBxiktcdfDPUJRKAv2xeCG1K7UU and 5jjxRiSnBPTE8WDCBnGRw4n9zXcpgXYowyGVN2JVuQ3E are signers. All other accounts are not.

Now let's say numReadonlySignedAccounts was 1. That would mean that the first account, 9iGipTrLnL8qWWUPoBBxiktcdfDPUJRKAv2xeCG1K7UU is writable, and the second account, 5jjxRiSnBPTE8WDCBnGRw4n9zXcpgXYowyGVN2JVuQ3E is not.

Now we know the isSigner and isWritable status of our 2 signer accounts. We know the other 6 accounts are not signers, but not which of them are writable.

Now let's say numReadonlyUnsignedAccounts is 4. Notice this is the last of our categories, not signer and read-only. This would mean that the last 4 accounts are not writable: from 11111111111111111111111111111111 to the last account. And that means that our 3rd and 4th account, 73p6jUhJ1iRB2Prc5qEfserpFprFs5QhwqYfNzjXeATQ and ComputeBudget111111111111111111111111111111 are writable.

So basically you can use the header information and the order of the account to derive isSigner and isWritable for every account.

You can see example code that does this here: https://github.com/solana-labs/solana-web3.js/blob/ca243cbe943d31ea7f587ca6890d7c67d5493fa2/packages/transactions/src/decompile-transaction.ts#L20 This is part of the new/experimental web3js so the data structures (and field names) are different, but hopefully it's quite legible!

--

Using the numbers in your updated question, you have:

  • numRequiredSignatures is 1, so only the first account, DG5Ba67Ys5U5JcrMjcE3urmorYErguhuViLg7CuZy4Nq is a signer. All others are not

  • numReadonlySignedAccounts is 0, so that signer is writable.

  • numReadonlyUnsignedAccounts is 7, so the last 7 accounts are read-only (starting with ComputeBudget111111111111111111111111111111 to the end of the array), all other non-signer accounts are writable.

--

On the second part of your question, you're correct that those numbers are indices into the accountKeys array. Given that your transaction version is legacy you can't have any address lookup tables, which would usually be the explanation for indices that are greater than the length of that array. You have 22 account keys, so I'm not sure where index 22 is coming from, that'd be undefined. Can you give a link to this transaction on an explorer so I can take a look?

4
  • Thanks for the reply. very helpful. only my headers are different. Do they have the same working principle? Are there any peculiarities? my headers: => numReadonlySignedAccounts: 0, numReadonlyUnsignedAccounts: 7, numRequiredSignatures: 1
    – slntrx
    Jan 19 at 4:42
  • 1
    I've edited the answer to use those field names, they have the same meaning just slightly reworded. And added the explanation using those numbers. I noticed you updated accountKeys and it now has 22 accounts - so index 19 makes sense now. But then you added an instruction with 22 so I'm still stumped on that! Can you link to the transaction on an explorer?
    – Callum M
    Jan 19 at 8:39
  • I apologize for not being precise enough. I'm not a native English speaker, so this data is from different transactions that come to me. I didn't save their signatures. But you've helped me a lot. I think I've solved my problem. Thank you.
    – slntrx
    Jan 19 at 8:58
  • 1
    I think I will ask a separate question about the fact that I have different number of keys and different number of indexes, but first I will gather enough information.
    – slntrx
    Jan 19 at 8:59

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.