@valve-tech/tx-tracker 0.7.0 → 0.9.2

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/dist/events.d.ts +11 -1
  3. package/dist/events.d.ts.map +1 -1
  4. package/dist/events.js +1 -0
  5. package/dist/events.js.map +1 -1
  6. package/dist/group-events.d.ts +82 -0
  7. package/dist/group-events.d.ts.map +1 -0
  8. package/dist/group-events.js +47 -0
  9. package/dist/group-events.js.map +1 -0
  10. package/dist/group.d.ts +31 -0
  11. package/dist/group.d.ts.map +1 -0
  12. package/dist/group.js +196 -0
  13. package/dist/group.js.map +1 -0
  14. package/dist/index.d.ts +12 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +6 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/observations.d.ts +11 -1
  19. package/dist/observations.d.ts.map +1 -1
  20. package/dist/observations.js +5 -1
  21. package/dist/observations.js.map +1 -1
  22. package/dist/reorg.d.ts.map +1 -1
  23. package/dist/reorg.js +7 -12
  24. package/dist/reorg.js.map +1 -1
  25. package/dist/replace-transaction.d.ts +46 -0
  26. package/dist/replace-transaction.d.ts.map +1 -0
  27. package/dist/replace-transaction.js +51 -0
  28. package/dist/replace-transaction.js.map +1 -0
  29. package/dist/tracker.d.ts +50 -4
  30. package/dist/tracker.d.ts.map +1 -1
  31. package/dist/tracker.js +192 -27
  32. package/dist/tracker.js.map +1 -1
  33. package/dist/wait-for-pending.d.ts +47 -0
  34. package/dist/wait-for-pending.d.ts.map +1 -0
  35. package/dist/wait-for-pending.js +71 -0
  36. package/dist/wait-for-pending.js.map +1 -0
  37. package/dist/wait-for-transaction.d.ts +61 -0
  38. package/dist/wait-for-transaction.d.ts.map +1 -0
  39. package/dist/wait-for-transaction.js +72 -0
  40. package/dist/wait-for-transaction.js.map +1 -0
  41. package/dist/watch-transaction.d.ts +63 -0
  42. package/dist/watch-transaction.d.ts.map +1 -0
  43. package/dist/watch-transaction.js +76 -0
  44. package/dist/watch-transaction.js.map +1 -0
  45. package/package.json +2 -2
  46. package/skills/tx-tracker-integration/SKILL.md +30 -0
@@ -0,0 +1,72 @@
1
+ /**
2
+ * `waitForTransaction` — Promise variant of `watchTransaction`. Use
3
+ * when you'd rather `await` the outcome than register callbacks.
4
+ *
5
+ * Resolves with a discriminated union: { status: 'mined' | 'dropped'
6
+ * | 'replaced' | 'failed', ... }. Rejects only on tracker/source
7
+ * errors — transaction outcomes are part of the resolved value, not
8
+ * exceptions.
9
+ *
10
+ * Internally constructs a private ChainSource + TxTracker and tears
11
+ * them down before resolving.
12
+ */
13
+ import { createChainSource } from '@valve-tech/chain-source';
14
+ import { createTxTracker } from './tracker.js';
15
+ export const waitForTransaction = (options) => {
16
+ const internalOptions = options;
17
+ const confirmations = options.confirmations ?? 1;
18
+ const staleAfterBlocks = options.staleAfterBlocks ?? 12;
19
+ return new Promise((resolve) => {
20
+ const source = internalOptions._sourceOverride ??
21
+ createChainSource({
22
+ client: options.client,
23
+ pollIntervalMs: options.pollIntervalMs,
24
+ onError: options.onError,
25
+ });
26
+ const tracker = createTxTracker({
27
+ source,
28
+ chainId: options.chainId ?? options.client.chain?.id ?? 0,
29
+ onError: options.onError,
30
+ });
31
+ source.start();
32
+ tracker.start();
33
+ let teardownSubscribe = null;
34
+ // No `settled` flag: tracker.stop() / source.stop() / teardownSubscribe
35
+ // are all idempotent, and Promise resolve is a no-op on second call.
36
+ // The first finish() detaches the subscription, so subsequent events
37
+ // for this hash don't reach the callback — no double-call path remains.
38
+ const finish = (outcome) => {
39
+ teardownSubscribe?.();
40
+ tracker.stop();
41
+ source.stop();
42
+ resolve(outcome);
43
+ };
44
+ teardownSubscribe = tracker.subscribe(options.hash, (event) => {
45
+ if (event.kind === 'seen-in-block' && event.confirmations >= confirmations) {
46
+ if (options.withReceipts && event.receipt && event.receipt.status === '0x0') {
47
+ finish({ status: 'failed', event, receipt: event.receipt });
48
+ return;
49
+ }
50
+ finish({ status: 'mined', event });
51
+ return;
52
+ }
53
+ if (event.kind === 'unseen-for-N-blocks' && event.blocks >= staleAfterBlocks) {
54
+ finish({ status: 'dropped', reason: 'unseen-for-N-blocks' });
55
+ return;
56
+ }
57
+ if (event.kind === 'replaced-by') {
58
+ finish({
59
+ status: 'replaced',
60
+ replacementHash: event.replacementHash,
61
+ event,
62
+ });
63
+ return;
64
+ }
65
+ }, {
66
+ emitInitial: false,
67
+ unseenThresholdBlocks: staleAfterBlocks,
68
+ ...(options.withReceipts ? { withReceipts: true } : {}),
69
+ });
70
+ });
71
+ };
72
+ //# sourceMappingURL=wait-for-transaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait-for-transaction.js","sourceRoot":"","sources":["../src/wait-for-transaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAO5D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAuC9C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,OAAkC,EACE,EAAE;IACtC,MAAM,eAAe,GAAG,OAA4C,CAAA;IACpE,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,CAAC,CAAA;IAChD,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,EAAE,CAAA;IAEvD,OAAO,IAAI,OAAO,CAA4B,CAAC,OAAO,EAAE,EAAE;QACxD,MAAM,MAAM,GACV,eAAe,CAAC,eAAe;YAC/B,iBAAiB,CAAC;gBAChB,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,cAAc,EAAE,OAAO,CAAC,cAAc;gBACtC,OAAO,EAAE,OAAO,CAAC,OAAO;aACzB,CAAC,CAAA;QACJ,MAAM,OAAO,GAAG,eAAe,CAAC;YAC9B,MAAM;YACN,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC;YACzD,OAAO,EAAE,OAAO,CAAC,OAAO;SACzB,CAAC,CAAA;QAEF,MAAM,CAAC,KAAK,EAAE,CAAA;QACd,OAAO,CAAC,KAAK,EAAE,CAAA;QAEf,IAAI,iBAAiB,GAAwB,IAAI,CAAA;QAEjD,wEAAwE;QACxE,qEAAqE;QACrE,qEAAqE;QACrE,wEAAwE;QACxE,MAAM,MAAM,GAAG,CAAC,OAAkC,EAAQ,EAAE;YAC1D,iBAAiB,EAAE,EAAE,CAAA;YACrB,OAAO,CAAC,IAAI,EAAE,CAAA;YACd,MAAM,CAAC,IAAI,EAAE,CAAA;YACb,OAAO,CAAC,OAAO,CAAC,CAAA;QAClB,CAAC,CAAA;QAED,iBAAiB,GAAG,OAAO,CAAC,SAAS,CACnC,OAAO,CAAC,IAAI,EACZ,CAAC,KAAK,EAAE,EAAE;YACR,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,IAAI,KAAK,CAAC,aAAa,IAAI,aAAa,EAAE,CAAC;gBAC3E,IAAI,OAAO,CAAC,YAAY,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;oBAC5E,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;oBAC3D,OAAM;gBACR,CAAC;gBACD,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAA;gBAClC,OAAM;YACR,CAAC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,qBAAqB,IAAI,KAAK,CAAC,MAAM,IAAI,gBAAgB,EAAE,CAAC;gBAC7E,MAAM,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC,CAAA;gBAC5D,OAAM;YACR,CAAC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;gBACjC,MAAM,CAAC;oBACL,MAAM,EAAE,UAAU;oBAClB,eAAe,EAAE,KAAK,CAAC,eAAe;oBACtC,KAAK;iBACN,CAAC,CAAA;gBACF,OAAM;YACR,CAAC;QACH,CAAC,EACD;YACE,WAAW,EAAE,KAAK;YAClB,qBAAqB,EAAE,gBAAgB;YACvC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACxD,CACF,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * `watchTransaction` — one-shot convenience over createChainSource +
3
+ * createTxTracker. Provex upstream item 4 (memory:
4
+ * upstream-candidates.md#L43). Use this when you don't need the full
5
+ * tracker API — just "tell me when this hash mines or drops."
6
+ *
7
+ * Internally constructs a private ChainSource and TxTracker, sets up
8
+ * a single-hash subscription, and tears down both source + tracker on
9
+ * terminal state or explicit stop.
10
+ */
11
+ import type { PublicClient } from 'viem';
12
+ import { type ChainSource } from '@valve-tech/chain-source';
13
+ import type { Hash, TxEventSeenInBlock } from './events.js';
14
+ export interface WatchTransactionOptions {
15
+ client: PublicClient;
16
+ hash: Hash;
17
+ /** Required confirmations before onMined fires. Default 1. */
18
+ confirmations?: number;
19
+ /** Blocks of "no observation" before onDropped fires. Default 12. */
20
+ staleAfterBlocks?: number;
21
+ /**
22
+ * Tag emitted events with this chainId. Falls back to
23
+ * `client.chain?.id`, then `0`. Consumers piping events from multiple
24
+ * watchers into one stream should set this for unambiguous routing.
25
+ */
26
+ chainId?: number;
27
+ /** Pass through to the internal ChainSource. */
28
+ pollIntervalMs?: number;
29
+ onMined?: (event: TxEventSeenInBlock) => void;
30
+ onDropped?: () => void;
31
+ onError?: (method: string, err: unknown) => void;
32
+ }
33
+ /**
34
+ * Extended options for internal use only — not part of the public API.
35
+ * The `_sourceOverride` seam allows tests to inject a pre-built
36
+ * `ChainSource` (driven by `emitBlock`/`emitMempool`) in place of the
37
+ * default `createChainSource(client)` path. Production callers never
38
+ * need this.
39
+ *
40
+ * @internal
41
+ */
42
+ export interface WatchTransactionInternalOptions extends WatchTransactionOptions {
43
+ /** @internal — test injection seam; do not use in production code. */
44
+ _sourceOverride?: ChainSource;
45
+ }
46
+ /**
47
+ * Watch a single tx hash. Returns an unsubscribe function — calling
48
+ * it before terminal cancels the watch and tears down the internal
49
+ * source/tracker.
50
+ *
51
+ * @example
52
+ * const stop = watchTransaction({
53
+ * client,
54
+ * hash: '0xabc...',
55
+ * confirmations: 3,
56
+ * onMined: (event) => console.log('mined at', event.blockNumber),
57
+ * onDropped: () => console.log('dropped'),
58
+ * })
59
+ * // ... later, before terminal
60
+ * stop()
61
+ */
62
+ export declare const watchTransaction: (options: WatchTransactionOptions | WatchTransactionInternalOptions) => (() => void);
63
+ //# sourceMappingURL=watch-transaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch-transaction.d.ts","sourceRoot":"","sources":["../src/watch-transaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAA;AAExC,OAAO,EAEL,KAAK,WAAW,EACjB,MAAM,0BAA0B,CAAA;AAEjC,OAAO,KAAK,EACV,IAAI,EACJ,kBAAkB,EACnB,MAAM,aAAa,CAAA;AAGpB,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,YAAY,CAAA;IACpB,IAAI,EAAE,IAAI,CAAA;IACV,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gDAAgD;IAChD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAA;IAC7C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,CAAA;CACjD;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,+BAAgC,SAAQ,uBAAuB;IAC9E,sEAAsE;IACtE,eAAe,CAAC,EAAE,WAAW,CAAA;CAC9B;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,gBAAgB,GAC3B,SAAS,uBAAuB,GAAG,+BAA+B,KACjE,CAAC,MAAM,IAAI,CAsDb,CAAA"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * `watchTransaction` — one-shot convenience over createChainSource +
3
+ * createTxTracker. Provex upstream item 4 (memory:
4
+ * upstream-candidates.md#L43). Use this when you don't need the full
5
+ * tracker API — just "tell me when this hash mines or drops."
6
+ *
7
+ * Internally constructs a private ChainSource and TxTracker, sets up
8
+ * a single-hash subscription, and tears down both source + tracker on
9
+ * terminal state or explicit stop.
10
+ */
11
+ import { createChainSource, } from '@valve-tech/chain-source';
12
+ import { createTxTracker } from './tracker.js';
13
+ /**
14
+ * Watch a single tx hash. Returns an unsubscribe function — calling
15
+ * it before terminal cancels the watch and tears down the internal
16
+ * source/tracker.
17
+ *
18
+ * @example
19
+ * const stop = watchTransaction({
20
+ * client,
21
+ * hash: '0xabc...',
22
+ * confirmations: 3,
23
+ * onMined: (event) => console.log('mined at', event.blockNumber),
24
+ * onDropped: () => console.log('dropped'),
25
+ * })
26
+ * // ... later, before terminal
27
+ * stop()
28
+ */
29
+ export const watchTransaction = (options) => {
30
+ const confirmations = options.confirmations ?? 1;
31
+ const staleAfterBlocks = options.staleAfterBlocks ?? 12;
32
+ const internal = options;
33
+ const source = internal._sourceOverride ?? createChainSource({
34
+ client: options.client,
35
+ pollIntervalMs: options.pollIntervalMs,
36
+ onError: options.onError,
37
+ });
38
+ const tracker = createTxTracker({
39
+ source,
40
+ chainId: options.chainId ?? options.client.chain?.id ?? 0,
41
+ onError: options.onError,
42
+ });
43
+ source.start();
44
+ tracker.start();
45
+ let teardown = null;
46
+ let done = false;
47
+ const finish = () => {
48
+ if (done)
49
+ return;
50
+ done = true;
51
+ teardown?.();
52
+ teardown = null;
53
+ tracker.stop();
54
+ source.stop();
55
+ };
56
+ const unsub = tracker.subscribe(options.hash, (event) => {
57
+ if (done)
58
+ return;
59
+ if (event.kind === 'seen-in-block' && event.confirmations >= confirmations) {
60
+ options.onMined?.(event);
61
+ finish();
62
+ return;
63
+ }
64
+ if (event.kind === 'unseen-for-N-blocks' && event.blocks >= staleAfterBlocks) {
65
+ options.onDropped?.();
66
+ finish();
67
+ return;
68
+ }
69
+ }, {
70
+ emitInitial: false,
71
+ unseenThresholdBlocks: staleAfterBlocks,
72
+ });
73
+ teardown = unsub;
74
+ return () => finish();
75
+ };
76
+ //# sourceMappingURL=watch-transaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch-transaction.js","sourceRoot":"","sources":["../src/watch-transaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EACL,iBAAiB,GAElB,MAAM,0BAA0B,CAAA;AAMjC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAoC9C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,OAAkE,EACpD,EAAE;IAChB,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,CAAC,CAAA;IAChD,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,EAAE,CAAA;IAEvD,MAAM,QAAQ,GAAG,OAA0C,CAAA;IAC3D,MAAM,MAAM,GAAgB,QAAQ,CAAC,eAAe,IAAI,iBAAiB,CAAC;QACxE,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC,CAAA;IACF,MAAM,OAAO,GAAG,eAAe,CAAC;QAC9B,MAAM;QACN,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC;QACzD,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC,CAAA;IAEF,MAAM,CAAC,KAAK,EAAE,CAAA;IACd,OAAO,CAAC,KAAK,EAAE,CAAA;IAEf,IAAI,QAAQ,GAAwB,IAAI,CAAA;IACxC,IAAI,IAAI,GAAG,KAAK,CAAA;IAEhB,MAAM,MAAM,GAAG,GAAS,EAAE;QACxB,IAAI,IAAI;YAAE,OAAM;QAChB,IAAI,GAAG,IAAI,CAAA;QACX,QAAQ,EAAE,EAAE,CAAA;QACZ,QAAQ,GAAG,IAAI,CAAA;QACf,OAAO,CAAC,IAAI,EAAE,CAAA;QACd,MAAM,CAAC,IAAI,EAAE,CAAA;IACf,CAAC,CAAA;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAC7B,OAAO,CAAC,IAAI,EACZ,CAAC,KAAK,EAAE,EAAE;QACR,IAAI,IAAI;YAAE,OAAM;QAChB,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,IAAI,KAAK,CAAC,aAAa,IAAI,aAAa,EAAE,CAAC;YAC3E,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAA;YACxB,MAAM,EAAE,CAAA;YACR,OAAM;QACR,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,qBAAqB,IAAI,KAAK,CAAC,MAAM,IAAI,gBAAgB,EAAE,CAAC;YAC7E,OAAO,CAAC,SAAS,EAAE,EAAE,CAAA;YACrB,MAAM,EAAE,CAAA;YACR,OAAM;QACR,CAAC;IACH,CAAC,EACD;QACE,WAAW,EAAE,KAAK;QAClB,qBAAqB,EAAE,gBAAgB;KACxC,CACF,CAAA;IACD,QAAQ,GAAG,KAAK,CAAA;IAEhB,OAAO,GAAG,EAAE,CAAC,MAAM,EAAE,CAAA;AACvB,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valve-tech/tx-tracker",
3
- "version": "0.7.0",
3
+ "version": "0.9.2",
4
4
  "description": "Per-tx state machine for EVM chains: emits neutral observations (`seen-in-mempool`, `seen-in-block`, `replaced-by`, `vanished-from-block`, `unseen-for-N-blocks`, etc.) so wallet UIs, indexers, and relays can write their own interpretations on top. Three consumption shapes (callback, async iterator, snapshot) over one push-based core. Per-method capability detection — works on HTTP, WS, both, or neither. Part of the valve-tech/evm-toolkit synchronized release line — implementation lands in subsequent 0.3.x releases per docs/tx-tracker-spec.md.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/valve-tech/evm-toolkit/tree/main/packages/tx-tracker#readme",
@@ -49,7 +49,7 @@
49
49
  "prepare": "yarn build"
50
50
  },
51
51
  "dependencies": {
52
- "@valve-tech/chain-source": "^0.7.0"
52
+ "@valve-tech/chain-source": "^0.9.2"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "viem": "^2.0.0"
@@ -158,6 +158,36 @@ import { createGasOracle } from '@valve-tech/gas-oracle'
158
158
  dependencies, and almost always `"@valve-tech/chain-source"` alongside
159
159
  it (the tracker requires a source).
160
160
 
161
+ ## Speed-up workflow (cross-package)
162
+
163
+ For callers tracking a tx via `@valve-tech/tx-tracker` who want to bump
164
+ it when it stalls or drops, pair with `@valve-tech/gas-oracle`'s
165
+ `recommendBumpTier` + `bumpForReplacement` helpers:
166
+
167
+ ```ts
168
+ import { recommendBumpTier, bumpForReplacement } from '@valve-tech/gas-oracle'
169
+
170
+ // tx-tracker tells you the tx is stuck:
171
+ tracker.on('stuck', (stuck) => {
172
+ const tier = recommendBumpTier(
173
+ gasOracleState,
174
+ { priorityTip: stuck.maxPriorityFeePerGas, identifier: { hash: stuck.hash } },
175
+ )
176
+ if (tier === null) return // Already paying above top tier — caller's call
177
+
178
+ const target = gasOracleState.tiers[tier]
179
+ const gas = bumpForReplacement(
180
+ { maxFeePerGas: stuck.maxFeePerGas, maxPriorityFeePerGas: stuck.maxPriorityFeePerGas },
181
+ { maxFeePerGas: target.maxFeePerGas, maxPriorityFeePerGas: target.maxPriorityFeePerGas },
182
+ )
183
+ walletClient.sendTransaction({ ...stuck, ...gas })
184
+ })
185
+ ```
186
+
187
+ Outpace correction (passing `identifier`) reads `gasOracleState.mempoolSamples`
188
+ to compute the tip needed to outpace the stuck tx in the live
189
+ distribution, on top of the EIP-1559 +10% protocol floor.
190
+
161
191
  ## Where to find more
162
192
 
163
193
  - Full API + types: `node_modules/@valve-tech/tx-tracker/AGENTS.md`