Skip to content

Commit 07825de

Browse files
authored
Unwrap generics from Anchor (#913)
1 parent 8050a63 commit 07825de

36 files changed

+560
-138
lines changed

.changeset/four-bears-shave.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@codama/nodes-from-anchor': patch
3+
'@codama/errors': patch
4+
---
5+
6+
Unwrap generic types and constants from Anchor IDLs when converting them to Codama IDLs.

packages/errors/src/codes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export const CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING = 2100002;
6161
export const CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING = 2100003;
6262
export const CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED = 2100004;
6363
export const CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED = 2100005;
64+
export const CODAMA_ERROR__ANCHOR__GENERIC_TYPE_MISSING = 2100006;
6465

6566
// Renderers-related errors.
6667
// Reserve error codes in the range [2800000-2800999].
@@ -84,6 +85,7 @@ export const CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE = 2800000;
8485
export type CodamaErrorCode =
8586
| typeof CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING
8687
| typeof CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING
88+
| typeof CODAMA_ERROR__ANCHOR__GENERIC_TYPE_MISSING
8789
| typeof CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED
8890
| typeof CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED
8991
| typeof CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING

packages/errors/src/context.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
import {
2323
CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING,
2424
CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING,
25+
CODAMA_ERROR__ANCHOR__GENERIC_TYPE_MISSING,
2526
CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED,
2627
CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED,
2728
CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING,
@@ -69,6 +70,9 @@ export type CodamaErrorContext = DefaultUnspecifiedErrorContextToUndefined<{
6970
[CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING]: {
7071
name: string;
7172
};
73+
[CODAMA_ERROR__ANCHOR__GENERIC_TYPE_MISSING]: {
74+
name: string;
75+
};
7276
[CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED]: {
7377
kind: string;
7478
};

packages/errors/src/messages.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import {
77
CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING,
88
CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING,
9+
CODAMA_ERROR__ANCHOR__GENERIC_TYPE_MISSING,
910
CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED,
1011
CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED,
1112
CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING,
@@ -49,6 +50,7 @@ export const CodamaErrorMessages: Readonly<{
4950
}> = {
5051
[CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING]: 'Account type [$name] is missing from the IDL types.',
5152
[CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING]: 'Argument name [$name] is missing from the instruction definition.',
53+
[CODAMA_ERROR__ANCHOR__GENERIC_TYPE_MISSING]: 'Generic type [$name] is missing from the IDL types.',
5254
[CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED]: 'Program ID kind [$kind] is not implemented.',
5355
[CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED]: 'Seed kind [$kind] is not implemented.',
5456
[CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING]: 'Field type is missing for path [$path] in [$idlType].',

packages/nodes-from-anchor/src/discriminators.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { BytesValueNode, bytesValueNode, pascalCase, snakeCase } from '@codama/nodes';
2-
import { sha256 } from '@noble/hashes/sha256';
2+
import { sha256 } from '@noble/hashes/sha2';
33

44
import { hex } from './utils';
55

packages/nodes-from-anchor/src/v01/AccountNode.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,23 @@ import {
1212
} from '@codama/nodes';
1313

1414
import { getAnchorDiscriminatorV01 } from './../discriminators';
15-
import { IdlV01Account, IdlV01TypeDef } from './idl';
15+
import type { IdlV01Account, IdlV01TypeDef } from './idl';
1616
import { typeNodeFromAnchorV01 } from './typeNodes';
17+
import type { GenericsV01 } from './unwrapGenerics';
1718

18-
export function accountNodeFromAnchorV01(idl: IdlV01Account, types: IdlV01TypeDef[]): AccountNode {
19+
export function accountNodeFromAnchorV01(
20+
idl: IdlV01Account,
21+
types: IdlV01TypeDef[],
22+
generics: GenericsV01,
23+
): AccountNode {
1924
const name = camelCase(idl.name);
2025
const type = types.find(({ name }) => name === idl.name);
2126

2227
if (!type) {
2328
throw new CodamaError(CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING, { name: idl.name });
2429
}
2530

26-
const data = typeNodeFromAnchorV01(type.type);
31+
const data = typeNodeFromAnchorV01(type.type, generics);
2732
assertIsNode(data, 'structTypeNode');
2833

2934
const discriminator = structFieldTypeNode({
@@ -39,9 +44,3 @@ export function accountNodeFromAnchorV01(idl: IdlV01Account, types: IdlV01TypeDe
3944
name,
4045
});
4146
}
42-
43-
export function accountNodeFromAnchorV01WithTypeDefinition(types: IdlV01TypeDef[]) {
44-
return function (idl: IdlV01Account): AccountNode {
45-
return accountNodeFromAnchorV01(idl, types);
46-
};
47-
}
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { DefinedTypeNode, definedTypeNode } from '@codama/nodes';
22

3-
import { IdlV01TypeDef } from './idl';
3+
import type { IdlV01TypeDef } from './idl';
44
import { typeNodeFromAnchorV01 } from './typeNodes';
5+
import type { GenericsV01 } from './unwrapGenerics';
56

6-
export function definedTypeNodeFromAnchorV01(idl: Partial<IdlV01TypeDef>): DefinedTypeNode {
7+
export function definedTypeNodeFromAnchorV01(idl: Partial<IdlV01TypeDef>, generics: GenericsV01): DefinedTypeNode {
78
const name = idl.name ?? '';
89
const idlType = idl.type ?? { fields: [], kind: 'struct' };
9-
const type = typeNodeFromAnchorV01(idlType);
10+
const type = typeNodeFromAnchorV01(idlType, generics);
1011
return definedTypeNode({ docs: idl.docs, name, type });
1112
}
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { InstructionArgumentNode, instructionArgumentNode } from '@codama/nodes';
22

3-
import { IdlV01Field } from './idl';
3+
import type { IdlV01Field } from './idl';
44
import { typeNodeFromAnchorV01 } from './typeNodes';
5+
import type { GenericsV01 } from './unwrapGenerics';
56

6-
export function instructionArgumentNodeFromAnchorV01(idl: IdlV01Field): InstructionArgumentNode {
7+
export function instructionArgumentNodeFromAnchorV01(idl: IdlV01Field, generics: GenericsV01): InstructionArgumentNode {
78
return instructionArgumentNode({
89
docs: idl.docs ?? [],
910
name: idl.name,
10-
type: typeNodeFromAnchorV01(idl.type),
11+
type: typeNodeFromAnchorV01(idl.type, generics),
1112
});
1213
}

packages/nodes-from-anchor/src/v01/InstructionNode.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,18 @@ import {
1010
} from '@codama/nodes';
1111

1212
import { getAnchorDiscriminatorV01 } from '../discriminators';
13-
import { IdlV01Instruction } from './idl';
13+
import type { IdlV01Instruction } from './idl';
1414
import { instructionAccountNodesFromAnchorV01 } from './InstructionAccountNode';
1515
import { instructionArgumentNodeFromAnchorV01 } from './InstructionArgumentNode';
16+
import type { GenericsV01 } from './unwrapGenerics';
1617

17-
export function instructionNodeFromAnchorV01(allAccounts: AccountNode[], idl: IdlV01Instruction): InstructionNode {
18+
export function instructionNodeFromAnchorV01(
19+
allAccounts: AccountNode[],
20+
idl: IdlV01Instruction,
21+
generics: GenericsV01,
22+
): InstructionNode {
1823
const name = idl.name;
19-
let dataArguments = idl.args.map(instructionArgumentNodeFromAnchorV01);
24+
let dataArguments = idl.args.map(arg => instructionArgumentNodeFromAnchorV01(arg, generics));
2025

2126
const discriminatorField = instructionArgumentNode({
2227
defaultValue: getAnchorDiscriminatorV01(idl.discriminator),

packages/nodes-from-anchor/src/v01/ProgramNode.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
11
import { ProgramNode, programNode, ProgramVersion } from '@codama/nodes';
22

3-
import { accountNodeFromAnchorV01WithTypeDefinition } from './AccountNode';
3+
import { accountNodeFromAnchorV01 } from './AccountNode';
44
import { definedTypeNodeFromAnchorV01 } from './DefinedTypeNode';
55
import { errorNodeFromAnchorV01 } from './ErrorNode';
66
import { IdlV01 } from './idl';
77
import { instructionNodeFromAnchorV01 } from './InstructionNode';
8+
import { extractGenerics } from './unwrapGenerics';
89

910
export function programNodeFromAnchorV01(idl: IdlV01): ProgramNode {
10-
const types = idl.types ?? [];
11+
const [types, generics] = extractGenerics(idl.types ?? []);
1112
const accounts = idl.accounts ?? [];
1213
const instructions = idl.instructions ?? [];
1314
const errors = idl.errors ?? [];
1415

1516
const filteredTypes = types.filter(type => !accounts.some(account => account.name === type.name));
16-
const definedTypes = filteredTypes.map(definedTypeNodeFromAnchorV01);
17-
const accountNodeFromAnchorV01 = accountNodeFromAnchorV01WithTypeDefinition(types);
18-
const accountNodes = accounts.map(accountNodeFromAnchorV01);
17+
const definedTypes = filteredTypes.map(type => definedTypeNodeFromAnchorV01(type, generics));
18+
const accountNodes = accounts.map(account => accountNodeFromAnchorV01(account, types, generics));
1919

2020
return programNode({
2121
accounts: accountNodes,
2222
definedTypes,
2323
errors: errors.map(errorNodeFromAnchorV01),
24-
instructions: instructions.map(instruction => instructionNodeFromAnchorV01(accountNodes, instruction)),
24+
instructions: instructions.map(instruction =>
25+
instructionNodeFromAnchorV01(accountNodes, instruction, generics),
26+
),
2527
name: idl.metadata.name,
2628
origin: 'anchor',
2729
publicKey: idl.address,

0 commit comments

Comments
 (0)