@continuumdao/ctm-mpc-defi 0.2.20 → 0.2.24
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 +256 -46
- package/dist/agent/catalog.cjs.map +1 -1
- package/dist/agent/catalog.d.ts +606 -154
- package/dist/agent/catalog.js +250 -47
- package/dist/agent/catalog.js.map +1 -1
- package/dist/agent/skills/gmx/SKILL.md +30 -0
- package/dist/agent/skills/hyperliquid/SKILL.md +32 -0
- package/dist/agent/skills/uniswap-v4/SKILL.md +83 -0
- package/dist/chains/evm/index.cjs +5 -1
- package/dist/chains/evm/index.cjs.map +1 -1
- package/dist/chains/evm/index.d.ts +4 -4
- package/dist/chains/evm/index.js +5 -1
- package/dist/chains/evm/index.js.map +1 -1
- package/dist/chains/near/index.d.ts +1 -1
- package/dist/chains/solana/index.d.ts +1 -1
- package/dist/core/index.cjs +25 -0
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.ts +11 -36
- package/dist/core/index.js +23 -1
- package/dist/core/index.js.map +1 -1
- package/dist/eip712Multisign-xhXpUYp3.d.ts +36 -0
- package/dist/{envelope-CpBUh9eP.d.ts → envelope-C_bfuKab.d.ts} +3 -1
- package/dist/index.cjs +371 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.js +369 -14
- package/dist/index.js.map +1 -1
- package/dist/protocols/evm/aave-v4/index.cjs +5 -1
- package/dist/protocols/evm/aave-v4/index.cjs.map +1 -1
- package/dist/protocols/evm/aave-v4/index.d.ts +1 -1
- package/dist/protocols/evm/aave-v4/index.js +5 -1
- package/dist/protocols/evm/aave-v4/index.js.map +1 -1
- package/dist/protocols/evm/circle-cctp/index.cjs +5 -1
- package/dist/protocols/evm/circle-cctp/index.cjs.map +1 -1
- package/dist/protocols/evm/circle-cctp/index.d.ts +2 -2
- package/dist/protocols/evm/circle-cctp/index.js +5 -1
- package/dist/protocols/evm/circle-cctp/index.js.map +1 -1
- package/dist/protocols/evm/curve-dao/index.cjs +5 -1
- package/dist/protocols/evm/curve-dao/index.cjs.map +1 -1
- package/dist/protocols/evm/curve-dao/index.d.ts +2 -2
- package/dist/protocols/evm/curve-dao/index.js +5 -1
- package/dist/protocols/evm/curve-dao/index.js.map +1 -1
- package/dist/protocols/evm/ethena/index.cjs +5 -1
- package/dist/protocols/evm/ethena/index.cjs.map +1 -1
- package/dist/protocols/evm/ethena/index.d.ts +1 -1
- package/dist/protocols/evm/ethena/index.js +5 -1
- package/dist/protocols/evm/ethena/index.js.map +1 -1
- package/dist/protocols/evm/euler-v2/index.cjs +5 -1
- package/dist/protocols/evm/euler-v2/index.cjs.map +1 -1
- package/dist/protocols/evm/euler-v2/index.d.ts +1 -1
- package/dist/protocols/evm/euler-v2/index.js +5 -1
- package/dist/protocols/evm/euler-v2/index.js.map +1 -1
- package/dist/protocols/evm/gmx/index.cjs +44 -1
- package/dist/protocols/evm/gmx/index.cjs.map +1 -1
- package/dist/protocols/evm/gmx/index.d.ts +23 -3
- package/dist/protocols/evm/gmx/index.js +43 -2
- package/dist/protocols/evm/gmx/index.js.map +1 -1
- package/dist/protocols/evm/hyperliquid/index.cjs +483 -208
- package/dist/protocols/evm/hyperliquid/index.cjs.map +1 -1
- package/dist/protocols/evm/hyperliquid/index.d.ts +168 -53
- package/dist/protocols/evm/hyperliquid/index.js +472 -210
- package/dist/protocols/evm/hyperliquid/index.js.map +1 -1
- package/dist/protocols/evm/lido/index.cjs +5 -1
- package/dist/protocols/evm/lido/index.cjs.map +1 -1
- package/dist/protocols/evm/lido/index.d.ts +1 -1
- package/dist/protocols/evm/lido/index.js +5 -1
- package/dist/protocols/evm/lido/index.js.map +1 -1
- package/dist/protocols/evm/maple/index.cjs +5 -1
- package/dist/protocols/evm/maple/index.cjs.map +1 -1
- package/dist/protocols/evm/maple/index.d.ts +1 -1
- package/dist/protocols/evm/maple/index.js +5 -1
- package/dist/protocols/evm/maple/index.js.map +1 -1
- package/dist/protocols/evm/morpho/index.cjs +5 -1
- package/dist/protocols/evm/morpho/index.cjs.map +1 -1
- package/dist/protocols/evm/morpho/index.d.ts +1 -1
- package/dist/protocols/evm/morpho/index.js +5 -1
- package/dist/protocols/evm/morpho/index.js.map +1 -1
- package/dist/protocols/evm/permit2/index.cjs +4 -0
- package/dist/protocols/evm/permit2/index.cjs.map +1 -1
- package/dist/protocols/evm/permit2/index.d.ts +1 -1
- package/dist/protocols/evm/permit2/index.js +4 -0
- package/dist/protocols/evm/permit2/index.js.map +1 -1
- package/dist/protocols/evm/sky/index.cjs +5 -1
- package/dist/protocols/evm/sky/index.cjs.map +1 -1
- package/dist/protocols/evm/sky/index.d.ts +1 -1
- package/dist/protocols/evm/sky/index.js +5 -1
- package/dist/protocols/evm/sky/index.js.map +1 -1
- package/dist/protocols/evm/uniswap-v4/index.cjs +1415 -13
- package/dist/protocols/evm/uniswap-v4/index.cjs.map +1 -1
- package/dist/protocols/evm/uniswap-v4/index.d.ts +353 -4
- package/dist/protocols/evm/uniswap-v4/index.js +1357 -15
- package/dist/protocols/evm/uniswap-v4/index.js.map +1 -1
- package/dist/{registry-Bv5o37_w.d.ts → registry-DxDSPQ-p.d.ts} +1 -1
- package/dist/{types-BfjWdw1j.d.ts → types-PZrvtjv8.d.ts} +2 -0
- package/dist/{types-DUeNJLr9.d.ts → types-RZWOTm8c.d.ts} +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -61,6 +61,9 @@ function finalizeMultisign(input) {
|
|
|
61
61
|
bodyForSign.value = valueWei.toString();
|
|
62
62
|
}
|
|
63
63
|
if (clientId) bodyForSign.clientId = clientId;
|
|
64
|
+
if (input.expiryDate != null && input.expiryDate > 0) {
|
|
65
|
+
bodyForSign.expiryDate = Math.floor(input.expiryDate);
|
|
66
|
+
}
|
|
64
67
|
return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
|
|
65
68
|
}
|
|
66
69
|
var coreChainCategoryModule = {
|
|
@@ -198,6 +201,7 @@ function buildEip712MultisignBody(args) {
|
|
|
198
201
|
destinationChainID: args.destinationChainID,
|
|
199
202
|
destinationAddress: args.destinationAddress,
|
|
200
203
|
extraJSON,
|
|
204
|
+
expiryDate: args.expiryDate,
|
|
201
205
|
legs: [
|
|
202
206
|
{
|
|
203
207
|
msgHash: msgHashNo0x(digest),
|
|
@@ -215,6 +219,24 @@ function buildEip712MultisignBody(args) {
|
|
|
215
219
|
]
|
|
216
220
|
});
|
|
217
221
|
}
|
|
222
|
+
|
|
223
|
+
// src/core/expiry.ts
|
|
224
|
+
var DEFAULT_DEFI_MULTISIGN_EXPIRY_SECONDS = 30 * 60;
|
|
225
|
+
var DEFI_PROTOCOLS_WITH_30MIN_EXPIRY = /* @__PURE__ */ new Set([
|
|
226
|
+
"uniswap-v4",
|
|
227
|
+
"gmx",
|
|
228
|
+
"hyperliquid",
|
|
229
|
+
"curve-dao"
|
|
230
|
+
]);
|
|
231
|
+
function defiMultisignExpiryUnixSeconds(protocolId, explicitExpiryDate) {
|
|
232
|
+
if (typeof explicitExpiryDate === "number" && Number.isFinite(explicitExpiryDate) && explicitExpiryDate > 0) {
|
|
233
|
+
return Math.floor(explicitExpiryDate);
|
|
234
|
+
}
|
|
235
|
+
if (protocolId && DEFI_PROTOCOLS_WITH_30MIN_EXPIRY.has(protocolId)) {
|
|
236
|
+
return Math.floor(Date.now() / 1e3) + DEFAULT_DEFI_MULTISIGN_EXPIRY_SECONDS;
|
|
237
|
+
}
|
|
238
|
+
return void 0;
|
|
239
|
+
}
|
|
218
240
|
function isEvmNativeToken(address) {
|
|
219
241
|
try {
|
|
220
242
|
return viem.getAddress(address) === viem.zeroAddress;
|
|
@@ -390,7 +412,8 @@ async function buildEvmMultisignBatch(args) {
|
|
|
390
412
|
destinationChainID: String(chainId),
|
|
391
413
|
destinationAddress: args.destinationAddress ?? steps[0].to,
|
|
392
414
|
legs,
|
|
393
|
-
extraJSON: Object.keys(extraJSON).length > 0 ? extraJSON : void 0
|
|
415
|
+
extraJSON: Object.keys(extraJSON).length > 0 ? extraJSON : void 0,
|
|
416
|
+
expiryDate: context.expiryDate
|
|
394
417
|
});
|
|
395
418
|
const pv = args.payableValueWei;
|
|
396
419
|
if (pv != null && pv > 0n) {
|
|
@@ -593,8 +616,18 @@ var UNIVERSAL_ROUTER_SPENDER = {
|
|
|
593
616
|
143: "0x0d97dc33264bfc1c226207428a79b26757fb9dc3",
|
|
594
617
|
59144: "0x661e93cca42afacb172121ef892830ca3b70f08d",
|
|
595
618
|
4217: "0x1febb76be10aaf3a1402f04e8e835f2c382f7914",
|
|
596
|
-
196: "0x5507749f2c558bb3e162c6e90c314c092e7372ff"
|
|
619
|
+
196: "0x5507749f2c558bb3e162c6e90c314c092e7372ff",
|
|
620
|
+
/** Robinhood Chain mainnet — Universal Router v2.1.1 (Trade API / interface) */
|
|
621
|
+
4663: "0x8876789976decbfcbbbe364623c63652db8c0904"
|
|
622
|
+
};
|
|
623
|
+
var UNIVERSAL_ROUTER_VERSION_BY_CHAIN = {
|
|
624
|
+
/** Robinhood has UR 2.1.1 only in the supported-chains table (no 2.0 Trade API column). */
|
|
625
|
+
4663: "2.1.1"
|
|
597
626
|
};
|
|
627
|
+
function getUniswapUniversalRouterVersion(chainId) {
|
|
628
|
+
const v = UNIVERSAL_ROUTER_VERSION_BY_CHAIN[chainId];
|
|
629
|
+
return typeof v === "string" && v.trim() ? v.trim() : UNISWAP_UNIVERSAL_ROUTER_VERSION_DEFAULT;
|
|
630
|
+
}
|
|
598
631
|
function isUniswapV4ChainSupported(chainId) {
|
|
599
632
|
if (chainId == null) return false;
|
|
600
633
|
const n = parseEvmChainIdToNumber(chainId);
|
|
@@ -629,7 +662,9 @@ var POSITION_MANAGER_BY_CHAIN = {
|
|
|
629
662
|
11155111: "0x4B2C77d209D3405F41a037Ec6c77F7F5b8e2ca80",
|
|
630
663
|
130: "0x0d97dc33264bfc1c226207428a79b26757fb9dc3",
|
|
631
664
|
1868: "0x0e2850543f69f678257266e0907ff9a58b3f13de",
|
|
632
|
-
59144: "0x661e93cca42afacb172121ef892830ca3b70f08d"
|
|
665
|
+
59144: "0x661e93cca42afacb172121ef892830ca3b70f08d",
|
|
666
|
+
/** Robinhood Chain mainnet */
|
|
667
|
+
4663: "0x58daec3116aae6D93017bAAea7749052E8a04fA7"
|
|
633
668
|
};
|
|
634
669
|
function getUniswapV4PositionManagerOrThrow(chainId) {
|
|
635
670
|
const raw = POSITION_MANAGER_BY_CHAIN[chainId];
|
|
@@ -676,8 +711,8 @@ function parseUniswapChainId(value) {
|
|
|
676
711
|
function trimAddr(a) {
|
|
677
712
|
return a.trim();
|
|
678
713
|
}
|
|
679
|
-
function
|
|
680
|
-
const t = (
|
|
714
|
+
function isUniswapNativeTokenAddress(token) {
|
|
715
|
+
const t = (token ?? "").toString().trim();
|
|
681
716
|
if (!t) return false;
|
|
682
717
|
try {
|
|
683
718
|
return viem.getAddress(t) === viem.zeroAddress;
|
|
@@ -692,7 +727,16 @@ function isUniswapFullQuoteResponseNativeIn(stored) {
|
|
|
692
727
|
const input = q.input;
|
|
693
728
|
if (!input) return false;
|
|
694
729
|
const raw = (input.address ?? input.token ?? "").toString().trim();
|
|
695
|
-
return
|
|
730
|
+
return isUniswapNativeTokenAddress(raw);
|
|
731
|
+
}
|
|
732
|
+
function isUniswapFullQuoteResponseNativeOut(stored) {
|
|
733
|
+
if (!stored) return false;
|
|
734
|
+
const q = stored.quote;
|
|
735
|
+
if (!q || typeof q !== "object" || Array.isArray(q)) return false;
|
|
736
|
+
const output = q.output;
|
|
737
|
+
if (!output) return false;
|
|
738
|
+
const raw = (output.address ?? output.token ?? "").toString().trim();
|
|
739
|
+
return isUniswapNativeTokenAddress(raw);
|
|
696
740
|
}
|
|
697
741
|
async function fetchEthereumAddressForKeyGen(managementNodeUrl, keyGenId, readAuth = { bearerOnGet: true, jwt: null }, init) {
|
|
698
742
|
const base = managementNodeUrl.trim().replace(/\/$/, "");
|
|
@@ -754,6 +798,31 @@ function buildUniswapQuoteRequestBody(args) {
|
|
|
754
798
|
}
|
|
755
799
|
return body;
|
|
756
800
|
}
|
|
801
|
+
function resolveChainIdFromStoredUniswapQuote(stored) {
|
|
802
|
+
if (!stored) return 0;
|
|
803
|
+
const top = stored;
|
|
804
|
+
for (const key of ["tokenInChainId", "chainId"]) {
|
|
805
|
+
const raw = top[key];
|
|
806
|
+
if (raw != null && String(raw).trim() !== "") {
|
|
807
|
+
try {
|
|
808
|
+
return parseUniswapChainId(raw);
|
|
809
|
+
} catch {
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
const q = top.quote;
|
|
814
|
+
if (q && typeof q === "object" && !Array.isArray(q)) {
|
|
815
|
+
const input = q.input;
|
|
816
|
+
const chain = input?.chainId;
|
|
817
|
+
if (chain != null && String(chain).trim() !== "") {
|
|
818
|
+
try {
|
|
819
|
+
return parseUniswapChainId(chain);
|
|
820
|
+
} catch {
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
return 0;
|
|
825
|
+
}
|
|
757
826
|
function errorMessageFromUniswapJsonBody(value) {
|
|
758
827
|
if (value == null) return null;
|
|
759
828
|
if (typeof value === "string") {
|
|
@@ -866,16 +935,18 @@ async function uniswapTradeQuote(args) {
|
|
|
866
935
|
}
|
|
867
936
|
const base = args.baseUrl && args.baseUrl.trim() ? args.baseUrl.trim().replace(/\/$/, "") : DEFAULT_TRADE_BASE;
|
|
868
937
|
const quoteUrl = `${base}/quote`;
|
|
869
|
-
const
|
|
938
|
+
const chainIdForRouter = parseUniswapChainId(resolveInputChainId(args));
|
|
939
|
+
const urv = args.universalRouterVersion && args.universalRouterVersion.trim() || getUniswapUniversalRouterVersion(chainIdForRouter);
|
|
870
940
|
const body = buildUniswapQuoteRequestBody({ ...args, swapper });
|
|
871
|
-
const nativeIn =
|
|
941
|
+
const nativeIn = isUniswapNativeTokenAddress(args.tokenIn);
|
|
942
|
+
const nativeOut = isUniswapNativeTokenAddress(args.tokenOut);
|
|
872
943
|
const headers = {
|
|
873
944
|
...UNISWAP_QUOTE_HEADERS_BASE,
|
|
874
945
|
"x-api-key": apiKey,
|
|
875
946
|
"x-universal-router-version": urv,
|
|
876
947
|
"x-permit2-disabled": args.permit2Disabled === true ? "true" : "false",
|
|
877
|
-
/** Native (0x0)
|
|
878
|
-
"x-erc20eth-enabled": nativeIn ? "true" : "false"
|
|
948
|
+
/** Native (0x0) in or out: enables ERC20↔ETH routes (incl. UniswapX on Robinhood). */
|
|
949
|
+
"x-erc20eth-enabled": nativeIn || nativeOut ? "true" : "false"
|
|
879
950
|
};
|
|
880
951
|
const fetchFn = args.fetchImpl ?? globalThis.fetch;
|
|
881
952
|
const res = await fetchFn(quoteUrl, {
|
|
@@ -886,7 +957,11 @@ async function uniswapTradeQuote(args) {
|
|
|
886
957
|
});
|
|
887
958
|
const text = await res.text();
|
|
888
959
|
if (!res.ok) {
|
|
889
|
-
|
|
960
|
+
let msg = messageFromUniswapHttpResponseBody(text, res.status, res.statusText);
|
|
961
|
+
if (res.status === 404 && chainIdForRouter === 4663) {
|
|
962
|
+
msg += " On Robinhood Chain, confirm USDG is 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168, use Native ETH or WETH (0x0Bd7\u2026) as output, and try at least ~$300 notional (UniswapX minimum).";
|
|
963
|
+
}
|
|
964
|
+
throw new Error(msg);
|
|
890
965
|
}
|
|
891
966
|
const forParse = text.replace(/^\uFEFF/, "");
|
|
892
967
|
try {
|
|
@@ -993,16 +1068,17 @@ async function uniswapCreateSwap(args) {
|
|
|
993
1068
|
quote: classic,
|
|
994
1069
|
deadline
|
|
995
1070
|
};
|
|
996
|
-
const urv = (args.universalRouterVersion ??
|
|
1071
|
+
const urv = (args.universalRouterVersion ?? "").trim() || getUniswapUniversalRouterVersion(resolveChainIdFromStoredUniswapQuote(args.fullQuoteFromPermit));
|
|
997
1072
|
const fn = args.fetchImpl ?? globalThis.fetch;
|
|
998
1073
|
const nativeIn = isUniswapFullQuoteResponseNativeIn(args.fullQuoteFromPermit);
|
|
1074
|
+
const nativeOut = isUniswapFullQuoteResponseNativeOut(args.fullQuoteFromPermit);
|
|
999
1075
|
const res = await fn(url, {
|
|
1000
1076
|
method: "POST",
|
|
1001
1077
|
headers: {
|
|
1002
1078
|
"Content-Type": "application/json",
|
|
1003
1079
|
"x-api-key": args.uniswapApiKey.trim(),
|
|
1004
1080
|
"x-universal-router-version": urv,
|
|
1005
|
-
"x-erc20eth-enabled": nativeIn ? "true" : "false",
|
|
1081
|
+
"x-erc20eth-enabled": nativeIn || nativeOut ? "true" : "false",
|
|
1006
1082
|
"x-permit2-disabled": "true"
|
|
1007
1083
|
},
|
|
1008
1084
|
body: JSON.stringify(body)
|
|
@@ -2202,6 +2278,270 @@ async function swapExactInput(args) {
|
|
|
2202
2278
|
return swapFromQuote({ ...args, swap });
|
|
2203
2279
|
}
|
|
2204
2280
|
|
|
2281
|
+
// src/protocols/evm/uniswap-v4/limitOrder.ts
|
|
2282
|
+
function trimAddr3(a) {
|
|
2283
|
+
return a.trim();
|
|
2284
|
+
}
|
|
2285
|
+
var UNISWAP_LIMIT_ORDER_CHAIN_ID = 1;
|
|
2286
|
+
var DEFAULT_UNISWAPX_ORDER_BASE = "https://api.uniswap.org/v2";
|
|
2287
|
+
var DEFAULT_LIMIT_ORDER_QUOTE_PATH = "/limit_order_quote";
|
|
2288
|
+
var UNISWAP_QUOTE_HEADERS_BASE2 = {
|
|
2289
|
+
"Content-Type": "application/json",
|
|
2290
|
+
"User-Agent": "ctm-mpc-defi uniswapLimitOrderQuote/1.0 (TS)"
|
|
2291
|
+
};
|
|
2292
|
+
function isUniswapLimitOrderChainSupported(chainId) {
|
|
2293
|
+
return parseUniswapChainId(chainId) === UNISWAP_LIMIT_ORDER_CHAIN_ID;
|
|
2294
|
+
}
|
|
2295
|
+
function assertUniswapLimitOrderChain(chainId) {
|
|
2296
|
+
if (!isUniswapLimitOrderChainSupported(chainId)) {
|
|
2297
|
+
throw new Error(
|
|
2298
|
+
`UniswapX limit orders are only supported on Ethereum mainnet (chainId ${UNISWAP_LIMIT_ORDER_CHAIN_ID}). Got ${chainId}. Use market swap on this chain or wait for UniswapX limit support.`
|
|
2299
|
+
);
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
function inferPrimaryTypeFromPermitTypes(types) {
|
|
2303
|
+
for (const key of Object.keys(types)) {
|
|
2304
|
+
if (key !== "EIP712Domain") {
|
|
2305
|
+
return key;
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
throw new Error("permitData.types missing primaryType (no non-EIP712Domain entry)");
|
|
2309
|
+
}
|
|
2310
|
+
function permitDataToEip712Payload(permitData) {
|
|
2311
|
+
const domain = permitData.domain;
|
|
2312
|
+
const types = permitData.types;
|
|
2313
|
+
const message = permitData.values ?? permitData.message;
|
|
2314
|
+
if (domain == null || typeof domain !== "object" || Array.isArray(domain)) {
|
|
2315
|
+
throw new Error("limit order quote: permitData.domain missing");
|
|
2316
|
+
}
|
|
2317
|
+
if (types == null || typeof types !== "object" || Array.isArray(types)) {
|
|
2318
|
+
throw new Error("limit order quote: permitData.types missing");
|
|
2319
|
+
}
|
|
2320
|
+
if (message == null || typeof message !== "object" || Array.isArray(message)) {
|
|
2321
|
+
throw new Error("limit order quote: permitData.values (message) missing");
|
|
2322
|
+
}
|
|
2323
|
+
const primaryType = typeof permitData.primaryType === "string" && permitData.primaryType.trim() ? permitData.primaryType.trim() : inferPrimaryTypeFromPermitTypes(
|
|
2324
|
+
types
|
|
2325
|
+
);
|
|
2326
|
+
return {
|
|
2327
|
+
domain,
|
|
2328
|
+
types,
|
|
2329
|
+
primaryType,
|
|
2330
|
+
message
|
|
2331
|
+
};
|
|
2332
|
+
}
|
|
2333
|
+
function extractPermitDataFromLimitQuote(quoteResponse) {
|
|
2334
|
+
const permitData = quoteResponse.permitData;
|
|
2335
|
+
if (permitData == null) return null;
|
|
2336
|
+
if (typeof permitData !== "object" || Array.isArray(permitData)) {
|
|
2337
|
+
throw new Error("limit order quote: permitData is not an object");
|
|
2338
|
+
}
|
|
2339
|
+
return permitData;
|
|
2340
|
+
}
|
|
2341
|
+
function buildLimitOrderQuoteRequestBody(args) {
|
|
2342
|
+
const base = buildUniswapQuoteRequestBody({
|
|
2343
|
+
type: args.type,
|
|
2344
|
+
amount: args.amount,
|
|
2345
|
+
tokenIn: args.tokenIn,
|
|
2346
|
+
tokenOut: args.tokenOut,
|
|
2347
|
+
chainId: args.chainId,
|
|
2348
|
+
tokenInChainId: args.tokenInChainId,
|
|
2349
|
+
tokenOutChainId: args.tokenOutChainId,
|
|
2350
|
+
swapper: args.swapper
|
|
2351
|
+
});
|
|
2352
|
+
assertUniswapLimitOrderChain(base.tokenInChainId);
|
|
2353
|
+
return {
|
|
2354
|
+
...base,
|
|
2355
|
+
limitPrice: String(args.limitPrice).trim(),
|
|
2356
|
+
orderDeadline: args.orderDeadline
|
|
2357
|
+
};
|
|
2358
|
+
}
|
|
2359
|
+
async function uniswapLimitOrderQuote(args) {
|
|
2360
|
+
const apiKey = (args.uniswapApiKey || "").trim();
|
|
2361
|
+
if (!apiKey) {
|
|
2362
|
+
throw new Error("uniswapApiKey (x-api-key) is required");
|
|
2363
|
+
}
|
|
2364
|
+
let swapper;
|
|
2365
|
+
if ((args.swapper || "").trim()) {
|
|
2366
|
+
swapper = trimAddr3(args.swapper);
|
|
2367
|
+
} else {
|
|
2368
|
+
const keyGen = (args.keyGen || "").trim();
|
|
2369
|
+
if (!keyGen) {
|
|
2370
|
+
throw new Error("keyGen is required when swapper is not provided");
|
|
2371
|
+
}
|
|
2372
|
+
const mpc = (args.managementNodeUrl || "").trim();
|
|
2373
|
+
if (!mpc) {
|
|
2374
|
+
throw new Error("managementNodeUrl is required when swapper is not provided (to resolve keyGen)");
|
|
2375
|
+
}
|
|
2376
|
+
swapper = await fetchEthereumAddressForKeyGen(
|
|
2377
|
+
mpc,
|
|
2378
|
+
keyGen,
|
|
2379
|
+
args.nodeReadAuth ?? { bearerOnGet: true, jwt: null }
|
|
2380
|
+
);
|
|
2381
|
+
}
|
|
2382
|
+
const chainIdForGuard = parseUniswapChainId(resolveInputChainId(args));
|
|
2383
|
+
assertUniswapLimitOrderChain(chainIdForGuard);
|
|
2384
|
+
const base = args.baseUrl && args.baseUrl.trim() ? args.baseUrl.trim().replace(/\/$/, "") : "https://trade-api.gateway.uniswap.org/v1";
|
|
2385
|
+
const quoteUrl = `${base}${DEFAULT_LIMIT_ORDER_QUOTE_PATH}`;
|
|
2386
|
+
const body = buildLimitOrderQuoteRequestBody({ ...args, swapper });
|
|
2387
|
+
const headers = {
|
|
2388
|
+
...UNISWAP_QUOTE_HEADERS_BASE2,
|
|
2389
|
+
"x-api-key": apiKey
|
|
2390
|
+
};
|
|
2391
|
+
const fetchFn = args.fetchImpl ?? globalThis.fetch;
|
|
2392
|
+
const res = await fetchFn(quoteUrl, {
|
|
2393
|
+
method: "POST",
|
|
2394
|
+
headers,
|
|
2395
|
+
body: JSON.stringify(body),
|
|
2396
|
+
signal: args.signal
|
|
2397
|
+
});
|
|
2398
|
+
const text = await res.text();
|
|
2399
|
+
if (!res.ok) {
|
|
2400
|
+
throw new Error(messageFromUniswapHttpResponseBody(text, res.status, res.statusText));
|
|
2401
|
+
}
|
|
2402
|
+
const forParse = text.replace(/^\uFEFF/, "");
|
|
2403
|
+
try {
|
|
2404
|
+
return JSON.parse(forParse);
|
|
2405
|
+
} catch {
|
|
2406
|
+
throw new Error(
|
|
2407
|
+
`Limit order quote: ${messageFromUniswapHttpResponseBody(text, res.status, res.statusText)}`
|
|
2408
|
+
);
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
function buildUniswapXLimitOrderSubmitBody(args) {
|
|
2412
|
+
const quote = args.quoteResponse.quote;
|
|
2413
|
+
if (quote == null || typeof quote !== "object" || Array.isArray(quote)) {
|
|
2414
|
+
throw new Error("limit order submit: quoteResponse.quote missing");
|
|
2415
|
+
}
|
|
2416
|
+
const routing = typeof args.quoteResponse.routing === "string" && args.quoteResponse.routing.trim() ? args.quoteResponse.routing.trim() : "LIMIT_ORDER";
|
|
2417
|
+
const chainId = args.quoteResponse.chainId ?? quote.chainId ?? UNISWAP_LIMIT_ORDER_CHAIN_ID;
|
|
2418
|
+
const quoteId = typeof args.quoteResponse.quoteId === "string" ? args.quoteResponse.quoteId : void 0;
|
|
2419
|
+
const requestId = typeof args.quoteResponse.requestId === "string" ? args.quoteResponse.requestId : void 0;
|
|
2420
|
+
return {
|
|
2421
|
+
signature: args.signatureHex.startsWith("0x") ? args.signatureHex : `0x${args.signatureHex}`,
|
|
2422
|
+
quote,
|
|
2423
|
+
chainId: parseUniswapChainId(chainId),
|
|
2424
|
+
orderType: "Limit",
|
|
2425
|
+
routing,
|
|
2426
|
+
...quoteId ? { quoteId } : {},
|
|
2427
|
+
...requestId ? { requestId } : {}
|
|
2428
|
+
};
|
|
2429
|
+
}
|
|
2430
|
+
async function fetchUniswapXLimitOrders(args) {
|
|
2431
|
+
const chainId = args.chainId ?? UNISWAP_LIMIT_ORDER_CHAIN_ID;
|
|
2432
|
+
assertUniswapLimitOrderChain(chainId);
|
|
2433
|
+
const base = args.baseUrl && args.baseUrl.trim() ? args.baseUrl.trim().replace(/\/$/, "") : DEFAULT_UNISWAPX_ORDER_BASE;
|
|
2434
|
+
const params = new URLSearchParams({
|
|
2435
|
+
chainId: String(chainId),
|
|
2436
|
+
swapper: trimAddr3(args.swapper)
|
|
2437
|
+
});
|
|
2438
|
+
if (args.limit != null && args.limit > 0) {
|
|
2439
|
+
params.set("limit", String(Math.floor(args.limit)));
|
|
2440
|
+
}
|
|
2441
|
+
const url = `${base}/limit-orders?${params.toString()}`;
|
|
2442
|
+
const headers = {
|
|
2443
|
+
Accept: "application/json",
|
|
2444
|
+
"User-Agent": "ctm-mpc-defi uniswapLimitOrdersList/1.0 (TS)"
|
|
2445
|
+
};
|
|
2446
|
+
const apiKey = (args.uniswapApiKey || "").trim();
|
|
2447
|
+
if (apiKey) {
|
|
2448
|
+
headers["x-api-key"] = apiKey;
|
|
2449
|
+
}
|
|
2450
|
+
const fetchFn = args.fetchImpl ?? globalThis.fetch;
|
|
2451
|
+
const res = await fetchFn(url, { method: "GET", headers });
|
|
2452
|
+
const text = await res.text();
|
|
2453
|
+
if (!res.ok) {
|
|
2454
|
+
const parsed = (() => {
|
|
2455
|
+
try {
|
|
2456
|
+
return JSON.parse(text);
|
|
2457
|
+
} catch {
|
|
2458
|
+
return null;
|
|
2459
|
+
}
|
|
2460
|
+
})();
|
|
2461
|
+
const msg = errorMessageFromUniswapJsonBody(parsed) ?? (text.trim() || res.statusText);
|
|
2462
|
+
throw new Error(`List limit orders HTTP ${res.status}: ${msg}`);
|
|
2463
|
+
}
|
|
2464
|
+
return JSON.parse(text.replace(/^\uFEFF/, ""));
|
|
2465
|
+
}
|
|
2466
|
+
async function uniswapFetchLimitOrdersMcp(args) {
|
|
2467
|
+
let swapper;
|
|
2468
|
+
if ((args.swapper || "").trim()) {
|
|
2469
|
+
swapper = trimAddr3(args.swapper);
|
|
2470
|
+
} else {
|
|
2471
|
+
const keyGen = (args.keyGen || "").trim();
|
|
2472
|
+
if (!keyGen) {
|
|
2473
|
+
throw new Error("swapper or keyGen is required");
|
|
2474
|
+
}
|
|
2475
|
+
const mpc = (args.managementNodeUrl || "").trim();
|
|
2476
|
+
if (!mpc) {
|
|
2477
|
+
throw new Error("managementNodeUrl is required when swapper is not provided");
|
|
2478
|
+
}
|
|
2479
|
+
swapper = await fetchEthereumAddressForKeyGen(
|
|
2480
|
+
mpc,
|
|
2481
|
+
keyGen,
|
|
2482
|
+
args.nodeReadAuth ?? { bearerOnGet: true, jwt: null }
|
|
2483
|
+
);
|
|
2484
|
+
}
|
|
2485
|
+
return fetchUniswapXLimitOrders({
|
|
2486
|
+
swapper,
|
|
2487
|
+
chainId: args.chainId,
|
|
2488
|
+
uniswapApiKey: args.uniswapApiKey,
|
|
2489
|
+
limit: args.limit,
|
|
2490
|
+
baseUrl: args.baseUrl,
|
|
2491
|
+
fetchImpl: args.fetchImpl
|
|
2492
|
+
});
|
|
2493
|
+
}
|
|
2494
|
+
async function buildEvmMultisignBodyUniswapV4LimitOrderBatch(args) {
|
|
2495
|
+
assertUniswapLimitOrderChain(args.chainId);
|
|
2496
|
+
const permitRaw = extractPermitDataFromLimitQuote(args.fullLimitQuote);
|
|
2497
|
+
if (!permitRaw) {
|
|
2498
|
+
throw new Error(
|
|
2499
|
+
"Limit order quote has no permitData \u2014 cannot build EIP-712 sign request. Re-quote or confirm mainnet limit order support for this pair."
|
|
2500
|
+
);
|
|
2501
|
+
}
|
|
2502
|
+
const typedData = permitDataToEip712Payload(permitRaw);
|
|
2503
|
+
const submitTemplate = buildUniswapXLimitOrderSubmitBody({
|
|
2504
|
+
quoteResponse: args.fullLimitQuote,
|
|
2505
|
+
signatureHex: "0x"
|
|
2506
|
+
});
|
|
2507
|
+
return buildEip712MultisignBody({
|
|
2508
|
+
keyGen: args.keyGen,
|
|
2509
|
+
purposeText: args.purposeText,
|
|
2510
|
+
destinationChainID: String(UNISWAP_LIMIT_ORDER_CHAIN_ID),
|
|
2511
|
+
destinationAddress: PERMIT2_ADDRESS,
|
|
2512
|
+
typedData,
|
|
2513
|
+
delivery: {
|
|
2514
|
+
kind: "uniswapx_limit_order",
|
|
2515
|
+
chainId: UNISWAP_LIMIT_ORDER_CHAIN_ID,
|
|
2516
|
+
swapper: viem.getAddress(args.swapper),
|
|
2517
|
+
submitBodyTemplate: submitTemplate,
|
|
2518
|
+
quoteResponse: args.fullLimitQuote,
|
|
2519
|
+
uniswapApiKey: args.uniswapApiKey,
|
|
2520
|
+
tradeApiBaseUrl: args.tradeApiBaseUrl ?? "https://trade-api.gateway.uniswap.org/v1"
|
|
2521
|
+
},
|
|
2522
|
+
audit: {
|
|
2523
|
+
protocol: "uniswap-v4",
|
|
2524
|
+
action: "limitOrder",
|
|
2525
|
+
routing: args.fullLimitQuote.routing ?? "LIMIT_ORDER",
|
|
2526
|
+
orderType: "Limit",
|
|
2527
|
+
primaryType: typedData.primaryType
|
|
2528
|
+
},
|
|
2529
|
+
expiryDate: args.expiryDate
|
|
2530
|
+
});
|
|
2531
|
+
}
|
|
2532
|
+
async function buildEvmMultisignBodyUniswapV4LimitOrderBatchFromMcp(args) {
|
|
2533
|
+
return buildEvmMultisignBodyUniswapV4LimitOrderBatch({
|
|
2534
|
+
keyGen: args.keyGen,
|
|
2535
|
+
chainId: args.chainId,
|
|
2536
|
+
purposeText: args.purposeText,
|
|
2537
|
+
fullLimitQuote: args.fullLimitQuote,
|
|
2538
|
+
swapper: viem.getAddress(args.executorAddress),
|
|
2539
|
+
uniswapApiKey: args.uniswapApiKey,
|
|
2540
|
+
tradeApiBaseUrl: args.tradeApiBaseUrl,
|
|
2541
|
+
expiryDate: args.expiryDate
|
|
2542
|
+
});
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2205
2545
|
// src/protocols/evm/uniswap-v4/index.ts
|
|
2206
2546
|
var UNISWAP_V4_PROTOCOL_ID = "uniswap-v4";
|
|
2207
2547
|
var uniswapV4ProtocolModule = {
|
|
@@ -2248,6 +2588,17 @@ var uniswapV4ProtocolModule = {
|
|
|
2248
2588
|
type: { type: "EXACT_INPUT | EXACT_OUTPUT", required: true, description: "Trade type" }
|
|
2249
2589
|
}
|
|
2250
2590
|
},
|
|
2591
|
+
{
|
|
2592
|
+
id: "uniswap-v4.limit-order",
|
|
2593
|
+
protocolId: UNISWAP_V4_PROTOCOL_ID,
|
|
2594
|
+
chainCategory: "evm",
|
|
2595
|
+
description: "Place UniswapX limit order via EIP-712 sign + POST /order (Ethereum mainnet only)",
|
|
2596
|
+
commonParams: ["keyGen", "purposeText"],
|
|
2597
|
+
params: {
|
|
2598
|
+
fullLimitQuote: { type: "object", required: true, description: "Full limit order quote from Trade API" },
|
|
2599
|
+
uniswapApiKey: { type: "string", required: true, description: "Uniswap Trade API key" }
|
|
2600
|
+
}
|
|
2601
|
+
},
|
|
2251
2602
|
{
|
|
2252
2603
|
id: "uniswap-v4.mint-liquidity",
|
|
2253
2604
|
protocolId: UNISWAP_V4_PROTOCOL_ID,
|
|
@@ -2303,6 +2654,10 @@ var uniswapV4 = {
|
|
|
2303
2654
|
swapExactInput,
|
|
2304
2655
|
swapFromQuote,
|
|
2305
2656
|
buildSwapMultisignBody: buildEvmMultisignBodyUniswapV4SkipPermit2Batch,
|
|
2657
|
+
limitOrderQuote: uniswapLimitOrderQuote,
|
|
2658
|
+
buildLimitOrderMultisignBody: buildEvmMultisignBodyUniswapV4LimitOrderBatchFromMcp,
|
|
2659
|
+
fetchLimitOrders: fetchUniswapXLimitOrders,
|
|
2660
|
+
fetchLimitOrdersMcp: uniswapFetchLimitOrdersMcp,
|
|
2306
2661
|
quote: uniswapTradeQuote,
|
|
2307
2662
|
createLiquidityPosition: uniswapLpCreatePosition,
|
|
2308
2663
|
increaseLiquidityPosition: uniswapLpIncreasePosition,
|
|
@@ -2688,6 +3043,8 @@ Object.defineProperty(exports, "firstClientIdFromKeyGen", {
|
|
|
2688
3043
|
get: function () { return continuumNodeSdk.getClientIdFromKeyGenResult; }
|
|
2689
3044
|
});
|
|
2690
3045
|
exports.COINGECKO_PLATFORM_BY_CHAIN_ID = COINGECKO_PLATFORM_BY_CHAIN_ID;
|
|
3046
|
+
exports.DEFAULT_DEFI_MULTISIGN_EXPIRY_SECONDS = DEFAULT_DEFI_MULTISIGN_EXPIRY_SECONDS;
|
|
3047
|
+
exports.DEFI_PROTOCOLS_WITH_30MIN_EXPIRY = DEFI_PROTOCOLS_WITH_30MIN_EXPIRY;
|
|
2691
3048
|
exports.EIP712_SIGN_REQUEST_KIND = EIP712_SIGN_REQUEST_KIND;
|
|
2692
3049
|
exports.NEAR_CHAIN_CATEGORY = NEAR_CHAIN_CATEGORY;
|
|
2693
3050
|
exports.SOLANA_CHAIN_CATEGORY = SOLANA_CHAIN_CATEGORY;
|
|
@@ -2699,6 +3056,7 @@ exports.coingeckoPlatformForChainId = coingeckoPlatformForChainId;
|
|
|
2699
3056
|
exports.coreChainCategoryModule = coreChainCategoryModule;
|
|
2700
3057
|
exports.curveDao = curveDao;
|
|
2701
3058
|
exports.curveDaoProtocolModule = curveDaoProtocolModule;
|
|
3059
|
+
exports.defiMultisignExpiryUnixSeconds = defiMultisignExpiryUnixSeconds;
|
|
2702
3060
|
exports.evmChainCategoryModule = evmChainCategoryModule;
|
|
2703
3061
|
exports.finalizeMultisign = finalizeMultisign;
|
|
2704
3062
|
exports.getAaveGraphqlProxyUrl = getAaveGraphqlProxyUrl;
|