web3-mev-error-decoder 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +167 -2
- package/dist/error-decoder/constants.d.ts +5 -0
- package/dist/error-decoder/constants.js +19 -0
- package/dist/error-decoder/constants.js.map +1 -0
- package/dist/error-decoder/decoder.d.ts +43 -0
- package/dist/error-decoder/decoder.js +98 -0
- package/dist/error-decoder/decoder.js.map +1 -0
- package/dist/error-decoder/enums.d.ts +9 -0
- package/dist/error-decoder/enums.js +11 -0
- package/dist/error-decoder/enums.js.map +1 -0
- package/dist/error-decoder/handlers.d.ts +32 -0
- package/dist/error-decoder/handlers.js +131 -0
- package/dist/error-decoder/handlers.js.map +1 -0
- package/dist/error-decoder/index.d.ts +7 -0
- package/dist/error-decoder/index.js +7 -0
- package/dist/error-decoder/index.js.map +1 -0
- package/dist/error-decoder/results.d.ts +19 -0
- package/dist/error-decoder/results.js +53 -0
- package/dist/error-decoder/results.js.map +1 -0
- package/dist/error-decoder/types.d.ts +31 -0
- package/dist/error-decoder/types.js +2 -0
- package/dist/error-decoder/types.js.map +1 -0
- package/dist/error-decoder/viem.d.ts +19 -0
- package/dist/error-decoder/viem.js +47 -0
- package/dist/error-decoder/viem.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/multicall/abi.d.ts +7 -0
- package/dist/multicall/abi.js +27 -0
- package/dist/multicall/abi.js.map +1 -0
- package/dist/multicall/ethers.d.ts +50 -0
- package/dist/multicall/ethers.js +78 -0
- package/dist/multicall/ethers.js.map +1 -0
- package/dist/multicall/index.d.ts +21 -0
- package/dist/multicall/index.js +33 -0
- package/dist/multicall/index.js.map +1 -0
- package/dist/multicall/viem.d.ts +14 -0
- package/dist/multicall/viem.js +32 -0
- package/dist/multicall/viem.js.map +1 -0
- package/dist/provider/fallback-full.d.ts +124 -0
- package/dist/provider/fallback-full.js +629 -0
- package/dist/provider/fallback-full.js.map +1 -0
- package/dist/provider/fallback.d.ts +37 -0
- package/dist/provider/fallback.js +120 -0
- package/dist/provider/fallback.js.map +1 -0
- package/dist/provider/index.d.ts +7 -0
- package/dist/provider/index.js +5 -0
- package/dist/provider/index.js.map +1 -0
- package/dist/provider/viem-fallback.d.ts +47 -0
- package/dist/provider/viem-fallback.js +69 -0
- package/dist/provider/viem-fallback.js.map +1 -0
- package/dist/transaction/ethers.d.ts +27 -0
- package/dist/transaction/ethers.js +97 -0
- package/dist/transaction/ethers.js.map +1 -0
- package/dist/transaction/index.d.ts +21 -0
- package/dist/transaction/index.js +31 -0
- package/dist/transaction/index.js.map +1 -0
- package/dist/transaction/types.d.ts +46 -0
- package/dist/transaction/types.js +21 -0
- package/dist/transaction/types.js.map +1 -0
- package/dist/transaction/viem.d.ts +29 -0
- package/dist/transaction/viem.js +86 -0
- package/dist/transaction/viem.js.map +1 -0
- package/dist/types.d.ts +18 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +59 -0
- package/dist/utils.js +140 -0
- package/dist/utils.js.map +1 -0
- package/package.json +106 -4
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { JsonRpcApiProvider, Network, type JsonRpcError, type JsonRpcPayload, type JsonRpcResult, type Networkish } from 'ethers';
|
|
2
|
+
export interface FallbackProviderEntry {
|
|
3
|
+
provider: JsonRpcApiProvider;
|
|
4
|
+
/** Per-call timeout in ms. Default: 10_000. */
|
|
5
|
+
timeout?: number;
|
|
6
|
+
/** Retries against the same provider before moving to the next. Default: 0. */
|
|
7
|
+
retries?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface SimpleFallbackProviderOptions {
|
|
10
|
+
entries: FallbackProviderEntry[];
|
|
11
|
+
network?: Networkish;
|
|
12
|
+
/**
|
|
13
|
+
* When true, `eth_sendRawTransaction` is broadcast to every provider and the
|
|
14
|
+
* first success wins. Default: false.
|
|
15
|
+
*/
|
|
16
|
+
broadcastToAll?: boolean;
|
|
17
|
+
/** Default per-call timeout. Default: 10_000. */
|
|
18
|
+
defaultTimeout?: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Minimal RPC fallback provider for ethers v6.
|
|
22
|
+
*
|
|
23
|
+
* Requests are tried against providers in order, preferring the last provider
|
|
24
|
+
* that worked; each attempt is bounded by a timeout. Blockchain-level errors
|
|
25
|
+
* (INSUFFICIENT_FUNDS, CALL_EXCEPTION, ...) are thrown immediately instead of
|
|
26
|
+
* being retried against the next provider.
|
|
27
|
+
*/
|
|
28
|
+
export declare class SimpleFallbackProvider extends JsonRpcApiProvider {
|
|
29
|
+
#private;
|
|
30
|
+
readonly entries: FallbackProviderEntry[];
|
|
31
|
+
constructor(options: SimpleFallbackProviderOptions);
|
|
32
|
+
/** Index of the provider currently preferred (last known-good). */
|
|
33
|
+
get preferredIndex(): number;
|
|
34
|
+
_detectNetwork(): Promise<Network>;
|
|
35
|
+
_send(payload: JsonRpcPayload | Array<JsonRpcPayload>): Promise<Array<JsonRpcResult | JsonRpcError>>;
|
|
36
|
+
}
|
|
37
|
+
export declare function isBlockchainLevelError(error: unknown): boolean;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { JsonRpcApiProvider, Network, } from 'ethers';
|
|
2
|
+
import { withTimeout, getErrorMessage } from '../utils.js';
|
|
3
|
+
/**
|
|
4
|
+
* Minimal RPC fallback provider for ethers v6.
|
|
5
|
+
*
|
|
6
|
+
* Requests are tried against providers in order, preferring the last provider
|
|
7
|
+
* that worked; each attempt is bounded by a timeout. Blockchain-level errors
|
|
8
|
+
* (INSUFFICIENT_FUNDS, CALL_EXCEPTION, ...) are thrown immediately instead of
|
|
9
|
+
* being retried against the next provider.
|
|
10
|
+
*/
|
|
11
|
+
export class SimpleFallbackProvider extends JsonRpcApiProvider {
|
|
12
|
+
entries;
|
|
13
|
+
#preferred = 0;
|
|
14
|
+
#broadcastToAll;
|
|
15
|
+
#defaultTimeout;
|
|
16
|
+
constructor(options) {
|
|
17
|
+
const { entries, network } = options;
|
|
18
|
+
if (!entries.length) {
|
|
19
|
+
throw new Error('SimpleFallbackProvider: at least one provider is required');
|
|
20
|
+
}
|
|
21
|
+
super(network, network ? { staticNetwork: Network.from(network) } : { batchMaxCount: 1, batchStallTime: 0 });
|
|
22
|
+
this.entries = entries;
|
|
23
|
+
this.#broadcastToAll = options.broadcastToAll ?? false;
|
|
24
|
+
this.#defaultTimeout = options.defaultTimeout ?? 10_000;
|
|
25
|
+
this._start();
|
|
26
|
+
}
|
|
27
|
+
/** Index of the provider currently preferred (last known-good). */
|
|
28
|
+
get preferredIndex() {
|
|
29
|
+
return this.#preferred;
|
|
30
|
+
}
|
|
31
|
+
async _detectNetwork() {
|
|
32
|
+
for (const entry of this.entries) {
|
|
33
|
+
try {
|
|
34
|
+
return await entry.provider.getNetwork();
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// try the next provider
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
throw new Error('SimpleFallbackProvider: could not detect network on any provider');
|
|
41
|
+
}
|
|
42
|
+
async _send(payload) {
|
|
43
|
+
const payloads = Array.isArray(payload) ? payload : [payload];
|
|
44
|
+
return Promise.all(payloads.map((p) => this.#sendSingle(p)));
|
|
45
|
+
}
|
|
46
|
+
async #sendSingle(payload) {
|
|
47
|
+
if (this.#broadcastToAll && payload.method === 'eth_sendRawTransaction') {
|
|
48
|
+
return this.#broadcast(payload);
|
|
49
|
+
}
|
|
50
|
+
const ordered = this.#ordered();
|
|
51
|
+
let lastError;
|
|
52
|
+
for (const entry of ordered) {
|
|
53
|
+
const timeout = entry.timeout ?? this.#defaultTimeout;
|
|
54
|
+
const retries = entry.retries ?? 0;
|
|
55
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
56
|
+
try {
|
|
57
|
+
const result = await withTimeout(entry.provider.send(payload.method, payload.params), timeout);
|
|
58
|
+
this.#preferred = this.entries.indexOf(entry);
|
|
59
|
+
return { jsonrpc: '2.0', id: payload.id, result };
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
lastError = e;
|
|
63
|
+
if (isBlockchainLevelError(e))
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
jsonrpc: '2.0',
|
|
70
|
+
id: payload.id,
|
|
71
|
+
error: {
|
|
72
|
+
code: lastError?.code ?? -32000,
|
|
73
|
+
message: `SimpleFallbackProvider: all providers failed: ${getErrorMessage(lastError)}`,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
async #broadcast(payload) {
|
|
78
|
+
const params = payload.params;
|
|
79
|
+
const results = await Promise.allSettled(this.entries.map((e) => withTimeout(e.provider.send(payload.method, params), e.timeout ?? this.#defaultTimeout)));
|
|
80
|
+
const firstOk = results.find((r) => r.status === 'fulfilled');
|
|
81
|
+
if (firstOk) {
|
|
82
|
+
return { jsonrpc: '2.0', id: payload.id, result: firstOk.value };
|
|
83
|
+
}
|
|
84
|
+
const firstRejected = results.find((r) => r.status === 'rejected');
|
|
85
|
+
const err = firstRejected?.reason;
|
|
86
|
+
return {
|
|
87
|
+
jsonrpc: '2.0',
|
|
88
|
+
id: payload.id,
|
|
89
|
+
error: {
|
|
90
|
+
code: err?.code ?? -32000,
|
|
91
|
+
message: getErrorMessage(err),
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
#ordered() {
|
|
96
|
+
const { entries } = this;
|
|
97
|
+
return [...entries.slice(this.#preferred), ...entries.slice(0, this.#preferred)];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Errors caused by the transaction itself (not by the RPC) should stop the
|
|
102
|
+
* failover loop — the next RPC will fail the same way.
|
|
103
|
+
*/
|
|
104
|
+
const BLOCKCHAIN_ERROR_PATTERNS = [
|
|
105
|
+
'insufficient funds',
|
|
106
|
+
'nonce',
|
|
107
|
+
'replacement transaction underpriced',
|
|
108
|
+
'already known',
|
|
109
|
+
'execution reverted',
|
|
110
|
+
'out of gas',
|
|
111
|
+
'intrinsic gas',
|
|
112
|
+
'invalid sender',
|
|
113
|
+
'max fee per gas',
|
|
114
|
+
'gas price below',
|
|
115
|
+
];
|
|
116
|
+
export function isBlockchainLevelError(error) {
|
|
117
|
+
const message = getErrorMessage(error).toLowerCase();
|
|
118
|
+
return BLOCKCHAIN_ERROR_PATTERNS.some((pattern) => message.includes(pattern));
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=fallback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fallback.js","sourceRoot":"","sources":["../../src/provider/fallback.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { SimpleFallbackProvider, isBlockchainLevelError } from './fallback.js';
|
|
2
|
+
export type { FallbackProviderEntry, SimpleFallbackProviderOptions } from './fallback.js';
|
|
3
|
+
export { FallbackProvider } from './fallback-full.js';
|
|
4
|
+
export { FallbackProviderError, DEFAULT_RETRIES, DEFAULT_TIMEOUT, RETRY_DELAY, ALWAYS_SUPPORTED_METHODS, DEFAULT_FALLBACK_OPTIONS, isBlockchainError, isAlreadyKnownError, providerSupportsMethod, filterProvidersByMethod, filterValidProviders, getBlockNumber, getBlockNumberWithTimeout, getBlockNumbersAndMedian, } from './fallback-full.js';
|
|
5
|
+
export type { ProviderConfig, LoggingOptions, FallbackProviderOptions, } from './fallback-full.js';
|
|
6
|
+
export { createViemFallbackTransport, createViemFallbackClient, probeRpcEndpoints, } from './viem-fallback.js';
|
|
7
|
+
export type { RpcProbeResult, ViemFallbackTransportOptions, ViemFallbackClientOptions, } from './viem-fallback.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { SimpleFallbackProvider, isBlockchainLevelError } from './fallback.js';
|
|
2
|
+
export { FallbackProvider } from './fallback-full.js';
|
|
3
|
+
export { FallbackProviderError, DEFAULT_RETRIES, DEFAULT_TIMEOUT, RETRY_DELAY, ALWAYS_SUPPORTED_METHODS, DEFAULT_FALLBACK_OPTIONS, isBlockchainError, isAlreadyKnownError, providerSupportsMethod, filterProvidersByMethod, filterValidProviders, getBlockNumber, getBlockNumberWithTimeout, getBlockNumbersAndMedian, } from './fallback-full.js';
|
|
4
|
+
export { createViemFallbackTransport, createViemFallbackClient, probeRpcEndpoints, } from './viem-fallback.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/provider/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAG/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,WAAW,EACX,wBAAwB,EACxB,wBAAwB,EACxB,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,EACpB,cAAc,EACd,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAO5B,OAAO,EACL,2BAA2B,EAC3B,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type Chain, type PublicClient, type Transport } from 'viem';
|
|
2
|
+
export interface RpcProbeResult {
|
|
3
|
+
url: string;
|
|
4
|
+
ok: boolean;
|
|
5
|
+
chainId?: number;
|
|
6
|
+
blockNumber?: bigint;
|
|
7
|
+
latencyMs?: number;
|
|
8
|
+
error?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Probe JSON-RPC endpoints: reachability, chain id, block number and latency.
|
|
12
|
+
* Results are sorted best-first (matching chain id, then lowest latency);
|
|
13
|
+
* failed probes go last. Useful to order the transports handed to
|
|
14
|
+
* `createViemFallbackTransport`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function probeRpcEndpoints(urls: readonly string[], opts?: {
|
|
17
|
+
expectedChainId?: number;
|
|
18
|
+
timeout?: number;
|
|
19
|
+
}): Promise<RpcProbeResult[]>;
|
|
20
|
+
export interface ViemFallbackTransportOptions {
|
|
21
|
+
/** RPC URLs to fail over between. Order matters: first is preferred. */
|
|
22
|
+
urls: readonly string[];
|
|
23
|
+
/** Optional WebSocket URLs placed in front of the HTTP transports. */
|
|
24
|
+
webSocketUrls?: readonly string[];
|
|
25
|
+
/** Per-request timeout in ms. Default: 10_000. */
|
|
26
|
+
timeout?: number;
|
|
27
|
+
/** Retries per transport. Default: 2. */
|
|
28
|
+
retryCount?: number;
|
|
29
|
+
/** Enable viem's automatic ranking by latency. Default: true. */
|
|
30
|
+
rank?: boolean;
|
|
31
|
+
/** Custom webSocket/http factory override (testing). */
|
|
32
|
+
transportFactory?: (url: string, kind: 'http' | 'ws') => Transport;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Build a viem `fallback` transport over a list of RPC URLs, with per-URL
|
|
36
|
+
* timeout/retry configuration. This is the viem counterpart of
|
|
37
|
+
* `FallbackProvider` / `SimpleFallbackProvider` for ethers.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createViemFallbackTransport(opts: ViemFallbackTransportOptions): Transport;
|
|
40
|
+
export interface ViemFallbackClientOptions extends ViemFallbackTransportOptions {
|
|
41
|
+
/** Target chain (e.g. mainnet from 'viem/chains'). Required unless you pass `transport` yourself. */
|
|
42
|
+
chain?: Chain;
|
|
43
|
+
/** Polling interval for watch utilities, in ms. */
|
|
44
|
+
pollingInterval?: number;
|
|
45
|
+
}
|
|
46
|
+
/** Convenience builder: a viem PublicClient backed by a fallback transport. */
|
|
47
|
+
export declare function createViemFallbackClient(opts: ViemFallbackClientOptions): PublicClient;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createPublicClient, fallback, http, webSocket } from 'viem';
|
|
2
|
+
/**
|
|
3
|
+
* Probe JSON-RPC endpoints: reachability, chain id, block number and latency.
|
|
4
|
+
* Results are sorted best-first (matching chain id, then lowest latency);
|
|
5
|
+
* failed probes go last. Useful to order the transports handed to
|
|
6
|
+
* `createViemFallbackTransport`.
|
|
7
|
+
*/
|
|
8
|
+
export async function probeRpcEndpoints(urls, opts = {}) {
|
|
9
|
+
const timeout = opts.timeout ?? 5_000;
|
|
10
|
+
const results = await Promise.all(urls.map(async (url) => {
|
|
11
|
+
const started = Date.now();
|
|
12
|
+
try {
|
|
13
|
+
const client = createPublicClient({ transport: http(url, { timeout, retryCount: 0 }) });
|
|
14
|
+
const [chainId, blockNumber] = await Promise.all([client.getChainId(), client.getBlockNumber()]);
|
|
15
|
+
return {
|
|
16
|
+
url,
|
|
17
|
+
ok: true,
|
|
18
|
+
chainId,
|
|
19
|
+
blockNumber,
|
|
20
|
+
latencyMs: Date.now() - started,
|
|
21
|
+
error: opts.expectedChainId != null && chainId !== opts.expectedChainId ? 'chain id mismatch' : undefined,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
return { url, ok: false, error: e?.message ?? String(e) };
|
|
26
|
+
}
|
|
27
|
+
}));
|
|
28
|
+
return results.sort((a, b) => {
|
|
29
|
+
if (a.ok !== b.ok)
|
|
30
|
+
return a.ok ? -1 : 1;
|
|
31
|
+
const aMatch = a.error === undefined;
|
|
32
|
+
const bMatch = b.error === undefined;
|
|
33
|
+
if (aMatch !== bMatch)
|
|
34
|
+
return aMatch ? -1 : 1;
|
|
35
|
+
return (a.latencyMs ?? Infinity) - (b.latencyMs ?? Infinity);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Build a viem `fallback` transport over a list of RPC URLs, with per-URL
|
|
40
|
+
* timeout/retry configuration. This is the viem counterpart of
|
|
41
|
+
* `FallbackProvider` / `SimpleFallbackProvider` for ethers.
|
|
42
|
+
*/
|
|
43
|
+
export function createViemFallbackTransport(opts) {
|
|
44
|
+
const { urls, webSocketUrls = [], timeout = 10_000, retryCount = 2, rank = true, transportFactory, } = opts;
|
|
45
|
+
if (urls.length === 0 && webSocketUrls.length === 0) {
|
|
46
|
+
throw new Error('createViemFallbackTransport: at least one URL is required');
|
|
47
|
+
}
|
|
48
|
+
const make = transportFactory ?? ((url, kind) => kind === 'ws'
|
|
49
|
+
? webSocket(url, { timeout, retryCount })
|
|
50
|
+
: http(url, { timeout, retryCount }));
|
|
51
|
+
const transports = [
|
|
52
|
+
...webSocketUrls.map((url) => make(url, 'ws')),
|
|
53
|
+
...urls.map((url) => make(url, 'http')),
|
|
54
|
+
];
|
|
55
|
+
return fallback(transports, {
|
|
56
|
+
rank,
|
|
57
|
+
retryCount,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/** Convenience builder: a viem PublicClient backed by a fallback transport. */
|
|
61
|
+
export function createViemFallbackClient(opts) {
|
|
62
|
+
const { chain, pollingInterval, ...transportOpts } = opts;
|
|
63
|
+
return createPublicClient({
|
|
64
|
+
chain,
|
|
65
|
+
transport: createViemFallbackTransport(transportOpts),
|
|
66
|
+
pollingInterval,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=viem-fallback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viem-fallback.js","sourceRoot":"","sources":["../../src/provider/viem-fallback.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type Provider, type Signer, type TransactionReceipt, type TransactionRequest, type TransactionResponse } from 'ethers';
|
|
2
|
+
import type { AbiLike } from '../types.js';
|
|
3
|
+
import type { DecodedError } from '../error-decoder/types.js';
|
|
4
|
+
import { type DecodedLog, type WaitForTransactionOptions, type WaitForTransactionResult } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Wait for a transaction with timeout, confirmation count, replacement
|
|
7
|
+
* notification, decoded logs, and automatic revert decoding.
|
|
8
|
+
*/
|
|
9
|
+
export declare function waitForTransaction(opts: WaitForTransactionOptions & {
|
|
10
|
+
provider: Provider;
|
|
11
|
+
}): Promise<WaitForTransactionResult>;
|
|
12
|
+
/** Send a transaction via a signer, then wait with full decode/timeout handling. */
|
|
13
|
+
export declare function sendAndConfirm(signer: Signer, tx: TransactionRequest, opts?: {
|
|
14
|
+
confirmations?: number;
|
|
15
|
+
timeout?: number;
|
|
16
|
+
abis?: Record<string, AbiLike>;
|
|
17
|
+
throwOnRevert?: boolean;
|
|
18
|
+
}): Promise<WaitForTransactionResult & {
|
|
19
|
+
response: TransactionResponse;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Recover + decode the revert reason of a (possibly mined) reverted transaction
|
|
23
|
+
* by replaying it via `eth_call`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getRevertReason(provider: Provider, txHash: string, abis?: ReadonlyArray<AbiLike>): Promise<DecodedError>;
|
|
26
|
+
/** Decode logs of a receipt using the provided ABI map. */
|
|
27
|
+
export declare function decodeReceiptLogs(receipt: TransactionReceipt, abis?: Record<string, AbiLike>): DecodedLog[];
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { isError, } from 'ethers';
|
|
2
|
+
import { callRequestFromTx, extractRevertData, toInterface } from '../utils.js';
|
|
3
|
+
import { ErrorDecoder } from '../error-decoder/index.js';
|
|
4
|
+
import { TransactionRevertedError, TransactionTimeoutError, } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Wait for a transaction with timeout, confirmation count, replacement
|
|
7
|
+
* notification, decoded logs, and automatic revert decoding.
|
|
8
|
+
*/
|
|
9
|
+
export async function waitForTransaction(opts) {
|
|
10
|
+
const { provider, hash, confirmations = 1, timeout = 120_000, abis, onReplaced, throwOnRevert = true, } = opts;
|
|
11
|
+
let receipt;
|
|
12
|
+
try {
|
|
13
|
+
receipt = await provider.waitForTransaction(hash, confirmations, timeout);
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
if (isError(e, 'TRANSACTION_REPLACED')) {
|
|
17
|
+
onReplaced?.({
|
|
18
|
+
reason: e.reason,
|
|
19
|
+
replacement: e.replacement ?? null,
|
|
20
|
+
receipt: e.receipt ?? null,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
throw e;
|
|
24
|
+
}
|
|
25
|
+
if (!receipt) {
|
|
26
|
+
throw new TransactionTimeoutError(hash, timeout);
|
|
27
|
+
}
|
|
28
|
+
if (receipt.status === 0) {
|
|
29
|
+
const decoded = await getRevertReason(provider, hash, abis ? Object.values(abis) : undefined);
|
|
30
|
+
if (throwOnRevert) {
|
|
31
|
+
throw new TransactionRevertedError(receipt, decoded, hash);
|
|
32
|
+
}
|
|
33
|
+
return { receipt, logs: [], decodedError: decoded };
|
|
34
|
+
}
|
|
35
|
+
return { receipt, logs: decodeReceiptLogs(receipt, abis) };
|
|
36
|
+
}
|
|
37
|
+
/** Send a transaction via a signer, then wait with full decode/timeout handling. */
|
|
38
|
+
export async function sendAndConfirm(signer, tx, opts = {}) {
|
|
39
|
+
const response = await signer.sendTransaction(tx);
|
|
40
|
+
const provider = response.provider ?? signer.provider;
|
|
41
|
+
if (!provider)
|
|
42
|
+
throw new Error('Signer has no provider to wait on');
|
|
43
|
+
const result = await waitForTransaction({
|
|
44
|
+
provider,
|
|
45
|
+
hash: response.hash,
|
|
46
|
+
confirmations: opts.confirmations,
|
|
47
|
+
timeout: opts.timeout,
|
|
48
|
+
abis: opts.abis,
|
|
49
|
+
throwOnRevert: opts.throwOnRevert,
|
|
50
|
+
});
|
|
51
|
+
return { ...result, response };
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Recover + decode the revert reason of a (possibly mined) reverted transaction
|
|
55
|
+
* by replaying it via `eth_call`.
|
|
56
|
+
*/
|
|
57
|
+
export async function getRevertReason(provider, txHash, abis) {
|
|
58
|
+
const receipt = await provider.getTransactionReceipt(txHash);
|
|
59
|
+
if (receipt && receipt.status === 1) {
|
|
60
|
+
throw new Error('Transaction succeeded — there is no revert reason');
|
|
61
|
+
}
|
|
62
|
+
const tx = await provider.getTransaction(txHash);
|
|
63
|
+
if (!tx) {
|
|
64
|
+
throw new Error(`Transaction ${txHash} not found`);
|
|
65
|
+
}
|
|
66
|
+
let data;
|
|
67
|
+
let callError;
|
|
68
|
+
try {
|
|
69
|
+
await provider.call(callRequestFromTx(tx));
|
|
70
|
+
// Call succeeded — state has moved on; cannot reproduce the revert.
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
data = extractRevertData(e);
|
|
74
|
+
callError = e;
|
|
75
|
+
}
|
|
76
|
+
return new ErrorDecoder(abis).decodeData(data, callError);
|
|
77
|
+
}
|
|
78
|
+
/** Decode logs of a receipt using the provided ABI map. */
|
|
79
|
+
export function decodeReceiptLogs(receipt, abis) {
|
|
80
|
+
if (!abis)
|
|
81
|
+
return [];
|
|
82
|
+
const out = [];
|
|
83
|
+
for (const log of receipt.logs) {
|
|
84
|
+
const abi = abis[log.address.toLowerCase()];
|
|
85
|
+
if (!abi)
|
|
86
|
+
continue;
|
|
87
|
+
try {
|
|
88
|
+
const parsed = toInterface(abi).parseLog({ topics: [...log.topics], data: log.data });
|
|
89
|
+
out.push({ log, name: parsed?.name ?? null, args: parsed?.args?.toArray() ?? [] });
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
out.push({ log, name: null });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=ethers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ethers.js","sourceRoot":"","sources":["../../src/transaction/ethers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { PublicClient } from 'viem';
|
|
2
|
+
import type { Provider } from 'ethers';
|
|
3
|
+
import { waitForTransaction as waitForTransactionEth, sendAndConfirm, getRevertReason, decodeReceiptLogs } from './ethers.js';
|
|
4
|
+
import { waitForTransactionViem, sendAndConfirmViem, decodeViemReceiptLogs } from './viem.js';
|
|
5
|
+
import { TransactionRevertedError, TransactionTimeoutError, type DecodedLog, type ReplacedInfo, type WaitForTransactionOptions, type WaitForTransactionResult } from './types.js';
|
|
6
|
+
export interface UnifiedWaitOptions {
|
|
7
|
+
/** ethers v6 provider. */
|
|
8
|
+
provider?: Provider;
|
|
9
|
+
/** viem public client. Takes precedence if both are given. */
|
|
10
|
+
client?: PublicClient;
|
|
11
|
+
hash: string;
|
|
12
|
+
confirmations?: number;
|
|
13
|
+
timeout?: number;
|
|
14
|
+
abis?: Record<string, any>;
|
|
15
|
+
onReplaced?: (info: any) => void;
|
|
16
|
+
throwOnRevert?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** Unified waitForTransaction: works with an ethers provider or a viem client. */
|
|
19
|
+
export declare function waitForTransaction(opts: UnifiedWaitOptions): Promise<WaitForTransactionResult>;
|
|
20
|
+
export { waitForTransactionEth, waitForTransactionViem, sendAndConfirm, sendAndConfirmViem, getRevertReason, decodeReceiptLogs, decodeViemReceiptLogs, TransactionRevertedError, TransactionTimeoutError, };
|
|
21
|
+
export type { WaitForTransactionOptions, WaitForTransactionResult, DecodedLog, ReplacedInfo };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { waitForTransaction as waitForTransactionEth, sendAndConfirm, getRevertReason, decodeReceiptLogs, } from './ethers.js';
|
|
2
|
+
import { waitForTransactionViem, sendAndConfirmViem, decodeViemReceiptLogs, } from './viem.js';
|
|
3
|
+
import { TransactionRevertedError, TransactionTimeoutError, } from './types.js';
|
|
4
|
+
/** Unified waitForTransaction: works with an ethers provider or a viem client. */
|
|
5
|
+
export async function waitForTransaction(opts) {
|
|
6
|
+
if (opts.client) {
|
|
7
|
+
return waitForTransactionViem({
|
|
8
|
+
client: opts.client,
|
|
9
|
+
hash: opts.hash,
|
|
10
|
+
confirmations: opts.confirmations,
|
|
11
|
+
timeout: opts.timeout,
|
|
12
|
+
abis: opts.abis,
|
|
13
|
+
onReplaced: opts.onReplaced,
|
|
14
|
+
throwOnRevert: opts.throwOnRevert,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
if (opts.provider) {
|
|
18
|
+
return waitForTransactionEth({
|
|
19
|
+
provider: opts.provider,
|
|
20
|
+
hash: opts.hash,
|
|
21
|
+
confirmations: opts.confirmations,
|
|
22
|
+
timeout: opts.timeout,
|
|
23
|
+
abis: opts.abis,
|
|
24
|
+
onReplaced: opts.onReplaced,
|
|
25
|
+
throwOnRevert: opts.throwOnRevert,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
throw new Error('waitForTransaction: provide either `provider` (ethers) or `client` (viem)');
|
|
29
|
+
}
|
|
30
|
+
export { waitForTransactionEth, waitForTransactionViem, sendAndConfirm, sendAndConfirmViem, getRevertReason, decodeReceiptLogs, decodeViemReceiptLogs, TransactionRevertedError, TransactionTimeoutError, };
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transaction/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,IAAI,qBAAqB,EAC3C,cAAc,EACd,eAAe,EACf,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,wBAAwB,EACxB,uBAAuB,GAKxB,MAAM,YAAY,CAAC;AAepB,kFAAkF;AAClF,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAwB;IAC/D,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,sBAAsB,CAAC;YAC5B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,aAAa,EAAE,IAAI,CAAC,aAAa;SAClC,CAAC,CAAC;IACL,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,OAAO,qBAAqB,CAAC;YAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,aAAa,EAAE,IAAI,CAAC,aAAa;SAClC,CAAC,CAAC;IACL,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,2EAA2E,CAAC,CAAC;AAC/F,CAAC;AAED,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,GACxB,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { TransactionReceipt } from 'ethers';
|
|
2
|
+
import type { AbiLike } from '../types.js';
|
|
3
|
+
import type { DecodedError } from '../error-decoder/types.js';
|
|
4
|
+
/** A log decoded against the user-provided ABI map. */
|
|
5
|
+
export interface DecodedLog {
|
|
6
|
+
/** Raw log object (ethers or viem shaped). */
|
|
7
|
+
log: any;
|
|
8
|
+
/** Event name, if matched. */
|
|
9
|
+
name: string | null;
|
|
10
|
+
/** Parsed event arguments. */
|
|
11
|
+
args?: unknown[];
|
|
12
|
+
}
|
|
13
|
+
export interface ReplacedInfo {
|
|
14
|
+
reason: 'repriced' | 'replaced' | 'cancelled';
|
|
15
|
+
replacement?: unknown | null;
|
|
16
|
+
receipt?: unknown | null;
|
|
17
|
+
}
|
|
18
|
+
export declare class TransactionRevertedError extends Error {
|
|
19
|
+
readonly receipt: unknown;
|
|
20
|
+
readonly decoded: DecodedError;
|
|
21
|
+
readonly hash: string;
|
|
22
|
+
constructor(receipt: unknown, decoded: DecodedError, hash: string);
|
|
23
|
+
}
|
|
24
|
+
export declare class TransactionTimeoutError extends Error {
|
|
25
|
+
readonly hash: string;
|
|
26
|
+
constructor(hash: string, timeoutMs: number);
|
|
27
|
+
}
|
|
28
|
+
export interface WaitForTransactionOptions {
|
|
29
|
+
hash: string;
|
|
30
|
+
/** Confirmations to wait for. Default: 1. */
|
|
31
|
+
confirmations?: number;
|
|
32
|
+
/** Timeout in ms. Default: 120_000. */
|
|
33
|
+
timeout?: number;
|
|
34
|
+
/** Map of contract address (lowercased) -> ABI, used to decode logs and custom errors. */
|
|
35
|
+
abis?: Record<string, AbiLike>;
|
|
36
|
+
/** Called when the tx is replaced / repriced / cancelled. */
|
|
37
|
+
onReplaced?: (info: ReplacedInfo) => void;
|
|
38
|
+
/** Throw `TransactionRevertedError` when the tx reverts. Default: true. */
|
|
39
|
+
throwOnRevert?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface WaitForTransactionResult {
|
|
42
|
+
receipt: TransactionReceipt | unknown;
|
|
43
|
+
logs: DecodedLog[];
|
|
44
|
+
/** Present when throwOnRevert=false and the tx reverted. */
|
|
45
|
+
decodedError?: DecodedError;
|
|
46
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export class TransactionRevertedError extends Error {
|
|
2
|
+
receipt;
|
|
3
|
+
decoded;
|
|
4
|
+
hash;
|
|
5
|
+
constructor(receipt, decoded, hash) {
|
|
6
|
+
super(`Transaction reverted: ${decoded.reason ?? 'unknown reason'}`);
|
|
7
|
+
this.name = 'TransactionRevertedError';
|
|
8
|
+
this.receipt = receipt;
|
|
9
|
+
this.decoded = decoded;
|
|
10
|
+
this.hash = hash;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class TransactionTimeoutError extends Error {
|
|
14
|
+
hash;
|
|
15
|
+
constructor(hash, timeoutMs) {
|
|
16
|
+
super(`Timed out waiting for transaction ${hash} after ${timeoutMs}ms`);
|
|
17
|
+
this.name = 'TransactionTimeoutError';
|
|
18
|
+
this.hash = hash;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/transaction/types.ts"],"names":[],"mappings":"AAoBA,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACxC,OAAO,CAAU;IACjB,OAAO,CAAe;IACtB,IAAI,CAAS;IAEtB,YAAY,OAAgB,EAAE,OAAqB,EAAE,IAAY;QAC/D,KAAK,CAAC,yBAAyB,OAAO,CAAC,MAAM,IAAI,gBAAgB,EAAE,CAAC,CAAC;QACrE,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;QACvC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IACvC,IAAI,CAAS;IACtB,YAAY,IAAY,EAAE,SAAiB;QACzC,KAAK,CAAC,qCAAqC,IAAI,UAAU,SAAS,IAAI,CAAC,CAAC;QACxE,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACtC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { PublicClient, WalletClient, TransactionReceipt as ViemReceipt } from 'viem';
|
|
2
|
+
import type { AbiLike } from '../types.js';
|
|
3
|
+
import type { DecodedError } from '../error-decoder/types.js';
|
|
4
|
+
import { TransactionTimeoutError, type DecodedLog, type WaitForTransactionOptions, type WaitForTransactionResult } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Wait for a transaction with timeout, confirmations, replacement callback,
|
|
7
|
+
* decoded logs, and automatic revert decoding.
|
|
8
|
+
*/
|
|
9
|
+
export declare function waitForTransactionViem(opts: WaitForTransactionOptions & {
|
|
10
|
+
client: PublicClient;
|
|
11
|
+
}): Promise<WaitForTransactionResult>;
|
|
12
|
+
/** Send a transaction via a wallet client, then wait with full decode/timeout handling. */
|
|
13
|
+
export declare function sendAndConfirmViem(wallet: WalletClient, request: any, opts?: {
|
|
14
|
+
publicClient?: PublicClient;
|
|
15
|
+
confirmations?: number;
|
|
16
|
+
timeout?: number;
|
|
17
|
+
abis?: Record<string, AbiLike>;
|
|
18
|
+
throwOnRevert?: boolean;
|
|
19
|
+
}): Promise<WaitForTransactionResult & {
|
|
20
|
+
hash: string;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Recover + decode the revert reason of a mined reverted transaction for viem
|
|
24
|
+
* by replaying it via `publicClient.call`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getRevertReasonViem(client: PublicClient, txHash: string, abis?: ReadonlyArray<AbiLike>): Promise<DecodedError>;
|
|
27
|
+
/** Decode logs of a viem receipt using the provided ABI map (parsed with ethers Interface). */
|
|
28
|
+
export declare function decodeViemReceiptLogs(receipt: ViemReceipt, abis?: Record<string, AbiLike>): DecodedLog[];
|
|
29
|
+
export { TransactionTimeoutError };
|