@logswap/sdk 0.5.55 → 0.5.57
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 +2 -75
- package/dist/actions.d.ts +1 -1
- package/dist/actions.js +1 -1
- package/dist/admin.d.ts +7 -7
- package/dist/admin.js +7 -7
- package/dist/claims.js +15 -34
- package/dist/client.d.ts +13 -6
- package/dist/client.js +74 -17
- package/dist/fpool.d.ts +53 -53
- package/dist/fpool.js +51 -51
- package/dist/keys.d.ts +1 -1
- package/dist/liquidity.d.ts +7 -7
- package/dist/liquidity.js +6 -6
- package/dist/onboard.d.ts +11 -0
- package/dist/onboard.js +23 -9
- package/dist/pools.d.ts +2 -2
- package/dist/pools.js +1 -1
- package/dist/write.d.ts +13 -1
- package/dist/write.js +26 -1
- package/package.json +3 -2
- package/src/actions.ts +1 -1
- package/src/admin.ts +8 -8
- package/src/claims.ts +14 -36
- package/src/client.ts +78 -19
- package/src/fpool.ts +68 -68
- package/src/keys.ts +1 -1
- package/src/liquidity.ts +8 -8
- package/src/onboard.ts +25 -8
- package/src/pools.ts +2 -2
- package/src/write.ts +27 -2
package/dist/write.d.ts
CHANGED
|
@@ -12,7 +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 type { Address, Hash } from "viem";
|
|
15
|
+
import type { Address, Hash, Hex } from "viem";
|
|
16
16
|
import type { LogswapClient } from "./client.js";
|
|
17
17
|
/** Disables the deadline check. Deliberate opt-out, never a default. */
|
|
18
18
|
export declare const NEVER: bigint;
|
|
@@ -73,6 +73,18 @@ export declare function sendRouterWrite(c: LogswapClient, args: {
|
|
|
73
73
|
args: readonly unknown[];
|
|
74
74
|
bufferPct?: bigint;
|
|
75
75
|
}): Promise<Hash>;
|
|
76
|
+
/**
|
|
77
|
+
* Whether an error is the user saying no in their wallet (EIP-1193 code 4001, viem's
|
|
78
|
+
* `UserRejectedRequestError`), however deep viem nested it.
|
|
79
|
+
*/
|
|
80
|
+
export declare function isUserRejection(e: unknown): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* The permit signatures are an optimisation: when they cannot be produced (a wallet without
|
|
83
|
+
* `signTypedData`, a read that failed) the write goes out plain and relies on a standing
|
|
84
|
+
* allowance. A REJECTED signature is not that — it was swallowed too, and the user who had just
|
|
85
|
+
* said no was shown a transaction prompt, which then reverted with a Permit2 error that hid why.
|
|
86
|
+
*/
|
|
87
|
+
export declare function fallBackUnlessRejected(e: unknown): Hex[];
|
|
76
88
|
/** Simulate a router write and return its decoded result, without sending. */
|
|
77
89
|
export declare function simulateRouterWrite<T>(c: LogswapClient, args: {
|
|
78
90
|
abi: readonly unknown[];
|
package/dist/write.js
CHANGED
|
@@ -92,6 +92,31 @@ export async function sendRouterWrite(c, args) {
|
|
|
92
92
|
const gas = (estimate * (100n + (args.bufferPct ?? 30n))) / 100n;
|
|
93
93
|
return c.wallet.writeContract({ ...params, gas });
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Whether an error is the user saying no in their wallet (EIP-1193 code 4001, viem's
|
|
97
|
+
* `UserRejectedRequestError`), however deep viem nested it.
|
|
98
|
+
*/
|
|
99
|
+
export function isUserRejection(e) {
|
|
100
|
+
const seen = new Set();
|
|
101
|
+
for (let x = e; x && typeof x === "object" && !seen.has(x); x = x.cause) {
|
|
102
|
+
seen.add(x);
|
|
103
|
+
const o = x;
|
|
104
|
+
if (o.name === "UserRejectedRequestError" || o.code === 4001)
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* The permit signatures are an optimisation: when they cannot be produced (a wallet without
|
|
111
|
+
* `signTypedData`, a read that failed) the write goes out plain and relies on a standing
|
|
112
|
+
* allowance. A REJECTED signature is not that — it was swallowed too, and the user who had just
|
|
113
|
+
* said no was shown a transaction prompt, which then reverted with a Permit2 error that hid why.
|
|
114
|
+
*/
|
|
115
|
+
export function fallBackUnlessRejected(e) {
|
|
116
|
+
if (isUserRejection(e))
|
|
117
|
+
throw e;
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
95
120
|
/** Simulate a router write and return its decoded result, without sending. */
|
|
96
121
|
export async function simulateRouterWrite(c, args) {
|
|
97
122
|
const account = args.account ?? c.wallet?.account?.address;
|
|
@@ -112,7 +137,7 @@ export async function simulateRouterWrite(c, args) {
|
|
|
112
137
|
*/
|
|
113
138
|
export async function sendRouterWriteWithPermits(c, args, pullTokens) {
|
|
114
139
|
const { permit2SigCalls } = await import("./onboard.js");
|
|
115
|
-
const sigCalls = await permit2SigCalls(c, pullTokens).catch(
|
|
140
|
+
const sigCalls = await permit2SigCalls(c, pullTokens).catch(fallBackUnlessRejected);
|
|
116
141
|
if (sigCalls.length === 0)
|
|
117
142
|
return sendRouterWrite(c, args);
|
|
118
143
|
const { encodeFunctionData } = await import("viem");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logswap/sdk",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.57",
|
|
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",
|
|
@@ -45,5 +45,6 @@
|
|
|
45
45
|
"repository": {
|
|
46
46
|
"type": "git",
|
|
47
47
|
"url": "git+https://github.com/logswap/logswap-sdk.git"
|
|
48
|
-
}
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://logswap.org"
|
|
49
50
|
}
|
package/src/actions.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* actions.ts — the router's transaction: a BATCH
|
|
2
|
+
* actions.ts — the router's transaction: a BATCH.
|
|
3
3
|
*
|
|
4
4
|
* `execute(actions, settle)` runs a list of actions — mint, burn, update, claim, swap, path, in any
|
|
5
5
|
* order, across any C markets — under ONE manager lock. Each action accrues deltas on the router
|
package/src/admin.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* admin — the protocol's writes: the C manager's cut of the mint fee (the F manager's is a
|
|
3
|
-
* constant
|
|
3
|
+
* constant), the policies a pool may be born with (the registry's), the
|
|
4
4
|
* policies' own numbers, and the two-step collector handover. Plain writes to the managers,
|
|
5
5
|
* the registry and the policies; no router.
|
|
6
6
|
*
|
|
7
|
-
* One vocabulary
|
|
7
|
+
* One vocabulary: both managers call the protocol's cut of the mint fee
|
|
8
8
|
* `MINT_FEE_PROTOCOL_CUT`; C sets it through `setFeeParams(uint256)`, F holds it as a constant
|
|
9
|
-
* (049). The harvest's cut is the policy's answer at every harvest
|
|
9
|
+
* (049). The harvest's cut is the policy's answer at every harvest, set on the
|
|
10
10
|
* policy (`setHarvestCut`) and capped by the manager (`HARVEST_CUT_MAX`); the release's
|
|
11
11
|
* protocol share likewise (`POT_CUT_MAX`).
|
|
12
12
|
*/
|
|
@@ -29,12 +29,12 @@ function write(c: LogswapClient, address: Address, abi: readonly unknown[], func
|
|
|
29
29
|
export async function setFeeParamsC(c: LogswapClient, mintFeeProtocolCutWad: bigint): Promise<Hash> {
|
|
30
30
|
return write(c, c.addresses.cPoolManager, cPoolManagerAbi, "setFeeParams", [mintFeeProtocolCutWad]);
|
|
31
31
|
}
|
|
32
|
-
/** The F manager's `MINT_FEE_PROTOCOL_CUT` — a constant since F version 18
|
|
32
|
+
/** The F manager's `MINT_FEE_PROTOCOL_CUT` — a constant since F version 18; there is no setter. */
|
|
33
33
|
export async function fMintFeeProtocolCut(c: LogswapClient): Promise<bigint> {
|
|
34
34
|
return c.public.readContract({ address: c.addresses.fPoolManager as Address, abi: fPoolManagerAbi, functionName: "MINT_FEE_PROTOCOL_CUT" } as never) as Promise<bigint>;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
// ─── the registry
|
|
37
|
+
// ─── the registry: the LOG authority's, not the collector's ─────────────────
|
|
38
38
|
|
|
39
39
|
const ZERO = "0x0000000000000000000000000000000000000000" as const;
|
|
40
40
|
|
|
@@ -58,7 +58,7 @@ export async function policyApproved(c: LogswapClient, policy: Address): Promise
|
|
|
58
58
|
/** One policy on the registry's list, with what it says it is. */
|
|
59
59
|
export interface RegistryEntry {
|
|
60
60
|
policy: Address;
|
|
61
|
-
/** The policy's own `kind()` tag
|
|
61
|
+
/** The policy's own `kind()` tag — what a pool born under it is. */
|
|
62
62
|
kind: FPoolKind;
|
|
63
63
|
name: string;
|
|
64
64
|
/** The block it closes to new pools from; 0 = open. */
|
|
@@ -68,7 +68,7 @@ export interface RegistryEntry {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
|
-
* Every policy listed, sunset ones included — one flat list
|
|
71
|
+
* Every policy listed, sunset ones included — one flat list, each with the kind
|
|
72
72
|
* it says it is; `kind` narrows it to one, which is what a create form's dropdown reads. Empty
|
|
73
73
|
* with no registry.
|
|
74
74
|
*/
|
|
@@ -138,7 +138,7 @@ export async function setPolicyApproved(c: LogswapClient, policy: Address, appro
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
/**
|
|
141
|
-
* Move a pool to another approved policy of the same kind
|
|
141
|
+
* Move a pool to another approved policy of the same kind: the registry
|
|
142
142
|
* owner's alone, orchestrated on the registry — `migrate(manager, poolId, to)`. The new policy
|
|
143
143
|
* takes the authority and the name from the old; the operator and the lists void; no swap lands
|
|
144
144
|
* in the block.
|
package/src/claims.ts
CHANGED
|
@@ -91,42 +91,20 @@ export async function checkReadiness(
|
|
|
91
91
|
owner: Address,
|
|
92
92
|
need: { base?: bigint; quote?: bigint; positions?: boolean } = {},
|
|
93
93
|
): Promise<Readiness> {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
] as const;
|
|
106
|
-
|
|
107
|
-
const [operator, baseAllow, quoteAllow] = await Promise.all([
|
|
94
|
+
// A token is ready when BOTH legs of its pull path are: the ERC-20 allowance to whoever pulls
|
|
95
|
+
// (Permit2 when wired) and, with Permit2, its unexpired allowance to the router. This used to
|
|
96
|
+
// read the ERC-20 allowance to the ROUTER, which on a Permit2 deployment is never granted — so
|
|
97
|
+
// it said "approve" forever, and approving the router changed nothing.
|
|
98
|
+
const { checkTokenReadiness } = await import("./onboard.js");
|
|
99
|
+
const ready = async (token: Address, amount?: bigint) => {
|
|
100
|
+
if (amount === undefined) return true;
|
|
101
|
+
const r = await checkTokenReadiness(c, token, owner, amount);
|
|
102
|
+
return !r.needsTokenApproval && !r.needsPermit2Approval;
|
|
103
|
+
};
|
|
104
|
+
const [operator, baseOk, quoteOk] = await Promise.all([
|
|
108
105
|
need.positions ? isRouterApproved(c, owner) : Promise.resolve(true),
|
|
109
|
-
need.base
|
|
110
|
-
|
|
111
|
-
address: key.base,
|
|
112
|
-
abi: erc20,
|
|
113
|
-
functionName: "allowance",
|
|
114
|
-
args: [owner, c.addresses.router],
|
|
115
|
-
}) as Promise<bigint>)
|
|
116
|
-
: Promise.resolve(0n),
|
|
117
|
-
need.quote
|
|
118
|
-
? (c.public.readContract({
|
|
119
|
-
address: key.quote,
|
|
120
|
-
abi: erc20,
|
|
121
|
-
functionName: "allowance",
|
|
122
|
-
args: [owner, c.addresses.router],
|
|
123
|
-
}) as Promise<bigint>)
|
|
124
|
-
: Promise.resolve(0n),
|
|
106
|
+
ready(key.base, need.base),
|
|
107
|
+
ready(key.quote, need.quote),
|
|
125
108
|
]);
|
|
126
|
-
|
|
127
|
-
return {
|
|
128
|
-
needsOperator: !operator,
|
|
129
|
-
needsBaseAllowance: need.base !== undefined && baseAllow < need.base,
|
|
130
|
-
needsQuoteAllowance: need.quote !== undefined && quoteAllow < need.quote,
|
|
131
|
-
};
|
|
109
|
+
return { needsOperator: !operator, needsBaseAllowance: !baseOk, needsQuoteAllowance: !quoteOk };
|
|
132
110
|
}
|
package/src/client.ts
CHANGED
|
@@ -24,7 +24,7 @@ export interface LogswapAddresses {
|
|
|
24
24
|
*/
|
|
25
25
|
fPoolManager?: Address;
|
|
26
26
|
/**
|
|
27
|
-
* The protocol's four F policies, one per kind
|
|
27
|
+
* The protocol's four F policies, one per kind: every F pool names one in its key,
|
|
28
28
|
* and the pool's roles, gates and terms live on it. A deployment predating them carries none.
|
|
29
29
|
*/
|
|
30
30
|
publicPolicy?: Address;
|
|
@@ -32,7 +32,7 @@ export interface LogswapAddresses {
|
|
|
32
32
|
polPolicy?: Address;
|
|
33
33
|
padPolicy?: Address;
|
|
34
34
|
/**
|
|
35
|
-
* The policy registry
|
|
35
|
+
* The policy registry: what a pool of each kind may be born under, and the
|
|
36
36
|
* owner that may move a pool between policies. Read from the F manager (`registry()`) when
|
|
37
37
|
* absent; a deployment with none asks nobody.
|
|
38
38
|
*/
|
|
@@ -52,7 +52,38 @@ export function createLogswapClient(args: {
|
|
|
52
52
|
wallet?: WalletClient;
|
|
53
53
|
addresses: LogswapAddresses;
|
|
54
54
|
}): LogswapClient {
|
|
55
|
-
return { public: args.public, wallet: args.wallet, addresses: args.addresses };
|
|
55
|
+
return { public: args.public, wallet: args.wallet && guardChain(args.wallet, args.public), addresses: args.addresses };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The wallet, with every signing call first checking that it is on the chain the reads come from.
|
|
60
|
+
*
|
|
61
|
+
* An injected wallet switched to another network would otherwise estimate and simulate against
|
|
62
|
+
* the public client's chain and then sign and send on its own — with deterministic deploy
|
|
63
|
+
* addresses, possibly into a different contract. Checked at each call, not once: a user can
|
|
64
|
+
* switch networks mid-session.
|
|
65
|
+
*/
|
|
66
|
+
function guardChain(wallet: WalletClient, pub: PublicClient): WalletClient {
|
|
67
|
+
if (typeof wallet.getChainId !== "function") return wallet; // a test double
|
|
68
|
+
let readChain: number | undefined = pub.chain?.id;
|
|
69
|
+
const check = async () => {
|
|
70
|
+
readChain ??= await pub.getChainId();
|
|
71
|
+
const walletChain = await wallet.getChainId();
|
|
72
|
+
if (walletChain !== readChain) {
|
|
73
|
+
throw new Error(`logswap: the wallet is on chain ${walletChain} but this app reads chain ${readChain} — switch the wallet's network`);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const guarded = new Set<PropertyKey>(["writeContract", "sendTransaction", "signTypedData"]);
|
|
77
|
+
return new Proxy(wallet, {
|
|
78
|
+
get(target, prop, receiver) {
|
|
79
|
+
const v = Reflect.get(target, prop, receiver);
|
|
80
|
+
if (!guarded.has(prop) || typeof v !== "function") return v;
|
|
81
|
+
return async (...a: unknown[]) => {
|
|
82
|
+
await check();
|
|
83
|
+
return (v as (...x: unknown[]) => unknown).apply(target, a);
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
});
|
|
56
87
|
}
|
|
57
88
|
|
|
58
89
|
/**
|
|
@@ -69,18 +100,18 @@ export function createLogswapClient(args: {
|
|
|
69
100
|
* manager sailed through `assertVersion` while `FEE_MAX()` still answered on it. Move this in the
|
|
70
101
|
* same change as `CParams.VERSION`, never after it.
|
|
71
102
|
*
|
|
72
|
-
* **3** since 2026-09-03
|
|
103
|
+
* **3** since 2026-09-03: `burnById` and `update` take an `owner`, `update`
|
|
73
104
|
* mints to `to`, `positions()` returns `aps` as uint128 — and a returned quote flow now carries the
|
|
74
|
-
* swept fees
|
|
105
|
+
* swept fees, which is why `exit`'s settle-to-one-asset math changed with it.
|
|
75
106
|
*
|
|
76
|
-
* **4** since 2026-09-18
|
|
107
|
+
* **4** since 2026-09-18: `PoolKey` is `(base, quote, tickSpacing, phi)` —
|
|
77
108
|
* the variance kernel and its two key fields are gone, so every pool id changed; `phiEff` is
|
|
78
109
|
* `phiOf`; `getPool` lost `sigma2Ema`; `Initialize` lost two fields; the cut is
|
|
79
110
|
* `MINT_FEE_PROTOCOL_CUT` / `setFeeParams`.
|
|
80
111
|
*/
|
|
81
112
|
export const EXPECTED_VERSION = 4n;
|
|
82
113
|
/**
|
|
83
|
-
* The F manager's own tag (
|
|
114
|
+
* The F manager's own tag (5 — the key's salt, pool names, the sponsor registry;
|
|
84
115
|
* 4 was the income-only harvest cut).
|
|
85
116
|
*
|
|
86
117
|
* A FLOOR, not an equality — unlike `EXPECTED_VERSION` above. The F primitive is iterating fast and
|
|
@@ -92,43 +123,43 @@ export const EXPECTED_VERSION = 4n;
|
|
|
92
123
|
*/
|
|
93
124
|
// 7 (2026-09-15): the reserves are the state and the marks derived, `lockStrike`, the dividend
|
|
94
125
|
// harvest, the relaunch (`dissolve(poolId, successor)`, `rollIn`), the reserve-named seed, the
|
|
95
|
-
// sponsor facet
|
|
96
|
-
// 8 (2026-09-15): the relaunch is in place
|
|
126
|
+
// sponsor facet.
|
|
127
|
+
// 8 (2026-09-15): the relaunch is in place — every share id carries the
|
|
97
128
|
// generation (`fPoolShareId(poolId, gen)`), `dissolve(poolId)`, `redeem`, `claim` / `dividendOf`
|
|
98
129
|
// / `rollIn` / `previewRollIn` take the generation, `Pool.gen` replaces `dissolved` and
|
|
99
130
|
// `successor`. A 7 deployment's share ids do not even resolve with this SDK.
|
|
100
|
-
// 9 (2026-09-16): `deepen` is gone, `Pool.leverTheta` is `harvestedTheta
|
|
131
|
+
// 9 (2026-09-16): `deepen` is gone, `Pool.leverTheta` is `harvestedTheta`.
|
|
101
132
|
// 10 (2026-09-17): no floor guard — `Pool.minBuffer`, `raiseMinBuffer`, `LEVER_FLOOR` gone;
|
|
102
|
-
// `dissolve` needs an empty bid on every pool
|
|
133
|
+
// `dissolve` needs an empty bid on every pool; the key bit is the CLASS, `pad`
|
|
103
134
|
// (036): `seed` mints a pad's shares to 0xdead, and the operator, the gates and the list are
|
|
104
135
|
// refused on it — `fPoolLaunch` no longer transfers the seed itself.
|
|
105
|
-
// 11 (2026-09-17): roles and entries
|
|
136
|
+
// 11 (2026-09-17): roles and entries — the operator runs the pool (`harvest`,
|
|
106
137
|
// `dissolve`, `setLegs`) and is the authority until appointed, two-step (`acceptOperator`,
|
|
107
138
|
// `Pool.pendingOperator`); `setLegL`/`admitLeg` are gone, `setLegs` edits the next generation's
|
|
108
139
|
// table while unseeded; `fPoolRelaunch` takes `legs`.
|
|
109
140
|
// `getPool` decodes one field fewer, so a 9 deployment's struct no longer matches this SDK.
|
|
110
|
-
// 12 (2026-09-17): one contract
|
|
141
|
+
// 12 (2026-09-17): one contract — the sponsor facet is folded back into the
|
|
111
142
|
// manager; `sponsor()` and the fallback are gone, every entry, error and event unchanged, so
|
|
112
143
|
// `fPoolManagerAbi` is the manager's own ABI and no longer a union. Layout unchanged.
|
|
113
|
-
// 13 (2026-09-18): one vocabulary
|
|
144
|
+
// 13 (2026-09-18): one vocabulary — `HARVEST_FEE` is `HARVEST_PROTOCOL_CUT` (a
|
|
114
145
|
// cut of harvested income, not a fee on the harvest) and the exemption is `harvestCutExempt` /
|
|
115
146
|
// `setHarvestCutExempt`; `acceptAuthority` clears the operator, pending and accepted (a mandate
|
|
116
147
|
// is voided by the handover of the role that granted it); `setLegs` needs a generation to have
|
|
117
148
|
// lived (`gen > 0`); `initialize` refuses a codeless base and `mint` refuses `to = address(0)`
|
|
118
149
|
// on both managers. Layout unchanged.
|
|
119
|
-
// 14 (2026-09-20): the policy
|
|
150
|
+
// 14 (2026-09-20): the policy — `FPoolKey.policy`, every pool id moves; `dissolve` is
|
|
120
151
|
// `retire`, `regenerate` releases the dead shares' pot, `harvestable`/`unharvested` are the
|
|
121
152
|
// readouts; `feePerL`, `edgePerL`, `HARVEST_PROTOCOL_CUT`, `harvestCutExempt` are gone.
|
|
122
|
-
// 15 (2026-09-20): the policy answers every question
|
|
153
|
+
// 15 (2026-09-20): the policy answers every question — `FPoolKey.authority` is
|
|
123
154
|
// `creator` (every pool id moves again); the roles, gates and list are the pool's POLICY's
|
|
124
155
|
// (`FPolicyBase` / `PrivatePolicy`), not the manager's: `getPool` has `policy` and `asks` and no
|
|
125
156
|
// role; `proposeAuthority`, `appointOperator`, `setGates`, `setAllowed` (`setMinters` / `setTakers` since 17) are policy writes;
|
|
126
157
|
// `policyApproved(kind, policy)` / `setPolicyApproved(kind, policy, ok)`; `Regenerated` names the payee;
|
|
127
158
|
// `HARVEST_CUT_MAX` / `POT_CUT_MAX` cap what a policy may route to the protocol.
|
|
128
|
-
// 16 (2026-09-21): the word is POLICY
|
|
159
|
+
// 16 (2026-09-21): the word is POLICY — a rename, no pool id moves: `FPoolKey.policy`,
|
|
129
160
|
// `IFPolicy`, `FPolicyBase`, `PublicPolicy` … `PadPolicy`, `policyApproved` / `setPolicyApproved`,
|
|
130
161
|
// `PolicyApproved`; `PolPolicy.setPolicy` / `PolicySet` are `setRules` / `RulesSet`.
|
|
131
|
-
// 17 (2026-09-21): the registry, the move, the stamp, two lists, one base
|
|
162
|
+
// 17 (2026-09-21): the registry, the move, the stamp, two lists, one base — no
|
|
132
163
|
// pool id moves: the F manager takes a `PolicyRegistry` at construction and asks it at a birth
|
|
133
164
|
// (`policyApproved` / `setPolicyApproved` left the manager: `registryApprove` …); the key's policy
|
|
134
165
|
// is the policy at birth, `migrate` moves a pool for the registry's owner; `stamp` / `setAsks` are
|
|
@@ -149,7 +180,7 @@ export async function assertVersion(c: LogswapClient, expected = EXPECTED_VERSIO
|
|
|
149
180
|
`against version ${expected}. Upgrade the SDK or point at the matching deployment.`,
|
|
150
181
|
);
|
|
151
182
|
}
|
|
152
|
-
// the F manager carries its own tag
|
|
183
|
+
// the F manager carries its own tag; assert it the same way when deployed
|
|
153
184
|
if (c.addresses.fPoolManager) {
|
|
154
185
|
const { fPoolManagerAbi } = await import("./generated.js");
|
|
155
186
|
const gotF = await c.public.readContract({
|
|
@@ -164,4 +195,32 @@ export async function assertVersion(c: LogswapClient, expected = EXPECTED_VERSIO
|
|
|
164
195
|
);
|
|
165
196
|
}
|
|
166
197
|
}
|
|
198
|
+
await assertWiring(c);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* The versions say the managers are the right code; this says the rest of the addresses belong
|
|
203
|
+
* to THEM. A stale router or lens from a previous deployment passes every version check and then
|
|
204
|
+
* fails in the worst way: approvals go to a router that pulls for another manager, or every pull
|
|
205
|
+
* reverts because the router's Permit2 is not the one the user approved.
|
|
206
|
+
*/
|
|
207
|
+
export async function assertWiring(c: LogswapClient): Promise<void> {
|
|
208
|
+
const { logswapRouterAbi, logswapLensAbi } = await import("./generated.js");
|
|
209
|
+
const rd = (address: Address, abi: readonly unknown[], functionName: string) =>
|
|
210
|
+
c.public.readContract({ address, abi, functionName } as never) as Promise<Address>;
|
|
211
|
+
const ZERO = "0x0000000000000000000000000000000000000000";
|
|
212
|
+
const want: Array<[string, Promise<Address>, Address]> = [
|
|
213
|
+
["router.mgr()", rd(c.addresses.router, logswapRouterAbi, "mgr"), c.addresses.cPoolManager],
|
|
214
|
+
["router.permit2()", rd(c.addresses.router, logswapRouterAbi, "permit2"), c.addresses.permit2 ?? ZERO],
|
|
215
|
+
["lens.mgr()", rd(c.addresses.lens, logswapLensAbi, "mgr"), c.addresses.cPoolManager],
|
|
216
|
+
];
|
|
217
|
+
if (c.addresses.fPoolManager) {
|
|
218
|
+
want.push(["router.fmgr()", rd(c.addresses.router, logswapRouterAbi, "fmgr"), c.addresses.fPoolManager]);
|
|
219
|
+
want.push(["lens.fmgr()", rd(c.addresses.lens, logswapLensAbi, "fmgr"), c.addresses.fPoolManager]);
|
|
220
|
+
}
|
|
221
|
+
const got = await Promise.all(want.map((w) => w[1]));
|
|
222
|
+
const bad = want.flatMap(([what, , expected], i) =>
|
|
223
|
+
got[i]!.toLowerCase() === expected.toLowerCase() ? [] : [`${what} is ${got[i]}, expected ${expected}`],
|
|
224
|
+
);
|
|
225
|
+
if (bad.length) throw new Error(`logswap: the deployment's addresses do not belong together — ${bad.join("; ")}`);
|
|
167
226
|
}
|