@latchprotocol/widgets 0.1.0
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/LICENSE +21 -0
- package/README.md +649 -0
- package/dist/adapters/binDistribution.d.ts +19 -0
- package/dist/adapters/binDistribution.d.ts.map +1 -0
- package/dist/adapters/protocol.d.ts +409 -0
- package/dist/adapters/protocol.d.ts.map +1 -0
- package/dist/adapters/sale.d.ts +142 -0
- package/dist/adapters/sale.d.ts.map +1 -0
- package/dist/adapters/viem.d.ts +89 -0
- package/dist/adapters/viem.d.ts.map +1 -0
- package/dist/callpath/constants.d.ts +218 -0
- package/dist/callpath/constants.d.ts.map +1 -0
- package/dist/callpath/launch.d.ts +1979 -0
- package/dist/callpath/launch.d.ts.map +1 -0
- package/dist/callpath/liquidity.d.ts +103 -0
- package/dist/callpath/liquidity.d.ts.map +1 -0
- package/dist/callpath/plan.d.ts +34 -0
- package/dist/callpath/plan.d.ts.map +1 -0
- package/dist/callpath/swap.d.ts +129 -0
- package/dist/callpath/swap.d.ts.map +1 -0
- package/dist/chunks/SwapWidget-DgyHAVc8.js +2404 -0
- package/dist/chunks/SwapWidget-DgyHAVc8.js.map +1 -0
- package/dist/chunks/scan-Dhu7f4Nl.js +2497 -0
- package/dist/chunks/scan-Dhu7f4Nl.js.map +1 -0
- package/dist/chunks/useLocker-D1c_NTk-.js +1613 -0
- package/dist/chunks/useLocker-D1c_NTk-.js.map +1 -0
- package/dist/components/LaunchWidget.d.ts +117 -0
- package/dist/components/LaunchWidget.d.ts.map +1 -0
- package/dist/components/LiquidityWidget.d.ts +33 -0
- package/dist/components/LiquidityWidget.d.ts.map +1 -0
- package/dist/components/LockerWidget.d.ts +51 -0
- package/dist/components/LockerWidget.d.ts.map +1 -0
- package/dist/components/LocksWidgets.d.ts +61 -0
- package/dist/components/LocksWidgets.d.ts.map +1 -0
- package/dist/components/SwapWidget.d.ts +165 -0
- package/dist/components/SwapWidget.d.ts.map +1 -0
- package/dist/components/TokenTrustPanel.d.ts +32 -0
- package/dist/components/TokenTrustPanel.d.ts.map +1 -0
- package/dist/components/lockCharts.d.ts +29 -0
- package/dist/components/lockCharts.d.ts.map +1 -0
- package/dist/components/portal.d.ts +10 -0
- package/dist/components/portal.d.ts.map +1 -0
- package/dist/components/primitives.d.ts +139 -0
- package/dist/components/primitives.d.ts.map +1 -0
- package/dist/components/swap/SwapSettings.d.ts +12 -0
- package/dist/components/swap/SwapSettings.d.ts.map +1 -0
- package/dist/components/swap/TokenSelect.d.ts +61 -0
- package/dist/components/swap/TokenSelect.d.ts.map +1 -0
- package/dist/components/swap/state.d.ts +208 -0
- package/dist/components/swap/state.d.ts.map +1 -0
- package/dist/config/chain.d.ts +163 -0
- package/dist/config/chain.d.ts.map +1 -0
- package/dist/config/integrator.d.ts +121 -0
- package/dist/config/integrator.d.ts.map +1 -0
- package/dist/context/WidgetProvider.d.ts +78 -0
- package/dist/context/WidgetProvider.d.ts.map +1 -0
- package/dist/core/clMath.d.ts +98 -0
- package/dist/core/clMath.d.ts.map +1 -0
- package/dist/core/errors.d.ts +18 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/format.d.ts +47 -0
- package/dist/core/format.d.ts.map +1 -0
- package/dist/core/liquidityGuards.d.ts +53 -0
- package/dist/core/liquidityGuards.d.ts.map +1 -0
- package/dist/core/liquidityRefresh.d.ts +35 -0
- package/dist/core/liquidityRefresh.d.ts.map +1 -0
- package/dist/core/math.d.ts +129 -0
- package/dist/core/math.d.ts.map +1 -0
- package/dist/core/pool.d.ts +33 -0
- package/dist/core/pool.d.ts.map +1 -0
- package/dist/core/tokenLists.d.ts +46 -0
- package/dist/core/tokenLists.d.ts.map +1 -0
- package/dist/embed/iframe.d.ts +185 -0
- package/dist/embed/iframe.d.ts.map +1 -0
- package/dist/embed/lockBadge.d.ts +55 -0
- package/dist/embed/lockBadge.d.ts.map +1 -0
- package/dist/embed/webComponent.d.ts +83 -0
- package/dist/embed/webComponent.d.ts.map +1 -0
- package/dist/embed.d.ts +25 -0
- package/dist/embed.d.ts.map +1 -0
- package/dist/embed.js +543 -0
- package/dist/embed.js.map +1 -0
- package/dist/headless.d.ts +60 -0
- package/dist/headless.d.ts.map +1 -0
- package/dist/headless.js +223 -0
- package/dist/headless.js.map +1 -0
- package/dist/hooks/useAsyncResource.d.ts +38 -0
- package/dist/hooks/useAsyncResource.d.ts.map +1 -0
- package/dist/hooks/useLaunch.d.ts +140 -0
- package/dist/hooks/useLaunch.d.ts.map +1 -0
- package/dist/hooks/useLiquidity.d.ts +91 -0
- package/dist/hooks/useLiquidity.d.ts.map +1 -0
- package/dist/hooks/useLocker.d.ts +77 -0
- package/dist/hooks/useLocker.d.ts.map +1 -0
- package/dist/hooks/useLocks.d.ts +33 -0
- package/dist/hooks/useLocks.d.ts.map +1 -0
- package/dist/hooks/useSwapExecute.d.ts +46 -0
- package/dist/hooks/useSwapExecute.d.ts.map +1 -0
- package/dist/hooks/useSwapQuote.d.ts +51 -0
- package/dist/hooks/useSwapQuote.d.ts.map +1 -0
- package/dist/hooks/useTokenLists.d.ts +26 -0
- package/dist/hooks/useTokenLists.d.ts.map +1 -0
- package/dist/hooks/useTokenTrust.d.ts +40 -0
- package/dist/hooks/useTokenTrust.d.ts.map +1 -0
- package/dist/hooks/useTokens.d.ts +15 -0
- package/dist/hooks/useTokens.d.ts.map +1 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1052 -0
- package/dist/index.js.map +1 -0
- package/dist/latch-embed.d.ts +19 -0
- package/dist/latch-embed.d.ts.map +1 -0
- package/dist/latch-embed.js +950 -0
- package/dist/latch-embed.js.map +1 -0
- package/dist/latch-embed.mjs +13162 -0
- package/dist/latch-embed.mjs.map +1 -0
- package/dist/locker/model.d.ts +73 -0
- package/dist/locker/model.d.ts.map +1 -0
- package/dist/locks/embedModel.d.ts +22 -0
- package/dist/locks/embedModel.d.ts.map +1 -0
- package/dist/locks/fetch.d.ts +60 -0
- package/dist/locks/fetch.d.ts.map +1 -0
- package/dist/locks/model.d.ts +143 -0
- package/dist/locks/model.d.ts.map +1 -0
- package/dist/locks/scan.d.ts +25 -0
- package/dist/locks/scan.d.ts.map +1 -0
- package/dist/styles/css.d.ts +32 -0
- package/dist/styles/css.d.ts.map +1 -0
- package/dist/styles.css +895 -0
- package/dist/trust/model.d.ts +48 -0
- package/dist/trust/model.d.ts.map +1 -0
- package/package.json +102 -0
|
@@ -0,0 +1,1613 @@
|
|
|
1
|
+
import { encodeAbiParameters as A, encodeFunctionData as $, isAddressEqual as b, BaseError as J, ExecutionRevertedError as Z, decodeAbiParameters as Le, zeroAddress as Ie, parseUnits as Ae } from "viem";
|
|
2
|
+
import { NATIVE_CURRENCY as Ce, quoterAbiFor as Te, isDynamicLPFee as Me, BIN_LAUNCH_GUARD_HOOK_ABI as ee, readBinPoolKeyParameters as te, binRawPriceFromId as ne, poolKeyToId as oe, readCLPoolKeyParameters as Ne, LAUNCHPAD_KIT_V2_ABI as Se, getDeployment as $e, CLOCK_MODE_CALLDATA as Pe, TIMESTAMP_CLOCK_MODE as Be, readContractClock as xe, readTokenMeta as De } from "@latchprotocol/sdk";
|
|
3
|
+
import { B as O, b6 as F, A as C, t as j, u as G, p as Q, E as N, w as f, bj as L, P as ie, m as Oe, l as Ee, n as _e, aT as ae, W as E, a4 as Re, bu as Fe, aI as Ge, aJ as se, G as U, _ as qe, bA as Ue, X as re, ae as Ke, aN as Xe, aY as Ye, F as We, b$ as me, bF as P, b9 as He, ao as Ve, ap as je, bx as Qe, bq as ce, aj as ze, bL as Je } from "./scan-Dhu7f4Nl.js";
|
|
4
|
+
import { useState as he, useEffect as Ze, useRef as et, useCallback as ue, useMemo as tt } from "react";
|
|
5
|
+
import { describeTokenLocks as nt, describeLaunch as ot, summarizeTokenTrust as it, describeLiquidity as at, describeLpFee as st, describeProtocolFee as rt, describeCreatorTax as ye, describeRegistry as ct, formatTrustSource as ut, readTokenTrust as lt } from "@latchprotocol/sdk/trust";
|
|
6
|
+
import { readFeeGate as le, readChainNow as dt, readPositionLocksOf as pt, readBeneficiaryLocks as mt } from "@latchprotocol/sdk/lock";
|
|
7
|
+
function ht(t, e, o) {
|
|
8
|
+
if (t > e)
|
|
9
|
+
throw new RangeError(`binIdLower ${t} exceeds binIdUpper ${e}`);
|
|
10
|
+
const n = [];
|
|
11
|
+
for (let p = t; p <= e; p += 1) n.push(p);
|
|
12
|
+
const a = n.filter((p) => p >= o).length, i = n.filter((p) => p <= o).length, s = e, r = Math.min(o, e), l = [];
|
|
13
|
+
let c = 0n, d = 0n;
|
|
14
|
+
for (const p of n) {
|
|
15
|
+
const m = p >= o && a > 0 ? O / BigInt(a) : 0n, u = p <= o && i > 0 ? O / BigInt(i) : 0n, h = p === s && m > 0n ? O - c : m, y = p === r && u > 0n ? O - d : u;
|
|
16
|
+
c += h, d += y, l.push({ binId: p, deltaId: p - o, distributionX: h, distributionY: y });
|
|
17
|
+
}
|
|
18
|
+
return l;
|
|
19
|
+
}
|
|
20
|
+
class Et extends Error {
|
|
21
|
+
constructor() {
|
|
22
|
+
super(
|
|
23
|
+
"[@latchprotocol/widgets] no sale adapter is configured. Latch has no sale contract - a launch is a pool with LaunchGuardHook attached, and buying into one is a swap. Set ProtocolAdapter.sale only if you run your own sale contract."
|
|
24
|
+
), this.name = "NoSaleAdapterError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function _t(t) {
|
|
28
|
+
return t.sale !== void 0;
|
|
29
|
+
}
|
|
30
|
+
const yt = [
|
|
31
|
+
{ name: "poolKey", type: "tuple", components: j },
|
|
32
|
+
{ name: "tickLower", type: "int24" },
|
|
33
|
+
{ name: "tickUpper", type: "int24" },
|
|
34
|
+
{ name: "liquidity", type: "uint256" },
|
|
35
|
+
{ name: "amount0Max", type: "uint128" },
|
|
36
|
+
{ name: "amount1Max", type: "uint128" },
|
|
37
|
+
{ name: "owner", type: "address" },
|
|
38
|
+
{ name: "hookData", type: "bytes" }
|
|
39
|
+
], ft = [
|
|
40
|
+
{ name: "tokenId", type: "uint256" },
|
|
41
|
+
{ name: "liquidity", type: "uint256" },
|
|
42
|
+
{ name: "amount0", type: "uint128" },
|
|
43
|
+
{ name: "amount1", type: "uint128" },
|
|
44
|
+
{ name: "hookData", type: "bytes" }
|
|
45
|
+
], fe = [
|
|
46
|
+
{ name: "currency0", type: "address" },
|
|
47
|
+
{ name: "currency1", type: "address" }
|
|
48
|
+
], ke = [
|
|
49
|
+
{ name: "currency0", type: "address" },
|
|
50
|
+
{ name: "currency1", type: "address" },
|
|
51
|
+
{ name: "recipient", type: "address" }
|
|
52
|
+
], kt = [
|
|
53
|
+
{ name: "currency", type: "address" },
|
|
54
|
+
{ name: "to", type: "address" }
|
|
55
|
+
];
|
|
56
|
+
function be() {
|
|
57
|
+
return [
|
|
58
|
+
C.SWEEP,
|
|
59
|
+
A(kt, [Ce, Q]),
|
|
60
|
+
"sweep unspent native value back to the caller"
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
const bt = [
|
|
64
|
+
{
|
|
65
|
+
name: "params",
|
|
66
|
+
type: "tuple",
|
|
67
|
+
components: [
|
|
68
|
+
{ name: "poolKey", type: "tuple", components: j },
|
|
69
|
+
{ name: "amount0", type: "uint128" },
|
|
70
|
+
{ name: "amount1", type: "uint128" },
|
|
71
|
+
{ name: "amount0Max", type: "uint128" },
|
|
72
|
+
{ name: "amount1Max", type: "uint128" },
|
|
73
|
+
{ name: "activeIdDesired", type: "uint256" },
|
|
74
|
+
{ name: "idSlippage", type: "uint256" },
|
|
75
|
+
{ name: "deltaIds", type: "int256[]" },
|
|
76
|
+
{ name: "distributionX", type: "uint256[]" },
|
|
77
|
+
{ name: "distributionY", type: "uint256[]" },
|
|
78
|
+
{ name: "minLiquidities", type: "uint256[]" },
|
|
79
|
+
{ name: "to", type: "address" },
|
|
80
|
+
{ name: "hookData", type: "bytes" }
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
], wt = [
|
|
84
|
+
{
|
|
85
|
+
name: "params",
|
|
86
|
+
type: "tuple",
|
|
87
|
+
components: [
|
|
88
|
+
{ name: "poolKey", type: "tuple", components: j },
|
|
89
|
+
{ name: "amount0Min", type: "uint128" },
|
|
90
|
+
{ name: "amount1Min", type: "uint128" },
|
|
91
|
+
{ name: "ids", type: "uint256[]" },
|
|
92
|
+
{ name: "amounts", type: "uint256[]" },
|
|
93
|
+
{ name: "from", type: "address" },
|
|
94
|
+
{ name: "hookData", type: "bytes" }
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
];
|
|
98
|
+
function z(t) {
|
|
99
|
+
return {
|
|
100
|
+
currency0: t.currency0,
|
|
101
|
+
currency1: t.currency1,
|
|
102
|
+
hooks: t.hooks,
|
|
103
|
+
poolManager: t.poolManager,
|
|
104
|
+
fee: t.fee,
|
|
105
|
+
parameters: t.parameters
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function gt(t) {
|
|
109
|
+
if (At(t.tickLower, t.tickUpper), t.liquidity <= 0n)
|
|
110
|
+
throw new RangeError(`[@latchprotocol/widgets] liquidity must be positive: ${t.liquidity}`);
|
|
111
|
+
const e = F().add(
|
|
112
|
+
C.CL_MINT_POSITION,
|
|
113
|
+
A(yt, [
|
|
114
|
+
z(t.poolKey),
|
|
115
|
+
t.tickLower,
|
|
116
|
+
t.tickUpper,
|
|
117
|
+
t.liquidity,
|
|
118
|
+
t.amount0Max,
|
|
119
|
+
t.amount1Max,
|
|
120
|
+
t.owner,
|
|
121
|
+
t.hookData ?? "0x"
|
|
122
|
+
]),
|
|
123
|
+
`mint CL position [${t.tickLower}, ${t.tickUpper}]`
|
|
124
|
+
).add(
|
|
125
|
+
C.SETTLE_PAIR,
|
|
126
|
+
A(fe, [t.poolKey.currency0, t.poolKey.currency1]),
|
|
127
|
+
"settle both currencies from the caller"
|
|
128
|
+
);
|
|
129
|
+
return (t.value ?? 0n) > 0n && e.add(...be()), {
|
|
130
|
+
to: t.positionManager,
|
|
131
|
+
data: $({
|
|
132
|
+
abi: G,
|
|
133
|
+
functionName: "modifyLiquidities",
|
|
134
|
+
args: [e.encode(), t.deadline]
|
|
135
|
+
}),
|
|
136
|
+
value: t.value ?? 0n,
|
|
137
|
+
planTrace: e.describe()
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function vt(t) {
|
|
141
|
+
if (t.liquidity <= 0n)
|
|
142
|
+
throw new RangeError(
|
|
143
|
+
`[@latchprotocol/widgets] liquidity to remove must be positive: ${t.liquidity}`
|
|
144
|
+
);
|
|
145
|
+
const e = t.recipient === t.owner ? Q : t.recipient, o = F().add(
|
|
146
|
+
C.CL_DECREASE_LIQUIDITY,
|
|
147
|
+
A(ft, [
|
|
148
|
+
t.tokenId,
|
|
149
|
+
t.liquidity,
|
|
150
|
+
t.amount0Min,
|
|
151
|
+
t.amount1Min,
|
|
152
|
+
t.hookData ?? "0x"
|
|
153
|
+
]),
|
|
154
|
+
`decrease CL position #${t.tokenId} by ${t.liquidity}`
|
|
155
|
+
).add(
|
|
156
|
+
C.TAKE_PAIR,
|
|
157
|
+
A(ke, [
|
|
158
|
+
t.poolKey.currency0,
|
|
159
|
+
t.poolKey.currency1,
|
|
160
|
+
e
|
|
161
|
+
]),
|
|
162
|
+
"take both currencies to the recipient"
|
|
163
|
+
);
|
|
164
|
+
return {
|
|
165
|
+
to: t.positionManager,
|
|
166
|
+
data: $({
|
|
167
|
+
abi: G,
|
|
168
|
+
functionName: "modifyLiquidities",
|
|
169
|
+
args: [o.encode(), t.deadline]
|
|
170
|
+
}),
|
|
171
|
+
value: 0n,
|
|
172
|
+
planTrace: o.describe()
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function Lt(t) {
|
|
176
|
+
const e = t.deltaIds.length;
|
|
177
|
+
if (e === 0)
|
|
178
|
+
throw new RangeError("[@latchprotocol/widgets] a bin mint must target at least one bin");
|
|
179
|
+
if (t.distributionX.length !== e || t.distributionY.length !== e)
|
|
180
|
+
throw new RangeError(
|
|
181
|
+
"[@latchprotocol/widgets] deltaIds, distributionX and distributionY must be the same length"
|
|
182
|
+
);
|
|
183
|
+
if (!Number.isInteger(t.activeIdDesired) || t.activeIdDesired < 0)
|
|
184
|
+
throw new RangeError(
|
|
185
|
+
`[@latchprotocol/widgets] activeIdDesired must be a non-negative integer: ${t.activeIdDesired}`
|
|
186
|
+
);
|
|
187
|
+
const o = F().add(
|
|
188
|
+
C.BIN_ADD_LIQUIDITY,
|
|
189
|
+
A(bt, [
|
|
190
|
+
{
|
|
191
|
+
poolKey: z(t.poolKey),
|
|
192
|
+
amount0: t.amount0,
|
|
193
|
+
amount1: t.amount1,
|
|
194
|
+
amount0Max: t.amount0Max,
|
|
195
|
+
amount1Max: t.amount1Max,
|
|
196
|
+
activeIdDesired: BigInt(t.activeIdDesired),
|
|
197
|
+
idSlippage: BigInt(t.idSlippage),
|
|
198
|
+
deltaIds: t.deltaIds.map((n) => BigInt(n)),
|
|
199
|
+
distributionX: [...t.distributionX],
|
|
200
|
+
distributionY: [...t.distributionY],
|
|
201
|
+
// One entry per bin. Zero means "accept whatever the pool mints"; the
|
|
202
|
+
// real slippage guard for a bin mint is idSlippage plus amountNMax.
|
|
203
|
+
minLiquidities: t.deltaIds.map(() => 0n),
|
|
204
|
+
to: t.to,
|
|
205
|
+
hookData: t.hookData ?? "0x"
|
|
206
|
+
}
|
|
207
|
+
]),
|
|
208
|
+
`add bin liquidity across ${e} bins around id ${t.activeIdDesired}`
|
|
209
|
+
).add(
|
|
210
|
+
C.SETTLE_PAIR,
|
|
211
|
+
A(fe, [t.poolKey.currency0, t.poolKey.currency1]),
|
|
212
|
+
"settle both currencies from the caller"
|
|
213
|
+
);
|
|
214
|
+
return (t.value ?? 0n) > 0n && o.add(...be()), {
|
|
215
|
+
to: t.positionManager,
|
|
216
|
+
data: $({
|
|
217
|
+
abi: G,
|
|
218
|
+
functionName: "modifyLiquidities",
|
|
219
|
+
args: [o.encode(), t.deadline]
|
|
220
|
+
}),
|
|
221
|
+
value: t.value ?? 0n,
|
|
222
|
+
planTrace: o.describe()
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function It(t) {
|
|
226
|
+
if (t.ids.length === 0)
|
|
227
|
+
throw new RangeError("[@latchprotocol/widgets] a bin burn must target at least one bin");
|
|
228
|
+
if (t.ids.length !== t.amounts.length)
|
|
229
|
+
throw new RangeError("[@latchprotocol/widgets] ids and amounts must be the same length");
|
|
230
|
+
const e = t.recipient === t.from ? Q : t.recipient, o = F().add(
|
|
231
|
+
C.BIN_REMOVE_LIQUIDITY,
|
|
232
|
+
A(wt, [
|
|
233
|
+
{
|
|
234
|
+
poolKey: z(t.poolKey),
|
|
235
|
+
amount0Min: t.amount0Min,
|
|
236
|
+
amount1Min: t.amount1Min,
|
|
237
|
+
ids: t.ids.map((n) => BigInt(n)),
|
|
238
|
+
amounts: [...t.amounts],
|
|
239
|
+
from: t.from,
|
|
240
|
+
hookData: t.hookData ?? "0x"
|
|
241
|
+
}
|
|
242
|
+
]),
|
|
243
|
+
`remove bin liquidity from ${t.ids.length} bins`
|
|
244
|
+
).add(
|
|
245
|
+
C.TAKE_PAIR,
|
|
246
|
+
A(ke, [
|
|
247
|
+
t.poolKey.currency0,
|
|
248
|
+
t.poolKey.currency1,
|
|
249
|
+
e
|
|
250
|
+
]),
|
|
251
|
+
"take both currencies to the recipient"
|
|
252
|
+
);
|
|
253
|
+
return {
|
|
254
|
+
to: t.positionManager,
|
|
255
|
+
data: $({
|
|
256
|
+
abi: G,
|
|
257
|
+
functionName: "modifyLiquidities",
|
|
258
|
+
args: [o.encode(), t.deadline]
|
|
259
|
+
}),
|
|
260
|
+
value: 0n,
|
|
261
|
+
planTrace: o.describe()
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function At(t, e) {
|
|
265
|
+
if (!Number.isInteger(t) || !Number.isInteger(e))
|
|
266
|
+
throw new RangeError(
|
|
267
|
+
`[@latchprotocol/widgets] ticks must be integers: [${t}, ${e}]`
|
|
268
|
+
);
|
|
269
|
+
if (t >= e)
|
|
270
|
+
throw new RangeError(
|
|
271
|
+
`[@latchprotocol/widgets] tickLower must be below tickUpper: [${t}, ${e}]`
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
const K = [
|
|
275
|
+
{
|
|
276
|
+
type: "function",
|
|
277
|
+
name: "getSlot0",
|
|
278
|
+
stateMutability: "view",
|
|
279
|
+
inputs: [{ name: "id", type: "bytes32" }],
|
|
280
|
+
outputs: [
|
|
281
|
+
{ name: "sqrtPriceX96", type: "uint160" },
|
|
282
|
+
{ name: "tick", type: "int24" },
|
|
283
|
+
{ name: "protocolFee", type: "uint24" },
|
|
284
|
+
{ name: "lpFee", type: "uint24" }
|
|
285
|
+
]
|
|
286
|
+
}
|
|
287
|
+
], X = [
|
|
288
|
+
{
|
|
289
|
+
type: "function",
|
|
290
|
+
name: "getSlot0",
|
|
291
|
+
stateMutability: "view",
|
|
292
|
+
inputs: [{ name: "id", type: "bytes32" }],
|
|
293
|
+
outputs: [
|
|
294
|
+
{ name: "activeId", type: "uint24" },
|
|
295
|
+
{ name: "protocolFee", type: "uint24" },
|
|
296
|
+
{ name: "lpFee", type: "uint24" }
|
|
297
|
+
]
|
|
298
|
+
}
|
|
299
|
+
], de = 2n ** 192n, _ = [
|
|
300
|
+
{
|
|
301
|
+
type: "function",
|
|
302
|
+
name: "getLiquidity",
|
|
303
|
+
stateMutability: "view",
|
|
304
|
+
inputs: [{ name: "id", type: "bytes32" }],
|
|
305
|
+
outputs: [{ name: "liquidity", type: "uint128" }]
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
type: "function",
|
|
309
|
+
name: "getFeeGrowthGlobals",
|
|
310
|
+
stateMutability: "view",
|
|
311
|
+
inputs: [{ name: "id", type: "bytes32" }],
|
|
312
|
+
outputs: [
|
|
313
|
+
{ name: "feeGrowthGlobal0x128", type: "uint256" },
|
|
314
|
+
{ name: "feeGrowthGlobal1x128", type: "uint256" }
|
|
315
|
+
]
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
type: "function",
|
|
319
|
+
name: "getPoolTickInfo",
|
|
320
|
+
stateMutability: "view",
|
|
321
|
+
inputs: [
|
|
322
|
+
{ name: "id", type: "bytes32" },
|
|
323
|
+
{ name: "tick", type: "int24" }
|
|
324
|
+
],
|
|
325
|
+
outputs: [
|
|
326
|
+
{
|
|
327
|
+
name: "info",
|
|
328
|
+
type: "tuple",
|
|
329
|
+
components: [
|
|
330
|
+
{ name: "liquidityGross", type: "uint128" },
|
|
331
|
+
{ name: "liquidityNet", type: "int128" },
|
|
332
|
+
{ name: "feeGrowthOutside0X128", type: "uint256" },
|
|
333
|
+
{ name: "feeGrowthOutside1X128", type: "uint256" }
|
|
334
|
+
]
|
|
335
|
+
}
|
|
336
|
+
]
|
|
337
|
+
}
|
|
338
|
+
], pe = [
|
|
339
|
+
{
|
|
340
|
+
type: "function",
|
|
341
|
+
name: "getBin",
|
|
342
|
+
stateMutability: "view",
|
|
343
|
+
inputs: [
|
|
344
|
+
{ name: "id", type: "bytes32" },
|
|
345
|
+
{ name: "binId", type: "uint24" }
|
|
346
|
+
],
|
|
347
|
+
outputs: [
|
|
348
|
+
{ name: "binReserveX", type: "uint128" },
|
|
349
|
+
{ name: "binReserveY", type: "uint128" },
|
|
350
|
+
{ name: "binLiquidity", type: "uint256" },
|
|
351
|
+
{ name: "totalShares", type: "uint256" }
|
|
352
|
+
]
|
|
353
|
+
}
|
|
354
|
+
], we = {
|
|
355
|
+
name: "poolKey",
|
|
356
|
+
type: "tuple",
|
|
357
|
+
components: [
|
|
358
|
+
{ name: "currency0", type: "address" },
|
|
359
|
+
{ name: "currency1", type: "address" },
|
|
360
|
+
{ name: "hooks", type: "address" },
|
|
361
|
+
{ name: "poolManager", type: "address" },
|
|
362
|
+
{ name: "fee", type: "uint24" },
|
|
363
|
+
{ name: "parameters", type: "bytes32" }
|
|
364
|
+
]
|
|
365
|
+
}, Y = [
|
|
366
|
+
{
|
|
367
|
+
type: "function",
|
|
368
|
+
name: "ownerOf",
|
|
369
|
+
stateMutability: "view",
|
|
370
|
+
inputs: [{ name: "id", type: "uint256" }],
|
|
371
|
+
outputs: [{ name: "owner", type: "address" }]
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
type: "function",
|
|
375
|
+
name: "positions",
|
|
376
|
+
stateMutability: "view",
|
|
377
|
+
inputs: [{ name: "tokenId", type: "uint256" }],
|
|
378
|
+
outputs: [
|
|
379
|
+
we,
|
|
380
|
+
{ name: "tickLower", type: "int24" },
|
|
381
|
+
{ name: "tickUpper", type: "int24" },
|
|
382
|
+
{ name: "liquidity", type: "uint128" },
|
|
383
|
+
{ name: "feeGrowthInside0LastX128", type: "uint256" },
|
|
384
|
+
{ name: "feeGrowthInside1LastX128", type: "uint256" },
|
|
385
|
+
{ name: "subscriber", type: "address" }
|
|
386
|
+
]
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
type: "event",
|
|
390
|
+
name: "Transfer",
|
|
391
|
+
inputs: [
|
|
392
|
+
{ name: "from", type: "address", indexed: !0 },
|
|
393
|
+
{ name: "to", type: "address", indexed: !0 },
|
|
394
|
+
{ name: "id", type: "uint256", indexed: !0 }
|
|
395
|
+
]
|
|
396
|
+
}
|
|
397
|
+
], W = [
|
|
398
|
+
{
|
|
399
|
+
type: "function",
|
|
400
|
+
name: "positions",
|
|
401
|
+
stateMutability: "view",
|
|
402
|
+
inputs: [{ name: "tokenId", type: "uint256" }],
|
|
403
|
+
outputs: [we, { name: "binId", type: "uint24" }]
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
type: "function",
|
|
407
|
+
name: "balanceOf",
|
|
408
|
+
stateMutability: "view",
|
|
409
|
+
inputs: [
|
|
410
|
+
{ name: "owner", type: "address" },
|
|
411
|
+
{ name: "id", type: "uint256" }
|
|
412
|
+
],
|
|
413
|
+
outputs: [{ name: "balance", type: "uint256" }]
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
type: "event",
|
|
417
|
+
name: "TransferBatch",
|
|
418
|
+
inputs: [
|
|
419
|
+
{ name: "sender", type: "address", indexed: !0 },
|
|
420
|
+
{ name: "from", type: "address", indexed: !0 },
|
|
421
|
+
{ name: "to", type: "address", indexed: !0 },
|
|
422
|
+
{ name: "ids", type: "uint256[]", indexed: !1 },
|
|
423
|
+
{ name: "amounts", type: "uint256[]", indexed: !1 }
|
|
424
|
+
]
|
|
425
|
+
}
|
|
426
|
+
], S = "0x0000000000000000000000000000000000000000";
|
|
427
|
+
class Ct {
|
|
428
|
+
kind = "viem";
|
|
429
|
+
isMock = !1;
|
|
430
|
+
chain;
|
|
431
|
+
#t;
|
|
432
|
+
constructor(e) {
|
|
433
|
+
this.#t = e, this.chain = e.chain;
|
|
434
|
+
}
|
|
435
|
+
get #e() {
|
|
436
|
+
return this.#t.publicClient;
|
|
437
|
+
}
|
|
438
|
+
get #n() {
|
|
439
|
+
return this.#t.overrides ?? {};
|
|
440
|
+
}
|
|
441
|
+
async getAccount() {
|
|
442
|
+
const e = this.#t.wallet;
|
|
443
|
+
return e === void 0 ? null : e.getAccount();
|
|
444
|
+
}
|
|
445
|
+
async listTokens() {
|
|
446
|
+
return this.#t.tokens;
|
|
447
|
+
}
|
|
448
|
+
async getToken(e) {
|
|
449
|
+
const o = this.#t.tokens.find((s) => b(s.address, e));
|
|
450
|
+
if (o !== void 0) return o;
|
|
451
|
+
if (b(e, S))
|
|
452
|
+
return {
|
|
453
|
+
address: S,
|
|
454
|
+
symbol: this.chain.nativeCurrency.symbol,
|
|
455
|
+
name: this.chain.nativeCurrency.name,
|
|
456
|
+
decimals: this.chain.nativeCurrency.decimals,
|
|
457
|
+
isNative: !0
|
|
458
|
+
};
|
|
459
|
+
const [n, a, i] = await Promise.all([
|
|
460
|
+
this.#e.readContract({ address: e, abi: N, functionName: "symbol" }),
|
|
461
|
+
this.#e.readContract({ address: e, abi: N, functionName: "name" }),
|
|
462
|
+
this.#e.readContract({ address: e, abi: N, functionName: "decimals" })
|
|
463
|
+
]);
|
|
464
|
+
return { address: e, symbol: n, name: a, decimals: Number(i) };
|
|
465
|
+
}
|
|
466
|
+
async getBalance(e, o) {
|
|
467
|
+
return e.isNative === !0 || b(e.address, S) ? this.#e.getBalance({ address: o }) : this.#e.readContract({
|
|
468
|
+
address: e.address,
|
|
469
|
+
abi: N,
|
|
470
|
+
functionName: "balanceOf",
|
|
471
|
+
args: [o]
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
async listPools() {
|
|
475
|
+
return this.#t.pools;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* The pool's live state from its manager's `getSlot0` (plus `getLiquidity`
|
|
479
|
+
* for a CL pool). An uninitialised pool answers a zero price, which is
|
|
480
|
+
* reported as an error rather than as tick 0.
|
|
481
|
+
*/
|
|
482
|
+
async getPoolState(e) {
|
|
483
|
+
const o = this.#n.getPoolState;
|
|
484
|
+
if (o !== void 0) return o(e);
|
|
485
|
+
if (e.poolType === "CL") {
|
|
486
|
+
const [[a, i], s] = await Promise.all([
|
|
487
|
+
this.#e.readContract({ address: e.key.poolManager, abi: K, functionName: "getSlot0", args: [e.id] }),
|
|
488
|
+
this.#e.readContract({ address: e.key.poolManager, abi: _, functionName: "getLiquidity", args: [e.id] })
|
|
489
|
+
]);
|
|
490
|
+
if (a === 0n)
|
|
491
|
+
throw new f("getPoolState", `pool ${e.id} is not initialised on ${e.key.poolManager}`);
|
|
492
|
+
return { poolId: e.id, poolType: "CL", currentTick: i, sqrtPriceX96: a, liquidity: s, source: "live" };
|
|
493
|
+
}
|
|
494
|
+
const [n] = await this.#e.readContract({ address: e.key.poolManager, abi: X, functionName: "getSlot0", args: [e.id] });
|
|
495
|
+
if (n === 0)
|
|
496
|
+
throw new f("getPoolState", `pool ${e.id} is not initialised on ${e.key.poolManager}`);
|
|
497
|
+
return { poolId: e.id, poolType: "BIN", activeId: n, source: "live" };
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* The two allowances `spender` needs before it can pull `token` through
|
|
501
|
+
* Permit2: ERC-20 to Permit2, then Permit2 to the spender. The spender is
|
|
502
|
+
* the router for a swap (the default) and a position manager for a
|
|
503
|
+
* liquidity add; the liquidity hooks pass it, because an allowance to the
|
|
504
|
+
* router does nothing for a mint.
|
|
505
|
+
*/
|
|
506
|
+
async getApprovalRequirements(e, o, n, a) {
|
|
507
|
+
if (e.isNative === !0 || b(e.address, S)) return [];
|
|
508
|
+
const i = L(this.chain, "permit2", "pull the input token for a swap"), s = a ?? L(this.chain, "universalRouter", "execute a swap"), r = [], l = await this.#e.readContract({
|
|
509
|
+
address: e.address,
|
|
510
|
+
abi: N,
|
|
511
|
+
functionName: "allowance",
|
|
512
|
+
args: [o, i]
|
|
513
|
+
});
|
|
514
|
+
l < n && r.push({
|
|
515
|
+
kind: "erc20-to-permit2",
|
|
516
|
+
token: e,
|
|
517
|
+
spender: i,
|
|
518
|
+
current: l,
|
|
519
|
+
required: n
|
|
520
|
+
});
|
|
521
|
+
const [c, d] = await this.#e.readContract({
|
|
522
|
+
address: i,
|
|
523
|
+
abi: ie,
|
|
524
|
+
functionName: "allowance",
|
|
525
|
+
args: [o, e.address, s]
|
|
526
|
+
}), p = BigInt(Math.floor(Date.now() / 1e3)), m = BigInt(d) !== 0n && BigInt(d) <= p;
|
|
527
|
+
return (BigInt(c) < n || m) && r.push({
|
|
528
|
+
kind: "permit2-to-router",
|
|
529
|
+
token: e,
|
|
530
|
+
spender: s,
|
|
531
|
+
current: m ? 0n : BigInt(c),
|
|
532
|
+
required: n
|
|
533
|
+
}), r;
|
|
534
|
+
}
|
|
535
|
+
async buildApproval(e) {
|
|
536
|
+
return e.kind === "erc20-to-permit2" ? {
|
|
537
|
+
to: e.token.address,
|
|
538
|
+
data: $({
|
|
539
|
+
abi: N,
|
|
540
|
+
functionName: "approve",
|
|
541
|
+
args: [e.spender, Oe]
|
|
542
|
+
}),
|
|
543
|
+
value: 0n,
|
|
544
|
+
summary: `Approve ${e.token.symbol} for Permit2`,
|
|
545
|
+
source: "live"
|
|
546
|
+
} : {
|
|
547
|
+
to: L(this.chain, "permit2", "approve the router through Permit2"),
|
|
548
|
+
data: $({
|
|
549
|
+
abi: ie,
|
|
550
|
+
functionName: "approve",
|
|
551
|
+
args: [e.token.address, e.spender, Ee, Number(_e)]
|
|
552
|
+
}),
|
|
553
|
+
value: 0n,
|
|
554
|
+
summary: `Approve ${e.spender} to spend ${e.token.symbol} via Permit2`,
|
|
555
|
+
source: "live"
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Quotes an exact-input swap.
|
|
560
|
+
*
|
|
561
|
+
* With `overrides.quoteSwap` the host answers. Otherwise every configured
|
|
562
|
+
* pool holding both tokens is quoted DIRECTLY against the deployed quoter for
|
|
563
|
+
* its type (`contracts.quoter` for CL, `contracts.binQuoter` for Bin) and the
|
|
564
|
+
* best output wins. No multi-hop routing: a route this adapter did not quote
|
|
565
|
+
* is a route it cannot vouch for. Throws when no quoter can answer.
|
|
566
|
+
*
|
|
567
|
+
* The LP fee shown beside the quote is the pool's static fee, or, for a
|
|
568
|
+
* dynamic-fee pool whose hook is a launch guard, the guard's `currentFee`.
|
|
569
|
+
* Any other dynamic pool is reported `lpFeeUnknown`, which the widget renders
|
|
570
|
+
* as "dynamic" rather than as a rate it did not read.
|
|
571
|
+
*/
|
|
572
|
+
async quoteSwap(e) {
|
|
573
|
+
const o = this.#n.quoteSwap;
|
|
574
|
+
if (o !== void 0) return o(e, this.#t.pools);
|
|
575
|
+
const n = this.chain.contracts, a = this.#t.pools.filter(
|
|
576
|
+
(u) => (e.poolId === void 0 || u.id === e.poolId) && (b(u.token0.address, e.tokenIn.address) && b(u.token1.address, e.tokenOut.address) || b(u.token1.address, e.tokenIn.address) && b(u.token0.address, e.tokenOut.address))
|
|
577
|
+
);
|
|
578
|
+
if (a.length === 0)
|
|
579
|
+
throw new f(
|
|
580
|
+
"quoteSwap",
|
|
581
|
+
e.poolId !== void 0 ? `pool ${e.poolId} is not a configured pool holding both ${e.tokenIn.symbol} and ${e.tokenOut.symbol}.` : `no configured pool holds both ${e.tokenIn.symbol} and ${e.tokenOut.symbol}. This adapter quotes direct pools only; supply \`overrides.quoteSwap\` for multi-hop routes.`
|
|
582
|
+
);
|
|
583
|
+
const i = a.filter(
|
|
584
|
+
(u) => u.poolType === "CL" ? n.quoter !== void 0 : n.binQuoter !== void 0
|
|
585
|
+
);
|
|
586
|
+
if (i.length === 0)
|
|
587
|
+
throw new f(
|
|
588
|
+
"quoteSwap",
|
|
589
|
+
`a pool for this pair exists but no quoter is configured for its type (${a.map((u) => u.poolType).join(", ")}). Set \`contracts.quoter\` (CL) / \`contracts.binQuoter\` (Bin), or supply \`overrides.quoteSwap\`. This adapter will not estimate a price it cannot verify.`
|
|
590
|
+
);
|
|
591
|
+
const s = await Promise.all(
|
|
592
|
+
i.map(async (u) => {
|
|
593
|
+
const h = u.poolType === "CL" ? n.quoter : n.binQuoter;
|
|
594
|
+
try {
|
|
595
|
+
const { result: y } = await this.#e.simulateContract({
|
|
596
|
+
address: h,
|
|
597
|
+
abi: Te(u.poolType),
|
|
598
|
+
functionName: "quoteExactInputSingle",
|
|
599
|
+
args: [
|
|
600
|
+
{
|
|
601
|
+
poolKey: u.key,
|
|
602
|
+
zeroForOne: b(u.key.currency0, e.tokenIn.address),
|
|
603
|
+
exactAmount: e.amountIn,
|
|
604
|
+
hookData: "0x"
|
|
605
|
+
}
|
|
606
|
+
]
|
|
607
|
+
}), [w, k] = y;
|
|
608
|
+
return { pool: u, amountOut: w, gasEstimate: k, error: null };
|
|
609
|
+
} catch (y) {
|
|
610
|
+
return { pool: u, amountOut: 0n, gasEstimate: 0n, error: y instanceof Error ? y : new Error(String(y)) };
|
|
611
|
+
}
|
|
612
|
+
})
|
|
613
|
+
), r = s.filter((u) => u.error === null);
|
|
614
|
+
if (r.length === 0) {
|
|
615
|
+
const u = s[0]?.error;
|
|
616
|
+
throw new f(
|
|
617
|
+
"quoteSwap",
|
|
618
|
+
`every direct pool for this pair failed to quote${u == null ? "" : `: ${u.message}`}`
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
const l = r.reduce((u, h) => h.amountOut > u.amountOut ? h : u), c = l.pool;
|
|
622
|
+
let d = c.lpFeePips, p = !1;
|
|
623
|
+
if (Me(c.lpFeePips)) {
|
|
624
|
+
const u = await this.#c(c);
|
|
625
|
+
u === null ? (d = 0, p = !0) : d = u;
|
|
626
|
+
}
|
|
627
|
+
const m = p ? null : await this.#u(c, e.tokenIn.address, e.amountIn, d);
|
|
628
|
+
return {
|
|
629
|
+
route: [
|
|
630
|
+
{
|
|
631
|
+
poolId: c.id,
|
|
632
|
+
poolType: c.poolType,
|
|
633
|
+
tokenIn: e.tokenIn,
|
|
634
|
+
tokenOut: e.tokenOut,
|
|
635
|
+
lpFeePips: d,
|
|
636
|
+
hooks: c.hooks
|
|
637
|
+
}
|
|
638
|
+
],
|
|
639
|
+
amountIn: e.amountIn,
|
|
640
|
+
grossAmountOut: l.amountOut,
|
|
641
|
+
spotAmountOut: m,
|
|
642
|
+
lpFeeAmount: e.amountIn * BigInt(d) / 1000000n,
|
|
643
|
+
lpFeePips: d,
|
|
644
|
+
...p ? { lpFeeUnknown: p } : {},
|
|
645
|
+
estimatedGas: l.gasEstimate,
|
|
646
|
+
source: "live"
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* `currentFee(poolId)` when the pool's hook is one of the configured launch
|
|
651
|
+
* guards; `null` when the hook is not a guard (the fee is then genuinely
|
|
652
|
+
* unreadable in advance). A guard that REVERTS `currentFee` — an unclaimed
|
|
653
|
+
* pool id — is also `null`. Anything else (transport failure, an unknown
|
|
654
|
+
* `CLOCK_MODE`) is thrown: an unreachable RPC is an error state, never a
|
|
655
|
+
* quote annotated "dynamic".
|
|
656
|
+
*/
|
|
657
|
+
async #c(e) {
|
|
658
|
+
const o = this.#o(e);
|
|
659
|
+
if (o === null) return null;
|
|
660
|
+
const n = o.poolType === "CL" ? ae(await this.#r(o.hook, "CL")) : ee;
|
|
661
|
+
try {
|
|
662
|
+
const a = await this.#e.readContract({ address: o.hook, abi: n, functionName: "currentFee", args: [e.id] });
|
|
663
|
+
return Number(a);
|
|
664
|
+
} catch (a) {
|
|
665
|
+
if (a instanceof J && a.walk((i) => i instanceof Z) !== null)
|
|
666
|
+
return null;
|
|
667
|
+
throw a;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
/** The configured launch guard this pool names, if any, with the pool type it serves. */
|
|
671
|
+
#o(e) {
|
|
672
|
+
const { launchGuardHook: o, binLaunchGuardHook: n } = this.chain.contracts;
|
|
673
|
+
return e.poolType === "CL" && o !== void 0 && b(e.hooks, o) ? { hook: o, poolType: "CL" } : e.poolType === "BIN" && n !== void 0 && b(e.hooks, n) ? { hook: n, poolType: "BIN" } : null;
|
|
674
|
+
}
|
|
675
|
+
/** `amountIn` priced at the pool's spot from `getSlot0`, less `lpFeePips`; `null` when the read fails. */
|
|
676
|
+
async #u(e, o, n, a) {
|
|
677
|
+
const i = b(e.key.currency0, o), s = n * BigInt(1e6 - a) / 1000000n;
|
|
678
|
+
try {
|
|
679
|
+
if (e.poolType === "CL") {
|
|
680
|
+
const [m] = await this.#e.readContract({ address: e.key.poolManager, abi: K, functionName: "getSlot0", args: [e.id] });
|
|
681
|
+
if (m === 0n) return null;
|
|
682
|
+
const u = m * m;
|
|
683
|
+
return i ? s * u / de : s * de / u;
|
|
684
|
+
}
|
|
685
|
+
const [r] = await this.#e.readContract({ address: e.key.poolManager, abi: X, functionName: "getSlot0", args: [e.id] }), { binStep: l } = te(e.key), c = ne(Number(r), l);
|
|
686
|
+
if (!Number.isFinite(c) || c <= 0) return null;
|
|
687
|
+
const d = 10n ** 18n, p = BigInt(Math.round(c * 1e18));
|
|
688
|
+
return p === 0n ? null : i ? s * p / d : s * d / p;
|
|
689
|
+
} catch {
|
|
690
|
+
return null;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
async buildSwap(e) {
|
|
694
|
+
const o = L(this.chain, "universalRouter", "execute a swap"), n = await this.getAccount();
|
|
695
|
+
if (n === null) throw new E("build a swap");
|
|
696
|
+
const a = this.#l(e), i = Re({
|
|
697
|
+
router: o,
|
|
698
|
+
hops: a,
|
|
699
|
+
amountIn: e.amountIn,
|
|
700
|
+
minAmountOutGross: e.minAmountOutGross,
|
|
701
|
+
minAmountOutNet: e.minAmountOutNet,
|
|
702
|
+
expectedAmountOutGross: e.quote.grossAmountOut,
|
|
703
|
+
integrator: e.integrator,
|
|
704
|
+
recipient: e.recipient,
|
|
705
|
+
sender: n,
|
|
706
|
+
deadline: e.deadline
|
|
707
|
+
});
|
|
708
|
+
return {
|
|
709
|
+
to: i.to,
|
|
710
|
+
data: i.data,
|
|
711
|
+
value: i.value,
|
|
712
|
+
summary: `Swap ${e.tokenIn.symbol} for ${e.tokenOut.symbol}`,
|
|
713
|
+
...i.integratorFee ? {
|
|
714
|
+
integratorFee: {
|
|
715
|
+
referrer: i.integratorFee.referrer,
|
|
716
|
+
feeBps: i.integratorFee.feeBps,
|
|
717
|
+
currency: i.integratorFee.currency,
|
|
718
|
+
expectedAmount: i.integratorFee.expectedAmount
|
|
719
|
+
}
|
|
720
|
+
} : {},
|
|
721
|
+
source: "live"
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
#l(e) {
|
|
725
|
+
const o = this.#n.findRoute;
|
|
726
|
+
if (o !== void 0)
|
|
727
|
+
return o(e.tokenIn, e.tokenOut, this.#t.pools);
|
|
728
|
+
const n = [];
|
|
729
|
+
for (const a of e.quote.route) {
|
|
730
|
+
const i = this.#t.pools.find((s) => s.id === a.poolId);
|
|
731
|
+
if (i === void 0)
|
|
732
|
+
throw new f(
|
|
733
|
+
"buildSwap",
|
|
734
|
+
`the quote routes through pool ${a.poolId}, which is not in the configured pool list`
|
|
735
|
+
);
|
|
736
|
+
n.push({
|
|
737
|
+
poolKey: i.key,
|
|
738
|
+
poolType: i.poolType,
|
|
739
|
+
currencyIn: a.tokenIn.address,
|
|
740
|
+
currencyOut: a.tokenOut.address,
|
|
741
|
+
...e.hookData ? { hookData: e.hookData } : {}
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
return n;
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Turns desired amounts into the liquidity the pool will mint and the
|
|
748
|
+
* amounts it will pull, from live state and the pool's own formulas
|
|
749
|
+
* (`core/clMath.ts`; `adapters/binDistribution.ts`). The amounts reported
|
|
750
|
+
* are what the position manager settles: an add rounds towards the pool.
|
|
751
|
+
*/
|
|
752
|
+
async quoteAddLiquidity(e) {
|
|
753
|
+
const o = this.#n.quoteAddLiquidity;
|
|
754
|
+
if (o !== void 0) return o(e);
|
|
755
|
+
const { pool: n, range: a } = e;
|
|
756
|
+
if (a.type === "CL") {
|
|
757
|
+
if (n.poolType !== "CL")
|
|
758
|
+
throw new f("quoteAddLiquidity", "tick range given for a bin pool");
|
|
759
|
+
const h = Fe(n);
|
|
760
|
+
if (a.tickLower % h !== 0 || a.tickUpper % h !== 0)
|
|
761
|
+
throw new RangeError(
|
|
762
|
+
`[@latchprotocol/widgets] ticks must be multiples of the pool's spacing ${h}: [${a.tickLower}, ${a.tickUpper}]`
|
|
763
|
+
);
|
|
764
|
+
const y = await this.getPoolState(n), w = y.sqrtPriceX96, k = Ge(
|
|
765
|
+
w,
|
|
766
|
+
se(a.tickLower),
|
|
767
|
+
se(a.tickUpper),
|
|
768
|
+
e.amount0Desired,
|
|
769
|
+
e.amount1Desired
|
|
770
|
+
);
|
|
771
|
+
if (k === 0n)
|
|
772
|
+
throw new f(
|
|
773
|
+
"quoteAddLiquidity",
|
|
774
|
+
"these amounts mint no liquidity in this range: at the pool's price the range needs the other token, or the amounts are too small"
|
|
775
|
+
);
|
|
776
|
+
const T = U(w, a.tickLower, a.tickUpper, k, !0), B = y.currentTick >= a.tickLower && y.currentTick < a.tickUpper, g = y.liquidity ?? 0n, M = B ? Number(k * 10000n / (g + k)) : null;
|
|
777
|
+
return { pool: n, range: a, amount0: T.amount0, amount1: T.amount1, liquidity: k, shareBps: M, source: "live" };
|
|
778
|
+
}
|
|
779
|
+
if (n.poolType !== "BIN")
|
|
780
|
+
throw new f("quoteAddLiquidity", "bin range given for a CL pool");
|
|
781
|
+
const s = (await this.getPoolState(n)).activeId;
|
|
782
|
+
if (Math.abs(s - a.activeIdDesired) > a.idSlippage)
|
|
783
|
+
throw new f(
|
|
784
|
+
"quoteAddLiquidity",
|
|
785
|
+
`the active bin is ${s}, more than ${a.idSlippage} bins from the ${a.activeIdDesired} the range was built around; rebuild the range`
|
|
786
|
+
);
|
|
787
|
+
const r = ht(a.binIdLower, a.binIdUpper, a.activeIdDesired), l = r.some((h) => h.distributionX > 0n), c = r.some((h) => h.distributionY > 0n), d = l ? e.amount0Desired : 0n, p = c ? e.amount1Desired : 0n;
|
|
788
|
+
if (d + p === 0n)
|
|
789
|
+
throw new f(
|
|
790
|
+
"quoteAddLiquidity",
|
|
791
|
+
"nothing to deposit: the chosen bins take only the token whose amount is zero"
|
|
792
|
+
);
|
|
793
|
+
const m = qe(n);
|
|
794
|
+
let u = 0n;
|
|
795
|
+
for (const h of r) {
|
|
796
|
+
const y = d * h.distributionX / 10n ** 18n, w = p * h.distributionY / 10n ** 18n, k = ne(h.binId, m);
|
|
797
|
+
u += BigInt(Math.floor(Number(y) * k)) + w;
|
|
798
|
+
}
|
|
799
|
+
return { pool: n, range: a, amount0: d, amount1: p, liquidity: u, shareBps: null, binDistribution: r, source: "live" };
|
|
800
|
+
}
|
|
801
|
+
async buildAddLiquidity(e) {
|
|
802
|
+
if (await this.getAccount() === null) throw new E("add liquidity");
|
|
803
|
+
const { quote: n } = e, a = this.#d(n.pool, e.amount0Max, e.amount1Max);
|
|
804
|
+
if (n.range.type === "CL") {
|
|
805
|
+
const l = L(
|
|
806
|
+
this.chain,
|
|
807
|
+
"clPositionManager",
|
|
808
|
+
"mint a concentrated-liquidity position"
|
|
809
|
+
), c = gt({
|
|
810
|
+
positionManager: l,
|
|
811
|
+
poolKey: n.pool.key,
|
|
812
|
+
tickLower: n.range.tickLower,
|
|
813
|
+
tickUpper: n.range.tickUpper,
|
|
814
|
+
liquidity: n.liquidity,
|
|
815
|
+
amount0Max: e.amount0Max,
|
|
816
|
+
amount1Max: e.amount1Max,
|
|
817
|
+
owner: e.recipient,
|
|
818
|
+
deadline: e.deadline,
|
|
819
|
+
value: a,
|
|
820
|
+
...e.hookData ? { hookData: e.hookData } : {}
|
|
821
|
+
});
|
|
822
|
+
return {
|
|
823
|
+
to: c.to,
|
|
824
|
+
data: c.data,
|
|
825
|
+
value: c.value,
|
|
826
|
+
summary: `Add liquidity to ${n.pool.token0.symbol}/${n.pool.token1.symbol}`,
|
|
827
|
+
source: "live"
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
const i = L(
|
|
831
|
+
this.chain,
|
|
832
|
+
"binPositionManager",
|
|
833
|
+
"add liquidity to a bin pool"
|
|
834
|
+
), s = n.binDistribution;
|
|
835
|
+
if (s === void 0 || s.length === 0)
|
|
836
|
+
throw new f(
|
|
837
|
+
"buildAddLiquidity",
|
|
838
|
+
"a bin mint needs a per-bin distribution; the quote did not supply one"
|
|
839
|
+
);
|
|
840
|
+
const r = Lt({
|
|
841
|
+
positionManager: i,
|
|
842
|
+
poolKey: n.pool.key,
|
|
843
|
+
amount0: n.amount0,
|
|
844
|
+
amount1: n.amount1,
|
|
845
|
+
amount0Max: e.amount0Max,
|
|
846
|
+
amount1Max: e.amount1Max,
|
|
847
|
+
activeIdDesired: n.range.activeIdDesired,
|
|
848
|
+
idSlippage: n.range.idSlippage,
|
|
849
|
+
deltaIds: s.map((l) => l.deltaId),
|
|
850
|
+
distributionX: s.map((l) => l.distributionX),
|
|
851
|
+
distributionY: s.map((l) => l.distributionY),
|
|
852
|
+
to: e.recipient,
|
|
853
|
+
deadline: e.deadline,
|
|
854
|
+
value: a,
|
|
855
|
+
...e.hookData ? { hookData: e.hookData } : {}
|
|
856
|
+
});
|
|
857
|
+
return {
|
|
858
|
+
to: r.to,
|
|
859
|
+
data: r.data,
|
|
860
|
+
value: r.value,
|
|
861
|
+
summary: `Add liquidity to ${n.pool.token0.symbol}/${n.pool.token1.symbol}`,
|
|
862
|
+
source: "live"
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
#d(e, o, n) {
|
|
866
|
+
return b(e.token0.address, S) ? o : b(e.token1.address, S) ? n : 0n;
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* A holder's positions, reconstructed from position-manager logs and
|
|
870
|
+
* confirmed against live state. Needs `positionsFromBlock`.
|
|
871
|
+
*
|
|
872
|
+
* CL: `Transfer(to = owner)` candidates, each confirmed by `ownerOf`, then
|
|
873
|
+
* `positions(tokenId)` for the key, ticks and liquidity; amounts and fees
|
|
874
|
+
* from the pool's slot0, tick info and fee-growth globals, exactly as the
|
|
875
|
+
* pool would credit them. Bin: `TransferBatch(to = owner)` candidates, each
|
|
876
|
+
* confirmed by `balanceOf`, grouped by pool; amounts from each bin's
|
|
877
|
+
* reserves and share supply. A position on a pool not in the configured
|
|
878
|
+
* list still appears, with its tokens read off their contracts.
|
|
879
|
+
*/
|
|
880
|
+
async listPositions(e, o) {
|
|
881
|
+
const n = this.#n.listPositions;
|
|
882
|
+
if (n !== void 0) return n(e, o);
|
|
883
|
+
const a = this.#t.positionsFromBlock;
|
|
884
|
+
if (a === void 0)
|
|
885
|
+
throw new f(
|
|
886
|
+
"listPositions",
|
|
887
|
+
"position enumeration scans the position managers' transfer logs and needs `positionsFromBlock` (the block they were deployed at) in the adapter options."
|
|
888
|
+
);
|
|
889
|
+
const i = o?.poolType, [s, r] = await Promise.all([
|
|
890
|
+
i === "BIN" ? Promise.resolve([]) : this.#p(e, a, o),
|
|
891
|
+
i === "CL" ? Promise.resolve([]) : this.#m(e, a, o)
|
|
892
|
+
]);
|
|
893
|
+
return [...s, ...r];
|
|
894
|
+
}
|
|
895
|
+
async #p(e, o, n) {
|
|
896
|
+
const a = this.chain.contracts.clPositionManager;
|
|
897
|
+
if (a === void 0) return [];
|
|
898
|
+
const i = await this.#e.getLogs({
|
|
899
|
+
address: a,
|
|
900
|
+
event: Y[2],
|
|
901
|
+
args: { to: e },
|
|
902
|
+
fromBlock: o,
|
|
903
|
+
toBlock: "latest"
|
|
904
|
+
}), s = [...new Set(i.map((l) => l.args.id))], r = [];
|
|
905
|
+
for (const l of s) {
|
|
906
|
+
let c;
|
|
907
|
+
try {
|
|
908
|
+
c = await this.#e.readContract({ address: a, abi: Y, functionName: "ownerOf", args: [l] });
|
|
909
|
+
} catch {
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
912
|
+
if (!b(c, e)) continue;
|
|
913
|
+
const [d, p, m, u, h, y] = await this.#e.readContract({
|
|
914
|
+
address: a,
|
|
915
|
+
abi: Y,
|
|
916
|
+
functionName: "positions",
|
|
917
|
+
args: [l]
|
|
918
|
+
}), w = await this.#a(d, "CL", n);
|
|
919
|
+
if (w === null) continue;
|
|
920
|
+
const [[k, T], [B, g], M, q] = await Promise.all([
|
|
921
|
+
this.#e.readContract({ address: d.poolManager, abi: K, functionName: "getSlot0", args: [w.id] }),
|
|
922
|
+
this.#e.readContract({ address: d.poolManager, abi: _, functionName: "getFeeGrowthGlobals", args: [w.id] }),
|
|
923
|
+
this.#e.readContract({ address: d.poolManager, abi: _, functionName: "getPoolTickInfo", args: [w.id, p] }),
|
|
924
|
+
this.#e.readContract({ address: d.poolManager, abi: _, functionName: "getPoolTickInfo", args: [w.id, m] })
|
|
925
|
+
]), D = U(k, p, m, u, !1), x = Ue({
|
|
926
|
+
liquidity: u,
|
|
927
|
+
tickLower: p,
|
|
928
|
+
tickUpper: m,
|
|
929
|
+
currentTick: T,
|
|
930
|
+
feeGrowthGlobal0X128: B,
|
|
931
|
+
feeGrowthGlobal1X128: g,
|
|
932
|
+
lower: M,
|
|
933
|
+
upper: q,
|
|
934
|
+
feeGrowthInside0LastX128: h,
|
|
935
|
+
feeGrowthInside1LastX128: y
|
|
936
|
+
});
|
|
937
|
+
r.push({
|
|
938
|
+
id: `cl:${l}`,
|
|
939
|
+
tokenId: l,
|
|
940
|
+
pool: w,
|
|
941
|
+
range: { type: "CL", tickLower: p, tickUpper: m },
|
|
942
|
+
liquidity: u,
|
|
943
|
+
amount0: D.amount0,
|
|
944
|
+
amount1: D.amount1,
|
|
945
|
+
feesOwed0: x.fees0,
|
|
946
|
+
feesOwed1: x.fees1,
|
|
947
|
+
inRange: T >= p && T < m,
|
|
948
|
+
source: "live"
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
return r;
|
|
952
|
+
}
|
|
953
|
+
async #m(e, o, n) {
|
|
954
|
+
const a = this.chain.contracts.binPositionManager;
|
|
955
|
+
if (a === void 0) return [];
|
|
956
|
+
const i = await this.#e.getLogs({
|
|
957
|
+
address: a,
|
|
958
|
+
event: W[2],
|
|
959
|
+
args: { to: e },
|
|
960
|
+
fromBlock: o,
|
|
961
|
+
toBlock: "latest"
|
|
962
|
+
}), s = [...new Set(i.flatMap((c) => c.args.ids ?? []))], r = /* @__PURE__ */ new Map();
|
|
963
|
+
for (const c of s) {
|
|
964
|
+
const d = await this.#e.readContract({ address: a, abi: W, functionName: "balanceOf", args: [e, c] });
|
|
965
|
+
if (d === 0n) continue;
|
|
966
|
+
const [p, m] = await this.#e.readContract({ address: a, abi: W, functionName: "positions", args: [c] }), u = oe(p), h = r.get(u) ?? { key: p, bins: [] };
|
|
967
|
+
h.bins.push({ binId: m, shares: d }), r.set(u, h);
|
|
968
|
+
}
|
|
969
|
+
const l = [];
|
|
970
|
+
for (const [c, { key: d, bins: p }] of r) {
|
|
971
|
+
const m = await this.#a(d, "BIN", n);
|
|
972
|
+
if (m === null) continue;
|
|
973
|
+
const [u] = await this.#e.readContract({ address: d.poolManager, abi: X, functionName: "getSlot0", args: [c] });
|
|
974
|
+
let h = 0n, y = 0n, w = 0n;
|
|
975
|
+
const k = [...p].sort((g, M) => g.binId - M.binId);
|
|
976
|
+
for (const g of k) {
|
|
977
|
+
const [M, q, , D] = await this.#e.readContract({
|
|
978
|
+
address: d.poolManager,
|
|
979
|
+
abi: pe,
|
|
980
|
+
functionName: "getBin",
|
|
981
|
+
args: [c, g.binId]
|
|
982
|
+
}), x = re({ shares: g.shares, totalShares: D, reserveX: M, reserveY: q });
|
|
983
|
+
h += x.amount0, y += x.amount1, w += g.shares;
|
|
984
|
+
}
|
|
985
|
+
const T = k[0], B = k[k.length - 1];
|
|
986
|
+
l.push({
|
|
987
|
+
id: `bin:${c}`,
|
|
988
|
+
pool: m,
|
|
989
|
+
range: { type: "BIN", activeIdDesired: u, binIdLower: T.binId, binIdUpper: B.binId, idSlippage: 0 },
|
|
990
|
+
liquidity: w,
|
|
991
|
+
amount0: h,
|
|
992
|
+
amount1: y,
|
|
993
|
+
/* Bin fees compound into the bins' reserves; they are inside amount0/amount1, never a separate figure. */
|
|
994
|
+
feesOwed0: 0n,
|
|
995
|
+
feesOwed1: 0n,
|
|
996
|
+
binAmounts: k.map((g) => ({ binId: g.binId, amount: g.shares })),
|
|
997
|
+
inRange: k.some((g) => g.binId === u),
|
|
998
|
+
source: "live"
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
return l;
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* The `PoolInfo` for a position's key: the configured one when the pool is
|
|
1005
|
+
* listed, else one built from the key with both tokens read off their
|
|
1006
|
+
* contracts. `null` when `only` names a different pool.
|
|
1007
|
+
*/
|
|
1008
|
+
async #a(e, o, n) {
|
|
1009
|
+
const a = oe(e);
|
|
1010
|
+
if (n !== void 0) return n.id.toLowerCase() === a.toLowerCase() ? n : null;
|
|
1011
|
+
const i = this.#t.pools.find((c) => c.id.toLowerCase() === a.toLowerCase());
|
|
1012
|
+
if (i !== void 0) return i;
|
|
1013
|
+
const [s, r] = await Promise.all([this.getToken(e.currency0), this.getToken(e.currency1)]);
|
|
1014
|
+
if (s === null || r === null) return null;
|
|
1015
|
+
const l = o === "CL" ? { tickSpacing: Ne(e).tickSpacing } : { binStep: te(e).binStep };
|
|
1016
|
+
return { id: a, key: e, poolType: o, token0: s, token1: r, lpFeePips: e.fee, hooks: e.hooks, ...l };
|
|
1017
|
+
}
|
|
1018
|
+
/**
|
|
1019
|
+
* What withdrawing `percentBps` of a position returns as PRINCIPAL, rounded
|
|
1020
|
+
* down as the pool rounds a burn. A CL decrease also pays out the position's
|
|
1021
|
+
* uncollected fees (`feesOwed0/1` on the position); they are not in these
|
|
1022
|
+
* figures because the position manager's minimum-out check is on the
|
|
1023
|
+
* principal alone, and a floor that counted fees could revert an honest
|
|
1024
|
+
* withdrawal.
|
|
1025
|
+
*/
|
|
1026
|
+
async quoteRemoveLiquidity(e, o) {
|
|
1027
|
+
const n = this.#n.quoteRemoveLiquidity;
|
|
1028
|
+
if (n !== void 0) return n(e, o);
|
|
1029
|
+
if (!Number.isInteger(o) || o <= 0 || o > 1e4)
|
|
1030
|
+
throw new RangeError(`[@latchprotocol/widgets] percentBps must be an integer in (0, 10000]: ${o}`);
|
|
1031
|
+
const { pool: a } = e;
|
|
1032
|
+
if (e.range.type === "CL") {
|
|
1033
|
+
const l = await this.getPoolState(a), c = e.liquidity * BigInt(o) / 10000n, d = U(l.sqrtPriceX96, e.range.tickLower, e.range.tickUpper, c, !1);
|
|
1034
|
+
return { position: e, percentBps: o, amount0: d.amount0, amount1: d.amount1, source: "live" };
|
|
1035
|
+
}
|
|
1036
|
+
const i = e.binAmounts ?? [];
|
|
1037
|
+
let s = 0n, r = 0n;
|
|
1038
|
+
for (const l of i) {
|
|
1039
|
+
const [c, d, , p] = await this.#e.readContract({
|
|
1040
|
+
address: a.key.poolManager,
|
|
1041
|
+
abi: pe,
|
|
1042
|
+
functionName: "getBin",
|
|
1043
|
+
args: [a.id, l.binId]
|
|
1044
|
+
}), m = re({ shares: l.amount * BigInt(o) / 10000n, totalShares: p, reserveX: c, reserveY: d });
|
|
1045
|
+
s += m.amount0, r += m.amount1;
|
|
1046
|
+
}
|
|
1047
|
+
return { position: e, percentBps: o, amount0: s, amount1: r, source: "live" };
|
|
1048
|
+
}
|
|
1049
|
+
async buildRemoveLiquidity(e) {
|
|
1050
|
+
const o = await this.getAccount();
|
|
1051
|
+
if (o === null) throw new E("remove liquidity");
|
|
1052
|
+
const { position: n } = e;
|
|
1053
|
+
if (n.range.type === "CL") {
|
|
1054
|
+
const r = L(
|
|
1055
|
+
this.chain,
|
|
1056
|
+
"clPositionManager",
|
|
1057
|
+
"decrease a concentrated-liquidity position"
|
|
1058
|
+
);
|
|
1059
|
+
if (n.tokenId === void 0)
|
|
1060
|
+
throw new f(
|
|
1061
|
+
"buildRemoveLiquidity",
|
|
1062
|
+
"a CL position must carry its ERC-721 tokenId"
|
|
1063
|
+
);
|
|
1064
|
+
const l = n.liquidity * BigInt(e.percentBps) / 10000n, c = vt({
|
|
1065
|
+
positionManager: r,
|
|
1066
|
+
poolKey: n.pool.key,
|
|
1067
|
+
tokenId: n.tokenId,
|
|
1068
|
+
liquidity: l,
|
|
1069
|
+
amount0Min: e.amount0Min,
|
|
1070
|
+
amount1Min: e.amount1Min,
|
|
1071
|
+
recipient: e.recipient,
|
|
1072
|
+
owner: o,
|
|
1073
|
+
deadline: e.deadline,
|
|
1074
|
+
...e.hookData ? { hookData: e.hookData } : {}
|
|
1075
|
+
});
|
|
1076
|
+
return {
|
|
1077
|
+
to: c.to,
|
|
1078
|
+
data: c.data,
|
|
1079
|
+
value: c.value,
|
|
1080
|
+
summary: `Remove ${e.percentBps / 100}% of position #${n.tokenId}`,
|
|
1081
|
+
source: "live"
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
const a = L(
|
|
1085
|
+
this.chain,
|
|
1086
|
+
"binPositionManager",
|
|
1087
|
+
"remove liquidity from a bin pool"
|
|
1088
|
+
), i = n.binAmounts;
|
|
1089
|
+
if (i === void 0 || i.length === 0)
|
|
1090
|
+
throw new f(
|
|
1091
|
+
"buildRemoveLiquidity",
|
|
1092
|
+
"a bin burn needs the per-bin share amounts held by the position"
|
|
1093
|
+
);
|
|
1094
|
+
const s = It({
|
|
1095
|
+
positionManager: a,
|
|
1096
|
+
poolKey: n.pool.key,
|
|
1097
|
+
amount0Min: e.amount0Min,
|
|
1098
|
+
amount1Min: e.amount1Min,
|
|
1099
|
+
ids: i.map((r) => r.binId),
|
|
1100
|
+
amounts: i.map(
|
|
1101
|
+
(r) => r.amount * BigInt(e.percentBps) / 10000n
|
|
1102
|
+
),
|
|
1103
|
+
from: o,
|
|
1104
|
+
recipient: e.recipient,
|
|
1105
|
+
deadline: e.deadline,
|
|
1106
|
+
...e.hookData ? { hookData: e.hookData } : {}
|
|
1107
|
+
});
|
|
1108
|
+
return {
|
|
1109
|
+
to: s.to,
|
|
1110
|
+
data: s.data,
|
|
1111
|
+
value: s.value,
|
|
1112
|
+
summary: `Remove ${e.percentBps / 100}% of a bin position`,
|
|
1113
|
+
source: "live"
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Requires at least one launch guard. A chain with neither is "no launchpad
|
|
1118
|
+
* here", signalled the way every missing contract is: `ChainConfigError`
|
|
1119
|
+
* naming `launchGuardHook`, which `isLaunchpadNotConfigured` recognises.
|
|
1120
|
+
*/
|
|
1121
|
+
#s(e) {
|
|
1122
|
+
const { launchGuardHook: o, binLaunchGuardHook: n } = this.chain.contracts;
|
|
1123
|
+
o === void 0 && n === void 0 && L(this.chain, "launchGuardHook", e);
|
|
1124
|
+
}
|
|
1125
|
+
/**
|
|
1126
|
+
* Every configured pool whose key names one of the chain's launch guards:
|
|
1127
|
+
* CL pools naming `launchGuardHook`, Bin pools naming `binLaunchGuardHook`.
|
|
1128
|
+
*
|
|
1129
|
+
* There is no on-chain enumeration of launches any more than there is of
|
|
1130
|
+
* pools, so the candidate set is the pool list the host supplied. Throws
|
|
1131
|
+
* `ChainConfigError` when no guard address is configured, which is how a
|
|
1132
|
+
* caller distinguishes "no launchpad on this chain" from "no launches yet".
|
|
1133
|
+
*/
|
|
1134
|
+
async listLaunches() {
|
|
1135
|
+
this.#s("read a launch schedule");
|
|
1136
|
+
const e = this.#t.pools.filter((n) => this.#o(n) !== null);
|
|
1137
|
+
return (await Promise.all(e.map((n) => this.#i(n)))).filter((n) => n !== null);
|
|
1138
|
+
}
|
|
1139
|
+
async getLaunch(e) {
|
|
1140
|
+
this.#s("read a launch schedule");
|
|
1141
|
+
const o = this.#t.pools.find((n) => n.id === e);
|
|
1142
|
+
if (o === void 0)
|
|
1143
|
+
throw new f(
|
|
1144
|
+
"getLaunch",
|
|
1145
|
+
`pool ${e} is not in the configured pool list. The singleton has no pool enumeration, so the widget can only read pools the host declared.`
|
|
1146
|
+
);
|
|
1147
|
+
return this.#o(o) === null ? null : this.#i(o);
|
|
1148
|
+
}
|
|
1149
|
+
/**
|
|
1150
|
+
* The pools a `LaunchpadKitV2` launch opened for `token`, read from the kit's
|
|
1151
|
+
* `legsOf(token)` and then from the guards, in leg order.
|
|
1152
|
+
*
|
|
1153
|
+
* Every leg's pool must be in the host's pool list — the kit knows the ids,
|
|
1154
|
+
* not the keys, and a pool the host has not declared cannot be quoted or
|
|
1155
|
+
* swapped through anyway. A missing one is an error naming the id, not a
|
|
1156
|
+
* shorter list.
|
|
1157
|
+
*/
|
|
1158
|
+
async getLaunchesForToken(e) {
|
|
1159
|
+
const o = L(this.chain, "launchpadKitV2", "look a launch up by its token"), n = await this.#e.readContract({
|
|
1160
|
+
address: o,
|
|
1161
|
+
abi: Se,
|
|
1162
|
+
functionName: "legsOf",
|
|
1163
|
+
args: [e]
|
|
1164
|
+
});
|
|
1165
|
+
if (n.length === 0) return [];
|
|
1166
|
+
const a = n.filter((r) => this.#t.pools.every((l) => l.id !== r));
|
|
1167
|
+
if (a.length > 0)
|
|
1168
|
+
throw new f(
|
|
1169
|
+
"getLaunchesForToken",
|
|
1170
|
+
`the kit lists ${n.length} pool(s) for ${e} but ${a.length} of them (${a.join(", ")}) are not in the configured pool list. Declare them (the pool manager's Initialize log carries the key) so the widget can read and route through them.`
|
|
1171
|
+
);
|
|
1172
|
+
const i = n.filter((r) => {
|
|
1173
|
+
const l = this.#t.pools.find((c) => c.id === r);
|
|
1174
|
+
return this.#o(l) === null;
|
|
1175
|
+
});
|
|
1176
|
+
if (i.length > 0)
|
|
1177
|
+
throw new f(
|
|
1178
|
+
"getLaunchesForToken",
|
|
1179
|
+
`${i.length} of the kit's pools for ${e} (${i.join(", ")}) name a launch guard this chain config does not declare. Set \`contracts.launchGuardHook\` (CL) and \`contracts.binLaunchGuardHook\` (Bin) to the kit's guards; a launch cannot be shown with a leg missing.`
|
|
1180
|
+
);
|
|
1181
|
+
return await Promise.all(
|
|
1182
|
+
n.map(async (r) => {
|
|
1183
|
+
const l = this.#t.pools.find((d) => d.id === r), c = await this.#i(l);
|
|
1184
|
+
if (c === null)
|
|
1185
|
+
throw new f(
|
|
1186
|
+
"getLaunchesForToken",
|
|
1187
|
+
`the kit lists pool ${r} for ${e} but its guard has no launch record for it`
|
|
1188
|
+
);
|
|
1189
|
+
return c;
|
|
1190
|
+
})
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* Which generation a launch hook is, by configuration first, then the SDK
|
|
1195
|
+
* address book, then the hook's own `CLOCK_MODE()` (a revert means the
|
|
1196
|
+
* block-numbered build). A transport failure throws; it is never a revert.
|
|
1197
|
+
*/
|
|
1198
|
+
async #r(e, o = "CL") {
|
|
1199
|
+
if (o === "CL") {
|
|
1200
|
+
const i = this.chain.contracts.launchGuardHookClock;
|
|
1201
|
+
if (i !== void 0) return i;
|
|
1202
|
+
}
|
|
1203
|
+
const n = $e(this.chain.chainId);
|
|
1204
|
+
if (o === "CL" && n?.launchGuardHook && b(n.launchGuardHook, e)) {
|
|
1205
|
+
const i = n.durationClocks.launchGuardHook;
|
|
1206
|
+
if (i !== null) return i;
|
|
1207
|
+
}
|
|
1208
|
+
const a = n?.launchpadV2;
|
|
1209
|
+
if (a !== void 0) {
|
|
1210
|
+
const i = o === "CL" ? a.clLaunchGuardHook : a.binLaunchGuardHook;
|
|
1211
|
+
if (i !== null && b(i, e)) return "timestamp";
|
|
1212
|
+
}
|
|
1213
|
+
try {
|
|
1214
|
+
const { data: i } = await this.#e.call({ to: e, data: Pe });
|
|
1215
|
+
if (i === void 0 || i === "0x") return "contract-block";
|
|
1216
|
+
const [s] = Le([{ type: "string" }], i);
|
|
1217
|
+
if (s === Be) return "timestamp";
|
|
1218
|
+
throw new f("getLaunch", `hook ${e} reports an unknown CLOCK_MODE "${s}"`);
|
|
1219
|
+
} catch (i) {
|
|
1220
|
+
if (i instanceof J && i.walk((s) => s instanceof Z) !== null)
|
|
1221
|
+
return "contract-block";
|
|
1222
|
+
throw i;
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
async #i(e) {
|
|
1226
|
+
const o = this.#o(e);
|
|
1227
|
+
if (o === null) return null;
|
|
1228
|
+
const n = o.hook, a = await this.#r(n, o.poolType);
|
|
1229
|
+
if (o.poolType === "BIN" && a !== "timestamp")
|
|
1230
|
+
throw new f(
|
|
1231
|
+
"getLaunch",
|
|
1232
|
+
`BinLaunchGuardHook ${n} answers as a block-numbered build; no such build exists, so this is not a Bin launch guard.`
|
|
1233
|
+
);
|
|
1234
|
+
const i = o.poolType === "CL" ? ae(a) : ee, s = await this.#e.readContract({
|
|
1235
|
+
address: n,
|
|
1236
|
+
abi: i,
|
|
1237
|
+
functionName: "getLaunch",
|
|
1238
|
+
args: [e.id]
|
|
1239
|
+
}), r = Ke(s, a);
|
|
1240
|
+
if (!Xe(r)) return null;
|
|
1241
|
+
const [l, c] = await Promise.all([
|
|
1242
|
+
this.#e.readContract({
|
|
1243
|
+
address: n,
|
|
1244
|
+
abi: i,
|
|
1245
|
+
functionName: "currentFee",
|
|
1246
|
+
args: [e.id]
|
|
1247
|
+
}),
|
|
1248
|
+
/* "Now" on the HOOK's clock. The timestamp build compares with
|
|
1249
|
+
block.timestamp. The block-numbered build compares with the EVM's
|
|
1250
|
+
block.number, which on an Arbitrum chain (Robinhood, 4663) is
|
|
1251
|
+
Ethereum's block number while the RPC head is the L2 block; against
|
|
1252
|
+
the RPC head every unopened launch rendered as settled. */
|
|
1253
|
+
xe(this.#e, this.chain.chainId)
|
|
1254
|
+
]), d = a === "timestamp" ? c.timestamp : c.contractBlockNumber, [p, m] = r.launchTokenIsCurrency0 ? [e.token0, e.token1] : [e.token1, e.token0];
|
|
1255
|
+
return {
|
|
1256
|
+
poolId: e.id,
|
|
1257
|
+
pool: e,
|
|
1258
|
+
hook: n,
|
|
1259
|
+
launchToken: p,
|
|
1260
|
+
quoteToken: m,
|
|
1261
|
+
guard: r,
|
|
1262
|
+
currentFeePips: Number(l),
|
|
1263
|
+
readAt: d,
|
|
1264
|
+
source: "live"
|
|
1265
|
+
};
|
|
1266
|
+
}
|
|
1267
|
+
async sendTransaction(e) {
|
|
1268
|
+
const o = this.#t.wallet;
|
|
1269
|
+
if (o === void 0) throw new E("send a transaction");
|
|
1270
|
+
return o.sendTransaction({
|
|
1271
|
+
to: e.to,
|
|
1272
|
+
data: e.data,
|
|
1273
|
+
value: e.value
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
1277
|
+
* The clock the next block will carry, as closely as the RPC can say: the
|
|
1278
|
+
* later of the PENDING block's timestamp (anvil and geth-style nodes compute
|
|
1279
|
+
* the next block's; an RPC without one refuses or echoes the latest) and the
|
|
1280
|
+
* latest block's. See `nextBlockClock` for why the pending read matters.
|
|
1281
|
+
*/
|
|
1282
|
+
async getBlockTimestamp() {
|
|
1283
|
+
const [e, o] = await Promise.allSettled([
|
|
1284
|
+
this.#e.getBlock({ blockTag: "pending" }),
|
|
1285
|
+
this.#e.getBlock({ blockTag: "latest" })
|
|
1286
|
+
]), n = Ye(
|
|
1287
|
+
e.status === "fulfilled" ? e.value.timestamp : null,
|
|
1288
|
+
o.status === "fulfilled" ? o.value.timestamp : null
|
|
1289
|
+
);
|
|
1290
|
+
if (n === null) throw o.status === "rejected" ? o.reason : new Error("no block timestamp could be read");
|
|
1291
|
+
return n;
|
|
1292
|
+
}
|
|
1293
|
+
async waitForTransaction(e) {
|
|
1294
|
+
const o = await this.#e.waitForTransactionReceipt({ hash: e });
|
|
1295
|
+
return {
|
|
1296
|
+
hash: e,
|
|
1297
|
+
status: o.status === "success" ? "success" : "reverted",
|
|
1298
|
+
blockNumber: o.blockNumber,
|
|
1299
|
+
source: "live"
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
function Rt(t) {
|
|
1304
|
+
return new Ct(t);
|
|
1305
|
+
}
|
|
1306
|
+
function Ft(t, e, o, n = {}) {
|
|
1307
|
+
const a = n.native ?? me, i = n.lp ?? {};
|
|
1308
|
+
return P(
|
|
1309
|
+
() => Ve(t, e, o, { native: a, lp: i }),
|
|
1310
|
+
[t, e, o, a.symbol, a.decimals, i.lpLocker, i.binLpLocker, i.poolType, i.lpLockerFromBlock, (i.lpLockerTokenIds ?? []).join(",")],
|
|
1311
|
+
{ enabled: He(e, i), refetchIntervalMs: n.refetchIntervalMs ?? 6e4 }
|
|
1312
|
+
);
|
|
1313
|
+
}
|
|
1314
|
+
function Gt(t, e, o, n = {}) {
|
|
1315
|
+
const a = n.native ?? me, i = n.lp ?? {}, s = !!i.lpLocker || !!i.binLpLocker;
|
|
1316
|
+
return P(
|
|
1317
|
+
() => je(t, e, o, { native: a, lp: i }),
|
|
1318
|
+
[t, e, o, a.symbol, a.decimals, i.lpLocker, i.binLpLocker, i.lpLockerFromBlock, (i.lpLockerTokenIds ?? []).join(",")],
|
|
1319
|
+
{ enabled: e !== null || s, refetchIntervalMs: n.refetchIntervalMs ?? 6e4 }
|
|
1320
|
+
);
|
|
1321
|
+
}
|
|
1322
|
+
function qt(t, e) {
|
|
1323
|
+
const [o, n] = he(() => Date.now());
|
|
1324
|
+
return Ze(() => {
|
|
1325
|
+
if (t === null) return;
|
|
1326
|
+
const a = setInterval(() => n(Date.now()), 1e3);
|
|
1327
|
+
return () => clearInterval(a);
|
|
1328
|
+
}, [t]), t === null || e === null ? null : We(t, e, o);
|
|
1329
|
+
}
|
|
1330
|
+
function I(t) {
|
|
1331
|
+
return t.status === "read" ? t.sources ?? [] : t.status === "error" && t.source ? [t.source] : [];
|
|
1332
|
+
}
|
|
1333
|
+
function v(t, e, o, n, a) {
|
|
1334
|
+
return { key: t, label: e, headline: o.headline, detail: o.detail, tone: o.tone, provenance: n.map((i) => ut(i, a.readAt)), sources: n };
|
|
1335
|
+
}
|
|
1336
|
+
const ge = {
|
|
1337
|
+
"launch-leg": "a Kit v2 launch leg",
|
|
1338
|
+
"lp-locker": "an LP-locker lock",
|
|
1339
|
+
"position-lock": "a LatchPositionLock time lock",
|
|
1340
|
+
given: "this page's pool list"
|
|
1341
|
+
};
|
|
1342
|
+
function ve(t) {
|
|
1343
|
+
return t.length <= 1 ? t[0] ?? "" : `${t.slice(0, -1).join(", ")} and ${t[t.length - 1]}`;
|
|
1344
|
+
}
|
|
1345
|
+
const Tt = (t, e) => t[e.toLowerCase()] ?? `${e.slice(0, 6)}…${e.slice(-4)}`;
|
|
1346
|
+
function Mt(t, e, o) {
|
|
1347
|
+
const n = [
|
|
1348
|
+
{
|
|
1349
|
+
...v("liquidity", "Liquidity locks", at(t.liquidity, t.kind), I(t.liquidity), e),
|
|
1350
|
+
share: t.liquidity.status !== "read" || !t.liquidity.measurable ? null : t.kind === "Bin" ? ce([{ key: "permanent", label: "Locked permanently (LP locker)", bps: t.liquidity.lockedActiveBps }], "of the active bin") : ce(
|
|
1351
|
+
[
|
|
1352
|
+
{ key: "permanent", label: "Locked permanently (LP locker)", bps: t.liquidity.permanentActiveBps },
|
|
1353
|
+
{ key: "time", label: "Time-locked until a date", bps: t.liquidity.timeLockedActiveBps }
|
|
1354
|
+
],
|
|
1355
|
+
"of active liquidity"
|
|
1356
|
+
)
|
|
1357
|
+
},
|
|
1358
|
+
v("lp-fee", "LP fee", st(t.lpFee), t.lpFee.kind === "error" ? [] : t.lpFee.source === null ? [] : [t.lpFee.source], e),
|
|
1359
|
+
v("protocol-fee", "Protocol fee", rt(t.protocolFee), I(t.protocolFee), e)
|
|
1360
|
+
];
|
|
1361
|
+
return t.tax.status !== "not-a-launch-pool" && n.push(v("tax", "Creator tax", ye(t.tax, e.readAt.chainNow), I(t.tax), e)), n.push(v("registry", "Hook in LatchRegistry", ct(t.registry), t.registry.status === "no-hook" ? [] : I(t.registry), e)), {
|
|
1362
|
+
poolId: t.poolId,
|
|
1363
|
+
title: `${e.symbol} / ${Tt(o, t.pairedWith)} · ${t.kind} pool`,
|
|
1364
|
+
foundBy: `Found through ${ve(t.origins.map((a) => ge[a]))}.`,
|
|
1365
|
+
rows: n
|
|
1366
|
+
};
|
|
1367
|
+
}
|
|
1368
|
+
function Nt(t) {
|
|
1369
|
+
const e = t.launch;
|
|
1370
|
+
if (e.status === "not-configured")
|
|
1371
|
+
return v("tax", "Creator tax", { headline: "Coming soon", detail: "Latch launches are coming soon on this chain, so there is no creator tax to read.", tone: "missing" }, [], t);
|
|
1372
|
+
if (e.status === "error")
|
|
1373
|
+
return v("tax", "Creator tax", { headline: "Could not be read", detail: `The launch read failed: ${e.message}.`, tone: "error" }, I(e), t);
|
|
1374
|
+
if (e.launch === null)
|
|
1375
|
+
return v("tax", "Creator tax", { headline: "Not a Latch launch", detail: "LaunchpadKitV2 has no launch for this token, so no Latch launch guard takes a creator tax on it.", tone: "neutral" }, I(e), t);
|
|
1376
|
+
const o = t.pools.filter((s) => s.origins.includes("launch-leg") && s.tax.status !== "not-a-launch-pool");
|
|
1377
|
+
if (o.length === 0)
|
|
1378
|
+
return v("tax", "Creator tax", { headline: "Could not be read", detail: "No launch pool of this token could be described, so its tax was not read.", tone: "error" }, I(e), t);
|
|
1379
|
+
const n = o.map((s) => ye(s.tax, t.readAt.chainNow)), a = o.flatMap((s) => I(s.tax)).filter((s, r, l) => l.findIndex((c) => c.address.toLowerCase() === s.address.toLowerCase()) === r), i = n[0];
|
|
1380
|
+
return n.every((s) => s.headline === i.headline && s.detail === i.detail) ? v("tax", "Creator tax", o.length === 1 ? i : { ...i, detail: `${i.detail ?? ""} Same on all ${o.length} launch pools.`.trim() }, a, t) : v("tax", "Creator tax", { headline: "Differs by pool", detail: "Each launch pool below carries its own terms.", tone: n.some((s) => s.tone === "caution") ? "caution" : "neutral" }, a, t);
|
|
1381
|
+
}
|
|
1382
|
+
function Ut(t, e = {}) {
|
|
1383
|
+
const o = t.discovery.searched.map((i) => ge[i]), n = `Pools listed are those found through ${o.length === 0 ? "no source yet: these reads are coming soon on this chain" : ve(o)}${t.discovery.truncated ? ", and only the first of them were read" : ""}${t.discovery.positionLocksTruncated ? " (newest position locks only)" : ""}. A pool of this token that no Latch launch or lock knows about is not listed.`, a = t.readAt.fromBlock === t.readAt.toBlock ? `block ${t.readAt.fromBlock.toLocaleString("en-US")}` : `blocks ${t.readAt.fromBlock.toLocaleString("en-US")}–${t.readAt.toBlock.toLocaleString("en-US")}`;
|
|
1384
|
+
return {
|
|
1385
|
+
summary: it(t),
|
|
1386
|
+
launch: v("launch", "Latch launch", ot(t.launch, t.readAt), I(t.launch), t),
|
|
1387
|
+
tokenLocks: {
|
|
1388
|
+
...v("token-locks", "Token locks & vesting", nt(t.tokenLocks, t.symbol, t.decimals), I(t.tokenLocks), t),
|
|
1389
|
+
share: t.tokenLocks.status === "read" && t.tokenLocks.lockCount > 0 ? Qe(t.tokenLocks) : null
|
|
1390
|
+
},
|
|
1391
|
+
creatorTax: Nt(t),
|
|
1392
|
+
pools: t.pools.map((i) => Mt(i, t, e)),
|
|
1393
|
+
failedPools: t.failedPools.map((i) => `${i.kind} pool ${i.poolId.slice(0, 10)}… could not be described: ${i.message}.`),
|
|
1394
|
+
discoveryNote: n,
|
|
1395
|
+
readAtNote: `Read from chain at ${a}; expiries judged against the chain's clock. Token units, never priced. A registry listing is what the registry records, not an audit.`
|
|
1396
|
+
};
|
|
1397
|
+
}
|
|
1398
|
+
async function St(t, e) {
|
|
1399
|
+
const o = await lt(t, {
|
|
1400
|
+
token: e.token,
|
|
1401
|
+
contracts: e.contracts,
|
|
1402
|
+
...e.pools !== void 0 ? { pools: e.pools } : {},
|
|
1403
|
+
...e.lpLockerTokenIds !== void 0 ? { lpLockerTokenIds: e.lpLockerTokenIds } : {},
|
|
1404
|
+
...e.native !== void 0 ? { native: e.native } : {}
|
|
1405
|
+
}), n = [...new Set(o.pools.map((r) => r.pairedWith.toLowerCase()))], a = e.native?.symbol ?? "ETH", i = await Promise.all(n.map((r) => r === Ie ? Promise.resolve({ symbol: a }) : De(t, r).catch(() => null))), s = {};
|
|
1406
|
+
return n.forEach((r, l) => {
|
|
1407
|
+
const c = i[l];
|
|
1408
|
+
c && (s[r] = c.symbol);
|
|
1409
|
+
}), { trust: o, symbols: s };
|
|
1410
|
+
}
|
|
1411
|
+
function Kt(t, e, o = {}) {
|
|
1412
|
+
const n = e.contracts, a = n === null ? "none" : Object.entries(n).map(([i, s]) => `${i}:${String(s ?? "")}`).sort().join("|");
|
|
1413
|
+
return P(
|
|
1414
|
+
() => St(t, { ...e, contracts: n }),
|
|
1415
|
+
[
|
|
1416
|
+
t,
|
|
1417
|
+
e.token.toLowerCase(),
|
|
1418
|
+
a,
|
|
1419
|
+
(e.pools ?? []).map((i) => `${i.kind}${i.poolId}`).join(","),
|
|
1420
|
+
(e.lpLockerTokenIds ?? []).join(","),
|
|
1421
|
+
e.native?.symbol,
|
|
1422
|
+
e.native?.decimals
|
|
1423
|
+
],
|
|
1424
|
+
{ enabled: n !== null, refetchIntervalMs: o.refetchIntervalMs ?? 6e4 }
|
|
1425
|
+
);
|
|
1426
|
+
}
|
|
1427
|
+
function Xt(t, e) {
|
|
1428
|
+
const o = t.trim().replace(/_/g, "");
|
|
1429
|
+
if (!/^\d+(\.\d+)?$/.test(o) || (o.split(".")[1] ?? "").length > e) return null;
|
|
1430
|
+
try {
|
|
1431
|
+
return Ae(o, e);
|
|
1432
|
+
} catch {
|
|
1433
|
+
return null;
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
function Yt(t) {
|
|
1437
|
+
const e = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})$/.exec(t.trim());
|
|
1438
|
+
if (e === null) return null;
|
|
1439
|
+
const o = Date.UTC(Number(e[1]), Number(e[2]) - 1, Number(e[3]), Number(e[4]), Number(e[5]));
|
|
1440
|
+
return Number.isFinite(o) ? BigInt(Math.floor(o / 1e3)) : null;
|
|
1441
|
+
}
|
|
1442
|
+
function Wt(t) {
|
|
1443
|
+
return new Date(Number(t) * 1e3).toISOString().slice(0, 16);
|
|
1444
|
+
}
|
|
1445
|
+
function Ht(t) {
|
|
1446
|
+
const e = t.trim();
|
|
1447
|
+
return /^\d+$/.test(e) ? BigInt(e) * 86400n : null;
|
|
1448
|
+
}
|
|
1449
|
+
function Vt(t, e) {
|
|
1450
|
+
return t === "timelock" ? e.unlockAt === null ? null : { start: e.unlockAt, cliff: e.unlockAt, end: e.unlockAt } : e.start === null || e.cliffDays === null || e.durationDays === null ? null : { start: e.start, cliff: e.start + e.cliffDays, end: e.start + e.durationDays };
|
|
1451
|
+
}
|
|
1452
|
+
function H(t, e) {
|
|
1453
|
+
if (t === 0n) return "0";
|
|
1454
|
+
const o = 10n ** BigInt(e), n = t / o, a = (t % o).toString().padStart(e, "0").replace(/0+$/, "");
|
|
1455
|
+
return a === "" ? n.toLocaleString("en-US") : `${n.toLocaleString("en-US")}.${a}`;
|
|
1456
|
+
}
|
|
1457
|
+
function jt(t, e) {
|
|
1458
|
+
const o = `${H(t.feeWei, e.decimals)} ${e.symbol} per lock`, n = t.pendingFee, a = n !== null && n.feeWei > t.feeWei, i = a ? n.feeWei : t.feeWei, s = n === null ? null : `${n.feeWei > t.feeWei ? "An increase" : "A change"} to ${H(n.feeWei, e.decimals)} ${e.symbol} applies from ${new Date(Number(n.effectiveAt) * 1e3).toISOString().replace("T", " ").slice(0, 16)} UTC.`;
|
|
1459
|
+
return {
|
|
1460
|
+
fee: o,
|
|
1461
|
+
sends: `${H(i, e.decimals)} ${e.symbol}`,
|
|
1462
|
+
pending: s,
|
|
1463
|
+
note: `Charged by the lock contract itself and paid only to its fee recipient ${t.recipient.slice(0, 6)}…${t.recipient.slice(-4)}.${a ? " The transaction sends the announced higher fee in case it applies before it mines; the contract refunds any surplus in the same call." : ""}`
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1466
|
+
function Qt(t) {
|
|
1467
|
+
const e = [];
|
|
1468
|
+
return t.approved || e.push({ key: "approve", label: `Approve LatchPositionLock to move position #${t.tokenId} (this NFT only)` }), e.push({ key: "lock", label: `Lock position #${t.tokenId} until ${new Date(Number(t.unlockAt) * 1e3).toISOString().replace("T", " ").slice(0, 16)} UTC, paying the fee` }), e;
|
|
1469
|
+
}
|
|
1470
|
+
function zt(t) {
|
|
1471
|
+
const e = [];
|
|
1472
|
+
return !t.native && t.allowance < t.amount && e.push({ key: "approve", label: `Approve LatchTokenLock for exactly ${t.amountText} ${t.symbol}` }), e.push({ key: "lock", label: `Lock ${t.amountText} ${t.symbol}, paying the fee${t.native ? " (the amount is sent with it)" : ""}` }), e;
|
|
1473
|
+
}
|
|
1474
|
+
const R = (t, e) => t != null && e !== null && e !== void 0 && t.toLowerCase() === e.toLowerCase();
|
|
1475
|
+
function Jt(t, e, o) {
|
|
1476
|
+
if (t.withdrawn) return [];
|
|
1477
|
+
const n = ["collect"];
|
|
1478
|
+
return R(t.owner, e) && (n.push("extend"), o >= t.unlockAt && n.push("withdraw")), R(t.pendingOwner, e) && n.push("accept"), n;
|
|
1479
|
+
}
|
|
1480
|
+
function Zt(t, e) {
|
|
1481
|
+
const o = [];
|
|
1482
|
+
return R(t.beneficiary, e) && t.claimable > 0n && o.push("claim"), R(t.pendingBeneficiary, e) && o.push("accept"), o;
|
|
1483
|
+
}
|
|
1484
|
+
const en = {
|
|
1485
|
+
collect: "Collect fees",
|
|
1486
|
+
extend: "Extend",
|
|
1487
|
+
withdraw: "Withdraw",
|
|
1488
|
+
accept: "Accept lock"
|
|
1489
|
+
}, tn = {
|
|
1490
|
+
claim: "Claim vested",
|
|
1491
|
+
accept: "Accept lock"
|
|
1492
|
+
};
|
|
1493
|
+
function nn(t) {
|
|
1494
|
+
const e = Je();
|
|
1495
|
+
return tt(() => {
|
|
1496
|
+
if (t !== void 0) return t;
|
|
1497
|
+
const o = e?.adapter;
|
|
1498
|
+
return o === void 0 || o.isMock ? null : {
|
|
1499
|
+
getAccount: () => o.getAccount(),
|
|
1500
|
+
sendTransaction: (n) => o.sendTransaction({ ...n, summary: "Latch lock", source: "live" })
|
|
1501
|
+
};
|
|
1502
|
+
}, [t, e?.adapter]);
|
|
1503
|
+
}
|
|
1504
|
+
function on(t) {
|
|
1505
|
+
return P(() => t === null ? Promise.resolve(null) : t.getAccount(), [t], { refetchIntervalMs: 4e3 });
|
|
1506
|
+
}
|
|
1507
|
+
function an(t, e) {
|
|
1508
|
+
return P(
|
|
1509
|
+
async () => {
|
|
1510
|
+
const [o, n] = await Promise.all([
|
|
1511
|
+
e.positionLock === null ? Promise.resolve(null) : le(t, e.positionLock),
|
|
1512
|
+
e.tokenLock === null ? Promise.resolve(null) : le(t, e.tokenLock)
|
|
1513
|
+
]);
|
|
1514
|
+
return { position: o, token: n };
|
|
1515
|
+
},
|
|
1516
|
+
[t, e.positionLock, e.tokenLock],
|
|
1517
|
+
{ enabled: e.positionLock !== null || e.tokenLock !== null, refetchIntervalMs: 6e4 }
|
|
1518
|
+
);
|
|
1519
|
+
}
|
|
1520
|
+
function sn(t, e, o) {
|
|
1521
|
+
return P(
|
|
1522
|
+
async () => {
|
|
1523
|
+
const n = o, [a, i, s] = await Promise.all([
|
|
1524
|
+
dt(t),
|
|
1525
|
+
e.positionLock === null ? Promise.resolve([]) : pt(t, e.positionLock, n),
|
|
1526
|
+
e.tokenLock === null ? Promise.resolve({ locks: [] }) : mt(t, e.tokenLock, n)
|
|
1527
|
+
]);
|
|
1528
|
+
return { positions: i, tokens: s.locks, now: a };
|
|
1529
|
+
},
|
|
1530
|
+
[t, e.positionLock, e.tokenLock, o],
|
|
1531
|
+
{ enabled: o !== null && (e.positionLock !== null || e.tokenLock !== null), refetchIntervalMs: 6e4 }
|
|
1532
|
+
);
|
|
1533
|
+
}
|
|
1534
|
+
class V extends Error {
|
|
1535
|
+
hash;
|
|
1536
|
+
constructor(e) {
|
|
1537
|
+
super(`The transaction ${e.slice(0, 10)}… was mined and reverted.`), this.name = "TransactionRevertedError", this.hash = e;
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
async function rn(t, e, o, n) {
|
|
1541
|
+
await t.call({ account: o, to: n.to, data: n.data, value: n.value });
|
|
1542
|
+
const a = await e.sendTransaction({ to: n.to, data: n.data, value: n.value });
|
|
1543
|
+
if ((await t.waitForTransactionReceipt({ hash: a })).status !== "success") throw new V(a);
|
|
1544
|
+
return a;
|
|
1545
|
+
}
|
|
1546
|
+
function cn(t, e, o, n) {
|
|
1547
|
+
const [a, i] = he({ k: "idle" }), s = et(!1), r = ue(
|
|
1548
|
+
async (c) => {
|
|
1549
|
+
if (s.current) return;
|
|
1550
|
+
const d = c.map((u) => u.label);
|
|
1551
|
+
if (e === null || o === null) {
|
|
1552
|
+
i({ k: "failed", labels: d, active: 0, message: "Connect a wallet first." });
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
s.current = !0;
|
|
1556
|
+
const p = [];
|
|
1557
|
+
let m = 0;
|
|
1558
|
+
try {
|
|
1559
|
+
for (; m < c.length; m++) {
|
|
1560
|
+
i({ k: "running", labels: d, active: m, phase: "simulating" });
|
|
1561
|
+
const u = await c[m].build();
|
|
1562
|
+
await t.call({ account: o, to: u.to, data: u.data, value: u.value }), i({ k: "running", labels: d, active: m, phase: "signing" });
|
|
1563
|
+
const h = await e.sendTransaction({ to: u.to, data: u.data, value: u.value });
|
|
1564
|
+
if (i({ k: "running", labels: d, active: m, phase: "confirming" }), (await t.waitForTransactionReceipt({ hash: h })).status !== "success") throw new V(h);
|
|
1565
|
+
p.push(h);
|
|
1566
|
+
}
|
|
1567
|
+
i({ k: "done", labels: d, hashes: p }), n?.();
|
|
1568
|
+
} catch (u) {
|
|
1569
|
+
i({ k: "failed", labels: d, active: m, message: u instanceof V ? u.message : ze(u, "transaction") });
|
|
1570
|
+
} finally {
|
|
1571
|
+
s.current = !1;
|
|
1572
|
+
}
|
|
1573
|
+
},
|
|
1574
|
+
[t, e, o, n]
|
|
1575
|
+
), l = ue(() => i({ k: "idle" }), []);
|
|
1576
|
+
return { state: a, run: r, reset: l };
|
|
1577
|
+
}
|
|
1578
|
+
export {
|
|
1579
|
+
sn as A,
|
|
1580
|
+
Ft as B,
|
|
1581
|
+
Gt as C,
|
|
1582
|
+
Kt as D,
|
|
1583
|
+
Et as N,
|
|
1584
|
+
en as P,
|
|
1585
|
+
tn as T,
|
|
1586
|
+
V as a,
|
|
1587
|
+
Lt as b,
|
|
1588
|
+
It as c,
|
|
1589
|
+
vt as d,
|
|
1590
|
+
gt as e,
|
|
1591
|
+
ht as f,
|
|
1592
|
+
Rt as g,
|
|
1593
|
+
St as h,
|
|
1594
|
+
_t as i,
|
|
1595
|
+
jt as j,
|
|
1596
|
+
Xt as k,
|
|
1597
|
+
Vt as l,
|
|
1598
|
+
Yt as m,
|
|
1599
|
+
Qt as n,
|
|
1600
|
+
zt as o,
|
|
1601
|
+
Ht as p,
|
|
1602
|
+
Jt as q,
|
|
1603
|
+
Zt as r,
|
|
1604
|
+
rn as s,
|
|
1605
|
+
Wt as t,
|
|
1606
|
+
Ut as u,
|
|
1607
|
+
qt as v,
|
|
1608
|
+
on as w,
|
|
1609
|
+
an as x,
|
|
1610
|
+
cn as y,
|
|
1611
|
+
nn as z
|
|
1612
|
+
};
|
|
1613
|
+
//# sourceMappingURL=useLocker-D1c_NTk-.js.map
|