This package provides a set of helpers that provide Codecs
for Codama nodes that describe data.
pnpm install @codama/dynamic-codecs
[!NOTE] This package is not included in the main
codama
package.
Given the full NodePath
of a node inside a Codama IDL, returns a Codec<unknown>
(as defined in @solana/codecs
) that enables encoding and decoding data for that node.
const codec = getNodeCodec([root, program, definedType]);
const bytes = codec.encode(someData);
const decodedData = codec.decode(bytes);
Note that it is important to provide the full NodePath
of the node in order to properly follow link nodes inside the Codama IDL. Here is a more complex example illustrating how link nodes are resolved:
// Here we define a program with two types, one of which is a link to the other.
const root = rootNode(
programNode({
definedTypes: [
definedTypeNode({ name: 'slot', type: numberTypeNode('u64') }),
definedTypeNode({ name: 'lastSlot', type: definedTypeLinkNode('slot') }),
],
name: 'myProgram',
publicKey: '1111',
}),
);
// The codec for the linked `lastSlot` defined type is resolved using the `slot` defined type.
const codec = getNodeCodec([root, root.program, root.program.definedTypes[1]]);
expect(codec.encode(42)).toStrictEqual(hex('2a00000000000000'));
expect(codec.decode(hex('2a00000000000000'))).toBe(42n);
The getNodeCodec
function accepts the following options.
Name | Type | Default | Description |
---|---|---|---|
bytesEncoding |
BytesEncoding |
"base64" |
The default encoding to use when formatting plain bytes. |
In the table below, we illustrate the format of each codec based on the node from which it was created.
Note that we purposefully avoid types such as Uint8Array
, Set
or Map
in order to keep the format JSON compatible. For instance, plain bytes are not provided as Uint8Array
but as a tuple of type [BytesEncoding, string]
— e.g. ["base64", "HelloWorld++"]
— where the default bytes encoding is base64
which is configurable via the bytesEncoding
option.
Node | Example | Notes |
---|---|---|
AccountLinkNode |
- | Same as AccountNode
|
AccountNode |
- | Same as node.data
|
DefinedTypeLinkNode |
- | Same as DefinedTypeNode
|
DefinedTypeNode |
- | Same as node.type
|
InstructionArgumentLinkNode |
- | Same as InstructionArgumentNode
|
InstructionArgumentNode |
- | Same as node.type
|
InstructionLinkNode |
- | Same as InstructionNode
|
InstructionNode |
- | Same as a StructTypeNode containing all node.arguments
|
AmountTypeNode |
42 |
Same as NumberTypeNode
|
ArrayTypeNode |
[1, 2, 3] |
|
BooleanTypeNode |
true or false
|
|
BytesTypeNode |
["base16", "00ffaa"] |
Uses bytesEncoding option to decode |
DateTimeTypeNode |
42 |
Same as NumberTypeNode
|
EnumTypeNode |
2 or { __kind: "move", x: 12, y: 34 }
|
Uses number indices for scalar enums. Uses discriminated unions otherwise. |
FixedSizeTypeNode |
- | Same as node.type
|
HiddenPrefixTypeNode |
- | Same as node.type
|
HiddenSuffixTypeNode |
- | Same as node.type
|
MapTypeNode |
{ key1: "value1", key2: "value2" } |
Represent Maps as objects
|
NumberTypeNode |
42 |
This could be a bigint
|
OptionTypeNode |
{ __option: "Some", value: 42 } or { __option: "None" }
|
Uses value objects (instead of T | null ) to avoid loosing information on nested options. |
PostOffsetTypeNode |
- | Same as node.type
|
PreOffsetTypeNode |
- | Same as node.type
|
PublicKeyTypeNode |
"3QC7Pnv2KfwwdC44gPcmQWuZXmRSbUpmWMJnhenMC8CU" |
Uses base58 representations of public keys |
RemainderOptionTypeNode |
{ __option: "Some", value: 42 } or { __option: "None" }
|
Same as OptionTypeNode
|
SentinelTypeNode |
- | Same as node.type
|
SetTypeNode |
[1, 2, 3] |
Same as ArrayTypeNode
|
SizePrefixTypeNode |
- | Same as node.type
|
SolAmountTypeNode |
42 |
Same as NumberTypeNode
|
StringTypeNode |
"Hello World" |
Uses the encoding defined in the node — i.e. node.encoding
|
StructTypeNode |
{ name: "John", age: 42 } |
|
TupleTypeNode |
["John", 42] |
Uses arrays to create tuples |
ZeroableOptionTypeNode |
{ __option: "Some", value: 42 } or { __option: "None" }
|
Same as OptionTypeNode
|
This visitor is used by getNodeCodec
under the hood. It returns a Codec<unknown>
for the visited node.
return visit(someTypeNode, getNodeCodecVisitor(linkables));
This visitor is used by the getValueNodeVisitor
under the hood. It returns an unknown
value for the visited ValueNode
.
return visit(someValueNode, getValueNodeVisitor(linkables));