@logswap/sdk 0.5.66 → 0.5.67

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/dist/pools.d.ts CHANGED
@@ -53,6 +53,32 @@ export declare function priceOf(state: Pick<PoolState, "x">, scale?: number): nu
53
53
  * it is 1 and nothing changes.
54
54
  */
55
55
  export declare function priceScale(baseDecimals: number, quoteDecimals: number): number;
56
+ /** The C manager's log-price wall: |x| ≤ 46 on the WEI ratio (`MAX_ABS_FLOOR`). */
57
+ export declare const C_MAX_ABS_X = 46;
58
+ /** The least derived base reserve a C book keeps, in base wei (`MIN_RESERVE`, decisions 023). */
59
+ export declare const C_MIN_RESERVE: bigint;
60
+ /**
61
+ * The prices a C market can hold, in human units — quote per whole base token (decisions 054).
62
+ *
63
+ * - `listMin`, `listMax`: the wall, `10^(base − quote) · e^{∓46}`. A market cannot be initialized,
64
+ * and no floor or cap placed, outside it. An 18-dec token against 6-dec USDC cannot list under
65
+ * 1.05e-8; against an 18-dec quote the same token lists down to 1.05e-20.
66
+ * - `ceiling`: the highest price the book can trade to with `lActive` of active exposure (quote
67
+ * wei): the derived reserve `lActive / p` must stay at or above `C_MIN_RESERVE` base wei, so
68
+ * `ceiling = lActive · 10^(base − quote) / 1e6`, capped by `listMax`. In whole units that is
69
+ * `L · 10^(base − 6)`: the quote's decimals cancel and the base's set it — harmless on an
70
+ * 18-dec base, but a WBTC book of 1,000 USDC of depth stops at 100,000. Omit `lActive` for the
71
+ * wall alone.
72
+ *
73
+ * Floats, for display and warnings; the chain is the authority.
74
+ */
75
+ export declare function cPriceRange(baseDecimals: number, quoteDecimals: number, lActive?: bigint): {
76
+ listMin: number;
77
+ listMax: number;
78
+ ceiling: number;
79
+ };
80
+ /** Whether a C market can be initialized at `price` (human units) for this pair's decimals. */
81
+ export declare function cListable(price: number, baseDecimals: number, quoteDecimals: number): boolean;
56
82
  /**
57
83
  * The model-free LP edge, $F - \tfrac12\Sigma$ — the protocol's headline metric, in quote per unit
58
84
  * of exposure.
package/dist/pools.js CHANGED
@@ -55,6 +55,37 @@ export function priceOf(state, scale = 1) {
55
55
  export function priceScale(baseDecimals, quoteDecimals) {
56
56
  return 10 ** (baseDecimals - quoteDecimals);
57
57
  }
58
+ /** The C manager's log-price wall: |x| ≤ 46 on the WEI ratio (`MAX_ABS_FLOOR`). */
59
+ export const C_MAX_ABS_X = 46;
60
+ /** The least derived base reserve a C book keeps, in base wei (`MIN_RESERVE`, decisions 023). */
61
+ export const C_MIN_RESERVE = 10n ** 6n;
62
+ /**
63
+ * The prices a C market can hold, in human units — quote per whole base token (decisions 054).
64
+ *
65
+ * - `listMin`, `listMax`: the wall, `10^(base − quote) · e^{∓46}`. A market cannot be initialized,
66
+ * and no floor or cap placed, outside it. An 18-dec token against 6-dec USDC cannot list under
67
+ * 1.05e-8; against an 18-dec quote the same token lists down to 1.05e-20.
68
+ * - `ceiling`: the highest price the book can trade to with `lActive` of active exposure (quote
69
+ * wei): the derived reserve `lActive / p` must stay at or above `C_MIN_RESERVE` base wei, so
70
+ * `ceiling = lActive · 10^(base − quote) / 1e6`, capped by `listMax`. In whole units that is
71
+ * `L · 10^(base − 6)`: the quote's decimals cancel and the base's set it — harmless on an
72
+ * 18-dec base, but a WBTC book of 1,000 USDC of depth stops at 100,000. Omit `lActive` for the
73
+ * wall alone.
74
+ *
75
+ * Floats, for display and warnings; the chain is the authority.
76
+ */
77
+ export function cPriceRange(baseDecimals, quoteDecimals, lActive) {
78
+ const scale = priceScale(baseDecimals, quoteDecimals);
79
+ const listMin = Math.exp(-C_MAX_ABS_X) * scale;
80
+ const listMax = Math.exp(C_MAX_ABS_X) * scale;
81
+ const ceiling = lActive === undefined || lActive === 0n ? listMax : Math.min(listMax, (Number(lActive) / Number(C_MIN_RESERVE)) * scale);
82
+ return { listMin, listMax, ceiling };
83
+ }
84
+ /** Whether a C market can be initialized at `price` (human units) for this pair's decimals. */
85
+ export function cListable(price, baseDecimals, quoteDecimals) {
86
+ const { listMin, listMax } = cPriceRange(baseDecimals, quoteDecimals);
87
+ return price >= listMin && price <= listMax;
88
+ }
58
89
  /**
59
90
  * The model-free LP edge, $F - \tfrac12\Sigma$ — the protocol's headline metric, in quote per unit
60
91
  * of exposure.
package/dist/write.d.ts CHANGED
@@ -59,6 +59,29 @@ export declare function resolveRecipient(c: LogswapClient, o?: WriteOptions): Ad
59
59
  * bound at all because it looks protective.
60
60
  */
61
61
  export declare function withSlippage(quoted: bigint, bps: number, side: "output" | "input"): bigint;
62
+ type AbiError = {
63
+ type: "error";
64
+ name: string;
65
+ inputs: readonly {
66
+ type: string;
67
+ }[];
68
+ };
69
+ /**
70
+ * Every custom error a router call can revert with that the router's own ABI does not declare: the
71
+ * C and F managers' (a mint, a swap or a settlement bubbles them up unchanged) and Permit2's.
72
+ * Without them viem can name only the router's errors, and anything raised in the manager comes
73
+ * back as a bare selector.
74
+ */
75
+ export declare const routerRevertErrors: readonly AbiError[];
76
+ /** `abi` plus every error in {@link routerRevertErrors} it does not already declare. */
77
+ export declare function withRevertErrors(abi: readonly unknown[]): readonly unknown[];
78
+ /**
79
+ * The decoded revert of a contract call, e.g. `SlippageIn()` or `AllowanceExpired(1700000000)`,
80
+ * found however deep viem nested it; the raw selector when the error is not in the ABI; undefined
81
+ * when the failure was not a revert. viem's `message` puts the name on its second line, so a UI
82
+ * that shows only the first line ("The contract function … reverted.") loses it.
83
+ */
84
+ export declare function revertName(e: unknown): string | undefined;
62
85
  /**
63
86
  * Send a router write with a gas buffer over an explicit estimate.
64
87
  *
@@ -104,3 +127,4 @@ export declare function sendRouterWriteWithPermits(c: LogswapClient, args: {
104
127
  args: readonly unknown[];
105
128
  bufferPct?: bigint;
106
129
  }, pullTokens: Address[]): Promise<Hash>;
130
+ export {};
package/dist/write.js CHANGED
@@ -12,6 +12,7 @@
12
12
  * raw `minOut`/`maxIn` the contract wants. `withSlippage()` derives one from a quote when that is
13
13
  * what you have — but the bound is what ships.
14
14
  */
15
+ import { cPoolManagerAbi, fPoolManagerAbi } from "./generated.js";
15
16
  /** Disables the deadline check. Deliberate opt-out, never a default. */
16
17
  export const NEVER = (1n << 256n) - 1n;
17
18
  /** Default deadline window: 20 minutes, the same order as every major DEX front end. */
@@ -70,6 +71,59 @@ export function withSlippage(quoted, bps, side) {
70
71
  // an input bound rounds UP: flooring it would put a wei-exact quote at bps = 0 one wei short
71
72
  return side === "output" ? (quoted * (10000n - b)) / 10000n : (quoted * (10000n + b) + 9999n) / 10000n;
72
73
  }
74
+ /** Permit2's pull errors — Uniswap's and the devnet mock's — which a router write can revert with. */
75
+ const permit2Errors = [
76
+ { type: "error", name: "AllowanceExpired", inputs: [{ type: "uint256" }] },
77
+ { type: "error", name: "InsufficientAllowance", inputs: [{ type: "uint256" }] },
78
+ { type: "error", name: "AllowanceExpired", inputs: [] },
79
+ { type: "error", name: "NotAllowed", inputs: [] },
80
+ ];
81
+ const errorKey = (e) => `${e.name}(${e.inputs.map((i) => i.type).join(",")})`;
82
+ /**
83
+ * Every custom error a router call can revert with that the router's own ABI does not declare: the
84
+ * C and F managers' (a mint, a swap or a settlement bubbles them up unchanged) and Permit2's.
85
+ * Without them viem can name only the router's errors, and anything raised in the manager comes
86
+ * back as a bare selector.
87
+ */
88
+ export const routerRevertErrors = (() => {
89
+ const seen = new Set();
90
+ const out = [];
91
+ for (const x of [...cPoolManagerAbi, ...fPoolManagerAbi, ...permit2Errors]) {
92
+ if (x.type !== "error")
93
+ continue;
94
+ const e = x;
95
+ if (!seen.has(errorKey(e))) {
96
+ seen.add(errorKey(e));
97
+ out.push(e);
98
+ }
99
+ }
100
+ return out;
101
+ })();
102
+ /** `abi` plus every error in {@link routerRevertErrors} it does not already declare. */
103
+ export function withRevertErrors(abi) {
104
+ const have = new Set(abi.filter((x) => x.type === "error").map((x) => errorKey(x)));
105
+ return [...abi, ...routerRevertErrors.filter((e) => !have.has(errorKey(e)))];
106
+ }
107
+ /**
108
+ * The decoded revert of a contract call, e.g. `SlippageIn()` or `AllowanceExpired(1700000000)`,
109
+ * found however deep viem nested it; the raw selector when the error is not in the ABI; undefined
110
+ * when the failure was not a revert. viem's `message` puts the name on its second line, so a UI
111
+ * that shows only the first line ("The contract function … reverted.") loses it.
112
+ */
113
+ export function revertName(e) {
114
+ const seen = new Set();
115
+ for (let x = e; x && typeof x === "object" && !seen.has(x); x = x.cause) {
116
+ seen.add(x);
117
+ const o = x;
118
+ if (o.name !== "ContractFunctionRevertedError")
119
+ continue;
120
+ if (o.data?.errorName)
121
+ return `${o.data.errorName}(${(o.data.args ?? []).map(String).join(", ")})`;
122
+ if (o.signature)
123
+ return o.signature;
124
+ }
125
+ return undefined;
126
+ }
73
127
  /**
74
128
  * Send a router write with a gas buffer over an explicit estimate.
75
129
  *
@@ -82,7 +136,7 @@ export async function sendRouterWrite(c, args) {
82
136
  const { account } = requireWallet(c);
83
137
  const params = {
84
138
  address: c.addresses.router,
85
- abi: args.abi,
139
+ abi: withRevertErrors(args.abi),
86
140
  functionName: args.functionName,
87
141
  args: args.args,
88
142
  account,
@@ -122,7 +176,7 @@ export async function simulateRouterWrite(c, args) {
122
176
  const account = args.account ?? c.wallet?.account?.address;
123
177
  const { result } = await c.public.simulateContract({
124
178
  address: c.addresses.router,
125
- abi: args.abi,
179
+ abi: withRevertErrors(args.abi),
126
180
  functionName: args.functionName,
127
181
  args: args.args,
128
182
  account,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logswap/sdk",
3
- "version": "0.5.66",
3
+ "version": "0.5.67",
4
4
  "description": "TypeScript SDK for Logswap, the liquidity primitive introducing the logarithmic invariant — typed wrappers over the CPoolManager / FPoolManager / Router / Lens surface.",
5
5
  "license": "GPL-2.0-or-later",
6
6
  "type": "module",
package/src/pools.ts CHANGED
@@ -82,6 +82,46 @@ export function priceScale(baseDecimals: number, quoteDecimals: number): number
82
82
  return 10 ** (baseDecimals - quoteDecimals);
83
83
  }
84
84
 
85
+ /** The C manager's log-price wall: |x| ≤ 46 on the WEI ratio (`MAX_ABS_FLOOR`). */
86
+ export const C_MAX_ABS_X = 46;
87
+
88
+ /** The least derived base reserve a C book keeps, in base wei (`MIN_RESERVE`, decisions 023). */
89
+ export const C_MIN_RESERVE = 10n ** 6n;
90
+
91
+ /**
92
+ * The prices a C market can hold, in human units — quote per whole base token (decisions 054).
93
+ *
94
+ * - `listMin`, `listMax`: the wall, `10^(base − quote) · e^{∓46}`. A market cannot be initialized,
95
+ * and no floor or cap placed, outside it. An 18-dec token against 6-dec USDC cannot list under
96
+ * 1.05e-8; against an 18-dec quote the same token lists down to 1.05e-20.
97
+ * - `ceiling`: the highest price the book can trade to with `lActive` of active exposure (quote
98
+ * wei): the derived reserve `lActive / p` must stay at or above `C_MIN_RESERVE` base wei, so
99
+ * `ceiling = lActive · 10^(base − quote) / 1e6`, capped by `listMax`. In whole units that is
100
+ * `L · 10^(base − 6)`: the quote's decimals cancel and the base's set it — harmless on an
101
+ * 18-dec base, but a WBTC book of 1,000 USDC of depth stops at 100,000. Omit `lActive` for the
102
+ * wall alone.
103
+ *
104
+ * Floats, for display and warnings; the chain is the authority.
105
+ */
106
+ export function cPriceRange(
107
+ baseDecimals: number,
108
+ quoteDecimals: number,
109
+ lActive?: bigint,
110
+ ): { listMin: number; listMax: number; ceiling: number } {
111
+ const scale = priceScale(baseDecimals, quoteDecimals);
112
+ const listMin = Math.exp(-C_MAX_ABS_X) * scale;
113
+ const listMax = Math.exp(C_MAX_ABS_X) * scale;
114
+ const ceiling =
115
+ lActive === undefined || lActive === 0n ? listMax : Math.min(listMax, (Number(lActive) / Number(C_MIN_RESERVE)) * scale);
116
+ return { listMin, listMax, ceiling };
117
+ }
118
+
119
+ /** Whether a C market can be initialized at `price` (human units) for this pair's decimals. */
120
+ export function cListable(price: number, baseDecimals: number, quoteDecimals: number): boolean {
121
+ const { listMin, listMax } = cPriceRange(baseDecimals, quoteDecimals);
122
+ return price >= listMin && price <= listMax;
123
+ }
124
+
85
125
  /**
86
126
  * The model-free LP edge, $F - \tfrac12\Sigma$ — the protocol's headline metric, in quote per unit
87
127
  * of exposure.
package/src/write.ts CHANGED
@@ -15,6 +15,7 @@
15
15
 
16
16
  import type { Address, Hash, Hex } from "viem";
17
17
  import type { LogswapClient } from "./client.js";
18
+ import { cPoolManagerAbi, fPoolManagerAbi } from "./generated.js";
18
19
 
19
20
  /** Disables the deadline check. Deliberate opt-out, never a default. */
20
21
  export const NEVER = (1n << 256n) - 1n;
@@ -87,6 +88,64 @@ export function withSlippage(quoted: bigint, bps: number, side: "output" | "inpu
87
88
  return side === "output" ? (quoted * (10_000n - b)) / 10_000n : (quoted * (10_000n + b) + 9_999n) / 10_000n;
88
89
  }
89
90
 
91
+ type AbiError = { type: "error"; name: string; inputs: readonly { type: string }[] };
92
+
93
+ /** Permit2's pull errors — Uniswap's and the devnet mock's — which a router write can revert with. */
94
+ const permit2Errors: readonly AbiError[] = [
95
+ { type: "error", name: "AllowanceExpired", inputs: [{ type: "uint256" }] },
96
+ { type: "error", name: "InsufficientAllowance", inputs: [{ type: "uint256" }] },
97
+ { type: "error", name: "AllowanceExpired", inputs: [] },
98
+ { type: "error", name: "NotAllowed", inputs: [] },
99
+ ];
100
+
101
+ const errorKey = (e: AbiError) => `${e.name}(${e.inputs.map((i) => i.type).join(",")})`;
102
+
103
+ /**
104
+ * Every custom error a router call can revert with that the router's own ABI does not declare: the
105
+ * C and F managers' (a mint, a swap or a settlement bubbles them up unchanged) and Permit2's.
106
+ * Without them viem can name only the router's errors, and anything raised in the manager comes
107
+ * back as a bare selector.
108
+ */
109
+ export const routerRevertErrors: readonly AbiError[] = (() => {
110
+ const seen = new Set<string>();
111
+ const out: AbiError[] = [];
112
+ for (const x of [...cPoolManagerAbi, ...fPoolManagerAbi, ...permit2Errors] as readonly { type: string }[]) {
113
+ if (x.type !== "error") continue;
114
+ const e = x as AbiError;
115
+ if (!seen.has(errorKey(e))) {
116
+ seen.add(errorKey(e));
117
+ out.push(e);
118
+ }
119
+ }
120
+ return out;
121
+ })();
122
+
123
+ /** `abi` plus every error in {@link routerRevertErrors} it does not already declare. */
124
+ export function withRevertErrors(abi: readonly unknown[]): readonly unknown[] {
125
+ const have = new Set(
126
+ (abi as readonly { type: string }[]).filter((x) => x.type === "error").map((x) => errorKey(x as AbiError)),
127
+ );
128
+ return [...abi, ...routerRevertErrors.filter((e) => !have.has(errorKey(e)))];
129
+ }
130
+
131
+ /**
132
+ * The decoded revert of a contract call, e.g. `SlippageIn()` or `AllowanceExpired(1700000000)`,
133
+ * found however deep viem nested it; the raw selector when the error is not in the ABI; undefined
134
+ * when the failure was not a revert. viem's `message` puts the name on its second line, so a UI
135
+ * that shows only the first line ("The contract function … reverted.") loses it.
136
+ */
137
+ export function revertName(e: unknown): string | undefined {
138
+ const seen = new Set<unknown>();
139
+ for (let x: unknown = e; x && typeof x === "object" && !seen.has(x); x = (x as { cause?: unknown }).cause) {
140
+ seen.add(x);
141
+ const o = x as { name?: string; data?: { errorName?: string; args?: readonly unknown[] }; signature?: string };
142
+ if (o.name !== "ContractFunctionRevertedError") continue;
143
+ if (o.data?.errorName) return `${o.data.errorName}(${(o.data.args ?? []).map(String).join(", ")})`;
144
+ if (o.signature) return o.signature;
145
+ }
146
+ return undefined;
147
+ }
148
+
90
149
  /**
91
150
  * Send a router write with a gas buffer over an explicit estimate.
92
151
  *
@@ -102,7 +161,7 @@ export async function sendRouterWrite(
102
161
  const { account } = requireWallet(c);
103
162
  const params = {
104
163
  address: c.addresses.router,
105
- abi: args.abi,
164
+ abi: withRevertErrors(args.abi),
106
165
  functionName: args.functionName,
107
166
  args: args.args,
108
167
  account,
@@ -147,7 +206,7 @@ export async function simulateRouterWrite<T>(
147
206
  const account = args.account ?? c.wallet?.account?.address;
148
207
  const { result } = await c.public.simulateContract({
149
208
  address: c.addresses.router,
150
- abi: args.abi,
209
+ abi: withRevertErrors(args.abi),
151
210
  functionName: args.functionName,
152
211
  args: args.args,
153
212
  account,