|
|
@@ -1,54 +1,36 @@
|
|
|
import {
|
|
|
- CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING,
|
|
|
- CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING,
|
|
|
- CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED,
|
|
|
- CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED,
|
|
|
- CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING,
|
|
|
- CodamaError,
|
|
|
-} from '@codama/errors';
|
|
|
-import {
|
|
|
- AccountNode,
|
|
|
- accountValueNode,
|
|
|
- argumentValueNode,
|
|
|
- camelCase,
|
|
|
- constantPdaSeedNodeFromBytes,
|
|
|
+ AccountValueNode,
|
|
|
+ ArgumentValueNode,
|
|
|
InstructionAccountNode,
|
|
|
instructionAccountNode,
|
|
|
InstructionArgumentNode,
|
|
|
+ isNode,
|
|
|
pdaNode,
|
|
|
PdaSeedNode,
|
|
|
PdaSeedValueNode,
|
|
|
- pdaSeedValueNode,
|
|
|
PdaValueNode,
|
|
|
pdaValueNode,
|
|
|
- publicKeyTypeNode,
|
|
|
PublicKeyValueNode,
|
|
|
publicKeyValueNode,
|
|
|
- resolveNestedTypeNode,
|
|
|
- variablePdaSeedNode,
|
|
|
} from '@codama/nodes';
|
|
|
-import { getBase58Codec } from '@solana/codecs';
|
|
|
|
|
|
-import { hex } from '../utils';
|
|
|
import { IdlV01InstructionAccount, IdlV01InstructionAccountItem, IdlV01Seed } from './idl';
|
|
|
+import { pdaSeedNodeFromAnchorV01 } from './PdaSeedNode';
|
|
|
|
|
|
export function instructionAccountNodesFromAnchorV01(
|
|
|
- allAccounts: AccountNode[],
|
|
|
- instructionArguments: InstructionArgumentNode[],
|
|
|
idl: IdlV01InstructionAccountItem[],
|
|
|
+ instructionArguments: InstructionArgumentNode[],
|
|
|
): InstructionAccountNode[] {
|
|
|
return idl.flatMap(account =>
|
|
|
'accounts' in account
|
|
|
- ? instructionAccountNodesFromAnchorV01(allAccounts, instructionArguments, account.accounts)
|
|
|
- : [instructionAccountNodeFromAnchorV01(allAccounts, instructionArguments, account, idl)],
|
|
|
+ ? instructionAccountNodesFromAnchorV01(account.accounts, instructionArguments)
|
|
|
+ : [instructionAccountNodeFromAnchorV01(account, instructionArguments)],
|
|
|
);
|
|
|
}
|
|
|
|
|
|
export function instructionAccountNodeFromAnchorV01(
|
|
|
- allAccounts: AccountNode[],
|
|
|
- instructionArguments: InstructionArgumentNode[],
|
|
|
idl: IdlV01InstructionAccount,
|
|
|
- parentIdl: IdlV01InstructionAccountItem[],
|
|
|
+ instructionArguments: InstructionArgumentNode[],
|
|
|
): InstructionAccountNode {
|
|
|
const isOptional = idl.optional ?? false;
|
|
|
const docs = idl.docs ?? [];
|
|
|
@@ -64,94 +46,33 @@ export function instructionAccountNodeFromAnchorV01(
|
|
|
// Currently, we gracefully ignore PDA default values if we encounter seeds with nested paths.
|
|
|
const seedsWithNestedPaths = idl.pda.seeds.some(seed => 'path' in seed && seed.path.includes('.'));
|
|
|
if (!seedsWithNestedPaths) {
|
|
|
- const [seeds, lookups] = idl.pda.seeds.reduce(
|
|
|
+ const [seedDefinitions, seedValues] = idl.pda.seeds.reduce(
|
|
|
([seeds, lookups], seed: IdlV01Seed) => {
|
|
|
- const kind = seed.kind;
|
|
|
-
|
|
|
- switch (kind) {
|
|
|
- case 'const':
|
|
|
- return [[...seeds, constantPdaSeedNodeFromBytes('base16', hex(seed.value))], lookups];
|
|
|
- case 'account': {
|
|
|
- const path = seed.path.split('.');
|
|
|
- if (path.length === 1) {
|
|
|
- return [
|
|
|
- [...seeds, variablePdaSeedNode(seed.path, publicKeyTypeNode())],
|
|
|
- [...lookups, pdaSeedValueNode(seed.path, accountValueNode(seed.path))],
|
|
|
- ];
|
|
|
- } else if (path.length === 2) {
|
|
|
- // TODO: Handle nested account paths.
|
|
|
- // Currently, this scenario is never reached.
|
|
|
-
|
|
|
- const accountName = camelCase(seed.account ?? '');
|
|
|
- const accountNode = allAccounts.find(({ name }) => name === accountName);
|
|
|
- if (!accountNode) {
|
|
|
- throw new CodamaError(CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING, { kind });
|
|
|
- }
|
|
|
-
|
|
|
- const fieldName = camelCase(path[1]);
|
|
|
- const accountFields = resolveNestedTypeNode(accountNode.data).fields;
|
|
|
- const fieldNode = accountFields.find(({ name }) => name === fieldName);
|
|
|
- if (!fieldNode) {
|
|
|
- throw new CodamaError(CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING, {
|
|
|
- idlType: seed.account,
|
|
|
- path: seed.path,
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- const seedName = camelCase(seed.path);
|
|
|
- return [[...seeds, variablePdaSeedNode(seedName, fieldNode.type)], []];
|
|
|
- } else {
|
|
|
- throw new CodamaError(CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING, {
|
|
|
- idlType: seed,
|
|
|
- path: seed.path,
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
- case 'arg': {
|
|
|
- const argumentName = camelCase(seed.path);
|
|
|
- const argumentNode = instructionArguments.find(({ name }) => name === argumentName);
|
|
|
- if (!argumentNode) {
|
|
|
- throw new CodamaError(CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING, { name: seed.path });
|
|
|
- }
|
|
|
-
|
|
|
- return [
|
|
|
- [...seeds, variablePdaSeedNode(seed.path, argumentNode.type)],
|
|
|
- [...lookups, pdaSeedValueNode(seed.path, argumentValueNode(seed.path))],
|
|
|
- ];
|
|
|
- }
|
|
|
- default:
|
|
|
- throw new CodamaError(CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED, { kind });
|
|
|
- }
|
|
|
+ const { definition, value } = pdaSeedNodeFromAnchorV01(seed, instructionArguments);
|
|
|
+ return [[...seeds, definition], value ? [...lookups, value] : lookups];
|
|
|
},
|
|
|
<[PdaSeedNode[], PdaSeedValueNode[]]>[[], []],
|
|
|
);
|
|
|
|
|
|
let programId: string | undefined;
|
|
|
+ let programIdValue: AccountValueNode | ArgumentValueNode | undefined;
|
|
|
if (idl.pda.program !== undefined) {
|
|
|
- const kind = idl.pda.program.kind;
|
|
|
- switch (kind) {
|
|
|
- case 'const': {
|
|
|
- programId = getBase58Codec().decode(new Uint8Array(idl.pda.program.value));
|
|
|
- break;
|
|
|
- }
|
|
|
- case 'account': {
|
|
|
- const programPath = idl.pda.program.path;
|
|
|
- const programNode = parentIdl.find(acc => acc.name == programPath);
|
|
|
- if (!(programNode && 'address' in programNode)) {
|
|
|
- throw new CodamaError(CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED, { kind });
|
|
|
- }
|
|
|
- programId = programNode.address;
|
|
|
- break;
|
|
|
- }
|
|
|
- default: {
|
|
|
- throw new CodamaError(CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED, { kind });
|
|
|
- }
|
|
|
+ const { definition, value } = pdaSeedNodeFromAnchorV01(idl.pda.program, instructionArguments);
|
|
|
+ if (
|
|
|
+ isNode(definition, 'constantPdaSeedNode') &&
|
|
|
+ isNode(definition.value, 'bytesValueNode') &&
|
|
|
+ definition.value.encoding === 'base58'
|
|
|
+ ) {
|
|
|
+ programId = definition.value.data;
|
|
|
+ } else if (value && isNode(value.value, ['accountValueNode', 'argumentValueNode'])) {
|
|
|
+ programIdValue = value.value;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
defaultValue = pdaValueNode(
|
|
|
- pdaNode({ name, seeds, ...(programId !== undefined ? { programId } : {}) }),
|
|
|
- lookups,
|
|
|
+ pdaNode({ name, programId, seeds: seedDefinitions }),
|
|
|
+ seedValues,
|
|
|
+ programIdValue,
|
|
|
);
|
|
|
}
|
|
|
}
|