@codama/dynamic-parsers
v1.4.1
Published
Helpers to dynamically identify and parse accounts and instructions
Maintainers
Readme
Codama ➤ Dynamic Parsers
This package provides a set of helpers that, given any Codama IDL, dynamically identifies and parses any byte array into deserialized accounts, events, and instructions.
Installation
pnpm install @codama/dynamic-parsers[!NOTE] This package is not included in the main
codamapackage.
Types
ParsedData<TNode>
This type represents the result of identifying and parsing a byte array from a given root node. It provides us with the full NodePath of the identified node, as well as the data deserialized from the provided bytes.
type ParsedData<TNode extends AccountNode | EventNode | InstructionNode> = {
data: unknown;
path: NodePath<TNode>;
};Functions
parseAccountData(rootNode, bytes)
Given a RootNode and a byte array, this function will attempt to identify the correct account node and use it to deserialize the provided bytes. Therefore, it returns a ParsedData<AccountNode> object if the parsing was successful, or undefined otherwise.
const parsedData = parseAccountData(rootNode, bytes);
// ^ ParsedData<AccountNode> | undefined
if (parsedData) {
const accountNode: AccountNode = getLastNodeFromPath(parsedData.path);
const decodedData: unknown = parsedData.data;
}parseEventData(rootNode, bytes)
Similarly to parseAccountData, this function will match the provided bytes to an event node and deserialize them accordingly. It returns a ParsedData<EventNode> object if the parsing was successful, or undefined otherwise.
const parsedData = parseEventData(rootNode, bytes);
// ^ ParsedData<EventNode> | undefined
if (parsedData) {
const eventNode: EventNode = getLastNodeFromPath(parsedData.path);
const decodedData: unknown = parsedData.data;
}parseInstructionData(rootNode, bytes)
Similarly to parseAccountData, this function will match the provided bytes to an instruction node and deserialize them accordingly. It returns a ParsedData<InstructionNode> object if the parsing was successful, or undefined otherwise.
const parsedData = parseInstructionData(rootNode, bytes);
// ^ ParsedData<InstructionNode> | undefined
if (parsedData) {
const instructionNode: InstructionNode = getLastNodeFromPath(parsedData.path);
const decodedData: unknown = parsedData.data;
}parseInstruction(rootNode, instruction)
This function accepts a RootNode and an Instruction type — as defined in @solana/instructions — in order to return a ParsedData<InstructionNode> object that also includes an accounts array that match each AccountMeta with its corresponding account name.
const parsedData = parseInstruction(rootNode, instruction);
if (parsedData) {
const namedAccounts = parsedData.accounts;
// ^ Array<AccountMeta & { name: string }>
}Note that it uses the instruction's programAddress to restrict the search to the matching program — including any of the root node's additionalPrograms. When no program of the root matches that address, nothing is parsed: matching an unknown program against another program's candidates would confidently misattribute the data, which matters when the result is displayed to end users (e.g. clear signing).
Program selection
All functions above search the root node's main program as well as its additionalPrograms, in that order. Additionally, they all accept an optional programAddress option that restricts the search to the programs matching that address. When no program matches, nothing is identified.
const parsedData = parseInstructionData(rootNode, bytes, { programAddress: address });The single-non-discriminated-candidate fallback follows the same selection when a programAddress is provided. Without one, it stays conservative and only applies to the main program, since bytes alone cannot tell which program a discriminator-less candidate belongs to.
identifyAccountData
This function tries to match the provided bytes to an account node, returning a NodePath<AccountNode> object if the identification was successful, or undefined otherwise. It is used by the parseAccountData function under the hood.
const path = identifyAccountData(root, bytes);
// ^ NodePath<AccountNode> | undefined
if (path) {
const accountNode: AccountNode = getLastNodeFromPath(path);
}identifyInstructionData
This function tries to match the provided bytes to an instruction node, returning a NodePath<InstructionNode> object if the identification was successful, or undefined otherwise. It is used by the parseInstructionData function under the hood.
const path = identifyInstructionData(root, bytes);
// ^ NodePath<InstructionNode> | undefined
if (path) {
const instructionNode: InstructionNode = getLastNodeFromPath(path);
}identifyEventData
This function tries to match the provided bytes to an event node, returning a NodePath<EventNode> object if the identification was successful, or undefined otherwise. It is used by the parseEventData function under the hood.
const path = identifyEventData(root, bytes);
// ^ NodePath<EventNode> | undefined
if (path) {
const eventNode: EventNode = getLastNodeFromPath(path);
}