Skip to content

Commit

Permalink
Added forwardOnly tx sender (#1001)
Browse files Browse the repository at this point in the history
* Added forwardOnly tx sender

* Bump
  • Loading branch information
lukecaan committed Apr 5, 2024
1 parent 2820f71 commit 0dfe615
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 0 deletions.
1 change: 1 addition & 0 deletions sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export * from './tx/fastSingleTxSender';
export * from './tx/retryTxSender';
export * from './tx/whileValidTxSender';
export * from './tx/priorityFeeCalculator';
export * from './tx/forwardOnlyTxSender';
export * from './tx/types';
export * from './util/computeUnits';
export * from './util/tps';
Expand Down
121 changes: 121 additions & 0 deletions sdk/src/tx/forwardOnlyTxSender.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { AnchorProvider } from '@coral-xyz/anchor';
import { ConfirmOptions, Connection, VersionedTransaction } from '@solana/web3.js';
import bs58 from 'bs58';
import { IWallet } from '../types';
import { BaseTxSender } from './baseTxSender';
import { ConfirmationStrategy, TxSigAndSlot } from './types';

const DEFAULT_TIMEOUT = 35000;
const DEFAULT_RETRY = 5000;

type ResolveReference = {
resolve?: () => void;
};

export class ForwardOnlyTxSender extends BaseTxSender {
connection: Connection;
wallet: IWallet;
opts: ConfirmOptions;
timeout: number;
retrySleep: number;
additionalConnections: Connection[];
timoutCount = 0;

public constructor({
connection,
wallet,
opts = { ...AnchorProvider.defaultOptions(), maxRetries: 0 },
timeout = DEFAULT_TIMEOUT,
retrySleep = DEFAULT_RETRY,
confirmationStrategy = ConfirmationStrategy.Combo,
additionalTxSenderCallbacks = [],
}: {
connection: Connection;
wallet: IWallet;
opts?: ConfirmOptions;
timeout?: number;
retrySleep?: number;
confirmationStrategy?: ConfirmationStrategy;
additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
}) {
super({
connection,
wallet,
opts,
timeout,
additionalConnections: [],
confirmationStrategy,
additionalTxSenderCallbacks,
});
this.connection = connection;
this.wallet = wallet;
this.opts = opts;
this.timeout = timeout;
this.retrySleep = retrySleep;
this.additionalConnections = [];
}

async sleep(reference: ResolveReference): Promise<void> {
return new Promise((resolve) => {
reference.resolve = resolve;
setTimeout(resolve, this.retrySleep);
});
}

sendToAdditionalConnections(
rawTx: Buffer | Uint8Array,
_opts: ConfirmOptions
): void {
this.additionalTxSenderCallbacks?.map((callback) => {
callback(bs58.encode(rawTx));
});
}

async sendRawTransaction(
rawTransaction: Buffer | Uint8Array,
opts: ConfirmOptions
): Promise<TxSigAndSlot> {

const deserializedTx = VersionedTransaction.deserialize(rawTransaction);

const txSig = deserializedTx.signatures[0];
const encodedTxSig = bs58.encode(txSig);

const startTime = this.getTimestamp();

this.sendToAdditionalConnections(rawTransaction, opts);

let done = false;
const resolveReference: ResolveReference = {
resolve: undefined,
};
const stopWaiting = () => {
done = true;
if (resolveReference.resolve) {
resolveReference.resolve();
}
};

(async () => {
while (!done && this.getTimestamp() - startTime < this.timeout) {
await this.sleep(resolveReference);
if (!done) {
this.sendToAdditionalConnections(rawTransaction, opts);
}
}
})();

let slot: number;
try {
const result = await this.confirmTransaction(encodedTxSig, opts.commitment);
slot = result.context.slot;
// eslint-disable-next-line no-useless-catch
} catch (e) {
throw e;
} finally {
stopWaiting();
}

return { txSig: encodedTxSig, slot };
}
}

0 comments on commit 0dfe615

Please sign in to comment.