Skip to content

Commit

Permalink
Update Anchor SDK to 0.25 & decouple Transaction stack with Provider (#9
Browse files Browse the repository at this point in the history
)

- Upgrade anchor SDK dependency to 0.25.0
- Remove transaction stack's dependency on Provider
  • Loading branch information
odcheung authored Jul 22, 2022
1 parent ca45d25 commit 9c86581
Show file tree
Hide file tree
Showing 5 changed files with 373 additions and 342 deletions.
4 changes: 2 additions & 2 deletions packages/common-sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"name": "@orca-so/common-sdk",
"version": "0.0.7",
"version": "0.1.0",
"description": "Common Typescript components across Orca",
"repository": "https://github.com/orca-so/orca-sdks",
"author": "Orca Foundation",
"license": "MIT",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"dependencies": {
"@project-serum/anchor": "0.20.1",
"@project-serum/anchor": "~0.25.0",
"@solana/spl-token": "0.1.8",
"decimal.js": "^10.3.1"
},
Expand Down
56 changes: 25 additions & 31 deletions packages/common-sdk/src/web3/transactions/transactions-builder.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,35 @@
import { Provider } from "@project-serum/anchor";
import { Transaction, Signer, TransactionInstruction, ConfirmOptions } from "@solana/web3.js";
import { AnchorProvider } from "@project-serum/anchor";
import { Wallet } from "@project-serum/anchor/dist/cjs/provider";
import {
ConfirmOptions,
Connection,
Signer,
Transaction,
TransactionInstruction,
} from "@solana/web3.js";
import { TransactionProcessor } from "./transactions-processor";
import { Instruction, TransactionPayload } from "./types";

/**
* @category Transactions Util
*/
export type TransformableInstruction = Instruction & {
toTx: () => TransactionBuilder;
};

/**
* @category Transactions Util
*/
export type BuildOptions = {
// If false, creates a transaction without a blockhash
// If true, creates a transaction by requesting latestBlockhash
// If object, creates a transaction by using object
latestBlockhash:
| boolean
| {
blockhash: string;
lastValidBlockHeight: number;
};
}
| undefined;
};

/**
* @category Transactions Util
*/
export class TransactionBuilder {
private provider: Provider;
private instructions: Instruction[];
private signers: Signer[];

constructor(provider: Provider) {
this.provider = provider;
constructor(readonly connection: Connection, readonly wallet: Wallet) {
this.instructions = [];
this.signers = [];
}
Expand Down Expand Up @@ -86,26 +81,21 @@ export class TransactionBuilder {
* Constructs a transaction payload with the gathered instructions
* @returns a TransactionPayload object that can be excuted or agregated into other transactions
*/
// TODO: Anchor 0.24+ removes .wallet from Provider
async build(options: BuildOptions = { latestBlockhash: false }): Promise<TransactionPayload> {
async build(options: BuildOptions = { latestBlockhash: undefined }): Promise<TransactionPayload> {
const { latestBlockhash } = options;
let recentBlockhash;
if (latestBlockhash === true) {
recentBlockhash = (await this.provider.connection.getLatestBlockhash("singleGossip"))
.blockhash;
} else if (latestBlockhash !== false && latestBlockhash.blockhash) {
recentBlockhash = latestBlockhash.blockhash;
}
let recentBlockhash = !latestBlockhash
? await this.connection.getLatestBlockhash("singleGossip")
: latestBlockhash;

const transaction = new Transaction({
recentBlockhash,
feePayer: this.provider.wallet.publicKey,
...recentBlockhash,
feePayer: this.wallet.publicKey,
});

const ix = this.compressIx(true);

transaction.add(...ix.instructions);
transaction.feePayer = this.provider.wallet.publicKey;
transaction.feePayer = this.wallet.publicKey;

return {
transaction: transaction,
Expand All @@ -119,7 +109,7 @@ export class TransactionBuilder {
*/
async buildAndExecute(): Promise<string> {
const tx = await this.build();
const tp = new TransactionProcessor(this.provider);
const tp = new TransactionProcessor(this.connection, this.wallet);
const { execute } = await tp.signAndConstructTransaction(tx);
return execute();
}
Expand All @@ -128,7 +118,11 @@ export class TransactionBuilder {
* Send multiple transactions at once.
* @deprecated This method is here for legacy reasons and we prefer the use of TransactionProcessor
*/
static async sendAll(provider: Provider, txns: TransactionBuilder[], opts?: ConfirmOptions) {
static async sendAll(
provider: AnchorProvider,
txns: TransactionBuilder[],
opts?: ConfirmOptions
) {
const txRequest = await Promise.all(
txns.map(async (txBuilder) => {
const { transaction, signers } = await txBuilder.build();
Expand Down
32 changes: 18 additions & 14 deletions packages/common-sdk/src/web3/transactions/transactions-processor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Provider } from "@project-serum/anchor";
import { Commitment, PublicKey, Signer, Transaction } from "@solana/web3.js";
import { Wallet } from "@project-serum/anchor/dist/cjs/provider";
import { Commitment, PublicKey, Signer, Transaction, Connection } from "@solana/web3.js";
import { SendTxRequest } from "./types";

// Only used internally
Expand All @@ -9,7 +9,11 @@ enum TransactionStatus {
}

export class TransactionProcessor {
constructor(readonly provider: Provider, readonly commitment: Commitment = "confirmed") {}
constructor(
readonly connection: Connection,
readonly wallet: Wallet,
readonly commitment: Commitment = "confirmed"
) {}

public async signTransaction(txRequest: SendTxRequest): Promise<{
transaction: Transaction;
Expand All @@ -24,14 +28,14 @@ export class TransactionProcessor {
lastValidBlockHeight: number;
}> {
// TODO: Neither Solana nor Anchor currently correctly handle latest block height confirmation
const { blockhash, lastValidBlockHeight } = await this.provider.connection.getLatestBlockhash(
const { blockhash, lastValidBlockHeight } = await this.connection.getLatestBlockhash(
this.commitment
);
const feePayer = this.provider.wallet.publicKey;
const feePayer = this.wallet.publicKey;
const pSignedTxs = txRequests.map((txRequest) => {
return rewriteTransaction(txRequest, feePayer, blockhash);
});
const transactions = await this.provider.wallet.signAllTransactions(pSignedTxs);
const transactions = await this.wallet.signAllTransactions(pSignedTxs);
return {
transactions,
lastValidBlockHeight,
Expand Down Expand Up @@ -63,14 +67,14 @@ export class TransactionProcessor {

// We separate the block expiry promise so that it can be shared for all the transactions
const expiry = checkBlockHeightExpiry(
this.provider,
this.connection,
lastValidBlockHeight,
this.commitment,
isDone
);
const txs = transactions.map((tx) => tx.serialize());
const txPromises = txs.map(async (tx) =>
confirmOrExpire(this.provider, tx, this.commitment, expiry)
confirmOrExpire(this.connection, tx, this.commitment, expiry)
);
let results: PromiseSettledResult<string>[] = [];
if (parallel) {
Expand Down Expand Up @@ -131,12 +135,12 @@ async function promiseToSettled<T>(promise: Promise<T>): Promise<PromiseSettledR
* Send a tx and confirm that it has reached `commitment` or expiration
*/
async function confirmOrExpire(
provider: Provider,
connection: Connection,
tx: Buffer,
commitment: Commitment,
expiry: Promise<TransactionStatus>
) {
const txId = await provider.connection.sendRawTransaction(tx, {
const txId = await connection.sendRawTransaction(tx, {
preflightCommitment: commitment,
});

Expand All @@ -147,7 +151,7 @@ async function confirmOrExpire(
// signed with the `commitment` level
const confirm = new Promise((resolve, reject) => {
try {
subscriptionId = provider.connection.onSignature(
subscriptionId = connection.onSignature(
txId,
() => {
subscriptionId = undefined;
Expand All @@ -170,19 +174,19 @@ async function confirmOrExpire(
}
} finally {
if (subscriptionId) {
provider.connection.removeSignatureListener(subscriptionId);
connection.removeSignatureListener(subscriptionId);
}
}
}

async function checkBlockHeightExpiry(
provider: Provider,
connection: Connection,
lastValidBlockHeight: number,
commitment: Commitment,
isDone: () => boolean
) {
while (!isDone()) {
let blockHeight = await provider.connection.getBlockHeight(commitment);
let blockHeight = await connection.getBlockHeight(commitment);
if (blockHeight > lastValidBlockHeight) {
break;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/orca-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"dependencies": {
"@orca-so/common-sdk": "^0.0.7",
"@orca-so/whirlpools-sdk": "^0.1.4",
"@project-serum/anchor": "0.20.1",
"@project-serum/anchor": "~0.25.0",
"@solana/spl-token": "0.1.8",
"axios": "^0.27.2",
"decimal.js": "^10.3.1"
Expand Down
Loading

0 comments on commit 9c86581

Please sign in to comment.