@logswap/sdk 0.5.38 → 0.5.40

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.d.ts CHANGED
@@ -464,7 +464,7 @@ export declare const fPoolManagerAbi: readonly [{
464
464
  readonly internalType: "int256";
465
465
  readonly type: "int256";
466
466
  }, {
467
- readonly name: "leverTheta";
467
+ readonly name: "harvestedTheta";
468
468
  readonly internalType: "int256";
469
469
  readonly type: "int256";
470
470
  }, {
@@ -1357,26 +1357,6 @@ export declare const fPoolManagerAbi: readonly [{
1357
1357
  readonly indexed: true;
1358
1358
  }];
1359
1359
  readonly name: "CollectorProposed";
1360
- }, {
1361
- readonly type: "event";
1362
- readonly anonymous: false;
1363
- readonly inputs: readonly [{
1364
- readonly name: "poolId";
1365
- readonly internalType: "bytes32";
1366
- readonly type: "bytes32";
1367
- readonly indexed: true;
1368
- }, {
1369
- readonly name: "from";
1370
- readonly internalType: "address";
1371
- readonly type: "address";
1372
- readonly indexed: true;
1373
- }, {
1374
- readonly name: "amount";
1375
- readonly internalType: "uint256";
1376
- readonly type: "uint256";
1377
- readonly indexed: false;
1378
- }];
1379
- readonly name: "Deepen";
1380
1360
  }, {
1381
1361
  readonly type: "event";
1382
1362
  readonly anonymous: false;
@@ -2343,20 +2323,6 @@ export declare const fPoolManagerAbi: readonly [{
2343
2323
  readonly type: "uint8";
2344
2324
  }];
2345
2325
  readonly stateMutability: "view";
2346
- }, {
2347
- readonly type: "function";
2348
- readonly inputs: readonly [{
2349
- readonly name: "poolId";
2350
- readonly internalType: "bytes32";
2351
- readonly type: "bytes32";
2352
- }, {
2353
- readonly name: "amount";
2354
- readonly internalType: "uint256";
2355
- readonly type: "uint256";
2356
- }];
2357
- readonly name: "deepen";
2358
- readonly outputs: readonly [];
2359
- readonly stateMutability: "nonpayable";
2360
2326
  }, {
2361
2327
  readonly type: "function";
2362
2328
  readonly inputs: readonly [{
@@ -3070,26 +3036,6 @@ export declare const fPoolManagerAbi: readonly [{
3070
3036
  readonly indexed: true;
3071
3037
  }];
3072
3038
  readonly name: "CollectorProposed";
3073
- }, {
3074
- readonly type: "event";
3075
- readonly anonymous: false;
3076
- readonly inputs: readonly [{
3077
- readonly name: "poolId";
3078
- readonly internalType: "bytes32";
3079
- readonly type: "bytes32";
3080
- readonly indexed: true;
3081
- }, {
3082
- readonly name: "from";
3083
- readonly internalType: "address";
3084
- readonly type: "address";
3085
- readonly indexed: true;
3086
- }, {
3087
- readonly name: "amount";
3088
- readonly internalType: "uint256";
3089
- readonly type: "uint256";
3090
- readonly indexed: false;
3091
- }];
3092
- readonly name: "Deepen";
3093
3039
  }, {
3094
3040
  readonly type: "event";
3095
3041
  readonly anonymous: false;
@@ -3963,12 +3909,6 @@ export declare function fPoolClaim(c: LogswapClient, a: {
3963
3909
  export declare function fPoolDividendOf(c: LogswapClient, poolId: Hex, holder: Address, gen?: bigint | number): Promise<bigint>;
3964
3910
  /** The lever's floor: `harvest` may not take Q/L under ln 1.25 — the floor stays ≥ 20% below the mark (decisions 025). */
3965
3911
  export declare const LEVER_FLOOR = 223143551314209755n;
3966
- /** Commit quote, deepening θ — the other sign of `harvest`, the same word as the C floor edit (decisions 011). The mark does not move: governance may write θ, never x. */
3967
- export declare function fPoolDeepen(c: LogswapClient, a: {
3968
- poolId: Hex;
3969
- amount: bigint;
3970
- account: Address;
3971
- }): Promise<`0x${string}`>;
3972
3912
  /** Plain ERC-20 approval to the F manager — the allowance every DIRECT call pulls against. */
3973
3913
  export declare function approveTokenForFPoolManager(c: LogswapClient, token: Address): Promise<Hash>;
3974
3914
  /** Does `owner` have enough allowance on `token` for the MANAGER to pull `need`? */
@@ -4131,6 +4071,82 @@ export declare function fPoolRelaunch(c: LogswapClient, a: {
4131
4071
  x0: bigint[];
4132
4072
  weights: bigint[];
4133
4073
  })): Promise<`0x${string}`>;
4074
+ /** ERC-6909 shares sent here are locked for good — the seed's custody (custody.md §4(b)). */
4075
+ export declare const DEAD_ADDRESS: Address;
4076
+ /** The manager's `MIN_SHARES`: the seed mints this much to 0xdead itself, the rest to the seeder. */
4077
+ export declare const F_MIN_SHARES = 1000n;
4078
+ export interface FPoolLaunchArgs extends Omit<FPoolCreateArgs, "account"> {
4079
+ L0: bigint;
4080
+ /** Quote the seed pulls. A pad seeds at 0 — pure float, a resting ask, nothing raised. */
4081
+ Q0: bigint;
4082
+ /**
4083
+ * Send every share the seed mints to the creator (`L0 − MIN_SHARES`) to 0xdead in the same
4084
+ * batch: the float and the raise can never be burned out from under the buyers. The lever
4085
+ * (harvest) is the authority's and survives it; the exit does not. A pad's default posture.
4086
+ */
4087
+ lockSeed?: boolean;
4088
+ /**
4089
+ * An opening buy of leg `j` (an index into `bases` AS GIVEN) for `amountIn` of quote, ON THE
4090
+ * MANAGER — the same sender, a plain allowance to the manager, the router nowhere near it. A
4091
+ * pad seeds at Q = 0, so until someone trades it the mark sits at p₀; buying inside the launch
4092
+ * gives it a price that has moved and a buffer under it. Nothing can trade between the seed and
4093
+ * this buy — they are one transaction — so `minOut` is safe at its default of 0.
4094
+ */
4095
+ openBuy?: {
4096
+ j: number;
4097
+ amountIn: bigint;
4098
+ minOut?: bigint;
4099
+ };
4100
+ /** The pool's label, set in the batch (≤ 31 bytes of UTF-8). */
4101
+ name?: string;
4102
+ /** Gate minting, list the creator, appoint them operator (decisions 021) — three calls, in the batch. */
4103
+ privatePool?: boolean;
4104
+ /**
4105
+ * The pool already exists (a previous launch got as far as `initialize` and no further — a seed
4106
+ * that reverted, a closed tab, before the launch was one transaction), so `initialize` is left
4107
+ * out: the key is a pure function of the arguments and a second `initialize` can only revert.
4108
+ */
4109
+ initialized?: boolean;
4110
+ /** Anything else, pre-encoded against {@link fPoolManagerAbi}, appended after the above. */
4111
+ extra?: Hex[];
4112
+ account: Address;
4113
+ }
4114
+ /**
4115
+ * The launch's calls, in order — the batch {@link fPoolLaunch} sends. Pure, so a form can show
4116
+ * what it is about to send, and a test can decode it. Legs are sorted here with their weights and
4117
+ * reserves (the key's canonical order; `openBuy.j` is re-indexed to match), and the weights are
4118
+ * checked here, where the message is readable.
4119
+ */
4120
+ export declare function fPoolLaunchCalls(poolId: Hex, a: FPoolLaunchArgs & ({
4121
+ r0: bigint[];
4122
+ } | {
4123
+ x0: bigint[];
4124
+ })): Hex[];
4125
+ /**
4126
+ * Create a pool as ONE transaction: `initialize`, `seed`, the seed lock, the opening buy, the
4127
+ * name, the private-pool gates — the manager's `multicall`, the creator as sender throughout.
4128
+ * Either every call lands or none does; there is no half-built pool to resume.
4129
+ *
4130
+ * Why the manager and not the router: every one of these entries authenticates by `msg.sender`
4131
+ * (`seed` is authority-only, so is everything after it). Routed, the router would be the sender
4132
+ * — the authority, the holder of the seed shares — and the handover back is two-step, so it
4133
+ * could not even close in the same transaction. `multicall` is delegatecall-to-self, so the
4134
+ * sender survives, which is what the manager's own doc says a router cannot do.
4135
+ *
4136
+ * What the batch PULLS, by plain allowance to the manager (never Permit2): `r0[j]` of each base,
4137
+ * `Q0` of quote, plus `openBuy.amountIn` of quote. Grant those first — one `approve` per token,
4138
+ * once ever ({@link approveTokenForFPoolManager}, {@link fPoolManagerAllowanceOk}).
4139
+ *
4140
+ * Returns the hash and the pool's id (the key's hash, {@link fPoolIdOf}).
4141
+ */
4142
+ export declare function fPoolLaunch(c: LogswapClient, a: FPoolLaunchArgs & ({
4143
+ r0: bigint[];
4144
+ } | {
4145
+ x0: bigint[];
4146
+ })): Promise<{
4147
+ hash: Hash;
4148
+ poolId: Hex;
4149
+ }>;
4134
4150
  /**
4135
4151
  * Propose the next authority — step one of two (contracts `2aa6b7b`, decisions 020). Nothing moves
4136
4152
  * until `next` accepts; proposing again (the zero address included) cancels a pending proposal.
@@ -4271,7 +4287,7 @@ export declare function fPoolShareHolders(c: LogswapClient, poolIdHex: Hex, opts
4271
4287
  holder: Address;
4272
4288
  shares: bigint;
4273
4289
  }>>;
4274
- /** 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). */
4290
+ /** 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, harvestedTheta). */
4275
4291
  export declare function getFPoolsRaw(c: LogswapClient, poolIds: Hex[]): Promise<readonly unknown[]>;
4276
4292
  /** Share value from the lens — (L + Q)/shares, WAD per share — the same figure as `fPoolShareValue`, from one source. */
4277
4293
  export declare function shareValueOnChain(c: LogswapClient, poolId: Hex): Promise<bigint>;
package/dist/fpool.js CHANGED
@@ -269,10 +269,6 @@ export async function fPoolDividendOf(c, poolId, holder, gen) {
269
269
  }
270
270
  /** The lever's floor: `harvest` may not take Q/L under ln 1.25 — the floor stays ≥ 20% below the mark (decisions 025). */
271
271
  export const LEVER_FLOOR = 223143551314209755n;
272
- /** Commit quote, deepening θ — the other sign of `harvest`, the same word as the C floor edit (decisions 011). The mark does not move: governance may write θ, never x. */
273
- export async function fPoolDeepen(c, a) {
274
- return writeFPool(c, a.poolId, "deepen", [a.amount], a.account);
275
- }
276
272
  // ─── internals ────────────────────────────────────────────────────────────────
277
273
  function defaultDeadline() {
278
274
  return BigInt(Math.floor(Date.now() / 1000) + 1800);
@@ -629,6 +625,71 @@ export async function fPoolRelaunch(c, a) {
629
625
  ];
630
626
  return writeFPool0(c, "multicall", [calls], a.account);
631
627
  }
628
+ /** ERC-6909 shares sent here are locked for good — the seed's custody (custody.md §4(b)). */
629
+ export const DEAD_ADDRESS = "0x000000000000000000000000000000000000dEaD";
630
+ /** The manager's `MIN_SHARES`: the seed mints this much to 0xdead itself, the rest to the seeder. */
631
+ export const F_MIN_SHARES = 1000n;
632
+ /**
633
+ * The launch's calls, in order — the batch {@link fPoolLaunch} sends. Pure, so a form can show
634
+ * what it is about to send, and a test can decode it. Legs are sorted here with their weights and
635
+ * reserves (the key's canonical order; `openBuy.j` is re-indexed to match), and the weights are
636
+ * checked here, where the message is readable.
637
+ */
638
+ export function fPoolLaunchCalls(poolId, a) {
639
+ const sum = a.weights.reduce((x, y) => x + y, 0n);
640
+ if (sum !== WAD)
641
+ throw new Error(`logswap: weights sum to ${sum}, expected 1e18`);
642
+ const given = "r0" in a ? a.r0 : a.x0.map((x, j) => fPoolReserveAt((a.weights[j] * a.L0) / WAD, x));
643
+ if (given.length !== a.bases.length)
644
+ throw new Error(`logswap: ${given.length} reserves for ${a.bases.length} legs`);
645
+ const { bases, companions } = sortFPoolLegs(a.bases, a.weights, given);
646
+ const key = { quote: a.quote, bases, weights: companions[0], phi: a.phi, lockStrike: a.lockStrike, authority: a.authority, salt: a.salt ?? ZERO_SALT };
647
+ const enc = (functionName, args) => encodeFunctionData({ abi: fPoolManagerAbi, functionName, args });
648
+ const calls = [];
649
+ if (!a.initialized)
650
+ calls.push(enc("initialize", [key]));
651
+ calls.push(enc("seed", [poolId, a.L0, companions[1], a.Q0]));
652
+ // gen 0 by construction: a launch is the pool's FIRST seed — a relaunch is `fPoolRelaunch`
653
+ if (a.lockSeed)
654
+ calls.push(enc("transfer", [DEAD_ADDRESS, fPoolShareId(poolId, 0), a.L0 - F_MIN_SHARES]));
655
+ if (a.openBuy) {
656
+ const j = bases.indexOf(a.bases[a.openBuy.j]);
657
+ if (j < 0)
658
+ throw new Error(`logswap: openBuy.j = ${a.openBuy.j} is not a leg`);
659
+ calls.push(enc("swapQuoteIn", [poolId, BigInt(j), a.openBuy.amountIn, a.openBuy.minOut ?? 0n, a.account]));
660
+ }
661
+ if (a.name)
662
+ calls.push(enc("setName", [poolId, textToBytes32(a.name)]));
663
+ if (a.privatePool) {
664
+ calls.push(enc("setGates", [poolId, true, false]));
665
+ calls.push(enc("setAllowed", [poolId, [a.account], true]));
666
+ calls.push(enc("appointOperator", [poolId, a.account]));
667
+ }
668
+ calls.push(...(a.extra ?? []));
669
+ return calls;
670
+ }
671
+ /**
672
+ * Create a pool as ONE transaction: `initialize`, `seed`, the seed lock, the opening buy, the
673
+ * name, the private-pool gates — the manager's `multicall`, the creator as sender throughout.
674
+ * Either every call lands or none does; there is no half-built pool to resume.
675
+ *
676
+ * Why the manager and not the router: every one of these entries authenticates by `msg.sender`
677
+ * (`seed` is authority-only, so is everything after it). Routed, the router would be the sender
678
+ * — the authority, the holder of the seed shares — and the handover back is two-step, so it
679
+ * could not even close in the same transaction. `multicall` is delegatecall-to-self, so the
680
+ * sender survives, which is what the manager's own doc says a router cannot do.
681
+ *
682
+ * What the batch PULLS, by plain allowance to the manager (never Permit2): `r0[j]` of each base,
683
+ * `Q0` of quote, plus `openBuy.amountIn` of quote. Grant those first — one `approve` per token,
684
+ * once ever ({@link approveTokenForFPoolManager}, {@link fPoolManagerAllowanceOk}).
685
+ *
686
+ * Returns the hash and the pool's id (the key's hash, {@link fPoolIdOf}).
687
+ */
688
+ export async function fPoolLaunch(c, a) {
689
+ const poolId = await fPoolIdOf(c, a);
690
+ const hash = await writeFPool0(c, "multicall", [fPoolLaunchCalls(poolId, a)], a.account);
691
+ return { hash, poolId };
692
+ }
632
693
  /**
633
694
  * Propose the next authority — step one of two (contracts `2aa6b7b`, decisions 020). Nothing moves
634
695
  * until `next` accepts; proposing again (the zero address included) cancels a pending proposal.
@@ -804,7 +865,7 @@ export async function fPoolShareHolders(c, poolIdHex, opts = {}) {
804
865
  .map(([holder, shares]) => ({ holder: holder, shares }))
805
866
  .sort((a, b) => (b.shares > a.shares ? 1 : -1));
806
867
  }
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). */
868
+ /** 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, harvestedTheta). */
808
869
  export async function getFPoolsRaw(c, poolIds) {
809
870
  const { logswapLensAbi } = await import("./generated.js");
810
871
  return (await c.public.readContract({ address: c.addresses.lens, abi: logswapLensAbi, functionName: "getFPools", args: [poolIds] }));
@@ -2223,7 +2223,7 @@ export declare const fPoolManagerAbi: readonly [{
2223
2223
  readonly internalType: "int256";
2224
2224
  readonly type: "int256";
2225
2225
  }, {
2226
- readonly name: "leverTheta";
2226
+ readonly name: "harvestedTheta";
2227
2227
  readonly internalType: "int256";
2228
2228
  readonly type: "int256";
2229
2229
  }, {
@@ -3116,26 +3116,6 @@ export declare const fPoolManagerAbi: readonly [{
3116
3116
  readonly indexed: true;
3117
3117
  }];
3118
3118
  readonly name: "CollectorProposed";
3119
- }, {
3120
- readonly type: "event";
3121
- readonly anonymous: false;
3122
- readonly inputs: readonly [{
3123
- readonly name: "poolId";
3124
- readonly internalType: "bytes32";
3125
- readonly type: "bytes32";
3126
- readonly indexed: true;
3127
- }, {
3128
- readonly name: "from";
3129
- readonly internalType: "address";
3130
- readonly type: "address";
3131
- readonly indexed: true;
3132
- }, {
3133
- readonly name: "amount";
3134
- readonly internalType: "uint256";
3135
- readonly type: "uint256";
3136
- readonly indexed: false;
3137
- }];
3138
- readonly name: "Deepen";
3139
3119
  }, {
3140
3120
  readonly type: "event";
3141
3121
  readonly anonymous: false;
@@ -4103,20 +4083,6 @@ export declare const fPoolSponsorAbi: readonly [{
4103
4083
  readonly type: "uint8";
4104
4084
  }];
4105
4085
  readonly stateMutability: "view";
4106
- }, {
4107
- readonly type: "function";
4108
- readonly inputs: readonly [{
4109
- readonly name: "poolId";
4110
- readonly internalType: "bytes32";
4111
- readonly type: "bytes32";
4112
- }, {
4113
- readonly name: "amount";
4114
- readonly internalType: "uint256";
4115
- readonly type: "uint256";
4116
- }];
4117
- readonly name: "deepen";
4118
- readonly outputs: readonly [];
4119
- readonly stateMutability: "nonpayable";
4120
4086
  }, {
4121
4087
  readonly type: "function";
4122
4088
  readonly inputs: readonly [{
@@ -4830,26 +4796,6 @@ export declare const fPoolSponsorAbi: readonly [{
4830
4796
  readonly indexed: true;
4831
4797
  }];
4832
4798
  readonly name: "CollectorProposed";
4833
- }, {
4834
- readonly type: "event";
4835
- readonly anonymous: false;
4836
- readonly inputs: readonly [{
4837
- readonly name: "poolId";
4838
- readonly internalType: "bytes32";
4839
- readonly type: "bytes32";
4840
- readonly indexed: true;
4841
- }, {
4842
- readonly name: "from";
4843
- readonly internalType: "address";
4844
- readonly type: "address";
4845
- readonly indexed: true;
4846
- }, {
4847
- readonly name: "amount";
4848
- readonly internalType: "uint256";
4849
- readonly type: "uint256";
4850
- readonly indexed: false;
4851
- }];
4852
- readonly name: "Deepen";
4853
4799
  }, {
4854
4800
  readonly type: "event";
4855
4801
  readonly anonymous: false;
@@ -5859,7 +5805,7 @@ export declare const logswapLensAbi: readonly [{
5859
5805
  readonly internalType: "int256";
5860
5806
  readonly type: "int256";
5861
5807
  }, {
5862
- readonly name: "leverTheta";
5808
+ readonly name: "harvestedTheta";
5863
5809
  readonly internalType: "int256";
5864
5810
  readonly type: "int256";
5865
5811
  }, {
package/dist/generated.js CHANGED
@@ -1299,7 +1299,7 @@ export const fPoolManagerAbi = [
1299
1299
  { name: 'L', internalType: 'uint256', type: 'uint256' },
1300
1300
  { name: 'shares', internalType: 'uint256', type: 'uint256' },
1301
1301
  { name: 'theta0', internalType: 'int256', type: 'int256' },
1302
- { name: 'leverTheta', internalType: 'int256', type: 'int256' },
1302
+ { name: 'harvestedTheta', internalType: 'int256', type: 'int256' },
1303
1303
  {
1304
1304
  name: 'pendingAuthority',
1305
1305
  internalType: 'address',
@@ -1845,26 +1845,6 @@ export const fPoolManagerAbi = [
1845
1845
  ],
1846
1846
  name: 'CollectorProposed',
1847
1847
  },
1848
- {
1849
- type: 'event',
1850
- anonymous: false,
1851
- inputs: [
1852
- {
1853
- name: 'poolId',
1854
- internalType: 'bytes32',
1855
- type: 'bytes32',
1856
- indexed: true,
1857
- },
1858
- { name: 'from', internalType: 'address', type: 'address', indexed: true },
1859
- {
1860
- name: 'amount',
1861
- internalType: 'uint256',
1862
- type: 'uint256',
1863
- indexed: false,
1864
- },
1865
- ],
1866
- name: 'Deepen',
1867
- },
1868
1848
  {
1869
1849
  type: 'event',
1870
1850
  anonymous: false,
@@ -2589,16 +2569,6 @@ export const fPoolSponsorAbi = [
2589
2569
  outputs: [{ name: '', internalType: 'uint8', type: 'uint8' }],
2590
2570
  stateMutability: 'view',
2591
2571
  },
2592
- {
2593
- type: 'function',
2594
- inputs: [
2595
- { name: 'poolId', internalType: 'bytes32', type: 'bytes32' },
2596
- { name: 'amount', internalType: 'uint256', type: 'uint256' },
2597
- ],
2598
- name: 'deepen',
2599
- outputs: [],
2600
- stateMutability: 'nonpayable',
2601
- },
2602
2572
  {
2603
2573
  type: 'function',
2604
2574
  inputs: [
@@ -3083,26 +3053,6 @@ export const fPoolSponsorAbi = [
3083
3053
  ],
3084
3054
  name: 'CollectorProposed',
3085
3055
  },
3086
- {
3087
- type: 'event',
3088
- anonymous: false,
3089
- inputs: [
3090
- {
3091
- name: 'poolId',
3092
- internalType: 'bytes32',
3093
- type: 'bytes32',
3094
- indexed: true,
3095
- },
3096
- { name: 'from', internalType: 'address', type: 'address', indexed: true },
3097
- {
3098
- name: 'amount',
3099
- internalType: 'uint256',
3100
- type: 'uint256',
3101
- indexed: false,
3102
- },
3103
- ],
3104
- name: 'Deepen',
3105
- },
3106
3056
  {
3107
3057
  type: 'event',
3108
3058
  anonymous: false,
@@ -3823,7 +3773,7 @@ export const logswapLensAbi = [
3823
3773
  { name: 'L', internalType: 'uint256', type: 'uint256' },
3824
3774
  { name: 'shares', internalType: 'uint256', type: 'uint256' },
3825
3775
  { name: 'theta0', internalType: 'int256', type: 'int256' },
3826
- { name: 'leverTheta', internalType: 'int256', type: 'int256' },
3776
+ { name: 'harvestedTheta', internalType: 'int256', type: 'int256' },
3827
3777
  {
3828
3778
  name: 'pendingAuthority',
3829
3779
  internalType: 'address',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logswap/sdk",
3
- "version": "0.5.38",
3
+ "version": "0.5.40",
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/fpool.ts CHANGED
@@ -128,7 +128,7 @@ export async function getFPool(c: LogswapClient, poolId: Hex): Promise<FPoolStat
128
128
  shares: bigint;
129
129
  theta0: bigint;
130
130
  bigSigma: bigint;
131
- leverTheta: bigint;
131
+ harvestedTheta: bigint;
132
132
  pendingAuthority: Address;
133
133
  operator: Address;
134
134
  minBuffer: bigint;
@@ -467,11 +467,6 @@ export async function fPoolDividendOf(c: LogswapClient, poolId: Hex, holder: Add
467
467
  /** The lever's floor: `harvest` may not take Q/L under ln 1.25 — the floor stays ≥ 20% below the mark (decisions 025). */
468
468
  export const LEVER_FLOOR = 223143551314209755n;
469
469
 
470
- /** Commit quote, deepening θ — the other sign of `harvest`, the same word as the C floor edit (decisions 011). The mark does not move: governance may write θ, never x. */
471
- export async function fPoolDeepen(c: LogswapClient, a: { poolId: Hex; amount: bigint; account: Address }) {
472
- return writeFPool(c, a.poolId, "deepen", [a.amount], a.account);
473
- }
474
-
475
470
  // ─── internals ────────────────────────────────────────────────────────────────
476
471
 
477
472
  function defaultDeadline(): bigint {
@@ -920,6 +915,108 @@ export async function fPoolRelaunch(
920
915
  return writeFPool0(c, "multicall", [calls], a.account);
921
916
  }
922
917
 
918
+ /** ERC-6909 shares sent here are locked for good — the seed's custody (custody.md §4(b)). */
919
+ export const DEAD_ADDRESS: Address = "0x000000000000000000000000000000000000dEaD";
920
+ /** The manager's `MIN_SHARES`: the seed mints this much to 0xdead itself, the rest to the seeder. */
921
+ export const F_MIN_SHARES = 1000n;
922
+
923
+ export interface FPoolLaunchArgs extends Omit<FPoolCreateArgs, "account"> {
924
+ L0: bigint;
925
+ /** Quote the seed pulls. A pad seeds at 0 — pure float, a resting ask, nothing raised. */
926
+ Q0: bigint;
927
+ /**
928
+ * Send every share the seed mints to the creator (`L0 − MIN_SHARES`) to 0xdead in the same
929
+ * batch: the float and the raise can never be burned out from under the buyers. The lever
930
+ * (harvest) is the authority's and survives it; the exit does not. A pad's default posture.
931
+ */
932
+ lockSeed?: boolean;
933
+ /**
934
+ * An opening buy of leg `j` (an index into `bases` AS GIVEN) for `amountIn` of quote, ON THE
935
+ * MANAGER — the same sender, a plain allowance to the manager, the router nowhere near it. A
936
+ * pad seeds at Q = 0, so until someone trades it the mark sits at p₀; buying inside the launch
937
+ * gives it a price that has moved and a buffer under it. Nothing can trade between the seed and
938
+ * this buy — they are one transaction — so `minOut` is safe at its default of 0.
939
+ */
940
+ openBuy?: { j: number; amountIn: bigint; minOut?: bigint };
941
+ /** The pool's label, set in the batch (≤ 31 bytes of UTF-8). */
942
+ name?: string;
943
+ /** Gate minting, list the creator, appoint them operator (decisions 021) — three calls, in the batch. */
944
+ privatePool?: boolean;
945
+ /**
946
+ * The pool already exists (a previous launch got as far as `initialize` and no further — a seed
947
+ * that reverted, a closed tab, before the launch was one transaction), so `initialize` is left
948
+ * out: the key is a pure function of the arguments and a second `initialize` can only revert.
949
+ */
950
+ initialized?: boolean;
951
+ /** Anything else, pre-encoded against {@link fPoolManagerAbi}, appended after the above. */
952
+ extra?: Hex[];
953
+ account: Address;
954
+ }
955
+
956
+ /**
957
+ * The launch's calls, in order — the batch {@link fPoolLaunch} sends. Pure, so a form can show
958
+ * what it is about to send, and a test can decode it. Legs are sorted here with their weights and
959
+ * reserves (the key's canonical order; `openBuy.j` is re-indexed to match), and the weights are
960
+ * checked here, where the message is readable.
961
+ */
962
+ export function fPoolLaunchCalls(
963
+ poolId: Hex,
964
+ a: FPoolLaunchArgs & ({ r0: bigint[] } | { x0: bigint[] }),
965
+ ): Hex[] {
966
+ const sum = a.weights.reduce((x, y) => x + y, 0n);
967
+ if (sum !== WAD) throw new Error(`logswap: weights sum to ${sum}, expected 1e18`);
968
+ const given = "r0" in a ? a.r0 : a.x0.map((x, j) => fPoolReserveAt((a.weights[j]! * a.L0) / WAD, x));
969
+ if (given.length !== a.bases.length) throw new Error(`logswap: ${given.length} reserves for ${a.bases.length} legs`);
970
+ const { bases, companions } = sortFPoolLegs(a.bases, a.weights, given);
971
+ const key = { quote: a.quote, bases, weights: companions[0]!, phi: a.phi, lockStrike: a.lockStrike, authority: a.authority, salt: a.salt ?? ZERO_SALT };
972
+ const enc = (functionName: string, args: unknown[]) =>
973
+ encodeFunctionData({ abi: fPoolManagerAbi, functionName, args } as never) as Hex;
974
+ const calls: Hex[] = [];
975
+ if (!a.initialized) calls.push(enc("initialize", [key]));
976
+ calls.push(enc("seed", [poolId, a.L0, companions[1]!, a.Q0]));
977
+ // gen 0 by construction: a launch is the pool's FIRST seed — a relaunch is `fPoolRelaunch`
978
+ if (a.lockSeed) calls.push(enc("transfer", [DEAD_ADDRESS, fPoolShareId(poolId, 0), a.L0 - F_MIN_SHARES]));
979
+ if (a.openBuy) {
980
+ const j = bases.indexOf(a.bases[a.openBuy.j]!);
981
+ if (j < 0) throw new Error(`logswap: openBuy.j = ${a.openBuy.j} is not a leg`);
982
+ calls.push(enc("swapQuoteIn", [poolId, BigInt(j), a.openBuy.amountIn, a.openBuy.minOut ?? 0n, a.account]));
983
+ }
984
+ if (a.name) calls.push(enc("setName", [poolId, textToBytes32(a.name)]));
985
+ if (a.privatePool) {
986
+ calls.push(enc("setGates", [poolId, true, false]));
987
+ calls.push(enc("setAllowed", [poolId, [a.account], true]));
988
+ calls.push(enc("appointOperator", [poolId, a.account]));
989
+ }
990
+ calls.push(...(a.extra ?? []));
991
+ return calls;
992
+ }
993
+
994
+ /**
995
+ * Create a pool as ONE transaction: `initialize`, `seed`, the seed lock, the opening buy, the
996
+ * name, the private-pool gates — the manager's `multicall`, the creator as sender throughout.
997
+ * Either every call lands or none does; there is no half-built pool to resume.
998
+ *
999
+ * Why the manager and not the router: every one of these entries authenticates by `msg.sender`
1000
+ * (`seed` is authority-only, so is everything after it). Routed, the router would be the sender
1001
+ * — the authority, the holder of the seed shares — and the handover back is two-step, so it
1002
+ * could not even close in the same transaction. `multicall` is delegatecall-to-self, so the
1003
+ * sender survives, which is what the manager's own doc says a router cannot do.
1004
+ *
1005
+ * What the batch PULLS, by plain allowance to the manager (never Permit2): `r0[j]` of each base,
1006
+ * `Q0` of quote, plus `openBuy.amountIn` of quote. Grant those first — one `approve` per token,
1007
+ * once ever ({@link approveTokenForFPoolManager}, {@link fPoolManagerAllowanceOk}).
1008
+ *
1009
+ * Returns the hash and the pool's id (the key's hash, {@link fPoolIdOf}).
1010
+ */
1011
+ export async function fPoolLaunch(
1012
+ c: LogswapClient,
1013
+ a: FPoolLaunchArgs & ({ r0: bigint[] } | { x0: bigint[] }),
1014
+ ): Promise<{ hash: Hash; poolId: Hex }> {
1015
+ const poolId = await fPoolIdOf(c, a);
1016
+ const hash = await writeFPool0(c, "multicall", [fPoolLaunchCalls(poolId, a)], a.account);
1017
+ return { hash, poolId };
1018
+ }
1019
+
923
1020
  /**
924
1021
  * Propose the next authority — step one of two (contracts `2aa6b7b`, decisions 020). Nothing moves
925
1022
  * until `next` accepts; proposing again (the zero address included) cancels a pending proposal.
@@ -1161,7 +1258,7 @@ export async function fPoolShareHolders(
1161
1258
  .sort((a, b) => (b.shares > a.shares ? 1 : -1));
1162
1259
  }
1163
1260
 
1164
- /** 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). */
1261
+ /** 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, harvestedTheta). */
1165
1262
  export async function getFPoolsRaw(c: LogswapClient, poolIds: Hex[]): Promise<readonly unknown[]> {
1166
1263
  const { logswapLensAbi } = await import("./generated.js");
1167
1264
  return (await c.public.readContract({ address: c.addresses.lens, abi: logswapLensAbi, functionName: "getFPools", args: [poolIds] } as never)) as readonly unknown[];
package/src/generated.ts CHANGED
@@ -1302,7 +1302,7 @@ export const fPoolManagerAbi = [
1302
1302
  { name: 'L', internalType: 'uint256', type: 'uint256' },
1303
1303
  { name: 'shares', internalType: 'uint256', type: 'uint256' },
1304
1304
  { name: 'theta0', internalType: 'int256', type: 'int256' },
1305
- { name: 'leverTheta', internalType: 'int256', type: 'int256' },
1305
+ { name: 'harvestedTheta', internalType: 'int256', type: 'int256' },
1306
1306
  {
1307
1307
  name: 'pendingAuthority',
1308
1308
  internalType: 'address',
@@ -1848,26 +1848,6 @@ export const fPoolManagerAbi = [
1848
1848
  ],
1849
1849
  name: 'CollectorProposed',
1850
1850
  },
1851
- {
1852
- type: 'event',
1853
- anonymous: false,
1854
- inputs: [
1855
- {
1856
- name: 'poolId',
1857
- internalType: 'bytes32',
1858
- type: 'bytes32',
1859
- indexed: true,
1860
- },
1861
- { name: 'from', internalType: 'address', type: 'address', indexed: true },
1862
- {
1863
- name: 'amount',
1864
- internalType: 'uint256',
1865
- type: 'uint256',
1866
- indexed: false,
1867
- },
1868
- ],
1869
- name: 'Deepen',
1870
- },
1871
1851
  {
1872
1852
  type: 'event',
1873
1853
  anonymous: false,
@@ -2594,16 +2574,6 @@ export const fPoolSponsorAbi = [
2594
2574
  outputs: [{ name: '', internalType: 'uint8', type: 'uint8' }],
2595
2575
  stateMutability: 'view',
2596
2576
  },
2597
- {
2598
- type: 'function',
2599
- inputs: [
2600
- { name: 'poolId', internalType: 'bytes32', type: 'bytes32' },
2601
- { name: 'amount', internalType: 'uint256', type: 'uint256' },
2602
- ],
2603
- name: 'deepen',
2604
- outputs: [],
2605
- stateMutability: 'nonpayable',
2606
- },
2607
2577
  {
2608
2578
  type: 'function',
2609
2579
  inputs: [
@@ -3088,26 +3058,6 @@ export const fPoolSponsorAbi = [
3088
3058
  ],
3089
3059
  name: 'CollectorProposed',
3090
3060
  },
3091
- {
3092
- type: 'event',
3093
- anonymous: false,
3094
- inputs: [
3095
- {
3096
- name: 'poolId',
3097
- internalType: 'bytes32',
3098
- type: 'bytes32',
3099
- indexed: true,
3100
- },
3101
- { name: 'from', internalType: 'address', type: 'address', indexed: true },
3102
- {
3103
- name: 'amount',
3104
- internalType: 'uint256',
3105
- type: 'uint256',
3106
- indexed: false,
3107
- },
3108
- ],
3109
- name: 'Deepen',
3110
- },
3111
3061
  {
3112
3062
  type: 'event',
3113
3063
  anonymous: false,
@@ -3830,7 +3780,7 @@ export const logswapLensAbi = [
3830
3780
  { name: 'L', internalType: 'uint256', type: 'uint256' },
3831
3781
  { name: 'shares', internalType: 'uint256', type: 'uint256' },
3832
3782
  { name: 'theta0', internalType: 'int256', type: 'int256' },
3833
- { name: 'leverTheta', internalType: 'int256', type: 'int256' },
3783
+ { name: 'harvestedTheta', internalType: 'int256', type: 'int256' },
3834
3784
  {
3835
3785
  name: 'pendingAuthority',
3836
3786
  internalType: 'address',