Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/swift-tomatoes-care.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@codama/nodes-from-anchor': patch
'@codama/renderers-js': patch
'@codama/errors': patch
---

Support constant program ID's for PDA instruction accounts in Anchor.
2 changes: 2 additions & 0 deletions packages/errors/src/codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING = 2100001;
export const CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING = 2100002;
export const CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING = 2100003;
export const CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED = 2100004;
export const CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED = 2100005;

// Renderers-related errors.
// Reserve error codes in the range [2800000-2800999].
Expand All @@ -83,6 +84,7 @@ export const CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE = 2800000;
export type CodamaErrorCode =
| typeof CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING
| typeof CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING
| typeof CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED
| typeof CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED
| typeof CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING
| typeof CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE
Expand Down
4 changes: 4 additions & 0 deletions packages/errors/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
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,
CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE,
Expand Down Expand Up @@ -68,6 +69,9 @@ export type CodamaErrorContext = DefaultUnspecifiedErrorContextToUndefined<{
[CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING]: {
name: string;
};
[CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED]: {
kind: string;
};
[CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED]: {
kind: string;
};
Expand Down
2 changes: 2 additions & 0 deletions packages/errors/src/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
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,
CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE,
Expand Down Expand Up @@ -48,6 +49,7 @@ export const CodamaErrorMessages: Readonly<{
}> = {
[CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING]: 'Account type [$name] is missing from the IDL types.',
[CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING]: 'Argument name [$name] is missing from the instruction definition.',
[CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED]: 'Program ID kind [$kind] is not implemented.',
[CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED]: 'Seed kind [$kind] is not implemented.',
[CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING]: 'Field type is missing for path [$path] in [$idlType].',
[CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE]: 'Unrecognized Anchor IDL type [$idlType].',
Expand Down
1 change: 1 addition & 0 deletions packages/nodes-from-anchor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"@codama/errors": "workspace:*",
"@codama/nodes": "workspace:*",
"@codama/visitors": "workspace:*",
"@solana/codecs": "2.0.0",
"@noble/hashes": "^1.7.0"
},
"license": "MIT",
Expand Down
21 changes: 20 additions & 1 deletion packages/nodes-from-anchor/src/v01/InstructionAccountNode.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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,
Expand All @@ -26,6 +27,7 @@ import {
resolveNestedTypeNode,
variablePdaSeedNode,
} from '@codama/nodes';
import { getBase58Codec } from '@solana/codecs';

import { hex } from '../utils';
import { IdlV01InstructionAccount, IdlV01InstructionAccountItem, IdlV01Seed } from './idl';
Expand Down Expand Up @@ -123,7 +125,24 @@ export function instructionAccountNodeFromAnchorV01(
<[PdaSeedNode[], PdaSeedValueNode[]]>[[], []],
);

defaultValue = pdaValueNode(pdaNode({ name, seeds }), lookups);
let programId: string | 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;
}
default: {
throw new CodamaError(CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED, { kind });
}
}
}

defaultValue = pdaValueNode(
pdaNode({ name, seeds, ...(programId !== undefined ? { programId } : {}) }),
lookups,
);
}
}

Expand Down
51 changes: 51 additions & 0 deletions packages/nodes-from-anchor/test/v01/InstructionAccountNode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,57 @@ test('it ignores PDA default values if at least one seed as a path of length gre
]);
});

test('it handles PDAs with a constant program id', () => {
const nodes = instructionAccountNodesFromAnchorV01(
[],
[],
[
{
name: 'program_data',
pda: {
program: {
kind: 'const',
value: [
2, 168, 246, 145, 78, 136, 161, 176, 226, 16, 21, 62, 247, 99, 174, 43, 0, 194, 185, 61, 22,
193, 36, 210, 192, 83, 122, 16, 4, 128, 0, 0,
],
},
seeds: [
{
kind: 'const',
value: [
166, 175, 151, 238, 166, 67, 87, 148, 114, 209, 13, 88, 186, 228, 206, 197, 182, 71,
129, 195, 206, 236, 229, 223, 184, 60, 97, 249, 63, 92, 203, 27,
],
},
],
},
},
],
);

expect(nodes).toEqual([
instructionAccountNode({
defaultValue: pdaValueNode(
pdaNode({
name: 'programData',
programId: 'BPFLoaderUpgradeab1e11111111111111111111111',
seeds: [
constantPdaSeedNodeFromBytes(
'base16',
'a6af97eea643579472d10d58bae4cec5b64781c3ceece5dfb83c61f93f5ccb1b',
),
],
}),
[],
),
isSigner: false,
isWritable: false,
name: 'programData',
}),
]);
});

test.skip('it handles account data paths of length 2', () => {
const nodes = instructionAccountNodesFromAnchorV01(
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,8 @@ export async function getCreateGuardInstructionAsync<
}
if (!accounts.mintTokenAccount.value) {
accounts.mintTokenAccount.value = await getProgramDerivedAddress({
programAddress,
programAddress:
'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL' as Address<'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'>,
seeds: [
getAddressEncoder().encode(
expectAddress(accounts.guardAuthority.value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ export async function getUpdateGuardInstructionAsync<
}
if (!accounts.tokenAccount.value) {
accounts.tokenAccount.value = await getProgramDerivedAddress({
programAddress,
programAddress:
'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL' as Address<'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'>,
seeds: [
getAddressEncoder().encode(
expectAddress(accounts.guardAuthority.value)
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading