@logswap/sdk 0.5.50 → 0.5.51
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/admin.d.ts +43 -25
- package/dist/admin.js +61 -35
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/fpool.d.ts +194 -38
- package/dist/fpool.js +82 -43
- package/dist/generated.d.ts +837 -264
- package/dist/generated.js +563 -176
- package/package.json +1 -1
- package/src/admin.ts +68 -37
- package/src/client.ts +1 -1
- package/src/fpool.ts +122 -77
- package/src/generated.ts +564 -175
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logswap/sdk",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.51",
|
|
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/admin.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* admin — the protocol's
|
|
3
|
-
*
|
|
4
|
-
* two-step collector handover. Plain writes to the managers
|
|
2
|
+
* admin — the protocol's writes: the C manager's cut of the mint fee (the F manager's is a
|
|
3
|
+
* constant, decisions 049), the policies a pool may be born with (the registry's), the
|
|
4
|
+
* policies' own numbers, and the two-step collector handover. Plain writes to the managers,
|
|
5
|
+
* the registry and the policies; no router.
|
|
5
6
|
*
|
|
6
7
|
* One vocabulary (decisions 040): both managers call the protocol's cut of the mint fee
|
|
7
|
-
* `MINT_FEE_PROTOCOL_CUT
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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 (decisions 044), set on the
|
|
10
|
+
* policy (`setHarvestCut`) and capped by the manager (`HARVEST_CUT_MAX`); the release's
|
|
11
|
+
* protocol share likewise (`POT_CUT_MAX`).
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
import type { Address, Hash } from "viem";
|
|
14
15
|
import type { LogswapClient } from "./client.js";
|
|
15
16
|
import { cPoolManagerAbi, fPoolManagerAbi, padPolicyAbi, polPolicyAbi, policyRegistryAbi, publicPolicyAbi } from "./generated.js";
|
|
16
|
-
import {
|
|
17
|
+
import { bytes32ToText, fPolicyBaseAbi, fPoolKindOfPolicy, textToBytes32, type FPoolKind } from "./fpool.js";
|
|
17
18
|
|
|
18
19
|
function wallet(c: LogswapClient) {
|
|
19
20
|
if (!c.wallet) throw new Error("a wallet client is required");
|
|
@@ -28,9 +29,9 @@ function write(c: LogswapClient, address: Address, abi: readonly unknown[], func
|
|
|
28
29
|
export async function setFeeParamsC(c: LogswapClient, mintFeeProtocolCutWad: bigint): Promise<Hash> {
|
|
29
30
|
return write(c, c.addresses.cPoolManager, cPoolManagerAbi, "setFeeParams", [mintFeeProtocolCutWad]);
|
|
30
31
|
}
|
|
31
|
-
/** The F manager's `
|
|
32
|
-
export async function
|
|
33
|
-
return
|
|
32
|
+
/** The F manager's `MINT_FEE_PROTOCOL_CUT` — a constant since F version 18 (decisions 049); there is no setter. */
|
|
33
|
+
export async function fMintFeeProtocolCut(c: LogswapClient): Promise<bigint> {
|
|
34
|
+
return c.public.readContract({ address: c.addresses.fPoolManager as Address, abi: fPoolManagerAbi, functionName: "MINT_FEE_PROTOCOL_CUT" } as never) as Promise<bigint>;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
// ─── the registry (decisions 046): the LOG authority's, not the collector's ─────────────────
|
|
@@ -47,16 +48,18 @@ export async function policyRegistryOf(c: LogswapClient): Promise<Address> {
|
|
|
47
48
|
return (await c.public.readContract({ address: c.addresses.fPoolManager as Address, abi: fPoolManagerAbi, functionName: "registry" } as never)) as Address;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
/** Whether `policy` is approved
|
|
51
|
-
export async function policyApproved(c: LogswapClient,
|
|
51
|
+
/** Whether `policy` is approved now — listed and not yet sunset. True everywhere on a deployment with no registry. */
|
|
52
|
+
export async function policyApproved(c: LogswapClient, policy: Address): Promise<boolean> {
|
|
52
53
|
const registry = await policyRegistryOf(c);
|
|
53
54
|
if (registry === ZERO) return true;
|
|
54
|
-
return c.public.readContract({ address: registry, abi: policyRegistryAbi, functionName: "isApproved", args: [
|
|
55
|
+
return c.public.readContract({ address: registry, abi: policyRegistryAbi, functionName: "isApproved", args: [policy] } as never) as Promise<boolean>;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
/** One policy on
|
|
58
|
+
/** One policy on the registry's list, with what it says it is. */
|
|
58
59
|
export interface RegistryEntry {
|
|
59
60
|
policy: Address;
|
|
61
|
+
/** The policy's own `kind()` tag (decisions 049) — what a pool born under it is. */
|
|
62
|
+
kind: FPoolKind;
|
|
60
63
|
name: string;
|
|
61
64
|
/** The block it closes to new pools from; 0 = open. */
|
|
62
65
|
until: bigint;
|
|
@@ -64,18 +67,26 @@ export interface RegistryEntry {
|
|
|
64
67
|
approved: boolean;
|
|
65
68
|
}
|
|
66
69
|
|
|
67
|
-
/**
|
|
68
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Every policy listed, sunset ones included — one flat list (decisions 049), each with the kind
|
|
72
|
+
* it says it is; `kind` narrows it to one, which is what a create form's dropdown reads. Empty
|
|
73
|
+
* with no registry.
|
|
74
|
+
*/
|
|
75
|
+
export async function registryPolicies(c: LogswapClient, kind?: FPoolKind): Promise<RegistryEntry[]> {
|
|
69
76
|
const registry = await policyRegistryOf(c);
|
|
70
77
|
if (registry === ZERO) return [];
|
|
71
|
-
const list = (await c.public.readContract({ address: registry, abi: policyRegistryAbi, functionName: "
|
|
78
|
+
const list = (await c.public.readContract({ address: registry, abi: policyRegistryAbi, functionName: "policies" } as never)) as readonly Address[];
|
|
72
79
|
const block = await c.public.getBlockNumber();
|
|
73
|
-
|
|
80
|
+
const all = await Promise.all(
|
|
74
81
|
list.map(async (policy) => {
|
|
75
|
-
const [listed, until, , name] =
|
|
76
|
-
|
|
82
|
+
const [[listed, until, , name], tag] = await Promise.all([
|
|
83
|
+
c.public.readContract({ address: registry, abi: policyRegistryAbi, functionName: "entries", args: [policy] } as never) as Promise<[boolean, bigint, number, `0x${string}`]>,
|
|
84
|
+
fPoolKindOfPolicy(c, policy),
|
|
85
|
+
]);
|
|
86
|
+
return { policy, kind: tag, name: bytes32ToText(name), until, approved: listed && (until === 0n || block < until) };
|
|
77
87
|
}),
|
|
78
88
|
);
|
|
89
|
+
return kind ? all.filter((e) => e.kind === kind) : all;
|
|
79
90
|
}
|
|
80
91
|
|
|
81
92
|
/** The registry's owner — the LOG authority — and the proposed next one. */
|
|
@@ -95,19 +106,19 @@ async function registryWrite(c: LogswapClient, functionName: string, args: reado
|
|
|
95
106
|
return write(c, registry, policyRegistryAbi, functionName, args);
|
|
96
107
|
}
|
|
97
108
|
|
|
98
|
-
/** `PolicyRegistry.approve`: list `policy`
|
|
99
|
-
export async function registryApprove(c: LogswapClient,
|
|
100
|
-
return registryWrite(c, "approve", [
|
|
109
|
+
/** `PolicyRegistry.approve`: list `policy` under `name` (at most 31 bytes). Again renames it and clears its sunset. The owner's. */
|
|
110
|
+
export async function registryApprove(c: LogswapClient, policy: Address, name: string): Promise<Hash> {
|
|
111
|
+
return registryWrite(c, "approve", [policy, textToBytes32(name)]);
|
|
101
112
|
}
|
|
102
113
|
|
|
103
|
-
/** `PolicyRegistry.sunset`: close `policy` to new pools
|
|
104
|
-
export async function registrySunset(c: LogswapClient,
|
|
105
|
-
return registryWrite(c, "sunset", [
|
|
114
|
+
/** `PolicyRegistry.sunset`: close `policy` to new pools from `untilBlock` on; 0 reopens. The owner's. */
|
|
115
|
+
export async function registrySunset(c: LogswapClient, policy: Address, untilBlock: bigint): Promise<Hash> {
|
|
116
|
+
return registryWrite(c, "sunset", [policy, untilBlock]);
|
|
106
117
|
}
|
|
107
118
|
|
|
108
|
-
/** `PolicyRegistry.revoke`: remove `policy` from
|
|
109
|
-
export async function registryRevoke(c: LogswapClient,
|
|
110
|
-
return registryWrite(c, "revoke", [
|
|
119
|
+
/** `PolicyRegistry.revoke`: remove `policy` from the list at once. Live pools are untouched. The owner's. */
|
|
120
|
+
export async function registryRevoke(c: LogswapClient, policy: Address): Promise<Hash> {
|
|
121
|
+
return registryWrite(c, "revoke", [policy]);
|
|
111
122
|
}
|
|
112
123
|
|
|
113
124
|
/** The registry owner's two-step handover. */
|
|
@@ -120,19 +131,20 @@ export async function registryAcceptOwner(c: LogswapClient): Promise<Hash> {
|
|
|
120
131
|
|
|
121
132
|
/**
|
|
122
133
|
* Approve or revoke, the F version 15–16 shape kept for callers: `approved` true is
|
|
123
|
-
* {@link registryApprove} under the
|
|
134
|
+
* {@link registryApprove} under the policy's own tag as its name, false is {@link registryRevoke}.
|
|
124
135
|
*/
|
|
125
|
-
export async function setPolicyApproved(c: LogswapClient,
|
|
126
|
-
return approved ? registryApprove(c,
|
|
136
|
+
export async function setPolicyApproved(c: LogswapClient, policy: Address, approved: boolean): Promise<Hash> {
|
|
137
|
+
return approved ? registryApprove(c, policy, await fPoolKindOfPolicy(c, policy)) : registryRevoke(c, policy);
|
|
127
138
|
}
|
|
128
139
|
|
|
129
140
|
/**
|
|
130
|
-
* Move a pool to another policy the
|
|
131
|
-
* owner's alone
|
|
132
|
-
* void; no swap lands
|
|
141
|
+
* Move a pool to another approved policy of the same kind (decisions 046, 049): the registry
|
|
142
|
+
* owner's alone, orchestrated on the registry — `migrate(manager, poolId, to)`. The new policy
|
|
143
|
+
* takes the authority and the name from the old; the operator and the lists void; no swap lands
|
|
144
|
+
* in the block.
|
|
133
145
|
*/
|
|
134
146
|
export async function fPoolMigrate(c: LogswapClient, a: { poolId: `0x${string}`; to: Address }): Promise<Hash> {
|
|
135
|
-
return
|
|
147
|
+
return registryWrite(c, "migrate", [c.addresses.fPoolManager as Address, a.poolId, a.to]);
|
|
136
148
|
}
|
|
137
149
|
|
|
138
150
|
// ─── the policies' numbers (the collector's; each bounded where it reaches the manager) ─────
|
|
@@ -156,6 +168,25 @@ export async function polSetRules(c: LogswapClient, policy: Address, s: { keepQu
|
|
|
156
168
|
return write(c, policy, polPolicyAbi, "setRules", [s.keepQuote, s.minQuoteAtSeed]);
|
|
157
169
|
}
|
|
158
170
|
|
|
171
|
+
/** `setQuoteListed` on any protocol policy: a quote a pool of that kind may be born against while it curates quotes. The collector's. */
|
|
172
|
+
export async function policySetQuoteListed(c: LogswapClient, policy: Address, quote: Address, listed: boolean): Promise<Hash> {
|
|
173
|
+
return write(c, policy, fPolicyBaseAbi, "setQuoteListed", [quote, listed]);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** `setQuoteCurated` on any protocol policy: on, a birth against an unlisted quote is refused. The collector's. */
|
|
177
|
+
export async function policySetQuoteCurated(c: LogswapClient, policy: Address, curated: boolean): Promise<Hash> {
|
|
178
|
+
return write(c, policy, fPolicyBaseAbi, "setQuoteCurated", [curated]);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Whether `quote` passes `policy`'s birth check now: listed, or the policy does not curate quotes. */
|
|
182
|
+
export async function policyQuoteAllowed(c: LogswapClient, policy: Address, quote: Address): Promise<{ curated: boolean; listed: boolean; allowed: boolean }> {
|
|
183
|
+
const [curated, listed] = await Promise.all([
|
|
184
|
+
c.public.readContract({ address: policy, abi: fPolicyBaseAbi, functionName: "quoteCurated" } as never) as Promise<boolean>,
|
|
185
|
+
c.public.readContract({ address: policy, abi: fPolicyBaseAbi, functionName: "quoteListed", args: [quote] } as never) as Promise<boolean>,
|
|
186
|
+
]);
|
|
187
|
+
return { curated, listed, allowed: !curated || listed };
|
|
188
|
+
}
|
|
189
|
+
|
|
159
190
|
/** `PublicPolicy.setListed`: an asset a curated seed may hold. */
|
|
160
191
|
export async function publicSetListed(c: LogswapClient, policy: Address, token: Address, listed: boolean): Promise<Hash> {
|
|
161
192
|
return write(c, policy, publicPolicyAbi, "setListed", [token, listed]);
|
package/src/client.ts
CHANGED
|
@@ -134,7 +134,7 @@ export const EXPECTED_VERSION = 4n;
|
|
|
134
134
|
// is the policy at birth, `migrate` moves a pool for the registry's owner; `stamp` / `setAsks` are
|
|
135
135
|
// the policy's; the desk's `setAllowed` / `isAllowed` are `setMinters` / `setTakers` / `isMinter` /
|
|
136
136
|
// `isTaker`; a pad and a POL hold one base (`OneBase`).
|
|
137
|
-
export const EXPECTED_F_VERSION =
|
|
137
|
+
export const EXPECTED_F_VERSION = 18n;
|
|
138
138
|
|
|
139
139
|
export async function assertVersion(c: LogswapClient, expected = EXPECTED_VERSION): Promise<void> {
|
|
140
140
|
const { cPoolManagerAbi } = await import("./generated.js");
|
package/src/fpool.ts
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
33
|
import { encodeFunctionData, toFunctionSelector, type Address, type Hash, type Hex } from "viem";
|
|
34
|
-
import { fPoolManagerAbi, logswapRouterAbi, padPolicyAbi, polPolicyAbi, privatePolicyAbi, publicPolicyAbi } from "./generated.js";
|
|
34
|
+
import { fPoolManagerAbi, logswapRouterAbi, padPolicyAbi, polPolicyAbi, policyRegistryAbi, privatePolicyAbi, publicPolicyAbi } from "./generated.js";
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* One contract, one ABI (decisions 039, F version 12): `harvest`, `claim`, `retire`, `regenerate`,
|
|
@@ -88,11 +88,11 @@ export interface FPoolState {
|
|
|
88
88
|
policy: Address;
|
|
89
89
|
/** Whether the policy asked to be consulted on swaps ({@link ASK_SWAP}) and mints ({@link ASK_MINT}) — the desk's policy does, no other. */
|
|
90
90
|
asks: number;
|
|
91
|
-
/** The sponsor's own label for this pool, mutable and never identity. "" when unnamed. */
|
|
91
|
+
/** The sponsor's own label for this pool — the policy's word (decisions 049), mutable and never identity. "" when unnamed. */
|
|
92
92
|
name: string;
|
|
93
93
|
/** The block of the last harvest / composition action: no swap runs in it. */
|
|
94
94
|
restructureBlock: number;
|
|
95
|
-
/**
|
|
95
|
+
/** What the pool is — its POLICY's self-description (decisions 049); see {@link FPoolKind}. */
|
|
96
96
|
kind: FPoolKind;
|
|
97
97
|
/** False before the first seed — and between a retire and the next one (decisions 032). */
|
|
98
98
|
seeded: boolean;
|
|
@@ -120,12 +120,12 @@ export async function getFPool(c: LogswapClient, poolId: Hex): Promise<FPoolStat
|
|
|
120
120
|
} as never) as Promise<T>;
|
|
121
121
|
|
|
122
122
|
// `getPool` returns the whole scalar struct in one call — the singleton's shape makes what used
|
|
123
|
-
// to be a dozen getters a single read. No role in it since F version 15
|
|
123
|
+
// to be a dozen getters a single read. No role in it since F version 15, no kind and no name
|
|
124
|
+
// since 18: those are the policy's.
|
|
124
125
|
const p = await rd<{
|
|
125
126
|
quote: Address;
|
|
126
127
|
phi: bigint;
|
|
127
128
|
policy: Address;
|
|
128
|
-
kind: number;
|
|
129
129
|
seeded: boolean;
|
|
130
130
|
gen: number;
|
|
131
131
|
n: number;
|
|
@@ -136,7 +136,6 @@ export async function getFPool(c: LogswapClient, poolId: Hex): Promise<FPoolStat
|
|
|
136
136
|
L: bigint;
|
|
137
137
|
shares: bigint;
|
|
138
138
|
theta0: bigint;
|
|
139
|
-
name: Hex;
|
|
140
139
|
}>("getPool", [poolId]);
|
|
141
140
|
|
|
142
141
|
// A pool that was never created reads as an all-zero struct rather than reverting, so the
|
|
@@ -148,12 +147,14 @@ export async function getFPool(c: LogswapClient, poolId: Hex): Promise<FPoolStat
|
|
|
148
147
|
|
|
149
148
|
const n = Number(p.n);
|
|
150
149
|
const idx = Array.from({ length: n }, (_, i) => BigInt(i));
|
|
151
|
-
const [theta, compositeX, legs] = await Promise.all([
|
|
150
|
+
const [theta, compositeX, legs, kind, name] = await Promise.all([
|
|
152
151
|
// before the seed there is no L and no floor: θ is X by convention (the manager says so since
|
|
153
152
|
// bd3dd87's successor; older deployments revert with DivWadFailed, so do not ask them)
|
|
154
153
|
p.L > 0n ? rd<bigint>("theta", [poolId]) : rd<bigint>("compositeX", [poolId]),
|
|
155
154
|
rd<bigint>("compositeX", [poolId]),
|
|
156
155
|
Promise.all(idx.map((i) => rd<readonly [Address, bigint, bigint, bigint]>("legOf", [poolId, i]))),
|
|
156
|
+
fPoolKindOfPolicy(c, p.policy),
|
|
157
|
+
fPoolNameOf(c, poolId, p.policy),
|
|
157
158
|
]);
|
|
158
159
|
|
|
159
160
|
const bases = legs.map((l) => l[0]);
|
|
@@ -178,9 +179,9 @@ export async function getFPool(c: LogswapClient, poolId: Hex): Promise<FPoolStat
|
|
|
178
179
|
bigSigma,
|
|
179
180
|
policy,
|
|
180
181
|
asks: Number(p.asks),
|
|
181
|
-
name
|
|
182
|
+
name,
|
|
182
183
|
restructureBlock: Number(restructureBlock),
|
|
183
|
-
kind
|
|
184
|
+
kind,
|
|
184
185
|
seeded,
|
|
185
186
|
gen: Number(gen),
|
|
186
187
|
totalSupply,
|
|
@@ -189,26 +190,50 @@ export async function getFPool(c: LogswapClient, poolId: Hex): Promise<FPoolStat
|
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
/**
|
|
192
|
-
* The kind of pool
|
|
193
|
-
* the
|
|
194
|
-
* creator; no gate, no operator. `private`, the
|
|
195
|
-
* mints, with an operator that reshapes the legs
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
* open to all. private → pol → pad is the ladder
|
|
199
|
-
* protocol. Every rate, role and gate is the policy's.
|
|
193
|
+
* The kind of pool — the POLICY's self-description (decisions 049: the manager knows no kind; the
|
|
194
|
+
* policy the key names is the kind, and what it promises is its code). `public`: the protocol's
|
|
195
|
+
* own pool — its policy requires the collector as creator; no gate, no operator. `private`, the
|
|
196
|
+
* desk: the one whose policy may gate swaps and mints, with an operator that reshapes the legs
|
|
197
|
+
* between generations. `pol`, a treasury's pool, one base: composition and access fixed at
|
|
198
|
+
* birth. `pad`, a launch, one base: its policy answers income only at every harvest and declared
|
|
199
|
+
* its seed the pool's at birth (`SEED_TO_DEAD`) — open to all. private → pol → pad is the ladder
|
|
200
|
+
* of rigidity; public is a pol held by the protocol. Every rate, role and gate is the policy's.
|
|
200
201
|
*/
|
|
201
202
|
export type FPoolKind = "public" | "private" | "pol" | "pad";
|
|
202
|
-
/** The key's enum values. */
|
|
203
|
-
export const F_KIND = { public: 0, private: 1, pol: 2, pad: 3 } as const;
|
|
204
203
|
const F_KIND_NAMES: readonly FPoolKind[] = ["public", "private", "pol", "pad"];
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
204
|
+
/** The policy's birth-time declaration that the seed's shares are the pool's (a pad's), in `asks`. */
|
|
205
|
+
export const SEED_TO_DEAD = 4;
|
|
206
|
+
|
|
207
|
+
const kindCache = new Map<string, Promise<FPoolKind>>();
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* What a policy IS — its `kind()` tag, read once per policy address and cached for the client's
|
|
211
|
+
* chain: a pool's kind is its policy's word (decisions 049), never the manager's. An unknown tag
|
|
212
|
+
* (a policy that is not one of the protocol's four shapes) throws; the app has no screen for it.
|
|
213
|
+
*/
|
|
214
|
+
export function fPoolKindOfPolicy(c: LogswapClient, policy: Address): Promise<FPoolKind> {
|
|
215
|
+
const key = `${c.public.chain?.id ?? 0}:${policy.toLowerCase()}`;
|
|
216
|
+
let hit = kindCache.get(key);
|
|
217
|
+
if (!hit) {
|
|
218
|
+
hit = (c.public.readContract({ address: policy, abi: fPolicyBaseAbi, functionName: "kind" } as never) as Promise<Hex>).then((word) => {
|
|
219
|
+
const tag = bytes32ToText(word) as FPoolKind;
|
|
220
|
+
if (!F_KIND_NAMES.includes(tag)) throw new Error(`logswap: policy ${policy} says it is "${tag}", which is no kind this SDK knows`);
|
|
221
|
+
return tag;
|
|
222
|
+
});
|
|
223
|
+
kindCache.set(key, hit);
|
|
224
|
+
hit.catch(() => kindCache.delete(key)); // a failed read is not a fact
|
|
225
|
+
}
|
|
226
|
+
return hit;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** The pool's label, as its policy holds it (decisions 049). "" when unnamed. */
|
|
230
|
+
export async function fPoolNameOf(c: LogswapClient, poolId: Hex, policy?: Address): Promise<string> {
|
|
231
|
+
const p = policy ?? (await fPoolPolicyOf(c, poolId));
|
|
232
|
+
const word = (await c.public.readContract({ address: p, abi: fPolicyBaseAbi, functionName: "nameOf", args: [poolId] } as never)) as Hex;
|
|
233
|
+
return bytes32ToText(word);
|
|
209
234
|
}
|
|
210
235
|
|
|
211
|
-
/** The deployment's policy for a kind (decisions 044):
|
|
236
|
+
/** The deployment's policy for a kind (decisions 044, 049): the protocol's policy that IS that kind. */
|
|
212
237
|
export function fPoolPolicyFor(c: LogswapClient, kind: FPoolKind): Address {
|
|
213
238
|
const a = c.addresses;
|
|
214
239
|
const policy = kind === "public" ? a.publicPolicy : kind === "private" ? a.privatePolicy : kind === "pol" ? a.polPolicy : a.padPolicy;
|
|
@@ -811,8 +836,8 @@ export async function fPoolQuoteSwap(
|
|
|
811
836
|
): Promise<bigint> {
|
|
812
837
|
try {
|
|
813
838
|
await c.public.simulateContract({
|
|
814
|
-
address: c.addresses.
|
|
815
|
-
abi:
|
|
839
|
+
address: c.addresses.router,
|
|
840
|
+
abi: logswapRouterAbi,
|
|
816
841
|
functionName: "quoteSwap",
|
|
817
842
|
// the taker matters only on a gated pool: the connected account, or the zero address
|
|
818
843
|
args: [a.poolId, a.kind, BigInt(a.j), BigInt(a.k ?? 0), a.amountIn, a.taker ?? c.wallet?.account?.address ?? ZERO_ADDRESS],
|
|
@@ -866,12 +891,16 @@ export interface FPoolCreateArgs {
|
|
|
866
891
|
weights: bigint[];
|
|
867
892
|
/** Fixed fee, WAD. The base-for-base fee is pinned at 2φ on-chain. */
|
|
868
893
|
phi: bigint;
|
|
869
|
-
/**
|
|
894
|
+
/**
|
|
895
|
+
* Which of the protocol's four the pool is — see {@link FPoolKind}. NOT a key field (decisions
|
|
896
|
+
* 049: the manager knows no kind): it selects the deployment's policy of that kind when `policy`
|
|
897
|
+
* is not named ({@link fPoolPolicyFor}), and it is what the policy will say it is.
|
|
898
|
+
*/
|
|
870
899
|
kind: FPoolKind;
|
|
871
900
|
/**
|
|
872
|
-
* The pool's policy (decisions 041, 044): the contract the key names, approved by the
|
|
873
|
-
*
|
|
874
|
-
* every protocol pool names.
|
|
901
|
+
* The pool's policy (decisions 041, 044, 049): the contract the key names, approved by the
|
|
902
|
+
* registry, and the pool's kind. Defaults to the deployment's policy for `kind`
|
|
903
|
+
* ({@link fPoolPolicyFor}) — the one every protocol pool names.
|
|
875
904
|
*/
|
|
876
905
|
policy?: Address;
|
|
877
906
|
/** Who is born holding the pool: immutable identity, the pool's first authority (the policy records it). */
|
|
@@ -880,7 +909,7 @@ export interface FPoolCreateArgs {
|
|
|
880
909
|
* The differentiator, and nothing else. Identity is the key's hash, so one sponsor cannot run
|
|
881
910
|
* two pools of the same shape without varying it — the second `initialize` would land on the
|
|
882
911
|
* first pool's id. Defaults to zero, which is the first book of any shape. A pool's NAME is not
|
|
883
|
-
* this: names are mutable state (`fPoolSetName`), so a rename forks nothing.
|
|
912
|
+
* this: names are the policy's mutable state (`fPoolSetName`), so a rename forks nothing.
|
|
884
913
|
*/
|
|
885
914
|
salt?: Hex;
|
|
886
915
|
account: Address;
|
|
@@ -909,7 +938,7 @@ export function sortFPoolLegs<T>(bases: Address[], ...companions: T[][]): { base
|
|
|
909
938
|
return { bases: idx.map((i) => bases[i]!), companions: companions.map((arr) => idx.map((i) => arr[i]!)) };
|
|
910
939
|
}
|
|
911
940
|
|
|
912
|
-
/** The key as the manager hashes it: legs sorted, the kind's policy filled in when none is named. */
|
|
941
|
+
/** The key as the manager hashes it: legs sorted, the kind's policy filled in when none is named; no kind in it (049). */
|
|
913
942
|
export function fPoolKeyOf(c: LogswapClient, a: Omit<FPoolCreateArgs, "account">) {
|
|
914
943
|
const { bases, companions } = sortFPoolLegs(a.bases, a.weights);
|
|
915
944
|
return {
|
|
@@ -917,7 +946,6 @@ export function fPoolKeyOf(c: LogswapClient, a: Omit<FPoolCreateArgs, "account">
|
|
|
917
946
|
bases,
|
|
918
947
|
weights: companions[0]!,
|
|
919
948
|
phi: a.phi,
|
|
920
|
-
kind: F_KIND[a.kind],
|
|
921
949
|
policy: a.policy ?? fPoolPolicyFor(c, a.kind),
|
|
922
950
|
creator: a.creator,
|
|
923
951
|
salt: a.salt ?? ZERO_SALT,
|
|
@@ -1092,7 +1120,7 @@ export interface FPoolLaunchArgs extends Omit<FPoolCreateArgs, "account"> {
|
|
|
1092
1120
|
* this buy — they are one transaction — so `minOut` is safe at its default of 0.
|
|
1093
1121
|
*/
|
|
1094
1122
|
openBuy?: { j: number; amountIn: bigint; minOut?: bigint };
|
|
1095
|
-
/** The pool's label
|
|
1123
|
+
/** The pool's label (≤ 31 bytes of UTF-8) — the policy's word (049), written right after the batch by {@link fPoolLaunch}; not in the batch. */
|
|
1096
1124
|
name?: string;
|
|
1097
1125
|
/**
|
|
1098
1126
|
* The pool already exists (a previous launch got as far as `initialize` and no further — a seed
|
|
@@ -1121,7 +1149,7 @@ export function fPoolLaunchCalls(
|
|
|
1121
1149
|
if (given.length !== a.bases.length) throw new Error(`logswap: ${given.length} reserves for ${a.bases.length} legs`);
|
|
1122
1150
|
const { bases, companions } = sortFPoolLegs(a.bases, a.weights, given);
|
|
1123
1151
|
if (!a.policy) throw new Error("logswap: fPoolLaunchCalls needs the key's policy — fPoolLaunch fills it from the deployment");
|
|
1124
|
-
const key = { quote: a.quote, bases, weights: companions[0]!, phi: a.phi,
|
|
1152
|
+
const key = { quote: a.quote, bases, weights: companions[0]!, phi: a.phi, policy: a.policy, creator: a.creator, salt: a.salt ?? ZERO_SALT };
|
|
1125
1153
|
const enc = (functionName: string, args: unknown[]) =>
|
|
1126
1154
|
encodeFunctionData({ abi: fPoolManagerAbi, functionName, args } as never) as Hex;
|
|
1127
1155
|
const calls: Hex[] = [];
|
|
@@ -1134,9 +1162,9 @@ export function fPoolLaunchCalls(
|
|
|
1134
1162
|
if (j < 0) throw new Error(`logswap: openBuy.j = ${a.openBuy.j} is not a leg`);
|
|
1135
1163
|
calls.push(enc("swapQuoteIn", [poolId, BigInt(j), a.openBuy.amountIn, a.openBuy.minOut ?? 0n, a.account]));
|
|
1136
1164
|
}
|
|
1137
|
-
|
|
1138
|
-
//
|
|
1139
|
-
//
|
|
1165
|
+
// the name, the desk's gates and its list are the POLICY's (decisions 044, 049), not the
|
|
1166
|
+
// manager's: they cannot ride in this batch — `fPoolLaunch` and `fPoolDeskOpening` send them
|
|
1167
|
+
// right after, as the same creator
|
|
1140
1168
|
calls.push(...(a.extra ?? []));
|
|
1141
1169
|
return calls;
|
|
1142
1170
|
}
|
|
@@ -1176,8 +1204,10 @@ export async function fPoolLaunch(
|
|
|
1176
1204
|
a: FPoolLaunchArgs & ({ r0: bigint[] } | { x0: bigint[] }),
|
|
1177
1205
|
): Promise<{ hash: Hash; poolId: Hex }> {
|
|
1178
1206
|
const poolId = await fPoolIdOf(c, a);
|
|
1179
|
-
const
|
|
1207
|
+
const policy = a.policy ?? fPoolPolicyFor(c, a.kind);
|
|
1208
|
+
const calls = fPoolLaunchCalls(poolId, { ...a, policy });
|
|
1180
1209
|
const hash = await writeFPool0(c, "multicall", [calls], a.account);
|
|
1210
|
+
if (a.name) await fPoolSetName(c, { poolId, name: a.name, account: a.account, policy });
|
|
1181
1211
|
return { hash, poolId };
|
|
1182
1212
|
}
|
|
1183
1213
|
|
|
@@ -1269,20 +1299,22 @@ export async function fPoolIsAllowed(c: LogswapClient, poolId: Hex, who: Address
|
|
|
1269
1299
|
return readDesk<boolean>(c, poolId, who, "isAllowed", policy);
|
|
1270
1300
|
}
|
|
1271
1301
|
|
|
1272
|
-
/** Label the pool — the
|
|
1273
|
-
export async function fPoolSetName(c: LogswapClient, a: { poolId: Hex; name: string; account: Address }) {
|
|
1274
|
-
return
|
|
1302
|
+
/** Label the pool — the authority's own words on the pool's POLICY (decisions 049), mutable, never identity. At most 31 bytes of UTF-8. */
|
|
1303
|
+
export async function fPoolSetName(c: LogswapClient, a: { poolId: Hex; name: string; account: Address; policy?: Address }) {
|
|
1304
|
+
return writePolicy(c, fPolicyBaseAbi, a, "setName", [textToBytes32(a.name)]);
|
|
1275
1305
|
}
|
|
1276
1306
|
|
|
1277
1307
|
/**
|
|
1278
|
-
* What the PROTOCOL says an address is — "Keyrock"
|
|
1279
|
-
* what makes it an attestation rather than a
|
|
1308
|
+
* What the PROTOCOL says an address is — "Keyrock" — on the REGISTRY (decisions 049). Only its
|
|
1309
|
+
* owner, the LOG authority, may write it, which is what makes it an attestation rather than a
|
|
1310
|
+
* claim anyone could make about themselves.
|
|
1280
1311
|
*/
|
|
1281
1312
|
export async function fPoolSetSponsorName(c: LogswapClient, a: { who: Address; name: string; account: Address }) {
|
|
1282
1313
|
const wallet = requireWallet(c);
|
|
1314
|
+
const registry = await registryAddress(c);
|
|
1283
1315
|
const { request } = await c.public.simulateContract({
|
|
1284
|
-
address:
|
|
1285
|
-
abi:
|
|
1316
|
+
address: registry,
|
|
1317
|
+
abi: policyRegistryAbi,
|
|
1286
1318
|
functionName: "setSponsorName",
|
|
1287
1319
|
args: [a.who, textToBytes32(a.name)],
|
|
1288
1320
|
account: a.account,
|
|
@@ -1290,17 +1322,26 @@ export async function fPoolSetSponsorName(c: LogswapClient, a: { who: Address; n
|
|
|
1290
1322
|
return wallet.writeContract(request as never);
|
|
1291
1323
|
}
|
|
1292
1324
|
|
|
1293
|
-
/** The protocol's attestation for an address, or "" when unattested — which most addresses are. */
|
|
1325
|
+
/** The protocol's attestation for an address, or "" when unattested — which most addresses are, and every address on a deployment with no registry. */
|
|
1294
1326
|
export async function fPoolSponsorName(c: LogswapClient, who: Address): Promise<string> {
|
|
1295
|
-
const
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
functionName: "sponsorName",
|
|
1299
|
-
args: [who],
|
|
1300
|
-
} as never)) as Hex;
|
|
1327
|
+
const registry = c.addresses.policyRegistry ?? (await fPoolRegistryOf(c));
|
|
1328
|
+
if (registry === ZERO_ADDRESS) return "";
|
|
1329
|
+
const word = (await c.public.readContract({ address: registry, abi: policyRegistryAbi, functionName: "sponsorName", args: [who] } as never)) as Hex;
|
|
1301
1330
|
return bytes32ToText(word);
|
|
1302
1331
|
}
|
|
1303
1332
|
|
|
1333
|
+
/** The registry the manager asks at every birth — `addresses.policyRegistry`, else the manager's word; zero on a bare deployment. */
|
|
1334
|
+
export async function fPoolRegistryOf(c: LogswapClient): Promise<Address> {
|
|
1335
|
+
if (c.addresses.policyRegistry) return c.addresses.policyRegistry;
|
|
1336
|
+
return (await c.public.readContract({ address: c.addresses.fPoolManager!, abi: fPoolManagerAbi, functionName: "registry" } as never)) as Address;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
async function registryAddress(c: LogswapClient): Promise<Address> {
|
|
1340
|
+
const registry = await fPoolRegistryOf(c);
|
|
1341
|
+
if (registry === ZERO_ADDRESS) throw new Error("logswap: this deployment carries no policy registry");
|
|
1342
|
+
return registry;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1304
1345
|
/** Who runs the pool (decisions 037): the appointed operator, or the authority until one is. */
|
|
1305
1346
|
export function fPoolOperatorOf(s: Pick<FPoolRoles, "authority" | "operator">): Address {
|
|
1306
1347
|
return s.operator === ZERO_ADDRESS ? s.authority : s.operator;
|
|
@@ -1385,9 +1426,10 @@ export interface DiscoveredFPool {
|
|
|
1385
1426
|
}
|
|
1386
1427
|
|
|
1387
1428
|
/**
|
|
1388
|
-
* Every F pool ever created, from `Initialize` logs alone
|
|
1389
|
-
* carries the full key preimage (bases,
|
|
1390
|
-
* never be inverted; contracts PR #17
|
|
1429
|
+
* Every F pool ever created, from `Initialize` logs alone — plus one `kind()` read per distinct
|
|
1430
|
+
* policy, cached. Possible only because the event carries the full key preimage (bases,
|
|
1431
|
+
* weights, phi, policy) — the poolId is a hash and could never be inverted; contracts PR #17
|
|
1432
|
+
* exists for exactly this call.
|
|
1391
1433
|
*/
|
|
1392
1434
|
export async function discoverFPools(
|
|
1393
1435
|
c: LogswapClient,
|
|
@@ -1414,27 +1456,30 @@ export async function discoverFPools(
|
|
|
1414
1456
|
const a = l.args as { poolId: Hex; Q0: bigint };
|
|
1415
1457
|
q0Of.set(a.poolId.toLowerCase(), a.Q0);
|
|
1416
1458
|
}
|
|
1417
|
-
return
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1459
|
+
return Promise.all(
|
|
1460
|
+
logs.map(async (l) => {
|
|
1461
|
+
const a = l.args as {
|
|
1462
|
+
poolId: Hex; quote: Address; creator: Address; bases: readonly Address[];
|
|
1463
|
+
weights: readonly bigint[]; phi: bigint; policy: Address;
|
|
1464
|
+
};
|
|
1465
|
+
const q0 = q0Of.get(a.poolId.toLowerCase());
|
|
1466
|
+
const kind = await fPoolKindOfPolicy(c, a.policy); // one read per distinct policy, cached
|
|
1467
|
+
return {
|
|
1468
|
+
poolId: a.poolId,
|
|
1469
|
+
quote: a.quote,
|
|
1470
|
+
bases: [...a.bases],
|
|
1471
|
+
weights: [...a.weights],
|
|
1472
|
+
phi: a.phi,
|
|
1473
|
+
kind,
|
|
1474
|
+
policy: a.policy,
|
|
1475
|
+
creator: a.creator,
|
|
1476
|
+
block: l.blockNumber ?? 0n,
|
|
1477
|
+
seeded: q0 !== undefined,
|
|
1478
|
+
q0: q0 ?? 0n,
|
|
1479
|
+
shape: kind === "pad" ? "launch" : "basket", // the policy's word, not n = 1: a mono POL is a pool (decisions 036, 049)
|
|
1480
|
+
};
|
|
1481
|
+
}),
|
|
1482
|
+
);
|
|
1438
1483
|
}
|
|
1439
1484
|
|
|
1440
1485
|
// ─── the policy page: what an authority controls (decisions 044) ────────────────────────
|