@metaplex-foundation/kinobi 0.6.0 → 0.7.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/nodes/InstructionNode.js +53 -15
- package/dist/cjs/nodes/InstructionNode.js.map +1 -1
- package/dist/cjs/renderers/js/GetJavaScriptRenderMapVisitor.js +77 -27
- package/dist/cjs/renderers/js/GetJavaScriptRenderMapVisitor.js.map +1 -1
- package/dist/cjs/renderers/js/GetJavaScriptTypeManifestVisitor.js +3 -0
- package/dist/cjs/renderers/js/GetJavaScriptTypeManifestVisitor.js.map +1 -1
- package/dist/cjs/renderers/js/GetJavaScriptValidatorBagVisitor.js +2 -0
- package/dist/cjs/renderers/js/GetJavaScriptValidatorBagVisitor.js.map +1 -1
- package/dist/cjs/renderers/js/templates/instructionsPage.njk +11 -24
- package/dist/cjs/renderers/js/templates/instructionsPageAccountMetas.njk +8 -51
- package/dist/cjs/renderers/js/templates/instructionsPageArgs.njk +34 -5
- package/dist/cjs/renderers/js/templates/instructionsPageResolvedInputs.njk +63 -0
- package/dist/cjs/visitors/BaseNodeOrNullVisitor.js +6 -1
- package/dist/cjs/visitors/BaseNodeOrNullVisitor.js.map +1 -1
- package/dist/cjs/visitors/BaseNodeVisitor.js +6 -1
- package/dist/cjs/visitors/BaseNodeVisitor.js.map +1 -1
- package/dist/cjs/visitors/BaseVoidVisitor.js +2 -0
- package/dist/cjs/visitors/BaseVoidVisitor.js.map +1 -1
- package/dist/cjs/visitors/aggregators/GetDefaultValidatorBagVisitor.js +32 -2
- package/dist/cjs/visitors/aggregators/GetDefaultValidatorBagVisitor.js.map +1 -1
- package/dist/cjs/visitors/aggregators/GetNodeInlineStringVisitor.js +4 -2
- package/dist/cjs/visitors/aggregators/GetNodeInlineStringVisitor.js.map +1 -1
- package/dist/cjs/visitors/aggregators/GetNodeTreeStringVisitor.js +6 -0
- package/dist/cjs/visitors/aggregators/GetNodeTreeStringVisitor.js.map +1 -1
- package/dist/cjs/visitors/aggregators/GetResolvedInstructionInputsVisitor.js +201 -0
- package/dist/cjs/visitors/aggregators/GetResolvedInstructionInputsVisitor.js.map +1 -0
- package/dist/cjs/visitors/aggregators/index.js +1 -1
- package/dist/cjs/visitors/aggregators/index.js.map +1 -1
- package/dist/cjs/visitors/transformers/AutoSetAnchorDiscriminatorsVisitor.js +1 -1
- package/dist/cjs/visitors/transformers/AutoSetAnchorDiscriminatorsVisitor.js.map +1 -1
- package/dist/cjs/visitors/transformers/CreateSubInstructionsFromEnumArgsVisitor.js +2 -2
- package/dist/cjs/visitors/transformers/CreateSubInstructionsFromEnumArgsVisitor.js.map +1 -1
- package/dist/cjs/visitors/transformers/FlattenInstructionArgsStructVisitor.js +1 -1
- package/dist/cjs/visitors/transformers/FlattenInstructionArgsStructVisitor.js.map +1 -1
- package/dist/cjs/visitors/transformers/SetInstructionAccountDefaultValuesVisitor.js +1 -1
- package/dist/cjs/visitors/transformers/SetInstructionAccountDefaultValuesVisitor.js.map +1 -1
- package/dist/cjs/visitors/transformers/SetInstructionDiscriminatorsVisitor.js +1 -1
- package/dist/cjs/visitors/transformers/SetInstructionDiscriminatorsVisitor.js.map +1 -1
- package/dist/cjs/visitors/transformers/UpdateInstructionsVisitor.js +8 -5
- package/dist/cjs/visitors/transformers/UpdateInstructionsVisitor.js.map +1 -1
- package/dist/cjs/visitors/transformers/UseCustomInstructionSerializerVisitor.js +1 -1
- package/dist/cjs/visitors/transformers/UseCustomInstructionSerializerVisitor.js.map +1 -1
- package/dist/types/idl/IdlInstruction.d.ts +0 -1
- package/dist/types/nodes/InstructionNode.d.ts +53 -14
- package/dist/types/renderers/js/GetJavaScriptRenderMapVisitor.d.ts +10 -2
- package/dist/types/renderers/js/GetJavaScriptTypeManifestVisitor.d.ts +1 -0
- package/dist/types/visitors/aggregators/GetResolvedInstructionInputsVisitor.d.ts +41 -0
- package/dist/types/visitors/aggregators/index.d.ts +1 -1
- package/dist/types/visitors/transformers/UpdateInstructionsVisitor.d.ts +7 -2
- package/package.json +1 -1
- package/src/idl/IdlInstruction.ts +0 -1
- package/src/nodes/InstructionNode.ts +99 -21
- package/src/renderers/js/GetJavaScriptRenderMapVisitor.ts +99 -36
- package/src/renderers/js/GetJavaScriptTypeManifestVisitor.ts +6 -0
- package/src/renderers/js/GetJavaScriptValidatorBagVisitor.ts +2 -0
- package/src/renderers/js/templates/instructionsPage.njk +11 -24
- package/src/renderers/js/templates/instructionsPageAccountMetas.njk +8 -51
- package/src/renderers/js/templates/instructionsPageArgs.njk +34 -5
- package/src/renderers/js/templates/instructionsPageResolvedInputs.njk +63 -0
- package/src/visitors/BaseNodeOrNullVisitor.ts +5 -0
- package/src/visitors/BaseNodeVisitor.ts +5 -0
- package/src/visitors/BaseVoidVisitor.ts +1 -0
- package/src/visitors/aggregators/GetDefaultValidatorBagVisitor.ts +48 -2
- package/src/visitors/aggregators/GetNodeInlineStringVisitor.ts +3 -2
- package/src/visitors/aggregators/GetNodeTreeStringVisitor.ts +6 -0
- package/src/visitors/aggregators/GetResolvedInstructionInputsVisitor.ts +275 -0
- package/src/visitors/aggregators/index.ts +1 -1
- package/src/visitors/transformers/AutoSetAnchorDiscriminatorsVisitor.ts +1 -0
- package/src/visitors/transformers/CreateSubInstructionsFromEnumArgsVisitor.ts +2 -0
- package/src/visitors/transformers/FlattenInstructionArgsStructVisitor.ts +1 -0
- package/src/visitors/transformers/SetInstructionAccountDefaultValuesVisitor.ts +1 -0
- package/src/visitors/transformers/SetInstructionDiscriminatorsVisitor.ts +1 -0
- package/src/visitors/transformers/UpdateInstructionsVisitor.ts +19 -14
- package/src/visitors/transformers/UseCustomInstructionSerializerVisitor.ts +1 -0
- package/dist/cjs/visitors/aggregators/GetResolvedInstructionAccountsVisitor.js +0 -123
- package/dist/cjs/visitors/aggregators/GetResolvedInstructionAccountsVisitor.js.map +0 -1
- package/dist/types/visitors/aggregators/GetResolvedInstructionAccountsVisitor.d.ts +0 -18
- package/src/visitors/aggregators/GetResolvedInstructionAccountsVisitor.ts +0 -155
|
@@ -1,62 +1,19 @@
|
|
|
1
|
-
{%
|
|
2
|
-
// Resolved accounts.
|
|
3
|
-
{% for account in accounts | sort(false, false, 'dependencyPosition') %}
|
|
4
|
-
{% if not account.defaultsTo %}
|
|
5
|
-
const {{ account.name | camelCase }}Account = {{ accountsObj }}.{{ account.name | camelCase }};
|
|
6
|
-
{% elif account.defaultsTo.kind === 'account' %}
|
|
7
|
-
const {{ account.name | camelCase }}Account = {{ accountsObj }}.{{ account.name | camelCase }} ?? {{ account.defaultsTo.name | camelCase }}Account;
|
|
8
|
-
{% elif account.defaultsTo.kind === 'pda' %}
|
|
9
|
-
const {{ account.name | camelCase }}Account = {{ accountsObj }}.{{ account.name | camelCase }} ?? find{{ account.defaultsTo.pdaAccount | pascalCase }}Pda(context,
|
|
10
|
-
{%- if (account.defaultsTo.seeds | length) > 0 -%}
|
|
11
|
-
{
|
|
12
|
-
{%- for seedKey, seedValue in account.defaultsTo.seeds -%}
|
|
13
|
-
{%- if seedValue.kind === 'value' -%}
|
|
14
|
-
{{ seedKey }}: {{ seedValue.render }},
|
|
15
|
-
{%- elif seedValue.kind === 'account' -%}
|
|
16
|
-
{{ seedKey }}: publicKey({{ seedValue.name | camelCase }}Account),
|
|
17
|
-
{%- else -%}
|
|
18
|
-
{{ seedKey }}: {{ argsObj }}.{{ seedValue.name | camelCase }},
|
|
19
|
-
{%- endif -%}
|
|
20
|
-
{%- endfor -%}
|
|
21
|
-
}
|
|
22
|
-
{%- endif -%}
|
|
23
|
-
);
|
|
24
|
-
{% elif account.defaultsTo.kind === 'publicKey' %}
|
|
25
|
-
const {{ account.name | camelCase }}Account = {{ accountsObj }}.{{ account.name | camelCase }} ?? publicKey('{{ account.defaultsTo.publicKey }}');
|
|
26
|
-
{% elif account.defaultsTo.kind === 'program' %}
|
|
27
|
-
const {{ account.name | camelCase }}Account = {{ accountsObj }}.{{ account.name | camelCase }} ?? { ...context.programs.getPublicKey('{{ account.defaultsTo.program.name }}', '{{ account.defaultsTo.program.publicKey }}'), isWritable: false };
|
|
28
|
-
{% elif account.defaultsTo.kind === 'programId' %}
|
|
29
|
-
const {{ account.name | camelCase }}Account = {{ accountsObj }}.{{ account.name | camelCase }} ?? { ...programId, isWritable: false };
|
|
30
|
-
{% elif account.defaultsTo.kind === 'identity' and (account.isSigner !== false) %}
|
|
31
|
-
const {{ account.name | camelCase }}Account = {{ accountsObj }}.{{ account.name | camelCase }} ?? context.identity;
|
|
32
|
-
{% elif account.defaultsTo.kind === 'identity' %}
|
|
33
|
-
const {{ account.name | camelCase }}Account = {{ accountsObj }}.{{ account.name | camelCase }} ?? context.identity.publicKey;
|
|
34
|
-
{% elif account.defaultsTo.kind === 'payer' and (account.isSigner !== false) %}
|
|
35
|
-
const {{ account.name | camelCase }}Account = {{ accountsObj }}.{{ account.name | camelCase }} ?? context.payer;
|
|
36
|
-
{% elif account.defaultsTo.kind === 'payer' %}
|
|
37
|
-
const {{ account.name | camelCase }}Account = {{ accountsObj }}.{{ account.name | camelCase }} ?? context.payer.publicKey;
|
|
38
|
-
{% else %}
|
|
39
|
-
const {{ account.name | camelCase }}Account = {{ accountsObj }}.{{ account.name | camelCase }};
|
|
40
|
-
{% endif %}
|
|
41
|
-
{% endfor %}
|
|
42
|
-
{% endif %}
|
|
43
|
-
|
|
44
|
-
{% for account in accounts | sort(false, false, 'position') %}
|
|
1
|
+
{% for account in accounts %}
|
|
45
2
|
{% set isWritableString = 'true' if account.isWritable else 'false' %}
|
|
46
3
|
// {{ account.name | camelCase | titleCase }}{% if account.resolvedIsOptional %} (optional){% endif %}.
|
|
47
4
|
{% if account.resolvedIsOptional %}
|
|
48
|
-
if ({{ account.name | camelCase }}
|
|
5
|
+
if (resolvedAccounts.{{ account.name | camelCase }}) {
|
|
49
6
|
{% endif %}
|
|
50
7
|
{% if account.resolvedIsSigner === 'either' %}
|
|
51
|
-
if (isSigner({{ account.name | camelCase }}
|
|
52
|
-
signers.push({{ account.name | camelCase }}
|
|
8
|
+
if (isSigner(resolvedAccounts.{{ account.name | camelCase }})) {
|
|
9
|
+
signers.push(resolvedAccounts.{{ account.name | camelCase }});
|
|
53
10
|
}
|
|
54
|
-
keys.push({ pubkey: publicKey({{ account.name | camelCase }}
|
|
11
|
+
keys.push({ pubkey: publicKey(resolvedAccounts.{{ account.name | camelCase }}), isSigner: isSigner(resolvedAccounts.{{ account.name | camelCase }}), isWritable: isWritable(resolvedAccounts.{{ account.name | camelCase }}, {{ isWritableString }}) });
|
|
55
12
|
{% elif account.resolvedIsSigner %}
|
|
56
|
-
signers.push({{ account.name | camelCase }}
|
|
57
|
-
keys.push({ pubkey: {{ account.name | camelCase }}
|
|
13
|
+
signers.push(resolvedAccounts.{{ account.name | camelCase }});
|
|
14
|
+
keys.push({ pubkey: resolvedAccounts.{{ account.name | camelCase }}.publicKey, isSigner: true, isWritable: isWritable(resolvedAccounts.{{ account.name | camelCase }}, {{ isWritableString }}) });
|
|
58
15
|
{% else %}
|
|
59
|
-
keys.push({ pubkey: {{ account.name | camelCase }}
|
|
16
|
+
keys.push({ pubkey: resolvedAccounts.{{ account.name | camelCase }}, isSigner: false, isWritable: isWritable(resolvedAccounts.{{ account.name | camelCase }}, {{ isWritableString }}) });
|
|
60
17
|
{% endif %}
|
|
61
18
|
{% if account.resolvedIsOptional %}
|
|
62
19
|
}
|
|
@@ -1,7 +1,36 @@
|
|
|
1
|
-
{% if not instruction.
|
|
2
|
-
//
|
|
3
|
-
{{ macros.exportType(instruction.name | pascalCase + 'InstructionData',
|
|
1
|
+
{% if not instruction.hasLinkedArgs and instruction.hasData %}
|
|
2
|
+
// Data.
|
|
3
|
+
{{ macros.exportType(instruction.name | pascalCase + 'InstructionData', argManifest) }}
|
|
4
4
|
|
|
5
|
-
{{ macros.exportSerializer(instruction.name | pascalCase + 'InstructionData',
|
|
5
|
+
{{ macros.exportSerializer(instruction.name | pascalCase + 'InstructionData', argManifest) }}
|
|
6
|
+
{% endif %}
|
|
6
7
|
|
|
7
|
-
{%
|
|
8
|
+
{% if not instruction.hasLinkedExtraArgs and instruction.hasExtraArgs %}
|
|
9
|
+
// Extra Args.
|
|
10
|
+
export type {{ instruction.name | pascalCase + 'InstructionExtraArgs' }} = {{ extraArgManifest.looseType }};
|
|
11
|
+
{% endif %}
|
|
12
|
+
|
|
13
|
+
{% if instruction.hasAnyArgs %}
|
|
14
|
+
{% set argType %}
|
|
15
|
+
{% if instruction.hasArgs and instruction.hasExtraArgs %}
|
|
16
|
+
{{ instruction.name | pascalCase + 'InstructionDataArgs' }} & {{ instruction.name | pascalCase + 'InstructionExtraArgs' }}
|
|
17
|
+
{% elif instruction.hasArgs %}
|
|
18
|
+
{{ instruction.name | pascalCase + 'InstructionDataArgs' }}
|
|
19
|
+
{% elif instruction.hasExtraArgs %}
|
|
20
|
+
{{ instruction.name | pascalCase + 'InstructionExtraArgs' }}
|
|
21
|
+
{% endif %}
|
|
22
|
+
{% endset %}
|
|
23
|
+
|
|
24
|
+
// Args.
|
|
25
|
+
{% if argDefaultKeys.length > 0 %}
|
|
26
|
+
type PickPartial<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
27
|
+
export type {{ instruction.name | pascalCase + 'InstructionArgs' }} = PickPartial<
|
|
28
|
+
{{ argType }},
|
|
29
|
+
{% for key in argDefaultKeys %}
|
|
30
|
+
"{{ key }}"{% if not loop.last %} | {% endif %}
|
|
31
|
+
{% endfor %}
|
|
32
|
+
>;
|
|
33
|
+
{% else %}
|
|
34
|
+
export type {{ instruction.name | pascalCase + 'InstructionArgs' }} = {{ argType }};
|
|
35
|
+
{% endif %}
|
|
36
|
+
{% endif %}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{% set hasResolvedAccounts = accounts.length > 0 or instruction.hasResolvers %}
|
|
2
|
+
{% set hasResolvedArgs = instruction.hasArgs or instruction.hasArgDefaults or instruction.hasResolvers %}
|
|
3
|
+
|
|
4
|
+
{% if resolvedInputs.length > 0 or hasResolvedAccounts or hasResolvedArgs %}
|
|
5
|
+
// Resolved inputs.
|
|
6
|
+
{% if hasResolvedAccounts %}
|
|
7
|
+
const resolvedAccounts: any = { ...{{ accountsObj }} };
|
|
8
|
+
{% endif %}
|
|
9
|
+
{% if hasResolvedArgs %}
|
|
10
|
+
const resolvedArgs: any = { ...{{ argsObj }} };
|
|
11
|
+
{% endif %}
|
|
12
|
+
{% for input in resolvedInputs %}
|
|
13
|
+
{% if input.kind === 'account' and input.defaultsTo %}
|
|
14
|
+
{% if input.defaultsTo.kind === 'account' %}
|
|
15
|
+
resolvedAccounts.{{ input.name | camelCase }} = resolvedAccounts.{{ input.name | camelCase }} ?? resolvedAccounts.{{ input.defaultsTo.name | camelCase }};
|
|
16
|
+
{% elif input.defaultsTo.kind === 'pda' %}
|
|
17
|
+
resolvedAccounts.{{ input.name | camelCase }} = resolvedAccounts.{{ input.name | camelCase }} ?? find{{ input.defaultsTo.pdaAccount | pascalCase }}Pda(context,
|
|
18
|
+
{%- if (input.defaultsTo.seeds | length) > 0 -%}
|
|
19
|
+
{
|
|
20
|
+
{%- for seedKey, seedValue in input.defaultsTo.seeds -%}
|
|
21
|
+
{%- if seedValue.kind === 'value' -%}
|
|
22
|
+
{{ seedKey }}: {{ seedValue.render }},
|
|
23
|
+
{%- elif seedValue.kind === 'account' -%}
|
|
24
|
+
{{ seedKey }}: publicKey(resolvedAccounts.{{ seedValue.name | camelCase }}),
|
|
25
|
+
{%- else -%}
|
|
26
|
+
{{ seedKey }}: resolvedArgs.{{ seedValue.name | camelCase }},
|
|
27
|
+
{%- endif -%}
|
|
28
|
+
{%- endfor -%}
|
|
29
|
+
}
|
|
30
|
+
{%- endif -%}
|
|
31
|
+
);
|
|
32
|
+
{% elif input.defaultsTo.kind === 'publicKey' %}
|
|
33
|
+
resolvedAccounts.{{ input.name | camelCase }} = resolvedAccounts.{{ input.name | camelCase }} ?? publicKey('{{ input.defaultsTo.publicKey }}');
|
|
34
|
+
{% elif input.defaultsTo.kind === 'program' %}
|
|
35
|
+
resolvedAccounts.{{ input.name | camelCase }} = resolvedAccounts.{{ input.name | camelCase }} ?? { ...context.programs.getPublicKey('{{ input.defaultsTo.program.name }}', '{{ input.defaultsTo.program.publicKey }}'), isWritable: false };
|
|
36
|
+
{% elif input.defaultsTo.kind === 'programId' %}
|
|
37
|
+
resolvedAccounts.{{ input.name | camelCase }} = resolvedAccounts.{{ input.name | camelCase }} ?? programId;
|
|
38
|
+
{% elif input.defaultsTo.kind === 'identity' and (input.isSigner !== false) %}
|
|
39
|
+
resolvedAccounts.{{ input.name | camelCase }} = resolvedAccounts.{{ input.name | camelCase }} ?? context.identity;
|
|
40
|
+
{% elif input.defaultsTo.kind === 'identity' %}
|
|
41
|
+
resolvedAccounts.{{ input.name | camelCase }} = resolvedAccounts.{{ input.name | camelCase }} ?? context.identity.publicKey;
|
|
42
|
+
{% elif input.defaultsTo.kind === 'payer' and (input.isSigner !== false) %}
|
|
43
|
+
resolvedAccounts.{{ input.name | camelCase }} = resolvedAccounts.{{ input.name | camelCase }} ?? context.payer;
|
|
44
|
+
{% elif input.defaultsTo.kind === 'payer' %}
|
|
45
|
+
resolvedAccounts.{{ input.name | camelCase }} = resolvedAccounts.{{ input.name | camelCase }} ?? context.payer.publicKey;
|
|
46
|
+
{% elif input.defaultsTo.kind === 'resolver' %}
|
|
47
|
+
resolvedAccounts.{{ input.name | camelCase }} = resolvedAccounts.{{ input.name | camelCase }} ?? {{ input.defaultsTo.name | camelCase }}(context, resolvedAccounts, resolvedArgs, programId);
|
|
48
|
+
{% endif %}
|
|
49
|
+
{% elif input.kind === 'arg' %}
|
|
50
|
+
{% if input.defaultsTo.kind === 'arg' %}
|
|
51
|
+
resolvedArgs.{{ input.name | camelCase }} = resolvedArgs.{{ input.name | camelCase }} ?? resolvedArgs.{{ input.defaultsTo.name | camelCase }};
|
|
52
|
+
{% elif input.defaultsTo.kind === 'account' %}
|
|
53
|
+
resolvedArgs.{{ input.name | camelCase }} = resolvedArgs.{{ input.name | camelCase }} ?? resolvedAccounts.{{ input.defaultsTo.name | camelCase }};
|
|
54
|
+
{% elif input.defaultsTo.kind === 'accountBump' %}
|
|
55
|
+
resolvedArgs.{{ input.name | camelCase }} = resolvedArgs.{{ input.name | camelCase }} ?? resolvedAccounts.{{ input.defaultsTo.name | camelCase }}.bump;
|
|
56
|
+
{% elif input.defaultsTo.kind === 'value' %}
|
|
57
|
+
resolvedArgs.{{ input.name | camelCase }} = resolvedArgs.{{ input.name | camelCase }} ?? {{ input.defaultsTo.render }};
|
|
58
|
+
{% elif input.defaultsTo.kind === 'resolver' %}
|
|
59
|
+
resolvedArgs.{{ input.name | camelCase }} = resolvedArgs.{{ input.name | camelCase }} ?? {{ input.defaultsTo.name | camelCase }}(context, resolvedAccounts, resolvedArgs, programId);
|
|
60
|
+
{% endif %}
|
|
61
|
+
{% endif %}
|
|
62
|
+
{% endfor %}
|
|
63
|
+
{% endif %}
|
|
@@ -63,10 +63,15 @@ export class BaseNodeOrNullVisitor implements Visitor<nodes.Node | null> {
|
|
|
63
63
|
const args = instruction.args.accept(this);
|
|
64
64
|
if (args === null) return null;
|
|
65
65
|
nodes.assertTypeStructOrDefinedLinkNode(args);
|
|
66
|
+
const extraArgs = instruction.extraArgs?.accept(this) ?? null;
|
|
67
|
+
if (extraArgs !== null) {
|
|
68
|
+
nodes.assertTypeStructOrDefinedLinkNode(args);
|
|
69
|
+
}
|
|
66
70
|
return new nodes.InstructionNode(
|
|
67
71
|
instruction.metadata,
|
|
68
72
|
instruction.accounts,
|
|
69
73
|
args,
|
|
74
|
+
extraArgs as nodes.TypeStructNode | nodes.TypeDefinedLinkNode | null,
|
|
70
75
|
instruction.subInstructions
|
|
71
76
|
.map((ix) => ix.accept(this))
|
|
72
77
|
.filter(
|
|
@@ -51,10 +51,15 @@ export class BaseNodeVisitor implements Visitor<nodes.Node> {
|
|
|
51
51
|
visitInstruction(instruction: nodes.InstructionNode): nodes.Node {
|
|
52
52
|
const args = instruction.args.accept(this);
|
|
53
53
|
nodes.assertTypeStructOrDefinedLinkNode(args);
|
|
54
|
+
const extraArgs = instruction.extraArgs?.accept(this) ?? null;
|
|
55
|
+
if (extraArgs !== null) {
|
|
56
|
+
nodes.assertTypeStructOrDefinedLinkNode(args);
|
|
57
|
+
}
|
|
54
58
|
return new nodes.InstructionNode(
|
|
55
59
|
instruction.metadata,
|
|
56
60
|
instruction.accounts,
|
|
57
61
|
args,
|
|
62
|
+
extraArgs as nodes.TypeStructNode | nodes.TypeDefinedLinkNode | null,
|
|
58
63
|
instruction.subInstructions
|
|
59
64
|
.map((ix) => ix.accept(this))
|
|
60
65
|
.filter(
|
|
@@ -21,6 +21,7 @@ export abstract class BaseVoidVisitor implements Visitor<void> {
|
|
|
21
21
|
|
|
22
22
|
visitInstruction(instruction: nodes.InstructionNode): void {
|
|
23
23
|
instruction.args.accept(this);
|
|
24
|
+
instruction.extraArgs?.accept(this);
|
|
24
25
|
instruction.subInstructions.forEach((ix) => ix.accept(this));
|
|
25
26
|
}
|
|
26
27
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as nodes from '../../nodes';
|
|
2
|
+
import { mainCase } from '../../utils';
|
|
2
3
|
import { NodeStack } from '../NodeStack';
|
|
3
4
|
import { ValidatorBag } from '../ValidatorBag';
|
|
4
5
|
import { Visitor } from '../Visitor';
|
|
5
|
-
import {
|
|
6
|
+
import { GetResolvedInstructionInputsVisitor } from './GetResolvedInstructionInputsVisitor';
|
|
6
7
|
|
|
7
8
|
export class GetDefaultValidatorBagVisitor implements Visitor<ValidatorBag> {
|
|
8
9
|
protected stack: NodeStack = new NodeStack();
|
|
@@ -84,7 +85,7 @@ export class GetDefaultValidatorBagVisitor implements Visitor<ValidatorBag> {
|
|
|
84
85
|
});
|
|
85
86
|
|
|
86
87
|
// Check for cyclic dependencies in account defaults.
|
|
87
|
-
const cyclicCheckVisitor = new
|
|
88
|
+
const cyclicCheckVisitor = new GetResolvedInstructionInputsVisitor();
|
|
88
89
|
try {
|
|
89
90
|
instruction.accept(cyclicCheckVisitor);
|
|
90
91
|
} catch (error) {
|
|
@@ -95,8 +96,53 @@ export class GetDefaultValidatorBagVisitor implements Visitor<ValidatorBag> {
|
|
|
95
96
|
);
|
|
96
97
|
}
|
|
97
98
|
|
|
99
|
+
// Check args.
|
|
98
100
|
bag.mergeWith([instruction.args.accept(this)]);
|
|
99
101
|
|
|
102
|
+
// Check extra args.
|
|
103
|
+
if (instruction.extraArgs) {
|
|
104
|
+
bag.mergeWith([instruction.extraArgs.accept(this)]);
|
|
105
|
+
if (
|
|
106
|
+
nodes.isTypeStructNode(instruction.args) &&
|
|
107
|
+
nodes.isTypeStructNode(instruction.extraArgs)
|
|
108
|
+
) {
|
|
109
|
+
const names = [
|
|
110
|
+
...instruction.args.fields.map(({ name }) => mainCase(name)),
|
|
111
|
+
...instruction.extraArgs.fields.map(({ name }) => mainCase(name)),
|
|
112
|
+
];
|
|
113
|
+
const duplicates = names.filter((e, i, a) => a.indexOf(e) !== i);
|
|
114
|
+
const uniqueDuplicates = [...new Set(duplicates)];
|
|
115
|
+
const hasConflictingNames = uniqueDuplicates.length > 0;
|
|
116
|
+
if (hasConflictingNames) {
|
|
117
|
+
bag.error(
|
|
118
|
+
`The names of the following instruction arguments are conflicting: ` +
|
|
119
|
+
`[${uniqueDuplicates.join(', ')}].`,
|
|
120
|
+
instruction,
|
|
121
|
+
this.stack
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Check arg defaults.
|
|
128
|
+
Object.entries(instruction.metadata.argDefaults).forEach(
|
|
129
|
+
([name, defaultsTo]) => {
|
|
130
|
+
if (defaultsTo.kind === 'accountBump') {
|
|
131
|
+
const defaultAccount = instruction.accounts.find(
|
|
132
|
+
(account) => account.name === defaultsTo.name
|
|
133
|
+
);
|
|
134
|
+
if (defaultAccount && defaultAccount.isSigner !== false) {
|
|
135
|
+
bag.error(
|
|
136
|
+
`Argument ${name} cannot default to the bump attribute of ` +
|
|
137
|
+
`the [${defaultsTo.name}] account as it may be a Signer.`,
|
|
138
|
+
instruction,
|
|
139
|
+
this.stack
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
|
|
100
146
|
// Check sub-instructions.
|
|
101
147
|
bag.mergeWith(instruction.subInstructions.map((ix) => ix.accept(this)));
|
|
102
148
|
|
|
@@ -32,11 +32,12 @@ export class GetNodeInlineStringVisitor implements Visitor<string> {
|
|
|
32
32
|
visitInstruction(instruction: nodes.InstructionNode): string {
|
|
33
33
|
const accounts = instruction.accounts.map((account) => account.name);
|
|
34
34
|
const args = instruction.args.accept(this);
|
|
35
|
+
const extraArgs = instruction.extraArgs?.accept(this);
|
|
36
|
+
const extraArgsString = extraArgs ? `,extraArgs:(${extraArgs})` : '';
|
|
35
37
|
return (
|
|
36
38
|
`${INSTRUCTION_PREFIX}[${instruction.name}](` +
|
|
37
39
|
`accounts:(${accounts.join(',')}),` +
|
|
38
|
-
`args:(${args})`
|
|
39
|
-
`)`
|
|
40
|
+
`args:(${args})${extraArgsString})`
|
|
40
41
|
);
|
|
41
42
|
}
|
|
42
43
|
|
|
@@ -91,6 +91,12 @@ export class GetNodeTreeStringVisitor implements Visitor<string> {
|
|
|
91
91
|
this.indent += 1;
|
|
92
92
|
children.push(instruction.args.accept(this));
|
|
93
93
|
this.indent -= 1;
|
|
94
|
+
if (instruction.extraArgs) {
|
|
95
|
+
children.push(this.indented('extra arguments:'));
|
|
96
|
+
this.indent += 1;
|
|
97
|
+
children.push(instruction.extraArgs.accept(this));
|
|
98
|
+
this.indent -= 1;
|
|
99
|
+
}
|
|
94
100
|
this.indent -= 1;
|
|
95
101
|
return children.join('\n');
|
|
96
102
|
}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import type * as nodes from '../../nodes';
|
|
2
|
+
import { BaseThrowVisitor } from '../BaseThrowVisitor';
|
|
3
|
+
|
|
4
|
+
type InstructionNodeInput =
|
|
5
|
+
| ({ kind: 'arg' } & InstructionNodeArg)
|
|
6
|
+
| ({ kind: 'account' } & nodes.InstructionNodeAccount);
|
|
7
|
+
|
|
8
|
+
type InstructionNodeArg = {
|
|
9
|
+
name: string;
|
|
10
|
+
defaultsTo: nodes.InstructionNodeArgDefaults;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type ResolvedInstructionAccount = nodes.InstructionNodeAccount & {
|
|
14
|
+
kind: 'account';
|
|
15
|
+
isPda: boolean;
|
|
16
|
+
dependsOn: nodes.InstructionNodeInputDependency[];
|
|
17
|
+
resolvedIsSigner: boolean | 'either';
|
|
18
|
+
resolvedIsOptional: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type ResolvedInstructionArg = InstructionNodeArg & {
|
|
22
|
+
kind: 'arg';
|
|
23
|
+
dependsOn: nodes.InstructionNodeInputDependency[];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type ResolvedInstructionInput =
|
|
27
|
+
| ResolvedInstructionAccount
|
|
28
|
+
| ResolvedInstructionArg;
|
|
29
|
+
|
|
30
|
+
export class GetResolvedInstructionInputsVisitor extends BaseThrowVisitor<
|
|
31
|
+
ResolvedInstructionInput[]
|
|
32
|
+
> {
|
|
33
|
+
protected stack: InstructionNodeInput[] = [];
|
|
34
|
+
|
|
35
|
+
protected resolved: ResolvedInstructionInput[] = [];
|
|
36
|
+
|
|
37
|
+
protected visitedAccounts = new Map<string, ResolvedInstructionAccount>();
|
|
38
|
+
|
|
39
|
+
protected visitedArgs = new Map<string, ResolvedInstructionArg>();
|
|
40
|
+
|
|
41
|
+
protected error: string | null = null;
|
|
42
|
+
|
|
43
|
+
getError(): string | null {
|
|
44
|
+
return this.error;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
visitInstruction(
|
|
48
|
+
instruction: nodes.InstructionNode
|
|
49
|
+
): ResolvedInstructionInput[] {
|
|
50
|
+
// Ensure we always start with a clean slate.
|
|
51
|
+
this.error = null;
|
|
52
|
+
this.stack = [];
|
|
53
|
+
this.resolved = [];
|
|
54
|
+
this.visitedAccounts = new Map();
|
|
55
|
+
this.visitedArgs = new Map();
|
|
56
|
+
|
|
57
|
+
const inputs: InstructionNodeInput[] = [
|
|
58
|
+
...instruction.accounts.map((account) => ({
|
|
59
|
+
kind: 'account' as const,
|
|
60
|
+
...account,
|
|
61
|
+
})),
|
|
62
|
+
...Object.entries(instruction.metadata.argDefaults).map(
|
|
63
|
+
([argName, argDefault]) => ({
|
|
64
|
+
kind: 'arg' as const,
|
|
65
|
+
name: argName,
|
|
66
|
+
defaultsTo: argDefault,
|
|
67
|
+
})
|
|
68
|
+
),
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
// Visit all instruction accounts.
|
|
72
|
+
inputs.forEach((input) => {
|
|
73
|
+
this.resolveInstructionInput(instruction, input);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return this.resolved;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
resolveInstructionInput(
|
|
80
|
+
instruction: nodes.InstructionNode,
|
|
81
|
+
input: InstructionNodeInput
|
|
82
|
+
): void {
|
|
83
|
+
// Ensure we don't visit the same input twice.
|
|
84
|
+
if (
|
|
85
|
+
(input.kind === 'account' && this.visitedAccounts.has(input.name)) ||
|
|
86
|
+
(input.kind === 'arg' && this.visitedArgs.has(input.name))
|
|
87
|
+
) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Ensure we don't have a circular dependency.
|
|
92
|
+
const isCircular = this.stack.some(
|
|
93
|
+
({ kind, name }) => kind === input.kind && name === input.name
|
|
94
|
+
);
|
|
95
|
+
if (isCircular) {
|
|
96
|
+
const cycle = [...this.stack.map(({ name }) => name), input.name].join(
|
|
97
|
+
' -> '
|
|
98
|
+
);
|
|
99
|
+
this.error =
|
|
100
|
+
`Circular dependency detected in the accounts and args of ` +
|
|
101
|
+
`the "${instruction.name}" instruction. ` +
|
|
102
|
+
`Got the following dependency cycle: ${cycle}.`;
|
|
103
|
+
throw new Error(this.error);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Resolve whilst keeping track of the stack.
|
|
107
|
+
this.stack.push(input);
|
|
108
|
+
const resolved =
|
|
109
|
+
input.kind === 'account'
|
|
110
|
+
? this.resolveInstructionAccount(instruction, input)
|
|
111
|
+
: this.resolveInstructionArg(instruction, input);
|
|
112
|
+
this.stack.pop();
|
|
113
|
+
|
|
114
|
+
// Store the resolved input.
|
|
115
|
+
this.resolved.push(resolved);
|
|
116
|
+
if (resolved.kind === 'account') {
|
|
117
|
+
this.visitedAccounts.set(input.name, resolved);
|
|
118
|
+
} else {
|
|
119
|
+
this.visitedArgs.set(input.name, resolved);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
resolveInstructionAccount(
|
|
124
|
+
instruction: nodes.InstructionNode,
|
|
125
|
+
account: nodes.InstructionNodeAccount & { kind: 'account' }
|
|
126
|
+
): ResolvedInstructionAccount {
|
|
127
|
+
// Get account dependencies.
|
|
128
|
+
const dependsOn: nodes.InstructionNodeInputDependency[] = [];
|
|
129
|
+
if (account.defaultsTo?.kind === 'account') {
|
|
130
|
+
dependsOn.push({ kind: 'account', name: account.defaultsTo.name });
|
|
131
|
+
} else if (account.defaultsTo?.kind === 'pda') {
|
|
132
|
+
const accounts = new Set<string>();
|
|
133
|
+
const args = new Set<string>();
|
|
134
|
+
Object.values(account.defaultsTo.seeds).forEach((seed) => {
|
|
135
|
+
if (seed.kind === 'account') {
|
|
136
|
+
accounts.add(seed.name);
|
|
137
|
+
} else if (seed.kind === 'arg') {
|
|
138
|
+
args.add(seed.name);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
dependsOn.push(
|
|
142
|
+
...[...accounts].map((name) => ({ kind: 'account' as const, name })),
|
|
143
|
+
...[...accounts].map((name) => ({ kind: 'arg' as const, name }))
|
|
144
|
+
);
|
|
145
|
+
} else if (account.defaultsTo?.kind === 'resolver') {
|
|
146
|
+
dependsOn.push(...account.defaultsTo.dependsOn);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Visit account dependencies first.
|
|
150
|
+
this.resolveInstructionDependencies(instruction, account, dependsOn);
|
|
151
|
+
|
|
152
|
+
const resolved: ResolvedInstructionAccount = {
|
|
153
|
+
...account,
|
|
154
|
+
isPda: Object.values(instruction.metadata.argDefaults).some(
|
|
155
|
+
(argDefault) =>
|
|
156
|
+
argDefault.kind === 'accountBump' && argDefault.name === account.name
|
|
157
|
+
),
|
|
158
|
+
dependsOn,
|
|
159
|
+
resolvedIsSigner: account.isSigner,
|
|
160
|
+
resolvedIsOptional: account.isOptional,
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
switch (resolved.defaultsTo?.kind) {
|
|
164
|
+
case 'account':
|
|
165
|
+
const defaultAccount = this.visitedAccounts.get(
|
|
166
|
+
resolved.defaultsTo.name
|
|
167
|
+
)!;
|
|
168
|
+
const resolvedIsPublicKey =
|
|
169
|
+
account.isSigner === false && defaultAccount.isSigner === false;
|
|
170
|
+
const resolvedIsSigner =
|
|
171
|
+
account.isSigner === true && defaultAccount.isSigner === true;
|
|
172
|
+
const resolvedIsOptionalSigner =
|
|
173
|
+
!resolvedIsPublicKey && !resolvedIsSigner;
|
|
174
|
+
resolved.resolvedIsSigner = resolvedIsOptionalSigner
|
|
175
|
+
? 'either'
|
|
176
|
+
: resolvedIsSigner;
|
|
177
|
+
resolved.resolvedIsOptional = defaultAccount.isOptional;
|
|
178
|
+
break;
|
|
179
|
+
case 'publicKey':
|
|
180
|
+
case 'program':
|
|
181
|
+
case 'programId':
|
|
182
|
+
resolved.resolvedIsSigner =
|
|
183
|
+
account.isSigner === false ? false : 'either';
|
|
184
|
+
resolved.resolvedIsOptional = false;
|
|
185
|
+
break;
|
|
186
|
+
case 'pda':
|
|
187
|
+
resolved.resolvedIsSigner =
|
|
188
|
+
account.isSigner === false ? false : 'either';
|
|
189
|
+
resolved.resolvedIsOptional = false;
|
|
190
|
+
const { seeds } = resolved.defaultsTo;
|
|
191
|
+
Object.keys(seeds).forEach((seedKey) => {
|
|
192
|
+
const seed = seeds[seedKey];
|
|
193
|
+
if (seed.kind !== 'account') return;
|
|
194
|
+
const dependency = this.visitedAccounts.get(seed.name)!;
|
|
195
|
+
if (dependency.resolvedIsOptional) {
|
|
196
|
+
this.error =
|
|
197
|
+
`Cannot use optional account "${seed.name}" as the "${seedKey}" PDA seed ` +
|
|
198
|
+
`for the "${account.name}" account of the "${instruction.name}" instruction.`;
|
|
199
|
+
throw new Error(this.error);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
break;
|
|
203
|
+
case 'identity':
|
|
204
|
+
case 'payer':
|
|
205
|
+
resolved.resolvedIsOptional = false;
|
|
206
|
+
break;
|
|
207
|
+
case 'resolver':
|
|
208
|
+
resolved.resolvedIsOptional = resolved.defaultsTo.resolvedIsOptional;
|
|
209
|
+
resolved.resolvedIsSigner = resolved.defaultsTo.resolvedIsSigner;
|
|
210
|
+
break;
|
|
211
|
+
default:
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return resolved;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
resolveInstructionArg(
|
|
219
|
+
instruction: nodes.InstructionNode,
|
|
220
|
+
arg: InstructionNodeArg & { kind: 'arg' }
|
|
221
|
+
): ResolvedInstructionArg {
|
|
222
|
+
// Get account dependencies.
|
|
223
|
+
const dependsOn: nodes.InstructionNodeInputDependency[] = [];
|
|
224
|
+
if (
|
|
225
|
+
arg.defaultsTo.kind === 'account' ||
|
|
226
|
+
arg.defaultsTo.kind === 'accountBump'
|
|
227
|
+
) {
|
|
228
|
+
dependsOn.push({ kind: 'account', name: arg.defaultsTo.name });
|
|
229
|
+
} else if (arg.defaultsTo.kind === 'arg') {
|
|
230
|
+
dependsOn.push({ kind: 'arg', name: arg.defaultsTo.name });
|
|
231
|
+
} else if (arg.defaultsTo.kind === 'resolver') {
|
|
232
|
+
dependsOn.push(...arg.defaultsTo.dependsOn);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Visit account dependencies first.
|
|
236
|
+
this.resolveInstructionDependencies(instruction, arg, dependsOn);
|
|
237
|
+
|
|
238
|
+
return { ...arg, dependsOn };
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
resolveInstructionDependencies(
|
|
242
|
+
instruction: nodes.InstructionNode,
|
|
243
|
+
parent: InstructionNodeInput,
|
|
244
|
+
dependencies: nodes.InstructionNodeInputDependency[]
|
|
245
|
+
): void {
|
|
246
|
+
dependencies.forEach((dependency) => {
|
|
247
|
+
let input: InstructionNodeInput | null = null;
|
|
248
|
+
if (dependency.kind === 'account') {
|
|
249
|
+
const dependencyAccount = instruction.accounts.find(
|
|
250
|
+
({ name }) => name === dependency.name
|
|
251
|
+
);
|
|
252
|
+
if (!dependencyAccount) {
|
|
253
|
+
this.error =
|
|
254
|
+
`Account "${dependency.name}" is not a valid dependency of ${parent.kind} ` +
|
|
255
|
+
`"${parent.name}" in the "${instruction.name}" instruction.`;
|
|
256
|
+
throw new Error(this.error);
|
|
257
|
+
}
|
|
258
|
+
input = { kind: 'account', ...dependencyAccount };
|
|
259
|
+
} else if (dependency.kind === 'arg') {
|
|
260
|
+
const dependencyArg =
|
|
261
|
+
instruction.metadata.argDefaults[dependency.name] ?? null;
|
|
262
|
+
if (dependencyArg) {
|
|
263
|
+
input = {
|
|
264
|
+
kind: 'arg',
|
|
265
|
+
name: dependency.name,
|
|
266
|
+
defaultsTo: dependencyArg,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
if (input) {
|
|
271
|
+
this.resolveInstructionInput(instruction, input);
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
@@ -3,4 +3,4 @@ export * from './GetDefaultValidatorBagVisitor';
|
|
|
3
3
|
export * from './GetDefinedTypeHistogramVisitor';
|
|
4
4
|
export * from './GetNodeInlineStringVisitor';
|
|
5
5
|
export * from './GetNodeTreeStringVisitor';
|
|
6
|
-
export * from './
|
|
6
|
+
export * from './GetResolvedInstructionInputsVisitor';
|
|
@@ -92,6 +92,7 @@ export class CreateSubInstructionsFromEnumArgsVisitor extends TransformNodesVisi
|
|
|
92
92
|
subFields
|
|
93
93
|
)
|
|
94
94
|
),
|
|
95
|
+
node.extraArgs,
|
|
95
96
|
[]
|
|
96
97
|
);
|
|
97
98
|
}
|
|
@@ -101,6 +102,7 @@ export class CreateSubInstructionsFromEnumArgsVisitor extends TransformNodesVisi
|
|
|
101
102
|
node.metadata,
|
|
102
103
|
node.accounts,
|
|
103
104
|
node.args,
|
|
105
|
+
node.extraArgs,
|
|
104
106
|
[...node.subInstructions, ...subInstructions]
|
|
105
107
|
);
|
|
106
108
|
},
|