diff --git a/CHANGELOG.md b/CHANGELOG.md index 66e54b5eea..ad91b52e5c 100644 --- a/CHANGELOG.md +++ b/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 diff --git a/ts/src/rpc.ts b/ts/src/rpc.ts index c4bc06fdc6..a259916b94 100644 --- a/ts/src/rpc.ts +++ b/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; /** * 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 => { + const accounts = async (accounts: RpcAccounts): Promise => { + const keys = await stateInstructionKeys( + programId, + provider, + m, + accounts + ); + return keys.concat(RpcFactory.accountsArray(accounts, m.accounts)); + }; + const ixFn = async (...args: any[]): Promise => { 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 => { + 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 => 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),