@logswap/sdk 0.5.64 → 0.5.66
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 +26 -8
- package/dist/admin.js +27 -7
- package/dist/client.d.ts +1 -1
- package/dist/client.js +13 -1
- package/dist/fpool.d.ts +104 -23
- package/dist/fpool.js +97 -28
- package/dist/generated.d.ts +172 -112
- package/dist/generated.js +85 -61
- package/dist/keys.d.ts +10 -1
- package/dist/keys.js +9 -0
- package/package.json +1 -1
- package/src/admin.ts +31 -8
- package/src/client.ts +13 -1
- package/src/fpool.ts +160 -35
- package/src/generated.ts +85 -61
- package/src/keys.ts +11 -1
package/dist/keys.d.ts
CHANGED
|
@@ -11,6 +11,15 @@
|
|
|
11
11
|
* if the two ever disagree, that test fails rather than the SDK silently addressing the wrong pool.
|
|
12
12
|
*/
|
|
13
13
|
import { type Address, type Hex } from "viem";
|
|
14
|
+
/**
|
|
15
|
+
* The fee domain of the family, `FeeParams.FEE_MIN` / `FEE_MAX` (decisions 043): one bound for a
|
|
16
|
+
* C market's φ and an F pool's alike, WAD. 1 bp and 1%. The F manager no longer answers
|
|
17
|
+
* `FEE_MIN()` / `FEE_MAX()` (F version 21 cut the getters for bytecode); every F policy still
|
|
18
|
+
* checks φ against these at `onInitialize`, and the C side re-exposes them through the lens's
|
|
19
|
+
* `cParams()`. Constants here, so a create form bounds φ with no read.
|
|
20
|
+
*/
|
|
21
|
+
export declare const FEE_MIN: bigint;
|
|
22
|
+
export declare const FEE_MAX: bigint;
|
|
14
23
|
/**
|
|
15
24
|
* The economic tuple that IS the market. Field order is load-bearing: it is the ABI encoding order,
|
|
16
25
|
* so it must match `src/types/PoolKey.sol` exactly.
|
|
@@ -21,7 +30,7 @@ export interface PoolKey {
|
|
|
21
30
|
/** Log-tick spacing, WAD. The LP-boundary ladder — position floors and caps. */
|
|
22
31
|
tickSpacing: bigint;
|
|
23
32
|
/**
|
|
24
|
-
* The swap fee, WAD, fixed for the life of the market:
|
|
33
|
+
* The swap fee, WAD, fixed for the life of the market: {@link FEE_MIN} (1 bp) ≤ φ ≤ {@link FEE_MAX} (1%),
|
|
25
34
|
* or `0n`, which selects `DEFAULT_FEE` (2 bp) at read time. Four fields since C version 4
|
|
26
35
|
*: `kappa` and `alpha` left with the variance kernel, and `phiMin` — a floor with
|
|
27
36
|
* nothing above it — became `phi`. Every pool id changed with the shape.
|
package/dist/keys.js
CHANGED
|
@@ -11,6 +11,15 @@
|
|
|
11
11
|
* if the two ever disagree, that test fails rather than the SDK silently addressing the wrong pool.
|
|
12
12
|
*/
|
|
13
13
|
import { encodeAbiParameters, keccak256 } from "viem";
|
|
14
|
+
/**
|
|
15
|
+
* The fee domain of the family, `FeeParams.FEE_MIN` / `FEE_MAX` (decisions 043): one bound for a
|
|
16
|
+
* C market's φ and an F pool's alike, WAD. 1 bp and 1%. The F manager no longer answers
|
|
17
|
+
* `FEE_MIN()` / `FEE_MAX()` (F version 21 cut the getters for bytecode); every F policy still
|
|
18
|
+
* checks φ against these at `onInitialize`, and the C side re-exposes them through the lens's
|
|
19
|
+
* `cParams()`. Constants here, so a create form bounds φ with no read.
|
|
20
|
+
*/
|
|
21
|
+
export const FEE_MIN = 10n ** 14n;
|
|
22
|
+
export const FEE_MAX = 10n ** 16n;
|
|
14
23
|
const POOL_KEY_ABI = [
|
|
15
24
|
{
|
|
16
25
|
type: "tuple",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logswap/sdk",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.66",
|
|
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
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import type { Address, Hash } from "viem";
|
|
15
15
|
import type { LogswapClient } from "./client.js";
|
|
16
16
|
import { cPoolManagerAbi, fPoolManagerAbi, padPolicyAbi, polPolicyAbi, policyRegistryAbi, publicPolicyAbi } from "./generated.js";
|
|
17
|
-
import { bytes32ToText, fPolicyBaseAbi, fPoolKindOfPolicy, textToBytes32, type FPoolKind } from "./fpool.js";
|
|
17
|
+
import { bytes32ToText, fPolicyBaseAbi, fPoolKeyOfPool, fPoolKindOfPolicy, textToBytes32, type FPoolKey, type FPoolKind } from "./fpool.js";
|
|
18
18
|
|
|
19
19
|
function wallet(c: LogswapClient) {
|
|
20
20
|
if (!c.wallet) throw new Error("a wallet client is required");
|
|
@@ -138,13 +138,36 @@ 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: the registry
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
141
|
+
* Move a pool to another approved policy of the same kind: the registry owner's alone,
|
|
142
|
+
* orchestrated on the registry — `migrate(manager, key, to)` since F version 20 (it took the
|
|
143
|
+
* pool's id before). The registry checks the key against the manager (`NoPool`), checks the
|
|
144
|
+
* manager is its own (`WrongManager`), and compares the two policies' tags recorded at approval
|
|
145
|
+
* ({@link registryKindOf}). The new policy is brought the creator (the key's), the authority and
|
|
146
|
+
* the name (read off the old policy defensively, the key's creator standing in when it cannot
|
|
147
|
+
* answer); the operator and the lists void; no swap lands in the block.
|
|
148
|
+
*
|
|
149
|
+
* Pass the pool's `key` when in hand. Given only `poolId`, the key is rebuilt from the pool's
|
|
150
|
+
* `FInitialize` log ({@link fPoolKeyOfPool}) with `salt` (zero by default) and checked against
|
|
151
|
+
* the id — the log does not carry the salt, so a salted pool needs it named.
|
|
152
|
+
*/
|
|
153
|
+
export async function fPoolMigrate(
|
|
154
|
+
c: LogswapClient,
|
|
155
|
+
a: { to: Address } & ({ key: FPoolKey } | { poolId: `0x${string}`; salt?: `0x${string}`; fromBlock?: bigint }),
|
|
156
|
+
): Promise<Hash> {
|
|
157
|
+
const key = "key" in a ? a.key : await fPoolKeyOfPool(c, a.poolId, { salt: a.salt, fromBlock: a.fromBlock });
|
|
158
|
+
return registryWrite(c, "migrate", [c.addresses.fPoolManager as Address, key, a.to]);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* The kind tag the registry recorded for `policy` at approval (`kindOf`, F version 20) — refreshed
|
|
163
|
+
* on re-approval and kept after a revoke; what `migrate` compares, never the policy's live
|
|
164
|
+
* answer. "" for a policy the registry never approved (or a deployment with no registry).
|
|
145
165
|
*/
|
|
146
|
-
export async function
|
|
147
|
-
|
|
166
|
+
export async function registryKindOf(c: LogswapClient, policy: Address): Promise<FPoolKind | ""> {
|
|
167
|
+
const registry = await policyRegistryOf(c);
|
|
168
|
+
if (registry === ZERO) return "";
|
|
169
|
+
const word = (await c.public.readContract({ address: registry, abi: policyRegistryAbi, functionName: "kindOf", args: [policy] } as never)) as `0x${string}`;
|
|
170
|
+
return bytes32ToText(word) as FPoolKind | "";
|
|
148
171
|
}
|
|
149
172
|
|
|
150
173
|
// ─── the policies' numbers (the collector's; each bounded where it reaches the manager) ─────
|
|
@@ -154,7 +177,7 @@ export async function setHarvestCut(c: LogswapClient, policy: Address, rateWad:
|
|
|
154
177
|
return write(c, policy, fPolicyBaseAbi, "setHarvestCut", [rateWad]);
|
|
155
178
|
}
|
|
156
179
|
|
|
157
|
-
/** `PadPolicy.setSchedule`: `T(0)`, the rung's growth, the creator's and the protocol's shares of the pot (≤ `POT_CUT_MAX`), the burn per rung (≤ `BURN_MAX`). */
|
|
180
|
+
/** `PadPolicy.setSchedule`: `T(0)`, the rung's growth, the creator's and the protocol's shares of the pot (≤ `POT_CUT_MAX`), the burn per rung (≤ `BURN_MAX`). The rung is the pool's generation since F version 21. */
|
|
158
181
|
export async function padSetSchedule(
|
|
159
182
|
c: LogswapClient,
|
|
160
183
|
policy: Address,
|
package/src/client.ts
CHANGED
|
@@ -165,7 +165,19 @@ export const EXPECTED_VERSION = 5n;
|
|
|
165
165
|
// is the policy at birth, `migrate` moves a pool for the registry's owner; `stamp` / `setAsks` are
|
|
166
166
|
// the policy's; the desk's `setAllowed` / `isAllowed` are `setMinters` / `setTakers` / `isMinter` /
|
|
167
167
|
// `isTaker`; a pad and a POL hold one base (`OneBase`).
|
|
168
|
-
|
|
168
|
+
// 18–19: no role, no kind and no name on the manager (049); the events carry what a reader needs (050).
|
|
169
|
+
// 20 (2026-09-25, logswap-contract #53): policy isolation — `PolicyRegistry.migrate(manager, key, to)`
|
|
170
|
+
// takes the pool's KEY (was its id), `kindOf(policy)` is the tag recorded at approval, the
|
|
171
|
+
// registry emits `Migrated`; `IFPolicy.onMigrate` is brought the creator, authority and name;
|
|
172
|
+
// the desk's lists are keyed by `listEpoch`. The manager's ABI did not move.
|
|
173
|
+
// 21 (2026-09-26, #54): `regenerate` is the generation step — the policy's `Terms` name a
|
|
174
|
+
// `carried` holder (a fifth word, 160 B), every other holder is frozen out pro rata into
|
|
175
|
+
// generation g's bundle and redeems it (`fPoolRedeem` / `fPoolRollIn` with gen = g), and the
|
|
176
|
+
// pool goes on as g + 1. The manager lost `FEE_MIN` / `FEE_MAX` (see keys.ts), `harvestable`
|
|
177
|
+
// (the bid: `getPool().Q` when L > 0), `idOf(FPoolKey)` (hashed locally, `fPoolIdOfKey`) and
|
|
178
|
+
// `reserveOf` (`legOf`'s fourth word). `PadPolicy.rung` is gone: the pad's rung is `gen`, the
|
|
179
|
+
// next threshold `threshold(gen)`. A pad never retires; a public pool refuses `regenerate`.
|
|
180
|
+
export const EXPECTED_F_VERSION = 21n;
|
|
169
181
|
|
|
170
182
|
export async function assertVersion(c: LogswapClient, expected = EXPECTED_VERSION): Promise<void> {
|
|
171
183
|
const { cPoolManagerAbi, fPoolManagerAbi } = await import("./generated.js");
|
package/src/fpool.ts
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* `addresses.router`.
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
|
-
import { encodeFunctionData, toFunctionSelector, type Address, type Hash, type Hex } from "viem";
|
|
33
|
+
import { encodeAbiParameters, encodeFunctionData, keccak256, toFunctionSelector, type Address, type Hash, type Hex } from "viem";
|
|
34
34
|
import { fPoolManagerAbi, logswapRouterAbi, padPolicyAbi, polPolicyAbi, policyRegistryAbi, privatePolicyAbi, publicPolicyAbi } from "./generated.js";
|
|
35
35
|
|
|
36
36
|
/**
|
|
@@ -99,9 +99,12 @@ export interface FPoolState {
|
|
|
99
99
|
/** False before the first seed — and between a retire and the next one. */
|
|
100
100
|
seeded: boolean;
|
|
101
101
|
/**
|
|
102
|
-
* The live GENERATION. Every retire freezes one into a bundle its shares
|
|
103
|
-
*
|
|
104
|
-
* ({@link
|
|
102
|
+
* The live GENERATION. Every retire freezes one into a bundle its shares redeem
|
|
103
|
+
* ({@link fPoolRedeem}) and opens the next; since F version 21 so does every `regenerate`
|
|
104
|
+
* (the generation step, {@link fPoolRegenerate}): the carried holder and the dead shares go on
|
|
105
|
+
* as `gen + 1`, every other holder of `gen` is frozen out into its bundle. The share id carries
|
|
106
|
+
* it ({@link fPoolShareId}), so generations `0 … gen-1` are claims ({@link fPoolClaimsOf}) and
|
|
107
|
+
* `gen` is the pool. On a pad, `gen` is the graduation count — the rung.
|
|
105
108
|
*/
|
|
106
109
|
gen: number;
|
|
107
110
|
totalSupply: bigint;
|
|
@@ -272,7 +275,7 @@ export interface FPoolRoles {
|
|
|
272
275
|
pendingOperator: Address;
|
|
273
276
|
gateMint: boolean;
|
|
274
277
|
gateSwap: boolean;
|
|
275
|
-
/** The policy's own ceiling on a harvest now — the
|
|
278
|
+
/** The policy's own ceiling on a harvest now — the bid ({@link FPoolDescription.harvestable}) narrowed by the policy's rule. */
|
|
276
279
|
maxHarvest: bigint;
|
|
277
280
|
}
|
|
278
281
|
|
|
@@ -314,7 +317,12 @@ export interface FPoolDescription {
|
|
|
314
317
|
* from the first wei after it.
|
|
315
318
|
*/
|
|
316
319
|
unharvested: bigint;
|
|
317
|
-
/**
|
|
320
|
+
/**
|
|
321
|
+
* The most a harvest may take now by the MANAGER's rule: the bid, `Q` once seeded (0 before).
|
|
322
|
+
* The manager's `harvestable()` getter was cut in F version 21; this is the same number, read
|
|
323
|
+
* off `getPool`. The policy may allow less (a pad: the income; a POL: above `keepQuote`) —
|
|
324
|
+
* {@link FPoolRoles.maxHarvest}.
|
|
325
|
+
*/
|
|
318
326
|
harvestable: bigint;
|
|
319
327
|
/** The dead shares' banked dividend — a pad's pot, the creator's income until a rung is climbed. */
|
|
320
328
|
pot: bigint;
|
|
@@ -328,10 +336,12 @@ export async function describeFPool(c: LogswapClient, s: FPoolState): Promise<FP
|
|
|
328
336
|
functionName,
|
|
329
337
|
args,
|
|
330
338
|
} as never) as Promise<T>;
|
|
331
|
-
// an unseeded pool has no L: nothing earned, nothing to harvest, no pot
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
339
|
+
// an unseeded pool has no L: nothing earned, nothing to harvest, no pot. The bid is the
|
|
340
|
+
// manager's ceiling (`harvestable()` until F version 21, which cut the getter): Q once seeded.
|
|
341
|
+
const harvestable = s.L > 0n ? s.Q : 0n;
|
|
342
|
+
const [unharvested, pot] = s.L > 0n
|
|
343
|
+
? await Promise.all([rd<bigint>("unharvested"), rd<bigint>("dividendOf", [s.poolId, BigInt(s.gen), DEAD_ADDRESS])])
|
|
344
|
+
: [0n, 0n];
|
|
335
345
|
return {
|
|
336
346
|
shape: s.kind === "pad" ? "launch": "basket", // the kind, not n = 1
|
|
337
347
|
legs: s.bases.length,
|
|
@@ -985,7 +995,50 @@ export function sortFPoolLegs<T>(bases: Address[], ...companions: T[][]): { base
|
|
|
985
995
|
}
|
|
986
996
|
|
|
987
997
|
/** The key as the manager hashes it: legs sorted, the kind's policy filled in when none is named; no kind in it (049). */
|
|
988
|
-
|
|
998
|
+
/**
|
|
999
|
+
* The tuple an F pool's id hashes — `src/types/FPoolKey.sol`, field order load-bearing (it is
|
|
1000
|
+
* the ABI encoding order). Stored by the manager at `initialize` and never in calldata again,
|
|
1001
|
+
* except `PolicyRegistry.migrate` (F version 20), which is handed it to check against the id.
|
|
1002
|
+
*/
|
|
1003
|
+
export interface FPoolKey {
|
|
1004
|
+
quote: Address;
|
|
1005
|
+
/** Sorted ascending, unique. */
|
|
1006
|
+
bases: Address[];
|
|
1007
|
+
/** WAD, aligned with `bases`, summing to 1e18. */
|
|
1008
|
+
weights: bigint[];
|
|
1009
|
+
phi: bigint;
|
|
1010
|
+
/** The policy AT BIRTH — not the live one after a move. */
|
|
1011
|
+
policy: Address;
|
|
1012
|
+
creator: Address;
|
|
1013
|
+
salt: Hex;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
const F_POOL_KEY_ABI = [
|
|
1017
|
+
{
|
|
1018
|
+
type: "tuple",
|
|
1019
|
+
components: [
|
|
1020
|
+
{ name: "quote", type: "address" },
|
|
1021
|
+
{ name: "bases", type: "address[]" },
|
|
1022
|
+
{ name: "weights", type: "uint256[]" },
|
|
1023
|
+
{ name: "phi", type: "uint256" },
|
|
1024
|
+
{ name: "policy", type: "address" },
|
|
1025
|
+
{ name: "creator", type: "address" },
|
|
1026
|
+
{ name: "salt", type: "bytes32" },
|
|
1027
|
+
],
|
|
1028
|
+
},
|
|
1029
|
+
] as const;
|
|
1030
|
+
|
|
1031
|
+
/**
|
|
1032
|
+
* An F pool's id: `keccak256(abi.encode(key))`, offline — what `initialize` computes inline. The
|
|
1033
|
+
* manager's `idOf(FPoolKey)` getter was cut in F version 21; this is the same hash (checked
|
|
1034
|
+
* against Foundry's encoder and the local deployment's pools in the tests). The key must be the
|
|
1035
|
+
* one the pool was initialized with: legs sorted ({@link fPoolKeyOf} sorts them), the birth policy.
|
|
1036
|
+
*/
|
|
1037
|
+
export function fPoolIdOfKey(key: FPoolKey): Hex {
|
|
1038
|
+
return keccak256(encodeAbiParameters(F_POOL_KEY_ABI, [key]));
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
export function fPoolKeyOf(c: LogswapClient, a: Omit<FPoolCreateArgs, "account">): FPoolKey {
|
|
989
1042
|
const { bases, companions } = sortFPoolLegs(a.bases, a.weights);
|
|
990
1043
|
return {
|
|
991
1044
|
quote: a.quote,
|
|
@@ -1014,15 +1067,47 @@ export async function fPoolInitialize(c: LogswapClient, a: FPoolCreateArgs) {
|
|
|
1014
1067
|
return c.wallet!.writeContract(request as never);
|
|
1015
1068
|
}
|
|
1016
1069
|
|
|
1017
|
-
/**
|
|
1070
|
+
/**
|
|
1071
|
+
* The pool id is the key's hash — pure, so it can be read before or after creation. Computed
|
|
1072
|
+
* locally since F version 21 ({@link fPoolIdOfKey}; the manager's `idOf` is gone): no RPC. Still
|
|
1073
|
+
* async, so callers written against the read keep working.
|
|
1074
|
+
*/
|
|
1018
1075
|
export async function fPoolIdOf(c: LogswapClient, a: Omit<FPoolCreateArgs, "account">): Promise<Hex> {
|
|
1019
|
-
|
|
1020
|
-
|
|
1076
|
+
return fPoolIdOfKey(fPoolKeyOf(c, a));
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/**
|
|
1080
|
+
* Rebuild a live pool's KEY from its id: the `FInitialize` log carries every field but the salt,
|
|
1081
|
+
* which is taken from `opts.salt` (zero by default — every pool the SDK's create flow makes
|
|
1082
|
+
* without naming one). The result is checked against the id, so a wrong salt throws rather than
|
|
1083
|
+
* returning a key that names another pool. What {@link fPoolMigrate} needs when handed an id.
|
|
1084
|
+
*/
|
|
1085
|
+
export async function fPoolKeyOfPool(c: LogswapClient, poolId: Hex, opts: { salt?: Hex; fromBlock?: bigint } = {}): Promise<FPoolKey> {
|
|
1086
|
+
type Ev = Extract<(typeof fPoolManagerAbi)[number], { type: "event"; name: "FInitialize" }>;
|
|
1087
|
+
const ev = fPoolManagerAbi.find((x): x is Ev => x.type === "event" && x.name === "FInitialize")!;
|
|
1088
|
+
const logs = await c.public.getLogs({
|
|
1021
1089
|
address: c.addresses.fPoolManager!,
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1090
|
+
event: ev,
|
|
1091
|
+
args: { poolId },
|
|
1092
|
+
fromBlock: opts.fromBlock ?? 0n,
|
|
1093
|
+
toBlock: "latest",
|
|
1094
|
+
});
|
|
1095
|
+
const l = logs[0];
|
|
1096
|
+
if (!l) throw new Error(`logswap: no FInitialize for F pool ${poolId}`);
|
|
1097
|
+
const a = l.args as { quote: Address; creator: Address; bases: readonly Address[]; weights: readonly bigint[]; phi: bigint; policy: Address };
|
|
1098
|
+
const key: FPoolKey = {
|
|
1099
|
+
quote: a.quote,
|
|
1100
|
+
bases: [...a.bases],
|
|
1101
|
+
weights: [...a.weights],
|
|
1102
|
+
phi: a.phi,
|
|
1103
|
+
policy: a.policy,
|
|
1104
|
+
creator: a.creator,
|
|
1105
|
+
salt: opts.salt ?? ZERO_SALT,
|
|
1106
|
+
};
|
|
1107
|
+
if (fPoolIdOfKey(key).toLowerCase() !== poolId.toLowerCase()) {
|
|
1108
|
+
throw new Error(`logswap: F pool ${poolId} was not born with salt ${key.salt} — pass its salt, or its whole key`);
|
|
1109
|
+
}
|
|
1110
|
+
return key;
|
|
1026
1111
|
}
|
|
1027
1112
|
|
|
1028
1113
|
/**
|
|
@@ -1068,7 +1153,7 @@ export async function fPoolRetireRaw(c: LogswapClient, a: { poolId: Hex; account
|
|
|
1068
1153
|
* Retire the live generation as ONE transaction: the harvest that empties the bid
|
|
1069
1154
|
* ({@link fPoolEmptyingHarvests} — a dividend to every share; none when it is already empty),
|
|
1070
1155
|
* then `retire` — the manager's `multicall`, the operator as sender. What a sponsor's
|
|
1071
|
-
* "retire" button should call. Throws before sending on a pad
|
|
1156
|
+
* "retire" button should call. Throws before sending on a pad: a pad never retires (F version 21).
|
|
1072
1157
|
*/
|
|
1073
1158
|
export async function fPoolRetire(c: LogswapClient, a: { poolId: Hex; account: Address }) {
|
|
1074
1159
|
const harvests = await fPoolEmptyingHarvests(c, a.poolId);
|
|
@@ -1083,26 +1168,39 @@ export async function fPoolRetire(c: LogswapClient, a: { poolId: Hex; account: A
|
|
|
1083
1168
|
* The harvests that empty an unlocked pool's bid, in order — what a relaunch sends before its
|
|
1084
1169
|
* `retire` (a retire needs an empty bid on every pool). Since F version 14 one
|
|
1085
1170
|
* `harvest(Q)` does it: the protocol's cut leaves the pool with the amount (with no collector
|
|
1086
|
-
* there is no cut). `[]` when the bid is already empty. Throws on a pad
|
|
1087
|
-
*
|
|
1171
|
+
* there is no cut). `[]` when the bid is already empty. Throws on a pad (F version 21: a pad
|
|
1172
|
+
* never retires, whatever its bid), and when the pool's policy keeps a floor on the bid
|
|
1088
1173
|
* (`PolPolicy.keepQuote`): a `retire` under that policy waits for the market.
|
|
1089
1174
|
*/
|
|
1090
1175
|
export async function fPoolEmptyingHarvests(c: LogswapClient, poolId: Hex): Promise<bigint[]> {
|
|
1091
1176
|
const s = await getFPool(c, poolId);
|
|
1177
|
+
// F version 21: `PadPolicy` refuses `retire` at any bid — a pad graduates (regenerate), it
|
|
1178
|
+
// never closes; a fresh start is a new pad with a new id
|
|
1179
|
+
if (s.kind === "pad") throw new Error("logswap: a pad never retires (F version 21) — it graduates by regenerate; a fresh start is a new pad");
|
|
1092
1180
|
if (s.Q === 0n) return [];
|
|
1093
|
-
if (s.kind === "pad") throw new Error("logswap: a pad is retired only once its bid is empty");
|
|
1094
1181
|
const { maxHarvest } = await getFPoolRoles(c, poolId, s);
|
|
1095
1182
|
if (maxHarvest < s.Q) throw new Error("logswap: the pool's policy keeps a floor on the bid — it cannot be harvested empty");
|
|
1096
1183
|
return [s.Q];
|
|
1097
1184
|
}
|
|
1098
1185
|
|
|
1099
1186
|
/**
|
|
1100
|
-
*
|
|
1101
|
-
*
|
|
1102
|
-
*
|
|
1103
|
-
*
|
|
1104
|
-
*
|
|
1105
|
-
*
|
|
1187
|
+
* The GENERATION STEP (F version 21) — on a pad, its graduation. The manager harvests the
|
|
1188
|
+
* generation's income first, releases the dead shares' pot, and asks the policy
|
|
1189
|
+
* (`onRegenerate`), whose {@link FPolicyTerms} name a `carried` holder. Then, for live
|
|
1190
|
+
* generation `g`:
|
|
1191
|
+
*
|
|
1192
|
+
* - the carried holder's and the dead shares' `g` shares are re-minted 1:1 as `g + 1`: they go on
|
|
1193
|
+
* as the pool;
|
|
1194
|
+
* - every OTHER holder of `g` is frozen out pro rata into generation `g`'s bundle (`Retired(g, …)`)
|
|
1195
|
+
* and redeems it with {@link fPoolRedeem} / rolls it with {@link fPoolRollIn} (`gen: g`); their
|
|
1196
|
+
* dividends on `g` stay claimable ({@link fPoolClaim} with `gen: g`). {@link fPoolClaimsOf}
|
|
1197
|
+
* lists them;
|
|
1198
|
+
* - the pot: `toPayee` to the payee, `protocolCut` to the collector, the rest bought in as dead
|
|
1199
|
+
* shares of `g + 1`; then the burn.
|
|
1200
|
+
*
|
|
1201
|
+
* A pad's gate is `threshold(gen)` (`PadPolicy.NotGraduated` below it); POL and private carry the
|
|
1202
|
+
* authority and send it the whole pot; a public pool refuses (`Refused`). A carried holder with no
|
|
1203
|
+
* share is `BadTerms`. Whoever runs the pool.
|
|
1106
1204
|
*/
|
|
1107
1205
|
export async function fPoolRegenerate(c: LogswapClient, a: { poolId: Hex; to?: Address; account: Address }) {
|
|
1108
1206
|
return writeFPool(c, a.poolId, "regenerate", [a.to ?? a.account], a.account);
|
|
@@ -1534,13 +1632,26 @@ export interface FPoolControlled {
|
|
|
1534
1632
|
pool: DiscoveredFPool;
|
|
1535
1633
|
roles: FPoolRoles;
|
|
1536
1634
|
state: FPoolState;
|
|
1537
|
-
/** The policy's numbers for this pool's kind — a pad's rung and threshold, a POL's floors, the desk's list flags. */
|
|
1635
|
+
/** The policy's numbers for this pool's kind — a pad's gen (its rung) and threshold, a POL's floors, the desk's list flags. */
|
|
1538
1636
|
rules: FPoolRules;
|
|
1539
1637
|
}
|
|
1540
1638
|
|
|
1541
1639
|
/** What a pool's policy says about it, by kind: the terms a buyer reads before entering. */
|
|
1542
1640
|
export type FPoolRules =
|
|
1543
|
-
| {
|
|
1641
|
+
| {
|
|
1642
|
+
kind: "pad";
|
|
1643
|
+
harvestCut: bigint;
|
|
1644
|
+
/** The pad's graduation count: the pool's generation (F version 21 — `PadPolicy.rung` is gone). */
|
|
1645
|
+
gen: number;
|
|
1646
|
+
/** @deprecated Equal to {@link gen} since F version 21, kept for callers; read `gen`. */
|
|
1647
|
+
rung: number;
|
|
1648
|
+
/** The pot the next graduation needs: `PadPolicy.threshold(gen)`. */
|
|
1649
|
+
threshold: bigint;
|
|
1650
|
+
pot: bigint;
|
|
1651
|
+
creatorShare: bigint;
|
|
1652
|
+
protocolShare: bigint;
|
|
1653
|
+
burnPerRung: bigint;
|
|
1654
|
+
}
|
|
1544
1655
|
| { kind: "pol"; harvestCut: bigint; keepQuote: bigint; minQuoteAtSeed: bigint }
|
|
1545
1656
|
| { kind: "public"; harvestCut: bigint; curated: boolean }
|
|
1546
1657
|
| { kind: "private"; harvestCut: bigint; gateMint: boolean; gateSwap: boolean; operator: Address };
|
|
@@ -1552,15 +1663,16 @@ export async function getFPoolRules(c: LogswapClient, s: Pick<FPoolState, "poolI
|
|
|
1552
1663
|
const harvestCut = await rd<bigint>(fPolicyBaseAbi, "harvestCut");
|
|
1553
1664
|
switch (s.kind) {
|
|
1554
1665
|
case "pad": {
|
|
1555
|
-
|
|
1556
|
-
|
|
1666
|
+
// the rung is the manager's generation (F version 21): a move carries it, nothing to ask the policy
|
|
1667
|
+
const gen = s.gen;
|
|
1668
|
+
const [creatorShare, protocolShare, burnPerRung, pot, threshold] = await Promise.all([
|
|
1557
1669
|
rd<bigint>(padPolicyAbi, "creatorShare"),
|
|
1558
1670
|
rd<bigint>(padPolicyAbi, "protocolShare"),
|
|
1559
1671
|
rd<bigint>(padPolicyAbi, "burnPerRung"),
|
|
1560
|
-
fPoolDividendOf(c, s.poolId, DEAD_ADDRESS,
|
|
1672
|
+
fPoolDividendOf(c, s.poolId, DEAD_ADDRESS, gen),
|
|
1673
|
+
rd<bigint>(padPolicyAbi, "threshold", [BigInt(gen)]),
|
|
1561
1674
|
]);
|
|
1562
|
-
|
|
1563
|
-
return { kind: "pad", harvestCut, rung: Number(rung), threshold, pot, creatorShare, protocolShare, burnPerRung };
|
|
1675
|
+
return { kind: "pad", harvestCut, gen, rung: gen, threshold, pot, creatorShare, protocolShare, burnPerRung };
|
|
1564
1676
|
}
|
|
1565
1677
|
case "pol": {
|
|
1566
1678
|
const [keepQuote, minQuoteAtSeed] = await Promise.all([rd<bigint>(polPolicyAbi, "keepQuote"), rd<bigint>(polPolicyAbi, "minQuoteAtSeed")]);
|
|
@@ -1640,6 +1752,19 @@ export async function fPoolShareHolders(
|
|
|
1640
1752
|
.sort((a, b) => (b.shares > a.shares ? 1 : -1));
|
|
1641
1753
|
}
|
|
1642
1754
|
|
|
1755
|
+
/**
|
|
1756
|
+
* What a policy answers `onRegenerate` with (and `onHarvest`'s split, the first four words):
|
|
1757
|
+
* `IFPolicy.Terms`. `carried` is F version 21's fifth word — the holder the next generation
|
|
1758
|
+
* carries beside the dead shares; the reply is exactly 160 bytes.
|
|
1759
|
+
*/
|
|
1760
|
+
export interface FPolicyTerms {
|
|
1761
|
+
payee: Address;
|
|
1762
|
+
toPayee: bigint;
|
|
1763
|
+
protocolCut: bigint;
|
|
1764
|
+
burn: bigint;
|
|
1765
|
+
carried: Address;
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1643
1768
|
/** Every F pool's state in one lens call (the raw manager struct: quote, phi, authority, kind, seeded, gen, n, Q, L, shares, theta0, bigSigma, harvestedTheta). */
|
|
1644
1769
|
export async function getFPoolsRaw(c: LogswapClient, poolIds: Hex[]): Promise<readonly unknown[]> {
|
|
1645
1770
|
const { logswapLensAbi } = await import("./generated.js");
|