@valve-tech/gas-oracle 0.6.0 → 0.8.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +115 -16
  3. package/dist/block-position.d.ts +3 -3
  4. package/dist/block-position.d.ts.map +1 -1
  5. package/dist/block-position.js +32 -20
  6. package/dist/block-position.js.map +1 -1
  7. package/dist/classify-tip.d.ts +33 -0
  8. package/dist/classify-tip.d.ts.map +1 -0
  9. package/dist/classify-tip.js +52 -0
  10. package/dist/classify-tip.js.map +1 -0
  11. package/dist/inclusion-labels.d.ts +30 -0
  12. package/dist/inclusion-labels.d.ts.map +1 -0
  13. package/dist/inclusion-labels.js +35 -0
  14. package/dist/inclusion-labels.js.map +1 -0
  15. package/dist/index.d.ts +7 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +10 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/math.d.ts +1 -1
  20. package/dist/math.d.ts.map +1 -1
  21. package/dist/math.js +20 -18
  22. package/dist/math.js.map +1 -1
  23. package/dist/oracle.d.ts +2 -2
  24. package/dist/oracle.d.ts.map +1 -1
  25. package/dist/oracle.js +27 -11
  26. package/dist/oracle.js.map +1 -1
  27. package/dist/presets.d.ts +36 -0
  28. package/dist/presets.d.ts.map +1 -0
  29. package/dist/presets.js +27 -0
  30. package/dist/presets.js.map +1 -0
  31. package/dist/replacement.d.ts +80 -0
  32. package/dist/replacement.d.ts.map +1 -0
  33. package/dist/replacement.js +114 -0
  34. package/dist/replacement.js.map +1 -0
  35. package/dist/types.d.ts +49 -5
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/types.js +57 -1
  38. package/dist/types.js.map +1 -1
  39. package/dist/viem-transport.d.ts +1 -1
  40. package/dist/viem-transport.d.ts.map +1 -1
  41. package/dist/viem-transport.js +11 -5
  42. package/dist/viem-transport.js.map +1 -1
  43. package/package.json +2 -2
  44. package/skills/gas-oracle-integration/SKILL.md +159 -13
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Same-nonce EIP-1559 replacement helpers. Pure functions; no I/O.
3
+ *
4
+ * The protocol-replacement-floor math is verified against geth
5
+ * `core/txpool/legacypool/list.go:Add()`, geth `core/txpool/blobpool/
6
+ * config.go`, reth `crates/transaction-pool/src/config.rs`, and PulseChain
7
+ * `gitlab.com/pulsechaincom/go-pulse/master/core/txpool/legacypool/
8
+ * legacypool.go`. The `+1n` term in `minimumReplacementFee` is load-
9
+ * bearing for small `current` values where geth's integer-floor threshold
10
+ * collapses below the strict `old < tx` check.
11
+ */
12
+ import { TIER_LADDER, TierName, TxType } from './types.js';
13
+ import { tipForBlockPosition } from './block-position.js';
14
+ export const ReplacementBumpPercent = {
15
+ /** geth `legacypool.DefaultConfig.PriceBump` — legacy / EIP-2930 / EIP-1559 / EIP-7702. */
16
+ default: 10n,
17
+ /** geth `blobpool.DefaultConfig.PriceBump` — EIP-4844 blob txs. */
18
+ blob: 100n,
19
+ };
20
+ /**
21
+ * Minimum fee required to replace a tx at a given current fee. Per-field
22
+ * primitive — apply once to `maxFeePerGas` and once to
23
+ * `maxPriorityFeePerGas` for an EIP-1559 replacement.
24
+ *
25
+ * Returns `(current * (100 + bump)) / 100 + 1`, where `bump` is `100n`
26
+ * for blob txs and `10n` otherwise. The `+1` clears geth's strict
27
+ * `old < tx` check at small `current` values where the integer-floor
28
+ * threshold collapses (e.g. `current=1`, `floor(1.1)=1`).
29
+ *
30
+ * Unknown future tx-type bytes default to the legacy/1559 +10% bump —
31
+ * the +100% rule is blob-specific.
32
+ */
33
+ export const minimumReplacementFee = (current, txType) => {
34
+ const bump = txType === TxType.blob
35
+ ? ReplacementBumpPercent.blob
36
+ : ReplacementBumpPercent.default;
37
+ return (current * (100n + bump)) / 100n + 1n;
38
+ };
39
+ /**
40
+ * Compute (maxFeePerGas, maxPriorityFeePerGas) for replacing a 1559 tx.
41
+ * Per-field rule: max(target, protocolFloor). Final guard ensures
42
+ * `result.maxFeePerGas >= result.maxPriorityFeePerGas` so the result is
43
+ * a well-formed tx even on degenerate target inputs.
44
+ *
45
+ * 1559-scoped — for blob replacement use `minimumReplacementFee(_,
46
+ * TxType.blob)` directly per fee field.
47
+ */
48
+ export const bumpForReplacement = (currentGas, targetGas) => {
49
+ const maxFeeFloor = minimumReplacementFee(currentGas.maxFeePerGas, TxType.eip1559);
50
+ const priorityFloor = minimumReplacementFee(currentGas.maxPriorityFeePerGas, TxType.eip1559);
51
+ const maxPriorityFeePerGas = targetGas.maxPriorityFeePerGas > priorityFloor
52
+ ? targetGas.maxPriorityFeePerGas
53
+ : priorityFloor;
54
+ let maxFeePerGas = targetGas.maxFeePerGas > maxFeeFloor ? targetGas.maxFeePerGas : maxFeeFloor;
55
+ if (maxFeePerGas < maxPriorityFeePerGas)
56
+ maxFeePerGas = maxPriorityFeePerGas;
57
+ return { maxFeePerGas, maxPriorityFeePerGas };
58
+ };
59
+ export const BumpStrategy = {
60
+ cheapestThatLands: 'cheapestThatLands',
61
+ oneStepFasterThanRecommended: 'oneStepFasterThanRecommended',
62
+ instant: 'instant',
63
+ };
64
+ /**
65
+ * Pick a tier to bump to for a same-nonce EIP-1559 replacement. The
66
+ * effective floor is `max(protocolFloor, outpaceFloor)`:
67
+ * - protocolFloor = `minimumReplacementFee(stuckTx.priorityTip,
68
+ * TxType.eip1559)` — the geth +10% rule.
69
+ * - outpaceFloor = the tip required to be ranked strictly above every
70
+ * tx currently ahead of `stuckTx.identifier` in
71
+ * `snapshot.mempoolSamples`. Computed by locating stuck's rank via
72
+ * `tipForBlockPosition({ kind: 'aheadOf', tx: identifier })` then
73
+ * querying `{ kind: 'rank', rank: stuckRank - 1n }` to outbid the
74
+ * tx currently just above stuck. When stuck is already at the top
75
+ * of the distribution (or not present), this is `0n` and only the
76
+ * protocol floor applies.
77
+ *
78
+ * Returns `null` when no tier clears the effective floor — the original
79
+ * was already paying above the top of the ladder, or the snapshot has
80
+ * no tip data.
81
+ */
82
+ export const recommendBumpTier = (snapshot, stuckTx, options = {}) => {
83
+ const strategy = options.strategy ?? BumpStrategy.cheapestThatLands;
84
+ const protocolFloor = minimumReplacementFee(stuckTx.priorityTip, TxType.eip1559);
85
+ const outpaceFloor = stuckTx.identifier
86
+ ? (() => {
87
+ const stuckPosition = tipForBlockPosition(snapshot.mempoolSamples, {
88
+ kind: 'aheadOf',
89
+ tx: stuckTx.identifier,
90
+ });
91
+ // Stuck not in mempool, or stuck already at rank 0 (no one above).
92
+ if (stuckPosition.pivot === null || stuckPosition.rank === 0n)
93
+ return 0n;
94
+ // Outbid the tx at rank `stuckRank - 1` (the cheapest tx
95
+ // currently ahead of stuck) — landing here is sufficient to
96
+ // outpace every tx currently above stuck.
97
+ return tipForBlockPosition(snapshot.mempoolSamples, {
98
+ kind: 'rank',
99
+ rank: stuckPosition.rank - 1n,
100
+ }).requiredTip;
101
+ })()
102
+ : 0n;
103
+ const floor = protocolFloor > outpaceFloor ? protocolFloor : outpaceFloor;
104
+ const cheapestIndex = TIER_LADDER.findIndex((tier) => snapshot.tiers[tier].maxPriorityFeePerGas > floor);
105
+ if (cheapestIndex === -1)
106
+ return null;
107
+ if (strategy === BumpStrategy.cheapestThatLands)
108
+ return TIER_LADDER[cheapestIndex];
109
+ if (strategy === BumpStrategy.instant)
110
+ return TierName.instant;
111
+ // oneStepFasterThanRecommended
112
+ return TIER_LADDER[Math.min(cheapestIndex + 1, TIER_LADDER.length - 1)];
113
+ };
114
+ //# sourceMappingURL=replacement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replacement.js","sourceRoot":"","sources":["../src/replacement.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -46,11 +46,29 @@ export interface TierRecommendation {
46
46
  gasPrice: bigint;
47
47
  maxFeePerBlobGas: bigint | null;
48
48
  }
49
- export type Trend = 'rising' | 'falling' | 'stable';
50
- export type TierName = 'slow' | 'standard' | 'fast' | 'instant';
49
+ export declare const Trend: {
50
+ readonly rising: "rising";
51
+ readonly falling: "falling";
52
+ readonly stable: "stable";
53
+ };
54
+ export type Trend = (typeof Trend)[keyof typeof Trend];
55
+ export declare const TierName: {
56
+ readonly slow: "slow";
57
+ readonly standard: "standard";
58
+ readonly fast: "fast";
59
+ readonly instant: "instant";
60
+ };
61
+ export type TierName = (typeof TierName)[keyof typeof TierName];
62
+ /**
63
+ * Canonical tier ordering, slow → instant. Used by helpers that walk the
64
+ * tier ladder (e.g., `classifyTip` finds the highest tier whose floor a
65
+ * tip clears; `recommendBumpTier` finds the cheapest tier that clears
66
+ * the protocol floor + outpace floor). Ordering is load-bearing.
67
+ */
68
+ export declare const TIER_LADDER: readonly TierName[];
51
69
  export interface MempoolStats {
52
- pendingCount: number;
53
- queuedCount: number;
70
+ pendingCount: bigint;
71
+ queuedCount: bigint;
54
72
  /** Sum of `tx.gas` across all pending txs — congestion proxy. */
55
73
  pendingGasDemand: bigint;
56
74
  /** Latest block's gas limit, useful for "pending demand vs. block capacity". */
@@ -104,7 +122,24 @@ export interface TipSample {
104
122
  * Future cutoffs can be added (e.g. `'eip4844'` for blob-only priority)
105
123
  * without re-interpreting existing values.
106
124
  */
107
- export type PriorityModel = 'flat' | 'eip1559';
125
+ export declare const PriorityModel: {
126
+ readonly flat: "flat";
127
+ readonly eip1559: "eip1559";
128
+ };
129
+ export type PriorityModel = (typeof PriorityModel)[keyof typeof PriorityModel];
130
+ /**
131
+ * EIP-2718 transaction type bytes. Identifier values — never participate
132
+ * in arithmetic, so they stay `number` per the package-wide bigint
133
+ * carve-out.
134
+ */
135
+ export declare const TxType: {
136
+ readonly legacy: 0;
137
+ readonly eip2930: 1;
138
+ readonly eip1559: 2;
139
+ readonly blob: 3;
140
+ readonly setCodeAuthorization: 4;
141
+ };
142
+ export type TxType = (typeof TxType)[keyof typeof TxType];
108
143
  /**
109
144
  * Producer-side toggles: which RPCs the oracle calls upstream each cycle.
110
145
  *
@@ -162,6 +197,15 @@ export interface GasOracleState {
162
197
  * §7-§9.
163
198
  */
164
199
  ring: BlockSample[];
200
+ /**
201
+ * Live mempool samples used to compute this snapshot's tiers.
202
+ * Producer-local — wire publishers should strip before serializing
203
+ * (same convention as `ring`). Consumed by replacement / classification
204
+ * helpers (e.g., `recommendBumpTier`'s outpace correction) for live-
205
+ * distribution analysis without re-fetching mempool data. Each poll
206
+ * replaces this field; no cumulative growth.
207
+ */
208
+ mempoolSamples: TipSample[];
165
209
  lastPublishedTips?: Record<TierName, bigint>;
166
210
  lastPublishedBlockNumber?: bigint;
167
211
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js CHANGED
@@ -7,5 +7,61 @@
7
7
  * bigint values. The caller owns that encoding — this package keeps the
8
8
  * canonical numeric form internally.
9
9
  */
10
- export {};
10
+ export const Trend = {
11
+ rising: 'rising',
12
+ falling: 'falling',
13
+ stable: 'stable',
14
+ };
15
+ export const TierName = {
16
+ slow: 'slow',
17
+ standard: 'standard',
18
+ fast: 'fast',
19
+ instant: 'instant',
20
+ };
21
+ /**
22
+ * Canonical tier ordering, slow → instant. Used by helpers that walk the
23
+ * tier ladder (e.g., `classifyTip` finds the highest tier whose floor a
24
+ * tip clears; `recommendBumpTier` finds the cheapest tier that clears
25
+ * the protocol floor + outpace floor). Ordering is load-bearing.
26
+ */
27
+ export const TIER_LADDER = [
28
+ TierName.slow,
29
+ TierName.standard,
30
+ TierName.fast,
31
+ TierName.instant,
32
+ ];
33
+ /**
34
+ * Where the chain's inclusion logic draws its priority cutoff in the
35
+ * tx-type space.
36
+ *
37
+ * - `'flat'` — chain ignores the EIP-2718 type byte for ordering.
38
+ * Tiers derive from a single gas-weighted distribution
39
+ * across all txs. Right for extractive validators
40
+ * (PulseChain et al.) where the only signal that matters
41
+ * is fee per gas, regardless of tx envelope.
42
+ * - `'eip1559'` — type 2+ txs get priority. Paying-lane tiers
43
+ * (standard/fast/instant) derive from type-2+ samples
44
+ * only; `slow` still draws from the full distribution
45
+ * so legacy senders find their lane. Right for chains
46
+ * that honor the 1559 fee-market shape.
47
+ *
48
+ * Future cutoffs can be added (e.g. `'eip4844'` for blob-only priority)
49
+ * without re-interpreting existing values.
50
+ */
51
+ export const PriorityModel = {
52
+ flat: 'flat',
53
+ eip1559: 'eip1559',
54
+ };
55
+ /**
56
+ * EIP-2718 transaction type bytes. Identifier values — never participate
57
+ * in arithmetic, so they stay `number` per the package-wide bigint
58
+ * carve-out.
59
+ */
60
+ export const TxType = {
61
+ legacy: 0,
62
+ eip2930: 1,
63
+ eip1559: 2,
64
+ blob: 3,
65
+ setCodeAuthorization: 4,
66
+ };
11
67
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA4CH,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;CACR,CAAA;AAGV,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,UAAU;IACpB,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,SAAS;CACV,CAAA;AAGV;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAwB;IAC9C,QAAQ,CAAC,IAAI;IACb,QAAQ,CAAC,QAAQ;IACjB,QAAQ,CAAC,IAAI;IACb,QAAQ,CAAC,OAAO;CACR,CAAA;AA2CV;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,SAAS;CACV,CAAA;AAGV;;;;GAIG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,MAAM,EAAE,CAAC;IACT,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,CAAC;IACP,oBAAoB,EAAE,CAAC;CACf,CAAA"}
@@ -32,7 +32,7 @@
32
32
  */
33
33
  import { type Transport } from 'viem';
34
34
  import { type CreateGasOracleOptions } from './oracle.js';
35
- import type { TierName } from './types.js';
35
+ import { TierName } from './types.js';
36
36
  export interface InterceptOptions {
37
37
  /**
38
38
  * Additive multi-tier read. Returns `{ baseFee, tiers: { slow, standard,
@@ -1 +1 @@
1
- {"version":3,"file":"viem-transport.d.ts","sourceRoot":"","sources":["../src/viem-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,MAAM,CAAA;AAE7C,OAAO,EAAmB,KAAK,sBAAsB,EAAkB,MAAM,aAAa,CAAA;AAC1F,OAAO,KAAK,EAAkB,QAAQ,EAAsB,MAAM,YAAY,CAAA;AAE9E,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAA;IAC/B;;;OAGG;IACH,wBAAwB,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAA;CAC5C;AAED,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,sBAAsB,EAAE,QAAQ,CAAC;IAClF;;;;OAIG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAA;IAC5B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;CAC7B;AAED,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG;IAAE,aAAa,EAAE,MAAM,IAAI,CAAA;CAAE,CAAA;AA8G1E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,GACxB,gBAAgB,SAAS,EACzB,SAAS,oBAAoB,KAC5B,kBAyCF,CAAA"}
1
+ {"version":3,"file":"viem-transport.d.ts","sourceRoot":"","sources":["../src/viem-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,MAAM,CAAA;AAE7C,OAAO,EAAmB,KAAK,sBAAsB,EAAkB,MAAM,aAAa,CAAA;AAC1F,OAAO,EAAE,QAAQ,EAAwD,MAAM,YAAY,CAAA;AAE3F,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAA;IAC/B;;;OAGG;IACH,wBAAwB,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAA;CAC5C;AAED,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,sBAAsB,EAAE,QAAQ,CAAC;IAClF;;;;OAIG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAA;IAC5B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;CAC7B;AAED,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG;IAAE,aAAa,EAAE,MAAM,IAAI,CAAA;CAAE,CAAA;AAmH1E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,GACxB,gBAAgB,SAAS,EACzB,SAAS,oBAAoB,KAC5B,kBAyCF,CAAA"}
@@ -32,6 +32,7 @@
32
32
  */
33
33
  import { custom } from 'viem';
34
34
  import { createGasOracle } from './oracle.js';
35
+ import { TierName, TxType } from './types.js';
35
36
  /**
36
37
  * Sentinel returned by `dispatchIntercept` when no intercept matched
37
38
  * and the request should be passed through to the inner transport.
@@ -40,23 +41,28 @@ import { createGasOracle } from './oracle.js';
40
41
  */
41
42
  const PASSTHROUGH = Symbol('gas-oracle:passthrough');
42
43
  const toHex = (n) => '0x' + n.toString(16);
43
- const TIER_NAMES = ['instant', 'fast', 'standard', 'slow'];
44
+ const TIER_NAMES = [
45
+ TierName.instant,
46
+ TierName.fast,
47
+ TierName.standard,
48
+ TierName.slow,
49
+ ];
44
50
  /**
45
51
  * Format a single tier for the `eth_gasFeeEstimate` response, scoped
46
52
  * to the requested tx type. Mirrors the relay's `gas-intercept.ts`
47
53
  * formatter so consumers of either surface get identical wire shapes.
48
54
  */
49
55
  const formatTier = (tier, txType) => {
50
- if (txType === 0 || txType === 1) {
56
+ if (txType === TxType.legacy || txType === TxType.eip2930) {
51
57
  return { gasPrice: toHex(tier.gasPrice) };
52
58
  }
53
- if (txType === 2 || txType === 4) {
59
+ if (txType === TxType.eip1559 || txType === TxType.setCodeAuthorization) {
54
60
  return {
55
61
  maxFeePerGas: toHex(tier.maxFeePerGas),
56
62
  maxPriorityFeePerGas: toHex(tier.maxPriorityFeePerGas),
57
63
  };
58
64
  }
59
- if (txType === 3) {
65
+ if (txType === TxType.blob) {
60
66
  return {
61
67
  maxFeePerGas: toHex(tier.maxFeePerGas),
62
68
  maxPriorityFeePerGas: toHex(tier.maxPriorityFeePerGas),
@@ -85,7 +91,7 @@ const buildGasFeeEstimate = (state, params) => {
85
91
  baseFeeTrend: state.baseFeeTrend,
86
92
  blockNumber: toHex(state.blockNumber),
87
93
  lastUpdated: toHex(state.timestamp),
88
- mempoolPendingCount: state.mempool.pendingCount,
94
+ mempoolPendingCount: Number(state.mempool.pendingCount),
89
95
  tiers,
90
96
  };
91
97
  if (state.blob)
@@ -1 +1 @@
1
- {"version":3,"file":"viem-transport.js","sourceRoot":"","sources":["../src/viem-transport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"viem-transport.js","sourceRoot":"","sources":["../src/viem-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,MAAM,EAAkB,MAAM,MAAM,CAAA;AAE7C,OAAO,EAAE,eAAe,EAA+C,MAAM,aAAa,CAAA;AAC1F,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAgD,MAAM,YAAY,CAAA;AAwC3F;;;;;GAKG;AACH,MAAM,WAAW,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAA;AAEpD,MAAM,KAAK,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;AAE1D,MAAM,UAAU,GAAe;IAC7B,QAAQ,CAAC,OAAO;IAChB,QAAQ,CAAC,IAAI;IACb,QAAQ,CAAC,QAAQ;IACjB,QAAQ,CAAC,IAAI;CACd,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,GAAG,CACjB,IAAwB,EACxB,MAA0B,EACF,EAAE;IAC1B,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC;QAC1D,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAA;IAC3C,CAAC;IACD,IAAI,MAAM,KAAK,MAAM,CAAC,OAAO,IAAI,MAAM,KAAK,MAAM,CAAC,oBAAoB,EAAE,CAAC;QACxE,OAAO;YACL,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC;YACtC,oBAAoB,EAAE,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC;SACvD,CAAA;IACH,CAAC;IACD,IAAI,MAAM,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC;QAC3B,OAAO;YACL,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC;YACtC,oBAAoB,EAAE,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC;YACtD,gBAAgB,EAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,IAAI,EAAE,CAAC;SACrD,CAAA;IACH,CAAC;IACD,yCAAyC;IACzC,MAAM,GAAG,GAA2B;QAClC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC9B,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC;QACtC,oBAAoB,EAAE,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC;KACvD,CAAA;IACD,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;QACnC,GAAG,CAAC,gBAAgB,GAAG,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;IACrD,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA;AAED,MAAM,mBAAmB,GAAG,CAC1B,KAAqB,EACrB,MAAiB,EACQ,EAAE;IAC3B,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACpE,MAAM,KAAK,GAA2C,EAAE,CAAA;IACxD,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAA;IACrD,CAAC;IACD,MAAM,GAAG,GAA4B;QACnC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;QAC7B,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC;QACrC,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC;QACnC,mBAAmB,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC;QACvD,KAAK;KACN,CAAA;IACD,IAAI,KAAK,CAAC,IAAI;QAAE,GAAG,CAAC,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IAC/D,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,iBAAiB,GAAG,KAAK,EAC7B,IAA4C,EAC5C,MAAiB,EACjB,SAA2B,EACY,EAAE;IACzC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAA;IAEhC,IAAI,IAAI,CAAC,MAAM,KAAK,oBAAoB,IAAI,SAAS,CAAC,kBAAkB,KAAK,KAAK,EAAE,CAAC;QACnF,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC5D,IAAI,CAAC,KAAK;YAAE,OAAO,WAAW,CAAA;QAC9B,OAAO,mBAAmB,CAAC,KAAK,EAAE,MAAmB,CAAC,CAAA;IACxD,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,SAAS,CAAC,YAAY,CAAA;QACnC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,KAAK;YAAE,OAAO,WAAW,CAAA;QAC5D,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC5D,IAAI,CAAC,KAAK;YAAE,OAAO,WAAW,CAAA;QAC9B,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAA;IAC1C,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,0BAA0B,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAG,SAAS,CAAC,wBAAwB,CAAA;QAC/C,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,KAAK;YAAE,OAAO,WAAW,CAAA;QAC5D,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC5D,IAAI,CAAC,KAAK;YAAE,OAAO,WAAW,CAAA;QAC9B,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC,CAAA;IACtD,CAAC;IAED,OAAO,WAAW,CAAA;AACpB,CAAC,CAAA;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,cAAyB,EACzB,OAA6B,EACT,EAAE;IACtB,MAAM,SAAS,GAAqB;QAClC,kBAAkB,EAAE,IAAI;QACxB,GAAG,OAAO,CAAC,SAAS;KACrB,CAAA;IAED,wEAAwE;IACxE,oEAAoE;IACpE,mDAAmD;IACnD,MAAM,WAAW,GAAG,cAAc,CAAC,EAAE,CAAC,CAAA;IACtC,+DAA+D;IAC/D,iEAAiE;IACjE,kEAAkE;IAClE,gEAAgE;IAChE,8DAA8D;IAC9D,MAAM,YAAY,GAAG;QACnB,OAAO,EAAE,WAAW,CAAC,OAAO;QAC5B,SAAS,EAAE,WAAW;KACuC,CAAA;IAC/D,+DAA+D;IAC/D,kEAAkE;IAClE,mEAAmE;IACnE,kEAAkE;IAClE,MAAM,MAAM,GAAG,eAAe,CAAC;QAC7B,aAAa,EAAE,KAAK;QACpB,GAAG,OAAO;QACV,MAAM,EAAE,YAAY;KACrB,CAAC,CAAA;IACF,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,KAAK,OAAO;QAAE,MAAM,CAAC,KAAK,EAAE,CAAA;IAE9D,MAAM,OAAO,GAAG,MAAM,CAAC;QACrB,OAAO,EAAE,KAAK,EAAE,IAA4C,EAAE,EAAE;YAC9D,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,CAAA;YAC/D,IAAI,MAAM,KAAK,WAAW;gBAAE,OAAO,MAAM,CAAA;YACzC,+DAA+D;YAC/D,gEAAgE;YAChE,OAAO,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAW,CAAC,CAAA;QACnF,CAAC;KACF,CAAC,CAAA;IAEF,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;AACvE,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valve-tech/gas-oracle",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Multi-tier gas-fee oracle for EVM chains. Computes slow/standard/fast/instant tier recommendations from block-included tips, mempool pending tips, and base-fee trend, with a configurable downside-decay cap and a chain-aware EIP-1559 priority cutoff. viem-native — pass it a PublicClient and it does the rest. Ships viem-actions and viem-transport subpaths for drop-in client extension and transport-wrapping.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/valve-tech/evm-toolkit/tree/main/packages/gas-oracle#readme",
@@ -59,7 +59,7 @@
59
59
  "prepare": "yarn build"
60
60
  },
61
61
  "dependencies": {
62
- "@valve-tech/chain-source": "^0.6.0"
62
+ "@valve-tech/chain-source": "^0.8.0"
63
63
  },
64
64
  "peerDependencies": {
65
65
  "viem": "^2.0.0"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: gas-oracle-integration
3
- description: Integrate `@valve-tech/gas-oracle` into an EVM dapp or backend. Use when the user wants gas-tier recommendations (`slow` / `standard` / `fast` / `instant`), needs to set `maxPriorityFeePerGas` and `maxFeePerGas` for a transaction, hits stuck-tx detection requirements, or asks "how do I price a transaction" against a viem `PublicClient`. Also use when seeing imports from `@valve-tech/gas-oracle` and the user asks for help configuring it per chain (Ethereum, Base, Arbitrum, OP, PulseChain), or asks about `priorityFeeDecayCap`, `priorityModel`, `tipForBlockPosition`, viem-actions, or viem-transport.
3
+ description: Integrate `@valve-tech/gas-oracle` into an EVM dapp or backend. Use when the user wants gas-tier recommendations (`slow` / `standard` / `fast` / `instant`), needs to set `maxPriorityFeePerGas` and `maxFeePerGas` for a transaction, or asks "how do I price a transaction" against a viem `PublicClient`. Also use when seeing imports from `@valve-tech/gas-oracle` and the user asks for help configuring it per chain (Ethereum, Base, Arbitrum, OP, PulseChain), or asks about `priorityFeeDecayCap`, `priorityModel`, `tipForBlockPosition`, viem-actions, or viem-transport. Also fires when the user asks about composing the oracle with `@valve-tech/tx-tracker` over a shared `ChainSource` — but actual per-tx tracking work belongs in the tx-tracker skill, not here.
4
4
  ---
5
5
 
6
6
  # Integrating `@valve-tech/gas-oracle`
@@ -10,6 +10,8 @@ working in a project that imports the package — it grounds you in the
10
10
  right configuration choices for the user's chain and the right
11
11
  integration shape for their codebase.
12
12
 
13
+ > **v0.8.0 default change**: `priorityModel` now defaults to `PriorityModel.eip1559` (was `flat`). Examples that previously omitted the field silently get the new default. Set `PriorityModel.flat` explicitly for PulseChain (chain 369) — or use `...chainPresets.pulsechain`.
14
+
13
15
  ## Decision tree: which integration to use
14
16
 
15
17
  ```
@@ -30,13 +32,13 @@ Is the user already passing a viem PublicClient around?
30
32
 
31
33
  | Chain | `chainId` | `priorityModel` | `baseFeeLivenessBlocks` | Notes |
32
34
  |---|---|---|---|---|
33
- | Ethereum mainnet | 1 | `'eip1559'` | 6 | Validators burn base fee. |
34
- | Base | 8453 | `'eip1559'` | 6 | Same as ETH. |
35
- | Arbitrum One | 42161 | `'eip1559'` | 6 | |
36
- | Optimism | 10 | `'eip1559'` | 6 | |
37
- | PulseChain mainnet | 369 | `'flat'` | 6 | Validators charge tips. |
38
- | PulseChain testnet v4 | 943 | `'flat'` | 6 | |
39
- | Unknown / unsure | — | `'flat'` | 6 | Conservative; never under-counts. |
35
+ | Ethereum mainnet | 1 | `PriorityModel.eip1559` (default) | 6 | Validators burn base fee. |
36
+ | Base | 8453 | `PriorityModel.eip1559` (default) | 6 | Same as ETH. |
37
+ | Arbitrum One | 42161 | `PriorityModel.eip1559` (default) | 6 | |
38
+ | Optimism | 10 | `PriorityModel.eip1559` (default) | 6 | |
39
+ | PulseChain mainnet | 369 | `PriorityModel.flat` | 6 | Validators charge tips. Use `...chainPresets.pulsechain`. |
40
+ | PulseChain testnet v4 | 943 | `PriorityModel.flat` | 6 | |
41
+ | Unknown / unsure | — | `PriorityModel.eip1559` (default) | 6 | Default is correct unless you've verified the chain is extractive. |
40
42
 
41
43
  `priorityFeeDecayCap`: leave at default (`WAD/8` = 12.5%/block, EIP-1559
42
44
  parity) unless you have a specific reason to tighten/loosen.
@@ -59,11 +61,12 @@ When reviewing user code, watch for these and suggest fixes:
59
61
  be missing. Fix: `await oracle.pollOnce()` after `start()` to seed
60
62
  state synchronously, then it's safe to call `getState()`.
61
63
 
62
- 4. **Using `priorityModel: 'eip1559'` on PulseChain or other tip-charging
63
- chains.** Cuts the distribution to type-2+ samples only, but
64
- PulseChain validators don't honor the type byte — they sort by tip
65
- regardless. Result: under-published tier values, your tx loses to
66
- legacy spam.
64
+ 4. **Using `PriorityModel.eip1559` on PulseChain or other tip-charging
65
+ chains.** This is now the default silent footgun on chain 369
66
+ unless you set `PriorityModel.flat` (or use `...chainPresets.pulsechain`).
67
+ It cuts the distribution to type-2+ samples only, but PulseChain
68
+ validators don't honor the type byte — they sort by tip regardless.
69
+ Result: under-published tier values, your tx loses to legacy spam.
67
70
 
68
71
  5. **`keepMempoolSnapshot: true` on a chain whose RPC gates
69
72
  `txpool_content`** (most public RPCs). Wastes a poll cycle's RPC
@@ -89,6 +92,96 @@ import { withGasOracle } from '@valve-tech/gas-oracle/viem-transport'
89
92
 
90
93
  `package.json` will show `"@valve-tech/gas-oracle": "^0.2.x"` in dependencies.
91
94
 
95
+ ## Replacement workflow — bumping a stuck tx
96
+
97
+ When the user has a stuck tx and asks how to bump / speed it up,
98
+ recommend the `recommendBumpTier` + `bumpForReplacement` pair. This is
99
+ the canonical caller pattern; don't roll your own +10% math:
100
+
101
+ ```ts
102
+ import {
103
+ recommendBumpTier,
104
+ bumpForReplacement,
105
+ BumpStrategy,
106
+ } from '@valve-tech/gas-oracle'
107
+
108
+ const tier = recommendBumpTier(
109
+ state,
110
+ { priorityTip: stuck.maxPriorityFeePerGas, identifier: { hash: stuck.hash } },
111
+ { strategy: BumpStrategy.cheapestThatLands }, // default
112
+ )
113
+ if (tier === null) return // already paying above top tier — caller's call
114
+
115
+ const target = state.tiers[tier]
116
+ const gas = bumpForReplacement(
117
+ { maxFeePerGas: stuck.maxFeePerGas, maxPriorityFeePerGas: stuck.maxPriorityFeePerGas },
118
+ { maxFeePerGas: target.maxFeePerGas, maxPriorityFeePerGas: target.maxPriorityFeePerGas },
119
+ )
120
+ walletClient.sendTransaction({ ...stuck, ...gas })
121
+ ```
122
+
123
+ `recommendBumpTier` reads `state.mempoolSamples` to compute outpace
124
+ correction (when an `identifier` is supplied) on top of the EIP-1559
125
+ +10% protocol floor. `bumpForReplacement` returns a gas object that
126
+ satisfies BOTH the protocol floor and the target tier — never one or
127
+ the other.
128
+
129
+ ## Tip classification
130
+
131
+ Inverse of `tipForBlockPosition`. Given a tip, ask "where would this
132
+ land?" instead of "what tip do I need to land here?":
133
+
134
+ ```ts
135
+ import { classifyTip } from '@valve-tech/gas-oracle'
136
+
137
+ const result = classifyTip(state, myTip)
138
+ // result.tier — TierName | null (null if below slow)
139
+ // result.requiredForNextTier — bigint floor of next tier above (null at instant)
140
+ // result.percentile — bigint 0-100 (0 = top, 100 = bottom)
141
+ // result.rank — bigint 0-indexed from top
142
+ // result.gasFromTop — bigint accumulated gas above this tip
143
+ ```
144
+
145
+ Useful for "your fee is low — bump?" UX nudges and for showing a
146
+ user where their existing in-flight tx sits vs. live competition.
147
+
148
+ ## UI labels
149
+
150
+ Branded / localized inclusion-time copy without forking the package:
151
+
152
+ ```ts
153
+ import { defaultInclusionLabels, inclusionLabel, TierName } from '@valve-tech/gas-oracle'
154
+
155
+ defaultInclusionLabels[TierName.standard] // 'Next block'
156
+
157
+ const es = { [TierName.standard]: 'Próximo bloque' }
158
+ inclusionLabel(TierName.standard, es) // 'Próximo bloque'
159
+ inclusionLabel(TierName.slow, es) // falls back to default English
160
+ ```
161
+
162
+ Pass partial overrides — anything not in the override map falls back
163
+ to the package default.
164
+
165
+ ## Chain presets
166
+
167
+ For PulseChain (and any future entries we ship), use the preset entry
168
+ points instead of typing `chainId` + `priorityModel` by hand:
169
+
170
+ ```ts
171
+ import { createGasOracle, chainPresets, presetForChainId } from '@valve-tech/gas-oracle'
172
+
173
+ // Static — caller knows which chain at code-time:
174
+ createGasOracle({ client, ...chainPresets.pulsechain })
175
+
176
+ // Dynamic — caller has chainId at runtime (e.g. from wallet):
177
+ const preset = presetForChainId(chainId)
178
+ createGasOracle({ client, chainId, ...preset })
179
+ ```
180
+
181
+ `presetForChainId` returns `undefined` for unknown chains; spreading
182
+ `undefined` into the options object is a no-op, so the call still works
183
+ on a chain we haven't preset (it just gets the package defaults).
184
+
92
185
  ## Where to find more
93
186
 
94
187
  - Full API + types: `node_modules/@valve-tech/gas-oracle/AGENTS.md`
@@ -96,3 +189,56 @@ import { withGasOracle } from '@valve-tech/gas-oracle/viem-transport'
96
189
  - Human-facing docs: `node_modules/@valve-tech/gas-oracle/README.md`
97
190
  - Source (when types alone aren't enough): `node_modules/@valve-tech/gas-oracle/dist/`
98
191
  (compiled JS + .d.ts) — sources aren't shipped, only built output.
192
+
193
+ ## Tx tracking — composing with `@valve-tech/tx-tracker`
194
+
195
+ When the user asks to "track this transaction," "watch tx hash,"
196
+ "know when my tx confirms," or "detect stuck transactions," redirect
197
+ them to `@valve-tech/tx-tracker` (sibling package). The gas oracle
198
+ does NOT track per-tx state — that's a separate concern with its own
199
+ state machine, retention policy, and consumption shapes. See
200
+ `node_modules/@valve-tech/tx-tracker/skills/tx-tracker-integration/SKILL.md`
201
+ for the full integration recipe.
202
+
203
+ The two packages are designed to share one upstream RPC stream:
204
+
205
+ ```ts
206
+ import { createChainSource } from '@valve-tech/chain-source'
207
+ import { createGasOracle } from '@valve-tech/gas-oracle'
208
+ import { createTxTracker } from '@valve-tech/tx-tracker'
209
+
210
+ const source = createChainSource({ client })
211
+ const oracle = createGasOracle({ source, chainId: 1 })
212
+ const tracker = createTxTracker({ source, chainId: 1 })
213
+
214
+ source.start(); oracle.start(); tracker.start()
215
+ ```
216
+
217
+ `ChainSource` owns the upstream poll cycle. The oracle reads it for
218
+ tier reduction; the tracker reads it for per-tx observations. **One
219
+ upstream RPC poll cycle, two derived views** (per spec §3.1). Each
220
+ surface owns its own lifecycle — `oracle.stop()` does not stop the
221
+ source or the tracker.
222
+
223
+ ### Anti-patterns when both are present
224
+
225
+ 7. **Constructing a private `ChainSource` for the tracker AND passing
226
+ `client` (not `source`) to `createGasOracle`.** That gives you two
227
+ independent sources for the same chain — double the RPC traffic
228
+ for no functional benefit. Either pass `source` to BOTH, or use
229
+ the `client` shorthand on BOTH (one private source on the oracle's
230
+ side, no tracker — meaningless if you want both).
231
+
232
+ 8. **Asking the gas oracle "is my tx confirmed?"** Wrong layer. The
233
+ oracle publishes tier recommendations; it does not observe per-tx
234
+ state. Use `tracker.getTxStatus(hash)` or
235
+ `tracker.subscribe(hash, cb)` from `@valve-tech/tx-tracker`.
236
+
237
+ ### Recognizing both packages in the user's code
238
+
239
+ ```ts
240
+ import { createGasOracle } from '@valve-tech/gas-oracle'
241
+ import { createTxTracker } from '@valve-tech/tx-tracker'
242
+ // `package.json` will have both under dependencies, plus
243
+ // `@valve-tech/chain-source` (the shared foundation both consume).
244
+ ```