@logswap/sdk 0.5.38 → 0.5.39

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
@@ -4131,6 +4131,82 @@ export declare function fPoolRelaunch(c: LogswapClient, a: {
4131
4131
  x0: bigint[];
4132
4132
  weights: bigint[];
4133
4133
  })): Promise<`0x${string}`>;
4134
+ /** ERC-6909 shares sent here are locked for good — the seed's custody (custody.md §4(b)). */
4135
+ export declare const DEAD_ADDRESS: Address;
4136
+ /** The manager's `MIN_SHARES`: the seed mints this much to 0xdead itself, the rest to the seeder. */
4137
+ export declare const F_MIN_SHARES = 1000n;
4138
+ export interface FPoolLaunchArgs extends Omit<FPoolCreateArgs, "account"> {
4139
+ L0: bigint;
4140
+ /** Quote the seed pulls. A pad seeds at 0 — pure float, a resting ask, nothing raised. */
4141
+ Q0: bigint;
4142
+ /**
4143
+ * Send every share the seed mints to the creator (`L0 − MIN_SHARES`) to 0xdead in the same
4144
+ * batch: the float and the raise can never be burned out from under the buyers. The lever
4145
+ * (harvest) is the authority's and survives it; the exit does not. A pad's default posture.
4146
+ */
4147
+ lockSeed?: boolean;
4148
+ /**
4149
+ * An opening buy of leg `j` (an index into `bases` AS GIVEN) for `amountIn` of quote, ON THE
4150
+ * MANAGER — the same sender, a plain allowance to the manager, the router nowhere near it. A
4151
+ * pad seeds at Q = 0, so until someone trades it the mark sits at p₀; buying inside the launch
4152
+ * gives it a price that has moved and a buffer under it. Nothing can trade between the seed and
4153
+ * this buy — they are one transaction — so `minOut` is safe at its default of 0.
4154
+ */
4155
+ openBuy?: {
4156
+ j: number;
4157
+ amountIn: bigint;
4158
+ minOut?: bigint;
4159
+ };
4160
+ /** The pool's label, set in the batch (≤ 31 bytes of UTF-8). */
4161
+ name?: string;
4162
+ /** Gate minting, list the creator, appoint them operator (decisions 021) — three calls, in the batch. */
4163
+ privatePool?: boolean;
4164
+ /**
4165
+ * The pool already exists (a previous launch got as far as `initialize` and no further — a seed
4166
+ * that reverted, a closed tab, before the launch was one transaction), so `initialize` is left
4167
+ * out: the key is a pure function of the arguments and a second `initialize` can only revert.
4168
+ */
4169
+ initialized?: boolean;
4170
+ /** Anything else, pre-encoded against {@link fPoolManagerAbi}, appended after the above. */
4171
+ extra?: Hex[];
4172
+ account: Address;
4173
+ }
4174
+ /**
4175
+ * The launch's calls, in order — the batch {@link fPoolLaunch} sends. Pure, so a form can show
4176
+ * what it is about to send, and a test can decode it. Legs are sorted here with their weights and
4177
+ * reserves (the key's canonical order; `openBuy.j` is re-indexed to match), and the weights are
4178
+ * checked here, where the message is readable.
4179
+ */
4180
+ export declare function fPoolLaunchCalls(poolId: Hex, a: FPoolLaunchArgs & ({
4181
+ r0: bigint[];
4182
+ } | {
4183
+ x0: bigint[];
4184
+ })): Hex[];
4185
+ /**
4186
+ * Create a pool as ONE transaction: `initialize`, `seed`, the seed lock, the opening buy, the
4187
+ * name, the private-pool gates — the manager's `multicall`, the creator as sender throughout.
4188
+ * Either every call lands or none does; there is no half-built pool to resume.
4189
+ *
4190
+ * Why the manager and not the router: every one of these entries authenticates by `msg.sender`
4191
+ * (`seed` is authority-only, so is everything after it). Routed, the router would be the sender
4192
+ * — the authority, the holder of the seed shares — and the handover back is two-step, so it
4193
+ * could not even close in the same transaction. `multicall` is delegatecall-to-self, so the
4194
+ * sender survives, which is what the manager's own doc says a router cannot do.
4195
+ *
4196
+ * What the batch PULLS, by plain allowance to the manager (never Permit2): `r0[j]` of each base,
4197
+ * `Q0` of quote, plus `openBuy.amountIn` of quote. Grant those first — one `approve` per token,
4198
+ * once ever ({@link approveTokenForFPoolManager}, {@link fPoolManagerAllowanceOk}).
4199
+ *
4200
+ * Returns the hash and the pool's id (the key's hash, {@link fPoolIdOf}).
4201
+ */
4202
+ export declare function fPoolLaunch(c: LogswapClient, a: FPoolLaunchArgs & ({
4203
+ r0: bigint[];
4204
+ } | {
4205
+ x0: bigint[];
4206
+ })): Promise<{
4207
+ hash: Hash;
4208
+ poolId: Hex;
4209
+ }>;
4134
4210
  /**
4135
4211
  * Propose the next authority — step one of two (contracts `2aa6b7b`, decisions 020). Nothing moves
4136
4212
  * until `next` accepts; proposing again (the zero address included) cancels a pending proposal.
package/dist/fpool.js CHANGED
@@ -629,6 +629,71 @@ export async function fPoolRelaunch(c, a) {
629
629
  ];
630
630
  return writeFPool0(c, "multicall", [calls], a.account);
631
631
  }
632
+ /** ERC-6909 shares sent here are locked for good — the seed's custody (custody.md §4(b)). */
633
+ export const DEAD_ADDRESS = "0x000000000000000000000000000000000000dEaD";
634
+ /** The manager's `MIN_SHARES`: the seed mints this much to 0xdead itself, the rest to the seeder. */
635
+ export const F_MIN_SHARES = 1000n;
636
+ /**
637
+ * The launch's calls, in order — the batch {@link fPoolLaunch} sends. Pure, so a form can show
638
+ * what it is about to send, and a test can decode it. Legs are sorted here with their weights and
639
+ * reserves (the key's canonical order; `openBuy.j` is re-indexed to match), and the weights are
640
+ * checked here, where the message is readable.
641
+ */
642
+ export function fPoolLaunchCalls(poolId, a) {
643
+ const sum = a.weights.reduce((x, y) => x + y, 0n);
644
+ if (sum !== WAD)
645
+ throw new Error(`logswap: weights sum to ${sum}, expected 1e18`);
646
+ const given = "r0" in a ? a.r0 : a.x0.map((x, j) => fPoolReserveAt((a.weights[j] * a.L0) / WAD, x));
647
+ if (given.length !== a.bases.length)
648
+ throw new Error(`logswap: ${given.length} reserves for ${a.bases.length} legs`);
649
+ const { bases, companions } = sortFPoolLegs(a.bases, a.weights, given);
650
+ const key = { quote: a.quote, bases, weights: companions[0], phi: a.phi, lockStrike: a.lockStrike, authority: a.authority, salt: a.salt ?? ZERO_SALT };
651
+ const enc = (functionName, args) => encodeFunctionData({ abi: fPoolManagerAbi, functionName, args });
652
+ const calls = [];
653
+ if (!a.initialized)
654
+ calls.push(enc("initialize", [key]));
655
+ calls.push(enc("seed", [poolId, a.L0, companions[1], a.Q0]));
656
+ // gen 0 by construction: a launch is the pool's FIRST seed — a relaunch is `fPoolRelaunch`
657
+ if (a.lockSeed)
658
+ calls.push(enc("transfer", [DEAD_ADDRESS, fPoolShareId(poolId, 0), a.L0 - F_MIN_SHARES]));
659
+ if (a.openBuy) {
660
+ const j = bases.indexOf(a.bases[a.openBuy.j]);
661
+ if (j < 0)
662
+ throw new Error(`logswap: openBuy.j = ${a.openBuy.j} is not a leg`);
663
+ calls.push(enc("swapQuoteIn", [poolId, BigInt(j), a.openBuy.amountIn, a.openBuy.minOut ?? 0n, a.account]));
664
+ }
665
+ if (a.name)
666
+ calls.push(enc("setName", [poolId, textToBytes32(a.name)]));
667
+ if (a.privatePool) {
668
+ calls.push(enc("setGates", [poolId, true, false]));
669
+ calls.push(enc("setAllowed", [poolId, [a.account], true]));
670
+ calls.push(enc("appointOperator", [poolId, a.account]));
671
+ }
672
+ calls.push(...(a.extra ?? []));
673
+ return calls;
674
+ }
675
+ /**
676
+ * Create a pool as ONE transaction: `initialize`, `seed`, the seed lock, the opening buy, the
677
+ * name, the private-pool gates — the manager's `multicall`, the creator as sender throughout.
678
+ * Either every call lands or none does; there is no half-built pool to resume.
679
+ *
680
+ * Why the manager and not the router: every one of these entries authenticates by `msg.sender`
681
+ * (`seed` is authority-only, so is everything after it). Routed, the router would be the sender
682
+ * — the authority, the holder of the seed shares — and the handover back is two-step, so it
683
+ * could not even close in the same transaction. `multicall` is delegatecall-to-self, so the
684
+ * sender survives, which is what the manager's own doc says a router cannot do.
685
+ *
686
+ * What the batch PULLS, by plain allowance to the manager (never Permit2): `r0[j]` of each base,
687
+ * `Q0` of quote, plus `openBuy.amountIn` of quote. Grant those first — one `approve` per token,
688
+ * once ever ({@link approveTokenForFPoolManager}, {@link fPoolManagerAllowanceOk}).
689
+ *
690
+ * Returns the hash and the pool's id (the key's hash, {@link fPoolIdOf}).
691
+ */
692
+ export async function fPoolLaunch(c, a) {
693
+ const poolId = await fPoolIdOf(c, a);
694
+ const hash = await writeFPool0(c, "multicall", [fPoolLaunchCalls(poolId, a)], a.account);
695
+ return { hash, poolId };
696
+ }
632
697
  /**
633
698
  * Propose the next authority — step one of two (contracts `2aa6b7b`, decisions 020). Nothing moves
634
699
  * until `next` accepts; proposing again (the zero address included) cancels a pending proposal.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logswap/sdk",
3
- "version": "0.5.38",
3
+ "version": "0.5.39",
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
@@ -920,6 +920,108 @@ export async function fPoolRelaunch(
920
920
  return writeFPool0(c, "multicall", [calls], a.account);
921
921
  }
922
922
 
923
+ /** ERC-6909 shares sent here are locked for good — the seed's custody (custody.md §4(b)). */
924
+ export const DEAD_ADDRESS: Address = "0x000000000000000000000000000000000000dEaD";
925
+ /** The manager's `MIN_SHARES`: the seed mints this much to 0xdead itself, the rest to the seeder. */
926
+ export const F_MIN_SHARES = 1000n;
927
+
928
+ export interface FPoolLaunchArgs extends Omit<FPoolCreateArgs, "account"> {
929
+ L0: bigint;
930
+ /** Quote the seed pulls. A pad seeds at 0 — pure float, a resting ask, nothing raised. */
931
+ Q0: bigint;
932
+ /**
933
+ * Send every share the seed mints to the creator (`L0 − MIN_SHARES`) to 0xdead in the same
934
+ * batch: the float and the raise can never be burned out from under the buyers. The lever
935
+ * (harvest) is the authority's and survives it; the exit does not. A pad's default posture.
936
+ */
937
+ lockSeed?: boolean;
938
+ /**
939
+ * An opening buy of leg `j` (an index into `bases` AS GIVEN) for `amountIn` of quote, ON THE
940
+ * MANAGER — the same sender, a plain allowance to the manager, the router nowhere near it. A
941
+ * pad seeds at Q = 0, so until someone trades it the mark sits at p₀; buying inside the launch
942
+ * gives it a price that has moved and a buffer under it. Nothing can trade between the seed and
943
+ * this buy — they are one transaction — so `minOut` is safe at its default of 0.
944
+ */
945
+ openBuy?: { j: number; amountIn: bigint; minOut?: bigint };
946
+ /** The pool's label, set in the batch (≤ 31 bytes of UTF-8). */
947
+ name?: string;
948
+ /** Gate minting, list the creator, appoint them operator (decisions 021) — three calls, in the batch. */
949
+ privatePool?: boolean;
950
+ /**
951
+ * The pool already exists (a previous launch got as far as `initialize` and no further — a seed
952
+ * that reverted, a closed tab, before the launch was one transaction), so `initialize` is left
953
+ * out: the key is a pure function of the arguments and a second `initialize` can only revert.
954
+ */
955
+ initialized?: boolean;
956
+ /** Anything else, pre-encoded against {@link fPoolManagerAbi}, appended after the above. */
957
+ extra?: Hex[];
958
+ account: Address;
959
+ }
960
+
961
+ /**
962
+ * The launch's calls, in order — the batch {@link fPoolLaunch} sends. Pure, so a form can show
963
+ * what it is about to send, and a test can decode it. Legs are sorted here with their weights and
964
+ * reserves (the key's canonical order; `openBuy.j` is re-indexed to match), and the weights are
965
+ * checked here, where the message is readable.
966
+ */
967
+ export function fPoolLaunchCalls(
968
+ poolId: Hex,
969
+ a: FPoolLaunchArgs & ({ r0: bigint[] } | { x0: bigint[] }),
970
+ ): Hex[] {
971
+ const sum = a.weights.reduce((x, y) => x + y, 0n);
972
+ if (sum !== WAD) throw new Error(`logswap: weights sum to ${sum}, expected 1e18`);
973
+ const given = "r0" in a ? a.r0 : a.x0.map((x, j) => fPoolReserveAt((a.weights[j]! * a.L0) / WAD, x));
974
+ if (given.length !== a.bases.length) throw new Error(`logswap: ${given.length} reserves for ${a.bases.length} legs`);
975
+ const { bases, companions } = sortFPoolLegs(a.bases, a.weights, given);
976
+ const key = { quote: a.quote, bases, weights: companions[0]!, phi: a.phi, lockStrike: a.lockStrike, authority: a.authority, salt: a.salt ?? ZERO_SALT };
977
+ const enc = (functionName: string, args: unknown[]) =>
978
+ encodeFunctionData({ abi: fPoolManagerAbi, functionName, args } as never) as Hex;
979
+ const calls: Hex[] = [];
980
+ if (!a.initialized) calls.push(enc("initialize", [key]));
981
+ calls.push(enc("seed", [poolId, a.L0, companions[1]!, a.Q0]));
982
+ // gen 0 by construction: a launch is the pool's FIRST seed — a relaunch is `fPoolRelaunch`
983
+ if (a.lockSeed) calls.push(enc("transfer", [DEAD_ADDRESS, fPoolShareId(poolId, 0), a.L0 - F_MIN_SHARES]));
984
+ if (a.openBuy) {
985
+ const j = bases.indexOf(a.bases[a.openBuy.j]!);
986
+ if (j < 0) throw new Error(`logswap: openBuy.j = ${a.openBuy.j} is not a leg`);
987
+ calls.push(enc("swapQuoteIn", [poolId, BigInt(j), a.openBuy.amountIn, a.openBuy.minOut ?? 0n, a.account]));
988
+ }
989
+ if (a.name) calls.push(enc("setName", [poolId, textToBytes32(a.name)]));
990
+ if (a.privatePool) {
991
+ calls.push(enc("setGates", [poolId, true, false]));
992
+ calls.push(enc("setAllowed", [poolId, [a.account], true]));
993
+ calls.push(enc("appointOperator", [poolId, a.account]));
994
+ }
995
+ calls.push(...(a.extra ?? []));
996
+ return calls;
997
+ }
998
+
999
+ /**
1000
+ * Create a pool as ONE transaction: `initialize`, `seed`, the seed lock, the opening buy, the
1001
+ * name, the private-pool gates — the manager's `multicall`, the creator as sender throughout.
1002
+ * Either every call lands or none does; there is no half-built pool to resume.
1003
+ *
1004
+ * Why the manager and not the router: every one of these entries authenticates by `msg.sender`
1005
+ * (`seed` is authority-only, so is everything after it). Routed, the router would be the sender
1006
+ * — the authority, the holder of the seed shares — and the handover back is two-step, so it
1007
+ * could not even close in the same transaction. `multicall` is delegatecall-to-self, so the
1008
+ * sender survives, which is what the manager's own doc says a router cannot do.
1009
+ *
1010
+ * What the batch PULLS, by plain allowance to the manager (never Permit2): `r0[j]` of each base,
1011
+ * `Q0` of quote, plus `openBuy.amountIn` of quote. Grant those first — one `approve` per token,
1012
+ * once ever ({@link approveTokenForFPoolManager}, {@link fPoolManagerAllowanceOk}).
1013
+ *
1014
+ * Returns the hash and the pool's id (the key's hash, {@link fPoolIdOf}).
1015
+ */
1016
+ export async function fPoolLaunch(
1017
+ c: LogswapClient,
1018
+ a: FPoolLaunchArgs & ({ r0: bigint[] } | { x0: bigint[] }),
1019
+ ): Promise<{ hash: Hash; poolId: Hex }> {
1020
+ const poolId = await fPoolIdOf(c, a);
1021
+ const hash = await writeFPool0(c, "multicall", [fPoolLaunchCalls(poolId, a)], a.account);
1022
+ return { hash, poolId };
1023
+ }
1024
+
923
1025
  /**
924
1026
  * Propose the next authority — step one of two (contracts `2aa6b7b`, decisions 020). Nothing moves
925
1027
  * until `next` accepts; proposing again (the zero address included) cancels a pending proposal.