From 6d02b0ef8787967d313a6ae15508b62055d593f5 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Wed, 3 Jan 2024 21:50:27 +0000 Subject: [PATCH] Add discriminator nodes (#136) * Add discriminator nodes * Add byteDiscriminatorNodeFromBase58 helper * Update @solana/codecs-strings to the latest version * Fix typo * Add DiscriminatorNodes to AccountNode * Rename AnchorDiscriminator helper file * Add DiscriminatorNodes to InstructionNode * Update merge and identity visitors * Add changeset --- .changeset/gold-beans-listen.md | 5 +++ package.json | 1 + pnpm-lock.yaml | 27 +++++++++++++ src/nodes/AccountNode.ts | 18 ++++----- src/nodes/InstructionNode.ts | 15 +++++-- src/nodes/Node.ts | 2 + .../ByteDiscriminatorNode.ts | 26 ++++++++++++ .../discriminatorNodes/DiscriminatorNode.ts | 25 ++++++++++++ .../FieldDiscriminatorNode.ts | 16 ++++++++ .../SizeDiscriminatorNode.ts | 10 +++++ src/nodes/discriminatorNodes/index.ts | 4 ++ src/nodes/index.ts | 1 + src/renderers/js/getRenderMapVisitor.ts | 23 ++++++----- src/renderers/js/templates/accountsPage.njk | 6 +-- src/shared/AccountDiscriminator.ts | 14 ------- ...nchorDiscriminator.ts => anchorHelpers.ts} | 8 ++-- src/shared/index.ts | 3 +- src/visitors/identityVisitor.ts | 40 ++++++++++++++++--- src/visitors/mergeVisitor.ts | 5 ++- ...setAccountDiscriminatorFromFieldVisitor.ts | 11 +++-- .../setAnchorDiscriminatorsVisitor.ts | 7 +++- ...ransformDefinedTypesIntoAccountsVisitor.ts | 2 +- 22 files changed, 207 insertions(+), 62 deletions(-) create mode 100644 .changeset/gold-beans-listen.md create mode 100644 src/nodes/discriminatorNodes/ByteDiscriminatorNode.ts create mode 100644 src/nodes/discriminatorNodes/DiscriminatorNode.ts create mode 100644 src/nodes/discriminatorNodes/FieldDiscriminatorNode.ts create mode 100644 src/nodes/discriminatorNodes/SizeDiscriminatorNode.ts create mode 100644 src/nodes/discriminatorNodes/index.ts delete mode 100644 src/shared/AccountDiscriminator.ts rename src/shared/{AnchorDiscriminator.ts => anchorHelpers.ts} (84%) diff --git a/.changeset/gold-beans-listen.md b/.changeset/gold-beans-listen.md new file mode 100644 index 000000000..a8e773423 --- /dev/null +++ b/.changeset/gold-beans-listen.md @@ -0,0 +1,5 @@ +--- +'@metaplex-foundation/kinobi': minor +--- + +Add discriminator nodes diff --git a/package.json b/package.json index 323b39938..1805fdf5a 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ }, "dependencies": { "@noble/hashes": "^1.1.5", + "@solana/codecs-strings": "2.0.0-experimental.a157265", "chalk": "^4.0.0", "json-stable-stringify": "^1.1.0", "nunjucks": "^3.2.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 46c94f951..b78354ffc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,9 @@ importers: '@noble/hashes': specifier: ^1.1.5 version: 1.1.5 + '@solana/codecs-strings': + specifier: 2.0.0-experimental.a157265 + version: 2.0.0-experimental.a157265(fastestsmallesttextencoderdecoder@1.0.22) chalk: specifier: ^4.0.0 version: 4.1.2 @@ -2062,6 +2065,26 @@ packages: engines: {node: '>=10'} dev: true + /@solana/codecs-core@2.0.0-experimental.a157265: + resolution: {integrity: sha512-78SjZiLWWjAn5sVL92T5W+4LXYG01Vu28tVbtiCWi4QEX21794bW6lMcXbPmbivFPbD8Dje+EHAYADfxYj6RTA==} + dev: false + + /@solana/codecs-numbers@2.0.0-experimental.a157265: + resolution: {integrity: sha512-Bkp7Y1KyhMsu8tHKxwHDXCnYxEawT0P4kEsIO1Fzs54pxOS1jtwJHo7e4FE8Kv8ZSajUQAnbmQqj5GaIU08h9A==} + dependencies: + '@solana/codecs-core': 2.0.0-experimental.a157265 + dev: false + + /@solana/codecs-strings@2.0.0-experimental.a157265(fastestsmallesttextencoderdecoder@1.0.22): + resolution: {integrity: sha512-1AypxqrFipI053/EOHZnDDcfKBduLjJdrpkbcqrgWJyciv/7+fMQjkgjbG+C8Vcqx5G8weUesXCcvAhqbdRwMw==} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + dependencies: + '@solana/codecs-core': 2.0.0-experimental.a157265 + '@solana/codecs-numbers': 2.0.0-experimental.a157265 + fastestsmallesttextencoderdecoder: 1.0.22 + dev: false + /@szmarczak/http-timer@4.0.6: resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} @@ -4574,6 +4597,10 @@ packages: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true + /fastestsmallesttextencoderdecoder@1.0.22: + resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} + dev: false + /fastq@1.14.0: resolution: {integrity: sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==} dependencies: diff --git a/src/nodes/AccountNode.ts b/src/nodes/AccountNode.ts index e14a60339..8f844f9c4 100644 --- a/src/nodes/AccountNode.ts +++ b/src/nodes/AccountNode.ts @@ -1,11 +1,7 @@ import type { IdlAccount } from '../idl'; -import { - AccountDiscriminator, - InvalidKinobiTreeError, - MainCaseString, - mainCase, -} from '../shared'; +import { InvalidKinobiTreeError, MainCaseString, mainCase } from '../shared'; import { assertIsNode } from './Node'; +import { DiscriminatorNode } from './discriminatorNodes'; import { PdaLinkNode, pdaLinkNode } from './linkNodes'; import { StructTypeNode, structTypeNode } from './typeNodes'; import { createTypeNodeFromIdl } from './typeNodes/TypeNode'; @@ -16,9 +12,7 @@ export type AccountNode = { // Children. readonly data: StructTypeNode; readonly pda?: PdaLinkNode; - - // Children to-be. - readonly discriminator?: AccountDiscriminator; + readonly discriminators?: DiscriminatorNode[]; // Data. readonly name: MainCaseString; @@ -37,13 +31,17 @@ export function accountNode(input: AccountNodeInput): AccountNode { } return { kind: 'accountNode', + + // Children. data: input.data ?? structTypeNode([]), pda: input.pda, + discriminators: input.discriminators, + + // Data. name: mainCase(input.name), idlName: input.idlName ?? input.name, docs: input.docs ?? [], size: input.size, - discriminator: input.discriminator, }; } diff --git a/src/nodes/InstructionNode.ts b/src/nodes/InstructionNode.ts index eb6fe372e..702ab253f 100644 --- a/src/nodes/InstructionNode.ts +++ b/src/nodes/InstructionNode.ts @@ -14,6 +14,7 @@ import { InstructionRemainingAccountsNode } from './InstructionRemainingAccounts import { isNode } from './Node'; import { ProgramNode } from './ProgramNode'; import { RootNode } from './RootNode'; +import { DiscriminatorNode } from './discriminatorNodes'; import { createTypeNodeFromIdl } from './typeNodes/TypeNode'; import { numberValueNode } from './valueNodes'; @@ -24,9 +25,10 @@ export type InstructionNode = { readonly accounts: InstructionAccountNode[]; readonly arguments: InstructionArgumentNode[]; readonly extraArguments?: InstructionArgumentNode[]; - readonly subInstructions?: InstructionNode[]; readonly remainingAccounts?: InstructionRemainingAccountsNode[]; readonly byteDeltas?: InstructionByteDeltaNode[]; + readonly discriminators?: DiscriminatorNode[]; + readonly subInstructions?: InstructionNode[]; // Data. readonly name: MainCaseString; @@ -49,15 +51,20 @@ export function instructionNode(input: InstructionNodeInput): InstructionNode { const name = mainCase(input.name); return { kind: 'instructionNode', - name, + + // Children. accounts: input.accounts ?? [], arguments: input.arguments ?? [], extraArguments: input.extraArguments, + remainingAccounts: input.remainingAccounts, + byteDeltas: input.byteDeltas, + discriminators: input.discriminators, subInstructions: input.subInstructions, + + // Data. + name, idlName: input.idlName ?? input.name, docs: input.docs ?? [], - remainingAccounts: input.remainingAccounts, - byteDeltas: input.byteDeltas, optionalAccountStrategy: input.optionalAccountStrategy ?? 'programId', }; } diff --git a/src/nodes/Node.ts b/src/nodes/Node.ts index 633fd57ec..88daa1a89 100644 --- a/src/nodes/Node.ts +++ b/src/nodes/Node.ts @@ -11,6 +11,7 @@ import type { PdaNode } from './PdaNode'; import type { ProgramNode } from './ProgramNode'; import type { RootNode } from './RootNode'; import { REGISTERED_CONTEXTUAL_VALUE_NODES } from './contextualValueNodes/ContextualValueNode'; +import { REGISTERED_DISCRIMINATOR_NODES } from './discriminatorNodes/DiscriminatorNode'; import { REGISTERED_LINK_NODES } from './linkNodes/LinkNode'; import { REGISTERED_PDA_SEED_NODES } from './pdaSeedNodes/PdaSeedNode'; import { REGISTERED_SIZE_NODES } from './sizeNodes/SizeNode'; @@ -34,6 +35,7 @@ const REGISTERED_NODES = { // Groups. ...REGISTERED_CONTEXTUAL_VALUE_NODES, + ...REGISTERED_DISCRIMINATOR_NODES, ...REGISTERED_LINK_NODES, ...REGISTERED_PDA_SEED_NODES, ...REGISTERED_SIZE_NODES, diff --git a/src/nodes/discriminatorNodes/ByteDiscriminatorNode.ts b/src/nodes/discriminatorNodes/ByteDiscriminatorNode.ts new file mode 100644 index 000000000..195e9a3ef --- /dev/null +++ b/src/nodes/discriminatorNodes/ByteDiscriminatorNode.ts @@ -0,0 +1,26 @@ +import { getBase58Encoder } from '@solana/codecs-strings'; + +export type ByteDiscriminatorNode = { + readonly kind: 'byteDiscriminatorNode'; + + // Data. + readonly bytes: number[]; + readonly offset: number; +}; + +export function byteDiscriminatorNode( + bytes: number[], + offset: number = 0 +): ByteDiscriminatorNode { + return { kind: 'byteDiscriminatorNode', bytes, offset }; +} + +export function byteDiscriminatorNodeFromBase58( + base58Bytes: string, + offset: number = 0 +): ByteDiscriminatorNode { + return byteDiscriminatorNode( + [...getBase58Encoder().encode(base58Bytes)], + offset + ); +} diff --git a/src/nodes/discriminatorNodes/DiscriminatorNode.ts b/src/nodes/discriminatorNodes/DiscriminatorNode.ts new file mode 100644 index 000000000..3629e5824 --- /dev/null +++ b/src/nodes/discriminatorNodes/DiscriminatorNode.ts @@ -0,0 +1,25 @@ +import { getNodeKinds } from '../../shared/utils'; +import type { ByteDiscriminatorNode } from './ByteDiscriminatorNode'; +import type { FieldDiscriminatorNode } from './FieldDiscriminatorNode'; +import type { SizeDiscriminatorNode } from './SizeDiscriminatorNode'; + +// Discriminator Node Registration. + +export const REGISTERED_DISCRIMINATOR_NODES = { + byteDiscriminatorNode: {} as ByteDiscriminatorNode, + fieldDiscriminatorNode: {} as FieldDiscriminatorNode, + sizeDiscriminatorNode: {} as SizeDiscriminatorNode, +}; + +export const REGISTERED_DISCRIMINATOR_NODE_KINDS = getNodeKinds( + REGISTERED_DISCRIMINATOR_NODES +); +export type RegisteredDiscriminatorNodeKind = + typeof REGISTERED_DISCRIMINATOR_NODE_KINDS[number]; +export type RegisteredDiscriminatorNode = + typeof REGISTERED_DISCRIMINATOR_NODES[RegisteredDiscriminatorNodeKind]; + +// Discriminator Node Helpers. + +export type DiscriminatorNode = RegisteredDiscriminatorNode; +export const DISCRIMINATOR_NODES = REGISTERED_DISCRIMINATOR_NODE_KINDS; diff --git a/src/nodes/discriminatorNodes/FieldDiscriminatorNode.ts b/src/nodes/discriminatorNodes/FieldDiscriminatorNode.ts new file mode 100644 index 000000000..d40f01910 --- /dev/null +++ b/src/nodes/discriminatorNodes/FieldDiscriminatorNode.ts @@ -0,0 +1,16 @@ +import { MainCaseString, mainCase } from '../../shared'; + +export type FieldDiscriminatorNode = { + readonly kind: 'fieldDiscriminatorNode'; + + // Data. + readonly name: MainCaseString; + readonly offset: number; +}; + +export function fieldDiscriminatorNode( + name: string, + offset: number = 0 +): FieldDiscriminatorNode { + return { kind: 'fieldDiscriminatorNode', name: mainCase(name), offset }; +} diff --git a/src/nodes/discriminatorNodes/SizeDiscriminatorNode.ts b/src/nodes/discriminatorNodes/SizeDiscriminatorNode.ts new file mode 100644 index 000000000..430b4e781 --- /dev/null +++ b/src/nodes/discriminatorNodes/SizeDiscriminatorNode.ts @@ -0,0 +1,10 @@ +export type SizeDiscriminatorNode = { + readonly kind: 'sizeDiscriminatorNode'; + + // Data. + readonly size: number; +}; + +export function sizeDiscriminatorNode(size: number): SizeDiscriminatorNode { + return { kind: 'sizeDiscriminatorNode', size }; +} diff --git a/src/nodes/discriminatorNodes/index.ts b/src/nodes/discriminatorNodes/index.ts new file mode 100644 index 000000000..33448ee77 --- /dev/null +++ b/src/nodes/discriminatorNodes/index.ts @@ -0,0 +1,4 @@ +export * from './ByteDiscriminatorNode'; +export * from './DiscriminatorNode'; +export * from './FieldDiscriminatorNode'; +export * from './SizeDiscriminatorNode'; diff --git a/src/nodes/index.ts b/src/nodes/index.ts index 2ae6668ac..391c3e5ad 100644 --- a/src/nodes/index.ts +++ b/src/nodes/index.ts @@ -12,6 +12,7 @@ export * from './ProgramNode'; export * from './RootNode'; export * from './contextualValueNodes'; +export * from './discriminatorNodes'; export * from './linkNodes'; export * from './pdaSeedNodes'; export * from './sizeNodes'; diff --git a/src/renderers/js/getRenderMapVisitor.ts b/src/renderers/js/getRenderMapVisitor.ts index c44e00b48..cbb40c1f5 100644 --- a/src/renderers/js/getRenderMapVisitor.ts +++ b/src/renderers/js/getRenderMapVisitor.ts @@ -4,6 +4,7 @@ import { Options as PrettierOptions, } from 'prettier'; import { + FieldDiscriminatorNode, getAllAccounts, getAllDefinedTypes, getAllInstructionsWithSubs, @@ -12,6 +13,7 @@ import { isNode, isNodeFilter, ProgramNode, + SizeDiscriminatorNode, structTypeNodeFromInstructionArgumentNodes, VALUE_NODES, } from '../../nodes'; @@ -315,12 +317,15 @@ export function getRenderMapVisitor( .addAlias('umi', 'publicKey', 'toPublicKey'); // Discriminator. - const { discriminator } = node; + const discriminator = + (node.discriminators ?? []).find( + (d) => !isNode(d, 'byteDiscriminatorNode') + ) ?? null; let resolvedDiscriminator: - | { kind: 'size'; value: string } - | { kind: 'field'; name: string; value: string } + | SizeDiscriminatorNode + | (FieldDiscriminatorNode & { value: string }) | null = null; - if (discriminator?.kind === 'field') { + if (isNode(discriminator, 'fieldDiscriminatorNode')) { const discriminatorField = node.data.fields.find( (f) => f.name === discriminator.name ); @@ -330,16 +335,12 @@ export function getRenderMapVisitor( if (discriminatorValue) { imports.mergeWith(discriminatorValue.imports); resolvedDiscriminator = { - kind: 'field', - name: discriminator.name, + ...discriminator, value: discriminatorValue.render, }; } - } else if (discriminator?.kind === 'size') { - resolvedDiscriminator = - node.size !== undefined - ? { kind: 'size', value: `${node.size}` } - : null; + } else if (isNode(discriminator, 'sizeDiscriminatorNode')) { + resolvedDiscriminator = discriminator; } // GPA Fields. diff --git a/src/renderers/js/templates/accountsPage.njk b/src/renderers/js/templates/accountsPage.njk index 628975023..90765f98d 100644 --- a/src/renderers/js/templates/accountsPage.njk +++ b/src/renderers/js/templates/accountsPage.njk @@ -69,10 +69,10 @@ export function get{{ account.name | pascalCase }}GpaBuilder(context: Pick({{ gpaFields.argument }}) .deserializeUsing<{{ account.name | pascalCase }}>((account) => deserialize{{ account.name | pascalCase }}(account)) - {%- if discriminator.kind === 'field' %} + {%- if discriminator.kind === 'fieldDiscriminatorNode' %} .whereField('{{ discriminator.name }}', {{ discriminator.value }}) - {% elif discriminator.kind === 'size' %} - .whereSize({{ discriminator.value }}) + {% elif discriminator.kind === 'sizeDiscriminatorNode' %} + .whereSize({{ discriminator.size }}) {% endif -%} ; } diff --git a/src/shared/AccountDiscriminator.ts b/src/shared/AccountDiscriminator.ts deleted file mode 100644 index e9f46c5a3..000000000 --- a/src/shared/AccountDiscriminator.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MainCaseString, mainCase } from './utils'; - -export type AccountDiscriminator = - | { kind: 'field'; name: MainCaseString; offset: number } - | { kind: 'size' }; - -export const fieldAccountDiscriminator = ( - name: string, - offset: number = 0 -): AccountDiscriminator => ({ kind: 'field', name: mainCase(name), offset }); - -export const sizeAccountDiscriminator = (): AccountDiscriminator => ({ - kind: 'size', -}); diff --git a/src/shared/AnchorDiscriminator.ts b/src/shared/anchorHelpers.ts similarity index 84% rename from src/shared/AnchorDiscriminator.ts rename to src/shared/anchorHelpers.ts index 8023a9b32..5146956fe 100644 --- a/src/shared/AnchorDiscriminator.ts +++ b/src/shared/anchorHelpers.ts @@ -1,19 +1,17 @@ import { sha256 } from '@noble/hashes/sha256'; -import { pascalCase, snakeCase } from './utils'; import { ArrayValueNode, arrayValueNode, numberValueNode } from '../nodes'; - -export type AnchorDiscriminator = ArrayValueNode; +import { pascalCase, snakeCase } from './utils'; export const getAnchorInstructionDiscriminator = ( idlName: string -): AnchorDiscriminator => { +): ArrayValueNode => { const hash = sha256(`global:${snakeCase(idlName)}`).slice(0, 8); return arrayValueNode([...hash].map((byte) => numberValueNode(byte))); }; export const getAnchorAccountDiscriminator = ( idlName: string -): AnchorDiscriminator => { +): ArrayValueNode => { const hash = sha256(`account:${pascalCase(idlName)}`).slice(0, 8); return arrayValueNode([...hash].map((byte) => numberValueNode(byte))); }; diff --git a/src/shared/index.ts b/src/shared/index.ts index d04d49e7b..5232a2a35 100644 --- a/src/shared/index.ts +++ b/src/shared/index.ts @@ -1,5 +1,4 @@ -export * from './AccountDiscriminator'; -export * from './AnchorDiscriminator'; +export * from './anchorHelpers'; export * from './GpaField'; export * from './ImportFrom'; export * from './LinkableDictionary'; diff --git a/src/visitors/identityVisitor.ts b/src/visitors/identityVisitor.ts index 33e653cfd..be95698b2 100644 --- a/src/visitors/identityVisitor.ts +++ b/src/visitors/identityVisitor.ts @@ -1,5 +1,6 @@ import { CONDITIONAL_VALUE_BRANCH_NODES, + DISCRIMINATOR_NODES, ENUM_VARIANT_TYPE_NODES, INSTRUCTION_INPUT_VALUE_NODE, Node, @@ -26,6 +27,7 @@ import { enumValueNode, instructionAccountNode, instructionArgumentNode, + instructionByteDeltaNode, instructionNode, instructionRemainingAccountsNode, mapEntryValueNode, @@ -141,11 +143,6 @@ export function identityVisitor( removeNullAndAssertIsNodeFilter('instructionArgumentNode') ) : undefined, - subInstructions: node.subInstructions - ? node.subInstructions - .map(visit(this)) - .filter(removeNullAndAssertIsNodeFilter('instructionNode')) - : undefined, remainingAccounts: node.remainingAccounts ? node.remainingAccounts .map(visit(this)) @@ -155,6 +152,23 @@ export function identityVisitor( ) ) : undefined, + byteDeltas: node.byteDeltas + ? node.byteDeltas + .map(visit(this)) + .filter( + removeNullAndAssertIsNodeFilter('instructionByteDeltaNode') + ) + : undefined, + discriminators: node.discriminators + ? node.discriminators + .map(visit(this)) + .filter(removeNullAndAssertIsNodeFilter(DISCRIMINATOR_NODES)) + : undefined, + subInstructions: node.subInstructions + ? node.subInstructions + .map(visit(this)) + .filter(removeNullAndAssertIsNodeFilter('instructionNode')) + : undefined, }); }; } @@ -194,6 +208,22 @@ export function identityVisitor( }; } + if (castedNodeKeys.includes('instructionByteDeltaNode')) { + visitor.visitInstructionByteDelta = function visitInstructionByteDelta( + node + ) { + const value = visit(this)(node.value); + if (value === null) return null; + assertIsNode(value, [ + 'numberValueNode', + 'accountLinkNode', + 'argumentValueNode', + 'resolverValueNode', + ]); + return instructionByteDeltaNode(value, { ...node }); + }; + } + if (castedNodeKeys.includes('definedTypeNode')) { visitor.visitDefinedType = function visitDefinedType(node) { const type = visit(this)(node.type); diff --git a/src/visitors/mergeVisitor.ts b/src/visitors/mergeVisitor.ts index d2094e96e..d46830ed0 100644 --- a/src/visitors/mergeVisitor.ts +++ b/src/visitors/mergeVisitor.ts @@ -43,6 +43,7 @@ export function mergeVisitor( return merge(node, [ ...visit(this)(node.data), ...(node.pda ? visit(this)(node.pda) : []), + ...(node.discriminators ?? []).flatMap(visit(this)), ]); }; } @@ -53,8 +54,10 @@ export function mergeVisitor( ...node.accounts.flatMap(visit(this)), ...node.arguments.flatMap(visit(this)), ...(node.extraArguments ?? []).flatMap(visit(this)), - ...(node.subInstructions ?? []).flatMap(visit(this)), ...(node.remainingAccounts ?? []).flatMap(visit(this)), + ...(node.byteDeltas ?? []).flatMap(visit(this)), + ...(node.discriminators ?? []).flatMap(visit(this)), + ...(node.subInstructions ?? []).flatMap(visit(this)), ]); }; } diff --git a/src/visitors/setAccountDiscriminatorFromFieldVisitor.ts b/src/visitors/setAccountDiscriminatorFromFieldVisitor.ts index 0a250719f..9a28814eb 100644 --- a/src/visitors/setAccountDiscriminatorFromFieldVisitor.ts +++ b/src/visitors/setAccountDiscriminatorFromFieldVisitor.ts @@ -1,8 +1,8 @@ -import { fieldAccountDiscriminator } from '../shared'; import { ValueNode, accountNode, assertIsNode, + fieldDiscriminatorNode, structFieldTypeNode, structTypeNode, } from '../nodes'; @@ -12,13 +12,13 @@ import { } from './bottomUpTransformerVisitor'; export function setAccountDiscriminatorFromFieldVisitor( - map: Record + map: Record ) { return bottomUpTransformerVisitor( Object.entries(map).map( ([ selectorStack, - { field, value }, + { field, value, offset }, ]): BottomUpNodeTransformerWithSelector => { const stack = selectorStack.split('.'); const name = stack.pop(); @@ -39,7 +39,10 @@ export function setAccountDiscriminatorFromFieldVisitor( const fieldNode = node.data.fields[fieldIndex]; return accountNode({ ...node, - discriminator: fieldAccountDiscriminator(field), + discriminators: [ + fieldDiscriminatorNode(field, offset), + ...(node.discriminators ?? []), + ], data: structTypeNode([ ...node.data.fields.slice(0, fieldIndex), structFieldTypeNode({ diff --git a/src/visitors/setAnchorDiscriminatorsVisitor.ts b/src/visitors/setAnchorDiscriminatorsVisitor.ts index b36cc435f..f32f13acf 100644 --- a/src/visitors/setAnchorDiscriminatorsVisitor.ts +++ b/src/visitors/setAnchorDiscriminatorsVisitor.ts @@ -2,6 +2,7 @@ import { ProgramNode, accountNode, arrayTypeNode, + fieldDiscriminatorNode, fixedSizeNode, instructionArgumentNode, instructionNode, @@ -10,7 +11,6 @@ import { structTypeNode, } from '../nodes'; import { - fieldAccountDiscriminator, getAnchorAccountDiscriminator, getAnchorInstructionDiscriminator, pipe, @@ -49,7 +49,10 @@ export function setAnchorDiscriminatorsVisitor() { return accountNode({ ...node, - discriminator: fieldAccountDiscriminator('discriminator'), + discriminators: [ + fieldDiscriminatorNode('discriminator'), + ...(node.discriminators ?? []), + ], data: structTypeNode([discriminatorArgument, ...node.data.fields]), }); }, diff --git a/src/visitors/transformDefinedTypesIntoAccountsVisitor.ts b/src/visitors/transformDefinedTypesIntoAccountsVisitor.ts index 90cc3a046..275bcb5b7 100644 --- a/src/visitors/transformDefinedTypesIntoAccountsVisitor.ts +++ b/src/visitors/transformDefinedTypesIntoAccountsVisitor.ts @@ -23,7 +23,7 @@ export function transformDefinedTypesIntoAccountsVisitor( ...node, data: node.type, size: undefined, - discriminator: undefined, + discriminators: [], }); });