@logswap/sdk 0.5.40 → 0.5.42
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/client.d.ts +1 -1
- package/dist/client.js +11 -1
- package/dist/fpool.d.ts +207 -288
- package/dist/fpool.js +125 -54
- package/dist/generated.d.ts +112 -226
- package/dist/generated.js +91 -167
- package/package.json +1 -1
- package/src/client.ts +11 -1
- package/src/fpool.ts +158 -86
- package/src/generated.ts +91 -167
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,
|
|
70
|
+
const { quote, Q, L, phi, theta0, bigSigma, authority, pendingAuthority, operator, pendingOperator, gateMint, gateSwap, restructureBlock, seeded, gen } = p;
|
|
71
71
|
const totalSupply = p.shares;
|
|
72
72
|
return {
|
|
73
73
|
poolId,
|
|
@@ -85,18 +85,27 @@ export async function getFPool(c, poolId) {
|
|
|
85
85
|
authority,
|
|
86
86
|
pendingAuthority,
|
|
87
87
|
operator,
|
|
88
|
+
pendingOperator,
|
|
88
89
|
name: bytes32ToText(p.name),
|
|
89
|
-
minBuffer,
|
|
90
90
|
gateMint,
|
|
91
91
|
gateSwap,
|
|
92
92
|
restructureBlock: Number(restructureBlock),
|
|
93
|
-
|
|
93
|
+
kind: fPoolKindOf(p.kind),
|
|
94
94
|
seeded,
|
|
95
95
|
gen: Number(gen),
|
|
96
96
|
totalSupply,
|
|
97
97
|
reserves,
|
|
98
98
|
};
|
|
99
99
|
}
|
|
100
|
+
/** The key's enum values. */
|
|
101
|
+
export const F_KIND = { public: 0, private: 1, pol: 2, pad: 3 };
|
|
102
|
+
const F_KIND_NAMES = ["public", "private", "pol", "pad"];
|
|
103
|
+
export function fPoolKindOf(n) {
|
|
104
|
+
const k = F_KIND_NAMES[Number(n)];
|
|
105
|
+
if (!k)
|
|
106
|
+
throw new Error(`logswap: unknown pool kind ${n}`);
|
|
107
|
+
return k;
|
|
108
|
+
}
|
|
100
109
|
export async function describeFPool(c, s) {
|
|
101
110
|
const rd = (functionName) => c.public.readContract({
|
|
102
111
|
address: c.addresses.fPoolManager,
|
|
@@ -110,7 +119,7 @@ export async function describeFPool(c, s) {
|
|
|
110
119
|
? await Promise.all([rd("feePerL"), rd("edgePerL")])
|
|
111
120
|
: [0n, 0n];
|
|
112
121
|
return {
|
|
113
|
-
shape: s.
|
|
122
|
+
shape: s.kind === "pad" ? "launch" : "basket", // the kind, not n = 1 (decisions 036)
|
|
114
123
|
legs: s.bases.length,
|
|
115
124
|
atFloor: s.Q === 0n,
|
|
116
125
|
feePerL,
|
|
@@ -242,8 +251,9 @@ export async function fPoolPreviewRollIn(c, poolId, gen, holder, shares) {
|
|
|
242
251
|
* Remove quote, lifting θ — price-neutral, no base moves, and since decisions 028 a DIVIDEND to
|
|
243
252
|
* every share: the amount goes into the pool's pot and each holder's slice is settled lazily on
|
|
244
253
|
* their next transfer, mint or burn, or pulled with {@link fPoolClaim}. The sponsor's own slice —
|
|
245
|
-
* its shares' and the locked seed's at 0xdead — is pushed to `to` at once.
|
|
246
|
-
* the lift stops at θ₀ (income only);
|
|
254
|
+
* its shares' and the locked seed's at 0xdead — is pushed to `to` at once. On a pad
|
|
255
|
+
* the lift stops at the seed floor θ₀ (income only); nothing else bounds it (decisions 035) — an
|
|
256
|
+
* unlocked pool's authority may take Q to zero.
|
|
247
257
|
*/
|
|
248
258
|
export async function fPoolHarvest(c, a) {
|
|
249
259
|
return writeFPool(c, a.poolId, "harvest", [a.amount, a.to ?? a.account], a.account);
|
|
@@ -267,8 +277,6 @@ export async function fPoolDividendOf(c, poolId, holder, gen) {
|
|
|
267
277
|
args: [poolId, BigInt(g), holder],
|
|
268
278
|
});
|
|
269
279
|
}
|
|
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
|
-
export const LEVER_FLOOR = 223143551314209755n;
|
|
272
280
|
// ─── internals ────────────────────────────────────────────────────────────────
|
|
273
281
|
function defaultDeadline() {
|
|
274
282
|
return BigInt(Math.floor(Date.now() / 1000) + 1800);
|
|
@@ -551,7 +559,7 @@ export async function fPoolInitialize(c, a) {
|
|
|
551
559
|
if (sum !== 10n ** 18n)
|
|
552
560
|
throw new Error(`logswap: weights sum to ${sum}, expected 1e18`);
|
|
553
561
|
const { bases, companions } = sortFPoolLegs(a.bases, a.weights);
|
|
554
|
-
const key = { quote: a.quote, bases, weights: companions[0], phi: a.phi,
|
|
562
|
+
const key = { quote: a.quote, bases, weights: companions[0], phi: a.phi, kind: F_KIND[a.kind], authority: a.authority, salt: a.salt ?? ZERO_SALT };
|
|
555
563
|
const wallet = requireWallet(c);
|
|
556
564
|
const { request } = await c.public.simulateContract({
|
|
557
565
|
address: c.addresses.fPoolManager,
|
|
@@ -565,7 +573,7 @@ export async function fPoolInitialize(c, a) {
|
|
|
565
573
|
/** The pool id is the key's hash — pure, so it can be read before or after creation. */
|
|
566
574
|
export async function fPoolIdOf(c, a) {
|
|
567
575
|
const { bases, companions } = sortFPoolLegs(a.bases, a.weights);
|
|
568
|
-
const key = { quote: a.quote, bases, weights: companions[0], phi: a.phi,
|
|
576
|
+
const key = { quote: a.quote, bases, weights: companions[0], phi: a.phi, kind: F_KIND[a.kind], authority: a.authority, salt: a.salt ?? ZERO_SALT };
|
|
569
577
|
return c.public.readContract({
|
|
570
578
|
address: c.addresses.fPoolManager,
|
|
571
579
|
abi: fPoolManagerAbi,
|
|
@@ -596,38 +604,99 @@ export async function fPoolSeed(c, a) {
|
|
|
596
604
|
return writeFPool(c, a.poolId, "seed", [a.L0, r0, a.Q0], a.account);
|
|
597
605
|
}
|
|
598
606
|
/**
|
|
599
|
-
* Retire the live generation (decisions 025, 032)
|
|
600
|
-
*
|
|
601
|
-
*
|
|
602
|
-
* ({@link
|
|
603
|
-
*
|
|
607
|
+
* Retire the live generation (decisions 025, 032, 035) — the raw entry. Allowed only at an empty
|
|
608
|
+
* bid, Q ≤ L/1e9, on every pool: the market took it, or the authority harvested it out first
|
|
609
|
+
* ({@link fPoolRetire} does both in one transaction). The live (S, Q, R_j) become a frozen bundle
|
|
610
|
+
* every share of this generation redeems ({@link fPoolRedeem}) or rolls ({@link fPoolRollIn}),
|
|
611
|
+
* forever; the pool is unseeded until the next {@link fPoolSeed}, which opens generation
|
|
612
|
+
* `gen + 1` under the same id, gates and lists.
|
|
604
613
|
*/
|
|
605
614
|
export async function fPoolDissolve(c, a) {
|
|
606
615
|
return writeFPool(c, a.poolId, "dissolve", [], a.account);
|
|
607
616
|
}
|
|
608
617
|
/**
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
612
|
-
*
|
|
613
|
-
|
|
614
|
-
|
|
618
|
+
* Retire the live generation as ONE transaction: the harvests that empty the bid
|
|
619
|
+
* ({@link fPoolEmptyingHarvests} — a dividend to every share; none when it is already empty),
|
|
620
|
+
* then `dissolve` — the manager's `multicall`, the authority as sender. What a sponsor's
|
|
621
|
+
* "dissolve" button should call. Throws before sending on a pad that still bids.
|
|
622
|
+
*/
|
|
623
|
+
export async function fPoolRetire(c, a) {
|
|
624
|
+
const harvests = await fPoolEmptyingHarvests(c, a.poolId);
|
|
625
|
+
if (harvests.length === 0)
|
|
626
|
+
return fPoolDissolve(c, a);
|
|
627
|
+
const enc = (functionName, args) => encodeFunctionData({ abi: fPoolManagerAbi, functionName, args });
|
|
628
|
+
const calls = [...harvests.map((amount) => enc("harvest", [a.poolId, amount, a.account])), enc("dissolve", [a.poolId])];
|
|
629
|
+
return writeFPool0(c, "multicall", [calls], a.account);
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* The harvests that empty an unlocked pool's bid, in order — what a relaunch sends before its
|
|
633
|
+
* `dissolve` (decisions 035: a dissolve needs an empty bid on every pool). One `harvest(Q)` when a
|
|
634
|
+
* collector is set. With none, the cut on income STAYS in the pool as LP quote (decisions 002)
|
|
635
|
+
* and reads as taken income, so a second harvest — capital, no cut — takes the rest; the
|
|
636
|
+
* contract's own arithmetic, replayed. `[]` when the bid is already empty. Throws on a
|
|
637
|
+
* pad that still bids (its bid empties only as the market sells it down), and in
|
|
638
|
+
* the one shape two harvests cannot empty (no collector, income above Q — harvest by hand).
|
|
639
|
+
*/
|
|
640
|
+
export async function fPoolEmptyingHarvests(c, poolId) {
|
|
641
|
+
const rd = (functionName, args = []) => c.public.readContract({ address: c.addresses.fPoolManager, abi: fPoolManagerAbi, functionName, args });
|
|
642
|
+
const [p, feePerL, fee, exempt, collector] = await Promise.all([
|
|
643
|
+
rd("getPool", [poolId]),
|
|
644
|
+
rd("feePerL", [poolId]),
|
|
645
|
+
rd("HARVEST_FEE"),
|
|
646
|
+
rd("harvestFeeExempt", [poolId]),
|
|
647
|
+
rd("feeCollector"),
|
|
648
|
+
]);
|
|
649
|
+
if (p.Q === 0n)
|
|
650
|
+
return [];
|
|
651
|
+
if (p.kind === F_KIND.pad)
|
|
652
|
+
throw new Error("logswap: a pad is retired only once its bid is empty (decisions 035)");
|
|
653
|
+
const earned = feePerL > 0n ? (feePerL * p.L) / WAD : 0n;
|
|
654
|
+
let taken = p.incomeTaken;
|
|
655
|
+
let q = p.Q;
|
|
656
|
+
const amounts = [];
|
|
657
|
+
for (let i = 0; i < 2 && q > 0n; i++) {
|
|
658
|
+
const amount = q;
|
|
659
|
+
const left = earned > taken ? earned - taken : 0n;
|
|
660
|
+
const taxable = amount < left ? amount : left;
|
|
661
|
+
taken += taxable;
|
|
662
|
+
const pFee = exempt ? 0n : (taxable * fee) / WAD;
|
|
663
|
+
const leaving = pFee !== 0n && collector !== ZERO_ADDRESS ? amount : amount - pFee;
|
|
664
|
+
q -= leaving;
|
|
665
|
+
amounts.push(amount);
|
|
666
|
+
}
|
|
667
|
+
if (q > 0n)
|
|
668
|
+
throw new Error("logswap: the bid does not empty in two harvests (no collector, income above Q) — harvest by hand first");
|
|
669
|
+
return amounts;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* The relaunch as ONE transaction (decisions 025, 032, 035, 037): `harvest` the bid out — a
|
|
673
|
+
* dividend to every share, {@link fPoolEmptyingHarvests} — `dissolve` the live generation at the
|
|
674
|
+
* empty bid, `redeem` the caller's own shares of it (when `shares` > 0), optionally `setLegs` the
|
|
675
|
+
* next generation's composition (`legs`: a private pool's reshape — retire, admit, reweight), and
|
|
676
|
+
* `seed` it with what came back — the manager's `multicall`, one sender throughout, the same
|
|
677
|
+
* pool. The operator's when one is appointed and the seed's inventory is its own; by default the
|
|
678
|
+
* authority's. Gates, allowlist and names carry over; anything else goes in `extra`, pre-encoded
|
|
679
|
+
* against {@link fPoolManagerAbi}. The seed names reserves (decisions 029): `r0` outright — one
|
|
680
|
+
* per leg of the NEXT table, 0 for a retired leg — or `x0` marks against the next table's
|
|
681
|
+
* `weights`.
|
|
615
682
|
*/
|
|
616
683
|
export async function fPoolRelaunch(c, a) {
|
|
617
|
-
const gen = await fPoolGen(c, a.poolId);
|
|
618
|
-
const r0 = "r0" in a ? a.r0 : a.x0.map((x, j) => fPoolReserveAt((a.weights[j] * a.L0) / WAD, x));
|
|
684
|
+
const [gen, harvests] = await Promise.all([fPoolGen(c, a.poolId), fPoolEmptyingHarvests(c, a.poolId)]);
|
|
685
|
+
const r0 = "r0" in a ? a.r0 : a.x0.map((x, j) => (a.weights[j] === 0n ? 0n : fPoolReserveAt((a.weights[j] * a.L0) / WAD, x)));
|
|
619
686
|
const enc = (functionName, args) => encodeFunctionData({ abi: fPoolManagerAbi, functionName, args });
|
|
620
687
|
const calls = [
|
|
688
|
+
...harvests.map((amount) => enc("harvest", [a.poolId, amount, a.account])),
|
|
621
689
|
enc("dissolve", [a.poolId]),
|
|
622
690
|
...(a.shares > 0n ? [enc("redeem", [a.poolId, BigInt(gen), a.account, a.shares])] : []),
|
|
691
|
+
...(a.legs ? [enc("setLegs", [a.poolId, a.legs.weights, a.legs.newBases ?? []])] : []),
|
|
623
692
|
enc("seed", [a.poolId, a.L0, r0, a.Q0]),
|
|
624
693
|
...(a.extra ?? []),
|
|
625
694
|
];
|
|
626
695
|
return writeFPool0(c, "multicall", [calls], a.account);
|
|
627
696
|
}
|
|
628
|
-
/**
|
|
697
|
+
/** Where a pad's seed lives (decisions 036): `seed` mints every share of a pad here itself. */
|
|
629
698
|
export const DEAD_ADDRESS = "0x000000000000000000000000000000000000dEaD";
|
|
630
|
-
/** The manager's `MIN_SHARES`: the seed mints this much to 0xdead
|
|
699
|
+
/** 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. */
|
|
631
700
|
export const F_MIN_SHARES = 1000n;
|
|
632
701
|
/**
|
|
633
702
|
* The launch's calls, in order — the batch {@link fPoolLaunch} sends. Pure, so a form can show
|
|
@@ -643,15 +712,14 @@ export function fPoolLaunchCalls(poolId, a) {
|
|
|
643
712
|
if (given.length !== a.bases.length)
|
|
644
713
|
throw new Error(`logswap: ${given.length} reserves for ${a.bases.length} legs`);
|
|
645
714
|
const { bases, companions } = sortFPoolLegs(a.bases, a.weights, given);
|
|
646
|
-
const key = { quote: a.quote, bases, weights: companions[0], phi: a.phi,
|
|
715
|
+
const key = { quote: a.quote, bases, weights: companions[0], phi: a.phi, kind: F_KIND[a.kind], authority: a.authority, salt: a.salt ?? ZERO_SALT };
|
|
647
716
|
const enc = (functionName, args) => encodeFunctionData({ abi: fPoolManagerAbi, functionName, args });
|
|
648
717
|
const calls = [];
|
|
649
718
|
if (!a.initialized)
|
|
650
719
|
calls.push(enc("initialize", [key]));
|
|
651
720
|
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
|
-
|
|
654
|
-
calls.push(enc("transfer", [DEAD_ADDRESS, fPoolShareId(poolId, 0), a.L0 - F_MIN_SHARES]));
|
|
721
|
+
// gen 0 by construction: a launch is the pool's FIRST seed — a relaunch is `fPoolRelaunch`.
|
|
722
|
+
// No transfer to 0xdead: on a pad `seed` mints every share there itself (decisions 036).
|
|
655
723
|
if (a.openBuy) {
|
|
656
724
|
const j = bases.indexOf(a.bases[a.openBuy.j]);
|
|
657
725
|
if (j < 0)
|
|
@@ -660,10 +728,11 @@ export function fPoolLaunchCalls(poolId, a) {
|
|
|
660
728
|
}
|
|
661
729
|
if (a.name)
|
|
662
730
|
calls.push(enc("setName", [poolId, textToBytes32(a.name)]));
|
|
663
|
-
if (a.
|
|
731
|
+
if (a.kind === "private") {
|
|
732
|
+
// the desk's opening posture: gated minting, the creator listed. No appointment: the
|
|
733
|
+
// authority is the operator until one is appointed (decisions 037)
|
|
664
734
|
calls.push(enc("setGates", [poolId, true, false]));
|
|
665
735
|
calls.push(enc("setAllowed", [poolId, [a.account], true]));
|
|
666
|
-
calls.push(enc("appointOperator", [poolId, a.account]));
|
|
667
736
|
}
|
|
668
737
|
calls.push(...(a.extra ?? []));
|
|
669
738
|
return calls;
|
|
@@ -749,35 +818,37 @@ export async function fPoolSponsorName(c, who) {
|
|
|
749
818
|
}));
|
|
750
819
|
return bytes32ToText(word);
|
|
751
820
|
}
|
|
752
|
-
/**
|
|
753
|
-
export
|
|
754
|
-
return
|
|
821
|
+
/** Who runs the pool (decisions 037): the appointed operator, or the authority until one is. */
|
|
822
|
+
export function fPoolOperatorOf(s) {
|
|
823
|
+
return s.operator === ZERO_ADDRESS ? s.authority : s.operator;
|
|
755
824
|
}
|
|
756
825
|
/**
|
|
757
|
-
*
|
|
758
|
-
*
|
|
826
|
+
* Propose the operator (authority; private pools only) — the hot key that runs the pool: `harvest`,
|
|
827
|
+
* `dissolve`, `setLegs`. Two-step: the proposed address takes the role with
|
|
828
|
+
* {@link fPoolAcceptOperator}. The zero address clears at once — the role returns to the authority.
|
|
759
829
|
*/
|
|
760
|
-
export async function
|
|
761
|
-
return writeFPool(c, a.poolId, "
|
|
830
|
+
export async function fPoolAppointOperator(c, a) {
|
|
831
|
+
return writeFPool(c, a.poolId, "appointOperator", [a.operator], a.account);
|
|
832
|
+
}
|
|
833
|
+
/** The proposed operator takes the role. */
|
|
834
|
+
export async function fPoolAcceptOperator(c, a) {
|
|
835
|
+
return writeFPool(c, a.poolId, "acceptOperator", [], a.account);
|
|
762
836
|
}
|
|
763
837
|
/**
|
|
764
|
-
*
|
|
765
|
-
*
|
|
766
|
-
*
|
|
767
|
-
*
|
|
768
|
-
*
|
|
838
|
+
* The next generation's composition (operator; private pools only; ONLY while the pool is
|
|
839
|
+
* unseeded — between a dissolve and the seed that prices it, decisions 037). `weights` has one
|
|
840
|
+
* entry per leg the pool has ever had, in index order (0 retires a leg; indices are never reused),
|
|
841
|
+
* then one per base in `newBases`, appended; they sum to 1e18 exactly. No value moves: the
|
|
842
|
+
* following {@link fPoolSeed} names every reserve. A live reshape is {@link fPoolRelaunch} with
|
|
843
|
+
* `legs` set.
|
|
769
844
|
*/
|
|
770
|
-
export async function
|
|
771
|
-
return writeFPool(c, a.poolId, "
|
|
772
|
-
}
|
|
773
|
-
/** Admit a base the pool has never held: `R` of it against liquidity `Lj`, so at `p = Lj / R` (operator, sole LP only). */
|
|
774
|
-
export async function fPoolAdmitLeg(c, a) {
|
|
775
|
-
return writeFPool(c, a.poolId, "admitLeg", [a.base, a.Lj, a.R], a.account);
|
|
845
|
+
export async function fPoolSetLegs(c, a) {
|
|
846
|
+
return writeFPool(c, a.poolId, "setLegs", [a.weights, a.newBases ?? []], a.account);
|
|
776
847
|
}
|
|
777
848
|
/**
|
|
778
849
|
* Move shares (ERC-6909 `transfer`) — to another holder, or to `0xdead` to lock them for good.
|
|
779
850
|
* Burning to the dead address is a sponsor's way to make its liquidity permanent: the shares can
|
|
780
|
-
* never be redeemed
|
|
851
|
+
* never be redeemed.
|
|
781
852
|
*/
|
|
782
853
|
export async function fPoolTransferShares(c, a) {
|
|
783
854
|
const wallet = requireWallet(c);
|
|
@@ -793,7 +864,7 @@ export async function fPoolTransferShares(c, a) {
|
|
|
793
864
|
}
|
|
794
865
|
/**
|
|
795
866
|
* Every F pool ever created, from `Initialize` logs alone. Possible only because the event
|
|
796
|
-
* carries the full key preimage (bases, weights, phi,
|
|
867
|
+
* carries the full key preimage (bases, weights, phi, pad) — the poolId is a hash and could
|
|
797
868
|
* never be inverted; contracts PR #17 exists for exactly this call.
|
|
798
869
|
*/
|
|
799
870
|
export async function discoverFPools(c, opts = {}) {
|
|
@@ -826,12 +897,12 @@ export async function discoverFPools(c, opts = {}) {
|
|
|
826
897
|
bases: [...a.bases],
|
|
827
898
|
weights: [...a.weights],
|
|
828
899
|
phi: a.phi,
|
|
829
|
-
|
|
900
|
+
kind: fPoolKindOf(a.kind),
|
|
830
901
|
authority: a.authority,
|
|
831
902
|
block: l.blockNumber ?? 0n,
|
|
832
903
|
seeded: q0 !== undefined,
|
|
833
904
|
q0: q0 ?? 0n,
|
|
834
|
-
shape: a.
|
|
905
|
+
shape: a.kind === F_KIND.pad ? "launch" : "basket", // the kind, not n = 1: a mono POL is a pool (decisions 036)
|
|
835
906
|
};
|
|
836
907
|
});
|
|
837
908
|
}
|
|
@@ -865,7 +936,7 @@ export async function fPoolShareHolders(c, poolIdHex, opts = {}) {
|
|
|
865
936
|
.map(([holder, shares]) => ({ holder: holder, shares }))
|
|
866
937
|
.sort((a, b) => (b.shares > a.shares ? 1 : -1));
|
|
867
938
|
}
|
|
868
|
-
/** Every F pool's state in one lens call (the raw manager struct: quote, phi, authority,
|
|
939
|
+
/** Every F pool's state in one lens call (the raw manager struct: quote, phi, authority, kind, seeded, gen, n, Q, L, shares, theta0, bigSigma, harvestedTheta). */
|
|
869
940
|
export async function getFPoolsRaw(c, poolIds) {
|
|
870
941
|
const { logswapLensAbi } = await import("./generated.js");
|
|
871
942
|
return (await c.public.readContract({ address: c.addresses.lens, abi: logswapLensAbi, functionName: "getFPools", args: [poolIds] }));
|