@valve-tech/gas-oracle 0.2.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 +270 -0
- package/dist/block-position.d.ts +97 -0
- package/dist/block-position.d.ts.map +1 -0
- package/dist/block-position.js +131 -0
- package/dist/block-position.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/math.d.ts +148 -0
- package/dist/math.d.ts.map +1 -0
- package/dist/math.js +343 -0
- package/dist/math.js.map +1 -0
- package/dist/mempool.d.ts +89 -0
- package/dist/mempool.d.ts.map +1 -0
- package/dist/mempool.js +108 -0
- package/dist/mempool.js.map +1 -0
- package/dist/oracle.d.ts +139 -0
- package/dist/oracle.d.ts.map +1 -0
- package/dist/oracle.js +208 -0
- package/dist/oracle.js.map +1 -0
- package/dist/samples.d.ts +36 -0
- package/dist/samples.d.ts.map +1 -0
- package/dist/samples.js +107 -0
- package/dist/samples.js.map +1 -0
- package/dist/transport.d.ts +75 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +72 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +168 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/dist/viem-actions.d.ts +77 -0
- package/dist/viem-actions.d.ts.map +1 -0
- package/dist/viem-actions.js +118 -0
- package/dist/viem-actions.js.map +1 -0
- package/dist/viem-transport.d.ts +85 -0
- package/dist/viem-transport.d.ts.map +1 -0
- package/dist/viem-transport.js +165 -0
- package/dist/viem-transport.js.map +1 -0
- package/package.json +81 -0
- package/src/index.ts +84 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Valve Tech
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# @valve-tech/gas-oracle
|
|
2
|
+
|
|
3
|
+
Multi-tier gas-fee oracle for EVM chains. Pass it a viem `PublicClient`
|
|
4
|
+
and it polls block + mempool data, computes `slow` / `standard` /
|
|
5
|
+
`fast` / `instant` tier recommendations, and serves them via an
|
|
6
|
+
in-memory cache. Includes a configurable downside-decay cap, a chain-
|
|
7
|
+
aware EIP-1559 priority cutoff, and EIP-4844 blob-fee handling.
|
|
8
|
+
|
|
9
|
+
Zero runtime dependencies. `viem` is the only peer dependency.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
yarn add @valve-tech/gas-oracle viem
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { createPublicClient, http, parseEther } from 'viem'
|
|
21
|
+
import { mainnet } from 'viem/chains'
|
|
22
|
+
import { createGasOracle } from '@valve-tech/gas-oracle'
|
|
23
|
+
|
|
24
|
+
const client = createPublicClient({ chain: mainnet, transport: http() })
|
|
25
|
+
|
|
26
|
+
const oracle = createGasOracle({
|
|
27
|
+
client,
|
|
28
|
+
chainId: 1,
|
|
29
|
+
priorityFeeDecayCap: parseEther('0.125'), // 12.5%/block, EIP-1559 parity
|
|
30
|
+
priorityModel: 'eip1559', // 'flat' for extractive networks
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
oracle.subscribe((state) => {
|
|
34
|
+
console.log('fast tier:', state.tiers.fast.maxPriorityFeePerGas)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
oracle.start()
|
|
38
|
+
|
|
39
|
+
// Sub-millisecond read, no RPC roundtrip:
|
|
40
|
+
const tier = oracle.getState()?.tiers.standard
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Tier semantics
|
|
44
|
+
|
|
45
|
+
Each tier is one `TierRecommendation`:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
interface TierRecommendation {
|
|
49
|
+
maxPriorityFeePerGas: bigint
|
|
50
|
+
maxFeePerGas: bigint // bufferedBaseFee + maxPriorityFeePerGas
|
|
51
|
+
gasPrice: bigint // baseFee + maxPriorityFeePerGas (legacy)
|
|
52
|
+
maxFeePerBlobGas: bigint | null // null on chains without EIP-4844
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Tier mapping in the gas-weighted percentile distribution:
|
|
57
|
+
|
|
58
|
+
| Tier | Percentile | Use for |
|
|
59
|
+
|------------|------------|--------------------------------------------------------------|
|
|
60
|
+
| `slow` | p10 | Background / non-time-sensitive ops (claims, batched writes) |
|
|
61
|
+
| `standard` | p50 | Default for most user actions |
|
|
62
|
+
| `fast` | p75 | Trades, swaps, anything competing with bots |
|
|
63
|
+
| `instant` | p90 | Auctions, MEV-adjacent, opt-out-of-mempool deals |
|
|
64
|
+
|
|
65
|
+
`slow` always reads from the full distribution (legacy + 1559) so legacy
|
|
66
|
+
senders can still find the lane they actually live in. Under
|
|
67
|
+
`priorityModel: 'eip1559'`, the paying-lane tiers (`standard`/`fast`/
|
|
68
|
+
`instant`) draw from type-2+ samples only — legacy spam can't suppress
|
|
69
|
+
them.
|
|
70
|
+
|
|
71
|
+
## Configuration
|
|
72
|
+
|
|
73
|
+
### `priorityFeeDecayCap`
|
|
74
|
+
|
|
75
|
+
How fast the published priority-fee tip is allowed to drop, expressed
|
|
76
|
+
wad (1e18 = 100%). Use `parseEther` for the human-readable form:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
priorityFeeDecayCap: parseEther('0.125') // 12.5%/block (EIP-1559 parity)
|
|
80
|
+
priorityFeeDecayCap: parseEther('0.05') // 5%/block (smoother)
|
|
81
|
+
priorityFeeDecayCap: parseEther('0') // no decay allowed (sticky floor)
|
|
82
|
+
priorityFeeDecayCap: parseEther('1') // full collapse after one block
|
|
83
|
+
priorityFeeDecayCap: null // uncapped — track raw mempool
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Validated at construction; out-of-range values throw. Upside is always
|
|
87
|
+
unclamped — real spikes propagate immediately.
|
|
88
|
+
|
|
89
|
+
### `priorityModel`
|
|
90
|
+
|
|
91
|
+
Where the chain's inclusion logic draws its priority cutoff in the
|
|
92
|
+
EIP-2718 type space:
|
|
93
|
+
|
|
94
|
+
- `'flat'` — every tx contributes equally to the gas-weighted
|
|
95
|
+
distribution. Right for extractive validators (PulseChain, etc.)
|
|
96
|
+
that ignore the type byte and just maximize fee per gas.
|
|
97
|
+
- `'eip1559'` — type 2+ samples drive the paying-lane tiers (standard/
|
|
98
|
+
fast/instant); `slow` still draws from the full distribution. Right
|
|
99
|
+
for chains that honor EIP-1559 ordering (Ethereum, most L2s).
|
|
100
|
+
|
|
101
|
+
Default `'flat'` (most conservative — never under-counts spam).
|
|
102
|
+
|
|
103
|
+
### `baseFeeLivenessBlocks`
|
|
104
|
+
|
|
105
|
+
How many blocks the published recommendation should survive in the
|
|
106
|
+
worst case. The buffered base fee underpinning `maxFeePerGas` becomes
|
|
107
|
+
`baseFee × (9/8)^N` (the EIP-1559 worst-case rise compounded over N
|
|
108
|
+
blocks), so a tx submitted with the snapshot still lands within `N`
|
|
109
|
+
blocks even if every intervening block is full.
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
baseFeeLivenessBlocks: 1 // default; one block of headroom (= old behavior)
|
|
113
|
+
baseFeeLivenessBlocks: 6 // ~1.5 minutes on Ethereum, ~2 minutes on PulseChain
|
|
114
|
+
baseFeeLivenessBlocks: 30 // generous cushion for slow human approvals
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
`falling` markets stay at 1× regardless of N (base fee will continue
|
|
118
|
+
to drop, headroom is wasted).
|
|
119
|
+
|
|
120
|
+
### `poll`
|
|
121
|
+
|
|
122
|
+
Producer-side toggles for upstream RPC calls:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
poll: {
|
|
126
|
+
feeHistory: true, // eth_feeHistory; powers trend detection
|
|
127
|
+
mempool: true, // txpool_content; powers pending-pressure signal
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Both default `true`. Setting either to `false` skips that RPC entirely
|
|
132
|
+
each cycle. Useful when the upstream provider gates the method (many
|
|
133
|
+
public RPCs return 405 on `txpool_content`) or when you want a
|
|
134
|
+
minimum-RPC-budget oracle. `eth_getBlockByNumber` is not toggleable.
|
|
135
|
+
|
|
136
|
+
### `keepMempoolSnapshot`
|
|
137
|
+
|
|
138
|
+
When `true`, the oracle retains the latest normalized mempool snapshot
|
|
139
|
+
and exposes it via `oracle.getMempoolSnapshot()`. The snapshot powers
|
|
140
|
+
`findInMempool` / `tipForBlockPosition({ kind: 'aheadOf' })`-style
|
|
141
|
+
lookups without a second RPC roundtrip. Memory cost is the size of one
|
|
142
|
+
`txpool_content` payload (5–15MB on busy ETH mainnet); leave off in
|
|
143
|
+
browser/mobile contexts. Default `false`.
|
|
144
|
+
|
|
145
|
+
## Mempool inspection
|
|
146
|
+
|
|
147
|
+
Two ways into the same data: pure helpers that take a normalized pool
|
|
148
|
+
(if you already have one) or oracle-backed actions (if you're already
|
|
149
|
+
running a `GasOracle`).
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
import {
|
|
153
|
+
normalizeMempool,
|
|
154
|
+
findByHash,
|
|
155
|
+
findByAddressNonce,
|
|
156
|
+
findInMempool,
|
|
157
|
+
} from '@valve-tech/gas-oracle'
|
|
158
|
+
|
|
159
|
+
// Normalize once at ingest — case-folds sender addresses and
|
|
160
|
+
// decimalizes nonce keys. All lookups expect the normalized form.
|
|
161
|
+
const pool = normalizeMempool(rawPoolFromTxpoolContent)
|
|
162
|
+
|
|
163
|
+
findByHash(pool, '0xdeadbeef…') // MempoolHit | null
|
|
164
|
+
findByAddressNonce(pool, '0xabc…', 5) // MempoolHit | null
|
|
165
|
+
findInMempool(pool, { hash: '0xdeadbeef…' }) // discriminated form
|
|
166
|
+
findInMempool(pool, { address: '0xabc…', nonce: 5n })
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
`MempoolHit` carries the matched `tx`, the `bucket` (`'pending'` /
|
|
170
|
+
`'queued'`), and the canonicalized `address` + `nonce`.
|
|
171
|
+
|
|
172
|
+
## Block-position calculations
|
|
173
|
+
|
|
174
|
+
Compute the priority fee required to land at a target position in the
|
|
175
|
+
next block. The query is a discriminated union — each `kind` carries
|
|
176
|
+
exactly the fields it needs:
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
import { tipForBlockPosition } from '@valve-tech/gas-oracle'
|
|
180
|
+
|
|
181
|
+
// Absolute targeting
|
|
182
|
+
tipForBlockPosition(samples, { kind: 'rank', rank: 0 }) // top of block
|
|
183
|
+
tipForBlockPosition(samples, { kind: 'percentile', percentile: 5 }) // top 5%
|
|
184
|
+
tipForBlockPosition(samples, { kind: 'gasFromTop', gas: 1_000_000n }) // first 1M gas
|
|
185
|
+
|
|
186
|
+
// Relative targeting — beat or undercut a specific tx
|
|
187
|
+
tipForBlockPosition(samples, { kind: 'aheadOf', tx: { hash: '0xabc…' } })
|
|
188
|
+
tipForBlockPosition(samples, { kind: 'behind', tx: { address: '0xabc…', nonce: 5 } })
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Returns `{ requiredTip, pivot, rank, gasFromTop }`. `requiredTip` is
|
|
192
|
+
the *minimum* tip — pivot.tip + 1 wei to outbid, or pivot.tip - 1 wei
|
|
193
|
+
to undercut. Add your own buffer for finality.
|
|
194
|
+
|
|
195
|
+
`samples` is typically the merged ring + mempool tip distribution —
|
|
196
|
+
the same union `computeTiers` reads. The viem-actions extension
|
|
197
|
+
exposes `client.tipForBlockPosition(query)` which assembles this
|
|
198
|
+
distribution for you from the oracle's state.
|
|
199
|
+
|
|
200
|
+
## viem integration
|
|
201
|
+
|
|
202
|
+
### Subpath: `@valve-tech/gas-oracle/viem-actions`
|
|
203
|
+
|
|
204
|
+
Extension surface for callers who want explicit access to tier shapes:
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
import { gasOracleActions } from '@valve-tech/gas-oracle/viem-actions'
|
|
208
|
+
|
|
209
|
+
const client = createPublicClient({ chain: mainnet, transport: http() })
|
|
210
|
+
.extend(gasOracleActions({
|
|
211
|
+
chainId: 1,
|
|
212
|
+
priorityFeeDecayCap: parseEther('0.125'),
|
|
213
|
+
priorityModel: 'eip1559',
|
|
214
|
+
}))
|
|
215
|
+
|
|
216
|
+
await client.getGasTiers() // full snapshot
|
|
217
|
+
await client.getGasTier('fast') // one tier
|
|
218
|
+
await client.findTxInMempool({ hash: '0xabc…' }) // mempool lookup
|
|
219
|
+
await client.tipForBlockPosition({ // position targeting
|
|
220
|
+
kind: 'aheadOf',
|
|
221
|
+
tx: { address: '0xabc…', nonce: 5 },
|
|
222
|
+
})
|
|
223
|
+
client.stopGasOracle() // shutdown hook
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Subpath: `@valve-tech/gas-oracle/viem-transport`
|
|
227
|
+
|
|
228
|
+
Drop-in replacement for callers who want viem's existing API to *just
|
|
229
|
+
work better* — `useFeeData`, `walletClient.sendTransaction({...})`,
|
|
230
|
+
`estimateMaxPriorityFeePerGas`, and so on:
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
import { withGasOracle } from '@valve-tech/gas-oracle/viem-transport'
|
|
234
|
+
|
|
235
|
+
const transport = withGasOracle(http(rpcUrl), {
|
|
236
|
+
chainId: 1,
|
|
237
|
+
priorityFeeDecayCap: parseEther('0.125'),
|
|
238
|
+
priorityModel: 'eip1559',
|
|
239
|
+
intercept: {
|
|
240
|
+
eth_gasFeeEstimate: true, // additive (default on)
|
|
241
|
+
eth_maxPriorityFeePerGas: 'fast', // tier required for standard methods
|
|
242
|
+
},
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
const client = createPublicClient({ chain: mainnet, transport })
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Default `intercept` is `{ eth_gasFeeEstimate: true }` only — the
|
|
249
|
+
additive method that returns multi-tier shape. Standard methods
|
|
250
|
+
(`eth_gasPrice`, `eth_maxPriorityFeePerGas`) pass through to upstream
|
|
251
|
+
unless explicitly opted in **with a tier name**. Boolean opt-in on the
|
|
252
|
+
standard methods is intentionally not accepted: a default tier choice
|
|
253
|
+
would silently make the method's number depend on the package version,
|
|
254
|
+
and that's the silently-pick-a-percentile foot-gun this design is
|
|
255
|
+
careful to avoid.
|
|
256
|
+
|
|
257
|
+
`eth_feeHistory` is intentionally NOT in the intercept config —
|
|
258
|
+
synthesizing a historical-percentile array from oracle state is its
|
|
259
|
+
own design problem. Always passes through to upstream.
|
|
260
|
+
|
|
261
|
+
## Wire format
|
|
262
|
+
|
|
263
|
+
Every fee field is a `bigint`. Callers serializing across HTTP / Redis
|
|
264
|
+
/ WebSocket should hex-encode (`'0x' + n.toString(16)`) since JSON has
|
|
265
|
+
no native bigint and `JSON.stringify` will throw on raw bigint values.
|
|
266
|
+
The package keeps the canonical numeric form internally.
|
|
267
|
+
|
|
268
|
+
## License
|
|
269
|
+
|
|
270
|
+
MIT
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block-position calculator.
|
|
3
|
+
*
|
|
4
|
+
* Validators include txs in *gas-weighted tip-descending order* — high
|
|
5
|
+
* tip-per-gas at the top of the block, low tip-per-gas at the bottom.
|
|
6
|
+
* "Position in the block" therefore has two natural axes:
|
|
7
|
+
*
|
|
8
|
+
* 1. **Rank** — count from the top. Position 0 is the highest-tip tx.
|
|
9
|
+
* 2. **Gas offset** — accumulated gas consumed by all higher-tip txs.
|
|
10
|
+
* Position is "I want my tx mined within the first 1M gas of the
|
|
11
|
+
* block" → walk samples in tip-desc order, sum gas, find the
|
|
12
|
+
* pivot whose cumulative cross 1M.
|
|
13
|
+
*
|
|
14
|
+
* Both axes resolve to the same machinery — pick a pivot in the
|
|
15
|
+
* sorted-by-tip-desc sample list, return the tip you'd need to pay to
|
|
16
|
+
* outbid it.
|
|
17
|
+
*
|
|
18
|
+
* `tipForBlockPosition` returns the *minimum* tip to land at the
|
|
19
|
+
* requested position; callers should add their own buffer for finality.
|
|
20
|
+
* Equality at the same tip is validator-policy-dependent and not
|
|
21
|
+
* guaranteed, so "outbid by 1 wei" is the honest minimum.
|
|
22
|
+
*/
|
|
23
|
+
import type { TipSample } from './types.js';
|
|
24
|
+
import type { TxIdentifier } from './mempool.js';
|
|
25
|
+
/**
|
|
26
|
+
* What position to target in the gas-weighted, tip-descending order
|
|
27
|
+
* of a block. Discriminated by `kind`:
|
|
28
|
+
*
|
|
29
|
+
* - `'rank'` — `rank` is 0-indexed from the top (highest tip).
|
|
30
|
+
* `rank: 0` → land at the very top; `rank: 4` →
|
|
31
|
+
* land in 5th place.
|
|
32
|
+
* - `'percentile'` — `percentile` is `[0, 100]` from the top.
|
|
33
|
+
* `percentile: 5` → I want to be in the top 5%.
|
|
34
|
+
* - `'gasFromTop'` — `gas` is a bigint of cumulative gas from the
|
|
35
|
+
* block top. `gas: 1_000_000n` → land within the
|
|
36
|
+
* first 1M gas of the block.
|
|
37
|
+
* - `'aheadOf'` — beat out a specific tx in the distribution.
|
|
38
|
+
* Useful for MEV-style "I just need to outrank
|
|
39
|
+
* this swap" targeting.
|
|
40
|
+
* - `'behind'` — be just behind a specific tx (still mine in the
|
|
41
|
+
* same block, but pay less). Useful for piggybacking
|
|
42
|
+
* on a high-tip tx that's already going to displace
|
|
43
|
+
* pressure.
|
|
44
|
+
*
|
|
45
|
+
* Discriminated-union over flat-options-with-mode: per project style,
|
|
46
|
+
* fields whose presence depends on the kind belong inside the kind's
|
|
47
|
+
* variant, not flattened with `?`-marks.
|
|
48
|
+
*/
|
|
49
|
+
export type BlockPositionQuery = {
|
|
50
|
+
kind: 'rank';
|
|
51
|
+
rank: number;
|
|
52
|
+
} | {
|
|
53
|
+
kind: 'percentile';
|
|
54
|
+
percentile: number;
|
|
55
|
+
} | {
|
|
56
|
+
kind: 'gasFromTop';
|
|
57
|
+
gas: bigint;
|
|
58
|
+
} | {
|
|
59
|
+
kind: 'aheadOf';
|
|
60
|
+
tx: TxIdentifier;
|
|
61
|
+
} | {
|
|
62
|
+
kind: 'behind';
|
|
63
|
+
tx: TxIdentifier;
|
|
64
|
+
};
|
|
65
|
+
export interface BlockPositionResult {
|
|
66
|
+
/**
|
|
67
|
+
* Minimum tip-per-gas to definitively land at the requested position.
|
|
68
|
+
* For `aheadOf` and `gasFromTop`/`rank`/`percentile` queries, this is
|
|
69
|
+
* `pivot.tip + 1n` (one wei above the tx at the boundary). For
|
|
70
|
+
* `behind`, this is `max(pivot.tip - 1n, 0n)`. Returns `0n` when the
|
|
71
|
+
* distribution is empty or the position is below everyone.
|
|
72
|
+
*/
|
|
73
|
+
requiredTip: bigint;
|
|
74
|
+
/**
|
|
75
|
+
* The sample at the boundary — the tx you're outbidding (or
|
|
76
|
+
* undercutting). `null` when the requested position is outside the
|
|
77
|
+
* distribution (e.g. `rank: 1000` in a 50-tx block) or the
|
|
78
|
+
* distribution is empty.
|
|
79
|
+
*/
|
|
80
|
+
pivot: TipSample | null;
|
|
81
|
+
/** Approximate rank of the resolved position, 0-indexed from top. */
|
|
82
|
+
rank: number;
|
|
83
|
+
/** Approximate gas-from-top of the resolved position. */
|
|
84
|
+
gasFromTop: bigint;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Compute the tip required to land at the requested position in the
|
|
88
|
+
* next block, given a sample distribution (typically the merged ring
|
|
89
|
+
* + mempool samples that `computeTiers` consumes, but any
|
|
90
|
+
* `TipSample[]` works — pass just block samples for "would I have
|
|
91
|
+
* landed in the last block?" hindsight).
|
|
92
|
+
*
|
|
93
|
+
* Pure: no I/O, no oracle dependency, no wall-clock. Test by feeding
|
|
94
|
+
* fixture samples and asserting the returned shape.
|
|
95
|
+
*/
|
|
96
|
+
export declare const tipForBlockPosition: (samples: TipSample[], query: BlockPositionQuery) => BlockPositionResult;
|
|
97
|
+
//# sourceMappingURL=block-position.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block-position.d.ts","sourceRoot":"","sources":["../src/block-position.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,EAAE,EAAE,YAAY,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,YAAY,CAAA;CAAE,CAAA;AAExC,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;;;;OAKG;IACH,KAAK,EAAE,SAAS,GAAG,IAAI,CAAA;IACvB,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAA;CACnB;AA+CD;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAC9B,SAAS,SAAS,EAAE,EACpB,OAAO,kBAAkB,KACxB,mBA0DF,CAAA"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block-position calculator.
|
|
3
|
+
*
|
|
4
|
+
* Validators include txs in *gas-weighted tip-descending order* — high
|
|
5
|
+
* tip-per-gas at the top of the block, low tip-per-gas at the bottom.
|
|
6
|
+
* "Position in the block" therefore has two natural axes:
|
|
7
|
+
*
|
|
8
|
+
* 1. **Rank** — count from the top. Position 0 is the highest-tip tx.
|
|
9
|
+
* 2. **Gas offset** — accumulated gas consumed by all higher-tip txs.
|
|
10
|
+
* Position is "I want my tx mined within the first 1M gas of the
|
|
11
|
+
* block" → walk samples in tip-desc order, sum gas, find the
|
|
12
|
+
* pivot whose cumulative cross 1M.
|
|
13
|
+
*
|
|
14
|
+
* Both axes resolve to the same machinery — pick a pivot in the
|
|
15
|
+
* sorted-by-tip-desc sample list, return the tip you'd need to pay to
|
|
16
|
+
* outbid it.
|
|
17
|
+
*
|
|
18
|
+
* `tipForBlockPosition` returns the *minimum* tip to land at the
|
|
19
|
+
* requested position; callers should add their own buffer for finality.
|
|
20
|
+
* Equality at the same tip is validator-policy-dependent and not
|
|
21
|
+
* guaranteed, so "outbid by 1 wei" is the honest minimum.
|
|
22
|
+
*/
|
|
23
|
+
const sortByTipDesc = (samples) => [...samples].sort((a, b) => (a.tip > b.tip ? -1 : a.tip < b.tip ? 1 : 0));
|
|
24
|
+
const matchesIdentifier = (sample, id) => {
|
|
25
|
+
if ('hash' in id) {
|
|
26
|
+
return (typeof sample.hash === 'string' &&
|
|
27
|
+
sample.hash.toLowerCase() === id.hash.toLowerCase());
|
|
28
|
+
}
|
|
29
|
+
if (sample.address === undefined || sample.nonce === undefined)
|
|
30
|
+
return false;
|
|
31
|
+
if (sample.address.toLowerCase() !== id.address.toLowerCase())
|
|
32
|
+
return false;
|
|
33
|
+
return sample.nonce === BigInt(id.nonce).toString();
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Walk samples in tip-desc order accumulating gas; return the index
|
|
37
|
+
* (0-based from top) where cumulative gas first crosses `targetGas`.
|
|
38
|
+
* Returns -1 when the target exceeds the sum of all gas (the position
|
|
39
|
+
* is below the whole distribution).
|
|
40
|
+
*/
|
|
41
|
+
const indexAtGasOffset = (sorted, targetGas) => {
|
|
42
|
+
if (targetGas <= 0n)
|
|
43
|
+
return 0;
|
|
44
|
+
let cumulative = 0n;
|
|
45
|
+
for (let i = 0; i < sorted.length; i += 1) {
|
|
46
|
+
cumulative += sorted[i].gas;
|
|
47
|
+
if (cumulative > targetGas)
|
|
48
|
+
return i;
|
|
49
|
+
}
|
|
50
|
+
return -1;
|
|
51
|
+
};
|
|
52
|
+
const sumGasUpTo = (sorted, indexExclusive) => {
|
|
53
|
+
let g = 0n;
|
|
54
|
+
const upper = Math.min(indexExclusive, sorted.length);
|
|
55
|
+
for (let i = 0; i < upper; i += 1)
|
|
56
|
+
g += sorted[i].gas;
|
|
57
|
+
return g;
|
|
58
|
+
};
|
|
59
|
+
const empty = () => ({
|
|
60
|
+
requiredTip: 0n,
|
|
61
|
+
pivot: null,
|
|
62
|
+
rank: 0,
|
|
63
|
+
gasFromTop: 0n,
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* Compute the tip required to land at the requested position in the
|
|
67
|
+
* next block, given a sample distribution (typically the merged ring
|
|
68
|
+
* + mempool samples that `computeTiers` consumes, but any
|
|
69
|
+
* `TipSample[]` works — pass just block samples for "would I have
|
|
70
|
+
* landed in the last block?" hindsight).
|
|
71
|
+
*
|
|
72
|
+
* Pure: no I/O, no oracle dependency, no wall-clock. Test by feeding
|
|
73
|
+
* fixture samples and asserting the returned shape.
|
|
74
|
+
*/
|
|
75
|
+
export const tipForBlockPosition = (samples, query) => {
|
|
76
|
+
if (samples.length === 0)
|
|
77
|
+
return empty();
|
|
78
|
+
const sorted = sortByTipDesc(samples);
|
|
79
|
+
let pivotIndex;
|
|
80
|
+
let beatPivot; // true = outbid (tip+1), false = undercut (tip-1)
|
|
81
|
+
switch (query.kind) {
|
|
82
|
+
case 'rank': {
|
|
83
|
+
pivotIndex = query.rank;
|
|
84
|
+
beatPivot = true;
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
case 'percentile': {
|
|
88
|
+
// 0% = top of block (highest tip); 100% = bottom. Clamp to [0, 100].
|
|
89
|
+
const pct = Math.min(100, Math.max(0, query.percentile));
|
|
90
|
+
pivotIndex = Math.floor((sorted.length * pct) / 100);
|
|
91
|
+
// Edge: percentile=100 lands at length, which is "below everything"
|
|
92
|
+
if (pivotIndex >= sorted.length)
|
|
93
|
+
pivotIndex = sorted.length - 1;
|
|
94
|
+
beatPivot = true;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
case 'gasFromTop': {
|
|
98
|
+
pivotIndex = indexAtGasOffset(sorted, query.gas);
|
|
99
|
+
beatPivot = true;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case 'aheadOf':
|
|
103
|
+
case 'behind': {
|
|
104
|
+
pivotIndex = sorted.findIndex((s) => matchesIdentifier(s, query.tx));
|
|
105
|
+
beatPivot = query.kind === 'aheadOf';
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (pivotIndex < 0 || pivotIndex >= sorted.length) {
|
|
110
|
+
// Position is below everyone (or pivot not found) — pay nothing in priority
|
|
111
|
+
return {
|
|
112
|
+
requiredTip: 0n,
|
|
113
|
+
pivot: null,
|
|
114
|
+
rank: sorted.length,
|
|
115
|
+
gasFromTop: sumGasUpTo(sorted, sorted.length),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const pivot = sorted[pivotIndex];
|
|
119
|
+
const requiredTip = beatPivot
|
|
120
|
+
? pivot.tip + 1n
|
|
121
|
+
: pivot.tip > 0n
|
|
122
|
+
? pivot.tip - 1n
|
|
123
|
+
: 0n;
|
|
124
|
+
return {
|
|
125
|
+
requiredTip,
|
|
126
|
+
pivot,
|
|
127
|
+
rank: pivotIndex,
|
|
128
|
+
gasFromTop: sumGasUpTo(sorted, pivotIndex),
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
//# sourceMappingURL=block-position.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block-position.js","sourceRoot":"","sources":["../src/block-position.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @valve-tech/gas-oracle — public API.
|
|
3
|
+
*
|
|
4
|
+
* Multi-tier gas-fee oracle for EVM chains. Pass it a viem PublicClient
|
|
5
|
+
* and it polls block + mempool data, computes slow/standard/fast/instant
|
|
6
|
+
* tier recommendations, and exposes them via a sub-millisecond in-memory
|
|
7
|
+
* read. Includes EIP-1559-style 12.5%/block downside cap so quiet blocks
|
|
8
|
+
* don't drop the published number off a cliff, and EIP-4844 blob fee
|
|
9
|
+
* for chains that support it.
|
|
10
|
+
*
|
|
11
|
+
* Zero runtime dependencies. viem is the only peer dependency, used to
|
|
12
|
+
* issue the underlying RPC calls (`eth_feeHistory`,
|
|
13
|
+
* `eth_getBlockByNumber`, `txpool_content`).
|
|
14
|
+
*/
|
|
15
|
+
export { createGasOracle, reducePollInputs, type CreateGasOracleOptions, type GasOracle, } from './oracle.js';
|
|
16
|
+
export { effectiveTip, computePercentiles, detectTrend, cappedTip, computeTiers, computeBlobBaseFee, flattenTxPool, gasWeightedPercentiles, sortedTips, DEFAULT_PRIORITY_FEE_DECAY_CAP, DEFAULT_BASE_FEE_LIVENESS_BLOCKS, } from './math.js';
|
|
17
|
+
export { blockToSample, mempoolToSamples, } from './samples.js';
|
|
18
|
+
export { fetchOracleInputs, type FeeHistoryResult, type BlockResult, type TxPoolContent, type OraclePollInputs, } from './transport.js';
|
|
19
|
+
export type { RawTx, TipPercentiles, TierRecommendation, TierName, Trend, MempoolStats, BlobStats, BlockSample, GasOracleState, TipSample, PriorityModel, PollOptions, } from './types.js';
|
|
20
|
+
export { normalizeMempool, findByHash, findByAddressNonce, findInMempool, } from './mempool.js';
|
|
21
|
+
export type { NormalizedMempool, TxIdentifier, MempoolBucket, MempoolHit, } from './mempool.js';
|
|
22
|
+
export { tipForBlockPosition } from './block-position.js';
|
|
23
|
+
export type { BlockPositionQuery, BlockPositionResult, } from './block-position.js';
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,KAAK,sBAAsB,EAC3B,KAAK,SAAS,GACf,MAAM,aAAa,CAAA;AAEpB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,SAAS,EACT,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,sBAAsB,EACtB,UAAU,EACV,8BAA8B,EAC9B,gCAAgC,GACjC,MAAM,WAAW,CAAA;AAElB,OAAO,EACL,aAAa,EACb,gBAAgB,GACjB,MAAM,cAAc,CAAA;AAErB,OAAO,EACL,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,gBAAgB,GACtB,MAAM,gBAAgB,CAAA;AAEvB,YAAY,EACV,KAAK,EACL,cAAc,EACd,kBAAkB,EAClB,QAAQ,EACR,KAAK,EACL,YAAY,EACZ,SAAS,EACT,WAAW,EACX,cAAc,EACd,SAAS,EACT,aAAa,EACb,WAAW,GACZ,MAAM,YAAY,CAAA;AAGnB,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,aAAa,GACd,MAAM,cAAc,CAAA;AACrB,YAAY,EACV,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,UAAU,GACX,MAAM,cAAc,CAAA;AAGrB,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AACzD,YAAY,EACV,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,qBAAqB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @valve-tech/gas-oracle — public API.
|
|
3
|
+
*
|
|
4
|
+
* Multi-tier gas-fee oracle for EVM chains. Pass it a viem PublicClient
|
|
5
|
+
* and it polls block + mempool data, computes slow/standard/fast/instant
|
|
6
|
+
* tier recommendations, and exposes them via a sub-millisecond in-memory
|
|
7
|
+
* read. Includes EIP-1559-style 12.5%/block downside cap so quiet blocks
|
|
8
|
+
* don't drop the published number off a cliff, and EIP-4844 blob fee
|
|
9
|
+
* for chains that support it.
|
|
10
|
+
*
|
|
11
|
+
* Zero runtime dependencies. viem is the only peer dependency, used to
|
|
12
|
+
* issue the underlying RPC calls (`eth_feeHistory`,
|
|
13
|
+
* `eth_getBlockByNumber`, `txpool_content`).
|
|
14
|
+
*/
|
|
15
|
+
export { createGasOracle, reducePollInputs, } from './oracle.js';
|
|
16
|
+
export { effectiveTip, computePercentiles, detectTrend, cappedTip, computeTiers, computeBlobBaseFee, flattenTxPool, gasWeightedPercentiles, sortedTips, DEFAULT_PRIORITY_FEE_DECAY_CAP, DEFAULT_BASE_FEE_LIVENESS_BLOCKS, } from './math.js';
|
|
17
|
+
export { blockToSample, mempoolToSamples, } from './samples.js';
|
|
18
|
+
export { fetchOracleInputs, } from './transport.js';
|
|
19
|
+
// Mempool inspection
|
|
20
|
+
export { normalizeMempool, findByHash, findByAddressNonce, findInMempool, } from './mempool.js';
|
|
21
|
+
// Block-position calculations
|
|
22
|
+
export { tipForBlockPosition } from './block-position.js';
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,eAAe,EACf,gBAAgB,GAGjB,MAAM,aAAa,CAAA;AAEpB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,SAAS,EACT,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,sBAAsB,EACtB,UAAU,EACV,8BAA8B,EAC9B,gCAAgC,GACjC,MAAM,WAAW,CAAA;AAElB,OAAO,EACL,aAAa,EACb,gBAAgB,GACjB,MAAM,cAAc,CAAA;AAErB,OAAO,EACL,iBAAiB,GAKlB,MAAM,gBAAgB,CAAA;AAiBvB,qBAAqB;AACrB,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,aAAa,GACd,MAAM,cAAc,CAAA;AAQrB,8BAA8B;AAC9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA"}
|