|
@@ -4,97 +4,267 @@ import Provider from "../provider";
|
|
|
import { Idl, idlAddress, decodeIdlAccount } from "../idl";
|
|
|
import Coder from "../coder";
|
|
|
import NamespaceFactory, {
|
|
|
- Rpcs,
|
|
|
- Ixs,
|
|
|
- Txs,
|
|
|
- Accounts,
|
|
|
- State,
|
|
|
- Simulate,
|
|
|
+ RpcNamespace,
|
|
|
+ InstructionNamespace,
|
|
|
+ TransactionNamespace,
|
|
|
+ AccountNamespace,
|
|
|
+ StateNamespace,
|
|
|
+ SimulateNamespace,
|
|
|
} from "./namespace";
|
|
|
import { getProvider } from "../";
|
|
|
import { decodeUtf8 } from "../utils";
|
|
|
import { EventParser } from "./event";
|
|
|
|
|
|
/**
|
|
|
- * Program is the IDL deserialized representation of a Solana program.
|
|
|
+ * ## Program
|
|
|
+ *
|
|
|
+ * Program provides the IDL deserialized client representation of an Anchor
|
|
|
+ * program.
|
|
|
+ *
|
|
|
+ * This API is the one stop shop for all things related to communicating with
|
|
|
+ * on-chain programs. Among other things, one can send transactions, fetch
|
|
|
+ * deserialized accounts, decode instruction data, subscribe to account
|
|
|
+ * changes, and listen to events.
|
|
|
+ *
|
|
|
+ * In addition to field accessors and methods, the object provides a set of
|
|
|
+ * dynamically generated properties (internally referred to as namespaces) that
|
|
|
+ * map one-to-one to program instructions and accounts. These namespaces
|
|
|
+ * generally can be used as follows:
|
|
|
+ *
|
|
|
+ * ```javascript
|
|
|
+ * program.<namespace>.<program-specific-field>
|
|
|
+ * ```
|
|
|
+ *
|
|
|
+ * API specifics are namespace dependent. The examples used in the documentation
|
|
|
+ * below will refer to the two counter examples found
|
|
|
+ * [here](https://project-serum.github.io/anchor/ts/#examples).
|
|
|
*/
|
|
|
export class Program {
|
|
|
/**
|
|
|
- * Address of the program.
|
|
|
+ * Async methods to send signed transactions invoking *non*-state methods
|
|
|
+ * on an Anchor program.
|
|
|
+ *
|
|
|
+ * ## rpc
|
|
|
+ *
|
|
|
+ * ```javascript
|
|
|
+ * program.rpc.<method>(...args, ctx);
|
|
|
+ * ```
|
|
|
+ *
|
|
|
+ * ## Parameters
|
|
|
+ *
|
|
|
+ * 1. `args` - The positional arguments for the program. The type and number
|
|
|
+ * of these arguments depend on the program being used.
|
|
|
+ * 2. `ctx` - [[Context]] non-argument parameters to pass to the method.
|
|
|
+ * Always the last parameter in the method call.
|
|
|
+ *
|
|
|
+ * ## Example
|
|
|
+ *
|
|
|
+ * To send a transaction invoking the `increment` method above,
|
|
|
+ *
|
|
|
+ * ```javascript
|
|
|
+ * const txSignature = await program.rpc.increment({
|
|
|
+ * accounts: {
|
|
|
+ * counter,
|
|
|
+ * authority,
|
|
|
+ * },
|
|
|
+ * });
|
|
|
+ * ```
|
|
|
*/
|
|
|
- readonly programId: PublicKey;
|
|
|
+ readonly rpc: RpcNamespace;
|
|
|
|
|
|
/**
|
|
|
- * IDL describing this program's interface.
|
|
|
+ * Async functions to fetch deserialized program accounts from a cluster.
|
|
|
+ *
|
|
|
+ * ## account
|
|
|
+ *
|
|
|
+ * ```javascript
|
|
|
+ * program.account.<account>(publicKey);
|
|
|
+ * ```
|
|
|
+ *
|
|
|
+ * ## Parameters
|
|
|
+ *
|
|
|
+ * 1. `publicKey` - The [[PublicKey]] of the account.
|
|
|
+ *
|
|
|
+ * ## Example
|
|
|
+ *
|
|
|
+ * To fetch a `Counter` object from the above example,
|
|
|
+ *
|
|
|
+ * ```javascript
|
|
|
+ * const counter = await program.account.counter(publicKey);
|
|
|
+ * ```
|
|
|
*/
|
|
|
- readonly idl: Idl;
|
|
|
+ readonly account: AccountNamespace;
|
|
|
|
|
|
/**
|
|
|
- * Async functions to invoke instructions against an Anchor program.
|
|
|
+ * Functions to build [[TransactionInstruction]] objects for program methods.
|
|
|
+ *
|
|
|
+ * ## instruction
|
|
|
+ *
|
|
|
+ * ```javascript
|
|
|
+ * program.instruction.<method>(...args, ctx);
|
|
|
+ * ```
|
|
|
+ *
|
|
|
+ * ## Parameters
|
|
|
+ *
|
|
|
+ * 1. `args` - The positional arguments for the program. The type and number
|
|
|
+ * of these arguments depend on the program being used.
|
|
|
+ * 2. `ctx` - [[Context]] non-argument parameters to pass to the method.
|
|
|
+ * Always the last parameter in the method call.
|
|
|
+ *
|
|
|
+ * ## Example
|
|
|
+ *
|
|
|
+ * To create an instruction for the `increment` method above,
|
|
|
+ *
|
|
|
+ * ```javascript
|
|
|
+ * const tx = await program.instruction.increment({
|
|
|
+ * accounts: {
|
|
|
+ * counter,
|
|
|
+ * },
|
|
|
+ * });
|
|
|
+ * ```
|
|
|
*/
|
|
|
- readonly rpc: Rpcs;
|
|
|
+ readonly instruction: InstructionNamespace;
|
|
|
|
|
|
/**
|
|
|
- * Async functions to fetch deserialized program accounts from a cluster.
|
|
|
+ * Functions to build [[Transaction]] objects.
|
|
|
+ *
|
|
|
+ * ## transaction
|
|
|
+ *
|
|
|
+ * ```javascript
|
|
|
+ * program.transaction.<method>(...args, ctx);
|
|
|
+ * ```
|
|
|
+ *
|
|
|
+ * ## Parameters
|
|
|
+ *
|
|
|
+ * 1. `args` - The positional arguments for the program. The type and number
|
|
|
+ * of these arguments depend on the program being used.
|
|
|
+ * 2. `ctx` - [[Context]] non-argument parameters to pass to the method.
|
|
|
+ * Always the last parameter in the method call.
|
|
|
+ *
|
|
|
+ * ## Example
|
|
|
+ *
|
|
|
+ * To create an instruction for the `increment` method above,
|
|
|
+ *
|
|
|
+ * ```javascript
|
|
|
+ * const tx = await program.transaction.increment({
|
|
|
+ * accounts: {
|
|
|
+ * counter,
|
|
|
+ * },
|
|
|
+ * });
|
|
|
+ * ```
|
|
|
*/
|
|
|
- readonly account: Accounts;
|
|
|
+ readonly transaction: TransactionNamespace;
|
|
|
|
|
|
/**
|
|
|
- * Functions to build `TransactionInstruction` objects.
|
|
|
+ * Async functions to simulate instructions against an Anchor program,
|
|
|
+ * returning a list of deserialized events *and* raw program logs.
|
|
|
+ *
|
|
|
+ * One can use this to read data calculated from a program on chain, by
|
|
|
+ * emitting an event in the program and reading the emitted event client side
|
|
|
+ * via the `simulate` namespace.
|
|
|
+ *
|
|
|
+ * ## simulate
|
|
|
+ *
|
|
|
+ * ```javascript
|
|
|
+ * program.simulate.<method>(...args, ctx);
|
|
|
+ * ```
|
|
|
+ *
|
|
|
+ * ## Parameters
|
|
|
+ *
|
|
|
+ * 1. `args` - The positional arguments for the program. The type and number
|
|
|
+ * of these arguments depend on the program being used.
|
|
|
+ * 2. `ctx` - [[Context]] non-argument parameters to pass to the method.
|
|
|
+ * Always the last parameter in the method call.
|
|
|
+ *
|
|
|
+ * ## Example
|
|
|
+ *
|
|
|
+ * To simulate the `increment` method above,
|
|
|
+ *
|
|
|
+ * ```javascript
|
|
|
+ * const tx = await program.simulate.increment({
|
|
|
+ * accounts: {
|
|
|
+ * counter,
|
|
|
+ * },
|
|
|
+ * });
|
|
|
+ * ```
|
|
|
*/
|
|
|
- readonly instruction: Ixs;
|
|
|
+ readonly simulate: SimulateNamespace;
|
|
|
|
|
|
/**
|
|
|
- * Functions to build `Transaction` objects.
|
|
|
+ * Object with state account accessors and rpcs.
|
|
|
*/
|
|
|
- readonly transaction: Txs;
|
|
|
+ readonly state: StateNamespace;
|
|
|
|
|
|
/**
|
|
|
- * Async functions to simulate instructions against an Anchor program.
|
|
|
+ * Address of the program.
|
|
|
*/
|
|
|
- readonly simulate: Simulate;
|
|
|
+ public get programId(): PublicKey {
|
|
|
+ return this._programId;
|
|
|
+ }
|
|
|
+ private _programId: PublicKey;
|
|
|
|
|
|
/**
|
|
|
- * Coder for serializing rpc requests.
|
|
|
+ * IDL defining the program's interface.
|
|
|
*/
|
|
|
- readonly coder: Coder;
|
|
|
+ public get idl(): Idl {
|
|
|
+ return this._idl;
|
|
|
+ }
|
|
|
+ private _idl: Idl;
|
|
|
|
|
|
/**
|
|
|
- * Object with state account accessors and rpcs.
|
|
|
+ * Coder for serializing requests.
|
|
|
*/
|
|
|
- readonly state: State;
|
|
|
+ public get coder(): Coder {
|
|
|
+ return this._coder;
|
|
|
+ }
|
|
|
+ private _coder: Coder;
|
|
|
|
|
|
/**
|
|
|
* Wallet and network provider.
|
|
|
*/
|
|
|
- readonly provider: Provider;
|
|
|
+ public get provider(): Provider {
|
|
|
+ return this._provider;
|
|
|
+ }
|
|
|
+ private _provider: Provider;
|
|
|
|
|
|
+ /**
|
|
|
+ * @param idl The interface definition.
|
|
|
+ * @param programId The on-chain address of the program.
|
|
|
+ * @param provider The network and wallet context to use. If not provided
|
|
|
+ * then uses [[getProvider]].
|
|
|
+ */
|
|
|
public constructor(idl: Idl, programId: PublicKey, provider?: Provider) {
|
|
|
- this.idl = idl;
|
|
|
- this.programId = programId;
|
|
|
- this.provider = provider ?? getProvider();
|
|
|
-
|
|
|
- // Build the serializer.
|
|
|
- const coder = new Coder(idl);
|
|
|
-
|
|
|
- // Build the dynamic namespaces.
|
|
|
- const [rpcs, ixs, txs, accounts, state, simulate] = NamespaceFactory.build(
|
|
|
- idl,
|
|
|
- coder,
|
|
|
- programId,
|
|
|
- this.provider
|
|
|
- );
|
|
|
- this.rpc = rpcs;
|
|
|
- this.instruction = ixs;
|
|
|
- this.transaction = txs;
|
|
|
- this.account = accounts;
|
|
|
- this.coder = coder;
|
|
|
+ // Fields.
|
|
|
+ this._idl = idl;
|
|
|
+ this._programId = programId;
|
|
|
+ this._provider = provider ?? getProvider();
|
|
|
+ this._coder = new Coder(idl);
|
|
|
+
|
|
|
+ // Dynamic namespaces.
|
|
|
+ const [
|
|
|
+ rpc,
|
|
|
+ instruction,
|
|
|
+ transaction,
|
|
|
+ account,
|
|
|
+ state,
|
|
|
+ simulate,
|
|
|
+ ] = NamespaceFactory.build(idl, this._coder, programId, this._provider);
|
|
|
+ this.rpc = rpc;
|
|
|
+ this.instruction = instruction;
|
|
|
+ this.transaction = transaction;
|
|
|
+ this.account = account;
|
|
|
this.state = state;
|
|
|
this.simulate = simulate;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Generates a Program client by fetching the IDL from chain.
|
|
|
+ * Generates a Program client by fetching the IDL from the network.
|
|
|
+ *
|
|
|
+ * In order to use this method, an IDL must have been previously initialized
|
|
|
+ * via the anchor CLI's `anchor idl init` command.
|
|
|
+ *
|
|
|
+ * @param programId The on-chain address of the program.
|
|
|
+ * @param provider The network and wallet context.
|
|
|
*/
|
|
|
public static async at(programId: PublicKey, provider?: Provider) {
|
|
|
const idl = await Program.fetchIdl(programId, provider);
|
|
@@ -103,6 +273,12 @@ export class Program {
|
|
|
|
|
|
/**
|
|
|
* Fetches an idl from the blockchain.
|
|
|
+ *
|
|
|
+ * In order to use this method, an IDL must have been previously initialized
|
|
|
+ * via the anchor CLI's `anchor idl init` command.
|
|
|
+ *
|
|
|
+ * @param programId The on-chain address of the program.
|
|
|
+ * @param provider The network and wallet context.
|
|
|
*/
|
|
|
public static async fetchIdl(programId: PublicKey, provider?: Provider) {
|
|
|
provider = provider ?? getProvider();
|
|
@@ -116,13 +292,21 @@ export class Program {
|
|
|
|
|
|
/**
|
|
|
* Invokes the given callback everytime the given event is emitted.
|
|
|
+ *
|
|
|
+ * @param eventName The PascalCase name of the event, provided by the IDL.
|
|
|
+ * @param callback The function to invoke whenever the event is emitted from
|
|
|
+ * program logs.
|
|
|
*/
|
|
|
public addEventListener(
|
|
|
eventName: string,
|
|
|
callback: (event: any, slot: number) => void
|
|
|
): number {
|
|
|
- const eventParser = new EventParser(this.coder, this.programId, this.idl);
|
|
|
- return this.provider.connection.onLogs(this.programId, (logs, ctx) => {
|
|
|
+ const eventParser = new EventParser(
|
|
|
+ this._coder,
|
|
|
+ this._programId,
|
|
|
+ this._idl
|
|
|
+ );
|
|
|
+ return this._provider.connection.onLogs(this._programId, (logs, ctx) => {
|
|
|
if (logs.err) {
|
|
|
console.error(logs);
|
|
|
return;
|
|
@@ -135,7 +319,10 @@ export class Program {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Unsubscribes from the given event listener.
|
|
|
+ */
|
|
|
public async removeEventListener(listener: number): Promise<void> {
|
|
|
- return this.provider.connection.removeOnLogsListener(listener);
|
|
|
+ return this._provider.connection.removeOnLogsListener(listener);
|
|
|
}
|
|
|
}
|