@logswap/sdk 0.5.65 → 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/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 +92 -23
- package/dist/fpool.js +97 -28
- package/dist/generated.d.ts +16 -129
- package/dist/generated.js +4 -80
- package/dist/keys.d.ts +10 -1
- package/dist/keys.js +9 -0
- package/dist/pools.d.ts +26 -0
- package/dist/pools.js +31 -0
- package/dist/write.d.ts +24 -0
- package/dist/write.js +56 -2
- 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 +4 -80
- package/src/keys.ts +11 -1
- package/src/pools.ts +40 -0
- package/src/write.ts +61 -2
package/dist/admin.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import type { Address, Hash } from "viem";
|
|
14
14
|
import type { LogswapClient } from "./client.js";
|
|
15
|
-
import { type FPoolKind } from "./fpool.js";
|
|
15
|
+
import { type FPoolKey, type FPoolKind } from "./fpool.js";
|
|
16
16
|
/** The C manager's `setFeeParams(mintFeeProtocolCut)` — one cut. */
|
|
17
17
|
export declare function setFeeParamsC(c: LogswapClient, mintFeeProtocolCutWad: bigint): Promise<Hash>;
|
|
18
18
|
/** The F manager's `MINT_FEE_PROTOCOL_CUT` — a constant since F version 18; there is no setter. */
|
|
@@ -62,18 +62,36 @@ export declare function registryAcceptOwner(c: LogswapClient): Promise<Hash>;
|
|
|
62
62
|
*/
|
|
63
63
|
export declare function setPolicyApproved(c: LogswapClient, policy: Address, approved: boolean): Promise<Hash>;
|
|
64
64
|
/**
|
|
65
|
-
* Move a pool to another approved policy of the same kind: the registry
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
65
|
+
* Move a pool to another approved policy of the same kind: the registry owner's alone,
|
|
66
|
+
* orchestrated on the registry — `migrate(manager, key, to)` since F version 20 (it took the
|
|
67
|
+
* pool's id before). The registry checks the key against the manager (`NoPool`), checks the
|
|
68
|
+
* manager is its own (`WrongManager`), and compares the two policies' tags recorded at approval
|
|
69
|
+
* ({@link registryKindOf}). The new policy is brought the creator (the key's), the authority and
|
|
70
|
+
* the name (read off the old policy defensively, the key's creator standing in when it cannot
|
|
71
|
+
* answer); the operator and the lists void; no swap lands in the block.
|
|
72
|
+
*
|
|
73
|
+
* Pass the pool's `key` when in hand. Given only `poolId`, the key is rebuilt from the pool's
|
|
74
|
+
* `FInitialize` log ({@link fPoolKeyOfPool}) with `salt` (zero by default) and checked against
|
|
75
|
+
* the id — the log does not carry the salt, so a salted pool needs it named.
|
|
69
76
|
*/
|
|
70
77
|
export declare function fPoolMigrate(c: LogswapClient, a: {
|
|
71
|
-
poolId: `0x${string}`;
|
|
72
78
|
to: Address;
|
|
73
|
-
}
|
|
79
|
+
} & ({
|
|
80
|
+
key: FPoolKey;
|
|
81
|
+
} | {
|
|
82
|
+
poolId: `0x${string}`;
|
|
83
|
+
salt?: `0x${string}`;
|
|
84
|
+
fromBlock?: bigint;
|
|
85
|
+
})): Promise<Hash>;
|
|
86
|
+
/**
|
|
87
|
+
* The kind tag the registry recorded for `policy` at approval (`kindOf`, F version 20) — refreshed
|
|
88
|
+
* on re-approval and kept after a revoke; what `migrate` compares, never the policy's live
|
|
89
|
+
* answer. "" for a policy the registry never approved (or a deployment with no registry).
|
|
90
|
+
*/
|
|
91
|
+
export declare function registryKindOf(c: LogswapClient, policy: Address): Promise<FPoolKind | "">;
|
|
74
92
|
/** The protocol's rate on the income part of every harvest under `policy`, WAD ≤ `HARVEST_CUT_MAX`. */
|
|
75
93
|
export declare function setHarvestCut(c: LogswapClient, policy: Address, rateWad: bigint): Promise<Hash>;
|
|
76
|
-
/** `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`). */
|
|
94
|
+
/** `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. */
|
|
77
95
|
export declare function padSetSchedule(c: LogswapClient, policy: Address, s: {
|
|
78
96
|
thresholdBase: bigint;
|
|
79
97
|
thresholdGrowth: bigint;
|
package/dist/admin.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* protocol share likewise (`POT_CUT_MAX`).
|
|
12
12
|
*/
|
|
13
13
|
import { cPoolManagerAbi, fPoolManagerAbi, padPolicyAbi, polPolicyAbi, policyRegistryAbi, publicPolicyAbi } from "./generated.js";
|
|
14
|
-
import { bytes32ToText, fPolicyBaseAbi, fPoolKindOfPolicy, textToBytes32 } from "./fpool.js";
|
|
14
|
+
import { bytes32ToText, fPolicyBaseAbi, fPoolKeyOfPool, fPoolKindOfPolicy, textToBytes32 } from "./fpool.js";
|
|
15
15
|
function wallet(c) {
|
|
16
16
|
if (!c.wallet)
|
|
17
17
|
throw new Error("a wallet client is required");
|
|
@@ -111,20 +111,40 @@ export async function setPolicyApproved(c, policy, approved) {
|
|
|
111
111
|
return approved ? registryApprove(c, policy, await fPoolKindOfPolicy(c, policy)) : registryRevoke(c, policy);
|
|
112
112
|
}
|
|
113
113
|
/**
|
|
114
|
-
* Move a pool to another approved policy of the same kind: the registry
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
114
|
+
* Move a pool to another approved policy of the same kind: the registry owner's alone,
|
|
115
|
+
* orchestrated on the registry — `migrate(manager, key, to)` since F version 20 (it took the
|
|
116
|
+
* pool's id before). The registry checks the key against the manager (`NoPool`), checks the
|
|
117
|
+
* manager is its own (`WrongManager`), and compares the two policies' tags recorded at approval
|
|
118
|
+
* ({@link registryKindOf}). The new policy is brought the creator (the key's), the authority and
|
|
119
|
+
* the name (read off the old policy defensively, the key's creator standing in when it cannot
|
|
120
|
+
* answer); the operator and the lists void; no swap lands in the block.
|
|
121
|
+
*
|
|
122
|
+
* Pass the pool's `key` when in hand. Given only `poolId`, the key is rebuilt from the pool's
|
|
123
|
+
* `FInitialize` log ({@link fPoolKeyOfPool}) with `salt` (zero by default) and checked against
|
|
124
|
+
* the id — the log does not carry the salt, so a salted pool needs it named.
|
|
118
125
|
*/
|
|
119
126
|
export async function fPoolMigrate(c, a) {
|
|
120
|
-
|
|
127
|
+
const key = "key" in a ? a.key : await fPoolKeyOfPool(c, a.poolId, { salt: a.salt, fromBlock: a.fromBlock });
|
|
128
|
+
return registryWrite(c, "migrate", [c.addresses.fPoolManager, key, a.to]);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The kind tag the registry recorded for `policy` at approval (`kindOf`, F version 20) — refreshed
|
|
132
|
+
* on re-approval and kept after a revoke; what `migrate` compares, never the policy's live
|
|
133
|
+
* answer. "" for a policy the registry never approved (or a deployment with no registry).
|
|
134
|
+
*/
|
|
135
|
+
export async function registryKindOf(c, policy) {
|
|
136
|
+
const registry = await policyRegistryOf(c);
|
|
137
|
+
if (registry === ZERO)
|
|
138
|
+
return "";
|
|
139
|
+
const word = (await c.public.readContract({ address: registry, abi: policyRegistryAbi, functionName: "kindOf", args: [policy] }));
|
|
140
|
+
return bytes32ToText(word);
|
|
121
141
|
}
|
|
122
142
|
// ─── the policies' numbers (the collector's; each bounded where it reaches the manager) ─────
|
|
123
143
|
/** The protocol's rate on the income part of every harvest under `policy`, WAD ≤ `HARVEST_CUT_MAX`. */
|
|
124
144
|
export async function setHarvestCut(c, policy, rateWad) {
|
|
125
145
|
return write(c, policy, fPolicyBaseAbi, "setHarvestCut", [rateWad]);
|
|
126
146
|
}
|
|
127
|
-
/** `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`). */
|
|
147
|
+
/** `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. */
|
|
128
148
|
export async function padSetSchedule(c, policy, s) {
|
|
129
149
|
return write(c, policy, padPolicyAbi, "setSchedule", [s.thresholdBase, s.thresholdGrowth, s.creatorShare, s.protocolShare, s.burnPerRung]);
|
|
130
150
|
}
|
package/dist/client.d.ts
CHANGED
|
@@ -83,7 +83,7 @@ export declare const EXPECTED_VERSION = 5n;
|
|
|
83
83
|
* passes it; when one lands, raise this constant in the same change, which is the discipline
|
|
84
84
|
* `EXPECTED_VERSION` enforces mechanically and this one asks for.
|
|
85
85
|
*/
|
|
86
|
-
export declare const EXPECTED_F_VERSION =
|
|
86
|
+
export declare const EXPECTED_F_VERSION = 21n;
|
|
87
87
|
export declare function assertVersion(c: LogswapClient, expected?: bigint): Promise<void>;
|
|
88
88
|
/**
|
|
89
89
|
* The versions say the managers are the right code; this says the rest of the addresses belong
|
package/dist/client.js
CHANGED
|
@@ -121,7 +121,19 @@ export const EXPECTED_VERSION = 5n;
|
|
|
121
121
|
// is the policy at birth, `migrate` moves a pool for the registry's owner; `stamp` / `setAsks` are
|
|
122
122
|
// the policy's; the desk's `setAllowed` / `isAllowed` are `setMinters` / `setTakers` / `isMinter` /
|
|
123
123
|
// `isTaker`; a pad and a POL hold one base (`OneBase`).
|
|
124
|
-
|
|
124
|
+
// 18–19: no role, no kind and no name on the manager (049); the events carry what a reader needs (050).
|
|
125
|
+
// 20 (2026-09-25, logswap-contract #53): policy isolation — `PolicyRegistry.migrate(manager, key, to)`
|
|
126
|
+
// takes the pool's KEY (was its id), `kindOf(policy)` is the tag recorded at approval, the
|
|
127
|
+
// registry emits `Migrated`; `IFPolicy.onMigrate` is brought the creator, authority and name;
|
|
128
|
+
// the desk's lists are keyed by `listEpoch`. The manager's ABI did not move.
|
|
129
|
+
// 21 (2026-09-26, #54): `regenerate` is the generation step — the policy's `Terms` name a
|
|
130
|
+
// `carried` holder (a fifth word, 160 B), every other holder is frozen out pro rata into
|
|
131
|
+
// generation g's bundle and redeems it (`fPoolRedeem` / `fPoolRollIn` with gen = g), and the
|
|
132
|
+
// pool goes on as g + 1. The manager lost `FEE_MIN` / `FEE_MAX` (see keys.ts), `harvestable`
|
|
133
|
+
// (the bid: `getPool().Q` when L > 0), `idOf(FPoolKey)` (hashed locally, `fPoolIdOfKey`) and
|
|
134
|
+
// `reserveOf` (`legOf`'s fourth word). `PadPolicy.rung` is gone: the pad's rung is `gen`, the
|
|
135
|
+
// next threshold `threshold(gen)`. A pad never retires; a public pool refuses `regenerate`.
|
|
136
|
+
export const EXPECTED_F_VERSION = 21n;
|
|
125
137
|
export async function assertVersion(c, expected = EXPECTED_VERSION) {
|
|
126
138
|
const { cPoolManagerAbi, fPoolManagerAbi } = await import("./generated.js");
|
|
127
139
|
// three independent reads: one round trip, not three in a row
|
package/dist/fpool.d.ts
CHANGED
|
@@ -416,6 +416,10 @@ export declare const fPolicyBaseAbi: readonly [{
|
|
|
416
416
|
readonly name: "burn";
|
|
417
417
|
readonly internalType: "uint256";
|
|
418
418
|
readonly type: "uint256";
|
|
419
|
+
}, {
|
|
420
|
+
readonly name: "carried";
|
|
421
|
+
readonly internalType: "address";
|
|
422
|
+
readonly type: "address";
|
|
419
423
|
}];
|
|
420
424
|
}];
|
|
421
425
|
readonly stateMutability: "nonpayable";
|
|
@@ -732,9 +736,12 @@ export interface FPoolState {
|
|
|
732
736
|
/** False before the first seed — and between a retire and the next one. */
|
|
733
737
|
seeded: boolean;
|
|
734
738
|
/**
|
|
735
|
-
* The live GENERATION. Every retire freezes one into a bundle its shares
|
|
736
|
-
*
|
|
737
|
-
* ({@link
|
|
739
|
+
* The live GENERATION. Every retire freezes one into a bundle its shares redeem
|
|
740
|
+
* ({@link fPoolRedeem}) and opens the next; since F version 21 so does every `regenerate`
|
|
741
|
+
* (the generation step, {@link fPoolRegenerate}): the carried holder and the dead shares go on
|
|
742
|
+
* as `gen + 1`, every other holder of `gen` is frozen out into its bundle. The share id carries
|
|
743
|
+
* it ({@link fPoolShareId}), so generations `0 … gen-1` are claims ({@link fPoolClaimsOf}) and
|
|
744
|
+
* `gen` is the pool. On a pad, `gen` is the graduation count — the rung.
|
|
738
745
|
*/
|
|
739
746
|
gen: number;
|
|
740
747
|
totalSupply: bigint;
|
|
@@ -785,7 +792,7 @@ export interface FPoolRoles {
|
|
|
785
792
|
pendingOperator: Address;
|
|
786
793
|
gateMint: boolean;
|
|
787
794
|
gateSwap: boolean;
|
|
788
|
-
/** The policy's own ceiling on a harvest now — the
|
|
795
|
+
/** The policy's own ceiling on a harvest now — the bid ({@link FPoolDescription.harvestable}) narrowed by the policy's rule. */
|
|
789
796
|
maxHarvest: bigint;
|
|
790
797
|
}
|
|
791
798
|
/** Read a pool's roles from its policy. `state` saves the `getPool` round trip when already in hand. */
|
|
@@ -804,7 +811,12 @@ export interface FPoolDescription {
|
|
|
804
811
|
* from the first wei after it.
|
|
805
812
|
*/
|
|
806
813
|
unharvested: bigint;
|
|
807
|
-
/**
|
|
814
|
+
/**
|
|
815
|
+
* The most a harvest may take now by the MANAGER's rule: the bid, `Q` once seeded (0 before).
|
|
816
|
+
* The manager's `harvestable()` getter was cut in F version 21; this is the same number, read
|
|
817
|
+
* off `getPool`. The policy may allow less (a pad: the income; a POL: above `keepQuote`) —
|
|
818
|
+
* {@link FPoolRoles.maxHarvest}.
|
|
819
|
+
*/
|
|
808
820
|
harvestable: bigint;
|
|
809
821
|
/** The dead shares' banked dividend — a pad's pot, the creator's income until a rung is climbed. */
|
|
810
822
|
pot: bigint;
|
|
@@ -1102,19 +1114,49 @@ export declare function sortFPoolLegs<T>(bases: Address[], ...companions: T[][])
|
|
|
1102
1114
|
companions: T[][];
|
|
1103
1115
|
};
|
|
1104
1116
|
/** The key as the manager hashes it: legs sorted, the kind's policy filled in when none is named; no kind in it (049). */
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1117
|
+
/**
|
|
1118
|
+
* The tuple an F pool's id hashes — `src/types/FPoolKey.sol`, field order load-bearing (it is
|
|
1119
|
+
* the ABI encoding order). Stored by the manager at `initialize` and never in calldata again,
|
|
1120
|
+
* except `PolicyRegistry.migrate` (F version 20), which is handed it to check against the id.
|
|
1121
|
+
*/
|
|
1122
|
+
export interface FPoolKey {
|
|
1123
|
+
quote: Address;
|
|
1124
|
+
/** Sorted ascending, unique. */
|
|
1125
|
+
bases: Address[];
|
|
1126
|
+
/** WAD, aligned with `bases`, summing to 1e18. */
|
|
1108
1127
|
weights: bigint[];
|
|
1109
1128
|
phi: bigint;
|
|
1110
|
-
policy
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1129
|
+
/** The policy AT BIRTH — not the live one after a move. */
|
|
1130
|
+
policy: Address;
|
|
1131
|
+
creator: Address;
|
|
1132
|
+
salt: Hex;
|
|
1133
|
+
}
|
|
1134
|
+
/**
|
|
1135
|
+
* An F pool's id: `keccak256(abi.encode(key))`, offline — what `initialize` computes inline. The
|
|
1136
|
+
* manager's `idOf(FPoolKey)` getter was cut in F version 21; this is the same hash (checked
|
|
1137
|
+
* against Foundry's encoder and the local deployment's pools in the tests). The key must be the
|
|
1138
|
+
* one the pool was initialized with: legs sorted ({@link fPoolKeyOf} sorts them), the birth policy.
|
|
1139
|
+
*/
|
|
1140
|
+
export declare function fPoolIdOfKey(key: FPoolKey): Hex;
|
|
1141
|
+
export declare function fPoolKeyOf(c: LogswapClient, a: Omit<FPoolCreateArgs, "account">): FPoolKey;
|
|
1114
1142
|
/** Create the pool (no funds move — `seed` arms it). Returns the tx hash; read the id with `fPoolIdOf`. */
|
|
1115
1143
|
export declare function fPoolInitialize(c: LogswapClient, a: FPoolCreateArgs): Promise<`0x${string}`>;
|
|
1116
|
-
/**
|
|
1144
|
+
/**
|
|
1145
|
+
* The pool id is the key's hash — pure, so it can be read before or after creation. Computed
|
|
1146
|
+
* locally since F version 21 ({@link fPoolIdOfKey}; the manager's `idOf` is gone): no RPC. Still
|
|
1147
|
+
* async, so callers written against the read keep working.
|
|
1148
|
+
*/
|
|
1117
1149
|
export declare function fPoolIdOf(c: LogswapClient, a: Omit<FPoolCreateArgs, "account">): Promise<Hex>;
|
|
1150
|
+
/**
|
|
1151
|
+
* Rebuild a live pool's KEY from its id: the `FInitialize` log carries every field but the salt,
|
|
1152
|
+
* which is taken from `opts.salt` (zero by default — every pool the SDK's create flow makes
|
|
1153
|
+
* without naming one). The result is checked against the id, so a wrong salt throws rather than
|
|
1154
|
+
* returning a key that names another pool. What {@link fPoolMigrate} needs when handed an id.
|
|
1155
|
+
*/
|
|
1156
|
+
export declare function fPoolKeyOfPool(c: LogswapClient, poolId: Hex, opts?: {
|
|
1157
|
+
salt?: Hex;
|
|
1158
|
+
fromBlock?: bigint;
|
|
1159
|
+
}): Promise<FPoolKey>;
|
|
1118
1160
|
/**
|
|
1119
1161
|
* The reserve a leg holds at a mark: `R = Lj·e^{−x}`, WAD math. The seed names RESERVES —
|
|
1120
1162
|
* the sponsor states holdings and the price follows, `p = Lj / R` — so this is
|
|
@@ -1157,7 +1199,7 @@ export declare function fPoolRetireRaw(c: LogswapClient, a: {
|
|
|
1157
1199
|
* Retire the live generation as ONE transaction: the harvest that empties the bid
|
|
1158
1200
|
* ({@link fPoolEmptyingHarvests} — a dividend to every share; none when it is already empty),
|
|
1159
1201
|
* then `retire` — the manager's `multicall`, the operator as sender. What a sponsor's
|
|
1160
|
-
* "retire" button should call. Throws before sending on a pad
|
|
1202
|
+
* "retire" button should call. Throws before sending on a pad: a pad never retires (F version 21).
|
|
1161
1203
|
*/
|
|
1162
1204
|
export declare function fPoolRetire(c: LogswapClient, a: {
|
|
1163
1205
|
poolId: Hex;
|
|
@@ -1167,18 +1209,29 @@ export declare function fPoolRetire(c: LogswapClient, a: {
|
|
|
1167
1209
|
* The harvests that empty an unlocked pool's bid, in order — what a relaunch sends before its
|
|
1168
1210
|
* `retire` (a retire needs an empty bid on every pool). Since F version 14 one
|
|
1169
1211
|
* `harvest(Q)` does it: the protocol's cut leaves the pool with the amount (with no collector
|
|
1170
|
-
* there is no cut). `[]` when the bid is already empty. Throws on a pad
|
|
1171
|
-
*
|
|
1212
|
+
* there is no cut). `[]` when the bid is already empty. Throws on a pad (F version 21: a pad
|
|
1213
|
+
* never retires, whatever its bid), and when the pool's policy keeps a floor on the bid
|
|
1172
1214
|
* (`PolPolicy.keepQuote`): a `retire` under that policy waits for the market.
|
|
1173
1215
|
*/
|
|
1174
1216
|
export declare function fPoolEmptyingHarvests(c: LogswapClient, poolId: Hex): Promise<bigint[]>;
|
|
1175
1217
|
/**
|
|
1176
|
-
*
|
|
1177
|
-
*
|
|
1178
|
-
*
|
|
1179
|
-
*
|
|
1180
|
-
*
|
|
1181
|
-
*
|
|
1218
|
+
* The GENERATION STEP (F version 21) — on a pad, its graduation. The manager harvests the
|
|
1219
|
+
* generation's income first, releases the dead shares' pot, and asks the policy
|
|
1220
|
+
* (`onRegenerate`), whose {@link FPolicyTerms} name a `carried` holder. Then, for live
|
|
1221
|
+
* generation `g`:
|
|
1222
|
+
*
|
|
1223
|
+
* - the carried holder's and the dead shares' `g` shares are re-minted 1:1 as `g + 1`: they go on
|
|
1224
|
+
* as the pool;
|
|
1225
|
+
* - every OTHER holder of `g` is frozen out pro rata into generation `g`'s bundle (`Retired(g, …)`)
|
|
1226
|
+
* and redeems it with {@link fPoolRedeem} / rolls it with {@link fPoolRollIn} (`gen: g`); their
|
|
1227
|
+
* dividends on `g` stay claimable ({@link fPoolClaim} with `gen: g`). {@link fPoolClaimsOf}
|
|
1228
|
+
* lists them;
|
|
1229
|
+
* - the pot: `toPayee` to the payee, `protocolCut` to the collector, the rest bought in as dead
|
|
1230
|
+
* shares of `g + 1`; then the burn.
|
|
1231
|
+
*
|
|
1232
|
+
* A pad's gate is `threshold(gen)` (`PadPolicy.NotGraduated` below it); POL and private carry the
|
|
1233
|
+
* authority and send it the whole pot; a public pool refuses (`Refused`). A carried holder with no
|
|
1234
|
+
* share is `BadTerms`. Whoever runs the pool.
|
|
1182
1235
|
*/
|
|
1183
1236
|
export declare function fPoolRegenerate(c: LogswapClient, a: {
|
|
1184
1237
|
poolId: Hex;
|
|
@@ -1458,14 +1511,18 @@ export interface FPoolControlled {
|
|
|
1458
1511
|
pool: DiscoveredFPool;
|
|
1459
1512
|
roles: FPoolRoles;
|
|
1460
1513
|
state: FPoolState;
|
|
1461
|
-
/** The policy's numbers for this pool's kind — a pad's rung and threshold, a POL's floors, the desk's list flags. */
|
|
1514
|
+
/** 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. */
|
|
1462
1515
|
rules: FPoolRules;
|
|
1463
1516
|
}
|
|
1464
1517
|
/** What a pool's policy says about it, by kind: the terms a buyer reads before entering. */
|
|
1465
1518
|
export type FPoolRules = {
|
|
1466
1519
|
kind: "pad";
|
|
1467
1520
|
harvestCut: bigint;
|
|
1521
|
+
/** The pad's graduation count: the pool's generation (F version 21 — `PadPolicy.rung` is gone). */
|
|
1522
|
+
gen: number;
|
|
1523
|
+
/** @deprecated Equal to {@link gen} since F version 21, kept for callers; read `gen`. */
|
|
1468
1524
|
rung: number;
|
|
1525
|
+
/** The pot the next graduation needs: `PadPolicy.threshold(gen)`. */
|
|
1469
1526
|
threshold: bigint;
|
|
1470
1527
|
pot: bigint;
|
|
1471
1528
|
creatorShare: bigint;
|
|
@@ -1510,6 +1567,18 @@ export declare function fPoolShareHolders(c: LogswapClient, poolIdHex: Hex, opts
|
|
|
1510
1567
|
holder: Address;
|
|
1511
1568
|
shares: bigint;
|
|
1512
1569
|
}>>;
|
|
1570
|
+
/**
|
|
1571
|
+
* What a policy answers `onRegenerate` with (and `onHarvest`'s split, the first four words):
|
|
1572
|
+
* `IFPolicy.Terms`. `carried` is F version 21's fifth word — the holder the next generation
|
|
1573
|
+
* carries beside the dead shares; the reply is exactly 160 bytes.
|
|
1574
|
+
*/
|
|
1575
|
+
export interface FPolicyTerms {
|
|
1576
|
+
payee: Address;
|
|
1577
|
+
toPayee: bigint;
|
|
1578
|
+
protocolCut: bigint;
|
|
1579
|
+
burn: bigint;
|
|
1580
|
+
carried: Address;
|
|
1581
|
+
}
|
|
1513
1582
|
/** 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). */
|
|
1514
1583
|
export declare function getFPoolsRaw(c: LogswapClient, poolIds: Hex[]): Promise<readonly unknown[]>;
|
|
1515
1584
|
/** Share value from the lens — (L + Q)/shares, WAD per share — the same figure as `fPoolShareValue`, from one source. */
|
package/dist/fpool.js
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* twice, forever. One router is one spender — see `fPoolZapIn`/`fPoolZapOut` below, which target
|
|
30
30
|
* `addresses.router`.
|
|
31
31
|
*/
|
|
32
|
-
import { encodeFunctionData, toFunctionSelector } from "viem";
|
|
32
|
+
import { encodeAbiParameters, encodeFunctionData, keccak256, toFunctionSelector } from "viem";
|
|
33
33
|
import { fPoolManagerAbi, logswapRouterAbi, padPolicyAbi, polPolicyAbi, policyRegistryAbi, privatePolicyAbi, publicPolicyAbi } from "./generated.js";
|
|
34
34
|
/**
|
|
35
35
|
* One contract, one ABI (F version 12): `harvest`, `claim`, `retire`, `regenerate`,
|
|
@@ -192,10 +192,12 @@ export async function describeFPool(c, s) {
|
|
|
192
192
|
functionName,
|
|
193
193
|
args,
|
|
194
194
|
});
|
|
195
|
-
// an unseeded pool has no L: nothing earned, nothing to harvest, no pot
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
195
|
+
// an unseeded pool has no L: nothing earned, nothing to harvest, no pot. The bid is the
|
|
196
|
+
// manager's ceiling (`harvestable()` until F version 21, which cut the getter): Q once seeded.
|
|
197
|
+
const harvestable = s.L > 0n ? s.Q : 0n;
|
|
198
|
+
const [unharvested, pot] = s.L > 0n
|
|
199
|
+
? await Promise.all([rd("unharvested"), rd("dividendOf", [s.poolId, BigInt(s.gen), DEAD_ADDRESS])])
|
|
200
|
+
: [0n, 0n];
|
|
199
201
|
return {
|
|
200
202
|
shape: s.kind === "pad" ? "launch" : "basket", // the kind, not n = 1
|
|
201
203
|
legs: s.bases.length,
|
|
@@ -669,7 +671,29 @@ export function sortFPoolLegs(bases, ...companions) {
|
|
|
669
671
|
const idx = bases.map((_, i) => i).sort((a, b) => (bases[a].toLowerCase() < bases[b].toLowerCase() ? -1 : 1));
|
|
670
672
|
return { bases: idx.map((i) => bases[i]), companions: companions.map((arr) => idx.map((i) => arr[i])) };
|
|
671
673
|
}
|
|
672
|
-
|
|
674
|
+
const F_POOL_KEY_ABI = [
|
|
675
|
+
{
|
|
676
|
+
type: "tuple",
|
|
677
|
+
components: [
|
|
678
|
+
{ name: "quote", type: "address" },
|
|
679
|
+
{ name: "bases", type: "address[]" },
|
|
680
|
+
{ name: "weights", type: "uint256[]" },
|
|
681
|
+
{ name: "phi", type: "uint256" },
|
|
682
|
+
{ name: "policy", type: "address" },
|
|
683
|
+
{ name: "creator", type: "address" },
|
|
684
|
+
{ name: "salt", type: "bytes32" },
|
|
685
|
+
],
|
|
686
|
+
},
|
|
687
|
+
];
|
|
688
|
+
/**
|
|
689
|
+
* An F pool's id: `keccak256(abi.encode(key))`, offline — what `initialize` computes inline. The
|
|
690
|
+
* manager's `idOf(FPoolKey)` getter was cut in F version 21; this is the same hash (checked
|
|
691
|
+
* against Foundry's encoder and the local deployment's pools in the tests). The key must be the
|
|
692
|
+
* one the pool was initialized with: legs sorted ({@link fPoolKeyOf} sorts them), the birth policy.
|
|
693
|
+
*/
|
|
694
|
+
export function fPoolIdOfKey(key) {
|
|
695
|
+
return keccak256(encodeAbiParameters(F_POOL_KEY_ABI, [key]));
|
|
696
|
+
}
|
|
673
697
|
export function fPoolKeyOf(c, a) {
|
|
674
698
|
const { bases, companions } = sortFPoolLegs(a.bases, a.weights);
|
|
675
699
|
return {
|
|
@@ -698,15 +722,46 @@ export async function fPoolInitialize(c, a) {
|
|
|
698
722
|
});
|
|
699
723
|
return c.wallet.writeContract(request);
|
|
700
724
|
}
|
|
701
|
-
/**
|
|
725
|
+
/**
|
|
726
|
+
* The pool id is the key's hash — pure, so it can be read before or after creation. Computed
|
|
727
|
+
* locally since F version 21 ({@link fPoolIdOfKey}; the manager's `idOf` is gone): no RPC. Still
|
|
728
|
+
* async, so callers written against the read keep working.
|
|
729
|
+
*/
|
|
702
730
|
export async function fPoolIdOf(c, a) {
|
|
703
|
-
|
|
704
|
-
|
|
731
|
+
return fPoolIdOfKey(fPoolKeyOf(c, a));
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Rebuild a live pool's KEY from its id: the `FInitialize` log carries every field but the salt,
|
|
735
|
+
* which is taken from `opts.salt` (zero by default — every pool the SDK's create flow makes
|
|
736
|
+
* without naming one). The result is checked against the id, so a wrong salt throws rather than
|
|
737
|
+
* returning a key that names another pool. What {@link fPoolMigrate} needs when handed an id.
|
|
738
|
+
*/
|
|
739
|
+
export async function fPoolKeyOfPool(c, poolId, opts = {}) {
|
|
740
|
+
const ev = fPoolManagerAbi.find((x) => x.type === "event" && x.name === "FInitialize");
|
|
741
|
+
const logs = await c.public.getLogs({
|
|
705
742
|
address: c.addresses.fPoolManager,
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
743
|
+
event: ev,
|
|
744
|
+
args: { poolId },
|
|
745
|
+
fromBlock: opts.fromBlock ?? 0n,
|
|
746
|
+
toBlock: "latest",
|
|
709
747
|
});
|
|
748
|
+
const l = logs[0];
|
|
749
|
+
if (!l)
|
|
750
|
+
throw new Error(`logswap: no FInitialize for F pool ${poolId}`);
|
|
751
|
+
const a = l.args;
|
|
752
|
+
const key = {
|
|
753
|
+
quote: a.quote,
|
|
754
|
+
bases: [...a.bases],
|
|
755
|
+
weights: [...a.weights],
|
|
756
|
+
phi: a.phi,
|
|
757
|
+
policy: a.policy,
|
|
758
|
+
creator: a.creator,
|
|
759
|
+
salt: opts.salt ?? ZERO_SALT,
|
|
760
|
+
};
|
|
761
|
+
if (fPoolIdOfKey(key).toLowerCase() !== poolId.toLowerCase()) {
|
|
762
|
+
throw new Error(`logswap: F pool ${poolId} was not born with salt ${key.salt} — pass its salt, or its whole key`);
|
|
763
|
+
}
|
|
764
|
+
return key;
|
|
710
765
|
}
|
|
711
766
|
/**
|
|
712
767
|
* The reserve a leg holds at a mark: `R = Lj·e^{−x}`, WAD math. The seed names RESERVES —
|
|
@@ -745,7 +800,7 @@ export async function fPoolRetireRaw(c, a) {
|
|
|
745
800
|
* Retire the live generation as ONE transaction: the harvest that empties the bid
|
|
746
801
|
* ({@link fPoolEmptyingHarvests} — a dividend to every share; none when it is already empty),
|
|
747
802
|
* then `retire` — the manager's `multicall`, the operator as sender. What a sponsor's
|
|
748
|
-
* "retire" button should call. Throws before sending on a pad
|
|
803
|
+
* "retire" button should call. Throws before sending on a pad: a pad never retires (F version 21).
|
|
749
804
|
*/
|
|
750
805
|
export async function fPoolRetire(c, a) {
|
|
751
806
|
const harvests = await fPoolEmptyingHarvests(c, a.poolId);
|
|
@@ -759,28 +814,41 @@ export async function fPoolRetire(c, a) {
|
|
|
759
814
|
* The harvests that empty an unlocked pool's bid, in order — what a relaunch sends before its
|
|
760
815
|
* `retire` (a retire needs an empty bid on every pool). Since F version 14 one
|
|
761
816
|
* `harvest(Q)` does it: the protocol's cut leaves the pool with the amount (with no collector
|
|
762
|
-
* there is no cut). `[]` when the bid is already empty. Throws on a pad
|
|
763
|
-
*
|
|
817
|
+
* there is no cut). `[]` when the bid is already empty. Throws on a pad (F version 21: a pad
|
|
818
|
+
* never retires, whatever its bid), and when the pool's policy keeps a floor on the bid
|
|
764
819
|
* (`PolPolicy.keepQuote`): a `retire` under that policy waits for the market.
|
|
765
820
|
*/
|
|
766
821
|
export async function fPoolEmptyingHarvests(c, poolId) {
|
|
767
822
|
const s = await getFPool(c, poolId);
|
|
823
|
+
// F version 21: `PadPolicy` refuses `retire` at any bid — a pad graduates (regenerate), it
|
|
824
|
+
// never closes; a fresh start is a new pad with a new id
|
|
825
|
+
if (s.kind === "pad")
|
|
826
|
+
throw new Error("logswap: a pad never retires (F version 21) — it graduates by regenerate; a fresh start is a new pad");
|
|
768
827
|
if (s.Q === 0n)
|
|
769
828
|
return [];
|
|
770
|
-
if (s.kind === "pad")
|
|
771
|
-
throw new Error("logswap: a pad is retired only once its bid is empty");
|
|
772
829
|
const { maxHarvest } = await getFPoolRoles(c, poolId, s);
|
|
773
830
|
if (maxHarvest < s.Q)
|
|
774
831
|
throw new Error("logswap: the pool's policy keeps a floor on the bid — it cannot be harvested empty");
|
|
775
832
|
return [s.Q];
|
|
776
833
|
}
|
|
777
834
|
/**
|
|
778
|
-
*
|
|
779
|
-
*
|
|
780
|
-
*
|
|
781
|
-
*
|
|
782
|
-
*
|
|
783
|
-
*
|
|
835
|
+
* The GENERATION STEP (F version 21) — on a pad, its graduation. The manager harvests the
|
|
836
|
+
* generation's income first, releases the dead shares' pot, and asks the policy
|
|
837
|
+
* (`onRegenerate`), whose {@link FPolicyTerms} name a `carried` holder. Then, for live
|
|
838
|
+
* generation `g`:
|
|
839
|
+
*
|
|
840
|
+
* - the carried holder's and the dead shares' `g` shares are re-minted 1:1 as `g + 1`: they go on
|
|
841
|
+
* as the pool;
|
|
842
|
+
* - every OTHER holder of `g` is frozen out pro rata into generation `g`'s bundle (`Retired(g, …)`)
|
|
843
|
+
* and redeems it with {@link fPoolRedeem} / rolls it with {@link fPoolRollIn} (`gen: g`); their
|
|
844
|
+
* dividends on `g` stay claimable ({@link fPoolClaim} with `gen: g`). {@link fPoolClaimsOf}
|
|
845
|
+
* lists them;
|
|
846
|
+
* - the pot: `toPayee` to the payee, `protocolCut` to the collector, the rest bought in as dead
|
|
847
|
+
* shares of `g + 1`; then the burn.
|
|
848
|
+
*
|
|
849
|
+
* A pad's gate is `threshold(gen)` (`PadPolicy.NotGraduated` below it); POL and private carry the
|
|
850
|
+
* authority and send it the whole pot; a public pool refuses (`Refused`). A carried holder with no
|
|
851
|
+
* share is `BadTerms`. Whoever runs the pool.
|
|
784
852
|
*/
|
|
785
853
|
export async function fPoolRegenerate(c, a) {
|
|
786
854
|
return writeFPool(c, a.poolId, "regenerate", [a.to ?? a.account], a.account);
|
|
@@ -1089,15 +1157,16 @@ export async function getFPoolRules(c, s, roles) {
|
|
|
1089
1157
|
const harvestCut = await rd(fPolicyBaseAbi, "harvestCut");
|
|
1090
1158
|
switch (s.kind) {
|
|
1091
1159
|
case "pad": {
|
|
1092
|
-
|
|
1093
|
-
|
|
1160
|
+
// the rung is the manager's generation (F version 21): a move carries it, nothing to ask the policy
|
|
1161
|
+
const gen = s.gen;
|
|
1162
|
+
const [creatorShare, protocolShare, burnPerRung, pot, threshold] = await Promise.all([
|
|
1094
1163
|
rd(padPolicyAbi, "creatorShare"),
|
|
1095
1164
|
rd(padPolicyAbi, "protocolShare"),
|
|
1096
1165
|
rd(padPolicyAbi, "burnPerRung"),
|
|
1097
|
-
fPoolDividendOf(c, s.poolId, DEAD_ADDRESS,
|
|
1166
|
+
fPoolDividendOf(c, s.poolId, DEAD_ADDRESS, gen),
|
|
1167
|
+
rd(padPolicyAbi, "threshold", [BigInt(gen)]),
|
|
1098
1168
|
]);
|
|
1099
|
-
|
|
1100
|
-
return { kind: "pad", harvestCut, rung: Number(rung), threshold, pot, creatorShare, protocolShare, burnPerRung };
|
|
1169
|
+
return { kind: "pad", harvestCut, gen, rung: gen, threshold, pot, creatorShare, protocolShare, burnPerRung };
|
|
1101
1170
|
}
|
|
1102
1171
|
case "pol": {
|
|
1103
1172
|
const [keepQuote, minQuoteAtSeed] = await Promise.all([rd(polPolicyAbi, "keepQuote"), rd(polPolicyAbi, "minQuoteAtSeed")]);
|