@logswap/sdk 0.5.68 → 0.5.70
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 +11 -7
- package/dist/admin.js +16 -8
- package/dist/client.d.ts +1 -1
- package/dist/client.js +3 -1
- package/dist/fpool.d.ts +93 -94
- package/dist/fpool.js +161 -20
- package/dist/generated.d.ts +110 -349
- package/dist/generated.js +83 -240
- package/package.json +1 -1
- package/src/admin.ts +25 -10
- package/src/client.ts +3 -1
- package/src/fpool.ts +218 -27
- package/src/generated.ts +83 -240
package/dist/admin.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* One vocabulary: both managers call the protocol's cut of the mint fee
|
|
8
8
|
* `MINT_FEE_PROTOCOL_CUT`; C sets it through `setFeeParams(uint256)`, F holds it as a constant
|
|
9
9
|
* (049). The harvest's cut is the policy's answer at every harvest, set on the
|
|
10
|
-
* policy (`
|
|
10
|
+
* policy (`PadPolicy.setSchedule`: the protocol's pot share and the ranges a creator chooses inside) and capped by the manager (`POT_CUT_MAX`, `BURN_MAX`; a harvest has no cut, decisions 056); the release's
|
|
11
11
|
* protocol share likewise (`POT_CUT_MAX`).
|
|
12
12
|
*/
|
|
13
13
|
import type { Address, Hash } from "viem";
|
|
@@ -89,17 +89,21 @@ export declare function fPoolMigrate(c: LogswapClient, a: {
|
|
|
89
89
|
* answer. "" for a policy the registry never approved (or a deployment with no registry).
|
|
90
90
|
*/
|
|
91
91
|
export declare function registryKindOf(c: LogswapClient, policy: Address): Promise<FPoolKind | "">;
|
|
92
|
-
/**
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
/**
|
|
93
|
+
* `PadPolicy.setSchedule` (decisions 056): `T(0)`, the rung's growth, the protocol's share of the pot (≤ `POT_CUT_MAX`,
|
|
94
|
+
* recorded into each pad at birth), and the RANGES a creator chooses inside at creation — his cut of the pot and the burn per
|
|
95
|
+
* rung (≤ `BURN_MAX`). A change applies to pads born after it. The rung is the pool's generation since F version 21.
|
|
96
|
+
*/
|
|
95
97
|
export declare function padSetSchedule(c: LogswapClient, policy: Address, s: {
|
|
96
98
|
thresholdBase: bigint;
|
|
97
99
|
thresholdGrowth: bigint;
|
|
98
|
-
creatorShare: bigint;
|
|
99
100
|
protocolShare: bigint;
|
|
100
|
-
|
|
101
|
+
creatorShareMin: bigint;
|
|
102
|
+
creatorShareMax: bigint;
|
|
103
|
+
burnMin: bigint;
|
|
104
|
+
burnMax: bigint;
|
|
101
105
|
}): Promise<Hash>;
|
|
102
|
-
/** `PolPolicy.setRules`:
|
|
106
|
+
/** `PolPolicy.setRules`: the reserve a harvest must leave in the bid (`may(Harvest)` refuses less) and what a relaunch's seed must bring, WAD fractions of the pool's L. */
|
|
103
107
|
export declare function polSetRules(c: LogswapClient, policy: Address, s: {
|
|
104
108
|
keepQuote: bigint;
|
|
105
109
|
minQuoteAtSeed: bigint;
|
package/dist/admin.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* One vocabulary: both managers call the protocol's cut of the mint fee
|
|
8
8
|
* `MINT_FEE_PROTOCOL_CUT`; C sets it through `setFeeParams(uint256)`, F holds it as a constant
|
|
9
9
|
* (049). The harvest's cut is the policy's answer at every harvest, set on the
|
|
10
|
-
* policy (`
|
|
10
|
+
* policy (`PadPolicy.setSchedule`: the protocol's pot share and the ranges a creator chooses inside) and capped by the manager (`POT_CUT_MAX`, `BURN_MAX`; a harvest has no cut, decisions 056); the release's
|
|
11
11
|
* protocol share likewise (`POT_CUT_MAX`).
|
|
12
12
|
*/
|
|
13
13
|
import { cPoolManagerAbi, fPoolManagerAbi, padPolicyAbi, polPolicyAbi, policyRegistryAbi, publicPolicyAbi } from "./generated.js";
|
|
@@ -140,15 +140,23 @@ export async function registryKindOf(c, policy) {
|
|
|
140
140
|
return bytes32ToText(word);
|
|
141
141
|
}
|
|
142
142
|
// ─── the policies' numbers (the collector's; each bounded where it reaches the manager) ─────
|
|
143
|
-
/**
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
143
|
+
/**
|
|
144
|
+
* `PadPolicy.setSchedule` (decisions 056): `T(0)`, the rung's growth, the protocol's share of the pot (≤ `POT_CUT_MAX`,
|
|
145
|
+
* recorded into each pad at birth), and the RANGES a creator chooses inside at creation — his cut of the pot and the burn per
|
|
146
|
+
* rung (≤ `BURN_MAX`). A change applies to pads born after it. The rung is the pool's generation since F version 21.
|
|
147
|
+
*/
|
|
148
148
|
export async function padSetSchedule(c, policy, s) {
|
|
149
|
-
return write(c, policy, padPolicyAbi, "setSchedule", [
|
|
149
|
+
return write(c, policy, padPolicyAbi, "setSchedule", [
|
|
150
|
+
s.thresholdBase,
|
|
151
|
+
s.thresholdGrowth,
|
|
152
|
+
s.protocolShare,
|
|
153
|
+
s.creatorShareMin,
|
|
154
|
+
s.creatorShareMax,
|
|
155
|
+
s.burnMin,
|
|
156
|
+
s.burnMax,
|
|
157
|
+
]);
|
|
150
158
|
}
|
|
151
|
-
/** `PolPolicy.setRules`:
|
|
159
|
+
/** `PolPolicy.setRules`: the reserve a harvest must leave in the bid (`may(Harvest)` refuses less) and what a relaunch's seed must bring, WAD fractions of the pool's L. */
|
|
152
160
|
export async function polSetRules(c, policy, s) {
|
|
153
161
|
return write(c, policy, polPolicyAbi, "setRules", [s.keepQuote, s.minQuoteAtSeed]);
|
|
154
162
|
}
|
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 = 23n;
|
|
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
|
@@ -133,7 +133,9 @@ export const EXPECTED_VERSION = 5n;
|
|
|
133
133
|
// (the bid: `getPool().Q` when L > 0), `idOf(FPoolKey)` (hashed locally, `fPoolIdOfKey`) and
|
|
134
134
|
// `reserveOf` (`legOf`'s fourth word). `PadPolicy.rung` is gone: the pad's rung is `gen`, the
|
|
135
135
|
// next threshold `threshold(gen)`. A pad never retires; a public pool refuses `regenerate`.
|
|
136
|
-
|
|
136
|
+
// 23: a harvest asks `may(Harvest)` and takes no terms and no cut (decisions 056): `onHarvest`, `HARVEST_CUT_MAX`,
|
|
137
|
+
// `harvestCut`, `setHarvestCut` are gone; a pad's split (creator's cut, token burn) rides in the key's salt.
|
|
138
|
+
export const EXPECTED_F_VERSION = 23n;
|
|
137
139
|
export async function assertVersion(c, expected = EXPECTED_VERSION) {
|
|
138
140
|
const { cPoolManagerAbi, fPoolManagerAbi } = await import("./generated.js");
|
|
139
141
|
// three independent reads: one round trip, not three in a row
|
package/dist/fpool.d.ts
CHANGED
|
@@ -40,8 +40,8 @@ import { fPoolManagerAbi, padPolicyAbi, polPolicyAbi, privatePolicyAbi, publicPo
|
|
|
40
40
|
*/
|
|
41
41
|
export { fPoolManagerAbi, padPolicyAbi, polPolicyAbi, privatePolicyAbi, publicPolicyAbi };
|
|
42
42
|
/**
|
|
43
|
-
* What every protocol policy shares (`FPolicyBase`): the roles and their handover
|
|
44
|
-
* `maxHarvest
|
|
43
|
+
* What every protocol policy shares (`FPolicyBase`): the roles and their handover and the
|
|
44
|
+
* `maxHarvest` readout (a harvest has no cut, decisions 056). `polPolicyAbi` is a superset of it and carries nothing that collides, so it stands
|
|
45
45
|
* in for the base — a call through it to any of the four policies decodes the base's functions.
|
|
46
46
|
*/
|
|
47
47
|
export declare const fPolicyBaseAbi: readonly [{
|
|
@@ -90,16 +90,6 @@ export declare const fPolicyBaseAbi: readonly [{
|
|
|
90
90
|
readonly type: "address";
|
|
91
91
|
}];
|
|
92
92
|
readonly stateMutability: "view";
|
|
93
|
-
}, {
|
|
94
|
-
readonly type: "function";
|
|
95
|
-
readonly inputs: readonly [];
|
|
96
|
-
readonly name: "harvestCut";
|
|
97
|
-
readonly outputs: readonly [{
|
|
98
|
-
readonly name: "";
|
|
99
|
-
readonly internalType: "uint256";
|
|
100
|
-
readonly type: "uint256";
|
|
101
|
-
}];
|
|
102
|
-
readonly stateMutability: "view";
|
|
103
93
|
}, {
|
|
104
94
|
readonly type: "function";
|
|
105
95
|
readonly inputs: readonly [];
|
|
@@ -219,61 +209,6 @@ export declare const fPolicyBaseAbi: readonly [{
|
|
|
219
209
|
readonly type: "bytes32";
|
|
220
210
|
}];
|
|
221
211
|
readonly stateMutability: "view";
|
|
222
|
-
}, {
|
|
223
|
-
readonly type: "function";
|
|
224
|
-
readonly inputs: readonly [{
|
|
225
|
-
readonly name: "a";
|
|
226
|
-
readonly internalType: "struct IFPolicy.Ask";
|
|
227
|
-
readonly type: "tuple";
|
|
228
|
-
readonly components: readonly [{
|
|
229
|
-
readonly name: "poolId";
|
|
230
|
-
readonly internalType: "bytes32";
|
|
231
|
-
readonly type: "bytes32";
|
|
232
|
-
}, {
|
|
233
|
-
readonly name: "gen";
|
|
234
|
-
readonly internalType: "uint256";
|
|
235
|
-
readonly type: "uint256";
|
|
236
|
-
}, {
|
|
237
|
-
readonly name: "action";
|
|
238
|
-
readonly internalType: "enum IFPolicy.Action";
|
|
239
|
-
readonly type: "uint8";
|
|
240
|
-
}, {
|
|
241
|
-
readonly name: "who";
|
|
242
|
-
readonly internalType: "address";
|
|
243
|
-
readonly type: "address";
|
|
244
|
-
}, {
|
|
245
|
-
readonly name: "amount";
|
|
246
|
-
readonly internalType: "uint256";
|
|
247
|
-
readonly type: "uint256";
|
|
248
|
-
}, {
|
|
249
|
-
readonly name: "income";
|
|
250
|
-
readonly internalType: "uint256";
|
|
251
|
-
readonly type: "uint256";
|
|
252
|
-
}, {
|
|
253
|
-
readonly name: "Q";
|
|
254
|
-
readonly internalType: "uint256";
|
|
255
|
-
readonly type: "uint256";
|
|
256
|
-
}, {
|
|
257
|
-
readonly name: "L";
|
|
258
|
-
readonly internalType: "uint256";
|
|
259
|
-
readonly type: "uint256";
|
|
260
|
-
}, {
|
|
261
|
-
readonly name: "n";
|
|
262
|
-
readonly internalType: "uint256";
|
|
263
|
-
readonly type: "uint256";
|
|
264
|
-
}];
|
|
265
|
-
}];
|
|
266
|
-
readonly name: "onHarvest";
|
|
267
|
-
readonly outputs: readonly [{
|
|
268
|
-
readonly name: "amount";
|
|
269
|
-
readonly internalType: "uint256";
|
|
270
|
-
readonly type: "uint256";
|
|
271
|
-
}, {
|
|
272
|
-
readonly name: "cut";
|
|
273
|
-
readonly internalType: "uint256";
|
|
274
|
-
readonly type: "uint256";
|
|
275
|
-
}];
|
|
276
|
-
readonly stateMutability: "view";
|
|
277
212
|
}, {
|
|
278
213
|
readonly type: "function";
|
|
279
214
|
readonly inputs: readonly [{
|
|
@@ -475,16 +410,6 @@ export declare const fPolicyBaseAbi: readonly [{
|
|
|
475
410
|
readonly type: "bool";
|
|
476
411
|
}];
|
|
477
412
|
readonly stateMutability: "view";
|
|
478
|
-
}, {
|
|
479
|
-
readonly type: "function";
|
|
480
|
-
readonly inputs: readonly [{
|
|
481
|
-
readonly name: "_harvestCut";
|
|
482
|
-
readonly internalType: "uint256";
|
|
483
|
-
readonly type: "uint256";
|
|
484
|
-
}];
|
|
485
|
-
readonly name: "setHarvestCut";
|
|
486
|
-
readonly outputs: readonly [];
|
|
487
|
-
readonly stateMutability: "nonpayable";
|
|
488
413
|
}, {
|
|
489
414
|
readonly type: "function";
|
|
490
415
|
readonly inputs: readonly [{
|
|
@@ -577,16 +502,6 @@ export declare const fPolicyBaseAbi: readonly [{
|
|
|
577
502
|
readonly indexed: true;
|
|
578
503
|
}];
|
|
579
504
|
readonly name: "AuthoritySet";
|
|
580
|
-
}, {
|
|
581
|
-
readonly type: "event";
|
|
582
|
-
readonly anonymous: false;
|
|
583
|
-
readonly inputs: readonly [{
|
|
584
|
-
readonly name: "harvestCut";
|
|
585
|
-
readonly internalType: "uint256";
|
|
586
|
-
readonly type: "uint256";
|
|
587
|
-
readonly indexed: false;
|
|
588
|
-
}];
|
|
589
|
-
readonly name: "HarvestCutSet";
|
|
590
505
|
}, {
|
|
591
506
|
readonly type: "event";
|
|
592
507
|
readonly anonymous: false;
|
|
@@ -1150,7 +1065,7 @@ export declare function fPoolIdOf(c: LogswapClient, a: Omit<FPoolCreateArgs, "ac
|
|
|
1150
1065
|
/**
|
|
1151
1066
|
* Rebuild a live pool's KEY from its id: the `FInitialize` log carries every field but the salt,
|
|
1152
1067
|
* 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
|
|
1068
|
+
* without naming one; a pad's carries its split, so it is rebuilt from the policy's record with nonce 0 — pass `opts.salt` for another nonce). The result is checked against the id, so a wrong salt throws rather than
|
|
1154
1069
|
* returning a key that names another pool. What {@link fPoolMigrate} needs when handed an id.
|
|
1155
1070
|
*/
|
|
1156
1071
|
export declare function fPoolKeyOfPool(c: LogswapClient, poolId: Hex, opts?: {
|
|
@@ -1273,6 +1188,27 @@ export declare function fPoolRelaunch(c: LogswapClient, a: {
|
|
|
1273
1188
|
export declare const DEAD_ADDRESS: Address;
|
|
1274
1189
|
/** The manager's `MIN_SHARES`: the seed mints this much to 0xdead on every pool, the rest to the seeder — or, on a pad, to 0xdead too. */
|
|
1275
1190
|
export declare const F_MIN_SHARES = 1000n;
|
|
1191
|
+
/**
|
|
1192
|
+
* One genesis transaction: a swap the creator sends right after the seed, inside the launch's
|
|
1193
|
+
* `multicall`. A `buy` spends `amountIn` of quote for leg `j` (an index into `bases` AS GIVEN); a
|
|
1194
|
+
* `sell` spends `amountIn` of that leg for quote. The creator pays and is paid — the manager settles
|
|
1195
|
+
* to its sender — so a `recipient` is paid by an ERC-20 transfer of the row's output
|
|
1196
|
+
* ({@link fPoolGenesisTransfers}); without one the output stays with the creator.
|
|
1197
|
+
*/
|
|
1198
|
+
export interface FPoolGenesisRow {
|
|
1199
|
+
side: "buy" | "sell";
|
|
1200
|
+
j: number;
|
|
1201
|
+
amountIn: bigint;
|
|
1202
|
+
/** Defaults to 0. With a `recipient`, {@link fPoolLaunch} pins it to the simulated output, which is what the transfer pays. */
|
|
1203
|
+
minOut?: bigint;
|
|
1204
|
+
recipient?: Address;
|
|
1205
|
+
}
|
|
1206
|
+
/** An ERC-20 transfer owed to a genesis recipient: one per (token, recipient), rows summed. */
|
|
1207
|
+
export interface FPoolGenesisTransfer {
|
|
1208
|
+
token: Address;
|
|
1209
|
+
to: Address;
|
|
1210
|
+
amount: bigint;
|
|
1211
|
+
}
|
|
1276
1212
|
export interface FPoolLaunchArgs extends Omit<FPoolCreateArgs, "account"> {
|
|
1277
1213
|
L0: bigint;
|
|
1278
1214
|
/** Quote the seed pulls. A pad seeds at 0 — pure float, a resting ask, nothing raised. */
|
|
@@ -1289,6 +1225,18 @@ export interface FPoolLaunchArgs extends Omit<FPoolCreateArgs, "account"> {
|
|
|
1289
1225
|
amountIn: bigint;
|
|
1290
1226
|
minOut?: bigint;
|
|
1291
1227
|
};
|
|
1228
|
+
/**
|
|
1229
|
+
* The genesis transactions: an ordered list of swaps right after the seed, each with an optional
|
|
1230
|
+
* recipient ({@link FPoolGenesisRow}). The same batch as `openBuy`, which stays as the one-buy
|
|
1231
|
+
* case and runs first when both are given. See `specs/f-pools/opening.md`.
|
|
1232
|
+
*/
|
|
1233
|
+
openBatch?: FPoolGenesisRow[];
|
|
1234
|
+
/**
|
|
1235
|
+
* How a row's recipient is paid. `auto` (default): in the launch's own transaction when the
|
|
1236
|
+
* wallet batches atomically (EIP-5792), else left to {@link fPoolSendGenesisTransfers};
|
|
1237
|
+
* `followup`: always left to it. Ignored when no row names a recipient.
|
|
1238
|
+
*/
|
|
1239
|
+
deliver?: "auto" | "followup";
|
|
1292
1240
|
/** 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. */
|
|
1293
1241
|
name?: string;
|
|
1294
1242
|
/**
|
|
@@ -1312,6 +1260,32 @@ export declare function fPoolLaunchCalls(poolId: Hex, a: FPoolLaunchArgs & ({
|
|
|
1312
1260
|
} | {
|
|
1313
1261
|
x0: bigint[];
|
|
1314
1262
|
})): Hex[];
|
|
1263
|
+
/** The genesis rows in the order they run: `openBuy` first when given, then `openBatch`. Legs as given. */
|
|
1264
|
+
export declare function fPoolGenesisRows(a: Pick<FPoolLaunchArgs, "openBuy" | "openBatch">): FPoolGenesisRow[];
|
|
1265
|
+
/**
|
|
1266
|
+
* What each genesis row returned, read by simulating the launch's `multicall` on the chain — the
|
|
1267
|
+
* contract's own rounding, no re-implementation. Exact at send time: the pool is new, and nothing
|
|
1268
|
+
* can trade between the seed and the rows. Needs the creator's funds and allowances, as the launch
|
|
1269
|
+
* does. One output per row, in {@link fPoolGenesisRows} order: base for a buy, quote for a sell.
|
|
1270
|
+
*/
|
|
1271
|
+
export declare function fPoolGenesisOutputs(c: LogswapClient, poolId: Hex, a: FPoolLaunchArgs & ({
|
|
1272
|
+
r0: bigint[];
|
|
1273
|
+
} | {
|
|
1274
|
+
x0: bigint[];
|
|
1275
|
+
})): Promise<bigint[]>;
|
|
1276
|
+
/**
|
|
1277
|
+
* The transfers that pay the recipients: each row's output (`outs`, aligned with
|
|
1278
|
+
* {@link fPoolGenesisRows}) to its `recipient`, summed per (token, recipient), zero amounts dropped.
|
|
1279
|
+
* The token is the leg's base for a buy and the quote for a sell. Pure.
|
|
1280
|
+
*/
|
|
1281
|
+
export declare function fPoolGenesisTransfers(a: Pick<FPoolLaunchArgs, "quote" | "bases" | "openBuy" | "openBatch">, outs: bigint[]): FPoolGenesisTransfer[];
|
|
1282
|
+
/** Pay genesis recipients with plain ERC-20 transfers, one transaction each, in order. For a launch that did not deliver itself. */
|
|
1283
|
+
export declare function fPoolSendGenesisTransfers(c: LogswapClient, a: {
|
|
1284
|
+
transfers: FPoolGenesisTransfer[];
|
|
1285
|
+
account: Address;
|
|
1286
|
+
}): Promise<Hash[]>;
|
|
1287
|
+
/** Whether the wallet runs a batch of calls atomically (EIP-5792 `atomic` capability), on the client's chain. A wallet without it, or one that errors, says no. */
|
|
1288
|
+
export declare function fPoolWalletBatchesAtomically(c: LogswapClient, account: Address): Promise<boolean>;
|
|
1315
1289
|
/**
|
|
1316
1290
|
* The desk's opening posture, on its policy: gated minting, the creator a
|
|
1317
1291
|
* minter. No appointment: the authority is the operator until one is appointed.
|
|
@@ -1346,6 +1320,8 @@ export declare function fPoolLaunch(c: LogswapClient, a: FPoolLaunchArgs & ({
|
|
|
1346
1320
|
})): Promise<{
|
|
1347
1321
|
hash: Hash;
|
|
1348
1322
|
poolId: Hex;
|
|
1323
|
+
transfers: FPoolGenesisTransfer[];
|
|
1324
|
+
delivered: boolean;
|
|
1349
1325
|
}>;
|
|
1350
1326
|
/**
|
|
1351
1327
|
* Propose the next authority — step one of two, on the pool's policy. Nothing moves
|
|
@@ -1517,7 +1493,6 @@ export interface FPoolControlled {
|
|
|
1517
1493
|
/** What a pool's policy says about it, by kind: the terms a buyer reads before entering. */
|
|
1518
1494
|
export type FPoolRules = {
|
|
1519
1495
|
kind: "pad";
|
|
1520
|
-
harvestCut: bigint;
|
|
1521
1496
|
/** The pad's graduation count: the pool's generation (F version 21 — `PadPolicy.rung` is gone). */
|
|
1522
1497
|
gen: number;
|
|
1523
1498
|
/** @deprecated Equal to {@link gen} since F version 21, kept for callers; read `gen`. */
|
|
@@ -1525,25 +1500,50 @@ export type FPoolRules = {
|
|
|
1525
1500
|
/** The pot the next graduation needs: `PadPolicy.threshold(gen)`. */
|
|
1526
1501
|
threshold: bigint;
|
|
1527
1502
|
pot: bigint;
|
|
1503
|
+
/** This pad's split, recorded at its birth from the key's salt and never changed (decisions 056): the creator's cut of the pot, the protocol's, and the burn per rung. The rest of the pot is bought in. */
|
|
1528
1504
|
creatorShare: bigint;
|
|
1529
1505
|
protocolShare: bigint;
|
|
1530
1506
|
burnPerRung: bigint;
|
|
1507
|
+
/** The ranges the collector's policy holds NOW for the pads born after this read: what a new creator may choose. */
|
|
1508
|
+
ranges: PadRanges;
|
|
1531
1509
|
} | {
|
|
1532
1510
|
kind: "pol";
|
|
1533
|
-
harvestCut: bigint;
|
|
1534
1511
|
keepQuote: bigint;
|
|
1535
1512
|
minQuoteAtSeed: bigint;
|
|
1536
1513
|
} | {
|
|
1537
1514
|
kind: "public";
|
|
1538
|
-
harvestCut: bigint;
|
|
1539
1515
|
curated: boolean;
|
|
1540
1516
|
} | {
|
|
1541
1517
|
kind: "private";
|
|
1542
|
-
harvestCut: bigint;
|
|
1543
1518
|
gateMint: boolean;
|
|
1544
1519
|
gateSwap: boolean;
|
|
1545
1520
|
operator: Address;
|
|
1546
1521
|
};
|
|
1522
|
+
/** The collector's ranges on a pad's creator choices (`PadPolicy`, decisions 056), WAD fractions: of the pot, and of every reserve per rung. */
|
|
1523
|
+
export interface PadRanges {
|
|
1524
|
+
/** The protocol's share of the pot, recorded into each pad at birth. */
|
|
1525
|
+
protocolShare: bigint;
|
|
1526
|
+
creatorShareMin: bigint;
|
|
1527
|
+
creatorShareMax: bigint;
|
|
1528
|
+
burnMin: bigint;
|
|
1529
|
+
burnMax: bigint;
|
|
1530
|
+
}
|
|
1531
|
+
/**
|
|
1532
|
+
* The salt that carries a pad's split (`PadPolicy.pack`, decisions 056): `creatorShare` in the top 64 bits, `burnPerRung` in
|
|
1533
|
+
* the next 64 (WAD fractions), a nonce in the low 128 that tells two otherwise identical pads apart. It is part of the pool's
|
|
1534
|
+
* identity, so it is chosen at launch (`FPoolLaunchArgs.salt`) and never changes; the policy refuses a split outside its ranges.
|
|
1535
|
+
*/
|
|
1536
|
+
export declare function padSalt(s: {
|
|
1537
|
+
creatorShare: bigint;
|
|
1538
|
+
burnPerRung: bigint;
|
|
1539
|
+
nonce?: bigint;
|
|
1540
|
+
}): Hex;
|
|
1541
|
+
/** The inverse of {@link padSalt}. */
|
|
1542
|
+
export declare function padSplitOfSalt(salt: Hex): {
|
|
1543
|
+
creatorShare: bigint;
|
|
1544
|
+
burnPerRung: bigint;
|
|
1545
|
+
nonce: bigint;
|
|
1546
|
+
};
|
|
1547
1547
|
/** The policy's terms for one pool, by its kind. */
|
|
1548
1548
|
export declare function getFPoolRules(c: LogswapClient, s: Pick<FPoolState, "poolId" | "policy" | "kind" | "gen">, roles?: FPoolRoles): Promise<FPoolRules>;
|
|
1549
1549
|
/**
|
|
@@ -1568,8 +1568,7 @@ export declare function fPoolShareHolders(c: LogswapClient, poolIdHex: Hex, opts
|
|
|
1568
1568
|
shares: bigint;
|
|
1569
1569
|
}>>;
|
|
1570
1570
|
/**
|
|
1571
|
-
* What a policy answers `onRegenerate` with
|
|
1572
|
-
* `IFPolicy.Terms`. `carried` is F version 21's fifth word — the holder the next generation
|
|
1571
|
+
* What a policy answers `onRegenerate` with: `IFPolicy.Terms`. `carried` is F version 21's fifth word — the holder the next generation
|
|
1573
1572
|
* carries beside the dead shares; the reply is exactly 160 bytes.
|
|
1574
1573
|
*/
|
|
1575
1574
|
export interface FPolicyTerms {
|
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 { encodeAbiParameters, encodeFunctionData, keccak256, toFunctionSelector } from "viem";
|
|
32
|
+
import { decodeAbiParameters, encodeAbiParameters, encodeFunctionData, erc20Abi, 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`,
|
|
@@ -40,8 +40,8 @@ import { fPoolManagerAbi, logswapRouterAbi, padPolicyAbi, polPolicyAbi, policyRe
|
|
|
40
40
|
*/
|
|
41
41
|
export { fPoolManagerAbi, padPolicyAbi, polPolicyAbi, privatePolicyAbi, publicPolicyAbi };
|
|
42
42
|
/**
|
|
43
|
-
* What every protocol policy shares (`FPolicyBase`): the roles and their handover
|
|
44
|
-
* `maxHarvest
|
|
43
|
+
* What every protocol policy shares (`FPolicyBase`): the roles and their handover and the
|
|
44
|
+
* `maxHarvest` readout (a harvest has no cut, decisions 056). `polPolicyAbi` is a superset of it and carries nothing that collides, so it stands
|
|
45
45
|
* in for the base — a call through it to any of the four policies decodes the base's functions.
|
|
46
46
|
*/
|
|
47
47
|
export const fPolicyBaseAbi = polPolicyAbi;
|
|
@@ -733,7 +733,7 @@ export async function fPoolIdOf(c, a) {
|
|
|
733
733
|
/**
|
|
734
734
|
* Rebuild a live pool's KEY from its id: the `FInitialize` log carries every field but the salt,
|
|
735
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
|
|
736
|
+
* without naming one; a pad's carries its split, so it is rebuilt from the policy's record with nonce 0 — pass `opts.salt` for another nonce). The result is checked against the id, so a wrong salt throws rather than
|
|
737
737
|
* returning a key that names another pool. What {@link fPoolMigrate} needs when handed an id.
|
|
738
738
|
*/
|
|
739
739
|
export async function fPoolKeyOfPool(c, poolId, opts = {}) {
|
|
@@ -758,6 +758,18 @@ export async function fPoolKeyOfPool(c, poolId, opts = {}) {
|
|
|
758
758
|
creator: a.creator,
|
|
759
759
|
salt: opts.salt ?? ZERO_SALT,
|
|
760
760
|
};
|
|
761
|
+
if (fPoolIdOfKey(key).toLowerCase() !== poolId.toLowerCase() && opts.salt === undefined) {
|
|
762
|
+
// a pad's salt carries its split (decisions 056): rebuild it from the policy's record with the default nonce
|
|
763
|
+
try {
|
|
764
|
+
const [creatorShare, burnPerRung] = (await c.public.readContract({ address: a.policy, abi: padPolicyAbi, functionName: "splitOf", args: [poolId] }));
|
|
765
|
+
const padKey = { ...key, salt: padSalt({ creatorShare, burnPerRung }) };
|
|
766
|
+
if (fPoolIdOfKey(padKey).toLowerCase() === poolId.toLowerCase())
|
|
767
|
+
return padKey;
|
|
768
|
+
}
|
|
769
|
+
catch {
|
|
770
|
+
/* not a pad: fall through to the error */
|
|
771
|
+
}
|
|
772
|
+
}
|
|
761
773
|
if (fPoolIdOfKey(key).toLowerCase() !== poolId.toLowerCase()) {
|
|
762
774
|
throw new Error(`logswap: F pool ${poolId} was not born with salt ${key.salt} — pass its salt, or its whole key`);
|
|
763
775
|
}
|
|
@@ -907,11 +919,11 @@ export function fPoolLaunchCalls(poolId, a) {
|
|
|
907
919
|
calls.push(enc("seed", [poolId, a.L0, companions[1], a.Q0]));
|
|
908
920
|
// gen 0 by construction: a launch is the pool's FIRST seed — a relaunch is `fPoolRelaunch`.
|
|
909
921
|
// No transfer to 0xdead: on a pad `seed` mints every share there itself.
|
|
910
|
-
|
|
911
|
-
const j = bases.indexOf(a.bases[
|
|
922
|
+
for (const row of fPoolGenesisRows(a)) {
|
|
923
|
+
const j = bases.indexOf(a.bases[row.j]);
|
|
912
924
|
if (j < 0)
|
|
913
|
-
throw new Error(`logswap:
|
|
914
|
-
calls.push(enc("swapQuoteIn", [poolId, BigInt(j),
|
|
925
|
+
throw new Error(`logswap: genesis row j = ${row.j} is not a leg`);
|
|
926
|
+
calls.push(enc(row.side === "buy" ? "swapQuoteIn" : "swapBaseIn", [poolId, BigInt(j), row.amountIn, row.minOut ?? 0n, a.account]));
|
|
915
927
|
}
|
|
916
928
|
// the name, the desk's gates and its list are the POLICY's, not the
|
|
917
929
|
// manager's: they cannot ride in this batch — `fPoolLaunch` and `fPoolDeskOpening` send them
|
|
@@ -919,6 +931,80 @@ export function fPoolLaunchCalls(poolId, a) {
|
|
|
919
931
|
calls.push(...(a.extra ?? []));
|
|
920
932
|
return calls;
|
|
921
933
|
}
|
|
934
|
+
/** The genesis rows in the order they run: `openBuy` first when given, then `openBatch`. Legs as given. */
|
|
935
|
+
export function fPoolGenesisRows(a) {
|
|
936
|
+
return [...(a.openBuy ? [{ side: "buy", ...a.openBuy }] : []), ...(a.openBatch ?? [])];
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* What each genesis row returned, read by simulating the launch's `multicall` on the chain — the
|
|
940
|
+
* contract's own rounding, no re-implementation. Exact at send time: the pool is new, and nothing
|
|
941
|
+
* can trade between the seed and the rows. Needs the creator's funds and allowances, as the launch
|
|
942
|
+
* does. One output per row, in {@link fPoolGenesisRows} order: base for a buy, quote for a sell.
|
|
943
|
+
*/
|
|
944
|
+
export async function fPoolGenesisOutputs(c, poolId, a) {
|
|
945
|
+
const rows = fPoolGenesisRows(a);
|
|
946
|
+
if (rows.length === 0)
|
|
947
|
+
return [];
|
|
948
|
+
const calls = fPoolLaunchCalls(poolId, a);
|
|
949
|
+
const { result } = await c.public.simulateContract({
|
|
950
|
+
address: c.addresses.fPoolManager,
|
|
951
|
+
abi: fPoolManagerAbi,
|
|
952
|
+
functionName: "multicall",
|
|
953
|
+
args: [calls],
|
|
954
|
+
account: signerFor(c, a.account),
|
|
955
|
+
});
|
|
956
|
+
const results = result;
|
|
957
|
+
const first = (a.initialized ? 0 : 1) + 1; // [initialize] · seed · rows
|
|
958
|
+
return rows.map((_, i) => decodeAbiParameters([{ type: "uint256" }], results[first + i])[0]);
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* The transfers that pay the recipients: each row's output (`outs`, aligned with
|
|
962
|
+
* {@link fPoolGenesisRows}) to its `recipient`, summed per (token, recipient), zero amounts dropped.
|
|
963
|
+
* The token is the leg's base for a buy and the quote for a sell. Pure.
|
|
964
|
+
*/
|
|
965
|
+
export function fPoolGenesisTransfers(a, outs) {
|
|
966
|
+
const out = new Map();
|
|
967
|
+
fPoolGenesisRows(a).forEach((row, i) => {
|
|
968
|
+
if (!row.recipient || !outs[i])
|
|
969
|
+
return;
|
|
970
|
+
const token = row.side === "buy" ? a.bases[row.j] : a.quote;
|
|
971
|
+
const k = `${token.toLowerCase()}:${row.recipient.toLowerCase()}`;
|
|
972
|
+
const t = out.get(k);
|
|
973
|
+
if (t)
|
|
974
|
+
t.amount += outs[i];
|
|
975
|
+
else
|
|
976
|
+
out.set(k, { token, to: row.recipient, amount: outs[i] });
|
|
977
|
+
});
|
|
978
|
+
return [...out.values()];
|
|
979
|
+
}
|
|
980
|
+
/** Pay genesis recipients with plain ERC-20 transfers, one transaction each, in order. For a launch that did not deliver itself. */
|
|
981
|
+
export async function fPoolSendGenesisTransfers(c, a) {
|
|
982
|
+
const wallet = requireWallet(c);
|
|
983
|
+
const hashes = [];
|
|
984
|
+
for (const t of a.transfers) {
|
|
985
|
+
const { request } = await c.public.simulateContract({
|
|
986
|
+
address: t.token,
|
|
987
|
+
abi: erc20Abi,
|
|
988
|
+
functionName: "transfer",
|
|
989
|
+
args: [t.to, t.amount],
|
|
990
|
+
account: signerFor(c, a.account),
|
|
991
|
+
});
|
|
992
|
+
hashes.push(await wallet.writeContract(request));
|
|
993
|
+
}
|
|
994
|
+
return hashes;
|
|
995
|
+
}
|
|
996
|
+
/** Whether the wallet runs a batch of calls atomically (EIP-5792 `atomic` capability), on the client's chain. A wallet without it, or one that errors, says no. */
|
|
997
|
+
export async function fPoolWalletBatchesAtomically(c, account) {
|
|
998
|
+
try {
|
|
999
|
+
const wallet = requireWallet(c);
|
|
1000
|
+
const chainId = wallet.chain?.id;
|
|
1001
|
+
const caps = (await wallet.getCapabilities({ account, chainId }));
|
|
1002
|
+
return caps?.atomic?.status === "supported" || caps?.atomic?.status === "ready";
|
|
1003
|
+
}
|
|
1004
|
+
catch {
|
|
1005
|
+
return false;
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
922
1008
|
/**
|
|
923
1009
|
* The desk's opening posture, on its policy: gated minting, the creator a
|
|
924
1010
|
* minter. No appointment: the authority is the operator until one is appointed.
|
|
@@ -951,11 +1037,42 @@ export async function fPoolDeskOpening(c, a) {
|
|
|
951
1037
|
export async function fPoolLaunch(c, a) {
|
|
952
1038
|
const poolId = await fPoolIdOf(c, a);
|
|
953
1039
|
const policy = a.policy ?? fPoolPolicyFor(c, a.kind);
|
|
954
|
-
|
|
955
|
-
|
|
1040
|
+
let args = { ...a, policy };
|
|
1041
|
+
// With recipients, each row's minOut is pinned to its simulated output and the transfers pay
|
|
1042
|
+
// exactly that: a row that returns less reverts the launch, a wei of surplus stays with the creator.
|
|
1043
|
+
let transfers = [];
|
|
1044
|
+
const rows = fPoolGenesisRows(a);
|
|
1045
|
+
if (rows.some((r) => r.recipient)) {
|
|
1046
|
+
const outs = await fPoolGenesisOutputs(c, poolId, args);
|
|
1047
|
+
args = { ...args, openBuy: undefined, openBatch: rows.map((r, i) => ({ ...r, minOut: outs[i] })) };
|
|
1048
|
+
transfers = fPoolGenesisTransfers(args, outs);
|
|
1049
|
+
}
|
|
1050
|
+
const calls = fPoolLaunchCalls(poolId, args);
|
|
1051
|
+
let hash;
|
|
1052
|
+
let delivered = transfers.length === 0;
|
|
1053
|
+
if (transfers.length > 0 && a.deliver !== "followup" && (await fPoolWalletBatchesAtomically(c, a.account))) {
|
|
1054
|
+
const wallet = requireWallet(c);
|
|
1055
|
+
const { id } = await wallet.sendCalls({
|
|
1056
|
+
account: signerFor(c, a.account),
|
|
1057
|
+
forceAtomic: true,
|
|
1058
|
+
calls: [
|
|
1059
|
+
{ to: c.addresses.fPoolManager, data: encodeFunctionData({ abi: fPoolManagerAbi, functionName: "multicall", args: [calls] }) },
|
|
1060
|
+
...transfers.map((t) => ({ to: t.token, data: encodeFunctionData({ abi: erc20Abi, functionName: "transfer", args: [t.to, t.amount] }) })),
|
|
1061
|
+
],
|
|
1062
|
+
});
|
|
1063
|
+
const status = await wallet.waitForCallsStatus({ id });
|
|
1064
|
+
const receipt = status.receipts?.[0];
|
|
1065
|
+
if (status.status !== "success" || !receipt)
|
|
1066
|
+
throw new Error("logswap: the launch batch did not succeed — nothing was created");
|
|
1067
|
+
hash = receipt.transactionHash;
|
|
1068
|
+
delivered = true;
|
|
1069
|
+
}
|
|
1070
|
+
else {
|
|
1071
|
+
hash = await writeFPool0(c, "multicall", [calls], a.account);
|
|
1072
|
+
}
|
|
956
1073
|
if (a.name)
|
|
957
1074
|
await fPoolSetName(c, { poolId, name: a.name, account: a.account, policy });
|
|
958
|
-
return { hash, poolId };
|
|
1075
|
+
return { hash, poolId, transfers, delivered };
|
|
959
1076
|
}
|
|
960
1077
|
// ─── the roles, on the policy ─────────────────────────────────────────────
|
|
961
1078
|
//
|
|
@@ -1151,34 +1268,58 @@ export async function discoverFPools(c, opts = {}) {
|
|
|
1151
1268
|
};
|
|
1152
1269
|
}));
|
|
1153
1270
|
}
|
|
1271
|
+
const MAX_U64 = (1n << 64n) - 1n;
|
|
1272
|
+
const MAX_U128 = (1n << 128n) - 1n;
|
|
1273
|
+
/**
|
|
1274
|
+
* The salt that carries a pad's split (`PadPolicy.pack`, decisions 056): `creatorShare` in the top 64 bits, `burnPerRung` in
|
|
1275
|
+
* the next 64 (WAD fractions), a nonce in the low 128 that tells two otherwise identical pads apart. It is part of the pool's
|
|
1276
|
+
* identity, so it is chosen at launch (`FPoolLaunchArgs.salt`) and never changes; the policy refuses a split outside its ranges.
|
|
1277
|
+
*/
|
|
1278
|
+
export function padSalt(s) {
|
|
1279
|
+
const nonce = s.nonce ?? 0n;
|
|
1280
|
+
if (s.creatorShare < 0n || s.creatorShare > MAX_U64 || s.burnPerRung < 0n || s.burnPerRung > MAX_U64)
|
|
1281
|
+
throw new Error("logswap: a pad's split is a WAD fraction that fits 64 bits");
|
|
1282
|
+
if (nonce < 0n || nonce > MAX_U128)
|
|
1283
|
+
throw new Error("logswap: a pad salt's nonce fits 128 bits");
|
|
1284
|
+
return `0x${((s.creatorShare << 192n) | (s.burnPerRung << 128n) | nonce).toString(16).padStart(64, "0")}`;
|
|
1285
|
+
}
|
|
1286
|
+
/** The inverse of {@link padSalt}. */
|
|
1287
|
+
export function padSplitOfSalt(salt) {
|
|
1288
|
+
const v = BigInt(salt);
|
|
1289
|
+
return { creatorShare: v >> 192n, burnPerRung: (v >> 128n) & MAX_U64, nonce: v & MAX_U128 };
|
|
1290
|
+
}
|
|
1154
1291
|
/** The policy's terms for one pool, by its kind. */
|
|
1155
1292
|
export async function getFPoolRules(c, s, roles) {
|
|
1156
1293
|
const rd = (abi, functionName, args = []) => c.public.readContract({ address: s.policy, abi, functionName, args });
|
|
1157
|
-
const harvestCut = await rd(fPolicyBaseAbi, "harvestCut");
|
|
1158
1294
|
switch (s.kind) {
|
|
1159
1295
|
case "pad": {
|
|
1160
1296
|
// the rung is the manager's generation (F version 21): a move carries it, nothing to ask the policy
|
|
1161
1297
|
const gen = s.gen;
|
|
1162
|
-
const [
|
|
1163
|
-
rd(padPolicyAbi, "
|
|
1164
|
-
rd(padPolicyAbi, "protocolShare"),
|
|
1165
|
-
rd(padPolicyAbi, "burnPerRung"),
|
|
1298
|
+
const [split, pot, threshold, protocolNow, creatorShareMin, creatorShareMax, burnMin, burnMax] = await Promise.all([
|
|
1299
|
+
rd(padPolicyAbi, "splitOf", [s.poolId]),
|
|
1166
1300
|
fPoolDividendOf(c, s.poolId, DEAD_ADDRESS, gen),
|
|
1167
1301
|
rd(padPolicyAbi, "threshold", [BigInt(gen)]),
|
|
1302
|
+
rd(padPolicyAbi, "protocolShare"),
|
|
1303
|
+
rd(padPolicyAbi, "creatorShareMin"),
|
|
1304
|
+
rd(padPolicyAbi, "creatorShareMax"),
|
|
1305
|
+
rd(padPolicyAbi, "burnMin"),
|
|
1306
|
+
rd(padPolicyAbi, "burnMax"),
|
|
1168
1307
|
]);
|
|
1169
|
-
|
|
1308
|
+
const [creatorShare, burnPerRung, protocolShare] = split;
|
|
1309
|
+
const ranges = { protocolShare: protocolNow, creatorShareMin, creatorShareMax, burnMin, burnMax };
|
|
1310
|
+
return { kind: "pad", gen, rung: gen, threshold, pot, creatorShare, protocolShare, burnPerRung, ranges };
|
|
1170
1311
|
}
|
|
1171
1312
|
case "pol": {
|
|
1172
1313
|
const [keepQuote, minQuoteAtSeed] = await Promise.all([rd(polPolicyAbi, "keepQuote"), rd(polPolicyAbi, "minQuoteAtSeed")]);
|
|
1173
|
-
return { kind: "pol",
|
|
1314
|
+
return { kind: "pol", keepQuote, minQuoteAtSeed };
|
|
1174
1315
|
}
|
|
1175
1316
|
case "public": {
|
|
1176
1317
|
const curated = await rd(publicPolicyAbi, "curated");
|
|
1177
|
-
return { kind: "public",
|
|
1318
|
+
return { kind: "public", curated };
|
|
1178
1319
|
}
|
|
1179
1320
|
case "private": {
|
|
1180
1321
|
const r = roles ?? (await getFPoolRoles(c, s.poolId, s));
|
|
1181
|
-
return { kind: "private",
|
|
1322
|
+
return { kind: "private", gateMint: r.gateMint, gateSwap: r.gateSwap, operator: fPoolOperatorOf(r) };
|
|
1182
1323
|
}
|
|
1183
1324
|
}
|
|
1184
1325
|
}
|