getResolvedInstructionInputsVisitor.test.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import {
  2. accountValueNode,
  3. instructionAccountNode,
  4. instructionArgumentNode,
  5. instructionNode,
  6. numberTypeNode,
  7. publicKeyTypeNode,
  8. } from '@kinobi-so/nodes';
  9. import test from 'ava';
  10. import { getResolvedInstructionInputsVisitor, visit } from '../src/index.js';
  11. test('it returns all instruction accounts in order of resolution', t => {
  12. // Given the following instruction node with an account that defaults to another account.
  13. const node = instructionNode({
  14. accounts: [
  15. instructionAccountNode({
  16. defaultValue: accountValueNode('authority'),
  17. isSigner: true,
  18. isWritable: false,
  19. name: 'owner',
  20. }),
  21. instructionAccountNode({
  22. isSigner: true,
  23. isWritable: false,
  24. name: 'authority',
  25. }),
  26. ],
  27. name: 'myInstruction',
  28. });
  29. // When we get its resolved inputs.
  30. const result = visit(node, getResolvedInstructionInputsVisitor());
  31. // Then we expect the accounts to be in order of resolution.
  32. t.deepEqual(result, [
  33. {
  34. ...node.accounts[1],
  35. dependsOn: [],
  36. isPda: false,
  37. resolvedIsOptional: false,
  38. resolvedIsSigner: true,
  39. },
  40. {
  41. ...node.accounts[0],
  42. dependsOn: [accountValueNode('authority')],
  43. isPda: false,
  44. resolvedIsOptional: false,
  45. resolvedIsSigner: true,
  46. },
  47. ]);
  48. });
  49. test('it sets the resolved signer to either when a non signer defaults to a signer account', t => {
  50. // Given the following instruction node such that a non signer account defaults to a signer account.
  51. const node = instructionNode({
  52. accounts: [
  53. instructionAccountNode({
  54. defaultValue: accountValueNode('authority'),
  55. isSigner: false,
  56. isWritable: false,
  57. name: 'owner',
  58. }),
  59. instructionAccountNode({
  60. isSigner: true,
  61. isWritable: false,
  62. name: 'authority',
  63. }),
  64. ],
  65. name: 'myInstruction',
  66. });
  67. // When we get its resolved inputs.
  68. const result = visit(node, getResolvedInstructionInputsVisitor());
  69. // Then we expect the resolved signer to be either for the non signer account.
  70. t.deepEqual(result[1], {
  71. ...node.accounts[0],
  72. dependsOn: [accountValueNode('authority')],
  73. isPda: false,
  74. resolvedIsOptional: false,
  75. resolvedIsSigner: 'either',
  76. });
  77. });
  78. test('it sets the resolved signer to either when a signer defaults to a non signer account', t => {
  79. // Given the following instruction node such that a signer account defaults to a non signer account.
  80. const node = instructionNode({
  81. accounts: [
  82. instructionAccountNode({
  83. defaultValue: accountValueNode('authority'),
  84. isSigner: true,
  85. isWritable: false,
  86. name: 'owner',
  87. }),
  88. instructionAccountNode({
  89. isSigner: false,
  90. isWritable: false,
  91. name: 'authority',
  92. }),
  93. ],
  94. name: 'myInstruction',
  95. });
  96. // When we get its resolved inputs.
  97. const result = visit(node, getResolvedInstructionInputsVisitor());
  98. // Then we expect the resolved signer to be either for the signer account.
  99. t.deepEqual(result[1], {
  100. ...node.accounts[0],
  101. dependsOn: [accountValueNode('authority')],
  102. isPda: false,
  103. resolvedIsOptional: false,
  104. resolvedIsSigner: 'either',
  105. });
  106. });
  107. test('it includes instruction data arguments with default values', t => {
  108. // Given the following instruction node with two arguments such that:
  109. // - The first argument defaults to an account.
  110. // - The second argument has no default value.
  111. const node = instructionNode({
  112. accounts: [
  113. instructionAccountNode({
  114. isSigner: true,
  115. isWritable: false,
  116. name: 'owner',
  117. }),
  118. ],
  119. arguments: [
  120. instructionArgumentNode({
  121. defaultValue: accountValueNode('owner'),
  122. name: 'ownerArg',
  123. type: publicKeyTypeNode(),
  124. }),
  125. instructionArgumentNode({
  126. name: 'argWithoutDefaults',
  127. type: numberTypeNode('u8'),
  128. }),
  129. ],
  130. name: 'myInstruction',
  131. });
  132. // When we get its resolved inputs.
  133. const result = visit(node, getResolvedInstructionInputsVisitor());
  134. // Then we expect the following inputs.
  135. t.deepEqual(result, [
  136. {
  137. ...node.accounts[0],
  138. dependsOn: [],
  139. isPda: false,
  140. resolvedIsOptional: false,
  141. resolvedIsSigner: true,
  142. },
  143. {
  144. ...node.arguments[0],
  145. dependsOn: [accountValueNode('owner')],
  146. },
  147. ]);
  148. // And the argument without default value is not included.
  149. t.false(result.some(input => input.name === 'argWithoutDefaults'));
  150. });
  151. test('it includes instruction extra arguments with default values', t => {
  152. // Given the following instruction node with two extra arguments such that:
  153. // - The first argument defaults to an account.
  154. // - The second argument has no default value.
  155. const node = instructionNode({
  156. accounts: [
  157. instructionAccountNode({
  158. isSigner: true,
  159. isWritable: false,
  160. name: 'owner',
  161. }),
  162. ],
  163. extraArguments: [
  164. instructionArgumentNode({
  165. defaultValue: accountValueNode('owner'),
  166. name: 'ownerArg',
  167. type: publicKeyTypeNode(),
  168. }),
  169. instructionArgumentNode({
  170. name: 'argWithoutDefaults',
  171. type: numberTypeNode('u8'),
  172. }),
  173. ],
  174. name: 'myInstruction',
  175. });
  176. // When we get its resolved inputs.
  177. const result = visit(node, getResolvedInstructionInputsVisitor());
  178. // Then we expect the following inputs.
  179. t.deepEqual(result, [
  180. {
  181. ...node.accounts[0],
  182. dependsOn: [],
  183. isPda: false,
  184. resolvedIsOptional: false,
  185. resolvedIsSigner: true,
  186. },
  187. {
  188. ...node.extraArguments![0],
  189. dependsOn: [accountValueNode('owner')],
  190. },
  191. ]);
  192. // And the argument without default value is not included.
  193. t.false(result.some(input => input.name === 'argWithoutDefaults'));
  194. });
  195. test('it returns an empty array for empty instructions', t => {
  196. // Given the following empty instruction node.
  197. const node = instructionNode({ name: 'myInstruction' });
  198. // When we get its resolved inputs.
  199. const result = visit(node, getResolvedInstructionInputsVisitor());
  200. // Then we expect an empty array.
  201. t.deepEqual(result, []);
  202. });