@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 +76 -0
- package/dist/fpool.js +65 -0
- package/package.json +1 -1
- package/src/fpool.ts +102 -0
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.
|
|
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.
|