Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ts: builder api #1324

Merged
merged 4 commits into from
Jan 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ incremented for features.

* lang: Add `seeds::program` constraint for specifying which program_id to use when deriving PDAs.([#1197](https://github.com/project-serum/anchor/pull/1197))
* ts: Remove error logging in the event parser when log websocket encounters a program error. ([#1313](https://github.com/project-serum/anchor/pull/1313))
* ts: Add new `methods` namespace to the program client, introducing a more ergonomic builder API ([#1324](https://github.com/project-serum/anchor/pull/1324)).

### Breaking

Expand Down
2 changes: 1 addition & 1 deletion cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1021,7 +1021,7 @@ fn docker_build_bpf(
println!(
"Building {} manifest: {:?}",
binary_name,
manifest_path.display().to_string()
manifest_path.display()
);

// Execute the build.
Expand Down
113 changes: 58 additions & 55 deletions tests/cfo/tests/cfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,29 +225,24 @@ describe("cfo", () => {
stake: stakeBump,
treasury: treasuryBump,
};
await program.rpc.createOfficer(
bumps,
distribution,
registrar,
msrmRegistrar,
{
accounts: {
officer,
srmVault,
usdcVault,
stake,
treasury,
srmMint: ORDERBOOK_ENV.mintA,
usdcMint: ORDERBOOK_ENV.usdc,
authority: program.provider.wallet.publicKey,
dexProgram: DEX_PID,
swapProgram: SWAP_PID,
tokenProgram: TOKEN_PID,
systemProgram: SystemProgram.programId,
rent: SYSVAR_RENT_PUBKEY,
},
}
);
await program.methods
.createOfficer(bumps, distribution, registrar, msrmRegistrar)
.accounts({
officer,
srmVault,
usdcVault,
stake,
treasury,
srmMint: ORDERBOOK_ENV.mintA,
usdcMint: ORDERBOOK_ENV.usdc,
authority: program.provider.wallet.publicKey,
dexProgram: DEX_PID,
swapProgram: SWAP_PID,
tokenProgram: TOKEN_PID,
systemProgram: SystemProgram.programId,
rent: SYSVAR_RENT_PUBKEY,
})
.rpc();

officerAccount = await program.account.officer.fetch(officer);
assert.ok(
Expand All @@ -260,34 +255,36 @@ describe("cfo", () => {
});

it("Creates a token account for the officer associated with the market", async () => {
await program.rpc.createOfficerToken(bBump, {
accounts: {
await program.methods
.createOfficerToken(bBump)
.accounts({
officer,
token: bVault,
mint: ORDERBOOK_ENV.mintB,
payer: program.provider.wallet.publicKey,
systemProgram: SystemProgram.programId,
tokenProgram: TOKEN_PID,
rent: SYSVAR_RENT_PUBKEY,
},
});
})
.rpc();
const tokenAccount = await B_TOKEN_CLIENT.getAccountInfo(bVault);
assert.ok(tokenAccount.state === 1);
assert.ok(tokenAccount.isInitialized);
});

it("Creates an open orders account for the officer", async () => {
await program.rpc.createOfficerOpenOrders(openOrdersBump, {
accounts: {
await program.methods
.createOfficerOpenOrders(openOrdersBump)
.accounts({
officer,
openOrders,
payer: program.provider.wallet.publicKey,
dexProgram: DEX_PID,
systemProgram: SystemProgram.programId,
rent: SYSVAR_RENT_PUBKEY,
market: ORDERBOOK_ENV.marketA.address,
},
});
})
.rpc();
await program.rpc.createOfficerOpenOrders(openOrdersBumpB, {
accounts: {
officer,
Expand All @@ -310,8 +307,9 @@ describe("cfo", () => {
program.provider,
sweepVault
);
await program.rpc.sweepFees({
accounts: {
await program.methods
.sweepFees()
.accounts({
officer,
sweepVault,
mint: ORDERBOOK_ENV.usdc,
Expand All @@ -323,8 +321,8 @@ describe("cfo", () => {
dexProgram: DEX_PID,
tokenProgram: TOKEN_PID,
},
},
});
})
.rpc();
const afterTokenAccount = await serumCmn.getTokenAccount(
program.provider,
sweepVault
Expand All @@ -336,26 +334,28 @@ describe("cfo", () => {
});

it("Creates a market auth token", async () => {
await program.rpc.authorizeMarket(marketAuthBump, {
accounts: {
await program.methods
.authorizeMarket(marketAuthBump)
.accounts({
officer,
authority: program.provider.wallet.publicKey,
marketAuth,
payer: program.provider.wallet.publicKey,
market: ORDERBOOK_ENV.marketA.address,
systemProgram: SystemProgram.programId,
},
});
await program.rpc.authorizeMarket(marketAuthBumpB, {
accounts: {
})
.rpc();
await program.methods
.authorizeMarket(marketAuthBumpB)
.accounts({
officer,
authority: program.provider.wallet.publicKey,
marketAuth: marketAuthB,
payer: program.provider.wallet.publicKey,
market: ORDERBOOK_ENV.marketB.address,
systemProgram: SystemProgram.programId,
},
});
})
.rpc();
});

it("Transfers into the mintB vault", async () => {
Expand All @@ -378,8 +378,9 @@ describe("cfo", () => {
quoteDecimals: 6,
strict: false,
};
await program.rpc.swapToUsdc(minExchangeRate, {
accounts: {
await program.methods
.swapToUsdc(minExchangeRate)
.accounts({
officer,
market: {
market: marketBClient.address,
Expand All @@ -402,8 +403,8 @@ describe("cfo", () => {
tokenProgram: TOKEN_PID,
instructions: SYSVAR_INSTRUCTIONS_PUBKEY,
rent: SYSVAR_RENT_PUBKEY,
},
});
})
.rpc();

const bVaultAfter = await B_TOKEN_CLIENT.getAccountInfo(bVault);
const usdcVaultAfter = await USDC_TOKEN_CLIENT.getAccountInfo(usdcVault);
Expand All @@ -424,8 +425,9 @@ describe("cfo", () => {
quoteDecimals: 6,
strict: false,
};
await program.rpc.swapToSrm(minExchangeRate, {
accounts: {
await program.methods
.swapToSrm(minExchangeRate)
.accounts({
officer,
market: {
market: marketAClient.address,
Expand All @@ -449,8 +451,8 @@ describe("cfo", () => {
tokenProgram: TOKEN_PID,
instructions: SYSVAR_INSTRUCTIONS_PUBKEY,
rent: SYSVAR_RENT_PUBKEY,
},
});
})
.rpc();

const srmVaultAfter = await SRM_TOKEN_CLIENT.getAccountInfo(srmVault);
const usdcVaultAfter = await USDC_TOKEN_CLIENT.getAccountInfo(usdcVault);
Expand All @@ -467,17 +469,18 @@ describe("cfo", () => {
const stakeBefore = await SRM_TOKEN_CLIENT.getAccountInfo(stake);
const mintInfoBefore = await SRM_TOKEN_CLIENT.getMintInfo();

await program.rpc.distribute({
accounts: {
await program.methods
.distribute()
.accounts({
officer,
treasury,
stake,
srmVault,
srmMint: ORDERBOOK_ENV.mintA,
tokenProgram: TOKEN_PID,
dexProgram: DEX_PID,
},
});
})
.rpc();

const srmVaultAfter = await SRM_TOKEN_CLIENT.getAccountInfo(srmVault);
const treasuryAfter = await SRM_TOKEN_CLIENT.getAccountInfo(treasury);
Expand Down
9 changes: 9 additions & 0 deletions ts/src/program/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import NamespaceFactory, {
AccountNamespace,
StateClient,
SimulateNamespace,
MethodsNamespace,
} from "./namespace/index.js";
import { utf8 } from "../utils/bytes/index.js";
import { EventManager } from "./event.js";
Expand Down Expand Up @@ -206,6 +207,12 @@ export class Program<IDL extends Idl = Idl> {
*/
readonly state?: StateClient<IDL>;

/**
* The namespace provides a builder API for all APIs on the program.
* This is an alternative to using namespace the other namespaces..
*/
readonly methods: MethodsNamespace<IDL>;

/**
* Address of the program.
*/
Expand Down Expand Up @@ -275,13 +282,15 @@ export class Program<IDL extends Idl = Idl> {
transaction,
account,
simulate,
methods,
state,
] = NamespaceFactory.build(idl, this._coder, programId, provider);
this.rpc = rpc;
this.instruction = instruction;
this.transaction = transaction;
this.account = account;
this.simulate = simulate;
this.methods = methods;
this.state = state;
}

Expand Down
12 changes: 12 additions & 0 deletions ts/src/program/namespace/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import AccountFactory, { AccountNamespace } from "./account.js";
import SimulateFactory, { SimulateNamespace } from "./simulate.js";
import { parseIdlErrors } from "../common.js";
import { AllInstructions } from "./types.js";
import { MethodsBuilderFactory, MethodsNamespace } from "./methods";

// Re-exports.
export { StateClient } from "./state.js";
Expand All @@ -20,6 +21,7 @@ export { RpcNamespace, RpcFn } from "./rpc.js";
export { AccountNamespace, AccountClient, ProgramAccount } from "./account.js";
export { SimulateNamespace, SimulateFn } from "./simulate.js";
export { IdlAccounts, IdlTypes } from "./types.js";
export { MethodsBuilderFactory, MethodsNamespace } from "./methods";

export default class NamespaceFactory {
/**
Expand All @@ -36,12 +38,14 @@ export default class NamespaceFactory {
TransactionNamespace<IDL>,
AccountNamespace<IDL>,
SimulateNamespace<IDL>,
MethodsNamespace<IDL>,
StateClient<IDL> | undefined
] {
const rpc: RpcNamespace = {};
const instruction: InstructionNamespace = {};
const transaction: TransactionNamespace = {};
const simulate: SimulateNamespace = {};
const methods: MethodsNamespace = {};

const idlErrors = parseIdlErrors(idl);

Expand All @@ -64,13 +68,20 @@ export default class NamespaceFactory {
programId,
idl
);
const methodItem = MethodsBuilderFactory.build(
ixItem,
txItem,
rpcItem,
simulateItem
);

const name = camelCase(idlIx.name);

instruction[name] = ixItem;
transaction[name] = txItem;
rpc[name] = rpcItem;
simulate[name] = simulateItem;
methods[name] = methodItem;
});

const account: AccountNamespace<IDL> = idl.accounts
Expand All @@ -83,6 +94,7 @@ export default class NamespaceFactory {
transaction as TransactionNamespace<IDL>,
account,
simulate as SimulateNamespace<IDL>,
methods as MethodsNamespace<IDL>,
state,
];
}
Expand Down
Loading