Browse Source

ts: Add instruction method to state namespace

Armani Ferrante 4 years ago
parent
commit
627c275e9c
2 changed files with 33 additions and 21 deletions
  1. 1 0
      CHANGELOG.md
  2. 32 21
      ts/src/rpc.ts

+ 1 - 0
CHANGELOG.md

@@ -18,6 +18,7 @@ incremented for features.
 * spl: Add shared memory api.
 * lang/attribute/access-control: Allow specifying multiple modifier functions.
 * lang/syn: Allow state structs that don't have a ctor or impl block (just trait implementations).
+* ts: Add instruction method to state namespace.
 
 ## [0.2.0] - 2021-02-08
 

+ 32 - 21
ts/src/rpc.ts

@@ -24,8 +24,6 @@ import {
 import { IdlError, ProgramError } from "./error";
 import Coder, {
   ACCOUNT_DISCRIMINATOR_SIZE,
-  SIGHASH_STATE_NAMESPACE,
-  SIGHASH_GLOBAL_NAMESPACE,
   accountDiscriminator,
   stateDiscriminator,
   accountSize,
@@ -68,8 +66,7 @@ export type RpcFn = (...args: any[]) => Promise<TransactionSignature>;
 /**
  * Ix is a function to create a `TransactionInstruction` generated from an IDL.
  */
-export type IxFn = IxProps & ((...args: any[]) => TransactionInstruction);
-
+export type IxFn = IxProps & ((...args: any[]) => any);
 type IxProps = {
   accounts: (ctx: RpcAccounts) => any;
 };
@@ -220,23 +217,36 @@ export class RpcFactory {
 
     // Namespace with all rpc functions.
     const rpc: Rpcs = {};
+    const ix: Ixs = {};
+
     idl.state.methods.forEach((m: IdlStateMethod) => {
-      rpc[m.name] = async (...args: any[]): Promise<TransactionSignature> => {
+      const accounts = async (accounts: RpcAccounts): Promise<any> => {
+        const keys = await stateInstructionKeys(
+          programId,
+          provider,
+          m,
+          accounts
+        );
+        return keys.concat(RpcFactory.accountsArray(accounts, m.accounts));
+      };
+      const ixFn = async (...args: any[]): Promise<TransactionInstruction> => {
         const [ixArgs, ctx] = splitArgsAndCtx(m, [...args]);
-        const keys = await stateInstructionKeys(programId, provider, m, ctx);
+        return new TransactionInstruction({
+          keys: await accounts(ctx.accounts),
+          programId,
+          data: coder.instruction.encodeState(
+            m.name,
+            toInstruction(m, ...ixArgs)
+          ),
+        });
+      };
+      ixFn["accounts"] = accounts;
+      ix[m.name] = ixFn;
+
+      rpc[m.name] = async (...args: any[]): Promise<TransactionSignature> => {
+        const [_, ctx] = splitArgsAndCtx(m, [...args]);
         const tx = new Transaction();
-        tx.add(
-          new TransactionInstruction({
-            keys: keys.concat(
-              RpcFactory.accountsArray(ctx.accounts, m.accounts)
-            ),
-            programId,
-            data: coder.instruction.encodeState(
-              m.name,
-              toInstruction(m, ...ixArgs)
-            ),
-          })
-        );
+        tx.add(await ix[m.name](...args));
         try {
           const txSig = await provider.send(tx, ctx.signers, ctx.options);
           return txSig;
@@ -249,8 +259,9 @@ export class RpcFactory {
         }
       };
     });
-    state["rpc"] = rpc;
 
+    state["rpc"] = rpc;
+    state["instruction"] = ix;
     // Calculates the address of the program's global state object account.
     state["address"] = async (): Promise<PublicKey> =>
       programStateAddress(programId);
@@ -655,7 +666,7 @@ async function stateInstructionKeys(
   programId: PublicKey,
   provider: Provider,
   m: IdlStateMethod,
-  ctx: RpcContext
+  accounts: RpcAccounts
 ) {
   if (m.name === "new") {
     // Ctor `new` method.
@@ -689,7 +700,7 @@ async function stateInstructionKeys(
       },
     ];
   } else {
-    validateAccounts(m.accounts, ctx.accounts);
+    validateAccounts(m.accounts, accounts);
     return [
       {
         pubkey: await programStateAddress(programId),