Skip to content

Commit

Permalink
fix: fix solana signer by migrating confirm transaction to get signat…
Browse files Browse the repository at this point in the history
…ure statuses
  • Loading branch information
RanGojo committed Nov 11, 2024
1 parent 1ec9b81 commit d16c0f3
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 37 deletions.
14 changes: 5 additions & 9 deletions signers/signer-solana/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,9 @@ Currecntly all Rango Solana transactions are Versioned (and serialized), only So

5. Send and confirm the transaction (similar to [jupiter suggested code](https://github.com/jup-ag/jupiter-quote-api-node/blob/main/example/utils/transactionSender.ts))

````ts
```ts
const { txId, txResponse } = await transactionSenderAndConfirmationWaiter({
connection,
serializedTransaction,
blockhashWithExpiryBlockHeight: {
blockhash: latestBlock.blockhash,
lastValidBlockHeight: latestBlock.lastValidBlockHeight,
},
}); ```
````
connection,
serializedTransaction,
});
```
7 changes: 1 addition & 6 deletions signers/signer-solana/src/utils/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,14 @@ export const generalSolanaTransactionExecutor = async (
const latestBlock = await connection.getLatestBlockhash('confirmed');

const finalTx = prepareTransaction(tx, latestBlock.blockhash);
const raw = await DefaultSolanaSigner(finalTx);
const serializedTransaction = await DefaultSolanaSigner(finalTx);

// We first simulate whether the transaction would be successful
await simulateTransaction(finalTx, tx.txType);

const serializedTransaction = Buffer.from(raw);
const { txId, txResponse } = await transactionSenderAndConfirmationWaiter({
connection,
serializedTransaction,
blockhashWithExpiryBlockHeight: {
blockhash: latestBlock.blockhash,
lastValidBlockHeight: latestBlock.lastValidBlockHeight,
},
});
if (!txId || !txResponse) {
throw new SignerError(
Expand Down
59 changes: 40 additions & 19 deletions signers/signer-solana/src/utils/send.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@ import type {

import { TransactionExpiredBlockheightExceededError } from '@solana/web3.js';
import promiseRetry from 'promise-retry';
import { SignerError, SignerErrorCode } from 'rango-types';

import { wait } from './helpers.js';

const SEND_OPTIONS = {
skipPreflight: true,
};
const TIME_OUT = 2_000;
const CONFIRMATION_TIME_OUT = 30_000;

// https://github.com/jup-ag/jupiter-quote-api-node/blob/main/example/utils/transactionSender.ts
export async function transactionSenderAndConfirmationWaiter({
connection,
serializedTransaction,
blockhashWithExpiryBlockHeight,
}: TransactionSenderAndConfirmationWaiterArgs): Promise<TransactionSenderAndConfirmationWaiterResponse> {
const txId = await connection.sendRawTransaction(
serializedTransaction,
Expand Down Expand Up @@ -46,32 +47,53 @@ export async function transactionSenderAndConfirmationWaiter({
};

try {
const BLOCK_HEIGHT_DIFF = 150;
void abortableResender();
const lastValidBlockHeight =
blockhashWithExpiryBlockHeight.lastValidBlockHeight - BLOCK_HEIGHT_DIFF;

// this would throw TransactionExpiredBlockheightExceededError
await Promise.race([
connection.confirmTransaction(
{
...blockhashWithExpiryBlockHeight,
lastValidBlockHeight,
signature: txId,
abortSignal,
},
'confirmed'
new Promise((_, reject) =>
setTimeout(() => {
if (!abortSignal.aborted) {
reject(
new SignerError(
SignerErrorCode.SEND_TX_ERROR,
undefined,
`Error confirming transaction (timeout)`
)
);
}
}, CONFIRMATION_TIME_OUT)
),
// eslint-disable-next-line no-async-promise-executor
new Promise(async (resolve) => {
new Promise(async (resolve, reject) => {
// in case ws socket died
while (!abortSignal.aborted) {
await wait(TIME_OUT);
const tx = await connection.getSignatureStatus(txId, {
searchTransactionHistory: false,
});
if (tx?.value?.confirmationStatus === 'confirmed') {
resolve(tx);
const { value: statuses } = await connection.getSignatureStatuses(
[txId],
{
searchTransactionHistory: false,
}
);
if (statuses?.length > 0) {
const status = statuses[0];
if (status) {
if (status.err) {
reject(
new SignerError(
SignerErrorCode.SEND_TX_ERROR,
undefined,
`Transaction failed: ${JSON.stringify(status.err)}`
)
);
}
if (
status.confirmationStatus &&
['confirmed', 'finalized'].includes(status.confirmationStatus)
) {
resolve(true);
}
}
}
}
}),
Expand All @@ -81,7 +103,6 @@ export async function transactionSenderAndConfirmationWaiter({
// we consume this error and getTransaction would return null
return { txId, txResponse: null };
}
// invalid state from web3.js
throw e;
} finally {
controller.abort();
Expand Down
4 changes: 1 addition & 3 deletions signers/signer-solana/src/utils/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type {
BlockhashWithExpiryBlockHeight,
Connection,
PublicKey,
SendOptions,
Expand Down Expand Up @@ -39,8 +38,7 @@ export interface SolanaExternalProvider {

export type TransactionSenderAndConfirmationWaiterArgs = {
connection: Connection;
serializedTransaction: Buffer;
blockhashWithExpiryBlockHeight: BlockhashWithExpiryBlockHeight;
serializedTransaction: SerializedTransaction;
};

export type TransactionSenderAndConfirmationWaiterResponse = {
Expand Down

0 comments on commit d16c0f3

Please sign in to comment.