Skip to content

Commit

Permalink
processTransactionBloxroute() (#380)
Browse files Browse the repository at this point in the history
  • Loading branch information
filipzeta authored Apr 30, 2024
1 parent 4675410 commit 89079b7
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
Version changes are pinned to SDK releases.

## [1.29.4]

- Add utils.processTransactionBloxroute(). ([#380](https://github.com/zetamarkets/sdk/pull/380))

## [1.29.3]

- WIF. ([#391](https://github.com/zetamarkets/sdk/pull/391))
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zetamarkets/sdk",
"repository": "https://github.com/zetamarkets/sdk/",
"version": "1.29.3",
"version": "1.29.4",
"description": "Zeta SDK",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand All @@ -23,6 +23,7 @@
"lodash": "^4.17.21",
"lodash.clonedeep": "^4.5.0",
"obscenity": "0.2.0",
"@bloxroute/solana-trader-client-ts": "2.1.0",
"zeta-solana-web3": "1.87.7"
},
"devDependencies": {
Expand Down
26 changes: 25 additions & 1 deletion src/exchange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { SubExchange } from "./subexchange";
import * as instructions from "./program-instructions";
import { Orderbook } from "./serum/market";
import fetch from "cross-fetch";
import { HttpProvider } from "@bloxroute/solana-trader-client-ts";

export class Exchange {
/**
Expand Down Expand Up @@ -97,6 +98,11 @@ export class Exchange {
}
private _provider: anchor.AnchorProvider;

public get httpProvider(): HttpProvider {
return this._httpProvider;
}
private _httpProvider: HttpProvider;

/**
* Separate connection used for orderbook subscriptions.
* For example you might use a connection with Whirligig and low commitment for faster results
Expand Down Expand Up @@ -330,6 +336,10 @@ export class Exchange {
private _autoPriorityFeeOffset: number = 0;
private _autoPriorityFeeMultiplier: number = 1;
private _autoPriorityFeeUseMax: boolean = false;
public get tipMultiplier(): number {
return this._tipMultiplier;
}
private _tipMultiplier: number = 1;

// Micro lamports per CU of fees.
public get autoPriorityFeeUpperLimit(): number {
Expand Down Expand Up @@ -363,6 +373,10 @@ export class Exchange {
this._autoPriorityFeeUseMax = useMax;
}

public setTipMultiplier(multiplier: number) {
this._tipMultiplier = multiplier;
}

public updatePriorityFee(microLamportsPerCU: number) {
this._priorityFee = microLamportsPerCU;
}
Expand Down Expand Up @@ -605,7 +619,13 @@ export class Exchange {
public async load(
loadConfig: types.LoadExchangeConfig,
wallet = new types.DummyWallet(),
callback?: (asset: Asset, event: EventType, slot: number, data: any) => void
callback?: (
asset: Asset,
event: EventType,
slot: number,
data: any
) => void,
bloxrouteHttpProvider?: HttpProvider
) {
if (this.isInitialized) {
throw Error("Exchange already loaded");
Expand All @@ -619,6 +639,10 @@ export class Exchange {
this.initialize(loadConfig, wallet);
}

if (bloxrouteHttpProvider) {
this._httpProvider = bloxrouteHttpProvider;
}

this._riskCalculator = new RiskCalculator(this.assets);

// Load variables from state.
Expand Down
121 changes: 121 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import { Network } from "./network";
import cloneDeep from "lodash.clonedeep";
import * as os from "os";
import { OpenOrders, _OPEN_ORDERS_LAYOUT_V2 } from "./serum/market";
import { HttpProvider } from "@bloxroute/solana-trader-client-ts";
import axios from "axios";

export function getNativeTickSize(asset: Asset): number {
Expand Down Expand Up @@ -951,6 +952,113 @@ function txConfirmationCheck(expectedLevel: string, currentLevel: string) {
return false;
}

export async function processTransactionBloxroute(
httpProvider: HttpProvider,
anchorProvider: anchor.AnchorProvider,
tx: Transaction,
tip: number,
blockhash?: { blockhash: string; lastValidBlockHeight: number },
retries?: number,
skipConfirmation?: boolean
): Promise<TransactionSignature> {
tx.add(
SystemProgram.transfer({
fromPubkey: anchorProvider.publicKey,
toPubkey: new PublicKey(
"HWEoBxYs7ssKuudEjzjmpfJVX7Dvi7wescFsVx2L5yoY" // Trader API tip wallet
),
lamports: tip,
})
);

if (Exchange.priorityFee != 0) {
tx.instructions.unshift(
ComputeBudgetProgram.setComputeUnitPrice({
microLamports: Math.round(Exchange.priorityFee),
})
);
}

let failures = 0;
while (true) {
let recentBlockhash =
blockhash ??
(await anchorProvider.connection.getLatestBlockhash(
Exchange.blockhashCommitment
));

let v0Tx: VersionedTransaction = new VersionedTransaction(
new TransactionMessage({
payerKey: anchorProvider.publicKey,
recentBlockhash: recentBlockhash.blockhash,
instructions: tx.instructions,
}).compileToV0Message(getZetaLutArr())
);
v0Tx = (await anchorProvider.wallet.signTransaction(
v0Tx
)) as VersionedTransaction;
let rawTx = v0Tx.serialize();

let txSig;
try {
txSig = (
await httpProvider.postSubmitV2({
transaction: {
content: Buffer.from(rawTx).toString("base64"),
isCleanup: false,
},
skipPreFlight: true,
frontRunningProtection: false,
})
).signature;

// Poll the tx confirmation for N seconds
// Polling is more reliable than websockets using confirmTransaction()
let currentBlockHeight = 0;
if (!skipConfirmation) {
while (currentBlockHeight < recentBlockhash.lastValidBlockHeight) {
let status = await anchorProvider.connection.getSignatureStatus(
txSig
);
currentBlockHeight = await anchorProvider.connection.getBlockHeight(
anchorProvider.connection.commitment
);
if (status.value != null) {
if (status.value.err != null) {
// Gets caught and parsed in the later catch
let err = parseInt(
status.value.err["InstructionError"][1]["Custom"]
);
throw err;
}
if (
txConfirmationCheck(
"confirmed",
status.value.confirmationStatus.toString()
)
) {
return txSig;
}
}
await sleep(1500); // Don't spam the RPC
}
throw Error(`Transaction ${txSig} was not confirmed`);
} else {
return txSig;
}
} catch (err) {
let parsedErr = parseError(err);
failures += 1;
if (!retries || failures > retries) {
console.log(`txSig: ${txSig} failed. Error = ${parsedErr}`);
throw parsedErr;
}
console.log(`Transaction failed to send. Retrying...`);
console.log(`failCount=${failures}. error=${parsedErr}`);
}
}
}

export async function processTransactionJito(
provider: anchor.AnchorProvider,
tx: Transaction,
Expand Down Expand Up @@ -1088,6 +1196,19 @@ export async function processTransaction(
);
}

if (Exchange.httpProvider) {
let txSig = await processTransactionBloxroute(
Exchange.httpProvider,
provider,
tx,
Exchange.tipMultiplier * Exchange.priorityFee + 1050,
blockhash,
retries,
Exchange.skipRpcConfirmation
);
return txSig;
}

let failures = 0;
while (true) {
let rawTx: Buffer | Uint8Array;
Expand Down

0 comments on commit 89079b7

Please sign in to comment.