hookr-sdk 0.2.1 → 1.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/CHANGELOG.md +70 -0
- package/LICENSE +21 -0
- package/MIGRATING.md +89 -0
- package/README.md +308 -105
- package/dist/core/abi.d.ts +10930 -0
- package/dist/core/abi.js +455 -0
- package/dist/core/advisories.d.ts +184 -0
- package/dist/core/advisories.js +291 -0
- package/dist/core/client.d.ts +55 -0
- package/dist/core/client.js +107 -0
- package/dist/core/generated.d.ts +14295 -0
- package/dist/core/generated.js +1058 -0
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.js +17 -0
- package/dist/core/launch.d.ts +200 -0
- package/dist/core/launch.js +427 -0
- package/dist/core/pair.d.ts +64 -0
- package/dist/core/pair.js +136 -0
- package/dist/core/params.d.ts +415 -0
- package/dist/core/params.js +1235 -0
- package/dist/core/policies.d.ts +136 -0
- package/dist/core/policies.js +125 -0
- package/dist/core/proofs.d.ts +25 -0
- package/dist/core/proofs.js +118 -0
- package/dist/core/quotes.d.ts +185 -0
- package/dist/core/quotes.js +550 -0
- package/dist/core/referrals.d.ts +32 -0
- package/dist/core/referrals.js +36 -0
- package/dist/core/registry.d.ts +357 -0
- package/dist/core/registry.js +378 -0
- package/dist/core/rules.d.ts +675 -0
- package/dist/core/rules.js +1049 -0
- package/dist/core/schema.d.ts +358 -0
- package/dist/core/schema.js +105 -0
- package/dist/core/stocks.generated.d.ts +11 -0
- package/dist/core/stocks.generated.js +1228 -0
- package/dist/core/vault.d.ts +59 -0
- package/dist/core/vault.js +112 -0
- package/dist/core/wallet.d.ts +142 -0
- package/dist/core/wallet.js +304 -0
- package/dist/deployments.d.ts +8 -0
- package/dist/deployments.js +26 -0
- package/dist/index.d.ts +42 -15
- package/dist/index.js +40 -15
- package/dist/releases.d.ts +219 -0
- package/dist/releases.js +365 -0
- package/dist/wallet-cap.d.ts +159 -0
- package/dist/wallet-cap.js +234 -0
- package/package.json +46 -10
- package/provenance.json +31 -0
- package/dist/abi.d.ts +0 -6404
- package/dist/abi.js +0 -8300
- package/dist/chain.d.ts +0 -87
- package/dist/chain.js +0 -86
- package/dist/claims.d.ts +0 -32
- package/dist/claims.js +0 -31
- package/dist/fees.d.ts +0 -59
- package/dist/fees.js +0 -142
- package/dist/links.d.ts +0 -48
- package/dist/links.js +0 -93
- package/dist/market.d.ts +0 -264
- package/dist/market.js +0 -310
- package/dist/reads.d.ts +0 -136
- package/dist/reads.js +0 -219
- package/dist/rules.d.ts +0 -84
- package/dist/rules.js +0 -296
- package/dist/swap.d.ts +0 -108
- package/dist/swap.js +0 -144
package/dist/rules.js
DELETED
|
@@ -1,296 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The public rules a market's stack can carry, and their bounds.
|
|
3
|
-
*
|
|
4
|
-
* Copied from the Hookr app's `src/lib/hooks-model.ts`: `RULES` mirrors `HOOKS` reduced to
|
|
5
|
-
* `{ key, name, summary, explanation }`, and `PARAMS` mirrors the bounds/step/default of the
|
|
6
|
-
* app's `PARAMS[type]` (its display-only `fmt` function is not carried here; `unit` is a short,
|
|
7
|
-
* human label instead — see the module doc below). Both are restricted to the app's
|
|
8
|
-
* `PUBLIC_BUILDER_HOOK_ORDER`, which today is the five deployed blocks (`HOOK_ORDER`): the
|
|
9
|
-
* directional tax module (`DIRECTIONAL_TAX_UI` in the app) is off and is not offered here either.
|
|
10
|
-
* `src/test/hookr-sdk-parity.test.ts` in the app asserts the key order and every bound match.
|
|
11
|
-
*
|
|
12
|
-
* A rule compiles into the native block's `Config` (see `fees.ts` and `market.ts`); it is not a
|
|
13
|
-
* separate contract call. At most five rules on a stack today, one per key, because there are
|
|
14
|
-
* only five public rule keys — `validateStack` still checks the count explicitly so a future
|
|
15
|
-
* sixth key does not silently raise the ceiling.
|
|
16
|
-
*/
|
|
17
|
-
/** The public rule keys, in the order the app's builder palette offers them. */
|
|
18
|
-
export const RULE_ORDER = ["snipe", "fee", "burn", "lp", "pot"];
|
|
19
|
-
export const RULES = Object.freeze([
|
|
20
|
-
Object.freeze({
|
|
21
|
-
key: "snipe",
|
|
22
|
-
name: "Anti-Snipe",
|
|
23
|
-
summary: "Caps early buys and adds an LP fee in the first blocks",
|
|
24
|
-
explanation: "It caps total ETH bought per pool block and adds an extra LP fee during a fixed opening window.",
|
|
25
|
-
}),
|
|
26
|
-
Object.freeze({
|
|
27
|
-
key: "fee",
|
|
28
|
-
name: "Surge Fees",
|
|
29
|
-
summary: "Fee scales with trade size",
|
|
30
|
-
explanation: "It raises the LP fee from a base rate toward a ceiling as trade size grows relative to in-range depth.",
|
|
31
|
-
}),
|
|
32
|
-
Object.freeze({
|
|
33
|
-
key: "burn",
|
|
34
|
-
name: "Auto Burn",
|
|
35
|
-
summary: "Burns a share of actual buy output",
|
|
36
|
-
explanation: "It sends a chosen share of each exact-input buy's token output directly to the dead address.",
|
|
37
|
-
}),
|
|
38
|
-
Object.freeze({
|
|
39
|
-
key: "lp",
|
|
40
|
-
name: "LP Rewards",
|
|
41
|
-
summary: "Fee share streams to LPs",
|
|
42
|
-
explanation: "It donates an ETH-side share of each exact-input buy to liquidity positions that are in range.",
|
|
43
|
-
}),
|
|
44
|
-
Object.freeze({
|
|
45
|
-
key: "pot",
|
|
46
|
-
name: "Nth-buy Pot",
|
|
47
|
-
summary: "A public counter pays every Nth buy",
|
|
48
|
-
explanation: "It fills a deterministic pot from exact-input buys and pays it to the recipient of every Nth qualifying buy.",
|
|
49
|
-
}),
|
|
50
|
-
]);
|
|
51
|
-
const RULES_BY_KEY = Object.freeze(Object.fromEntries(RULES.map((rule) => [rule.key, rule])));
|
|
52
|
-
export function ruleFor(key) {
|
|
53
|
-
return RULES_BY_KEY[key];
|
|
54
|
-
}
|
|
55
|
-
export const PARAMS = Object.freeze({
|
|
56
|
-
snipe: Object.freeze([
|
|
57
|
-
Object.freeze({
|
|
58
|
-
key: "guard",
|
|
59
|
-
label: "Guard window",
|
|
60
|
-
min: 5,
|
|
61
|
-
max: 500,
|
|
62
|
-
step: 5,
|
|
63
|
-
def: 100,
|
|
64
|
-
unit: "BLK",
|
|
65
|
-
hint: "Blocks after the pool opens with sniper protection active. Counted in the parent-chain blocks the contracts see (~12 s each), not this chain's ~0.1 s blocks, so 100 is roughly 20 minutes.",
|
|
66
|
-
}),
|
|
67
|
-
Object.freeze({
|
|
68
|
-
key: "maxbuy",
|
|
69
|
-
label: "Max buy",
|
|
70
|
-
min: 0.1,
|
|
71
|
-
max: 5,
|
|
72
|
-
step: 0.1,
|
|
73
|
-
def: 0.5,
|
|
74
|
-
unit: "%",
|
|
75
|
-
hint: "Cumulative cap on all buys in one pool block during the guard window, derived from a share of the launch's supply basis. Splitting one order does not create more room in that block.",
|
|
76
|
-
}),
|
|
77
|
-
Object.freeze({
|
|
78
|
-
key: "tax",
|
|
79
|
-
label: "Snipe tax",
|
|
80
|
-
min: 0,
|
|
81
|
-
max: 45,
|
|
82
|
-
step: 5,
|
|
83
|
-
def: 40,
|
|
84
|
-
unit: "%",
|
|
85
|
-
hint: "Extra LP fee on swaps inside the guard window. Goes to LPs.",
|
|
86
|
-
}),
|
|
87
|
-
]),
|
|
88
|
-
fee: Object.freeze([
|
|
89
|
-
Object.freeze({
|
|
90
|
-
key: "base",
|
|
91
|
-
label: "Base fee",
|
|
92
|
-
min: 0.05,
|
|
93
|
-
max: 1,
|
|
94
|
-
step: 0.05,
|
|
95
|
-
def: 0.3,
|
|
96
|
-
unit: "%",
|
|
97
|
-
hint: "Swap fee when the pool is calm.",
|
|
98
|
-
}),
|
|
99
|
-
Object.freeze({
|
|
100
|
-
key: "max",
|
|
101
|
-
label: "Max fee",
|
|
102
|
-
min: 1,
|
|
103
|
-
max: 10,
|
|
104
|
-
step: 0.5,
|
|
105
|
-
def: 3,
|
|
106
|
-
unit: "%",
|
|
107
|
-
hint: "Ceiling for large trades relative to pool depth.",
|
|
108
|
-
}),
|
|
109
|
-
Object.freeze({
|
|
110
|
-
key: "sens",
|
|
111
|
-
label: "Size sensitivity",
|
|
112
|
-
min: 1,
|
|
113
|
-
max: 10,
|
|
114
|
-
step: 1,
|
|
115
|
-
def: 5,
|
|
116
|
-
unit: "X",
|
|
117
|
-
hint: "How fast the fee ramps as a trade eats the pool.",
|
|
118
|
-
}),
|
|
119
|
-
]),
|
|
120
|
-
burn: Object.freeze([
|
|
121
|
-
Object.freeze({
|
|
122
|
-
key: "cut",
|
|
123
|
-
label: "Output burn",
|
|
124
|
-
min: 0.1,
|
|
125
|
-
max: 5,
|
|
126
|
-
step: 0.1,
|
|
127
|
-
def: 1,
|
|
128
|
-
unit: "% OUT",
|
|
129
|
-
hint: "Share of the actual token output sent directly to the dead address on each exact-input buy. No ETH vault or market buy.",
|
|
130
|
-
}),
|
|
131
|
-
]),
|
|
132
|
-
lp: Object.freeze([
|
|
133
|
-
Object.freeze({
|
|
134
|
-
key: "share",
|
|
135
|
-
label: "LP fee share",
|
|
136
|
-
min: 0.05,
|
|
137
|
-
max: 1,
|
|
138
|
-
step: 0.05,
|
|
139
|
-
def: 0.25,
|
|
140
|
-
unit: "%",
|
|
141
|
-
hint: "Slice of each buy donated to in-range LPs.",
|
|
142
|
-
}),
|
|
143
|
-
]),
|
|
144
|
-
pot: Object.freeze([
|
|
145
|
-
Object.freeze({
|
|
146
|
-
key: "cut",
|
|
147
|
-
label: "Pot share",
|
|
148
|
-
min: 0.1,
|
|
149
|
-
max: 2,
|
|
150
|
-
step: 0.1,
|
|
151
|
-
def: 0.5,
|
|
152
|
-
unit: "% SWAP",
|
|
153
|
-
hint: "Share of every exact-input buy added to the deterministic pot.",
|
|
154
|
-
}),
|
|
155
|
-
Object.freeze({
|
|
156
|
-
key: "every",
|
|
157
|
-
label: "Pays every N buys",
|
|
158
|
-
min: 100,
|
|
159
|
-
max: 5000,
|
|
160
|
-
step: 100,
|
|
161
|
-
def: 500,
|
|
162
|
-
unit: "buys",
|
|
163
|
-
hint: "The public counter advances at most once per pool per block. The Nth qualifying buy wins; this is not random.",
|
|
164
|
-
}),
|
|
165
|
-
Object.freeze({
|
|
166
|
-
key: "minbuy",
|
|
167
|
-
label: "Min qualifying buy",
|
|
168
|
-
min: 0.001,
|
|
169
|
-
max: 1,
|
|
170
|
-
step: 0.001,
|
|
171
|
-
def: 0.01,
|
|
172
|
-
unit: "ETH",
|
|
173
|
-
hint: "Buys below this cannot advance the public pot counter.",
|
|
174
|
-
}),
|
|
175
|
-
]),
|
|
176
|
-
});
|
|
177
|
-
/** `eth` -> wei at fixed 9-decimal precision, matching the app's `toWei` (avoids float drift). */
|
|
178
|
-
function toWei(eth) {
|
|
179
|
-
return BigInt(Math.round(eth * 1e9)) * 10n ** 9n;
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Compile a stack of public rule blocks into the exact rate fields the native block's `Config`
|
|
183
|
-
* carries, mirroring `compileStack` in the app's `src/lib/hooks-model.ts`.
|
|
184
|
-
*
|
|
185
|
-
* `baseFeePipsOverride` is the stack-level Base LP fee, chosen independently of whether a
|
|
186
|
-
* Surge Fees rule is present — it always wins over the Surge block's own "Base fee" slider,
|
|
187
|
-
* exactly like the app's builder. The block still supplies the surge ceiling and sensitivity.
|
|
188
|
-
*/
|
|
189
|
-
export function compileRuleBlocks(blocks, baseFeePipsOverride) {
|
|
190
|
-
const baseFeePips = Math.round(baseFeePipsOverride);
|
|
191
|
-
const out = {
|
|
192
|
-
guardBlocks: 0,
|
|
193
|
-
maxBuyBps: 0,
|
|
194
|
-
snipeTaxPips: 0,
|
|
195
|
-
baseFeePips,
|
|
196
|
-
maxFeePips: baseFeePips,
|
|
197
|
-
surgeSens: 0,
|
|
198
|
-
burnBps: 0,
|
|
199
|
-
lpBps: 0,
|
|
200
|
-
potBps: 0,
|
|
201
|
-
potEveryNBuys: 0,
|
|
202
|
-
potMinBuyWei: 0n,
|
|
203
|
-
};
|
|
204
|
-
for (const block of blocks) {
|
|
205
|
-
const p = block.params;
|
|
206
|
-
if (block.type === "snipe") {
|
|
207
|
-
out.guardBlocks = Math.round(p.guard);
|
|
208
|
-
out.maxBuyBps = Math.round(p.maxbuy * 100);
|
|
209
|
-
out.snipeTaxPips = Math.round(p.tax * 10_000);
|
|
210
|
-
}
|
|
211
|
-
if (block.type === "fee") {
|
|
212
|
-
out.maxFeePips = Math.round(p.max * 10_000);
|
|
213
|
-
out.surgeSens = Math.round(p.sens);
|
|
214
|
-
}
|
|
215
|
-
if (block.type === "burn") {
|
|
216
|
-
out.burnBps = Math.round(p.cut * 100);
|
|
217
|
-
}
|
|
218
|
-
if (block.type === "lp") {
|
|
219
|
-
out.lpBps = Math.round(p.share * 100);
|
|
220
|
-
}
|
|
221
|
-
if (block.type === "pot") {
|
|
222
|
-
out.potBps = Math.round(p.cut * 100);
|
|
223
|
-
out.potEveryNBuys = Math.round(p.every);
|
|
224
|
-
out.potMinBuyWei = toWei(p.minbuy);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
if (out.maxFeePips < out.baseFeePips)
|
|
228
|
-
out.maxFeePips = out.baseFeePips;
|
|
229
|
-
return Object.freeze(out);
|
|
230
|
-
}
|
|
231
|
-
/** The default single block for one rule: every param at its `def`. */
|
|
232
|
-
export function defaultBlock(key) {
|
|
233
|
-
const params = {};
|
|
234
|
-
for (const spec of PARAMS[key])
|
|
235
|
-
params[spec.key] = spec.def;
|
|
236
|
-
return Object.freeze({ type: key, params: Object.freeze(params) });
|
|
237
|
-
}
|
|
238
|
-
/** The starting stack a new configuration opens with: no rules, base fee only. */
|
|
239
|
-
export function defaultStack() {
|
|
240
|
-
return Object.freeze([]);
|
|
241
|
-
}
|
|
242
|
-
export const MAX_STACK_RULES = 5;
|
|
243
|
-
/** Whether `value` sits on `spec`'s step grid, within floating-point rounding. */
|
|
244
|
-
function onStep(value, spec) {
|
|
245
|
-
const steps = (value - spec.min) / spec.step;
|
|
246
|
-
return Math.abs(steps - Math.round(steps)) < 1e-9;
|
|
247
|
-
}
|
|
248
|
-
/**
|
|
249
|
-
* Validate a stack of rule blocks: unknown rule keys, duplicate rules, more than
|
|
250
|
-
* `MAX_STACK_RULES` rules, an unknown parameter, or a parameter outside its bounds or off its
|
|
251
|
-
* step grid. Every problem is reported, not just the first.
|
|
252
|
-
*/
|
|
253
|
-
export function validateStack(blocks) {
|
|
254
|
-
const errors = [];
|
|
255
|
-
if (blocks.length > MAX_STACK_RULES) {
|
|
256
|
-
errors.push(`A stack may carry at most ${MAX_STACK_RULES} rules; this one carries ${blocks.length}.`);
|
|
257
|
-
}
|
|
258
|
-
const seen = new Set();
|
|
259
|
-
for (const block of blocks) {
|
|
260
|
-
if (seen.has(block.type)) {
|
|
261
|
-
errors.push(`Rule "${block.type}" appears more than once in the stack.`);
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
seen.add(block.type);
|
|
265
|
-
const specs = PARAMS[block.type];
|
|
266
|
-
if (!specs) {
|
|
267
|
-
errors.push(`Unknown rule "${block.type}".`);
|
|
268
|
-
continue;
|
|
269
|
-
}
|
|
270
|
-
const knownKeys = new Set(specs.map((spec) => spec.key));
|
|
271
|
-
for (const paramKey of Object.keys(block.params)) {
|
|
272
|
-
if (!knownKeys.has(paramKey)) {
|
|
273
|
-
errors.push(`Rule "${block.type}" has no parameter "${paramKey}".`);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
for (const spec of specs) {
|
|
277
|
-
const value = block.params[spec.key];
|
|
278
|
-
if (value === undefined) {
|
|
279
|
-
errors.push(`Rule "${block.type}" is missing its "${spec.key}" parameter.`);
|
|
280
|
-
continue;
|
|
281
|
-
}
|
|
282
|
-
if (!Number.isFinite(value)) {
|
|
283
|
-
errors.push(`Rule "${block.type}"'s "${spec.key}" must be a finite number.`);
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
|
-
if (value < spec.min || value > spec.max) {
|
|
287
|
-
errors.push(`Rule "${block.type}"'s "${spec.key}" (${value}) must be between ${spec.min} and ${spec.max}.`);
|
|
288
|
-
continue;
|
|
289
|
-
}
|
|
290
|
-
if (!onStep(value, spec)) {
|
|
291
|
-
errors.push(`Rule "${block.type}"'s "${spec.key}" (${value}) must be a multiple of ${spec.step} from ${spec.min}.`);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
return Object.freeze({ ok: errors.length === 0, errors: Object.freeze(errors) });
|
|
296
|
-
}
|
package/dist/swap.d.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Quote and swap through Hookr's kernel router and quoter (chain 4663).
|
|
3
|
-
*
|
|
4
|
-
* Copied from the app's `src/lib/v2-swap.ts` (`v2ExactInputCall`, `v2ExactOutputCall`,
|
|
5
|
-
* `v2QuoteCall`): empty module data, the full-fill price limit in both directions, and native
|
|
6
|
-
* ETH sent as `value` exactly when the input currency is the zero address. A pool that carries
|
|
7
|
-
* any input cut (surge, guard, burn, LP reward or pot) rejects any other limit outright — see
|
|
8
|
-
* `market.ts`'s module doc for the fee model these cuts come from.
|
|
9
|
-
*/
|
|
10
|
-
import type { Address, ContractFunctionArgs, Hex, PublicClient } from "viem";
|
|
11
|
-
import { hookrKernelRouterV3Abi } from "./abi.js";
|
|
12
|
-
import type { PoolKey } from "./market.js";
|
|
13
|
-
/**
|
|
14
|
-
* The gas limit a swap on a correcting root must carry (the app's `CORRECTION_SWAP_GAS_FLOOR` in
|
|
15
|
-
* `src/lib/gas-headroom.ts`). The recapture root runs its correction in both swap phases, once in
|
|
16
|
-
* `beforeSwap` and again in `afterSwap` (`HookrSwapKernelV5Wth.sol`, `_tryCorrection` at lines 214
|
|
17
|
-
* and 250), each inside a bounded call that fails open: a wallet's gas estimate covers the swap
|
|
18
|
-
* alone, so an estimated transaction succeeds with the correction skipped and nothing recaptured.
|
|
19
|
-
* The swap builders below put this floor on the call whenever `key.hooks` is the current recapture
|
|
20
|
-
* root, or whenever the caller passes `correcting: true`; pass it through to `writeContract` (viem
|
|
21
|
-
* sends `gas` as the limit) instead of estimating.
|
|
22
|
-
*/
|
|
23
|
-
export declare const CORRECTION_SWAP_GAS_FLOOR = 1100000n;
|
|
24
|
-
/**
|
|
25
|
-
* True when `hooks` is the current recapture root, which corrects in both swap phases. This is the
|
|
26
|
-
* root's identity, not the pool's: a pool opened on a superseded recapture root keeps the executor
|
|
27
|
-
* frozen into its rules and keeps correcting, and this returns false for it. Read that from the
|
|
28
|
-
* pool itself with `poolCorrects(await readPoolRules(client, poolId))` and pass the answer as
|
|
29
|
-
* `correcting` to the swap builders.
|
|
30
|
-
*/
|
|
31
|
-
export declare function isCorrectingRoot(hooks: Address): boolean;
|
|
32
|
-
/** The gas limit to send with a swap on `key`: the floor when the pool corrects (`correcting`,
|
|
33
|
-
* defaulting to `isCorrectingRoot(key.hooks)`), else `undefined` (let the wallet estimate). */
|
|
34
|
-
export declare function swapGasLimit(key: PoolKey, correcting?: boolean): bigint | undefined;
|
|
35
|
-
/** Router / block `MIN_SQRT_PRICE_LIMIT`: the full-fill limit for a `zeroForOne` swap. */
|
|
36
|
-
export declare const MIN_SQRT_PRICE_LIMIT = 4295128740n;
|
|
37
|
-
/** Router / block `MAX_SQRT_PRICE_LIMIT`: the full-fill limit for a `oneForZero` swap. */
|
|
38
|
-
export declare const MAX_SQRT_PRICE_LIMIT = 1461446703485210103287273052203988822378723970341n;
|
|
39
|
-
/** `type(int128).max`: the router's and the quoter's ceiling on every amount and bound. */
|
|
40
|
-
export declare const INT128_MAX: bigint;
|
|
41
|
-
/** The bound an exact-input quote carries: the smallest value the quoter admits. */
|
|
42
|
-
export declare const QUOTE_MIN_OUT_BOUND = 1n;
|
|
43
|
-
/** The router's `moduleData` for a plain swap: the native block reads none. */
|
|
44
|
-
export declare const EMPTY_MODULE_DATA: Hex;
|
|
45
|
-
/** The full-fill `sqrtPriceLimitX96`: `MIN` when selling currency0, `MAX` otherwise. Any pool
|
|
46
|
-
* with an input cut rejects every other limit on an exact-input buy. */
|
|
47
|
-
export declare function fullFillLimit(zeroForOne: boolean): bigint;
|
|
48
|
-
/** `zeroForOne = currencyIn == key.currency0`. Throws when `currencyIn` is not in the pool. */
|
|
49
|
-
export declare function swapDirection(key: PoolKey, currencyIn: Address): boolean;
|
|
50
|
-
export type RouterCall<F extends "exactInput" | "exactOutput"> = Readonly<{
|
|
51
|
-
address: Address;
|
|
52
|
-
abi: typeof hookrKernelRouterV3Abi;
|
|
53
|
-
functionName: F;
|
|
54
|
-
args: ContractFunctionArgs<typeof hookrKernelRouterV3Abi, "payable", F>;
|
|
55
|
-
value: bigint;
|
|
56
|
-
/** Set to `CORRECTION_SWAP_GAS_FLOOR` when the pool corrects; absent otherwise. */
|
|
57
|
-
gas?: bigint;
|
|
58
|
-
}>;
|
|
59
|
-
/**
|
|
60
|
-
* `exactInput` through the Hookr router. `value` is `amountIn` when `currencyIn` is native ETH,
|
|
61
|
-
* else 0 (the router pulls the ERC-20 by `transferFrom`; approve it first). `gas` carries the
|
|
62
|
-
* correction floor when the pool corrects; send it as the gas limit. `correcting` defaults to
|
|
63
|
-
* `isCorrectingRoot(key.hooks)`; pass `poolCorrects(rules)` for a pool on a superseded root.
|
|
64
|
-
*/
|
|
65
|
-
export declare function buildExactInputSwapCall(input: {
|
|
66
|
-
key: PoolKey;
|
|
67
|
-
currencyIn: Address;
|
|
68
|
-
amountIn: bigint;
|
|
69
|
-
amountOutMinimum: bigint;
|
|
70
|
-
recipient: Address;
|
|
71
|
-
deadline: bigint;
|
|
72
|
-
correcting?: boolean;
|
|
73
|
-
}): RouterCall<"exactInput">;
|
|
74
|
-
/**
|
|
75
|
-
* `exactOutput` through the Hookr router. `value` is `amountInMaximum` when `currencyIn` is
|
|
76
|
-
* native ETH — the router refunds what the swap does not use. `correcting` works as on
|
|
77
|
-
* `buildExactInputSwapCall`.
|
|
78
|
-
*/
|
|
79
|
-
export declare function buildExactOutputSwapCall(input: {
|
|
80
|
-
key: PoolKey;
|
|
81
|
-
currencyIn: Address;
|
|
82
|
-
amountOut: bigint;
|
|
83
|
-
amountInMaximum: bigint;
|
|
84
|
-
recipient: Address;
|
|
85
|
-
deadline: bigint;
|
|
86
|
-
correcting?: boolean;
|
|
87
|
-
}): RouterCall<"exactOutput">;
|
|
88
|
-
export type Quote = Readonly<{
|
|
89
|
-
amountIn: bigint;
|
|
90
|
-
amountOut: bigint;
|
|
91
|
-
}>;
|
|
92
|
-
/**
|
|
93
|
-
* Quote through `kernelQuoter.quote`. Run as a simulated call from `account` rather than an
|
|
94
|
-
* ordinary read: the function is declared `nonpayable` (it runs the full module loop, including
|
|
95
|
-
* the pot leg, which is recipient-specific), which is also why the app's own equivalent
|
|
96
|
-
* (`quoteV2` in `src/lib/v2-swap.ts`) calls `simulateContract` rather than `readContract` — the
|
|
97
|
-
* same `eth_call` either way, just the viem entry point whose types match a nonpayable function.
|
|
98
|
-
* `amountSpecified` is negative for an exact-input quote, bound at 1 wei/unit — the least the
|
|
99
|
-
* quoter admits; pass `amountBound` to override it (an exact-output quote wants `INT128_MAX` or
|
|
100
|
-
* your own maximum).
|
|
101
|
-
*/
|
|
102
|
-
export declare function quoteExactInput(client: PublicClient, input: {
|
|
103
|
-
key: PoolKey;
|
|
104
|
-
user: Address;
|
|
105
|
-
currencyIn: Address;
|
|
106
|
-
amountIn: bigint;
|
|
107
|
-
amountBound?: bigint;
|
|
108
|
-
}): Promise<Quote>;
|
package/dist/swap.js
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { hookrKernelQuoterV1Abi, hookrKernelRouterV3Abi } from "./abi.js";
|
|
2
|
-
import { ADDRESSES, NATIVE_ADDRESS } from "./chain.js";
|
|
3
|
-
/**
|
|
4
|
-
* The gas limit a swap on a correcting root must carry (the app's `CORRECTION_SWAP_GAS_FLOOR` in
|
|
5
|
-
* `src/lib/gas-headroom.ts`). The recapture root runs its correction in both swap phases, once in
|
|
6
|
-
* `beforeSwap` and again in `afterSwap` (`HookrSwapKernelV5Wth.sol`, `_tryCorrection` at lines 214
|
|
7
|
-
* and 250), each inside a bounded call that fails open: a wallet's gas estimate covers the swap
|
|
8
|
-
* alone, so an estimated transaction succeeds with the correction skipped and nothing recaptured.
|
|
9
|
-
* The swap builders below put this floor on the call whenever `key.hooks` is the current recapture
|
|
10
|
-
* root, or whenever the caller passes `correcting: true`; pass it through to `writeContract` (viem
|
|
11
|
-
* sends `gas` as the limit) instead of estimating.
|
|
12
|
-
*/
|
|
13
|
-
export const CORRECTION_SWAP_GAS_FLOOR = 1100000n;
|
|
14
|
-
/**
|
|
15
|
-
* True when `hooks` is the current recapture root, which corrects in both swap phases. This is the
|
|
16
|
-
* root's identity, not the pool's: a pool opened on a superseded recapture root keeps the executor
|
|
17
|
-
* frozen into its rules and keeps correcting, and this returns false for it. Read that from the
|
|
18
|
-
* pool itself with `poolCorrects(await readPoolRules(client, poolId))` and pass the answer as
|
|
19
|
-
* `correcting` to the swap builders.
|
|
20
|
-
*/
|
|
21
|
-
export function isCorrectingRoot(hooks) {
|
|
22
|
-
return hooks.toLowerCase() === ADDRESSES.recaptureRoot.toLowerCase();
|
|
23
|
-
}
|
|
24
|
-
/** The gas limit to send with a swap on `key`: the floor when the pool corrects (`correcting`,
|
|
25
|
-
* defaulting to `isCorrectingRoot(key.hooks)`), else `undefined` (let the wallet estimate). */
|
|
26
|
-
export function swapGasLimit(key, correcting) {
|
|
27
|
-
return (correcting ?? isCorrectingRoot(key.hooks)) ? CORRECTION_SWAP_GAS_FLOOR : undefined;
|
|
28
|
-
}
|
|
29
|
-
/** Router / block `MIN_SQRT_PRICE_LIMIT`: the full-fill limit for a `zeroForOne` swap. */
|
|
30
|
-
export const MIN_SQRT_PRICE_LIMIT = 4295128740n;
|
|
31
|
-
/** Router / block `MAX_SQRT_PRICE_LIMIT`: the full-fill limit for a `oneForZero` swap. */
|
|
32
|
-
export const MAX_SQRT_PRICE_LIMIT = 1461446703485210103287273052203988822378723970341n;
|
|
33
|
-
/** `type(int128).max`: the router's and the quoter's ceiling on every amount and bound. */
|
|
34
|
-
export const INT128_MAX = (1n << 127n) - 1n;
|
|
35
|
-
/** The bound an exact-input quote carries: the smallest value the quoter admits. */
|
|
36
|
-
export const QUOTE_MIN_OUT_BOUND = 1n;
|
|
37
|
-
/** The router's `moduleData` for a plain swap: the native block reads none. */
|
|
38
|
-
export const EMPTY_MODULE_DATA = "0x";
|
|
39
|
-
/** The full-fill `sqrtPriceLimitX96`: `MIN` when selling currency0, `MAX` otherwise. Any pool
|
|
40
|
-
* with an input cut rejects every other limit on an exact-input buy. */
|
|
41
|
-
export function fullFillLimit(zeroForOne) {
|
|
42
|
-
return zeroForOne ? MIN_SQRT_PRICE_LIMIT : MAX_SQRT_PRICE_LIMIT;
|
|
43
|
-
}
|
|
44
|
-
/** `zeroForOne = currencyIn == key.currency0`. Throws when `currencyIn` is not in the pool. */
|
|
45
|
-
export function swapDirection(key, currencyIn) {
|
|
46
|
-
const same = (a, b) => a.toLowerCase() === b.toLowerCase();
|
|
47
|
-
if (same(currencyIn, key.currency0))
|
|
48
|
-
return true;
|
|
49
|
-
if (same(currencyIn, key.currency1))
|
|
50
|
-
return false;
|
|
51
|
-
throw new Error("That currency is not in this pool.");
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* `exactInput` through the Hookr router. `value` is `amountIn` when `currencyIn` is native ETH,
|
|
55
|
-
* else 0 (the router pulls the ERC-20 by `transferFrom`; approve it first). `gas` carries the
|
|
56
|
-
* correction floor when the pool corrects; send it as the gas limit. `correcting` defaults to
|
|
57
|
-
* `isCorrectingRoot(key.hooks)`; pass `poolCorrects(rules)` for a pool on a superseded root.
|
|
58
|
-
*/
|
|
59
|
-
export function buildExactInputSwapCall(input) {
|
|
60
|
-
const zeroForOne = swapDirection(input.key, input.currencyIn);
|
|
61
|
-
const native = input.currencyIn.toLowerCase() === NATIVE_ADDRESS.toLowerCase();
|
|
62
|
-
const gas = swapGasLimit(input.key, input.correcting);
|
|
63
|
-
return Object.freeze({
|
|
64
|
-
address: ADDRESSES.router,
|
|
65
|
-
abi: hookrKernelRouterV3Abi,
|
|
66
|
-
functionName: "exactInput",
|
|
67
|
-
args: [
|
|
68
|
-
{
|
|
69
|
-
key: input.key,
|
|
70
|
-
zeroForOne,
|
|
71
|
-
amountIn: input.amountIn,
|
|
72
|
-
amountOutMinimum: input.amountOutMinimum,
|
|
73
|
-
sqrtPriceLimitX96: fullFillLimit(zeroForOne),
|
|
74
|
-
recipient: input.recipient,
|
|
75
|
-
deadline: input.deadline,
|
|
76
|
-
},
|
|
77
|
-
EMPTY_MODULE_DATA,
|
|
78
|
-
],
|
|
79
|
-
value: native ? input.amountIn : 0n,
|
|
80
|
-
...(gas === undefined ? {} : { gas }),
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* `exactOutput` through the Hookr router. `value` is `amountInMaximum` when `currencyIn` is
|
|
85
|
-
* native ETH — the router refunds what the swap does not use. `correcting` works as on
|
|
86
|
-
* `buildExactInputSwapCall`.
|
|
87
|
-
*/
|
|
88
|
-
export function buildExactOutputSwapCall(input) {
|
|
89
|
-
const zeroForOne = swapDirection(input.key, input.currencyIn);
|
|
90
|
-
const native = input.currencyIn.toLowerCase() === NATIVE_ADDRESS.toLowerCase();
|
|
91
|
-
const gas = swapGasLimit(input.key, input.correcting);
|
|
92
|
-
return Object.freeze({
|
|
93
|
-
address: ADDRESSES.router,
|
|
94
|
-
abi: hookrKernelRouterV3Abi,
|
|
95
|
-
functionName: "exactOutput",
|
|
96
|
-
args: [
|
|
97
|
-
{
|
|
98
|
-
key: input.key,
|
|
99
|
-
zeroForOne,
|
|
100
|
-
amountOut: input.amountOut,
|
|
101
|
-
amountInMaximum: input.amountInMaximum,
|
|
102
|
-
sqrtPriceLimitX96: fullFillLimit(zeroForOne),
|
|
103
|
-
recipient: input.recipient,
|
|
104
|
-
deadline: input.deadline,
|
|
105
|
-
},
|
|
106
|
-
EMPTY_MODULE_DATA,
|
|
107
|
-
],
|
|
108
|
-
value: native ? input.amountInMaximum : 0n,
|
|
109
|
-
...(gas === undefined ? {} : { gas }),
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Quote through `kernelQuoter.quote`. Run as a simulated call from `account` rather than an
|
|
114
|
-
* ordinary read: the function is declared `nonpayable` (it runs the full module loop, including
|
|
115
|
-
* the pot leg, which is recipient-specific), which is also why the app's own equivalent
|
|
116
|
-
* (`quoteV2` in `src/lib/v2-swap.ts`) calls `simulateContract` rather than `readContract` — the
|
|
117
|
-
* same `eth_call` either way, just the viem entry point whose types match a nonpayable function.
|
|
118
|
-
* `amountSpecified` is negative for an exact-input quote, bound at 1 wei/unit — the least the
|
|
119
|
-
* quoter admits; pass `amountBound` to override it (an exact-output quote wants `INT128_MAX` or
|
|
120
|
-
* your own maximum).
|
|
121
|
-
*/
|
|
122
|
-
export async function quoteExactInput(client, input) {
|
|
123
|
-
const zeroForOne = swapDirection(input.key, input.currencyIn);
|
|
124
|
-
const { result } = await client.simulateContract({
|
|
125
|
-
address: ADDRESSES.quoter,
|
|
126
|
-
abi: hookrKernelQuoterV1Abi,
|
|
127
|
-
functionName: "quote",
|
|
128
|
-
account: input.user,
|
|
129
|
-
args: [
|
|
130
|
-
{
|
|
131
|
-
key: input.key,
|
|
132
|
-
payer: input.user,
|
|
133
|
-
recipient: input.user,
|
|
134
|
-
zeroForOne,
|
|
135
|
-
amountSpecified: -input.amountIn,
|
|
136
|
-
amountBound: input.amountBound ?? QUOTE_MIN_OUT_BOUND,
|
|
137
|
-
sqrtPriceLimitX96: fullFillLimit(zeroForOne),
|
|
138
|
-
},
|
|
139
|
-
EMPTY_MODULE_DATA,
|
|
140
|
-
],
|
|
141
|
-
});
|
|
142
|
-
const [amountIn, amountOut] = result;
|
|
143
|
-
return Object.freeze({ amountIn, amountOut });
|
|
144
|
-
}
|