PHP WebShell
Текущая директория: /usr/lib/node_modules/bitgo/node_modules/viem/_esm/actions/public
Просмотр файла: waitForTransactionReceipt.js
import { BlockNotFoundError } from '../../errors/block.js';
import { TransactionNotFoundError, TransactionReceiptNotFoundError, WaitForTransactionReceiptTimeoutError, } from '../../errors/transaction.js';
import { getAction } from '../../utils/getAction.js';
import { observe } from '../../utils/observe.js';
import { withResolvers } from '../../utils/promise/withResolvers.js';
import { withRetry, } from '../../utils/promise/withRetry.js';
import { stringify } from '../../utils/stringify.js';
import { getBlock } from './getBlock.js';
import { getTransaction, } from './getTransaction.js';
import { getTransactionReceipt, } from './getTransactionReceipt.js';
import { watchBlockNumber, } from './watchBlockNumber.js';
/**
* Waits for the [Transaction](https://viem.sh/docs/glossary/terms#transaction) to be included on a [Block](https://viem.sh/docs/glossary/terms#block) (one confirmation), and then returns the [Transaction Receipt](https://viem.sh/docs/glossary/terms#transaction-receipt).
*
* - Docs: https://viem.sh/docs/actions/public/waitForTransactionReceipt
* - Example: https://stackblitz.com/github/wevm/viem/tree/main/examples/transactions_sending-transactions
* - JSON-RPC Methods:
* - Polls [`eth_getTransactionReceipt`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getTransactionReceipt) on each block until it has been processed.
* - If a Transaction has been replaced:
* - Calls [`eth_getBlockByNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber) and extracts the transactions
* - Checks if one of the Transactions is a replacement
* - If so, calls [`eth_getTransactionReceipt`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getTransactionReceipt).
*
* The `waitForTransactionReceipt` action additionally supports Replacement detection (e.g. sped up Transactions).
*
* Transactions can be replaced when a user modifies their transaction in their wallet (to speed up or cancel). Transactions are replaced when they are sent from the same nonce.
*
* There are 3 types of Transaction Replacement reasons:
*
* - `repriced`: The gas price has been modified (e.g. different `maxFeePerGas`)
* - `cancelled`: The Transaction has been cancelled (e.g. `value === 0n`)
* - `replaced`: The Transaction has been replaced (e.g. different `value` or `data`)
*
* @param client - Client to use
* @param parameters - {@link WaitForTransactionReceiptParameters}
* @returns The transaction receipt. {@link WaitForTransactionReceiptReturnType}
*
* @example
* import { createPublicClient, waitForTransactionReceipt, http } from 'viem'
* import { mainnet } from 'viem/chains'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
* const transactionReceipt = await waitForTransactionReceipt(client, {
* hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d',
* })
*/
export async function waitForTransactionReceipt(client, parameters) {
const { checkReplacement = true, confirmations = 1, hash, onReplaced, retryCount = 6, retryDelay = ({ count }) => ~~(1 << count) * 200, // exponential backoff
timeout = 180_000, } = parameters;
const observerId = stringify(['waitForTransactionReceipt', client.uid, hash]);
const pollingInterval = (() => {
if (parameters.pollingInterval)
return parameters.pollingInterval;
if (client.chain?.experimental_preconfirmationTime)
return client.chain.experimental_preconfirmationTime;
return client.pollingInterval;
})();
let transaction;
let replacedTransaction;
let receipt;
let retrying = false;
let _unobserve;
let _unwatch;
const { promise, resolve, reject } = withResolvers();
const timer = timeout
? setTimeout(() => {
_unwatch?.();
_unobserve?.();
reject(new WaitForTransactionReceiptTimeoutError({ hash }));
}, timeout)
: undefined;
_unobserve = observe(observerId, { onReplaced, resolve, reject }, async (emit) => {
receipt = await getAction(client, getTransactionReceipt, 'getTransactionReceipt')({ hash }).catch(() => undefined);
if (receipt && confirmations <= 1) {
clearTimeout(timer);
emit.resolve(receipt);
_unobserve?.();
return;
}
_unwatch = getAction(client, watchBlockNumber, 'watchBlockNumber')({
emitMissed: true,
emitOnBegin: true,
poll: true,
pollingInterval,
async onBlockNumber(blockNumber_) {
const done = (fn) => {
clearTimeout(timer);
_unwatch?.();
fn();
_unobserve?.();
};
let blockNumber = blockNumber_;
if (retrying)
return;
try {
// If we already have a valid receipt, let's check if we have enough
// confirmations. If we do, then we can resolve.
if (receipt) {
if (confirmations > 1 &&
(!receipt.blockNumber ||
blockNumber - receipt.blockNumber + 1n < confirmations))
return;
done(() => emit.resolve(receipt));
return;
}
// Get the transaction to check if it's been replaced.
// We need to retry as some RPC Providers may be slow to sync
// up mined transactions.
if (checkReplacement && !transaction) {
retrying = true;
await withRetry(async () => {
transaction = (await getAction(client, getTransaction, 'getTransaction')({ hash }));
if (transaction.blockNumber)
blockNumber = transaction.blockNumber;
}, {
delay: retryDelay,
retryCount,
});
retrying = false;
}
// Get the receipt to check if it's been processed.
receipt = await getAction(client, getTransactionReceipt, 'getTransactionReceipt')({ hash });
// Check if we have enough confirmations. If not, continue polling.
if (confirmations > 1 &&
(!receipt.blockNumber ||
blockNumber - receipt.blockNumber + 1n < confirmations))
return;
done(() => emit.resolve(receipt));
}
catch (err) {
// If the receipt is not found, the transaction will be pending.
// We need to check if it has potentially been replaced.
if (err instanceof TransactionNotFoundError ||
err instanceof TransactionReceiptNotFoundError) {
if (!transaction) {
retrying = false;
return;
}
try {
replacedTransaction = transaction;
// Let's retrieve the transactions from the current block.
// We need to retry as some RPC Providers may be slow to sync
// up mined blocks.
retrying = true;
const block = await withRetry(() => getAction(client, getBlock, 'getBlock')({
blockNumber,
includeTransactions: true,
}), {
delay: retryDelay,
retryCount,
shouldRetry: ({ error }) => error instanceof BlockNotFoundError,
});
retrying = false;
const replacementTransaction = block.transactions.find(({ from, nonce }) => from === replacedTransaction.from &&
nonce === replacedTransaction.nonce);
// If we couldn't find a replacement transaction, continue polling.
if (!replacementTransaction)
return;
// If we found a replacement transaction, return it's receipt.
receipt = await getAction(client, getTransactionReceipt, 'getTransactionReceipt')({
hash: replacementTransaction.hash,
});
// Check if we have enough confirmations. If not, continue polling.
if (confirmations > 1 &&
(!receipt.blockNumber ||
blockNumber - receipt.blockNumber + 1n < confirmations))
return;
let reason = 'replaced';
if (replacementTransaction.to === replacedTransaction.to &&
replacementTransaction.value === replacedTransaction.value &&
replacementTransaction.input === replacedTransaction.input) {
reason = 'repriced';
}
else if (replacementTransaction.from === replacementTransaction.to &&
replacementTransaction.value === 0n) {
reason = 'cancelled';
}
done(() => {
emit.onReplaced?.({
reason,
replacedTransaction: replacedTransaction,
transaction: replacementTransaction,
transactionReceipt: receipt,
});
emit.resolve(receipt);
});
}
catch (err_) {
done(() => emit.reject(err_));
}
}
else {
done(() => emit.reject(err));
}
}
},
});
});
return promise;
}
//# sourceMappingURL=waitForTransactionReceipt.js.mapВыполнить команду
Для локальной разработки. Не используйте в интернете!