diff --git a/examples/basic/src/lib.rs b/examples/basic/src/lib.rs index aa721d7f7..2019e2f56 100644 --- a/examples/basic/src/lib.rs +++ b/examples/basic/src/lib.rs @@ -38,7 +38,7 @@ mod example { let leaf = &mut ctx.accounts.leaf; leaf.account.data = data; if let Some(custom) = custom { - leaf.custom = custom; + leaf.account.custom = custom; } Ok(()) } diff --git a/syn/src/lib.rs b/syn/src/lib.rs index 7479867f9..109e9d527 100644 --- a/syn/src/lib.rs +++ b/syn/src/lib.rs @@ -1,6 +1,7 @@ //! DSL syntax tokens. pub mod codegen; +#[cfg(target_arch = "x86")] pub mod idl; pub mod parser; diff --git a/syn/src/parser/mod.rs b/syn/src/parser/mod.rs index b4d994baf..7118a1a81 100644 --- a/syn/src/parser/mod.rs +++ b/syn/src/parser/mod.rs @@ -1,3 +1,4 @@ pub mod anchor; +#[cfg(target_arch = "x86")] pub mod file; pub mod program; diff --git a/ts/src/program.ts b/ts/src/program.ts index ca894bf98..abf71dbb7 100644 --- a/ts/src/program.ts +++ b/ts/src/program.ts @@ -2,7 +2,7 @@ import { PublicKey } from '@solana/web3.js'; import { RpcFactory } from './rpc'; import { Idl } from './idl'; import Coder from './coder'; -import { Rpcs, Ixs } from './rpc'; +import { Rpcs, Ixs, Accounts } from './rpc'; /** * Program is the IDL deserialized representation of a Solana program. @@ -24,6 +24,11 @@ export class Program { */ readonly rpc: Rpcs; + /** + * Async functions to fetch deserialized program accounts from a cluster. + */ + readonly account: Accounts; + /** * Functions to build `TransactionInstruction` objects. */ @@ -37,8 +42,9 @@ export class Program { const coder = new Coder(idl); // Build the dynamic RPC functions. - const [rpcs, ixs] = RpcFactory.build(idl, coder, programId); + const [rpcs, ixs, accounts] = RpcFactory.build(idl, coder, programId); this.rpc = rpcs; this.instruction = ixs; + this.account = accounts; } } diff --git a/ts/src/rpc.ts b/ts/src/rpc.ts index 68160d073..f5e88b2ab 100644 --- a/ts/src/rpc.ts +++ b/ts/src/rpc.ts @@ -9,25 +9,38 @@ import { getProvider } from './'; * Rpcs is a dynamically generated object with rpc methods attached. */ export interface Rpcs { - [key: string]: Rpc; + [key: string]: RpcFn; } /** * Ixs is a dynamically generated object with ix functions attached. */ export interface Ixs { - [key: string]: Ix; + [key: string]: IxFn; } /** - * Rpc is a single rpc method. + * Accounts is a dynamically generated object to fetch any given account + * of a program. */ -export type Rpc = (ctx: RpcContext, ...args: any[]) => Promise; +export interface Accounts { + [key: string]: AccountFn; +} + +/** + * RpcFn is a single rpc method. + */ +export type RpcFn = (ctx: RpcContext, ...args: any[]) => Promise; /** * Ix is a function to create a `TransactionInstruction`. */ -export type Ix = (ctx: RpcContext, ...args: any[]) => TransactionInstruction; +export type IxFn = (ctx: RpcContext, ...args: any[]) => TransactionInstruction; + +/** + * Account is a function returning a deserialized account, given an address. + */ +export type AccountFn = (address: PublicKey) => any; /** * Options for an RPC invocation. @@ -64,10 +77,11 @@ export class RpcFactory { * * @returns an object with all the RPC methods attached. */ - public static build(idl: Idl, coder: Coder, programId: PublicKey): [Rpcs, Ixs] { + public static build(idl: Idl, coder: Coder, programId: PublicKey): [Rpcs, Ixs, Accounts] { const rpcs: Rpcs = {}; const ixFns: Ixs = {}; - idl.instructions.forEach(idlIx=> { + const accountFns: Accounts = {}; + idl.instructions.forEach(idlIx => { // Function to create a raw `TransactionInstruction`. const ix = RpcFactory.buildIx( idlIx, @@ -81,10 +95,28 @@ export class RpcFactory { rpcs[name] = rpc; ixFns[name] = ix; }); - return [rpcs, ixFns]; + + idl.accounts.forEach(idlAccount => { + // todo + const accountFn = async (address: PublicKey): Promise => { + const provider = getProvider(); + if (provider === null) { + throw new Error('Provider not set'); + } + const accountInfo = await provider.connection.getAccountInfo(address); + if (accountInfo === null) { + throw new Error(`Entity does not exist ${address}`); + } + coder.accounts.decode(idlAccount.name, accountInfo.data); + }; + const name = camelCase(idlAccount.name); + accountFns[name] = accountFn; + }); + + return [rpcs, ixFns, accountFns]; } - private static buildIx(idlIx: IdlInstruction, coder: Coder, programId: PublicKey): Ix { + private static buildIx(idlIx: IdlInstruction, coder: Coder, programId: PublicKey): IxFn { if (idlIx.name === '_inner') { throw new IdlError('the _inner name is reserved'); } @@ -109,7 +141,7 @@ export class RpcFactory { return ix; } - private static buildRpc(ixFn: Ix): Rpc { + private static buildRpc(ixFn: IxFn): RpcFn { const rpc = async (ctx: RpcContext, ...args: any[]): Promise => { const tx = new Transaction(); if (ctx.instructions !== undefined) { diff --git a/ts/test.js b/ts/test.js index eaafaa9eb..79fb8433d 100644 --- a/ts/test.js +++ b/ts/test.js @@ -3,10 +3,19 @@ const anchor = require('.'); function test() { const fs = require('fs'); const idl = JSON.parse(fs.readFileSync('../examples/basic/idl.json', 'utf8')); - const program = new anchor.Program(idl); + const pid = '9gzNv4hUB1F3jQQNNcZxxjn1bCjgaTCrucDjFh2i8vc6'; + const program = new anchor.Program(idl, pid); + + /* + const ctx = { + authority: + }; + program.rpc.updateLeaf(); + */ console.log('RPCS', program.rpc); console.log('IXS', program.instruction); + console.log('Accounts', program.account); } test();