hookr-sdk 0.2.0 → 0.2.1

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/README.md CHANGED
@@ -99,8 +99,11 @@ const swapCall = buildExactInputSwapCall({ key, currencyIn: market.quote, amount
99
99
  A swap on a recapture pool needs more gas than an estimate reports, because the correction is
100
100
  fail-open: an estimate converges on the cheapest swap that succeeds, which is the one that skipped
101
101
  the correction. The swap builders put `gas: CORRECTION_SWAP_GAS_FLOOR` (1,100,000, the app's
102
- floor) on the call whenever the pool's root corrects, so pass the call to `writeContract` as it
103
- is; on the default root the call carries no `gas` and the wallet estimates as usual.
102
+ floor) on the call whenever the pool's root is the current recapture root, so pass the call to
103
+ `writeContract` as it is; on the default root the call carries no `gas` and the wallet estimates
104
+ as usual. A pool opened on a superseded recapture root keeps its executor and keeps correcting;
105
+ read `poolCorrects(await readPoolRules(client, poolId))` and pass it as `correcting` to the swap
106
+ builders to put the same floor on that call (since 0.2.1).
104
107
 
105
108
  ## Roots
106
109
 
@@ -138,6 +141,9 @@ parity test in that repository keeps the package and the app in step.
138
141
 
139
142
  ## Changes
140
143
 
144
+ - 0.2.1: the swap builders take `correcting` (default `isCorrectingRoot(key.hooks)`, the current
145
+ recapture root), and `poolCorrects(rules)` reads from a pool's frozen rules whether it names a
146
+ correction executor, so a pool on a superseded recapture root can carry the gas floor too.
141
147
  - 0.2.0: names both live roots (`ADDRESSES.recaptureRoot`, `RECAPTURE_KERNEL_ID`, `ROOTS`); the
142
148
  market builders take `root` and freeze the recapture correction fields (`RECAPTURE_CORRECTION`);
143
149
  swap calls carry `gas: CORRECTION_SWAP_GAS_FLOOR` on a correcting root; `listMarkets` scans in
package/dist/reads.d.ts CHANGED
@@ -98,6 +98,15 @@ export type PoolRules = Readonly<{
98
98
  * by this package.
99
99
  */
100
100
  export declare function readPoolRules(client: PublicClient, poolId: Hex): Promise<PoolRules>;
101
+ /**
102
+ * True when the pool's frozen rules name a correction executor, so the root's kernel dispatches a
103
+ * correction around every swap and the swap needs `CORRECTION_SWAP_GAS_FLOOR`. This is the pool's
104
+ * own record rather than the root's identity: a pool on a superseded recapture root keeps its
105
+ * executor and keeps correcting, which `isCorrectingRoot` (current root only) does not see. Pass
106
+ * the result as `correcting` to the swap builders. It is also true for a pool whose lane cannot
107
+ * run on ordinary gas (the first recapture root); the floor is then unused headroom, not a loss.
108
+ */
109
+ export declare function poolCorrects(rules: PoolRules): boolean;
101
110
  /** `HookrStackRegistryV1.KernelStatus`. */
102
111
  export type RootStatus = "unset" | "active" | "retired";
103
112
  /** One registered root (kernel) as the stack registry records it. */
package/dist/reads.js CHANGED
@@ -11,7 +11,7 @@
11
11
  */
12
12
  import { decodeAbiParameters, getAbiItem, toEventSelector } from "viem";
13
13
  import { hookrMarketCoordinatorV5Abi, hookrStackRegistryV2Abi } from "./abi.js";
14
- import { ADDRESSES, MODULE_ID } from "./chain.js";
14
+ import { ADDRESSES, MODULE_ID, NATIVE_ADDRESS } from "./chain.js";
15
15
  function marketOrigin(value) {
16
16
  if (value === 1)
17
17
  return "new-token";
@@ -153,6 +153,18 @@ export async function readPoolRules(client, poolId) {
153
153
  }
154
154
  return Object.freeze({ configured: true, limits: core.limits, nativeConfig });
155
155
  }
156
+ /**
157
+ * True when the pool's frozen rules name a correction executor, so the root's kernel dispatches a
158
+ * correction around every swap and the swap needs `CORRECTION_SWAP_GAS_FLOOR`. This is the pool's
159
+ * own record rather than the root's identity: a pool on a superseded recapture root keeps its
160
+ * executor and keeps correcting, which `isCorrectingRoot` (current root only) does not see. Pass
161
+ * the result as `correcting` to the swap builders. It is also true for a pool whose lane cannot
162
+ * run on ordinary gas (the first recapture root); the floor is then unused headroom, not a loss.
163
+ */
164
+ export function poolCorrects(rules) {
165
+ const executor = rules.limits?.correctionExecutor;
166
+ return executor !== undefined && executor.toLowerCase() !== NATIVE_ADDRESS.toLowerCase();
167
+ }
156
168
  function rootStatus(value) {
157
169
  if (value === 0)
158
170
  return "unset";
package/dist/swap.d.ts CHANGED
@@ -12,18 +12,26 @@ import { hookrKernelRouterV3Abi } from "./abi.js";
12
12
  import type { PoolKey } from "./market.js";
13
13
  /**
14
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 after the swap inside a bounded
16
- * call that fails open: a wallet's gas estimate covers the swap alone, so an estimated transaction
17
- * succeeds with the correction skipped and nothing recaptured. The swap builders below put this
18
- * floor on the call whenever `key.hooks` is a correcting root; pass it through to `writeContract`
19
- * (viem sends `gas` as the limit) instead of estimating.
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.
20
22
  */
21
23
  export declare const CORRECTION_SWAP_GAS_FLOOR = 1100000n;
22
- /** True when `hooks` is a root that corrects after the swap: today the recapture root. */
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
+ */
23
31
  export declare function isCorrectingRoot(hooks: Address): boolean;
24
- /** The gas limit to send with a swap on `key`: the floor on a correcting root, else `undefined`
25
- * (let the wallet estimate). */
26
- export declare function swapGasLimit(key: PoolKey): bigint | undefined;
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;
27
35
  /** Router / block `MIN_SQRT_PRICE_LIMIT`: the full-fill limit for a `zeroForOne` swap. */
28
36
  export declare const MIN_SQRT_PRICE_LIMIT = 4295128740n;
29
37
  /** Router / block `MAX_SQRT_PRICE_LIMIT`: the full-fill limit for a `oneForZero` swap. */
@@ -45,13 +53,14 @@ export type RouterCall<F extends "exactInput" | "exactOutput"> = Readonly<{
45
53
  functionName: F;
46
54
  args: ContractFunctionArgs<typeof hookrKernelRouterV3Abi, "payable", F>;
47
55
  value: bigint;
48
- /** Set to `CORRECTION_SWAP_GAS_FLOOR` when the pool's root corrects after the swap; absent otherwise. */
56
+ /** Set to `CORRECTION_SWAP_GAS_FLOOR` when the pool corrects; absent otherwise. */
49
57
  gas?: bigint;
50
58
  }>;
51
59
  /**
52
60
  * `exactInput` through the Hookr router. `value` is `amountIn` when `currencyIn` is native ETH,
53
61
  * else 0 (the router pulls the ERC-20 by `transferFrom`; approve it first). `gas` carries the
54
- * correction floor when the pool sits on a correcting root; send it as the gas limit.
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.
55
64
  */
56
65
  export declare function buildExactInputSwapCall(input: {
57
66
  key: PoolKey;
@@ -60,10 +69,12 @@ export declare function buildExactInputSwapCall(input: {
60
69
  amountOutMinimum: bigint;
61
70
  recipient: Address;
62
71
  deadline: bigint;
72
+ correcting?: boolean;
63
73
  }): RouterCall<"exactInput">;
64
74
  /**
65
75
  * `exactOutput` through the Hookr router. `value` is `amountInMaximum` when `currencyIn` is
66
- * native ETH — the router refunds what the swap does not use.
76
+ * native ETH — the router refunds what the swap does not use. `correcting` works as on
77
+ * `buildExactInputSwapCall`.
67
78
  */
68
79
  export declare function buildExactOutputSwapCall(input: {
69
80
  key: PoolKey;
@@ -72,6 +83,7 @@ export declare function buildExactOutputSwapCall(input: {
72
83
  amountInMaximum: bigint;
73
84
  recipient: Address;
74
85
  deadline: bigint;
86
+ correcting?: boolean;
75
87
  }): RouterCall<"exactOutput">;
76
88
  export type Quote = Readonly<{
77
89
  amountIn: bigint;
package/dist/swap.js CHANGED
@@ -2,21 +2,29 @@ import { hookrKernelQuoterV1Abi, hookrKernelRouterV3Abi } from "./abi.js";
2
2
  import { ADDRESSES, NATIVE_ADDRESS } from "./chain.js";
3
3
  /**
4
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 after the swap inside a bounded
6
- * call that fails open: a wallet's gas estimate covers the swap alone, so an estimated transaction
7
- * succeeds with the correction skipped and nothing recaptured. The swap builders below put this
8
- * floor on the call whenever `key.hooks` is a correcting root; pass it through to `writeContract`
9
- * (viem sends `gas` as the limit) instead of estimating.
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.
10
12
  */
11
13
  export const CORRECTION_SWAP_GAS_FLOOR = 1100000n;
12
- /** True when `hooks` is a root that corrects after the swap: today the recapture root. */
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
+ */
13
21
  export function isCorrectingRoot(hooks) {
14
22
  return hooks.toLowerCase() === ADDRESSES.recaptureRoot.toLowerCase();
15
23
  }
16
- /** The gas limit to send with a swap on `key`: the floor on a correcting root, else `undefined`
17
- * (let the wallet estimate). */
18
- export function swapGasLimit(key) {
19
- return isCorrectingRoot(key.hooks) ? CORRECTION_SWAP_GAS_FLOOR : undefined;
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;
20
28
  }
21
29
  /** Router / block `MIN_SQRT_PRICE_LIMIT`: the full-fill limit for a `zeroForOne` swap. */
22
30
  export const MIN_SQRT_PRICE_LIMIT = 4295128740n;
@@ -45,12 +53,13 @@ export function swapDirection(key, currencyIn) {
45
53
  /**
46
54
  * `exactInput` through the Hookr router. `value` is `amountIn` when `currencyIn` is native ETH,
47
55
  * else 0 (the router pulls the ERC-20 by `transferFrom`; approve it first). `gas` carries the
48
- * correction floor when the pool sits on a correcting root; send it as the gas limit.
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.
49
58
  */
50
59
  export function buildExactInputSwapCall(input) {
51
60
  const zeroForOne = swapDirection(input.key, input.currencyIn);
52
61
  const native = input.currencyIn.toLowerCase() === NATIVE_ADDRESS.toLowerCase();
53
- const gas = swapGasLimit(input.key);
62
+ const gas = swapGasLimit(input.key, input.correcting);
54
63
  return Object.freeze({
55
64
  address: ADDRESSES.router,
56
65
  abi: hookrKernelRouterV3Abi,
@@ -73,12 +82,13 @@ export function buildExactInputSwapCall(input) {
73
82
  }
74
83
  /**
75
84
  * `exactOutput` through the Hookr router. `value` is `amountInMaximum` when `currencyIn` is
76
- * native ETH — the router refunds what the swap does not use.
85
+ * native ETH — the router refunds what the swap does not use. `correcting` works as on
86
+ * `buildExactInputSwapCall`.
77
87
  */
78
88
  export function buildExactOutputSwapCall(input) {
79
89
  const zeroForOne = swapDirection(input.key, input.currencyIn);
80
90
  const native = input.currencyIn.toLowerCase() === NATIVE_ADDRESS.toLowerCase();
81
- const gas = swapGasLimit(input.key);
91
+ const gas = swapGasLimit(input.key, input.correcting);
82
92
  return Object.freeze({
83
93
  address: ADDRESSES.router,
84
94
  abi: hookrKernelRouterV3Abi,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hookr-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Build a market on Hookr's live root hooks, quote and swap through its router, read markets, and claim payouts.",
5
5
  "type": "module",
6
6
  "license": "MIT",