@continuumdao/ctm-mpc-defi 0.2.56 → 0.2.57

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.
Files changed (49) hide show
  1. package/dist/agent/catalog.cjs +304 -134
  2. package/dist/agent/catalog.cjs.map +1 -1
  3. package/dist/agent/catalog.d.ts +162 -42
  4. package/dist/agent/catalog.js +304 -136
  5. package/dist/agent/catalog.js.map +1 -1
  6. package/dist/agent/skills/aave-v4/SKILL.md +26 -3
  7. package/dist/agent/skills/aerodrome/SKILL.md +3 -1
  8. package/dist/agent/skills/curve-dao/SKILL.md +2 -2
  9. package/dist/agent/skills/uniswap-v4/SKILL.md +2 -2
  10. package/dist/index.cjs +165 -19
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.js +166 -20
  13. package/dist/index.js.map +1 -1
  14. package/dist/protocols/evm/aave-v4/index.cjs +198 -15
  15. package/dist/protocols/evm/aave-v4/index.cjs.map +1 -1
  16. package/dist/protocols/evm/aave-v4/index.d.ts +62 -7
  17. package/dist/protocols/evm/aave-v4/index.js +189 -16
  18. package/dist/protocols/evm/aave-v4/index.js.map +1 -1
  19. package/dist/protocols/evm/aerodrome/index.cjs +152 -63
  20. package/dist/protocols/evm/aerodrome/index.cjs.map +1 -1
  21. package/dist/protocols/evm/aerodrome/index.d.ts +30 -58
  22. package/dist/protocols/evm/aerodrome/index.js +151 -64
  23. package/dist/protocols/evm/aerodrome/index.js.map +1 -1
  24. package/dist/protocols/evm/compound-v3/index.cjs +115 -2
  25. package/dist/protocols/evm/compound-v3/index.cjs.map +1 -1
  26. package/dist/protocols/evm/compound-v3/index.js +116 -3
  27. package/dist/protocols/evm/compound-v3/index.js.map +1 -1
  28. package/dist/protocols/evm/curve-dao/index.cjs +120 -5
  29. package/dist/protocols/evm/curve-dao/index.cjs.map +1 -1
  30. package/dist/protocols/evm/curve-dao/index.js +120 -5
  31. package/dist/protocols/evm/curve-dao/index.js.map +1 -1
  32. package/dist/protocols/evm/euler-v2/index.cjs +121 -6
  33. package/dist/protocols/evm/euler-v2/index.cjs.map +1 -1
  34. package/dist/protocols/evm/euler-v2/index.js +121 -6
  35. package/dist/protocols/evm/euler-v2/index.js.map +1 -1
  36. package/dist/protocols/evm/morpho/index.cjs +129 -57
  37. package/dist/protocols/evm/morpho/index.cjs.map +1 -1
  38. package/dist/protocols/evm/morpho/index.d.ts +2 -1
  39. package/dist/protocols/evm/morpho/index.js +129 -58
  40. package/dist/protocols/evm/morpho/index.js.map +1 -1
  41. package/dist/protocols/evm/pendle/index.cjs +129 -10
  42. package/dist/protocols/evm/pendle/index.cjs.map +1 -1
  43. package/dist/protocols/evm/pendle/index.js +129 -10
  44. package/dist/protocols/evm/pendle/index.js.map +1 -1
  45. package/dist/protocols/evm/uniswap-v4/index.cjs +164 -17
  46. package/dist/protocols/evm/uniswap-v4/index.cjs.map +1 -1
  47. package/dist/protocols/evm/uniswap-v4/index.js +165 -18
  48. package/dist/protocols/evm/uniswap-v4/index.js.map +1 -1
  49. package/package.json +1 -1
@@ -11,7 +11,7 @@ Aave v4 organizes liquidity into **hubs** (market segments) and **spokes** (on-c
11
11
 
12
12
  | Concept | What it is | Agent needs to know |
13
13
  |---------|------------|---------------------|
14
- | **Hub** | Off-chain market segment (Core, Plus, Prime) | Maps to UI `marketId`: `main` → Plus, `core` → Core, `bluechip` → Prime |
14
+ | **Hub** | Off-chain market segment (Core, Plus, Prime, Coinbase Stocks) | Maps to UI `marketId`: `main` → Plus, `core` → Core, `bluechip` → Prime, `bstocks` → Coinbase Stocks (Base tokenized equities) |
15
15
  | **Spoke** | On-chain contract (`supply`, `withdraw`, `borrow`, `repay`) | **Do not guess.** The MCP server resolves spoke from the Aave v4 API using `chainId` + `underlying` + `marketId` |
16
16
  | **Reserve** | One asset in one hub (underlying + APY + spoke) | From `ctm_aave_v4_fetch_markets` — do not web-search rates |
17
17
  | **Position** | User’s supplies/debt on a spoke | Withdraw/borrow/repay risk depends on health factor on that spoke |
@@ -33,6 +33,7 @@ Do **not** web-search Aave APRs, APYs, or reserves. Load the protocol and use th
33
33
  | User intent | MCP tool |
34
34
  |-------------|----------|
35
35
  | List reserves / lending APRs / compare rates | `ctm_aave_v4_fetch_markets` |
36
+ | Base tokenized stocks (bStocks) | `ctm_aave_v4_fetch_stock_markets` |
36
37
  | One asset’s APY (optionally one hub) | `ctm_aave_v4_fetch_market` |
37
38
  | Supply / deposit (lend) | `ctm_aave_v4_build_deposit_multisign` |
38
39
  | Withdraw supplied balance | `ctm_aave_v4_build_withdraw_multisign` |
@@ -50,7 +51,7 @@ Do **not** web-search Aave APRs, APYs, or reserves. Load the protocol and use th
50
51
  | `purposeText` | yes | Human-readable reason for the sign request |
51
52
  | `underlying` | yes | Token address for the action (see per-action below) |
52
53
  | `amountHuman` | yes | Human amount (e.g. `"0.5"`, `"100"`) |
53
- | `marketId` | no | `main` (default), `core`, or `bluechip` |
54
+ | `marketId` | no | `main` (default), `core`, `bluechip`, or `bstocks` (aliases: `stocks`, `equities`) |
54
55
  | `useCustomGas` | no | `true` to use chain registry gas config |
55
56
  | `spoke` | no | **Omit** — server resolves from Aave API |
56
57
 
@@ -87,7 +88,7 @@ Do **not** web-search Aave APRs, APYs, or reserves. Load the protocol and use th
87
88
  Example: “How do Aave lending APRs compare to Compound on Ethereum?”
88
89
 
89
90
  1. `load_defi_protocol({ protocolId: "aave-v4" })` then `get_defi_protocol_skill`.
90
- 2. `ctm_aave_v4_fetch_markets` with `chainId` 1. Optional `marketId` (`main` / `core` / `bluechip`) or `underlying` to filter.
91
+ 2. `ctm_aave_v4_fetch_markets` with `chainId` 1. Optional `marketId` (`main` / `core` / `bluechip` / `bstocks`) or `underlying` to filter. On Base, `ctm_aave_v4_fetch_stock_markets` lists the Coinbase Stocks hub.
91
92
  3. Each row is one live spoke on a hub (unused zero-liquidity listings omitted): `supplyApyPercent`, `borrowApyPercent`, `utilizationPercent`, `availableLiquidity`. The same asset can appear on more than one spoke.
92
93
  4. Aave reports **APY** (compounded). Compound v3 reports **APR** — say so when comparing.
93
94
  5. Copy `underlying` + `marketId` for a later deposit/borrow. Do not invent rates from the web.
@@ -158,6 +159,28 @@ After stETH is supplied:
158
159
  }
159
160
  ```
160
161
 
162
+ ## bStocks (Base tokenized equities)
163
+
164
+ Aave v4 on Base (chainId **8453**) has a **Coinbase Stocks** hub. UI and MCP `marketId` is **`bstocks`**. The same hub resolver is used by the node app and by `ctm_aave_v4_fetch_stock_markets` / `build_*_multisign`.
165
+
166
+ - Collateral is whatever the Coinbase Stocks hub currently lists (`ctm_aave_v4_fetch_stock_markets`). Pass a ticker such as `AAPLc`; it resolves from the live Coinbase catalog. Equity reserves are **not borrowable**.
167
+ - Borrow asset: **USDC** only. Supply the stock with `marketId: "bstocks"`, then borrow USDC. `collateralUnderlying` may be the stock ticker.
168
+ - Chainlink equity feeds publish 24/5 (Sunday 20:00 ET through Friday 20:00 ET) and hold the last price over weekends and US market holidays. Health factor can still fall from interest while the feed is stale.
169
+ - Coinbase Tokenized Stocks are not for U.S. persons.
170
+ - Do not treat `main` as this hub. Base has no Plus hub; `main` does not select Coinbase Stocks.
171
+
172
+ ```json
173
+ {
174
+ "keyGenId": "<keygen-id>",
175
+ "chainId": 8453,
176
+ "purposeText": "Supply 1 AAPLc to Aave v4 bStocks",
177
+ "underlying": "AAPLc",
178
+ "marketId": "bstocks",
179
+ "amountHuman": "1",
180
+ "enableAsCollateralAfterSupply": true
181
+ }
182
+ ```
183
+
161
184
  ## Notes
162
185
 
163
186
  - Native supply uses wrapped native from `get_defi_protocol_supported_tokens` (`nativeWrapped`).
@@ -86,7 +86,9 @@ Skip emissions when `claimEmissions` is `null` (no gauge). Slipstream unstaked f
86
86
 
87
87
  Loaded from official GitHub (`velodrome-finance/sugar` `deployments/base.env` and `aerodrome-finance/docs` security.mdx) with baked fallbacks. Do not invent addresses.
88
88
 
89
- Coinbase B20 stocks (AAPLc, NVDAc, METAc, GOOGLc, SPCXc, …) trade on **Slipstream 3** (`clFactory3`) vs USDC. Stock-backed **loans** (lend/borrow USDC against B20 collateral) are Morpho — `load_defi_protocol morpho` and `ctm_morpho_fetch_stock_markets`, not Aerodrome LP. New official names are picked up from the [Base tokenized-stocks docs](https://docs.base.org/base-chain/asset-issuance/tokenized-stocks-on-base) and from Sugar tokens whose address uses the B20 ASSET prefix `0xb200…`. The docs fetch is optional: if that page is gone or unusable, discovery continues from the seed list + Sugar. `issued` is live `totalSupply() > 0` — do not hard-code unissued tickers. Quotes use factory `getPool` discovery + MixedRouteQuoterV3 (path bitmasks). Sugar `forSwaps` alone misses these pools. Native ETH → stock is typically WETH → USDC → stock.
89
+ Aero (the Aerodrome rename) is scheduled for **2026-10-22 00:00 UTC** on Base, Ethereum, OP Mainnet, Arc, Ink, Robinhood Chain, and Arbitrum. Those contract addresses are not published yet, so quotes and writes stay on the live Base deployment (`chainId` 8453). Tokenized stocks stay on Base even after that launch.
90
+
91
+ Coinbase B20 stocks (AAPLc, NVDAc, PYPLc, AMDc, ORCLc, BRK.Bc, …) trade on **Slipstream 3** (`clFactory3`) vs USDC. Tickers resolve from the live Coinbase tokenized-stocks API. There is no baked-in address list. Pass the ticker — do not ask for a contract address. Stock-backed **loans** (lend/borrow USDC against B20 collateral) are Morpho — `load_defi_protocol morpho` and `ctm_morpho_fetch_stock_markets`, not Aerodrome LP. Sugar tokens whose address uses the B20 ASSET prefix `0xb200…` are also treated as stocks. `issued` is live `totalSupply() > 0`. Quotes use factory `getPool` discovery + MixedRouteQuoterV3 (path bitmasks). Sugar `forSwaps` alone misses these pools. Native ETH → stock is typically WETH → USDC → stock.
90
92
 
91
93
  ## Out of scope
92
94
 
@@ -55,8 +55,8 @@ Always quote first unless the user already has a verified route. Explain quote o
55
55
  | Field | Required | Notes |
56
56
  |-------|----------|-------|
57
57
  | `chainId` | yes | Must be Curve-supported (see supported chains below) |
58
- | `tokenIn` | yes | ERC-20 address, or native: `0xeeee…`, `0x0`, `eth` |
59
- | `tokenOut` | yes | ERC-20 address or `0xeeee…` for native out |
58
+ | `tokenIn` | yes | ERC-20 address, a Coinbase stock ticker (`AAPLc`) from the live catalog, or native: `0xeeee…`, `0x0`, `eth` |
59
+ | `tokenOut` | yes | ERC-20 address, the same Coinbase stock ticker, or `0xeeee…` for native out |
60
60
  | `amountHuman` | yes | Human decimal string of **tokenIn** (e.g. `"100"`, `"0.5"`) |
61
61
  | `tokenInDecimals` | no | Omit to read decimals on-chain (native = 18) |
62
62
  | `rpcUrl` | no | **Do not pass** — server injects from chain registry |
@@ -41,8 +41,8 @@ Do not skip steps. Pass the **full quote JSON** into `create_swap`, then pass **
41
41
  |-------|----------|-------|
42
42
  | `type` | yes | `EXACT_INPUT` (sell exact tokenIn) or `EXACT_OUTPUT` (receive exact tokenOut) |
43
43
  | `amount` | yes | **Base units** string (wei for 18-decimal tokens). For human amounts, convert with token decimals first |
44
- | `tokenIn` | yes | Input token; native ETH: `0x0000000000000000000000000000000000000000` |
45
- | `tokenOut` | yes | Output token address (same chain) |
44
+ | `tokenIn` | yes | Input token address, or a Coinbase stock ticker (`AAPLc`) from the live catalog. Native ETH: `0x0000000000000000000000000000000000000000` |
45
+ | `tokenOut` | yes | Output token address, or the same Coinbase stock ticker |
46
46
  | `chainId` | yes | Must be Uniswap-supported |
47
47
  | `keyGenId` | recommended | Server resolves `swapper` (MPC executor) |
48
48
  | `swapper` | optional | MPC wallet address if `keyGenId` omitted |
package/dist/index.cjs CHANGED
@@ -51,6 +51,124 @@ var init_expiry = __esm({
51
51
  ]);
52
52
  }
53
53
  });
54
+ function isCoinbaseB20AssetToken(address) {
55
+ try {
56
+ return viem.getAddress(address).toLowerCase().startsWith(COINBASE_B20_ASSET_PREFIX);
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
61
+ function looksLikeCoinbaseStockSymbol(symbol) {
62
+ return /^[A-Za-z][A-Za-z0-9]{0,8}(?:\.[A-Za-z][A-Za-z0-9]{0,4})?c$/.test((symbol ?? "").trim());
63
+ }
64
+ function indexCatalog(rows) {
65
+ catalogRows = rows;
66
+ catalogAt = Date.now();
67
+ catalogBySymbol.clear();
68
+ catalogByAddress.clear();
69
+ for (const row of rows) {
70
+ catalogBySymbol.set(row.symbol.toLowerCase(), row);
71
+ catalogByAddress.set(row.address.toLowerCase(), row);
72
+ }
73
+ }
74
+ function parseCoinbaseTokenizedStocksPayload(payload) {
75
+ const tokens = Array.isArray(payload) ? payload : payload && typeof payload === "object" && Array.isArray(payload.tokens) ? payload.tokens : [];
76
+ const out = [];
77
+ const seen = /* @__PURE__ */ new Set();
78
+ for (const row of tokens) {
79
+ if (!row || typeof row !== "object") continue;
80
+ const rec = row;
81
+ const symbol = typeof rec.symbol === "string" ? rec.symbol.trim() : "";
82
+ const addressRaw = typeof rec.contract_address === "string" ? rec.contract_address.trim() : "";
83
+ if (!looksLikeCoinbaseStockSymbol(symbol) || !isCoinbaseB20AssetToken(addressRaw)) continue;
84
+ const address = viem.getAddress(addressRaw);
85
+ const key = address.toLowerCase();
86
+ if (seen.has(key)) continue;
87
+ seen.add(key);
88
+ const name = typeof rec.name === "string" && rec.name.trim() ? rec.name.trim() : symbol;
89
+ const iconUrl = typeof rec.icon_url === "string" && rec.icon_url.trim() ? rec.icon_url.trim() : void 0;
90
+ const decimals = typeof rec.decimals === "number" && Number.isInteger(rec.decimals) && rec.decimals >= 0 && rec.decimals <= 18 ? rec.decimals : COINBASE_B20_STOCK_DECIMALS;
91
+ out.push({ address, symbol, name, decimals, iconUrl });
92
+ if (out.length >= CATALOG_MAX) break;
93
+ }
94
+ return out;
95
+ }
96
+ async function fetchCoinbaseB20StockCatalog() {
97
+ const merged = [];
98
+ const seen = /* @__PURE__ */ new Set();
99
+ let pageToken = "";
100
+ for (let page = 0; page < 4; page++) {
101
+ const url = new URL(COINBASE_TOKENIZED_STOCKS_API_URL);
102
+ url.searchParams.set("page_size", "500");
103
+ if (pageToken) url.searchParams.set("page_token", pageToken);
104
+ const res = await fetch(url, { cache: "no-store", signal: AbortSignal.timeout(8e3) });
105
+ if (!res.ok) break;
106
+ const json = await res.json();
107
+ for (const row of parseCoinbaseTokenizedStocksPayload(json)) {
108
+ const key = row.address.toLowerCase();
109
+ if (seen.has(key)) continue;
110
+ seen.add(key);
111
+ merged.push(row);
112
+ if (merged.length >= CATALOG_MAX) break;
113
+ }
114
+ pageToken = typeof json.next_page_token === "string" ? json.next_page_token.trim() : "";
115
+ if (!pageToken || merged.length >= CATALOG_MAX) break;
116
+ }
117
+ if (merged.length > 0) indexCatalog(merged);
118
+ return catalogRows ?? [];
119
+ }
120
+ async function ensureCoinbaseB20StockCatalog() {
121
+ if (catalogRows && catalogRows.length > 0 && Date.now() - catalogAt < CATALOG_TTL_MS) return catalogRows;
122
+ if (!catalogInflight) {
123
+ catalogInflight = fetchCoinbaseB20StockCatalog().finally(() => {
124
+ catalogInflight = null;
125
+ });
126
+ }
127
+ try {
128
+ return await catalogInflight;
129
+ } catch {
130
+ return catalogRows ?? [];
131
+ }
132
+ }
133
+ function lookupCoinbaseB20StockToken(token) {
134
+ const key = (token ?? "").trim();
135
+ if (!key) return null;
136
+ const fromCatalog = catalogBySymbol.get(key.toLowerCase());
137
+ if (fromCatalog) return fromCatalog;
138
+ try {
139
+ return catalogByAddress.get(viem.getAddress(key).toLowerCase()) ?? null;
140
+ } catch {
141
+ return null;
142
+ }
143
+ }
144
+ async function canonicalizeEvmTokenInput(token) {
145
+ const raw = (token ?? "").trim();
146
+ if (!raw || viem.isAddress(raw)) return raw;
147
+ if (!looksLikeCoinbaseStockSymbol(raw)) return raw;
148
+ await ensureCoinbaseB20StockCatalog().catch(() => []);
149
+ const hit = lookupCoinbaseB20StockToken(raw);
150
+ if (!hit) {
151
+ throw new Error(
152
+ `Unknown Coinbase stock ticker "${raw}". It is not in the live tokenized-stocks catalog.`
153
+ );
154
+ }
155
+ return hit.address;
156
+ }
157
+ var COINBASE_B20_STOCK_DECIMALS, COINBASE_B20_ASSET_PREFIX, COINBASE_TOKENIZED_STOCKS_API_URL, CATALOG_TTL_MS, CATALOG_MAX, catalogRows, catalogAt, catalogInflight, catalogBySymbol, catalogByAddress;
158
+ var init_coinbaseB20 = __esm({
159
+ "src/protocols/evm/shared/coinbaseB20.ts"() {
160
+ COINBASE_B20_STOCK_DECIMALS = 8;
161
+ COINBASE_B20_ASSET_PREFIX = "0xb200000000000000000000";
162
+ COINBASE_TOKENIZED_STOCKS_API_URL = "https://api.coinbase.com/v1/tokenized-stocks";
163
+ CATALOG_TTL_MS = 15 * 60 * 1e3;
164
+ CATALOG_MAX = 500;
165
+ catalogRows = null;
166
+ catalogAt = 0;
167
+ catalogInflight = null;
168
+ catalogBySymbol = /* @__PURE__ */ new Map();
169
+ catalogByAddress = /* @__PURE__ */ new Map();
170
+ }
171
+ });
54
172
  function isAerodromeChainSupported(chainId) {
55
173
  const n = typeof chainId === "number" ? chainId : Number.parseInt(String(chainId), 10);
56
174
  return n === AERODROME_CHAIN_ID;
@@ -946,6 +1064,9 @@ var UNISWAP_V4_LP_COLLECT_DEFAULT_GAS_UNITS = 900000n;
946
1064
  var UNISWAP_V4_LP_ERC20_APPROVE_FALLBACK = 100000n;
947
1065
  var UNISWAP_V4_LP_WETH_DEPOSIT_FALLBACK = 120000n;
948
1066
  var UNISWAP_V4_LP_PERMIT2_APPROVE_FALLBACK = 100000n;
1067
+
1068
+ // src/protocols/evm/uniswap-v4/quote.ts
1069
+ init_coinbaseB20();
949
1070
  viem.parseAbi([
950
1071
  "function isAllowed(address account, uint8 permission) view returns (bool)",
951
1072
  "function PERMISSIONED_TOKEN() view returns (address)"
@@ -1312,6 +1433,11 @@ function messageFromUniswapHttpResponseBody(text, status, statusText = "") {
1312
1433
  return short;
1313
1434
  }
1314
1435
  async function uniswapTradeQuote(args) {
1436
+ args = {
1437
+ ...args,
1438
+ tokenIn: await canonicalizeEvmTokenInput(args.tokenIn),
1439
+ tokenOut: await canonicalizeEvmTokenInput(args.tokenOut)
1440
+ };
1315
1441
  const apiKey = (args.uniswapApiKey || "").trim();
1316
1442
  if (!apiKey) {
1317
1443
  throw new Error("uniswapApiKey (x-api-key) is required");
@@ -1431,6 +1557,7 @@ function parseUniswapQuoteClassicInOut(res) {
1431
1557
  }
1432
1558
 
1433
1559
  // src/protocols/evm/uniswap-v4/swapMultisign.ts
1560
+ init_coinbaseB20();
1434
1561
  init_defiEvmClient();
1435
1562
  function parseOptionalGasLimitString(raw) {
1436
1563
  if (raw == null) return null;
@@ -1763,7 +1890,7 @@ async function buildEvmMultisignBodyUniswapV4NativeInOnly(args, quoteInputWei) {
1763
1890
  });
1764
1891
  }
1765
1892
  async function buildEvmMultisignBodyUniswapV4SkipPermit2Batch(args) {
1766
- const tokenIn = viem.getAddress(args.tokenIn);
1893
+ const tokenIn = viem.getAddress(await canonicalizeEvmTokenInput(args.tokenIn));
1767
1894
  const parsedInOut = parseUniswapQuoteClassicInOut(args.fullQuoteSnapshot);
1768
1895
  const quoteInputWei = parsedInOut?.inputWei;
1769
1896
  if (quoteInputWei == null || quoteInputWei <= 0n) {
@@ -2038,6 +2165,7 @@ async function buildEvmMultisignBodyUniswapV4SkipPermit2Batch(args) {
2038
2165
  var UNISWAP_V4_LP_POOL_LOOKUP_HINT = "Pool may not be initialized on this chain. Call ctm_uniswap_v4_list_lp_pools for other presets, pass a custom existingPool.poolReference, or use newPool to initialize a pool.";
2039
2166
 
2040
2167
  // src/protocols/evm/uniswap-v4/liquidityApi.ts
2168
+ init_coinbaseB20();
2041
2169
  var LP_HEADERS_BASE = {
2042
2170
  "Content-Type": "application/json",
2043
2171
  Accept: "application/json",
@@ -2142,36 +2270,47 @@ function extractUniswapLpTokenAmounts(response) {
2142
2270
  return { token0: read("token0"), token1: read("token1") };
2143
2271
  }
2144
2272
  async function uniswapLpCreatePosition(args) {
2273
+ const independentAddress = await canonicalizeEvmTokenInput(args.independentToken.tokenAddress);
2274
+ const existingPool = args.existingPool ? {
2275
+ ...args.existingPool,
2276
+ token0Address: await canonicalizeEvmTokenInput(args.existingPool.token0Address),
2277
+ token1Address: await canonicalizeEvmTokenInput(args.existingPool.token1Address)
2278
+ } : void 0;
2279
+ const newPool = args.newPool ? {
2280
+ ...args.newPool,
2281
+ token0Address: await canonicalizeEvmTokenInput(args.newPool.token0Address),
2282
+ token1Address: await canonicalizeEvmTokenInput(args.newPool.token1Address)
2283
+ } : void 0;
2145
2284
  const body = {
2146
2285
  protocol: "V4",
2147
2286
  walletAddress: trimAddr2(args.walletAddress),
2148
2287
  chainId: args.chainId,
2149
2288
  independentToken: {
2150
- tokenAddress: trimAddr2(args.independentToken.tokenAddress),
2289
+ tokenAddress: trimAddr2(independentAddress),
2151
2290
  amount: String(args.independentToken.amount).trim()
2152
2291
  },
2153
2292
  slippageTolerance: args.slippageTolerance ?? UNISWAP_LP_DEFAULT_SLIPPAGE_PERCENT,
2154
2293
  deadline: args.deadline ?? lpDeadlineUnix(),
2155
2294
  simulateTransaction: args.simulateTransaction ?? false
2156
2295
  };
2157
- if (args.existingPool) {
2296
+ if (existingPool) {
2158
2297
  body.existingPool = {
2159
- token0Address: trimAddr2(args.existingPool.token0Address),
2160
- token1Address: trimAddr2(args.existingPool.token1Address),
2161
- poolReference: trimAddr2(args.existingPool.poolReference)
2298
+ token0Address: trimAddr2(existingPool.token0Address),
2299
+ token1Address: trimAddr2(existingPool.token1Address),
2300
+ poolReference: trimAddr2(existingPool.poolReference)
2162
2301
  };
2163
2302
  }
2164
- if (args.newPool) {
2303
+ if (newPool) {
2165
2304
  body.newPool = {
2166
- token0Address: trimAddr2(args.newPool.token0Address),
2167
- token1Address: trimAddr2(args.newPool.token1Address),
2168
- fee: args.newPool.fee,
2169
- tickSpacing: args.newPool.tickSpacing,
2170
- initialPrice: String(args.newPool.initialPrice).trim(),
2171
- ...args.newPool.hooks ? { hooks: trimAddr2(args.newPool.hooks) } : {}
2305
+ token0Address: trimAddr2(newPool.token0Address),
2306
+ token1Address: trimAddr2(newPool.token1Address),
2307
+ fee: newPool.fee,
2308
+ tickSpacing: newPool.tickSpacing,
2309
+ initialPrice: String(newPool.initialPrice).trim(),
2310
+ ...newPool.hooks ? { hooks: trimAddr2(newPool.hooks) } : {}
2172
2311
  };
2173
2312
  }
2174
- if (!args.existingPool && !args.newPool) {
2313
+ if (!existingPool && !newPool) {
2175
2314
  throw new Error("Provide existingPool or newPool for LP create.");
2176
2315
  }
2177
2316
  if (args.priceBounds) {
@@ -2206,11 +2345,11 @@ async function uniswapLpIncreasePosition(args) {
2206
2345
  protocol: "V4",
2207
2346
  walletAddress: trimAddr2(args.walletAddress),
2208
2347
  chainId: args.chainId,
2209
- token0Address: trimAddr2(args.token0Address),
2210
- token1Address: trimAddr2(args.token1Address),
2348
+ token0Address: trimAddr2(await canonicalizeEvmTokenInput(args.token0Address)),
2349
+ token1Address: trimAddr2(await canonicalizeEvmTokenInput(args.token1Address)),
2211
2350
  nftTokenId: String(args.nftTokenId),
2212
2351
  independentToken: {
2213
- tokenAddress: trimAddr2(args.independentToken.tokenAddress),
2352
+ tokenAddress: trimAddr2(await canonicalizeEvmTokenInput(args.independentToken.tokenAddress)),
2214
2353
  amount: String(args.independentToken.amount).trim()
2215
2354
  },
2216
2355
  slippageTolerance: args.slippageTolerance ?? UNISWAP_LP_DEFAULT_SLIPPAGE_PERCENT,
@@ -2820,6 +2959,7 @@ async function swapExactInput(args) {
2820
2959
  }
2821
2960
 
2822
2961
  // src/protocols/evm/uniswap-v4/limitOrder.ts
2962
+ init_coinbaseB20();
2823
2963
  function trimAddr3(a) {
2824
2964
  return a.trim();
2825
2965
  }
@@ -2920,6 +3060,11 @@ async function uniswapLimitOrderQuote(args) {
2920
3060
  args.nodeReadAuth ?? { bearerOnGet: true, jwt: null }
2921
3061
  );
2922
3062
  }
3063
+ args = {
3064
+ ...args,
3065
+ tokenIn: await canonicalizeEvmTokenInput(args.tokenIn),
3066
+ tokenOut: await canonicalizeEvmTokenInput(args.tokenOut)
3067
+ };
2923
3068
  const chainIdForGuard = parseUniswapChainId(resolveInputChainId(args));
2924
3069
  assertUniswapLimitOrderChain(chainIdForGuard);
2925
3070
  const base = args.baseUrl && args.baseUrl.trim() ? args.baseUrl.trim().replace(/\/$/, "") : "https://trade-api.gateway.uniswap.org/v1";
@@ -3372,6 +3517,7 @@ async function loadFullCurveSessionForRpc(rpcUrl) {
3372
3517
  var CURVE_ROUTER_EXCHANGE_DEFAULT_GAS_UNITS = 1200000n;
3373
3518
 
3374
3519
  // src/protocols/evm/curve-dao/multisign.ts
3520
+ init_coinbaseB20();
3375
3521
  init_defiEvmClient();
3376
3522
  var ETH_PLACEHOLDER2 = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
3377
3523
  function txToViemStep(tx) {
@@ -3387,7 +3533,7 @@ function txToViemStep(tx) {
3387
3533
  return { to, data, value };
3388
3534
  }
3389
3535
  async function buildEvmMultisignBodyCurveDaoBatch(args) {
3390
- const tokenIn = viem.getAddress(args.tokenIn);
3536
+ const tokenIn = viem.getAddress(await canonicalizeEvmTokenInput(args.tokenIn));
3391
3537
  const executor = viem.getAddress(args.executorAddress);
3392
3538
  const session = await loadFullCurveSessionForRpc(args.rpcUrl);
3393
3539
  if (!session?.curve?.router?.populateSwap) {
@@ -3396,7 +3542,7 @@ async function buildEvmMultisignBodyCurveDaoBatch(args) {
3396
3542
  const { curve, wrappedNative } = session;
3397
3543
  const wn = wrappedNative;
3398
3544
  const tokenInId = toCurveRouterTokenId(tokenIn, wn);
3399
- const outTrim = (args.tokenOut ?? "").trim();
3545
+ const outTrim = (await canonicalizeEvmTokenInput(args.tokenOut ?? "")).trim();
3400
3546
  const tokenOutId = toCurveRouterTokenId(
3401
3547
  outTrim.toLowerCase() === ETH_PLACEHOLDER2 ? ETH_PLACEHOLDER2 : viem.getAddress(outTrim),
3402
3548
  wn