@continuumdao/ctm-mpc-defi 0.2.22 → 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 +142 -13
- package/dist/agent/catalog.cjs.map +1 -1
- package/dist/agent/catalog.d.ts +282 -43
- package/dist/agent/catalog.js +138 -14
- 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 +26 -1
- package/dist/core/index.d.ts +4 -36
- package/dist/eip712Multisign-xhXpUYp3.d.ts +36 -0
- package/dist/index.cjs +344 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +344 -12
- package/dist/index.js.map +1 -1
- package/dist/protocols/evm/gmx/index.cjs +39 -0
- package/dist/protocols/evm/gmx/index.cjs.map +1 -1
- package/dist/protocols/evm/gmx/index.d.ts +21 -1
- package/dist/protocols/evm/gmx/index.js +38 -1
- package/dist/protocols/evm/gmx/index.js.map +1 -1
- package/dist/protocols/evm/hyperliquid/index.cjs +478 -208
- package/dist/protocols/evm/hyperliquid/index.cjs.map +1 -1
- package/dist/protocols/evm/hyperliquid/index.d.ts +166 -51
- package/dist/protocols/evm/hyperliquid/index.js +467 -210
- package/dist/protocols/evm/hyperliquid/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/uniswap-v4/index.cjs +734 -15
- package/dist/protocols/evm/uniswap-v4/index.cjs.map +1 -1
- package/dist/protocols/evm/uniswap-v4/index.d.ts +189 -17
- package/dist/protocols/evm/uniswap-v4/index.js +698 -16
- package/dist/protocols/evm/uniswap-v4/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -24,6 +24,36 @@ Perpetuals on Arbitrum (42161) and Avalanche (43114) via `@gmx-io/sdk` v2 **clas
|
|
|
24
24
|
|
|
25
25
|
Set `orderType: "limit"` and `triggerPriceUsdHuman` on increase/decrease builders.
|
|
26
26
|
|
|
27
|
+
## Take profit / stop loss (increase only)
|
|
28
|
+
|
|
29
|
+
On **increase** (market or limit), pass optional native GMX bracket triggers. Each defaults to the full `sizeUsdHuman` position.
|
|
30
|
+
|
|
31
|
+
- `takeProfitPriceUsdHuman` — take-profit trigger (USD index)
|
|
32
|
+
- `stopLossPriceUsdHuman` — stop-loss trigger (USD index)
|
|
33
|
+
- `patternFailureUsdHuman` — audit / trade-idea alias; used as stop-loss when `stopLossPriceUsdHuman` is omitted
|
|
34
|
+
|
|
35
|
+
Example long limit with TP/SL on Arbitrum:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"keyGenId": "<keygen-id>",
|
|
40
|
+
"chainId": 42161,
|
|
41
|
+
"purposeText": "GMX long ETH limit with bracket",
|
|
42
|
+
"useCustomGas": false,
|
|
43
|
+
"symbol": "ETH/USD [WETH-USDC]",
|
|
44
|
+
"direction": "long",
|
|
45
|
+
"orderType": "limit",
|
|
46
|
+
"triggerPriceUsdHuman": "2900",
|
|
47
|
+
"takeProfitPriceUsdHuman": "3100",
|
|
48
|
+
"stopLossPriceUsdHuman": "2850",
|
|
49
|
+
"sizeUsdHuman": "200",
|
|
50
|
+
"collateralAmountHuman": "50",
|
|
51
|
+
"collateralToken": "USDC"
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
TP/SL orders are keeper-executed asynchronously after the increase fills (same as limit entry).
|
|
56
|
+
|
|
27
57
|
Example short limit on Arbitrum (ETH/USDC collateral):
|
|
28
58
|
|
|
29
59
|
```json
|
|
@@ -124,6 +124,38 @@ Positions and orders from MCP reflect **live HyperCore state** after prior txs a
|
|
|
124
124
|
|
|
125
125
|
Validate `szHuman` against `availableToBuy` / `availableToSell` from `fetch_open_context`.
|
|
126
126
|
|
|
127
|
+
## Bracket limit order (TP/SL on open)
|
|
128
|
+
|
|
129
|
+
When **`takeProfitTriggerPxHuman`** and/or **`stopLossTriggerPxHuman`** are set on `ctm_hyperliquid_build_limit_order_multisign`, the tool submits **one L1 EIP-712** action with `grouping: "normalTpsl"` (entry + TP/SL children). This is **not** CoreWriter — no HyperEVM gas at Execute; deliver signature to Hyperliquid `/exchange` (same path as `update_leverage`).
|
|
130
|
+
|
|
131
|
+
- **Auto from trade ideas:** map target → TP, invalidation → SL when both levels exist after desk offsets (`targetOffsetPct` / `targetOffsetMode` in `trade-desk.yaml` — conservative TP **inside** target: long below, short above; `price` or `atr` mode).
|
|
132
|
+
- **Geometry:** long → SL < entry < TP; short → TP < entry < SL.
|
|
133
|
+
- **`tpslExecMode`:** `limit_at_trigger` (default — limit px = trigger px) or `market` (10% slippage tolerance on HL). Configure default in trade-desk / node trade defaults under `hyperliquid.tpslExecMode`.
|
|
134
|
+
- **`targetOffsetPct` / `targetOffsetMode`:** desk defaults under `hyperliquid` — pull TP inside analysis target (`price` = % of target; `atr` = % of one ATR bar from analysis OHLCV).
|
|
135
|
+
- **OCO semantics:** TP/SL children activate when the entry order **fully fills**. If the parent is canceled before fill, children are canceled. Untriggered children do **not** appear in `fetch_open_orders` until entry fills.
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"keyGen": { "pubkeyhex": "…", "keylist": ["…"] },
|
|
140
|
+
"chainId": 999,
|
|
141
|
+
"rpcUrl": "https://…",
|
|
142
|
+
"executorAddress": "0x…",
|
|
143
|
+
"chainDetail": {},
|
|
144
|
+
"purposeText": "HL long BTC 0.01 @ 95000 TP 100000 SL 90000",
|
|
145
|
+
"useCustomGas": false,
|
|
146
|
+
"coin": "BTC",
|
|
147
|
+
"isBuy": true,
|
|
148
|
+
"limitPxHuman": "95000",
|
|
149
|
+
"szHuman": "0.01",
|
|
150
|
+
"tif": "gtc",
|
|
151
|
+
"takeProfitTriggerPxHuman": "100000",
|
|
152
|
+
"stopLossTriggerPxHuman": "90000",
|
|
153
|
+
"tpslExecMode": "limit_at_trigger"
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
After `{ requestId }`: `sign_request_agree` → `trigger_sign_result` **without txParams** → Execute posts to `/exchange`.
|
|
158
|
+
|
|
127
159
|
## Close position example
|
|
128
160
|
|
|
129
161
|
Use `isLong: true` for a **long** position (submits sell reduce-only IoC):
|
|
@@ -132,6 +132,30 @@ Assume 0.1 ETH = `100000000000000000` wei.
|
|
|
132
132
|
|
|
133
133
|
Use the same `swapTransactionDeadlineUnix` in step 2 and `swapDeadlineUnix` in step 3.
|
|
134
134
|
|
|
135
|
+
## Limit orders (UniswapX — Ethereum mainnet only)
|
|
136
|
+
|
|
137
|
+
Official UniswapX limit orders are **chainId 1 only** (not Robinhood 4663 or L2s today). Flow:
|
|
138
|
+
|
|
139
|
+
| Step | Tool | Creates sign request? |
|
|
140
|
+
|------|------|------------------------|
|
|
141
|
+
| 1. Quote | `ctm_uniswap_v4_limit_order_quote` | No — quote + `permitData` |
|
|
142
|
+
| 2. Submit | `ctm_uniswap_v4_build_limit_order_multisign` | Yes → EIP-712 `{ requestId }` → delivery POST `/v1/order` |
|
|
143
|
+
|
|
144
|
+
Optional: `ctm_uniswap_v4_fetch_limit_orders` — list open orders for swapper.
|
|
145
|
+
|
|
146
|
+
Trade-build bridge: `build_trade_from_*` with `protocolId: uniswap`, `chainId: 1`, `orderKind: limit`.
|
|
147
|
+
|
|
148
|
+
## Take-profit / stop-loss (agent monitor)
|
|
149
|
+
|
|
150
|
+
Uniswap spot has **no native TP/SL** like Hyperliquid. Use:
|
|
151
|
+
|
|
152
|
+
- `evaluate_uniswap_tpsl_monitor` — price vs TP/SL levels
|
|
153
|
+
- `register_uniswap_tpsl_monitor_cron` — creates a polling cron job that triggers **market swap** exits
|
|
154
|
+
|
|
155
|
+
Best-effort only — not exchange-grade resting orders. Template: `uniswap-tpsl-monitor-cron.example.md`.
|
|
156
|
+
|
|
157
|
+
Robinhood Chain (4663) OHLCV for monitors uses **Bitquery** (`BITQUERY_API_KEY`); other OHLCV chains use The Graph.
|
|
158
|
+
|
|
135
159
|
## Teaching users about slippage
|
|
136
160
|
|
|
137
161
|
- **Quote slippage** (`slippage` on quote, default 0.5%): Trade API routing tolerance.
|
|
@@ -217,8 +241,9 @@ OHLCV is **only** available on chains with a pinned public Uniswap V4 subgraph o
|
|
|
217
241
|
| 81457 | Blast |
|
|
218
242
|
| 42161 | Arbitrum |
|
|
219
243
|
| 43114 | Avalanche |
|
|
244
|
+
| 4663 | Robinhood (Bitquery OHLCV — not limit orders) |
|
|
220
245
|
|
|
221
|
-
**Swap / LP / quote tools** work on all `supportedChainIds` (~20+ EVM chains). On chains **without** a pinned subgraph (e.g. zkSync `324`, Celo `42220`, World Chain `480`, Linea `59144`, Zora `7777777`), use **CoinGecko/CoinMarketCap time series** via `get_defi_protocol_fetch_options` — do not call `fetch_ohlcv`.
|
|
246
|
+
**Swap / LP / quote tools** work on all `supportedChainIds` (~20+ EVM chains). **Limit orders** are **mainnet (1) only**. On chains **without** a pinned subgraph (e.g. zkSync `324`, Celo `42220`, World Chain `480`, Linea `59144`, Zora `7777777`), use **CoinGecko/CoinMarketCap time series** via `get_defi_protocol_fetch_options` — do not call `fetch_ohlcv`.
|
|
222
247
|
|
|
223
248
|
All OHLCV tiers (native subgraph, subgraph aggregation, sub-hour swap bucketing) require the same subgraph; there is no RPC-only fallback.
|
|
224
249
|
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
export { C as ChainCategory, a as ChainSupportContext, E as EvmTokenKind, b as KeyGenSubsetForPermit, c as MultisignCommonArgs, N as NearTokenKind, P as ParamDoc, d as ProtocolActionDescriptor, e as ProtocolModule, S as SolanaTokenKind, T as TokenRef } from '../types-PZrvtjv8.js';
|
|
1
|
+
export { C as ChainCategory, a as ChainSupportContext, E as EvmTokenKind, K as KeyGenSubset, b as KeyGenSubsetForPermit, M as MultisignBuildResult, c as MultisignCommonArgs, N as NearTokenKind, P as ParamDoc, d as ProtocolActionDescriptor, e as ProtocolModule, S as SolanaTokenKind, T as TokenRef } from '../types-PZrvtjv8.js';
|
|
3
2
|
export { getClientIdFromKeyGenResult as firstClientIdFromKeyGen } from '@continuumdao/continuum-node-sdk';
|
|
4
3
|
export { C as ChainCategoryBuildInput, a as ChainCategoryModule, M as MultisignLeg, c as coreChainCategoryModule, f as finalizeMultisign } from '../envelope-C_bfuKab.js';
|
|
5
4
|
export { g as getActionsByChainCategory, a as getProtocolModule, b as getProtocolModules, r as registerProtocolModule } from '../registry-DxDSPQ-p.js';
|
|
6
|
-
|
|
5
|
+
export { B as BuildEip712MultisignBodyArgs, E as EIP712_SIGN_REQUEST_KIND, a as Eip712MultisignDelivery, b as Eip712TypedDataField, c as Eip712TypedDataPayload, d as buildEip712MultisignBody } from '../eip712Multisign-xhXpUYp3.js';
|
|
6
|
+
import 'viem';
|
|
7
7
|
|
|
8
8
|
/** Merge user purpose text with an optional batch / protocol suffix. */
|
|
9
9
|
declare function mergePurposeText(purposeText: string | undefined, purposeSuffix?: string): string;
|
|
@@ -29,42 +29,10 @@ declare function postJsonViaOptionalProxy<T>(args: {
|
|
|
29
29
|
proxyEnvelope?: unknown;
|
|
30
30
|
}): Promise<T>;
|
|
31
31
|
|
|
32
|
-
declare const EIP712_SIGN_REQUEST_KIND: "eip712";
|
|
33
|
-
type Eip712TypedDataField = {
|
|
34
|
-
name: string;
|
|
35
|
-
type: string;
|
|
36
|
-
};
|
|
37
|
-
type Eip712TypedDataPayload = {
|
|
38
|
-
domain: TypedDataDomain;
|
|
39
|
-
types: Record<string, readonly Eip712TypedDataField[] | Eip712TypedDataField[]>;
|
|
40
|
-
primaryType: string;
|
|
41
|
-
message: Record<string, unknown>;
|
|
42
|
-
};
|
|
43
|
-
type Eip712MultisignDelivery = Record<string, unknown> & {
|
|
44
|
-
kind: string;
|
|
45
|
-
};
|
|
46
|
-
type BuildEip712MultisignBodyArgs = {
|
|
47
|
-
keyGen: KeyGenSubset;
|
|
48
|
-
purposeText: string;
|
|
49
|
-
purposeSuffix?: string;
|
|
50
|
-
/** Chain id stored on the sign request (protocol context; may differ from EIP-712 domain chainId). */
|
|
51
|
-
destinationChainID: string;
|
|
52
|
-
destinationAddress: string;
|
|
53
|
-
typedData: Eip712TypedDataPayload;
|
|
54
|
-
delivery: Eip712MultisignDelivery;
|
|
55
|
-
audit?: Record<string, unknown>;
|
|
56
|
-
expiryDate?: number;
|
|
57
|
-
};
|
|
58
|
-
/**
|
|
59
|
-
* Build an mpc-auth multiSignRequest body for a single-leg EIP-712 digest (no EVM tx broadcast).
|
|
60
|
-
* `msgHash` is the EIP-712 hash; `msgRaw` is UTF-8 hex JSON audit envelope (not RLP calldata).
|
|
61
|
-
*/
|
|
62
|
-
declare function buildEip712MultisignBody(args: BuildEip712MultisignBodyArgs): MultisignBuildResult;
|
|
63
|
-
|
|
64
32
|
/** Default MPC sign-request agreement window for fast-moving DeFi protocols (30 minutes). */
|
|
65
33
|
declare const DEFAULT_DEFI_MULTISIGN_EXPIRY_SECONDS: number;
|
|
66
34
|
/** Protocol ids that default to 30-minute expiry when `expiryDate` is omitted on multisign MCP tools. */
|
|
67
35
|
declare const DEFI_PROTOCOLS_WITH_30MIN_EXPIRY: Set<string>;
|
|
68
36
|
declare function defiMultisignExpiryUnixSeconds(protocolId: string | undefined, explicitExpiryDate?: number | null): number | undefined;
|
|
69
37
|
|
|
70
|
-
export {
|
|
38
|
+
export { DEFAULT_DEFI_MULTISIGN_EXPIRY_SECONDS, DEFI_PROTOCOLS_WITH_30MIN_EXPIRY, defiMultisignExpiryUnixSeconds, getAaveGraphqlProxyUrl, getCoingeckoProxyUrl, getEulerGraphqlProxyUrl, getMapleGraphqlProxyUrl, getMorphoGraphqlProxyUrl, mergePurposeText, postJsonViaOptionalProxy, setAaveGraphqlProxyUrl, setCoingeckoProxyUrl, setEulerGraphqlProxyUrl, setMapleGraphqlProxyUrl, setMorphoGraphqlProxyUrl };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { TypedDataDomain } from 'viem';
|
|
2
|
+
import { K as KeyGenSubset, M as MultisignBuildResult } from './types-PZrvtjv8.js';
|
|
3
|
+
|
|
4
|
+
declare const EIP712_SIGN_REQUEST_KIND: "eip712";
|
|
5
|
+
type Eip712TypedDataField = {
|
|
6
|
+
name: string;
|
|
7
|
+
type: string;
|
|
8
|
+
};
|
|
9
|
+
type Eip712TypedDataPayload = {
|
|
10
|
+
domain: TypedDataDomain;
|
|
11
|
+
types: Record<string, readonly Eip712TypedDataField[] | Eip712TypedDataField[]>;
|
|
12
|
+
primaryType: string;
|
|
13
|
+
message: Record<string, unknown>;
|
|
14
|
+
};
|
|
15
|
+
type Eip712MultisignDelivery = Record<string, unknown> & {
|
|
16
|
+
kind: string;
|
|
17
|
+
};
|
|
18
|
+
type BuildEip712MultisignBodyArgs = {
|
|
19
|
+
keyGen: KeyGenSubset;
|
|
20
|
+
purposeText: string;
|
|
21
|
+
purposeSuffix?: string;
|
|
22
|
+
/** Chain id stored on the sign request (protocol context; may differ from EIP-712 domain chainId). */
|
|
23
|
+
destinationChainID: string;
|
|
24
|
+
destinationAddress: string;
|
|
25
|
+
typedData: Eip712TypedDataPayload;
|
|
26
|
+
delivery: Eip712MultisignDelivery;
|
|
27
|
+
audit?: Record<string, unknown>;
|
|
28
|
+
expiryDate?: number;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Build an mpc-auth multiSignRequest body for a single-leg EIP-712 digest (no EVM tx broadcast).
|
|
32
|
+
* `msgHash` is the EIP-712 hash; `msgRaw` is UTF-8 hex JSON audit envelope (not RLP calldata).
|
|
33
|
+
*/
|
|
34
|
+
declare function buildEip712MultisignBody(args: BuildEip712MultisignBodyArgs): MultisignBuildResult;
|
|
35
|
+
|
|
36
|
+
export { type BuildEip712MultisignBodyArgs as B, EIP712_SIGN_REQUEST_KIND as E, type Eip712MultisignDelivery as a, type Eip712TypedDataField as b, type Eip712TypedDataPayload as c, buildEip712MultisignBody as d };
|
package/dist/index.cjs
CHANGED
|
@@ -616,8 +616,18 @@ var UNIVERSAL_ROUTER_SPENDER = {
|
|
|
616
616
|
143: "0x0d97dc33264bfc1c226207428a79b26757fb9dc3",
|
|
617
617
|
59144: "0x661e93cca42afacb172121ef892830ca3b70f08d",
|
|
618
618
|
4217: "0x1febb76be10aaf3a1402f04e8e835f2c382f7914",
|
|
619
|
-
196: "0x5507749f2c558bb3e162c6e90c314c092e7372ff"
|
|
619
|
+
196: "0x5507749f2c558bb3e162c6e90c314c092e7372ff",
|
|
620
|
+
/** Robinhood Chain mainnet — Universal Router v2.1.1 (Trade API / interface) */
|
|
621
|
+
4663: "0x8876789976decbfcbbbe364623c63652db8c0904"
|
|
620
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"
|
|
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
|
+
}
|
|
621
631
|
function isUniswapV4ChainSupported(chainId) {
|
|
622
632
|
if (chainId == null) return false;
|
|
623
633
|
const n = parseEvmChainIdToNumber(chainId);
|
|
@@ -652,7 +662,9 @@ var POSITION_MANAGER_BY_CHAIN = {
|
|
|
652
662
|
11155111: "0x4B2C77d209D3405F41a037Ec6c77F7F5b8e2ca80",
|
|
653
663
|
130: "0x0d97dc33264bfc1c226207428a79b26757fb9dc3",
|
|
654
664
|
1868: "0x0e2850543f69f678257266e0907ff9a58b3f13de",
|
|
655
|
-
59144: "0x661e93cca42afacb172121ef892830ca3b70f08d"
|
|
665
|
+
59144: "0x661e93cca42afacb172121ef892830ca3b70f08d",
|
|
666
|
+
/** Robinhood Chain mainnet */
|
|
667
|
+
4663: "0x58daec3116aae6D93017bAAea7749052E8a04fA7"
|
|
656
668
|
};
|
|
657
669
|
function getUniswapV4PositionManagerOrThrow(chainId) {
|
|
658
670
|
const raw = POSITION_MANAGER_BY_CHAIN[chainId];
|
|
@@ -699,8 +711,8 @@ function parseUniswapChainId(value) {
|
|
|
699
711
|
function trimAddr(a) {
|
|
700
712
|
return a.trim();
|
|
701
713
|
}
|
|
702
|
-
function
|
|
703
|
-
const t = (
|
|
714
|
+
function isUniswapNativeTokenAddress(token) {
|
|
715
|
+
const t = (token ?? "").toString().trim();
|
|
704
716
|
if (!t) return false;
|
|
705
717
|
try {
|
|
706
718
|
return viem.getAddress(t) === viem.zeroAddress;
|
|
@@ -715,7 +727,16 @@ function isUniswapFullQuoteResponseNativeIn(stored) {
|
|
|
715
727
|
const input = q.input;
|
|
716
728
|
if (!input) return false;
|
|
717
729
|
const raw = (input.address ?? input.token ?? "").toString().trim();
|
|
718
|
-
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);
|
|
719
740
|
}
|
|
720
741
|
async function fetchEthereumAddressForKeyGen(managementNodeUrl, keyGenId, readAuth = { bearerOnGet: true, jwt: null }, init) {
|
|
721
742
|
const base = managementNodeUrl.trim().replace(/\/$/, "");
|
|
@@ -777,6 +798,31 @@ function buildUniswapQuoteRequestBody(args) {
|
|
|
777
798
|
}
|
|
778
799
|
return body;
|
|
779
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
|
+
}
|
|
780
826
|
function errorMessageFromUniswapJsonBody(value) {
|
|
781
827
|
if (value == null) return null;
|
|
782
828
|
if (typeof value === "string") {
|
|
@@ -889,16 +935,18 @@ async function uniswapTradeQuote(args) {
|
|
|
889
935
|
}
|
|
890
936
|
const base = args.baseUrl && args.baseUrl.trim() ? args.baseUrl.trim().replace(/\/$/, "") : DEFAULT_TRADE_BASE;
|
|
891
937
|
const quoteUrl = `${base}/quote`;
|
|
892
|
-
const
|
|
938
|
+
const chainIdForRouter = parseUniswapChainId(resolveInputChainId(args));
|
|
939
|
+
const urv = args.universalRouterVersion && args.universalRouterVersion.trim() || getUniswapUniversalRouterVersion(chainIdForRouter);
|
|
893
940
|
const body = buildUniswapQuoteRequestBody({ ...args, swapper });
|
|
894
|
-
const nativeIn =
|
|
941
|
+
const nativeIn = isUniswapNativeTokenAddress(args.tokenIn);
|
|
942
|
+
const nativeOut = isUniswapNativeTokenAddress(args.tokenOut);
|
|
895
943
|
const headers = {
|
|
896
944
|
...UNISWAP_QUOTE_HEADERS_BASE,
|
|
897
945
|
"x-api-key": apiKey,
|
|
898
946
|
"x-universal-router-version": urv,
|
|
899
947
|
"x-permit2-disabled": args.permit2Disabled === true ? "true" : "false",
|
|
900
|
-
/** Native (0x0)
|
|
901
|
-
"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"
|
|
902
950
|
};
|
|
903
951
|
const fetchFn = args.fetchImpl ?? globalThis.fetch;
|
|
904
952
|
const res = await fetchFn(quoteUrl, {
|
|
@@ -909,7 +957,11 @@ async function uniswapTradeQuote(args) {
|
|
|
909
957
|
});
|
|
910
958
|
const text = await res.text();
|
|
911
959
|
if (!res.ok) {
|
|
912
|
-
|
|
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);
|
|
913
965
|
}
|
|
914
966
|
const forParse = text.replace(/^\uFEFF/, "");
|
|
915
967
|
try {
|
|
@@ -1016,16 +1068,17 @@ async function uniswapCreateSwap(args) {
|
|
|
1016
1068
|
quote: classic,
|
|
1017
1069
|
deadline
|
|
1018
1070
|
};
|
|
1019
|
-
const urv = (args.universalRouterVersion ??
|
|
1071
|
+
const urv = (args.universalRouterVersion ?? "").trim() || getUniswapUniversalRouterVersion(resolveChainIdFromStoredUniswapQuote(args.fullQuoteFromPermit));
|
|
1020
1072
|
const fn = args.fetchImpl ?? globalThis.fetch;
|
|
1021
1073
|
const nativeIn = isUniswapFullQuoteResponseNativeIn(args.fullQuoteFromPermit);
|
|
1074
|
+
const nativeOut = isUniswapFullQuoteResponseNativeOut(args.fullQuoteFromPermit);
|
|
1022
1075
|
const res = await fn(url, {
|
|
1023
1076
|
method: "POST",
|
|
1024
1077
|
headers: {
|
|
1025
1078
|
"Content-Type": "application/json",
|
|
1026
1079
|
"x-api-key": args.uniswapApiKey.trim(),
|
|
1027
1080
|
"x-universal-router-version": urv,
|
|
1028
|
-
"x-erc20eth-enabled": nativeIn ? "true" : "false",
|
|
1081
|
+
"x-erc20eth-enabled": nativeIn || nativeOut ? "true" : "false",
|
|
1029
1082
|
"x-permit2-disabled": "true"
|
|
1030
1083
|
},
|
|
1031
1084
|
body: JSON.stringify(body)
|
|
@@ -2225,6 +2278,270 @@ async function swapExactInput(args) {
|
|
|
2225
2278
|
return swapFromQuote({ ...args, swap });
|
|
2226
2279
|
}
|
|
2227
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
|
+
|
|
2228
2545
|
// src/protocols/evm/uniswap-v4/index.ts
|
|
2229
2546
|
var UNISWAP_V4_PROTOCOL_ID = "uniswap-v4";
|
|
2230
2547
|
var uniswapV4ProtocolModule = {
|
|
@@ -2271,6 +2588,17 @@ var uniswapV4ProtocolModule = {
|
|
|
2271
2588
|
type: { type: "EXACT_INPUT | EXACT_OUTPUT", required: true, description: "Trade type" }
|
|
2272
2589
|
}
|
|
2273
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
|
+
},
|
|
2274
2602
|
{
|
|
2275
2603
|
id: "uniswap-v4.mint-liquidity",
|
|
2276
2604
|
protocolId: UNISWAP_V4_PROTOCOL_ID,
|
|
@@ -2326,6 +2654,10 @@ var uniswapV4 = {
|
|
|
2326
2654
|
swapExactInput,
|
|
2327
2655
|
swapFromQuote,
|
|
2328
2656
|
buildSwapMultisignBody: buildEvmMultisignBodyUniswapV4SkipPermit2Batch,
|
|
2657
|
+
limitOrderQuote: uniswapLimitOrderQuote,
|
|
2658
|
+
buildLimitOrderMultisignBody: buildEvmMultisignBodyUniswapV4LimitOrderBatchFromMcp,
|
|
2659
|
+
fetchLimitOrders: fetchUniswapXLimitOrders,
|
|
2660
|
+
fetchLimitOrdersMcp: uniswapFetchLimitOrdersMcp,
|
|
2329
2661
|
quote: uniswapTradeQuote,
|
|
2330
2662
|
createLiquidityPosition: uniswapLpCreatePosition,
|
|
2331
2663
|
increaseLiquidityPosition: uniswapLpIncreasePosition,
|