@logswap/sdk 0.5.37 → 0.5.38

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/fpool.js CHANGED
@@ -67,7 +67,7 @@ export async function getFPool(c, poolId) {
67
67
  const weights = legs.map((l) => l[1]);
68
68
  const x = legs.map((l) => l[2]); // derived by the manager: x_j = ln(w_j·L / R_j) (decisions 026)
69
69
  const reserves = legs.map((l) => l[3]); // the state
70
- const { quote, Q, L, phi, theta0, bigSigma, authority, pendingAuthority, operator, minBuffer, gateMint, gateSwap, restructureBlock, lockStrike, seeded, dissolved, successor } = p;
70
+ const { quote, Q, L, phi, theta0, bigSigma, authority, pendingAuthority, operator, minBuffer, gateMint, gateSwap, restructureBlock, lockStrike, seeded, gen } = p;
71
71
  const totalSupply = p.shares;
72
72
  return {
73
73
  poolId,
@@ -92,8 +92,7 @@ export async function getFPool(c, poolId) {
92
92
  restructureBlock: Number(restructureBlock),
93
93
  lockStrike,
94
94
  seeded,
95
- dissolved,
96
- successor,
95
+ gen: Number(gen),
97
96
  totalSupply,
98
97
  reserves,
99
98
  };
@@ -208,31 +207,33 @@ export async function fPoolZapOut(c, a) {
208
207
  return writeRouter(c, "zapOut", [a.poolId, a.shares, a.tokenOut, a.minOut ?? 0n, to, a.deadline ?? defaultDeadline()], a.account);
209
208
  }
210
209
  /**
211
- * Roll a dissolved pool's bundle into its successor (decisions 025), on the router under one
212
- * lock: burn `shares` of `fromPool` in place — the legs, the quote and any unpulled dividend come
213
- * back — buy through `toPool`'s own curve only what its ratio lacks, mint `dL` of it to `to`, and
214
- * refund the rest in kind. Quote the bundle does not cover is pulled from the payer, at most
215
- * `maxQuoteIn`; surplus base is refunded, never sold. Size `dL` with {@link fPoolPreviewRollIn}.
216
- * The router must be the caller's ERC-6909 operator ({@link approveRouterForFPool}).
210
+ * Roll a retired generation's bundle into the pool's live one (decisions 025, 032), on the
211
+ * router under one lock: redeem `shares` of generation `gen` in place — the legs, the quote and
212
+ * any unpulled dividend come back — buy through the pool's own curve only what the live
213
+ * generation's ratio lacks, mint `dL` of it to `to`, and refund the rest in kind. Quote the
214
+ * bundle does not cover is pulled from the payer, at most `maxQuoteIn`; surplus base is
215
+ * refunded, never sold. Size `dL` with {@link fPoolPreviewRollIn}. The router must be the
216
+ * caller's ERC-6909 operator ({@link approveRouterForFPool}).
217
217
  */
218
218
  export async function fPoolRollIn(c, a) {
219
219
  const to = a.to ?? a.account;
220
- return writeRouter(c, "rollIn", [a.fromPool, a.toPool, a.shares, a.dL, a.maxQuoteIn ?? 0n, a.minShares ?? 0n, to, a.deadline ?? defaultDeadline()], a.account);
220
+ return writeRouter(c, "rollIn", [a.poolId, BigInt(a.gen), a.shares, a.dL, a.maxQuoteIn ?? 0n, a.minShares ?? 0n, to, a.deadline ?? defaultDeadline()], a.account);
221
221
  }
222
222
  /**
223
- * The roll `holder`'s `shares` of `fromPool` fund into `toPool` WITHOUT a trade: the largest `dL`
224
- * the bundle's base covers on every successor leg, and the quote the bundle is short of (pass it
225
- * as `maxQuoteIn`) or over (refunded — the up direction's distribution) at that `dL`. A
226
- * successor leg the bundle does not hold makes `dL` zero: such a roll must buy, so size it below
227
- * with `previewZapIn` in mind.
223
+ * The roll `holder`'s `shares` of retired generation `gen` fund into the live one WITHOUT a
224
+ * trade: the largest `dL` the bundle's base covers on every leg, and the quote the bundle is
225
+ * short of (pass it as `maxQuoteIn`) or over (refunded — the up direction's distribution) at
226
+ * that `dL`. A leg the live generation admitted since makes `dL` zero: such a roll must buy, so
227
+ * size it below with `previewZapIn` in mind. Zero for the live generation, or before the next
228
+ * seed.
228
229
  */
229
- export async function fPoolPreviewRollIn(c, fromPool, toPool, holder, shares) {
230
+ export async function fPoolPreviewRollIn(c, poolId, gen, holder, shares) {
230
231
  const { logswapLensAbi } = await import("./generated.js");
231
232
  const [dL, quoteShort, quoteExcess] = (await c.public.readContract({
232
233
  address: c.addresses.lens,
233
234
  abi: logswapLensAbi,
234
235
  functionName: "previewRollIn",
235
- args: [fromPool, toPool, holder, shares],
236
+ args: [poolId, BigInt(gen), holder, shares],
236
237
  }));
237
238
  return { dL, quoteShort, quoteExcess };
238
239
  }
@@ -247,17 +248,23 @@ export async function fPoolPreviewRollIn(c, fromPool, toPool, holder, shares) {
247
248
  export async function fPoolHarvest(c, a) {
248
249
  return writeFPool(c, a.poolId, "harvest", [a.amount, a.to ?? a.account], a.account);
249
250
  }
250
- /** Pull one's settled dividend (decisions 028) without moving shares; anyone with shares. */
251
+ /**
252
+ * Pull one's settled dividend (decisions 028) on a generation's shares without moving them;
253
+ * anyone with shares. `gen` defaults to the live generation; a retired generation's harvests
254
+ * stay claimable under its own id (decisions 032).
255
+ */
251
256
  export async function fPoolClaim(c, a) {
252
- return writeFPool(c, a.poolId, "claim", [a.to ?? a.account], a.account);
257
+ const gen = a.gen ?? (await fPoolGen(c, a.poolId));
258
+ return writeFPool(c, a.poolId, "claim", [BigInt(gen), a.to ?? a.account], a.account);
253
259
  }
254
- /** A holder's dividend as of now — banked plus pending on the current balance (decisions 028). */
255
- export async function fPoolDividendOf(c, poolId, holder) {
260
+ /** A holder's dividend as of now on generation `gen` (the live one by default) — banked plus pending on the current balance (decisions 028). */
261
+ export async function fPoolDividendOf(c, poolId, holder, gen) {
262
+ const g = gen ?? (await fPoolGen(c, poolId));
256
263
  return c.public.readContract({
257
264
  address: c.addresses.fPoolManager,
258
265
  abi: fPoolManagerAbi,
259
266
  functionName: "dividendOf",
260
- args: [poolId, holder],
267
+ args: [poolId, BigInt(g), holder],
261
268
  });
262
269
  }
263
270
  /** The lever's floor: `harvest` may not take Q/L under ln 1.25 — the floor stays ≥ 20% below the mark (decisions 025). */
@@ -386,22 +393,71 @@ export async function approveRouterForFPool(c, account) {
386
393
  // One ERC-6909 space, split structurally on bit 255 — the C manager's scheme. Derived here rather
387
394
  // than read from the chain: it is pure, and a client that has to call to learn an id cannot build
388
395
  // a multicall that uses it.
389
- /** The ERC-6909 id carrying a pool's shares. Bit 255 set. */
390
- export function fPoolShareId(poolId) {
391
- return (1n << 255n) | (BigInt(poolId) >> 1n);
396
+ /**
397
+ * The ERC-6909 id carrying generation `gen` of a pool's shares (decisions 032): bit 255 set (the
398
+ * share flag), the pool id's top 239 bits, the generation in the low 16. Each generation's shares
399
+ * are their own asset — a retired one is a claim on its bundle, the live one on the pool.
400
+ */
401
+ export function fPoolShareId(poolId, gen = 0n) {
402
+ return (1n << 255n) | ((BigInt(poolId) >> 17n) << 16n) | BigInt(gen);
403
+ }
404
+ /** The generation a share id carries — its low 16 bits. */
405
+ export function fPoolGenOfShareId(id) {
406
+ return Number(id & 0xffffn);
407
+ }
408
+ /** The pool's live generation, one read. */
409
+ export async function fPoolGen(c, poolId) {
410
+ const p = (await c.public.readContract({
411
+ address: c.addresses.fPoolManager,
412
+ abi: fPoolManagerAbi,
413
+ functionName: "getPool",
414
+ args: [poolId],
415
+ }));
416
+ return Number(p.gen);
392
417
  }
393
418
  /** The ERC-6909 id carrying claims on a token. Bit 255 clear, so it can never meet a share id. */
394
419
  export function fPoolClaimId(token) {
395
420
  return BigInt(token);
396
421
  }
397
- export async function fPoolShareBalance(c, poolId, owner) {
422
+ /** A holder's shares of generation `gen` — the live one by default. */
423
+ export async function fPoolShareBalance(c, poolId, owner, gen) {
424
+ const g = gen ?? (await fPoolGen(c, poolId));
398
425
  return c.public.readContract({
399
426
  address: c.addresses.fPoolManager,
400
427
  abi: fPoolManagerAbi,
401
428
  functionName: "balanceOf",
402
- args: [owner, fPoolShareId(poolId)],
429
+ args: [owner, fPoolShareId(poolId, g)],
403
430
  });
404
431
  }
432
+ /** A retired generation's bundle (decisions 032): what is left to redeem — supply, quote, base per leg index. */
433
+ export async function fPoolBundleOf(c, poolId, gen) {
434
+ const [supply, quote, base] = (await c.public.readContract({
435
+ address: c.addresses.fPoolManager,
436
+ abi: fPoolManagerAbi,
437
+ functionName: "bundleOf",
438
+ args: [poolId, BigInt(gen)],
439
+ }));
440
+ return { supply, quote, base: [...base] };
441
+ }
442
+ /** A holder's claims on a pool's retired generations — one row per generation still held (decisions 032). */
443
+ export async function fPoolClaimsOf(c, poolId, owner) {
444
+ const { logswapLensAbi } = await import("./generated.js");
445
+ const rows = (await c.public.readContract({
446
+ address: c.addresses.lens,
447
+ abi: logswapLensAbi,
448
+ functionName: "fClaimsOf",
449
+ args: [poolId, owner],
450
+ }));
451
+ return rows.map((r) => ({ gen: Number(r.gen), shares: r.shares, base: [...r.base], quote: r.quote, dividend: r.dividend }));
452
+ }
453
+ /**
454
+ * Redeem `shares` of a RETIRED generation (decisions 032): its bundle, pro rata — the base per
455
+ * leg and the quote — plus the owner's settled dividend. Not `burn`: nothing can move a bundle's
456
+ * ratio, so there is no slippage to bound. The owner, or an operator of theirs.
457
+ */
458
+ export async function fPoolRedeem(c, a) {
459
+ return writeFPool(c, a.poolId, "redeem", [BigInt(a.gen), a.owner ?? a.account, a.shares], a.account);
460
+ }
405
461
  export async function fPoolClaimBalance(c, token, owner) {
406
462
  return c.public.readContract({
407
463
  address: c.addresses.fPoolManager,
@@ -544,36 +600,31 @@ export async function fPoolSeed(c, a) {
544
600
  return writeFPool(c, a.poolId, "seed", [a.L0, r0, a.Q0], a.account);
545
601
  }
546
602
  /**
547
- * End of life (decisions 025). Allowed at Q ≤ L/1e9 on every pool — the market filled the ask —
548
- * and on a pool that is not strike-locked at any Q, provided `successor` names an initialized
549
- * pool of the same authority and quote: the relaunch. After it every share is a frozen in-kind
550
- * claim redeemed by `burn` (or rolled with {@link fPoolRollIn}), forever; the pool's `successor`
551
- * carries the lineage. Never a second dissolve on one pool: the successor is a NEW pool.
603
+ * Retire the live generation (decisions 025, 032). Allowed at Q ≤ L/1e9 on every pool — the
604
+ * market filled the ask — and on a pool that is not strike-locked at any Q. The live (S, Q, R_j)
605
+ * become a frozen bundle every share of this generation redeems ({@link fPoolRedeem}) or rolls
606
+ * ({@link fPoolRollIn}), forever; the pool is unseeded until the next {@link fPoolSeed}, which
607
+ * opens generation `gen + 1` under the same id, gates, lists and promises.
552
608
  */
553
609
  export async function fPoolDissolve(c, a) {
554
- return writeFPool(c, a.poolId, "dissolve", [a.successor ?? ZERO_SALT], a.account);
610
+ return writeFPool(c, a.poolId, "dissolve", [], a.account);
555
611
  }
556
612
  /**
557
- * The sponsor's relaunch as ONE transaction (decisions 025): `initialize` the successor key,
558
- * `dissolve` the old pool into it, `burn` the sponsor's own shares, `seed` the successor with what
559
- * came back — the manager's `multicall`, the sponsor as sender throughout. Gates, allowlist,
560
- * operator, floor guard and name are re-applied afterwards, or appended to `extra` pre-encoded
561
- * against {@link fPoolManagerAbi}. Returns the tx hash; the successor's id is {@link fPoolIdOf}
562
- * of `nextKey`.
613
+ * The sponsor's relaunch as ONE transaction (decisions 025, 032): `dissolve` the live generation,
614
+ * `redeem` the sponsor's own shares of it (when `shares` > 0), `seed` the next generation with
615
+ * what came back — the manager's `multicall`, the sponsor as sender throughout, the same pool.
616
+ * Gates, allowlist, operator, `minBuffer` and names carry over; anything else goes in `extra`,
617
+ * pre-encoded against {@link fPoolManagerAbi}. The seed names reserves (decisions 029): `r0`
618
+ * outright, or `x0` marks against the key's `weights`.
563
619
  */
564
620
  export async function fPoolRelaunch(c, a) {
565
- const { bases, companions } = sortFPoolLegs(a.nextKey.bases, a.nextKey.weights);
566
- const key = {
567
- quote: a.nextKey.quote, bases, weights: companions[0], phi: a.nextKey.phi, lockStrike: a.nextKey.lockStrike,
568
- authority: a.nextKey.authority, salt: a.nextKey.salt ?? ZERO_SALT,
569
- };
570
- const next = await fPoolIdOf(c, a.nextKey);
621
+ const gen = await fPoolGen(c, a.poolId);
622
+ const r0 = "r0" in a ? a.r0 : a.x0.map((x, j) => fPoolReserveAt((a.weights[j] * a.L0) / WAD, x));
571
623
  const enc = (functionName, args) => encodeFunctionData({ abi: fPoolManagerAbi, functionName, args });
572
624
  const calls = [
573
- enc("initialize", [key]),
574
- enc("dissolve", [a.poolId, next]),
575
- enc("burn", [a.poolId, a.account, a.shares, 0n]),
576
- enc("seed", [next, a.L0, a.r0, a.Q0]),
625
+ enc("dissolve", [a.poolId]),
626
+ ...(a.shares > 0n ? [enc("redeem", [a.poolId, BigInt(gen), a.account, a.shares])] : []),
627
+ enc("seed", [a.poolId, a.L0, r0, a.Q0]),
577
628
  ...(a.extra ?? []),
578
629
  ];
579
630
  return writeFPool0(c, "multicall", [calls], a.account);
@@ -669,11 +720,12 @@ export async function fPoolAdmitLeg(c, a) {
669
720
  */
670
721
  export async function fPoolTransferShares(c, a) {
671
722
  const wallet = requireWallet(c);
723
+ const gen = a.gen ?? (await fPoolGen(c, a.poolId));
672
724
  const { request } = await c.public.simulateContract({
673
725
  address: c.addresses.fPoolManager,
674
726
  abi: fPoolManagerAbi,
675
727
  functionName: "transfer",
676
- args: [a.to, fPoolShareId(a.poolId), a.shares],
728
+ args: [a.to, fPoolShareId(a.poolId, gen), a.shares],
677
729
  account: a.account,
678
730
  });
679
731
  return wallet.writeContract(request);
@@ -731,7 +783,7 @@ export async function fPoolShareHolders(c, poolIdHex, opts = {}) {
731
783
  const ev = fPoolManagerAbi.find((x) => x.type === "event" && x.name === "Transfer");
732
784
  if (!ev)
733
785
  throw new Error("logswap: 6909 Transfer event missing from the generated ABI");
734
- const id = fPoolShareId(poolIdHex);
786
+ const id = fPoolShareId(poolIdHex, opts.gen ?? (await fPoolGen(c, poolIdHex)));
735
787
  const logs = await c.public.getLogs({
736
788
  address: c.addresses.fPoolManager,
737
789
  event: ev,
@@ -752,7 +804,7 @@ export async function fPoolShareHolders(c, poolIdHex, opts = {}) {
752
804
  .map(([holder, shares]) => ({ holder: holder, shares }))
753
805
  .sort((a, b) => (b.shares > a.shares ? 1 : -1));
754
806
  }
755
- /** Every F pool's state in one lens call (the raw manager struct: quote, phi, authority, lockStrike, seeded, dissolved, successor, n, Q, L, shares, theta0, bigSigma, leverTheta). */
807
+ /** Every F pool's state in one lens call (the raw manager struct: quote, phi, authority, lockStrike, seeded, gen, n, Q, L, shares, theta0, bigSigma, leverTheta). */
756
808
  export async function getFPoolsRaw(c, poolIds) {
757
809
  const { logswapLensAbi } = await import("./generated.js");
758
810
  return (await c.public.readContract({ address: c.addresses.lens, abi: logswapLensAbi, functionName: "getFPools", args: [poolIds] }));