anchor/ts/src/program.ts

112 lines
2.8 KiB
TypeScript

import { PublicKey } from "@solana/web3.js";
import { inflate } from "pako";
import Provider from "./provider";
import { RpcFactory } from "./rpc";
import { Idl, idlAddress, decodeIdlAccount } from "./idl";
import Coder from "./coder";
import { Rpcs, Ixs, Txs, Accounts, State } from "./rpc";
import { getProvider } from "./";
/**
* Program is the IDL deserialized representation of a Solana program.
*/
export class Program {
/**
* Address of the program.
*/
readonly programId: PublicKey;
/**
* IDL describing this program's interface.
*/
readonly idl: Idl;
/**
* Async functions to invoke instructions against a Solana priogram running
* on a cluster.
*/
readonly rpc: Rpcs;
/**
* Async functions to fetch deserialized program accounts from a cluster.
*/
readonly account: Accounts;
/**
* Functions to build `TransactionInstruction` objects.
*/
readonly instruction: Ixs;
/**
* Functions to build `Transaction` objects.
*/
readonly transaction: Txs;
/**
* Coder for serializing rpc requests.
*/
readonly coder: Coder;
/**
* Object with state account accessors and rpcs.
*/
readonly state: State;
/**
* Wallet and network provider.
*/
readonly provider: Provider;
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 RPC functions.
const [rpcs, ixs, txs, accounts, state] = RpcFactory.build(
idl,
coder,
programId,
this.provider
);
this.rpc = rpcs;
this.instruction = ixs;
this.transaction = txs;
this.account = accounts;
this.coder = coder;
this.state = state;
}
/**
* Generates a Program client by fetching the IDL from chain.
*/
public static async at(programId: PublicKey, provider?: Provider) {
const idl = await Program.fetchIdl(programId, provider);
return new Program(idl, programId, provider);
}
/**
* Fetches an idl from the blockchain.
*/
public static async fetchIdl(programId: PublicKey, provider?: Provider) {
provider = provider ?? getProvider();
const address = await idlAddress(programId);
const accountInfo = await provider.connection.getAccountInfo(address);
// Chop off account discriminator.
let idlAccount = decodeIdlAccount(accountInfo.data.slice(8));
const inflatedIdl = inflate(idlAccount.data);
return JSON.parse(decodeUtf8(inflatedIdl));
}
}
function decodeUtf8(array: Uint8Array): string {
const decoder =
typeof TextDecoder === "undefined"
? new (require("util").TextDecoder)("utf-8") // Node.
: new TextDecoder("utf-8"); // Browser.
return decoder.decode(array);
}