@continuumdao/ctm-mpc-defi 0.2.26 → 0.2.28
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/agent/catalog.cjs +681 -46
- package/dist/agent/catalog.cjs.map +1 -1
- package/dist/agent/catalog.d.ts +1209 -21
- package/dist/agent/catalog.js +668 -47
- package/dist/agent/catalog.js.map +1 -1
- package/dist/agent/skills/morpho/SKILL.md +38 -6
- package/dist/agent/skills/uniswap-v4/SKILL.md +15 -0
- package/dist/core/index.cjs +19 -0
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.ts +8 -1
- package/dist/core/index.js +17 -1
- package/dist/core/index.js.map +1 -1
- package/dist/index.cjs +363 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +361 -23
- package/dist/index.js.map +1 -1
- package/dist/protocols/evm/aave-v4/index.cjs.map +1 -1
- package/dist/protocols/evm/aave-v4/index.js.map +1 -1
- package/dist/protocols/evm/euler-v2/index.cjs.map +1 -1
- package/dist/protocols/evm/euler-v2/index.js.map +1 -1
- package/dist/protocols/evm/maple/index.cjs.map +1 -1
- package/dist/protocols/evm/maple/index.js.map +1 -1
- package/dist/protocols/evm/morpho/index.cjs +1153 -142
- package/dist/protocols/evm/morpho/index.cjs.map +1 -1
- package/dist/protocols/evm/morpho/index.d.ts +314 -8
- package/dist/protocols/evm/morpho/index.js +1131 -144
- package/dist/protocols/evm/morpho/index.js.map +1 -1
- package/dist/protocols/evm/permit2/index.cjs.map +1 -1
- package/dist/protocols/evm/permit2/index.js.map +1 -1
- package/dist/protocols/evm/sky/index.cjs.map +1 -1
- package/dist/protocols/evm/sky/index.js.map +1 -1
- package/dist/protocols/evm/uniswap-v4/index.cjs +863 -25
- package/dist/protocols/evm/uniswap-v4/index.cjs.map +1 -1
- package/dist/protocols/evm/uniswap-v4/index.d.ts +266 -9
- package/dist/protocols/evm/uniswap-v4/index.js +834 -27
- package/dist/protocols/evm/uniswap-v4/index.js.map +1 -1
- package/package.json +2 -1
|
@@ -72,11 +72,23 @@ var UNIVERSAL_ROUTER_SPENDER = {
|
|
|
72
72
|
/** Robinhood Chain mainnet — Universal Router v2.1.1 (Trade API / interface) */
|
|
73
73
|
4663: "0x8876789976decbfcbbbe364623c63652db8c0904"
|
|
74
74
|
};
|
|
75
|
+
var UNIVERSAL_ROUTER_V2_2_SPENDER = {
|
|
76
|
+
1: "0xCb640A86855f1A828c27241bA364348de28abe66",
|
|
77
|
+
11155111: "0xB0C89059d7190EDb17eFF19829cc009cEe923916"
|
|
78
|
+
};
|
|
75
79
|
var UNIVERSAL_ROUTER_VERSION_BY_CHAIN = {
|
|
76
80
|
/** Robinhood has UR 2.1.1 only in the supported-chains table (no 2.0 Trade API column). */
|
|
77
81
|
4663: "2.1.1"
|
|
78
82
|
};
|
|
79
|
-
|
|
83
|
+
var UNISWAP_UNIVERSAL_ROUTER_VERSION_DEFAULT = "2.0";
|
|
84
|
+
var UNISWAP_UNIVERSAL_ROUTER_VERSION_PERMISSIONED = "2.2.0";
|
|
85
|
+
function getUniswapUniversalRouterVersion(chainId, opts) {
|
|
86
|
+
if (opts?.permissioned) {
|
|
87
|
+
const v22 = UNIVERSAL_ROUTER_V2_2_SPENDER[chainId];
|
|
88
|
+
if (typeof v22 === "string" && v22.startsWith("0x")) {
|
|
89
|
+
return UNISWAP_UNIVERSAL_ROUTER_VERSION_PERMISSIONED;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
80
92
|
const v = UNIVERSAL_ROUTER_VERSION_BY_CHAIN[chainId];
|
|
81
93
|
return typeof v === "string" && v.trim() ? v.trim() : UNISWAP_UNIVERSAL_ROUTER_VERSION_DEFAULT;
|
|
82
94
|
}
|
|
@@ -87,7 +99,11 @@ function isUniswapV4ChainSupported(chainId) {
|
|
|
87
99
|
const a = UNIVERSAL_ROUTER_SPENDER[n];
|
|
88
100
|
return typeof a === "string" && a.startsWith("0x");
|
|
89
101
|
}
|
|
90
|
-
function getUniswapUniversalRouterSpenderOrThrow(chainId) {
|
|
102
|
+
function getUniswapUniversalRouterSpenderOrThrow(chainId, opts) {
|
|
103
|
+
if (opts?.permissioned) {
|
|
104
|
+
const raw22 = UNIVERSAL_ROUTER_V2_2_SPENDER[chainId];
|
|
105
|
+
if (raw22 && raw22.startsWith("0x")) return viem.getAddress(raw22);
|
|
106
|
+
}
|
|
91
107
|
const raw = UNIVERSAL_ROUTER_SPENDER[chainId];
|
|
92
108
|
if (!raw || !raw.startsWith("0x")) {
|
|
93
109
|
throw new Error(
|
|
@@ -96,12 +112,16 @@ function getUniswapUniversalRouterSpenderOrThrow(chainId) {
|
|
|
96
112
|
}
|
|
97
113
|
return viem.getAddress(raw);
|
|
98
114
|
}
|
|
115
|
+
function tryGetUniswapUniversalRouterV22(chainId) {
|
|
116
|
+
const raw = UNIVERSAL_ROUTER_V2_2_SPENDER[chainId];
|
|
117
|
+
if (!raw || !raw.startsWith("0x")) return null;
|
|
118
|
+
return viem.getAddress(raw);
|
|
119
|
+
}
|
|
99
120
|
var MAX_UINT160 = (1n << 160n) - 1n;
|
|
100
121
|
var MAX_UINT48 = (1n << 48n) - 1n;
|
|
101
122
|
var UNISWAP_UNIVERSAL_ROUTER_DEFAULT_GAS_UNITS = 1500000n;
|
|
102
123
|
var UNISWAP_TRADE_BASE_DEFAULT = "https://trade-api.gateway.uniswap.org/v1";
|
|
103
124
|
var UNISWAP_LP_API_BASE_DEFAULT = "https://api.uniswap.org";
|
|
104
|
-
var UNISWAP_UNIVERSAL_ROUTER_VERSION_DEFAULT = "2.0";
|
|
105
125
|
var UNISWAP_SWAP_DEFAULT_EXPIRY_MINUTES = 30;
|
|
106
126
|
var UNISWAP_SWAP_DEFAULT_DEADLINE_SEC_OFFSET = UNISWAP_SWAP_DEFAULT_EXPIRY_MINUTES * 60;
|
|
107
127
|
var UNISWAP_LP_DEFAULT_EXPIRY_MINUTES = 30;
|
|
@@ -120,6 +140,18 @@ var POSITION_MANAGER_BY_CHAIN = {
|
|
|
120
140
|
/** Robinhood Chain mainnet */
|
|
121
141
|
4663: "0x58daec3116aae6D93017bAAea7749052E8a04fA7"
|
|
122
142
|
};
|
|
143
|
+
var PERMISSIONED_POSITION_MANAGER_BY_CHAIN = {
|
|
144
|
+
1: "0x89628C9B4CE81951a9BC1F36F0688Fad6A6ee248",
|
|
145
|
+
11155111: "0x68fC145BB20b388965bED184Df5ef912215bb3C7"
|
|
146
|
+
};
|
|
147
|
+
var PERMISSIONED_HOOKS_BY_CHAIN = {
|
|
148
|
+
1: "0x69603ab16110Eb0bB5f5E9C8019749eE41A128C0",
|
|
149
|
+
11155111: "0x8B0E8d467af81D9F5B49165e104a2fe1b98328C0"
|
|
150
|
+
};
|
|
151
|
+
var PERMISSIONS_ADAPTER_FACTORY_BY_CHAIN = {
|
|
152
|
+
1: "0x38f9Ab57FBE2704EbB727cB20e33201aF0E5F961",
|
|
153
|
+
11155111: "0xEe258C31574fb59660C23534E76AF6497c2e5683"
|
|
154
|
+
};
|
|
123
155
|
var ROBINHOOD_CHAIN_ID = 4663;
|
|
124
156
|
var ROBINHOOD_WETH_ADDRESS = "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73";
|
|
125
157
|
function getUniswapV4PositionManagerOrThrow(chainId) {
|
|
@@ -138,6 +170,76 @@ function tryGetUniswapV4PositionManager(chainId) {
|
|
|
138
170
|
return null;
|
|
139
171
|
}
|
|
140
172
|
}
|
|
173
|
+
function getUniswapV4PermissionedPositionManagerOrThrow(chainId) {
|
|
174
|
+
const raw = PERMISSIONED_POSITION_MANAGER_BY_CHAIN[chainId];
|
|
175
|
+
if (!raw || !raw.startsWith("0x") || raw.length !== 42) {
|
|
176
|
+
throw new Error(
|
|
177
|
+
`No Uniswap V4 Permissioned PositionManager is configured for chainId ${chainId}.`
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
return viem.getAddress(raw);
|
|
181
|
+
}
|
|
182
|
+
function tryGetUniswapV4PermissionedPositionManager(chainId) {
|
|
183
|
+
try {
|
|
184
|
+
return getUniswapV4PermissionedPositionManagerOrThrow(chainId);
|
|
185
|
+
} catch {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function getUniswapV4PermissionedHooksOrThrow(chainId) {
|
|
190
|
+
const raw = PERMISSIONED_HOOKS_BY_CHAIN[chainId];
|
|
191
|
+
if (!raw || !raw.startsWith("0x") || raw.length !== 42) {
|
|
192
|
+
throw new Error(`No Uniswap V4 PermissionedHooks is configured for chainId ${chainId}.`);
|
|
193
|
+
}
|
|
194
|
+
return viem.getAddress(raw);
|
|
195
|
+
}
|
|
196
|
+
function tryGetUniswapV4PermissionedHooks(chainId) {
|
|
197
|
+
try {
|
|
198
|
+
return getUniswapV4PermissionedHooksOrThrow(chainId);
|
|
199
|
+
} catch {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
function getUniswapV4PermissionsAdapterFactoryOrThrow(chainId) {
|
|
204
|
+
const raw = PERMISSIONS_ADAPTER_FACTORY_BY_CHAIN[chainId];
|
|
205
|
+
if (!raw || !raw.startsWith("0x") || raw.length !== 42) {
|
|
206
|
+
throw new Error(
|
|
207
|
+
`No Uniswap V4 PermissionsAdapterFactory is configured for chainId ${chainId}.`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
return viem.getAddress(raw);
|
|
211
|
+
}
|
|
212
|
+
function tryGetUniswapV4PermissionsAdapterFactory(chainId) {
|
|
213
|
+
try {
|
|
214
|
+
return getUniswapV4PermissionsAdapterFactoryOrThrow(chainId);
|
|
215
|
+
} catch {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function isUniswapV4PermissionedPositionManager(chainId, address) {
|
|
220
|
+
if (!address?.toString().trim()) return false;
|
|
221
|
+
const perm = tryGetUniswapV4PermissionedPositionManager(chainId);
|
|
222
|
+
if (!perm) return false;
|
|
223
|
+
try {
|
|
224
|
+
return viem.getAddress(address) === perm;
|
|
225
|
+
} catch {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function isUniswapV4AnyPositionManager(chainId, address) {
|
|
230
|
+
if (!address?.toString().trim()) return false;
|
|
231
|
+
try {
|
|
232
|
+
const a = viem.getAddress(address);
|
|
233
|
+
const std = tryGetUniswapV4PositionManager(chainId);
|
|
234
|
+
const perm = tryGetUniswapV4PermissionedPositionManager(chainId);
|
|
235
|
+
return std != null && a === std || perm != null && a === perm;
|
|
236
|
+
} catch {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function resolveUniswapV4PositionManager(chainId, kind = "standard") {
|
|
241
|
+
return kind === "permissioned" ? getUniswapV4PermissionedPositionManagerOrThrow(chainId) : getUniswapV4PositionManagerOrThrow(chainId);
|
|
242
|
+
}
|
|
141
243
|
var POSITION_MANAGER_DEPLOY_BLOCK_BY_CHAIN = {
|
|
142
244
|
/** Ethereum mainnet — Uniswap v4 launch (Jan 2025). */
|
|
143
245
|
1: 22938741n
|
|
@@ -153,6 +255,231 @@ var UNISWAP_V4_LP_DECREASE_DEFAULT_GAS_UNITS = 1200000n;
|
|
|
153
255
|
var UNISWAP_V4_LP_COLLECT_DEFAULT_GAS_UNITS = 900000n;
|
|
154
256
|
var UNISWAP_V4_LP_ERC20_APPROVE_FALLBACK = 100000n;
|
|
155
257
|
var UNISWAP_V4_LP_WETH_DEPOSIT_FALLBACK = 120000n;
|
|
258
|
+
var UNISWAP_V4_LP_PERMIT2_APPROVE_FALLBACK = 100000n;
|
|
259
|
+
var UNISWAP_V4_PERMISSION_FLAG_SWAP = 1;
|
|
260
|
+
var UNISWAP_V4_PERMISSION_FLAG_LIQUIDITY = 2;
|
|
261
|
+
var permissionsAdapterAbi = viem.parseAbi([
|
|
262
|
+
"function isAllowed(address account, uint8 permission) view returns (bool)",
|
|
263
|
+
"function PERMISSIONED_TOKEN() view returns (address)"
|
|
264
|
+
]);
|
|
265
|
+
var factoryAbi = viem.parseAbi([
|
|
266
|
+
"function verifiedPermissionsAdapterOf(address permissionsAdapter) view returns (address)"
|
|
267
|
+
]);
|
|
268
|
+
function normalizeTokenList(tokens) {
|
|
269
|
+
const out = [];
|
|
270
|
+
const seen = /* @__PURE__ */ new Set();
|
|
271
|
+
for (const raw of tokens) {
|
|
272
|
+
const t = (raw ?? "").toString().trim();
|
|
273
|
+
if (!t) continue;
|
|
274
|
+
if (isUniswapNativeTokenAddress(t)) continue;
|
|
275
|
+
let addr;
|
|
276
|
+
try {
|
|
277
|
+
addr = viem.getAddress(t);
|
|
278
|
+
} catch {
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
if (addr === viem.zeroAddress) continue;
|
|
282
|
+
const key = addr.toLowerCase();
|
|
283
|
+
if (seen.has(key)) continue;
|
|
284
|
+
seen.add(key);
|
|
285
|
+
out.push(addr);
|
|
286
|
+
if (out.length >= 2) break;
|
|
287
|
+
}
|
|
288
|
+
return out;
|
|
289
|
+
}
|
|
290
|
+
function parsePermissionRow(raw) {
|
|
291
|
+
const tokenRaw = (raw.token ?? raw.address ?? "").toString().trim();
|
|
292
|
+
if (!tokenRaw) return null;
|
|
293
|
+
let token;
|
|
294
|
+
try {
|
|
295
|
+
token = viem.getAddress(tokenRaw);
|
|
296
|
+
} catch {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
const isPermissioned = Boolean(raw.isPermissioned);
|
|
300
|
+
const isAllowlisted = isPermissioned ? Boolean(raw.isAllowlisted) : true;
|
|
301
|
+
let adapterTokenAddress;
|
|
302
|
+
const adapterRaw = (raw.adapterTokenAddress ?? "").toString().trim();
|
|
303
|
+
if (adapterRaw) {
|
|
304
|
+
try {
|
|
305
|
+
adapterTokenAddress = viem.getAddress(adapterRaw);
|
|
306
|
+
} catch {
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const kycUrl = typeof raw.kycUrl === "string" && raw.kycUrl.trim() ? raw.kycUrl.trim() : void 0;
|
|
310
|
+
const issuer = typeof raw.issuer === "string" && raw.issuer.trim() ? raw.issuer.trim() : void 0;
|
|
311
|
+
return { token, isPermissioned, isAllowlisted, adapterTokenAddress, kycUrl, issuer };
|
|
312
|
+
}
|
|
313
|
+
async function uniswapV4CheckPermissions(args) {
|
|
314
|
+
const apiKey = args.uniswapApiKey?.trim();
|
|
315
|
+
if (!apiKey) throw new Error("uniswapApiKey is required for POST /v1/permissions");
|
|
316
|
+
const walletAddress = viem.getAddress(args.walletAddress.trim());
|
|
317
|
+
const chainId = parseUniswapChainId(args.chainId);
|
|
318
|
+
const tokens = normalizeTokenList(args.tokens);
|
|
319
|
+
if (tokens.length === 0) {
|
|
320
|
+
return {
|
|
321
|
+
results: [],
|
|
322
|
+
anyPermissioned: false,
|
|
323
|
+
allAllowlisted: true,
|
|
324
|
+
requiresUniversalRouterV22: false
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
const base = (args.baseUrl?.trim() || UNISWAP_TRADE_BASE_DEFAULT).replace(/\/$/, "");
|
|
328
|
+
const url = `${base}/permissions`;
|
|
329
|
+
const fetchFn = args.fetchImpl ?? globalThis.fetch;
|
|
330
|
+
const res = await fetchFn(url, {
|
|
331
|
+
method: "POST",
|
|
332
|
+
headers: {
|
|
333
|
+
"Content-Type": "application/json",
|
|
334
|
+
"User-Agent": "ctm-mpc-defi uniswapPermissions/1.0 (TS)",
|
|
335
|
+
"x-api-key": apiKey
|
|
336
|
+
},
|
|
337
|
+
body: JSON.stringify({
|
|
338
|
+
walletAddress,
|
|
339
|
+
tokens,
|
|
340
|
+
chainId
|
|
341
|
+
}),
|
|
342
|
+
signal: args.signal
|
|
343
|
+
});
|
|
344
|
+
const text = await res.text();
|
|
345
|
+
if (!res.ok) {
|
|
346
|
+
throw new Error(
|
|
347
|
+
`Uniswap POST /permissions failed: ${messageFromUniswapHttpResponseBody(text, res.status, res.statusText)}`
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
let parsed;
|
|
351
|
+
try {
|
|
352
|
+
parsed = JSON.parse(text.replace(/^\uFEFF/, ""));
|
|
353
|
+
} catch {
|
|
354
|
+
throw new Error(
|
|
355
|
+
`Uniswap POST /permissions: ${messageFromUniswapHttpResponseBody(text, res.status, res.statusText)}`
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
const rawResults = Array.isArray(parsed.results) ? parsed.results : [];
|
|
359
|
+
const results = [];
|
|
360
|
+
for (const row of rawResults) {
|
|
361
|
+
if (!row || typeof row !== "object" || Array.isArray(row)) continue;
|
|
362
|
+
const parsedRow = parsePermissionRow(row);
|
|
363
|
+
if (parsedRow) results.push(parsedRow);
|
|
364
|
+
}
|
|
365
|
+
for (const token of tokens) {
|
|
366
|
+
if (!results.some((r) => r.token === token)) {
|
|
367
|
+
results.push({ token, isPermissioned: false, isAllowlisted: true });
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
const anyPermissioned = results.some((r) => r.isPermissioned);
|
|
371
|
+
const allAllowlisted = results.every((r) => !r.isPermissioned || r.isAllowlisted);
|
|
372
|
+
return {
|
|
373
|
+
requestId: typeof parsed.requestId === "string" ? parsed.requestId : void 0,
|
|
374
|
+
results,
|
|
375
|
+
anyPermissioned,
|
|
376
|
+
allAllowlisted,
|
|
377
|
+
requiresUniversalRouterV22: anyPermissioned
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
var UniswapV4PermissionDeniedError = class extends Error {
|
|
381
|
+
code = "UNISWAP_V4_PERMISSION_DENIED";
|
|
382
|
+
permissions;
|
|
383
|
+
blocked;
|
|
384
|
+
constructor(permissions) {
|
|
385
|
+
const blocked = permissions.results.filter((r) => r.isPermissioned && !r.isAllowlisted);
|
|
386
|
+
const issuer = blocked.find((b) => b.issuer)?.issuer;
|
|
387
|
+
const kycUrl = blocked.find((b) => b.kycUrl)?.kycUrl;
|
|
388
|
+
const parts = [
|
|
389
|
+
"Wallet is not allowlisted for one or more permissioned Uniswap V4 tokens.",
|
|
390
|
+
issuer ? `Issuer: ${issuer}.` : null,
|
|
391
|
+
kycUrl ? `Complete KYC at: ${kycUrl}` : "Open the issuer KYC URL from check_permissions."
|
|
392
|
+
].filter(Boolean);
|
|
393
|
+
super(parts.join(" "));
|
|
394
|
+
this.name = "UniswapV4PermissionDeniedError";
|
|
395
|
+
this.permissions = permissions;
|
|
396
|
+
this.blocked = blocked;
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
function assertUniswapV4PermissionsAllowlisted(permissions) {
|
|
400
|
+
if (!permissions.allAllowlisted) {
|
|
401
|
+
throw new UniswapV4PermissionDeniedError(permissions);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
async function readUniswapV4OnChainPermissionFlags(args) {
|
|
405
|
+
const factory = tryGetUniswapV4PermissionsAdapterFactory(args.chainId);
|
|
406
|
+
if (!factory) return [];
|
|
407
|
+
const client = args.publicClient ?? viem.createPublicClient({
|
|
408
|
+
chain: viem.defineChain({
|
|
409
|
+
id: args.chainId,
|
|
410
|
+
name: `uniswap-perm-${args.chainId}`,
|
|
411
|
+
nativeCurrency: { name: "ETH", symbol: "ETH", decimals: 18 },
|
|
412
|
+
rpcUrls: { default: { http: [args.rpcUrl] } }
|
|
413
|
+
}),
|
|
414
|
+
transport: viem.http(args.rpcUrl)
|
|
415
|
+
});
|
|
416
|
+
const wallet = viem.getAddress(args.walletAddress);
|
|
417
|
+
const out = [];
|
|
418
|
+
for (const raw of args.currencyOrAdapterAddresses) {
|
|
419
|
+
let address;
|
|
420
|
+
try {
|
|
421
|
+
address = viem.getAddress(raw);
|
|
422
|
+
} catch {
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
if (address === viem.zeroAddress) continue;
|
|
426
|
+
let underlying;
|
|
427
|
+
try {
|
|
428
|
+
underlying = viem.getAddress(
|
|
429
|
+
await client.readContract({
|
|
430
|
+
address: factory,
|
|
431
|
+
abi: factoryAbi,
|
|
432
|
+
functionName: "verifiedPermissionsAdapterOf",
|
|
433
|
+
args: [address]
|
|
434
|
+
})
|
|
435
|
+
);
|
|
436
|
+
} catch {
|
|
437
|
+
out.push({
|
|
438
|
+
address,
|
|
439
|
+
isVerifiedAdapter: false,
|
|
440
|
+
swapAllowed: true,
|
|
441
|
+
liquidityAllowed: true
|
|
442
|
+
});
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
if (underlying === viem.zeroAddress) {
|
|
446
|
+
out.push({
|
|
447
|
+
address,
|
|
448
|
+
isVerifiedAdapter: false,
|
|
449
|
+
swapAllowed: true,
|
|
450
|
+
liquidityAllowed: true
|
|
451
|
+
});
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
const [swapAllowed, liquidityAllowed] = await Promise.all([
|
|
455
|
+
client.readContract({
|
|
456
|
+
address,
|
|
457
|
+
abi: permissionsAdapterAbi,
|
|
458
|
+
functionName: "isAllowed",
|
|
459
|
+
args: [wallet, UNISWAP_V4_PERMISSION_FLAG_SWAP]
|
|
460
|
+
}),
|
|
461
|
+
client.readContract({
|
|
462
|
+
address,
|
|
463
|
+
abi: permissionsAdapterAbi,
|
|
464
|
+
functionName: "isAllowed",
|
|
465
|
+
args: [wallet, UNISWAP_V4_PERMISSION_FLAG_LIQUIDITY]
|
|
466
|
+
})
|
|
467
|
+
]);
|
|
468
|
+
out.push({
|
|
469
|
+
address,
|
|
470
|
+
isVerifiedAdapter: true,
|
|
471
|
+
underlyingToken: underlying,
|
|
472
|
+
swapAllowed: Boolean(swapAllowed),
|
|
473
|
+
liquidityAllowed: Boolean(liquidityAllowed)
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
return out;
|
|
477
|
+
}
|
|
478
|
+
async function uniswapV4CheckPermissionsMcp(args) {
|
|
479
|
+
return uniswapV4CheckPermissions(args);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// src/protocols/evm/uniswap-v4/quote.ts
|
|
156
483
|
var DEFAULT_TRADE_BASE = "https://trade-api.gateway.uniswap.org/v1";
|
|
157
484
|
var UNISWAP_QUOTE_HEADERS_BASE = {
|
|
158
485
|
"Content-Type": "application/json",
|
|
@@ -402,7 +729,25 @@ async function uniswapTradeQuote(args) {
|
|
|
402
729
|
const base = args.baseUrl && args.baseUrl.trim() ? args.baseUrl.trim().replace(/\/$/, "") : DEFAULT_TRADE_BASE;
|
|
403
730
|
const quoteUrl = `${base}/quote`;
|
|
404
731
|
const chainIdForRouter = parseUniswapChainId(resolveInputChainId(args));
|
|
405
|
-
|
|
732
|
+
let permissions;
|
|
733
|
+
const shouldCheckPermissions = args.forcePermissionedRouter !== true && args.skipPermissionCheck !== true && args.checkPermissions !== false;
|
|
734
|
+
if (shouldCheckPermissions) {
|
|
735
|
+
try {
|
|
736
|
+
permissions = await uniswapV4CheckPermissions({
|
|
737
|
+
walletAddress: swapper,
|
|
738
|
+
tokens: [args.tokenIn, args.tokenOut],
|
|
739
|
+
chainId: chainIdForRouter,
|
|
740
|
+
uniswapApiKey: apiKey,
|
|
741
|
+
baseUrl: base,
|
|
742
|
+
signal: args.signal,
|
|
743
|
+
fetchImpl: args.fetchImpl
|
|
744
|
+
});
|
|
745
|
+
} catch {
|
|
746
|
+
permissions = void 0;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
const permissionedRouter = args.forcePermissionedRouter === true || Boolean(permissions?.requiresUniversalRouterV22);
|
|
750
|
+
const urv = args.universalRouterVersion && args.universalRouterVersion.trim() || getUniswapUniversalRouterVersion(chainIdForRouter, { permissioned: permissionedRouter });
|
|
406
751
|
const body = buildUniswapQuoteRequestBody({ ...args, swapper });
|
|
407
752
|
const nativeIn = isUniswapNativeTokenAddress(args.tokenIn);
|
|
408
753
|
const nativeOut = isUniswapNativeTokenAddress(args.tokenOut);
|
|
@@ -431,13 +776,27 @@ async function uniswapTradeQuote(args) {
|
|
|
431
776
|
}
|
|
432
777
|
const forParse = text.replace(/^\uFEFF/, "");
|
|
433
778
|
try {
|
|
434
|
-
|
|
779
|
+
const parsed = JSON.parse(forParse);
|
|
780
|
+
if (permissionedRouter || urv === UNISWAP_UNIVERSAL_ROUTER_VERSION_PERMISSIONED) {
|
|
781
|
+
parsed._continuumPermissioned = true;
|
|
782
|
+
parsed._continuumUniversalRouterVersion = urv;
|
|
783
|
+
}
|
|
784
|
+
if (permissions) {
|
|
785
|
+
parsed._continuumPermissions = permissions;
|
|
786
|
+
}
|
|
787
|
+
return parsed;
|
|
435
788
|
} catch {
|
|
436
789
|
throw new Error(
|
|
437
790
|
`Trade API: ${messageFromUniswapHttpResponseBody(text, res.status, res.statusText)}`
|
|
438
791
|
);
|
|
439
792
|
}
|
|
440
793
|
}
|
|
794
|
+
function isUniswapStoredQuotePermissioned(stored) {
|
|
795
|
+
if (!stored) return false;
|
|
796
|
+
if (stored._continuumPermissioned === true) return true;
|
|
797
|
+
const v = stored._continuumUniversalRouterVersion;
|
|
798
|
+
return typeof v === "string" && v.trim() === UNISWAP_UNIVERSAL_ROUTER_VERSION_PERMISSIONED;
|
|
799
|
+
}
|
|
441
800
|
function uniswapQuoteToJsonQuoteOneLine(quote) {
|
|
442
801
|
return JSON.stringify(quote);
|
|
443
802
|
}
|
|
@@ -991,7 +1350,9 @@ async function uniswapCreateSwap(args) {
|
|
|
991
1350
|
quote: classic,
|
|
992
1351
|
deadline
|
|
993
1352
|
};
|
|
994
|
-
const
|
|
1353
|
+
const chainIdForRouter = resolveChainIdFromStoredUniswapQuote(args.fullQuoteFromPermit);
|
|
1354
|
+
const permissioned = isUniswapStoredQuotePermissioned(args.fullQuoteFromPermit);
|
|
1355
|
+
const urv = (args.universalRouterVersion ?? "").trim() || getUniswapUniversalRouterVersion(chainIdForRouter, { permissioned });
|
|
995
1356
|
const fn = args.fetchImpl ?? globalThis.fetch;
|
|
996
1357
|
const nativeIn = isUniswapFullQuoteResponseNativeIn(args.fullQuoteFromPermit);
|
|
997
1358
|
const nativeOut = isUniswapFullQuoteResponseNativeOut(args.fullQuoteFromPermit);
|
|
@@ -1119,8 +1480,8 @@ function applySlippagePercentToApproveWei(baseWei, slippagePercent) {
|
|
|
1119
1480
|
if (bps <= 0) return baseWei;
|
|
1120
1481
|
return (baseWei * BigInt(1e4 + bps) + 9999n) / 10000n;
|
|
1121
1482
|
}
|
|
1122
|
-
function permit2SpenderAndApproveWeiFromSwapCalldata(dataHex, tokenIn, quoteInputWei, chainId) {
|
|
1123
|
-
const canonical = getUniswapUniversalRouterSpenderOrThrow(chainId);
|
|
1483
|
+
function permit2SpenderAndApproveWeiFromSwapCalldata(dataHex, tokenIn, quoteInputWei, chainId, permissioned = false) {
|
|
1484
|
+
const canonical = getUniswapUniversalRouterSpenderOrThrow(chainId, { permissioned });
|
|
1124
1485
|
try {
|
|
1125
1486
|
const d = viem.decodeFunctionData({ abi: uniswapDispatchExecuteAbi, data: dataHex });
|
|
1126
1487
|
if (d.functionName !== "execute") {
|
|
@@ -1256,6 +1617,27 @@ async function buildEvmMultisignBodyUniswapV4SkipPermit2Batch(args) {
|
|
|
1256
1617
|
"Could not read a positive input amount from the quote. Refresh the quote and ensure the Trade API returned classic quote.input.amount."
|
|
1257
1618
|
);
|
|
1258
1619
|
}
|
|
1620
|
+
const permissioned = isUniswapStoredQuotePermissioned(args.fullQuoteSnapshot);
|
|
1621
|
+
if (args.skipPermissionCheck !== true) {
|
|
1622
|
+
const cached = args.fullQuoteSnapshot._continuumPermissions;
|
|
1623
|
+
if (cached && typeof cached === "object" && cached.allAllowlisted === false) {
|
|
1624
|
+
assertUniswapV4PermissionsAllowlisted({
|
|
1625
|
+
results: cached.results ?? [],
|
|
1626
|
+
anyPermissioned: Boolean(cached.anyPermissioned),
|
|
1627
|
+
allAllowlisted: false,
|
|
1628
|
+
requiresUniversalRouterV22: Boolean(cached.requiresUniversalRouterV22)
|
|
1629
|
+
});
|
|
1630
|
+
} else if (args.uniswapApiKey?.trim() && (permissioned || args.tokenOut)) {
|
|
1631
|
+
const tokens = [args.tokenIn, args.tokenOut].filter(Boolean);
|
|
1632
|
+
const permissions = await uniswapV4CheckPermissions({
|
|
1633
|
+
walletAddress: args.executorAddress,
|
|
1634
|
+
tokens,
|
|
1635
|
+
chainId: args.chainId,
|
|
1636
|
+
uniswapApiKey: args.uniswapApiKey.trim()
|
|
1637
|
+
});
|
|
1638
|
+
assertUniswapV4PermissionsAllowlisted(permissions);
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1259
1641
|
if (tokenIn === viem.zeroAddress) {
|
|
1260
1642
|
return buildEvmMultisignBodyUniswapV4NativeInOnly(args, quoteInputWei);
|
|
1261
1643
|
}
|
|
@@ -1266,12 +1648,15 @@ async function buildEvmMultisignBodyUniswapV4SkipPermit2Batch(args) {
|
|
|
1266
1648
|
const d = (args.swap.data ?? "0x").toString().trim();
|
|
1267
1649
|
return d.startsWith("0x") ? d : `0x${d}`;
|
|
1268
1650
|
})();
|
|
1269
|
-
const canonicalUniversalRouter = getUniswapUniversalRouterSpenderOrThrow(args.chainId
|
|
1651
|
+
const canonicalUniversalRouter = getUniswapUniversalRouterSpenderOrThrow(args.chainId, {
|
|
1652
|
+
permissioned
|
|
1653
|
+
});
|
|
1270
1654
|
const { permit2Spender, approveWei: baseApproveWei, calldataAmountWei } = permit2SpenderAndApproveWeiFromSwapCalldata(
|
|
1271
1655
|
dataHex,
|
|
1272
1656
|
tokenIn,
|
|
1273
1657
|
quoteInputWei,
|
|
1274
|
-
args.chainId
|
|
1658
|
+
args.chainId,
|
|
1659
|
+
permissioned
|
|
1275
1660
|
);
|
|
1276
1661
|
const approveAmountWei = applySlippagePercentToApproveWei(baseApproveWei, args.slippagePercent);
|
|
1277
1662
|
const usePermit2Triple = toRouter.toLowerCase() === permit2Spender.toLowerCase();
|
|
@@ -2321,6 +2706,9 @@ var erc20AllowanceAbi2 = viem.parseAbi([
|
|
|
2321
2706
|
"function allowance(address owner, address spender) view returns (uint256)",
|
|
2322
2707
|
"function decimals() view returns (uint8)"
|
|
2323
2708
|
]);
|
|
2709
|
+
var permit2ApproveAbi = viem.parseAbi([
|
|
2710
|
+
"function approve(address token, address spender, uint160 amount, uint48 expiration)"
|
|
2711
|
+
]);
|
|
2324
2712
|
function parseOptionalGasLimitString2(raw) {
|
|
2325
2713
|
if (raw == null) return null;
|
|
2326
2714
|
const s = String(raw).trim();
|
|
@@ -2444,7 +2832,9 @@ async function buildEvmMultisignBodyUniswapV4LiquidityBatchInternal(args) {
|
|
|
2444
2832
|
const dataHex = dataHexFromTx(tx);
|
|
2445
2833
|
const valueWei = parseTxValueWei(tx);
|
|
2446
2834
|
const executor = viem.getAddress(args.executorAddress);
|
|
2447
|
-
const
|
|
2835
|
+
const positionManagerKind = args.positionManagerKind === "permissioned" || args.positionManagerKind === "standard" ? args.positionManagerKind : isUniswapV4PermissionedPositionManager(args.chainId, to) ? "permissioned" : "standard";
|
|
2836
|
+
const usePermit2 = args.usePermit2Approvals === true || args.usePermit2Approvals !== false && positionManagerKind === "permissioned";
|
|
2837
|
+
const erc20Spender = usePermit2 ? PERMIT2_ADDRESS : to;
|
|
2448
2838
|
const chain = viem.defineChain({
|
|
2449
2839
|
id: args.chainId,
|
|
2450
2840
|
name: `uniswap-v4-lp-${args.chainId}`,
|
|
@@ -2452,15 +2842,21 @@ async function buildEvmMultisignBodyUniswapV4LiquidityBatchInternal(args) {
|
|
|
2452
2842
|
rpcUrls: { default: { http: [args.rpcUrl] } }
|
|
2453
2843
|
});
|
|
2454
2844
|
const publicClient = viem.createPublicClient({ chain, transport: viem.http(args.rpcUrl) });
|
|
2455
|
-
const
|
|
2845
|
+
const needsTokenApproves = args.action === "mint" || args.action === "increase";
|
|
2846
|
+
const approveTargets = needsTokenApproves ? await resolveApproveTargets({
|
|
2456
2847
|
publicClient,
|
|
2457
2848
|
executor,
|
|
2458
|
-
spender,
|
|
2849
|
+
spender: erc20Spender,
|
|
2459
2850
|
token0: parsed.token0,
|
|
2460
2851
|
token1: parsed.token1,
|
|
2461
2852
|
nativeWrapped: args.nativeWrapped
|
|
2462
|
-
});
|
|
2853
|
+
}) : [];
|
|
2463
2854
|
const steps = [];
|
|
2855
|
+
let permit2Expiration48 = 0n;
|
|
2856
|
+
if (usePermit2 && needsTokenApproves) {
|
|
2857
|
+
permit2Expiration48 = BigInt(Math.floor(Date.now() / 1e3) + UNISWAP_LP_DEFAULT_DEADLINE_SEC_OFFSET);
|
|
2858
|
+
if (permit2Expiration48 > MAX_UINT48) permit2Expiration48 = MAX_UINT48;
|
|
2859
|
+
}
|
|
2464
2860
|
for (const target of approveTargets) {
|
|
2465
2861
|
if (target.kind === "weth_deposit") {
|
|
2466
2862
|
steps.push({
|
|
@@ -2473,13 +2869,17 @@ async function buildEvmMultisignBodyUniswapV4LiquidityBatchInternal(args) {
|
|
|
2473
2869
|
address: target.token,
|
|
2474
2870
|
abi: erc20AllowanceAbi2,
|
|
2475
2871
|
functionName: "allowance",
|
|
2476
|
-
args: [executor,
|
|
2872
|
+
args: [executor, erc20Spender]
|
|
2477
2873
|
});
|
|
2478
2874
|
if (wethAllowance < target.amount) {
|
|
2479
|
-
if (wethAllowance > 0n) {
|
|
2875
|
+
if (wethAllowance > 0n && !usePermit2) {
|
|
2480
2876
|
steps.push({
|
|
2481
2877
|
to: target.token,
|
|
2482
|
-
data: viem.encodeFunctionData({
|
|
2878
|
+
data: viem.encodeFunctionData({
|
|
2879
|
+
abi: viem.erc20Abi,
|
|
2880
|
+
functionName: "approve",
|
|
2881
|
+
args: [erc20Spender, 0n]
|
|
2882
|
+
}),
|
|
2483
2883
|
value: 0n,
|
|
2484
2884
|
fallbackGas: UNISWAP_V4_LP_ERC20_APPROVE_FALLBACK
|
|
2485
2885
|
});
|
|
@@ -2489,7 +2889,7 @@ async function buildEvmMultisignBodyUniswapV4LiquidityBatchInternal(args) {
|
|
|
2489
2889
|
data: viem.encodeFunctionData({
|
|
2490
2890
|
abi: viem.erc20Abi,
|
|
2491
2891
|
functionName: "approve",
|
|
2492
|
-
args: [
|
|
2892
|
+
args: [erc20Spender, target.amount]
|
|
2493
2893
|
}),
|
|
2494
2894
|
value: 0n,
|
|
2495
2895
|
fallbackGas: UNISWAP_V4_LP_ERC20_APPROVE_FALLBACK
|
|
@@ -2501,13 +2901,66 @@ async function buildEvmMultisignBodyUniswapV4LiquidityBatchInternal(args) {
|
|
|
2501
2901
|
data: viem.encodeFunctionData({
|
|
2502
2902
|
abi: viem.erc20Abi,
|
|
2503
2903
|
functionName: "approve",
|
|
2504
|
-
args: [
|
|
2904
|
+
args: [erc20Spender, target.amount]
|
|
2505
2905
|
}),
|
|
2506
2906
|
value: 0n,
|
|
2507
2907
|
fallbackGas: UNISWAP_V4_LP_ERC20_APPROVE_FALLBACK
|
|
2508
2908
|
});
|
|
2509
2909
|
}
|
|
2510
2910
|
}
|
|
2911
|
+
if (usePermit2 && needsTokenApproves) {
|
|
2912
|
+
const pairs = [parsed.token0, parsed.token1].filter(Boolean);
|
|
2913
|
+
for (const row of pairs) {
|
|
2914
|
+
const amt = BigInt(row.amount);
|
|
2915
|
+
if (amt <= 0n) continue;
|
|
2916
|
+
let token;
|
|
2917
|
+
if (isNativeUniswapLpTokenAddress(row.tokenAddress)) {
|
|
2918
|
+
if (!args.nativeWrapped) {
|
|
2919
|
+
throw new Error("nativeWrapped is required when LP uses native ETH (0x0) token.");
|
|
2920
|
+
}
|
|
2921
|
+
token = viem.getAddress(args.nativeWrapped);
|
|
2922
|
+
if (!approveTargets.some((a) => a.token === token && a.kind === "weth_deposit")) {
|
|
2923
|
+
steps.push({
|
|
2924
|
+
to: token,
|
|
2925
|
+
data: viem.encodeFunctionData({ abi: wethDepositAbi, functionName: "deposit" }),
|
|
2926
|
+
value: amt,
|
|
2927
|
+
fallbackGas: UNISWAP_V4_LP_WETH_DEPOSIT_FALLBACK
|
|
2928
|
+
});
|
|
2929
|
+
const wethAllowance = await publicClient.readContract({
|
|
2930
|
+
address: token,
|
|
2931
|
+
abi: erc20AllowanceAbi2,
|
|
2932
|
+
functionName: "allowance",
|
|
2933
|
+
args: [executor, PERMIT2_ADDRESS]
|
|
2934
|
+
});
|
|
2935
|
+
if (wethAllowance < amt) {
|
|
2936
|
+
steps.push({
|
|
2937
|
+
to: token,
|
|
2938
|
+
data: viem.encodeFunctionData({
|
|
2939
|
+
abi: viem.erc20Abi,
|
|
2940
|
+
functionName: "approve",
|
|
2941
|
+
args: [PERMIT2_ADDRESS, amt]
|
|
2942
|
+
}),
|
|
2943
|
+
value: 0n,
|
|
2944
|
+
fallbackGas: UNISWAP_V4_LP_ERC20_APPROVE_FALLBACK
|
|
2945
|
+
});
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
} else {
|
|
2949
|
+
token = viem.getAddress(row.tokenAddress);
|
|
2950
|
+
}
|
|
2951
|
+
const amount160 = amt > MAX_UINT160 ? MAX_UINT160 : amt;
|
|
2952
|
+
steps.push({
|
|
2953
|
+
to: PERMIT2_ADDRESS,
|
|
2954
|
+
data: viem.encodeFunctionData({
|
|
2955
|
+
abi: permit2ApproveAbi,
|
|
2956
|
+
functionName: "approve",
|
|
2957
|
+
args: [token, to, amount160, Number(permit2Expiration48)]
|
|
2958
|
+
}),
|
|
2959
|
+
value: 0n,
|
|
2960
|
+
fallbackGas: UNISWAP_V4_LP_PERMIT2_APPROVE_FALLBACK
|
|
2961
|
+
});
|
|
2962
|
+
}
|
|
2963
|
+
}
|
|
2511
2964
|
const lpFallbackGas = defaultGasForAction(args.action);
|
|
2512
2965
|
const fromTradeApi = parseOptionalGasLimitString2(tx.gasLimit) ?? parseOptionalGasLimitString2(tx.gas);
|
|
2513
2966
|
steps.push({
|
|
@@ -2519,6 +2972,7 @@ async function buildEvmMultisignBodyUniswapV4LiquidityBatchInternal(args) {
|
|
|
2519
2972
|
const actionLabel = args.action === "mint" ? "mint liquidity" : args.action === "increase" ? "increase liquidity" : args.action === "decrease" ? "decrease liquidity" : "collect fees";
|
|
2520
2973
|
const dataNo0x = dataHex.startsWith("0x") ? dataHex.slice(2) : dataHex;
|
|
2521
2974
|
const lpIndex = steps.length - 1;
|
|
2975
|
+
const purposeSuffix = usePermit2 ? `Uniswap V4 permissioned: ${steps.length}-tx batch \u2014 ${actionLabel} (ERC-20\u2192Permit2, Permit2\u2192PosM, Position Manager).` : `Uniswap V4: ${steps.length}-tx batch \u2014 ${actionLabel} (classic ERC-20 approve + Position Manager).`;
|
|
2522
2976
|
return buildEvmMultisignBatch({
|
|
2523
2977
|
context: {
|
|
2524
2978
|
chainCategory: "evm",
|
|
@@ -2532,7 +2986,7 @@ async function buildEvmMultisignBodyUniswapV4LiquidityBatchInternal(args) {
|
|
|
2532
2986
|
customGasChainDetails: args.customGasChainDetails
|
|
2533
2987
|
},
|
|
2534
2988
|
steps,
|
|
2535
|
-
purposeSuffix
|
|
2989
|
+
purposeSuffix,
|
|
2536
2990
|
firstMsgRawNo0x: dataNo0x,
|
|
2537
2991
|
destinationAddress: to,
|
|
2538
2992
|
buildBatchMeta: ({ index }) => {
|
|
@@ -2542,13 +2996,17 @@ async function buildEvmMultisignBodyUniswapV4LiquidityBatchInternal(args) {
|
|
|
2542
2996
|
kind: "UniswapV4Liquidity",
|
|
2543
2997
|
action: args.action,
|
|
2544
2998
|
step: index,
|
|
2545
|
-
lpTx: isLpStep
|
|
2999
|
+
lpTx: isLpStep,
|
|
3000
|
+
positionManagerKind,
|
|
3001
|
+
usePermit2
|
|
2546
3002
|
}),
|
|
2547
3003
|
...isLpStep ? {
|
|
2548
3004
|
evm: { type: "uniswap_v4_liquidity_tx", version: 1, chainId: String(args.chainId) },
|
|
2549
3005
|
uniswapV4Liquidity: {
|
|
2550
3006
|
action: args.action,
|
|
2551
|
-
skipPermit2Batch:
|
|
3007
|
+
skipPermit2Batch: !usePermit2,
|
|
3008
|
+
usePermit2Approvals: usePermit2,
|
|
3009
|
+
positionManagerKind,
|
|
2552
3010
|
nftTokenId: args.nftTokenId != null ? String(args.nftTokenId) : void 0,
|
|
2553
3011
|
poolReference: args.poolReference,
|
|
2554
3012
|
lpResponseSnapshot: args.lpResponse,
|
|
@@ -2581,6 +3039,260 @@ async function buildEvmMultisignBodyUniswapV4DecreaseLiquidityBatch(args) {
|
|
|
2581
3039
|
async function buildEvmMultisignBodyUniswapV4CollectFeesBatch(args) {
|
|
2582
3040
|
return buildEvmMultisignBodyUniswapV4LiquidityBatchInternal({ ...args, action: "collect" });
|
|
2583
3041
|
}
|
|
3042
|
+
var PERMISSIONED_LP_PRESETS = [
|
|
3043
|
+
// No public launch-partner presets hard-coded yet — use custom existingPool with hooks.
|
|
3044
|
+
];
|
|
3045
|
+
function buildUniswapV4PermissionedLpPoolRow(args) {
|
|
3046
|
+
const chainId = parseUniswapChainId(args.chainId);
|
|
3047
|
+
const hooks = (args.hooks?.trim() ? viem.getAddress(args.hooks.trim()) : tryGetUniswapV4PermissionedHooks(chainId)) ?? (() => {
|
|
3048
|
+
throw new Error(`No PermissionedHooks for chainId ${chainId}; pass hooks explicitly.`);
|
|
3049
|
+
})();
|
|
3050
|
+
const positionManager = tryGetUniswapV4PermissionedPositionManager(chainId);
|
|
3051
|
+
if (!positionManager) {
|
|
3052
|
+
throw new Error(`No Permissioned PositionManager for chainId ${chainId}.`);
|
|
3053
|
+
}
|
|
3054
|
+
const adapter = viem.getAddress(args.adapterAddress);
|
|
3055
|
+
const other = viem.getAddress(args.otherCurrencyAddress);
|
|
3056
|
+
const sorted = sortUniswapV4PoolCurrencies(adapter, other);
|
|
3057
|
+
const poolReference = computeUniswapV4PoolReference({
|
|
3058
|
+
token0Address: sorted.currency0,
|
|
3059
|
+
token1Address: sorted.currency1,
|
|
3060
|
+
fee: args.fee,
|
|
3061
|
+
tickSpacing: args.tickSpacing,
|
|
3062
|
+
hooks
|
|
3063
|
+
});
|
|
3064
|
+
return {
|
|
3065
|
+
presetId: args.presetId,
|
|
3066
|
+
pairSlug: args.pairSlug,
|
|
3067
|
+
pairLabel: args.pairLabel,
|
|
3068
|
+
fee: args.fee,
|
|
3069
|
+
feeLabel: args.feeLabel,
|
|
3070
|
+
tickSpacing: args.tickSpacing,
|
|
3071
|
+
token0Symbol: sorted.currency0 === adapter ? args.adapterSymbol ?? "v4PT" : args.otherSymbol ?? "TOKEN",
|
|
3072
|
+
token1Symbol: sorted.currency1 === adapter ? args.adapterSymbol ?? "v4PT" : args.otherSymbol ?? "TOKEN",
|
|
3073
|
+
token0Address: sorted.currency0,
|
|
3074
|
+
token1Address: sorted.currency1,
|
|
3075
|
+
poolReference,
|
|
3076
|
+
hooks,
|
|
3077
|
+
nativeWrapped: args.nativeWrapped ? viem.getAddress(args.nativeWrapped) : void 0,
|
|
3078
|
+
usesNativeEth: Boolean(args.usesNativeEth),
|
|
3079
|
+
positionManagerKind: "permissioned",
|
|
3080
|
+
positionManager,
|
|
3081
|
+
underlyingPermissionedToken: args.underlyingPermissionedToken ? viem.getAddress(args.underlyingPermissionedToken) : void 0,
|
|
3082
|
+
adapterAddress: adapter,
|
|
3083
|
+
issuer: args.issuer
|
|
3084
|
+
};
|
|
3085
|
+
}
|
|
3086
|
+
function listUniswapV4PermissionedLpPools(args) {
|
|
3087
|
+
const chainId = parseUniswapChainId(args.chainId);
|
|
3088
|
+
const positionManager = tryGetUniswapV4PermissionedPositionManager(chainId);
|
|
3089
|
+
const hooks = tryGetUniswapV4PermissionedHooks(chainId);
|
|
3090
|
+
if (!positionManager || !hooks) {
|
|
3091
|
+
return {
|
|
3092
|
+
chainId,
|
|
3093
|
+
chainLabel: `chain ${chainId}`,
|
|
3094
|
+
pools: [],
|
|
3095
|
+
positionManagerKind: "permissioned",
|
|
3096
|
+
notes: "No Permissioned PositionManager / PermissionedHooks configured for this chain. Ethereum mainnet (1) and Sepolia (11155111) are supported. Pass custom existingPool with adapter currency + hooks."
|
|
3097
|
+
};
|
|
3098
|
+
}
|
|
3099
|
+
let pools = PERMISSIONED_LP_PRESETS.filter(
|
|
3100
|
+
(p) => p.chainId === chainId
|
|
3101
|
+
).map(
|
|
3102
|
+
(p) => buildUniswapV4PermissionedLpPoolRow({
|
|
3103
|
+
chainId,
|
|
3104
|
+
presetId: p.presetId,
|
|
3105
|
+
pairSlug: p.pairSlug,
|
|
3106
|
+
pairLabel: p.pairLabel,
|
|
3107
|
+
fee: p.fee,
|
|
3108
|
+
feeLabel: p.feeLabel,
|
|
3109
|
+
tickSpacing: p.tickSpacing,
|
|
3110
|
+
adapterAddress: p.adapterAddress,
|
|
3111
|
+
otherCurrencyAddress: p.otherCurrency,
|
|
3112
|
+
adapterSymbol: p.adapterSymbol,
|
|
3113
|
+
otherSymbol: p.otherSymbol,
|
|
3114
|
+
underlyingPermissionedToken: p.underlyingPermissionedToken,
|
|
3115
|
+
usesNativeEth: p.usesNativeEth,
|
|
3116
|
+
nativeWrapped: p.nativeWrapped,
|
|
3117
|
+
issuer: p.issuer,
|
|
3118
|
+
hooks
|
|
3119
|
+
})
|
|
3120
|
+
);
|
|
3121
|
+
const pairFilter = args.pair?.trim().toLowerCase();
|
|
3122
|
+
if (pairFilter) {
|
|
3123
|
+
pools = pools.filter(
|
|
3124
|
+
(row) => row.pairSlug.includes(pairFilter) || row.pairLabel.toLowerCase().includes(pairFilter) || row.presetId.includes(pairFilter)
|
|
3125
|
+
);
|
|
3126
|
+
}
|
|
3127
|
+
const chainLabel = PERMISSIONED_LP_PRESETS.find((p) => p.chainId === chainId)?.chainLabel ?? (chainId === 1 ? "Ethereum" : chainId === 11155111 ? "Sepolia" : `chain ${chainId}`);
|
|
3128
|
+
return {
|
|
3129
|
+
chainId,
|
|
3130
|
+
chainLabel,
|
|
3131
|
+
pools,
|
|
3132
|
+
positionManagerKind: "permissioned",
|
|
3133
|
+
notes: `Permissioned LP uses Permissioned Position Manager (UNI-V4-PERM-POSM) and PermissionedHooks. Pool currencies use the Permissions Adapter address, not the underlying token. Requires LIQUIDITY_ALLOWED on the wallet. Curated presets may be empty \u2014 pass existingPool with adapter + hooks + fee/tickSpacing. positionManager=${positionManager} hooks=${hooks}`
|
|
3134
|
+
};
|
|
3135
|
+
}
|
|
3136
|
+
function resolveUniswapV4PermissionedLpPoolPreset(args) {
|
|
3137
|
+
const listed = listUniswapV4PermissionedLpPools({ chainId: args.chainId });
|
|
3138
|
+
const preset = args.presetId.trim().toLowerCase();
|
|
3139
|
+
const row = listed.pools.find((p) => p.presetId.toLowerCase() === preset);
|
|
3140
|
+
if (!row) {
|
|
3141
|
+
throw new Error(
|
|
3142
|
+
`Unknown permissioned LP pool preset "${args.presetId}" on chainId ${listed.chainId}. Call ctm_uniswap_v4_list_lp_pools with permissioned=true, or pass custom existingPool.`
|
|
3143
|
+
);
|
|
3144
|
+
}
|
|
3145
|
+
return row;
|
|
3146
|
+
}
|
|
3147
|
+
function uniswapV4ListLpPools(args) {
|
|
3148
|
+
if (args.permissioned) {
|
|
3149
|
+
return listUniswapV4PermissionedLpPools(args);
|
|
3150
|
+
}
|
|
3151
|
+
const std = listUniswapV4StandardLpPools(args);
|
|
3152
|
+
return {
|
|
3153
|
+
...std,
|
|
3154
|
+
positionManagerKind: "standard"
|
|
3155
|
+
};
|
|
3156
|
+
}
|
|
3157
|
+
function buildUniswapV4KycApplyLink(args) {
|
|
3158
|
+
const walletAddress = viem.getAddress(args.walletAddress.trim());
|
|
3159
|
+
const chainId = parseUniswapChainId(args.chainId);
|
|
3160
|
+
const kycUrl = args.kycUrl.trim();
|
|
3161
|
+
if (!kycUrl) throw new Error("kycUrl is required");
|
|
3162
|
+
let token;
|
|
3163
|
+
let adapterTokenAddress;
|
|
3164
|
+
if (args.token?.trim()) {
|
|
3165
|
+
try {
|
|
3166
|
+
token = viem.getAddress(args.token.trim());
|
|
3167
|
+
} catch {
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
if (args.adapterTokenAddress?.trim()) {
|
|
3171
|
+
try {
|
|
3172
|
+
adapterTokenAddress = viem.getAddress(args.adapterTokenAddress.trim());
|
|
3173
|
+
} catch {
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
let applyUrl = kycUrl;
|
|
3177
|
+
try {
|
|
3178
|
+
const u = new URL(kycUrl);
|
|
3179
|
+
if (!u.searchParams.has("wallet") && !u.searchParams.has("address")) {
|
|
3180
|
+
u.searchParams.set("wallet", walletAddress);
|
|
3181
|
+
u.searchParams.set("address", walletAddress);
|
|
3182
|
+
}
|
|
3183
|
+
if (!u.searchParams.has("chainId")) u.searchParams.set("chainId", String(chainId));
|
|
3184
|
+
if (token && !u.searchParams.has("token")) u.searchParams.set("token", token);
|
|
3185
|
+
applyUrl = u.toString();
|
|
3186
|
+
} catch {
|
|
3187
|
+
applyUrl = kycUrl;
|
|
3188
|
+
}
|
|
3189
|
+
return {
|
|
3190
|
+
walletAddress,
|
|
3191
|
+
chainId,
|
|
3192
|
+
issuer: args.issuer?.trim() || void 0,
|
|
3193
|
+
kycUrl,
|
|
3194
|
+
applyUrl,
|
|
3195
|
+
token,
|
|
3196
|
+
adapterTokenAddress
|
|
3197
|
+
};
|
|
3198
|
+
}
|
|
3199
|
+
function pickUniswapV4KycTarget(results) {
|
|
3200
|
+
return results.find((r) => r.isPermissioned && !r.isAllowlisted && r.kycUrl) ?? results.find((r) => r.isPermissioned && r.kycUrl) ?? null;
|
|
3201
|
+
}
|
|
3202
|
+
function uniswapV4KycApplyLinkMcp(args) {
|
|
3203
|
+
return buildUniswapV4KycApplyLink(args);
|
|
3204
|
+
}
|
|
3205
|
+
var ALLOWLIST_FINALIZE_FALLBACK_GAS = 250000n;
|
|
3206
|
+
async function buildEvmMultisignBodyUniswapV4PermissionedAllowlistFinalize(args) {
|
|
3207
|
+
const to = viem.getAddress(args.to.trim());
|
|
3208
|
+
let dataHex = (args.data ?? "0x").toString().trim();
|
|
3209
|
+
if (!dataHex.startsWith("0x")) dataHex = `0x${dataHex}`;
|
|
3210
|
+
if (dataHex.length < 10) {
|
|
3211
|
+
throw new Error("allowlist finalize `data` must be non-empty ABI-encoded calldata");
|
|
3212
|
+
}
|
|
3213
|
+
let value = 0n;
|
|
3214
|
+
if (args.valueWei != null && String(args.valueWei).trim() !== "") {
|
|
3215
|
+
try {
|
|
3216
|
+
value = BigInt(String(args.valueWei).trim());
|
|
3217
|
+
} catch {
|
|
3218
|
+
value = 0n;
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
const steps = [
|
|
3222
|
+
{
|
|
3223
|
+
to,
|
|
3224
|
+
data: dataHex,
|
|
3225
|
+
value,
|
|
3226
|
+
fallbackGas: ALLOWLIST_FINALIZE_FALLBACK_GAS
|
|
3227
|
+
}
|
|
3228
|
+
];
|
|
3229
|
+
const dataNo0x = dataHex.slice(2);
|
|
3230
|
+
const issuerLabel = args.issuer?.trim() || "issuer";
|
|
3231
|
+
return buildEvmMultisignBatch({
|
|
3232
|
+
context: {
|
|
3233
|
+
chainCategory: "evm",
|
|
3234
|
+
keyGen: args.keyGen,
|
|
3235
|
+
purposeText: args.purposeText,
|
|
3236
|
+
chainId: args.chainId,
|
|
3237
|
+
rpcUrl: args.rpcUrl,
|
|
3238
|
+
executorAddress: args.executorAddress,
|
|
3239
|
+
chainDetail: args.chainDetail,
|
|
3240
|
+
useCustomGas: args.useCustomGas,
|
|
3241
|
+
customGasChainDetails: args.customGasChainDetails
|
|
3242
|
+
},
|
|
3243
|
+
steps,
|
|
3244
|
+
purposeSuffix: `Uniswap V4 permissioned: 1-tx allowlist finalize (${issuerLabel}).`,
|
|
3245
|
+
firstMsgRawNo0x: dataNo0x,
|
|
3246
|
+
destinationAddress: to,
|
|
3247
|
+
buildBatchMeta: () => ({
|
|
3248
|
+
signatureText: JSON.stringify({
|
|
3249
|
+
kind: "UniswapV4PermissionedAllowlist",
|
|
3250
|
+
issuer: args.issuer,
|
|
3251
|
+
entityId: args.entityId != null ? String(args.entityId) : void 0
|
|
3252
|
+
}),
|
|
3253
|
+
evm: {
|
|
3254
|
+
type: "uniswap_v4_permissioned_allowlist",
|
|
3255
|
+
version: 1,
|
|
3256
|
+
chainId: String(args.chainId)
|
|
3257
|
+
},
|
|
3258
|
+
uniswapV4PermissionedAllowlist: {
|
|
3259
|
+
to,
|
|
3260
|
+
dataNibbles: dataNo0x.length,
|
|
3261
|
+
issuer: args.issuer,
|
|
3262
|
+
entityId: args.entityId != null ? String(args.entityId) : void 0,
|
|
3263
|
+
tokenAddress: args.tokenAddress,
|
|
3264
|
+
originalPurpose: args.purposeText
|
|
3265
|
+
}
|
|
3266
|
+
})
|
|
3267
|
+
});
|
|
3268
|
+
}
|
|
3269
|
+
function isUniswapV4PermissionedAllowlistEvmSignRequest(detail) {
|
|
3270
|
+
if (!detail) return false;
|
|
3271
|
+
const raw = detail.ExtraJSON ?? detail.extraJSON;
|
|
3272
|
+
let ex = null;
|
|
3273
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) ex = raw;
|
|
3274
|
+
else if (typeof raw === "string" && raw.trim()) {
|
|
3275
|
+
try {
|
|
3276
|
+
const p = JSON.parse(raw);
|
|
3277
|
+
if (p && typeof p === "object" && !Array.isArray(p)) ex = p;
|
|
3278
|
+
} catch {
|
|
3279
|
+
return false;
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3282
|
+
if (!ex) return false;
|
|
3283
|
+
const bm = ex.batchMeta;
|
|
3284
|
+
if (Array.isArray(bm) && bm[0] && typeof bm[0] === "object" && !Array.isArray(bm[0])) {
|
|
3285
|
+
const evm0 = bm[0].evm;
|
|
3286
|
+
if (evm0 && typeof evm0 === "object" && !Array.isArray(evm0)) {
|
|
3287
|
+
if (String(evm0.type ?? "") === "uniswap_v4_permissioned_allowlist") {
|
|
3288
|
+
return true;
|
|
3289
|
+
}
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3292
|
+
const evm = ex.evm;
|
|
3293
|
+
if (!evm || typeof evm !== "object" || Array.isArray(evm)) return false;
|
|
3294
|
+
return String(evm.type ?? "") === "uniswap_v4_permissioned_allowlist";
|
|
3295
|
+
}
|
|
2584
3296
|
|
|
2585
3297
|
// src/protocols/evm/uniswap-v4/support.ts
|
|
2586
3298
|
function computeUniswapV4Session(args) {
|
|
@@ -2599,7 +3311,12 @@ function computeUniswapV4Session(args) {
|
|
|
2599
3311
|
chainId: chainIdNum,
|
|
2600
3312
|
rpcUrl,
|
|
2601
3313
|
chainSupported,
|
|
2602
|
-
universalRouter
|
|
3314
|
+
universalRouter,
|
|
3315
|
+
universalRouterV22: tryGetUniswapUniversalRouterV22(chainIdNum) ?? void 0,
|
|
3316
|
+
positionManager: tryGetUniswapV4PositionManager(chainIdNum) ?? void 0,
|
|
3317
|
+
permissionedPositionManager: tryGetUniswapV4PermissionedPositionManager(chainIdNum) ?? void 0,
|
|
3318
|
+
permissionedHooks: tryGetUniswapV4PermissionedHooks(chainIdNum) ?? void 0,
|
|
3319
|
+
permissionsAdapterFactory: tryGetUniswapV4PermissionsAdapterFactory(chainIdNum) ?? void 0
|
|
2603
3320
|
};
|
|
2604
3321
|
}
|
|
2605
3322
|
|
|
@@ -2890,6 +3607,28 @@ async function fetchUniswapV4PoolMeta(args) {
|
|
|
2890
3607
|
);
|
|
2891
3608
|
return data.pool ?? null;
|
|
2892
3609
|
}
|
|
3610
|
+
var LATEST_SWAP_GQL = `
|
|
3611
|
+
query UniswapV4LatestSwap($pool: String!) {
|
|
3612
|
+
swaps(
|
|
3613
|
+
where: { pool: $pool }
|
|
3614
|
+
orderBy: timestamp
|
|
3615
|
+
orderDirection: desc
|
|
3616
|
+
first: 1
|
|
3617
|
+
) {
|
|
3618
|
+
token0Price
|
|
3619
|
+
sqrtPriceX96
|
|
3620
|
+
}
|
|
3621
|
+
}`;
|
|
3622
|
+
async function fetchUniswapV4LatestSwap(args) {
|
|
3623
|
+
const pool = normalizePoolId(args.poolReference);
|
|
3624
|
+
const data = await postUniswapV4SubgraphGql(
|
|
3625
|
+
args.chainId,
|
|
3626
|
+
LATEST_SWAP_GQL,
|
|
3627
|
+
{ pool },
|
|
3628
|
+
args.theGraphApiKey
|
|
3629
|
+
);
|
|
3630
|
+
return data.swaps?.[0] ?? null;
|
|
3631
|
+
}
|
|
2893
3632
|
|
|
2894
3633
|
// src/protocols/evm/uniswap-v4/bitqueryApiKey.ts
|
|
2895
3634
|
var BITQUERY_API_KEY_ENV = "BITQUERY_API_KEY";
|
|
@@ -3178,7 +3917,7 @@ function parseDecimal(raw) {
|
|
|
3178
3917
|
const n = Number(raw);
|
|
3179
3918
|
return Number.isFinite(n) && n > 0 ? n : null;
|
|
3180
3919
|
}
|
|
3181
|
-
function
|
|
3920
|
+
function priceFromUniswapV4SwapRow(row) {
|
|
3182
3921
|
const fromToken0 = parseDecimal(row.token0Price);
|
|
3183
3922
|
if (fromToken0 != null) return fromToken0;
|
|
3184
3923
|
const sqrt = row.sqrtPriceX96?.trim();
|
|
@@ -3200,7 +3939,7 @@ function bucketUniswapV4SwapsIntoCandles(args) {
|
|
|
3200
3939
|
const buckets = /* @__PURE__ */ new Map();
|
|
3201
3940
|
for (const swap of args.swaps) {
|
|
3202
3941
|
const ts = Number(swap.timestamp);
|
|
3203
|
-
const price =
|
|
3942
|
+
const price = priceFromUniswapV4SwapRow(swap);
|
|
3204
3943
|
if (!Number.isFinite(ts) || price == null) continue;
|
|
3205
3944
|
const bucket = bucketStartSec(Math.floor(ts), args.bucketSec);
|
|
3206
3945
|
const vol = parseDecimal(swap.amountUSD) ?? 0;
|
|
@@ -3541,6 +4280,74 @@ async function uniswapV4FetchOhlcv(args) {
|
|
|
3541
4280
|
};
|
|
3542
4281
|
}
|
|
3543
4282
|
|
|
4283
|
+
// src/protocols/evm/uniswap-v4/livePrice.ts
|
|
4284
|
+
function applyPriceQuote(price, quote) {
|
|
4285
|
+
if (!Number.isFinite(price) || price <= 0) return null;
|
|
4286
|
+
if (quote === "token1PerToken0") {
|
|
4287
|
+
const inverted = 1 / price;
|
|
4288
|
+
return Number.isFinite(inverted) && inverted > 0 ? inverted : null;
|
|
4289
|
+
}
|
|
4290
|
+
return price;
|
|
4291
|
+
}
|
|
4292
|
+
function bitqueryFilterFromPoolReference(poolReference) {
|
|
4293
|
+
const ref = poolReference.trim();
|
|
4294
|
+
if (!ref) return null;
|
|
4295
|
+
if (ref.startsWith("symbol:")) {
|
|
4296
|
+
return { kind: "symbol", symbol: ref.slice("symbol:".length).trim() };
|
|
4297
|
+
}
|
|
4298
|
+
if (ref.startsWith("0x")) {
|
|
4299
|
+
return { kind: "address", address: ref };
|
|
4300
|
+
}
|
|
4301
|
+
return null;
|
|
4302
|
+
}
|
|
4303
|
+
async function fetchUniswapV4BitqueryLatestClose(args) {
|
|
4304
|
+
const filter = bitqueryFilterFromPoolReference(args.poolReference);
|
|
4305
|
+
if (!filter) return null;
|
|
4306
|
+
const apiKey = resolveBitqueryApiKey(args.bitqueryApiKey);
|
|
4307
|
+
if (!apiKey) return null;
|
|
4308
|
+
const interval = args.interval?.trim() || "15m";
|
|
4309
|
+
const endTimeMs = Date.now();
|
|
4310
|
+
const startTimeMs = endTimeMs - 6 * 3600 * 1e3;
|
|
4311
|
+
const { candles } = await fetchRobinhoodBitqueryOhlcv({
|
|
4312
|
+
filter,
|
|
4313
|
+
interval,
|
|
4314
|
+
startTimeMs,
|
|
4315
|
+
endTimeMs,
|
|
4316
|
+
apiKey,
|
|
4317
|
+
limit: 5
|
|
4318
|
+
});
|
|
4319
|
+
if (candles.length === 0) return null;
|
|
4320
|
+
const last = candles[candles.length - 1];
|
|
4321
|
+
const close = Number(last.close);
|
|
4322
|
+
return Number.isFinite(close) && close > 0 ? close : null;
|
|
4323
|
+
}
|
|
4324
|
+
async function fetchUniswapV4ChartLivePrice(args) {
|
|
4325
|
+
const chainId = Math.floor(Number(args.chainId));
|
|
4326
|
+
if (!Number.isFinite(chainId) || chainId <= 0) return null;
|
|
4327
|
+
const poolReference = args.poolReference.trim();
|
|
4328
|
+
if (!poolReference) return null;
|
|
4329
|
+
const dataSource = String(args.dataSource ?? "").trim().toLowerCase();
|
|
4330
|
+
if (dataSource === "bitquery" || isRobinhoodOhlcvChain(chainId)) {
|
|
4331
|
+
return fetchUniswapV4BitqueryLatestClose({
|
|
4332
|
+
poolReference,
|
|
4333
|
+
interval: args.interval,
|
|
4334
|
+
bitqueryApiKey: args.bitqueryApiKey
|
|
4335
|
+
});
|
|
4336
|
+
}
|
|
4337
|
+
if (!uniswapV4SubgraphSupportedChainIds().includes(chainId)) {
|
|
4338
|
+
return null;
|
|
4339
|
+
}
|
|
4340
|
+
const row = await fetchUniswapV4LatestSwap({
|
|
4341
|
+
chainId,
|
|
4342
|
+
poolReference,
|
|
4343
|
+
theGraphApiKey: resolveTheGraphApiKey(args.theGraphApiKey)
|
|
4344
|
+
});
|
|
4345
|
+
if (!row) return null;
|
|
4346
|
+
const raw = priceFromUniswapV4SwapRow(row);
|
|
4347
|
+
if (raw == null) return null;
|
|
4348
|
+
return applyPriceQuote(raw, args.priceQuote);
|
|
4349
|
+
}
|
|
4350
|
+
|
|
3544
4351
|
// src/protocols/evm/uniswap-v4/limitOrder.ts
|
|
3545
4352
|
function trimAddr3(a) {
|
|
3546
4353
|
return a.trim();
|
|
@@ -4059,6 +4866,7 @@ exports.UNISWAP_SWAP_DEFAULT_EXPIRY_MINUTES = UNISWAP_SWAP_DEFAULT_EXPIRY_MINUTE
|
|
|
4059
4866
|
exports.UNISWAP_TRADE_BASE_DEFAULT = UNISWAP_TRADE_BASE_DEFAULT;
|
|
4060
4867
|
exports.UNISWAP_UNIVERSAL_ROUTER_DEFAULT_GAS_UNITS = UNISWAP_UNIVERSAL_ROUTER_DEFAULT_GAS_UNITS;
|
|
4061
4868
|
exports.UNISWAP_UNIVERSAL_ROUTER_VERSION_DEFAULT = UNISWAP_UNIVERSAL_ROUTER_VERSION_DEFAULT;
|
|
4869
|
+
exports.UNISWAP_UNIVERSAL_ROUTER_VERSION_PERMISSIONED = UNISWAP_UNIVERSAL_ROUTER_VERSION_PERMISSIONED;
|
|
4062
4870
|
exports.UNISWAP_V4_LP_COLLECT_DEFAULT_GAS_UNITS = UNISWAP_V4_LP_COLLECT_DEFAULT_GAS_UNITS;
|
|
4063
4871
|
exports.UNISWAP_V4_LP_DECREASE_DEFAULT_GAS_UNITS = UNISWAP_V4_LP_DECREASE_DEFAULT_GAS_UNITS;
|
|
4064
4872
|
exports.UNISWAP_V4_LP_ERC20_APPROVE_FALLBACK = UNISWAP_V4_LP_ERC20_APPROVE_FALLBACK;
|
|
@@ -4066,16 +4874,21 @@ exports.UNISWAP_V4_LP_INCREASE_DEFAULT_GAS_UNITS = UNISWAP_V4_LP_INCREASE_DEFAUL
|
|
|
4066
4874
|
exports.UNISWAP_V4_LP_LOG_CHUNK_SIZE_DEFAULT = UNISWAP_V4_LP_LOG_CHUNK_SIZE_DEFAULT;
|
|
4067
4875
|
exports.UNISWAP_V4_LP_LOG_CHUNK_SIZE_MIN = UNISWAP_V4_LP_LOG_CHUNK_SIZE_MIN;
|
|
4068
4876
|
exports.UNISWAP_V4_LP_MINT_DEFAULT_GAS_UNITS = UNISWAP_V4_LP_MINT_DEFAULT_GAS_UNITS;
|
|
4877
|
+
exports.UNISWAP_V4_LP_PERMIT2_APPROVE_FALLBACK = UNISWAP_V4_LP_PERMIT2_APPROVE_FALLBACK;
|
|
4069
4878
|
exports.UNISWAP_V4_LP_POOL_LOOKUP_HINT = UNISWAP_V4_LP_POOL_LOOKUP_HINT;
|
|
4070
4879
|
exports.UNISWAP_V4_LP_POSITION_REGISTRY_HINT = UNISWAP_V4_LP_POSITION_REGISTRY_HINT;
|
|
4071
4880
|
exports.UNISWAP_V4_LP_WETH_DEPOSIT_FALLBACK = UNISWAP_V4_LP_WETH_DEPOSIT_FALLBACK;
|
|
4072
4881
|
exports.UNISWAP_V4_OHLCV_INTERVALS = UNISWAP_V4_OHLCV_INTERVALS;
|
|
4882
|
+
exports.UNISWAP_V4_PERMISSION_FLAG_LIQUIDITY = UNISWAP_V4_PERMISSION_FLAG_LIQUIDITY;
|
|
4883
|
+
exports.UNISWAP_V4_PERMISSION_FLAG_SWAP = UNISWAP_V4_PERMISSION_FLAG_SWAP;
|
|
4073
4884
|
exports.UNISWAP_V4_PROTOCOL_ID = UNISWAP_V4_PROTOCOL_ID;
|
|
4074
4885
|
exports.UNISWAP_V4_SUBGRAPH_ID_BY_CHAIN_ID = UNISWAP_V4_SUBGRAPH_ID_BY_CHAIN_ID;
|
|
4886
|
+
exports.UniswapV4PermissionDeniedError = UniswapV4PermissionDeniedError;
|
|
4075
4887
|
exports.aggregateOhlcvCandles = aggregateOhlcvCandles;
|
|
4076
4888
|
exports.applySlippagePercentToApproveWei = applySlippagePercentToApproveWei;
|
|
4077
4889
|
exports.assertUniswapLimitOrderChain = assertUniswapLimitOrderChain;
|
|
4078
4890
|
exports.assertUniswapV4OhlcvInterval = assertUniswapV4OhlcvInterval;
|
|
4891
|
+
exports.assertUniswapV4PermissionsAllowlisted = assertUniswapV4PermissionsAllowlisted;
|
|
4079
4892
|
exports.bitqueryApiKeyVariablesHint = bitqueryApiKeyVariablesHint;
|
|
4080
4893
|
exports.bitqueryAuthErrorMessage = bitqueryAuthErrorMessage;
|
|
4081
4894
|
exports.buildEvmMultisignBodyUniswapV4CollectFeesBatch = buildEvmMultisignBodyUniswapV4CollectFeesBatch;
|
|
@@ -4084,9 +4897,12 @@ exports.buildEvmMultisignBodyUniswapV4IncreaseLiquidityBatch = buildEvmMultisign
|
|
|
4084
4897
|
exports.buildEvmMultisignBodyUniswapV4LimitOrderBatch = buildEvmMultisignBodyUniswapV4LimitOrderBatch;
|
|
4085
4898
|
exports.buildEvmMultisignBodyUniswapV4LimitOrderBatchFromMcp = buildEvmMultisignBodyUniswapV4LimitOrderBatchFromMcp;
|
|
4086
4899
|
exports.buildEvmMultisignBodyUniswapV4MintLiquidityBatch = buildEvmMultisignBodyUniswapV4MintLiquidityBatch;
|
|
4900
|
+
exports.buildEvmMultisignBodyUniswapV4PermissionedAllowlistFinalize = buildEvmMultisignBodyUniswapV4PermissionedAllowlistFinalize;
|
|
4087
4901
|
exports.buildEvmMultisignBodyUniswapV4SkipPermit2Batch = buildEvmMultisignBodyUniswapV4SkipPermit2Batch;
|
|
4088
4902
|
exports.buildLimitOrderQuoteRequestBody = buildLimitOrderQuoteRequestBody;
|
|
4089
4903
|
exports.buildUniswapQuoteRequestBody = buildUniswapQuoteRequestBody;
|
|
4904
|
+
exports.buildUniswapV4KycApplyLink = buildUniswapV4KycApplyLink;
|
|
4905
|
+
exports.buildUniswapV4PermissionedLpPoolRow = buildUniswapV4PermissionedLpPoolRow;
|
|
4090
4906
|
exports.buildUniswapV4PurposePrefill = buildUniswapV4PurposePrefill;
|
|
4091
4907
|
exports.buildUniswapXLimitOrderSubmitBody = buildUniswapXLimitOrderSubmitBody;
|
|
4092
4908
|
exports.computeUniswapV4PoolReference = computeUniswapV4PoolReference;
|
|
@@ -4099,6 +4915,8 @@ exports.extractUniswapLpTokenAmounts = extractUniswapLpTokenAmounts;
|
|
|
4099
4915
|
exports.extractUniswapLpTransaction = extractUniswapLpTransaction;
|
|
4100
4916
|
exports.fetchEthereumAddressForKeyGen = fetchEthereumAddressForKeyGen;
|
|
4101
4917
|
exports.fetchRobinhoodBitqueryOhlcv = fetchRobinhoodBitqueryOhlcv;
|
|
4918
|
+
exports.fetchUniswapV4ChartLivePrice = fetchUniswapV4ChartLivePrice;
|
|
4919
|
+
exports.fetchUniswapV4LatestSwap = fetchUniswapV4LatestSwap;
|
|
4102
4920
|
exports.fetchUniswapV4PoolDayDatas = fetchUniswapV4PoolDayDatas;
|
|
4103
4921
|
exports.fetchUniswapV4PoolHourDatas = fetchUniswapV4PoolHourDatas;
|
|
4104
4922
|
exports.fetchUniswapV4PoolMeta = fetchUniswapV4PoolMeta;
|
|
@@ -4112,6 +4930,9 @@ exports.formatUniswapV4PositionNotFoundError = formatUniswapV4PositionNotFoundEr
|
|
|
4112
4930
|
exports.getClassicQuoteFromStoredUniswapResponse = getClassicQuoteFromStoredUniswapResponse;
|
|
4113
4931
|
exports.getUniswapUniversalRouterSpenderOrThrow = getUniswapUniversalRouterSpenderOrThrow;
|
|
4114
4932
|
exports.getUniswapUniversalRouterVersion = getUniswapUniversalRouterVersion;
|
|
4933
|
+
exports.getUniswapV4PermissionedHooksOrThrow = getUniswapV4PermissionedHooksOrThrow;
|
|
4934
|
+
exports.getUniswapV4PermissionedPositionManagerOrThrow = getUniswapV4PermissionedPositionManagerOrThrow;
|
|
4935
|
+
exports.getUniswapV4PermissionsAdapterFactoryOrThrow = getUniswapV4PermissionsAdapterFactoryOrThrow;
|
|
4115
4936
|
exports.getUniswapV4PositionManagerDeployBlock = getUniswapV4PositionManagerDeployBlock;
|
|
4116
4937
|
exports.getUniswapV4PositionManagerOrThrow = getUniswapV4PositionManagerOrThrow;
|
|
4117
4938
|
exports.isBitqueryAuthOrRateLimitError = isBitqueryAuthOrRateLimitError;
|
|
@@ -4123,10 +4944,15 @@ exports.isUniswapFullQuoteResponseNativeIn = isUniswapFullQuoteResponseNativeIn;
|
|
|
4123
4944
|
exports.isUniswapFullQuoteResponseNativeOut = isUniswapFullQuoteResponseNativeOut;
|
|
4124
4945
|
exports.isUniswapLimitOrderChainSupported = isUniswapLimitOrderChainSupported;
|
|
4125
4946
|
exports.isUniswapNativeTokenAddress = isUniswapNativeTokenAddress;
|
|
4947
|
+
exports.isUniswapStoredQuotePermissioned = isUniswapStoredQuotePermissioned;
|
|
4126
4948
|
exports.isUniswapTokenInAddressNative = isUniswapTokenInAddressNative;
|
|
4949
|
+
exports.isUniswapV4AnyPositionManager = isUniswapV4AnyPositionManager;
|
|
4127
4950
|
exports.isUniswapV4ChainSupported = isUniswapV4ChainSupported;
|
|
4128
4951
|
exports.isUniswapV4LiquidityEvmSignRequest = isUniswapV4LiquidityEvmSignRequest;
|
|
4952
|
+
exports.isUniswapV4PermissionedAllowlistEvmSignRequest = isUniswapV4PermissionedAllowlistEvmSignRequest;
|
|
4953
|
+
exports.isUniswapV4PermissionedPositionManager = isUniswapV4PermissionedPositionManager;
|
|
4129
4954
|
exports.isUniswapV4SwapEvmSignRequest = isUniswapV4SwapEvmSignRequest;
|
|
4955
|
+
exports.listUniswapV4PermissionedLpPools = listUniswapV4PermissionedLpPools;
|
|
4130
4956
|
exports.listUniswapV4PositionsForWallet = listUniswapV4PositionsForWallet;
|
|
4131
4957
|
exports.listUniswapV4StandardLpPools = listUniswapV4StandardLpPools;
|
|
4132
4958
|
exports.mapBitqueryOhlcvRowsToCandles = mapBitqueryOhlcvRowsToCandles;
|
|
@@ -4137,7 +4963,9 @@ exports.parseUniswapQuoteClassicInOut = parseUniswapQuoteClassicInOut;
|
|
|
4137
4963
|
exports.parseUniswapQuoteSlippageInfo = parseUniswapQuoteSlippageInfo;
|
|
4138
4964
|
exports.parseUniswapV4ScanFromDateYmd = parseUniswapV4ScanFromDateYmd;
|
|
4139
4965
|
exports.permitDataToEip712Payload = permitDataToEip712Payload;
|
|
4966
|
+
exports.pickUniswapV4KycTarget = pickUniswapV4KycTarget;
|
|
4140
4967
|
exports.quoteSwap = quoteSwap;
|
|
4968
|
+
exports.readUniswapV4OnChainPermissionFlags = readUniswapV4OnChainPermissionFlags;
|
|
4141
4969
|
exports.readUniswapV4PositionInfoRaw = readUniswapV4PositionInfoRaw;
|
|
4142
4970
|
exports.requireBitqueryApiKey = requireBitqueryApiKey;
|
|
4143
4971
|
exports.resolveBitqueryApiKey = resolveBitqueryApiKey;
|
|
@@ -4151,6 +4979,8 @@ exports.resolveUniswapV4LpExistingPoolFromKey = resolveUniswapV4LpExistingPoolFr
|
|
|
4151
4979
|
exports.resolveUniswapV4LpPoolPreset = resolveUniswapV4LpPoolPreset;
|
|
4152
4980
|
exports.resolveUniswapV4OhlcvDataTier = resolveUniswapV4OhlcvDataTier;
|
|
4153
4981
|
exports.resolveUniswapV4OhlcvPool = resolveUniswapV4OhlcvPool;
|
|
4982
|
+
exports.resolveUniswapV4PermissionedLpPoolPreset = resolveUniswapV4PermissionedLpPoolPreset;
|
|
4983
|
+
exports.resolveUniswapV4PositionManager = resolveUniswapV4PositionManager;
|
|
4154
4984
|
exports.resolveUniswapV4PositionScanFromDate = resolveUniswapV4PositionScanFromDate;
|
|
4155
4985
|
exports.sortUniswapV4PoolCurrencies = sortUniswapV4PoolCurrencies;
|
|
4156
4986
|
exports.submitUniswapXLimitOrder = submitUniswapXLimitOrder;
|
|
@@ -4159,6 +4989,10 @@ exports.swapFromQuote = swapFromQuote;
|
|
|
4159
4989
|
exports.swapTransactionDeadlineUnixFromExpiryMinutes = swapTransactionDeadlineUnixFromExpiryMinutes;
|
|
4160
4990
|
exports.theGraphApiKeyVariablesHint = theGraphApiKeyVariablesHint;
|
|
4161
4991
|
exports.theGraphRateLimitErrorMessage = theGraphRateLimitErrorMessage;
|
|
4992
|
+
exports.tryGetUniswapUniversalRouterV22 = tryGetUniswapUniversalRouterV22;
|
|
4993
|
+
exports.tryGetUniswapV4PermissionedHooks = tryGetUniswapV4PermissionedHooks;
|
|
4994
|
+
exports.tryGetUniswapV4PermissionedPositionManager = tryGetUniswapV4PermissionedPositionManager;
|
|
4995
|
+
exports.tryGetUniswapV4PermissionsAdapterFactory = tryGetUniswapV4PermissionsAdapterFactory;
|
|
4162
4996
|
exports.tryGetUniswapV4PositionManager = tryGetUniswapV4PositionManager;
|
|
4163
4997
|
exports.uniswapCreateSwap = uniswapCreateSwap;
|
|
4164
4998
|
exports.uniswapFetchLimitOrdersMcp = uniswapFetchLimitOrdersMcp;
|
|
@@ -4171,7 +5005,11 @@ exports.uniswapLpTxFieldForAction = uniswapLpTxFieldForAction;
|
|
|
4171
5005
|
exports.uniswapQuoteToJsonQuoteOneLine = uniswapQuoteToJsonQuoteOneLine;
|
|
4172
5006
|
exports.uniswapTradeQuote = uniswapTradeQuote;
|
|
4173
5007
|
exports.uniswapV4 = uniswapV4;
|
|
5008
|
+
exports.uniswapV4CheckPermissions = uniswapV4CheckPermissions;
|
|
5009
|
+
exports.uniswapV4CheckPermissionsMcp = uniswapV4CheckPermissionsMcp;
|
|
4174
5010
|
exports.uniswapV4FetchOhlcv = uniswapV4FetchOhlcv;
|
|
5011
|
+
exports.uniswapV4KycApplyLinkMcp = uniswapV4KycApplyLinkMcp;
|
|
5012
|
+
exports.uniswapV4ListLpPools = uniswapV4ListLpPools;
|
|
4175
5013
|
exports.uniswapV4ListPositionsForMcp = uniswapV4ListPositionsForMcp;
|
|
4176
5014
|
exports.uniswapV4ListPositionsFromRegistryForMcp = uniswapV4ListPositionsFromRegistryForMcp;
|
|
4177
5015
|
exports.uniswapV4ListPositionsRegistryMcpPlaceholder = uniswapV4ListPositionsRegistryMcpPlaceholder;
|