|
@@ -1,17 +1,24 @@
|
|
|
import {
|
|
import {
|
|
|
|
|
+ accountValueNode,
|
|
|
argumentValueNode,
|
|
argumentValueNode,
|
|
|
|
|
+ constantPdaSeedNodeFromString,
|
|
|
instructionAccountNode,
|
|
instructionAccountNode,
|
|
|
instructionArgumentNode,
|
|
instructionArgumentNode,
|
|
|
instructionNode,
|
|
instructionNode,
|
|
|
numberTypeNode,
|
|
numberTypeNode,
|
|
|
|
|
+ pdaNode,
|
|
|
|
|
+ pdaSeedValueNode,
|
|
|
|
|
+ pdaValueNode,
|
|
|
programNode,
|
|
programNode,
|
|
|
|
|
+ publicKeyTypeNode,
|
|
|
resolverValueNode,
|
|
resolverValueNode,
|
|
|
|
|
+ variablePdaSeedNode,
|
|
|
} from '@kinobi-so/nodes';
|
|
} from '@kinobi-so/nodes';
|
|
|
import { visit } from '@kinobi-so/visitors-core';
|
|
import { visit } from '@kinobi-so/visitors-core';
|
|
|
import { test } from 'vitest';
|
|
import { test } from 'vitest';
|
|
|
|
|
|
|
|
import { getRenderMapVisitor } from '../src';
|
|
import { getRenderMapVisitor } from '../src';
|
|
|
-import { codeContains, codeDoesNotContain, renderMapContains } from './_setup';
|
|
|
|
|
|
|
+import { codeContains, codeDoesNotContain, renderMapContains, renderMapContainsImports } from './_setup';
|
|
|
|
|
|
|
|
test('it renders instruction accounts that can either be signer or non-signer', async () => {
|
|
test('it renders instruction accounts that can either be signer or non-signer', async () => {
|
|
|
// Given the following instruction with a signer or non-signer account.
|
|
// Given the following instruction with a signer or non-signer account.
|
|
@@ -100,3 +107,148 @@ test('it only renders the args variable on the async function if the sync functi
|
|
|
await codeContains(asyncFunction, ['// Original args.', 'const args = { ...input }']);
|
|
await codeContains(asyncFunction, ['// Original args.', 'const args = { ...input }']);
|
|
|
await codeDoesNotContain(syncFunction, ['// Original args.', 'const args = { ...input }']);
|
|
await codeDoesNotContain(syncFunction, ['// Original args.', 'const args = { ...input }']);
|
|
|
});
|
|
});
|
|
|
|
|
+
|
|
|
|
|
+test('it renders instruction accounts with linked PDAs as default value', async () => {
|
|
|
|
|
+ // Given the following program with a PDA node and an instruction account using it as default value.
|
|
|
|
|
+ const node = programNode({
|
|
|
|
|
+ instructions: [
|
|
|
|
|
+ instructionNode({
|
|
|
|
|
+ accounts: [
|
|
|
|
|
+ instructionAccountNode({ isSigner: true, isWritable: false, name: 'authority' }),
|
|
|
|
|
+ instructionAccountNode({
|
|
|
|
|
+ defaultValue: pdaValueNode('counter', [
|
|
|
|
|
+ pdaSeedValueNode('authority', accountValueNode('authority')),
|
|
|
|
|
+ ]),
|
|
|
|
|
+ isSigner: false,
|
|
|
|
|
+ isWritable: false,
|
|
|
|
|
+ name: 'counter',
|
|
|
|
|
+ }),
|
|
|
|
|
+ ],
|
|
|
|
|
+ name: 'increment',
|
|
|
|
|
+ }),
|
|
|
|
|
+ ],
|
|
|
|
|
+ name: 'counter',
|
|
|
|
|
+ pdas: [
|
|
|
|
|
+ pdaNode({
|
|
|
|
|
+ name: 'counter',
|
|
|
|
|
+ seeds: [
|
|
|
|
|
+ constantPdaSeedNodeFromString('utf8', 'counter'),
|
|
|
|
|
+ variablePdaSeedNode('authority', publicKeyTypeNode()),
|
|
|
|
|
+ ],
|
|
|
|
|
+ }),
|
|
|
|
|
+ ],
|
|
|
|
|
+ publicKey: '1111',
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // When we render it.
|
|
|
|
|
+ const renderMap = visit(node, getRenderMapVisitor());
|
|
|
|
|
+
|
|
|
|
|
+ // Then we expect the following default value to be rendered.
|
|
|
|
|
+ await renderMapContains(renderMap, 'instructions/increment.ts', [
|
|
|
|
|
+ 'if (!accounts.counter.value) { ' +
|
|
|
|
|
+ 'accounts.counter.value = await findCounterPda( { authority: expectAddress ( accounts.authority.value ) } ); ' +
|
|
|
|
|
+ '}',
|
|
|
|
|
+ ]);
|
|
|
|
|
+ renderMapContainsImports(renderMap, 'instructions/increment.ts', { '../pdas': ['findCounterPda'] });
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+test('it renders instruction accounts with inlined PDAs as default value', async () => {
|
|
|
|
|
+ // Given the following instruction with an inlined PDA default value.
|
|
|
|
|
+ const node = programNode({
|
|
|
|
|
+ instructions: [
|
|
|
|
|
+ instructionNode({
|
|
|
|
|
+ accounts: [
|
|
|
|
|
+ instructionAccountNode({ isSigner: true, isWritable: false, name: 'authority' }),
|
|
|
|
|
+ instructionAccountNode({
|
|
|
|
|
+ defaultValue: pdaValueNode(
|
|
|
|
|
+ pdaNode({
|
|
|
|
|
+ name: 'counter',
|
|
|
|
|
+ seeds: [
|
|
|
|
|
+ constantPdaSeedNodeFromString('utf8', 'counter'),
|
|
|
|
|
+ variablePdaSeedNode('authority', publicKeyTypeNode()),
|
|
|
|
|
+ ],
|
|
|
|
|
+ }),
|
|
|
|
|
+ [pdaSeedValueNode('authority', accountValueNode('authority'))],
|
|
|
|
|
+ ),
|
|
|
|
|
+ isSigner: false,
|
|
|
|
|
+ isWritable: false,
|
|
|
|
|
+ name: 'counter',
|
|
|
|
|
+ }),
|
|
|
|
|
+ ],
|
|
|
|
|
+ name: 'increment',
|
|
|
|
|
+ }),
|
|
|
|
|
+ ],
|
|
|
|
|
+ name: 'counter',
|
|
|
|
|
+ publicKey: '1111',
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // When we render it.
|
|
|
|
|
+ const renderMap = visit(node, getRenderMapVisitor());
|
|
|
|
|
+
|
|
|
|
|
+ // Then we expect the following default value to be rendered.
|
|
|
|
|
+ await renderMapContains(renderMap, 'instructions/increment.ts', [
|
|
|
|
|
+ 'if (!accounts.counter.value) { ' +
|
|
|
|
|
+ 'accounts.counter.value = await getProgramDerivedAddress( { ' +
|
|
|
|
|
+ ' programAddress, ' +
|
|
|
|
|
+ ' seeds: [ ' +
|
|
|
|
|
+ " getUtf8Encoder().encode('counter'), " +
|
|
|
|
|
+ ' getAddressEncoder().encode(expectAddress(accounts.authority.value)) ' +
|
|
|
|
|
+ ' ] ' +
|
|
|
|
|
+ '} ); ' +
|
|
|
|
|
+ '}',
|
|
|
|
|
+ ]);
|
|
|
|
|
+ renderMapContainsImports(renderMap, 'instructions/increment.ts', {
|
|
|
|
|
+ '@solana/web3.js': ['getProgramDerivedAddress'],
|
|
|
|
|
+ });
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+test('it renders instruction accounts with inlined PDAs from another program as default value', async () => {
|
|
|
|
|
+ // Given the following instruction with an inlined PDA default value from another program.
|
|
|
|
|
+ const node = programNode({
|
|
|
|
|
+ instructions: [
|
|
|
|
|
+ instructionNode({
|
|
|
|
|
+ accounts: [
|
|
|
|
|
+ instructionAccountNode({ isSigner: true, isWritable: false, name: 'authority' }),
|
|
|
|
|
+ instructionAccountNode({
|
|
|
|
|
+ defaultValue: pdaValueNode(
|
|
|
|
|
+ pdaNode({
|
|
|
|
|
+ name: 'counter',
|
|
|
|
|
+ programId: '2222',
|
|
|
|
|
+ seeds: [
|
|
|
|
|
+ constantPdaSeedNodeFromString('utf8', 'counter'),
|
|
|
|
|
+ variablePdaSeedNode('authority', publicKeyTypeNode()),
|
|
|
|
|
+ ],
|
|
|
|
|
+ }),
|
|
|
|
|
+ [pdaSeedValueNode('authority', accountValueNode('authority'))],
|
|
|
|
|
+ ),
|
|
|
|
|
+ isSigner: false,
|
|
|
|
|
+ isWritable: false,
|
|
|
|
|
+ name: 'counter',
|
|
|
|
|
+ }),
|
|
|
|
|
+ ],
|
|
|
|
|
+ name: 'increment',
|
|
|
|
|
+ }),
|
|
|
|
|
+ ],
|
|
|
|
|
+ name: 'counter',
|
|
|
|
|
+ publicKey: '1111',
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // When we render it.
|
|
|
|
|
+ const renderMap = visit(node, getRenderMapVisitor());
|
|
|
|
|
+
|
|
|
|
|
+ // Then we expect the following default value to be rendered.
|
|
|
|
|
+ await renderMapContains(renderMap, 'instructions/increment.ts', [
|
|
|
|
|
+ 'if (!accounts.counter.value) { ' +
|
|
|
|
|
+ 'accounts.counter.value = await getProgramDerivedAddress( { ' +
|
|
|
|
|
+ " programAddress: '2222' as Address<'2222'>, " +
|
|
|
|
|
+ ' seeds: [ ' +
|
|
|
|
|
+ " getUtf8Encoder().encode('counter'), " +
|
|
|
|
|
+ ' getAddressEncoder().encode(expectAddress(accounts.authority.value)) ' +
|
|
|
|
|
+ ' ] ' +
|
|
|
|
|
+ '} ); ' +
|
|
|
|
|
+ '}',
|
|
|
|
|
+ ]);
|
|
|
|
|
+ renderMapContainsImports(renderMap, 'instructions/increment.ts', {
|
|
|
|
|
+ '@solana/web3.js': ['Address', 'getProgramDerivedAddress'],
|
|
|
|
|
+ });
|
|
|
|
|
+});
|