@sherwoodagent/cli 0.42.0 → 0.47.1
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/{addresses-DCQMJJFI.js → addresses-DOWLGXGE.js} +4 -4
- package/dist/{agent-5YEJ6W6W.js → agent-4HKHLQEJ.js} +3035 -2029
- package/dist/agent-4HKHLQEJ.js.map +1 -0
- package/dist/autoresearch-IA7HGSNW.js +267 -0
- package/dist/autoresearch-IA7HGSNW.js.map +1 -0
- package/dist/{chat-UWJ6JBFE.js → chat-MRTPUZ3X.js} +8 -8
- package/dist/{chunk-FOOZC4AM.js → chunk-2LRC7I33.js} +2 -2
- package/dist/{chunk-4EHI4SKM.js → chunk-2W4KGGPU.js} +11 -1
- package/dist/chunk-2W4KGGPU.js.map +1 -0
- package/dist/chunk-7HJXZ4NM.js +189 -0
- package/dist/chunk-7HJXZ4NM.js.map +1 -0
- package/dist/{chunk-JNDEZFXW.js → chunk-E6LH2FJ6.js} +4 -4
- package/dist/{chunk-XAUMJZU2.js → chunk-FWC57PT7.js} +2 -2
- package/dist/{chunk-4OAZ7TP5.js → chunk-IS2CLLUT.js} +4 -4
- package/dist/{chunk-T2IA6CCW.js → chunk-KJ35EF7N.js} +4 -4
- package/dist/{chunk-GMVDHSCF.js → chunk-OHQOTSFG.js} +39 -3
- package/dist/chunk-OHQOTSFG.js.map +1 -0
- package/dist/chunk-R2P4C2I7.js +560 -0
- package/dist/chunk-R2P4C2I7.js.map +1 -0
- package/dist/{chunk-5Q3VT6NQ.js → chunk-R7X33D2S.js} +5 -5
- package/dist/{chunk-6U3A6ZJ2.js → chunk-WMZEOR5W.js} +6 -127
- package/dist/chunk-WMZEOR5W.js.map +1 -0
- package/dist/{chunk-SWKHSKDH.js → chunk-XDBRKW7I.js} +3 -3
- package/dist/chunk-YTYXBX7B.js +495 -0
- package/dist/chunk-YTYXBX7B.js.map +1 -0
- package/dist/{client-DRVUILER.js → client-UHHCB6EZ.js} +4 -4
- package/dist/{config-YRERDZSL.js → config-REASKDIK.js} +6 -2
- package/dist/{eas-KBU2BAOD.js → eas-PEEWGSAO.js} +6 -6
- package/dist/{governor-KH7RNH2E.js → governor-MG5VVSU4.js} +6 -6
- package/dist/index.js +1012 -265
- package/dist/index.js.map +1 -1
- package/dist/{network-3HB46JMQ.js → network-3ZU7UBDU.js} +3 -3
- package/dist/{price-TTQWI672.js → price-WCCXWPDM.js} +5 -5
- package/dist/{research-J3HYU3N6.js → research-QBKISW2M.js} +9 -9
- package/dist/research-YJWSQS2A.js +14 -0
- package/dist/serve-6MYBOAX6.js +222 -0
- package/dist/serve-6MYBOAX6.js.map +1 -0
- package/dist/{session-NUPHC6ZN.js → session-FPCPCVQX.js} +10 -10
- package/dist/summary-formatter-JIGWN4QS.js +180 -0
- package/dist/summary-formatter-JIGWN4QS.js.map +1 -0
- package/dist/{trade-VGECC4QZ.js → trade-NO6CNWCA.js} +19 -17
- package/dist/{trade-VGECC4QZ.js.map → trade-NO6CNWCA.js.map} +1 -1
- package/dist/{xmtp-JO7W6RFK.js → xmtp-ACB2W573.js} +6 -6
- package/package.json +5 -2
- package/dist/agent-5YEJ6W6W.js.map +0 -1
- package/dist/chunk-4EHI4SKM.js.map +0 -1
- package/dist/chunk-6U3A6ZJ2.js.map +0 -1
- package/dist/chunk-GMVDHSCF.js.map +0 -1
- package/dist/research-NR4VC5LN.js +0 -14
- /package/dist/{addresses-DCQMJJFI.js.map → addresses-DOWLGXGE.js.map} +0 -0
- /package/dist/{chat-UWJ6JBFE.js.map → chat-MRTPUZ3X.js.map} +0 -0
- /package/dist/{chunk-FOOZC4AM.js.map → chunk-2LRC7I33.js.map} +0 -0
- /package/dist/{chunk-JNDEZFXW.js.map → chunk-E6LH2FJ6.js.map} +0 -0
- /package/dist/{chunk-XAUMJZU2.js.map → chunk-FWC57PT7.js.map} +0 -0
- /package/dist/{chunk-4OAZ7TP5.js.map → chunk-IS2CLLUT.js.map} +0 -0
- /package/dist/{chunk-T2IA6CCW.js.map → chunk-KJ35EF7N.js.map} +0 -0
- /package/dist/{chunk-5Q3VT6NQ.js.map → chunk-R7X33D2S.js.map} +0 -0
- /package/dist/{chunk-SWKHSKDH.js.map → chunk-XDBRKW7I.js.map} +0 -0
- /package/dist/{client-DRVUILER.js.map → client-UHHCB6EZ.js.map} +0 -0
- /package/dist/{config-YRERDZSL.js.map → config-REASKDIK.js.map} +0 -0
- /package/dist/{eas-KBU2BAOD.js.map → eas-PEEWGSAO.js.map} +0 -0
- /package/dist/{governor-KH7RNH2E.js.map → governor-MG5VVSU4.js.map} +0 -0
- /package/dist/{network-3HB46JMQ.js.map → network-3ZU7UBDU.js.map} +0 -0
- /package/dist/{price-TTQWI672.js.map → price-WCCXWPDM.js.map} +0 -0
- /package/dist/{research-J3HYU3N6.js.map → research-QBKISW2M.js.map} +0 -0
- /package/dist/{research-NR4VC5LN.js.map → research-YJWSQS2A.js.map} +0 -0
- /package/dist/{session-NUPHC6ZN.js.map → session-FPCPCVQX.js.map} +0 -0
- /package/dist/{xmtp-JO7W6RFK.js.map → xmtp-ACB2W573.js.map} +0 -0
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
UNISWAP
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FWC57PT7.js";
|
|
4
4
|
import {
|
|
5
5
|
getAccount,
|
|
6
6
|
getPublicClient,
|
|
7
7
|
sendTxWithRetry,
|
|
8
8
|
waitForReceipt
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-XDBRKW7I.js";
|
|
10
10
|
import {
|
|
11
11
|
getChain
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-2LRC7I33.js";
|
|
13
13
|
import {
|
|
14
|
-
getUniswapApiKey
|
|
15
|
-
|
|
16
|
-
setVeniceApiKey
|
|
17
|
-
} from "./chunk-4EHI4SKM.js";
|
|
14
|
+
getUniswapApiKey
|
|
15
|
+
} from "./chunk-2W4KGGPU.js";
|
|
18
16
|
import {
|
|
19
17
|
UNISWAP_QUOTER_V2_ABI
|
|
20
18
|
} from "./chunk-D77JGXIV.js";
|
|
@@ -248,121 +246,6 @@ var UniswapProvider = class {
|
|
|
248
246
|
}
|
|
249
247
|
};
|
|
250
248
|
|
|
251
|
-
// src/lib/venice.ts
|
|
252
|
-
var VENICE_API_BASE = "https://api.venice.ai/api/v1";
|
|
253
|
-
async function provisionApiKey() {
|
|
254
|
-
const account = getAccount();
|
|
255
|
-
const tokenRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {
|
|
256
|
-
signal: AbortSignal.timeout(15e3)
|
|
257
|
-
});
|
|
258
|
-
if (!tokenRes.ok) {
|
|
259
|
-
throw new Error(`Failed to get validation token: ${tokenRes.status} ${tokenRes.statusText}`);
|
|
260
|
-
}
|
|
261
|
-
const tokenData = await tokenRes.json();
|
|
262
|
-
const token = tokenData?.data?.token;
|
|
263
|
-
if (!token) {
|
|
264
|
-
throw new Error("Venice API returned no validation token");
|
|
265
|
-
}
|
|
266
|
-
const signature = await account.signMessage({ message: token });
|
|
267
|
-
const keyRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {
|
|
268
|
-
method: "POST",
|
|
269
|
-
headers: {
|
|
270
|
-
"Content-Type": "application/json"
|
|
271
|
-
},
|
|
272
|
-
signal: AbortSignal.timeout(15e3),
|
|
273
|
-
body: JSON.stringify({
|
|
274
|
-
address: account.address,
|
|
275
|
-
signature,
|
|
276
|
-
token,
|
|
277
|
-
apiKeyType: "INFERENCE",
|
|
278
|
-
description: "Sherwood syndicate agent"
|
|
279
|
-
})
|
|
280
|
-
});
|
|
281
|
-
if (!keyRes.ok) {
|
|
282
|
-
const body = await keyRes.text();
|
|
283
|
-
throw new Error(`Failed to generate API key: ${keyRes.status} ${body}`);
|
|
284
|
-
}
|
|
285
|
-
const keyData = await keyRes.json();
|
|
286
|
-
const apiKey = keyData?.data?.apiKey;
|
|
287
|
-
if (!apiKey) {
|
|
288
|
-
throw new Error("Venice API returned no API key");
|
|
289
|
-
}
|
|
290
|
-
setVeniceApiKey(apiKey);
|
|
291
|
-
return apiKey;
|
|
292
|
-
}
|
|
293
|
-
async function checkApiKeyValid() {
|
|
294
|
-
const apiKey = getVeniceApiKey();
|
|
295
|
-
if (!apiKey) return false;
|
|
296
|
-
try {
|
|
297
|
-
const res = await fetch(`${VENICE_API_BASE}/models`, {
|
|
298
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
299
|
-
signal: AbortSignal.timeout(15e3)
|
|
300
|
-
});
|
|
301
|
-
return res.ok;
|
|
302
|
-
} catch {
|
|
303
|
-
return false;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
async function chatCompletion(opts) {
|
|
307
|
-
const apiKey = getVeniceApiKey();
|
|
308
|
-
if (!apiKey) {
|
|
309
|
-
throw new Error("No Venice API key configured. Run 'sherwood venice provision' first.");
|
|
310
|
-
}
|
|
311
|
-
const body = {
|
|
312
|
-
model: opts.model,
|
|
313
|
-
messages: opts.messages
|
|
314
|
-
};
|
|
315
|
-
if (opts.temperature !== void 0) body.temperature = opts.temperature;
|
|
316
|
-
if (opts.maxTokens !== void 0) body.max_tokens = opts.maxTokens;
|
|
317
|
-
const veniceParams = {};
|
|
318
|
-
if (opts.enableWebSearch) veniceParams.enable_web_search = "on";
|
|
319
|
-
if (opts.disableThinking) veniceParams.disable_thinking = true;
|
|
320
|
-
if (Object.keys(veniceParams).length > 0) body.venice_parameters = veniceParams;
|
|
321
|
-
const res = await fetch(`${VENICE_API_BASE}/chat/completions`, {
|
|
322
|
-
method: "POST",
|
|
323
|
-
headers: {
|
|
324
|
-
"Content-Type": "application/json",
|
|
325
|
-
Authorization: `Bearer ${apiKey}`
|
|
326
|
-
},
|
|
327
|
-
signal: AbortSignal.timeout(12e4),
|
|
328
|
-
// inference can be slow
|
|
329
|
-
body: JSON.stringify(body)
|
|
330
|
-
});
|
|
331
|
-
if (!res.ok) {
|
|
332
|
-
const errBody = await res.text();
|
|
333
|
-
throw new Error(`Venice inference failed: ${res.status} ${errBody}`);
|
|
334
|
-
}
|
|
335
|
-
const data = await res.json();
|
|
336
|
-
const choice = data.choices?.[0];
|
|
337
|
-
if (!choice) {
|
|
338
|
-
throw new Error("Venice returned no choices");
|
|
339
|
-
}
|
|
340
|
-
return {
|
|
341
|
-
content: choice.message?.content ?? "",
|
|
342
|
-
model: data.model ?? opts.model,
|
|
343
|
-
usage: {
|
|
344
|
-
promptTokens: data.usage?.prompt_tokens ?? 0,
|
|
345
|
-
completionTokens: data.usage?.completion_tokens ?? 0,
|
|
346
|
-
totalTokens: data.usage?.total_tokens ?? 0
|
|
347
|
-
}
|
|
348
|
-
};
|
|
349
|
-
}
|
|
350
|
-
async function listModels() {
|
|
351
|
-
const apiKey = getVeniceApiKey();
|
|
352
|
-
if (!apiKey) {
|
|
353
|
-
throw new Error("No Venice API key configured. Run 'sherwood venice provision' first.");
|
|
354
|
-
}
|
|
355
|
-
const res = await fetch(`${VENICE_API_BASE}/models`, {
|
|
356
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
357
|
-
signal: AbortSignal.timeout(15e3)
|
|
358
|
-
});
|
|
359
|
-
if (!res.ok) {
|
|
360
|
-
throw new Error(`Failed to list Venice models: ${res.status} ${res.statusText}`);
|
|
361
|
-
}
|
|
362
|
-
const data = await res.json();
|
|
363
|
-
return (data.data ?? []).map((m) => m.id);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
249
|
// src/lib/quote.ts
|
|
367
250
|
import { encodeFunctionData, decodeFunctionResult, concat, pad, numberToHex } from "viem";
|
|
368
251
|
async function getQuote(params) {
|
|
@@ -434,13 +317,9 @@ async function getMultiHopQuote(params) {
|
|
|
434
317
|
|
|
435
318
|
export {
|
|
436
319
|
UniswapProvider,
|
|
437
|
-
provisionApiKey,
|
|
438
|
-
checkApiKeyValid,
|
|
439
|
-
chatCompletion,
|
|
440
|
-
listModels,
|
|
441
320
|
getQuote,
|
|
442
321
|
applySlippage,
|
|
443
322
|
encodeSwapPath,
|
|
444
323
|
getMultiHopQuote
|
|
445
324
|
};
|
|
446
|
-
//# sourceMappingURL=chunk-
|
|
325
|
+
//# sourceMappingURL=chunk-WMZEOR5W.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/uniswap.ts","../src/lib/quote.ts"],"sourcesContent":["/**\n * Uniswap Trading API provider — swaps on Base via the hosted API.\n *\n * Uses the 3-step flow:\n * 1. POST /check_approval → check/submit token approval\n * 2. POST /quote → get optimal route + executable quote\n * 3. POST /swap → get transaction calldata to sign\n *\n * API key required — set via `sherwood config set --uniswap-api-key <key>`\n * or UNISWAP_API_KEY env var.\n *\n * Docs: https://docs.uniswap.org/api/trading-api\n * Key: https://developers.uniswap.org/\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { isAddress, isHex, formatUnits } from \"viem\";\nimport { base, baseSepolia } from \"viem/chains\";\nimport type { TradingProvider, ProviderInfo, SwapParams, SwapQuoteParams, TxResult, SwapQuote } from \"../types.js\";\nimport { getPublicClient, getAccount, writeContractWithRetry, sendTxWithRetry, waitForReceipt } from \"../lib/client.js\";\nimport { getChain } from \"../lib/network.js\";\nimport { getUniswapApiKey } from \"../lib/config.js\";\n\nconst API_BASE = \"https://trade-api.gateway.uniswap.org/v1\";\n\n// ── API Types ──\n\ninterface ApprovalResponse {\n approval: {\n to: Address;\n from: Address;\n data: Hex;\n value: string;\n chainId: number;\n } | null;\n}\n\n// CLASSIC route quote\ninterface ClassicQuote {\n routing: \"CLASSIC\" | \"WRAP\" | \"UNWRAP\";\n quote: {\n input: { token: string; amount: string };\n output: { token: string; amount: string };\n slippage: number;\n route: unknown[];\n gasFee: string;\n gasFeeUSD: string;\n gasUseEstimate: string;\n };\n permitData: Record<string, unknown> | null;\n}\n\n// UniswapX route quote (PRIORITY on Base)\ninterface UniswapXQuote {\n routing: \"DUTCH_V2\" | \"DUTCH_V3\" | \"PRIORITY\";\n quote: {\n orderInfo: {\n outputs: Array<{\n token: string;\n startAmount: string;\n endAmount: string;\n recipient: string;\n }>;\n input: { token: string; startAmount: string; endAmount: string };\n deadline: number;\n nonce: string;\n };\n encodedOrder: string;\n orderHash: string;\n };\n permitData: Record<string, unknown> | null;\n}\n\ntype QuoteResponse = ClassicQuote | UniswapXQuote;\n\ninterface SwapResponse {\n swap: {\n to: Address;\n from: Address;\n data: Hex;\n value: string;\n chainId: number;\n gasLimit?: string;\n };\n}\n\n// ── Helpers ──\n\nfunction getApiKey(): string {\n const key = getUniswapApiKey();\n if (!key) {\n throw new Error(\n \"Uniswap API key not configured. Run 'sherwood config set --uniswap-api-key <key>' \" +\n \"or set UNISWAP_API_KEY env var.\\n\" +\n \"Get your key at https://developers.uniswap.org/\",\n );\n }\n return key;\n}\n\nfunction apiHeaders(): Record<string, string> {\n return {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": getApiKey(),\n \"x-universal-router-version\": \"2.0\",\n };\n}\n\nfunction isUniswapXRouting(routing: string): boolean {\n return routing === \"DUTCH_V2\" || routing === \"DUTCH_V3\" || routing === \"PRIORITY\";\n}\n\nfunction getOutputAmount(q: QuoteResponse): string {\n if (isUniswapXRouting(q.routing)) {\n const ux = q as UniswapXQuote;\n const firstOutput = ux.quote.orderInfo.outputs[0];\n if (!firstOutput) throw new Error(\"UniswapX quote has no outputs\");\n return firstOutput.startAmount; // best-case fill\n }\n return (q as ClassicQuote).quote.output.amount;\n}\n\nasync function fetchWithRetry(\n url: string,\n init: RequestInit,\n maxRetries = 3,\n): Promise<Response> {\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const response = await fetch(url, {\n ...init,\n signal: AbortSignal.timeout(30_000),\n });\n if (response.status !== 429 && response.status < 500) return response;\n if (attempt === maxRetries) return response;\n\n const delay = Math.min(200 * Math.pow(2, attempt) + Math.random() * 100, 10000);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n throw new Error(\"Unreachable\");\n}\n\n// ── Provider ──\n\nexport class UniswapProvider implements TradingProvider {\n info(): ProviderInfo {\n return {\n name: \"uniswap\",\n type: \"trading\",\n capabilities: [\n \"swap.exact-input\",\n \"swap.quote\",\n \"swap.check-approval\",\n ],\n supportedChains: [base, baseSepolia],\n };\n }\n\n /**\n * Get a quote from the Uniswap Trading API.\n * Returns the optimal route (CLASSIC, PRIORITY, or UniswapX).\n */\n async quote(params: SwapQuoteParams): Promise<SwapQuote> {\n const account = getAccount();\n const chainId = getChain().id;\n\n const body = {\n swapper: account.address,\n tokenIn: params.tokenIn,\n tokenOut: params.tokenOut,\n tokenInChainId: String(chainId),\n tokenOutChainId: String(chainId),\n amount: params.amountIn.toString(),\n type: \"EXACT_INPUT\",\n slippageTolerance: 0.5,\n routingPreference: \"BEST_PRICE\",\n };\n\n const res = await fetchWithRetry(`${API_BASE}/quote`, {\n method: \"POST\",\n headers: apiHeaders(),\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`Uniswap quote failed (${res.status}): ${err}`);\n }\n\n const data = (await res.json()) as QuoteResponse;\n const amountOut = BigInt(getOutputAmount(data));\n\n return {\n amountOut,\n priceImpact: 0,\n route: `${data.routing}: ${params.tokenIn.slice(0, 8)}→${params.tokenOut.slice(0, 8)}`,\n };\n }\n\n /**\n * Get a full quote response (preserving the raw API response for swap execution).\n */\n async fullQuote(params: {\n tokenIn: Address;\n tokenOut: Address;\n amountIn: bigint;\n slippageTolerance?: number;\n }): Promise<{ quoteResponse: QuoteResponse; amountOut: bigint; routing: string }> {\n const account = getAccount();\n const chainId = getChain().id;\n\n const body = {\n swapper: account.address,\n tokenIn: params.tokenIn,\n tokenOut: params.tokenOut,\n tokenInChainId: String(chainId),\n tokenOutChainId: String(chainId),\n amount: params.amountIn.toString(),\n type: \"EXACT_INPUT\",\n slippageTolerance: params.slippageTolerance ?? 0.5,\n routingPreference: \"BEST_PRICE\",\n };\n\n const res = await fetchWithRetry(`${API_BASE}/quote`, {\n method: \"POST\",\n headers: apiHeaders(),\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`Uniswap quote failed (${res.status}): ${err}`);\n }\n\n const quoteResponse = (await res.json()) as QuoteResponse;\n const amountOut = BigInt(getOutputAmount(quoteResponse));\n return { quoteResponse, amountOut, routing: quoteResponse.routing };\n }\n\n /**\n * Check and handle token approval for Uniswap.\n * Uses the Trading API's /check_approval endpoint.\n */\n async checkApproval(params: {\n token: Address;\n amount: bigint;\n }): Promise<void> {\n const account = getAccount();\n const chainId = getChain().id;\n const client = getPublicClient();\n\n const res = await fetchWithRetry(`${API_BASE}/check_approval`, {\n method: \"POST\",\n headers: apiHeaders(),\n body: JSON.stringify({\n walletAddress: account.address,\n token: params.token,\n amount: params.amount.toString(),\n chainId,\n }),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`Approval check failed (${res.status}): ${err}`);\n }\n\n const data = (await res.json()) as ApprovalResponse;\n\n if (data.approval) {\n // API returns a ready-to-send transaction — use sendTxWithRetry for nonce safety\n const approvalHash = await sendTxWithRetry({\n to: data.approval.to,\n data: data.approval.data,\n value: BigInt(data.approval.value || \"0\"),\n account,\n chain: getChain(),\n });\n await waitForReceipt(approvalHash);\n }\n }\n\n /**\n * Execute a swap via the Uniswap Trading API.\n *\n * Full flow: check_approval → quote → swap → sign & broadcast.\n */\n async swap(params: SwapParams): Promise<TxResult> {\n const account = getAccount();\n const client = getPublicClient();\n\n // 1. Check approval (skip for native ETH)\n const ETH_ADDRESS = \"0x0000000000000000000000000000000000000000\" as Address;\n if (params.tokenIn !== ETH_ADDRESS) {\n await this.checkApproval({\n token: params.tokenIn,\n amount: params.amountIn,\n });\n }\n\n // 2. Get quote\n const { quoteResponse } = await this.fullQuote({\n tokenIn: params.tokenIn,\n tokenOut: params.tokenOut,\n amountIn: params.amountIn,\n slippageTolerance: params.slippageTolerance ?? 0.5,\n });\n\n // 3. Prepare swap request — routing-aware permitData handling\n const quoteRaw = quoteResponse as unknown as Record<string, unknown>;\n const { permitData, ...cleanQuote } = quoteRaw;\n const swapRequest: Record<string, unknown> = { ...cleanQuote };\n\n // Sign permitData if present (required for both CLASSIC and UniswapX).\n // For CLASSIC routes using Permit2 (PermitSingle): include BOTH permitData + signature.\n // For UniswapX routes: include signature only (order-level signing, no permitData in body).\n if (permitData && typeof permitData === \"object\") {\n const typedData = permitData as {\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n values: Record<string, unknown>;\n };\n const primaryType =\n Object.keys(typedData.types).find((k) => k !== \"EIP712Domain\") ?? \"PermitSingle\";\n const signature = await account.signTypedData({\n domain: typedData.domain as Record<string, unknown>,\n types: typedData.types as Record<string, Array<{ name: string; type: string }>>,\n primaryType,\n message: typedData.values,\n });\n swapRequest.signature = signature;\n // CLASSIC routes: /swap requires both permitData and signature\n // UniswapX routes: /swap requires signature only (order is in quote body)\n if (!isUniswapXRouting(quoteResponse.routing)) {\n swapRequest.permitData = permitData;\n }\n }\n\n // 4. Get swap transaction\n const swapRes = await fetchWithRetry(`${API_BASE}/swap`, {\n method: \"POST\",\n headers: apiHeaders(),\n body: JSON.stringify(swapRequest),\n });\n\n if (!swapRes.ok) {\n const err = await swapRes.text();\n throw new Error(`Uniswap swap failed (${swapRes.status}): ${err}`);\n }\n\n const swapData = (await swapRes.json()) as SwapResponse;\n\n // 5. Validate before broadcasting\n if (!swapData.swap?.data || swapData.swap.data === (\"\" as Hex) || swapData.swap.data === \"0x\") {\n throw new Error(\"Empty swap data — quote may have expired. Try again.\");\n }\n if (!isAddress(swapData.swap.to) || !isAddress(swapData.swap.from)) {\n throw new Error(\"Invalid address in swap response\");\n }\n\n // 6. Sign and broadcast with retry-aware sender\n // Apply a 1.5x buffer to the API's gasLimit: the Uniswap API under-estimates for WETH\n // and other non-USDC inputs where PermitSingle+transfer adds overhead.\n const gasLimit = swapData.swap.gasLimit\n ? (BigInt(swapData.swap.gasLimit) * 150n) / 100n\n : undefined;\n const hash = await sendTxWithRetry({\n to: swapData.swap.to,\n data: swapData.swap.data,\n value: BigInt(swapData.swap.value || \"0\"),\n gas: gasLimit,\n account,\n chain: getChain(),\n });\n\n const receipt = await waitForReceipt(hash);\n return {\n hash,\n success: receipt.status === \"success\",\n gasUsed: receipt.gasUsed,\n };\n }\n}\n","/**\n * Uniswap V3 Quoter V2 integration for swap quotes.\n *\n * quoteExactInputSingle is NOT a view function — it reverts internally\n * after computing the quote. Must use eth_call to get the return data.\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeFunctionData, decodeFunctionResult, concat, pad, numberToHex } from \"viem\";\nimport { getPublicClient } from \"./client.js\";\nimport { UNISWAP_QUOTER_V2_ABI } from \"./abis.js\";\nimport { UNISWAP } from \"./addresses.js\";\n\nexport interface QuoteResult {\n amountOut: bigint;\n sqrtPriceX96After: bigint;\n gasEstimate: bigint;\n}\n\n/**\n * Get a swap quote from Uniswap Quoter V2.\n */\nexport async function getQuote(params: {\n tokenIn: Address;\n tokenOut: Address;\n amountIn: bigint;\n fee: number;\n}): Promise<QuoteResult> {\n const client = getPublicClient();\n\n const calldata = encodeFunctionData({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInputSingle\",\n args: [\n {\n tokenIn: params.tokenIn,\n tokenOut: params.tokenOut,\n amountIn: params.amountIn,\n fee: params.fee,\n sqrtPriceLimitX96: 0n,\n },\n ],\n });\n\n const { data } = await client.call({\n to: UNISWAP().QUOTER_V2,\n data: calldata,\n });\n\n if (!data) {\n throw new Error(\"Quoter returned no data — pool may not exist for this pair/fee\");\n }\n\n const [amountOut, sqrtPriceX96After, , gasEstimate] = decodeFunctionResult({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInputSingle\",\n data,\n }) as [bigint, bigint, number, bigint];\n\n return { amountOut, sqrtPriceX96After, gasEstimate };\n}\n\n/**\n * Apply slippage tolerance to a quote amount.\n * Returns the minimum acceptable output amount.\n */\nexport function applySlippage(amountOut: bigint, slippageBps: number): bigint {\n return (amountOut * BigInt(10000 - slippageBps)) / 10000n;\n}\n\n/**\n * Encode a Uniswap V3 multi-hop swap path.\n * Format: abi.encodePacked(address, uint24, address, uint24, address, ...)\n */\nexport function encodeSwapPath(tokens: Address[], fees: number[]): Hex {\n if (tokens.length < 2 || fees.length !== tokens.length - 1) {\n throw new Error(\"Invalid path: need at least 2 tokens and (tokens-1) fees\");\n }\n\n const parts: Hex[] = [];\n for (let i = 0; i < tokens.length; i++) {\n // Address: 20 bytes (no padding)\n parts.push(tokens[i].toLowerCase() as Hex);\n if (i < fees.length) {\n // Fee: 3 bytes (uint24), left-padded to 3 bytes\n parts.push(pad(numberToHex(fees[i]), { size: 3 }) as Hex);\n }\n }\n return concat(parts);\n}\n\n/**\n * Get a multi-hop swap quote from Uniswap Quoter V2.\n */\nexport async function getMultiHopQuote(params: {\n path: Hex;\n amountIn: bigint;\n}): Promise<QuoteResult> {\n const client = getPublicClient();\n\n const calldata = encodeFunctionData({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInput\",\n args: [params.path, params.amountIn],\n });\n\n const { data } = await client.call({\n to: UNISWAP().QUOTER_V2,\n data: calldata,\n });\n\n if (!data) {\n throw new Error(\"Quoter returned no data — pool may not exist for this path\");\n }\n\n const [amountOut, , , gasEstimate] = decodeFunctionResult({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInput\",\n data,\n }) as [bigint, bigint[], number[], bigint];\n\n return { amountOut, sqrtPriceX96After: 0n, gasEstimate };\n}\n\n/** Token decimals for display purposes. */\nexport const TOKEN_DECIMALS: Record<string, number> = {\n USDC: 6,\n WETH: 18,\n cbETH: 18,\n wstETH: 18,\n cbBTC: 8,\n DAI: 18,\n AERO: 18,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAgBA,SAAS,iBAAqC;AAC9C,SAAS,MAAM,mBAAmB;AAMlC,IAAM,WAAW;AAiEjB,SAAS,YAAoB;AAC3B,QAAM,MAAM,iBAAiB;AAC7B,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IAGF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,aAAqC;AAC5C,SAAO;AAAA,IACL,gBAAgB;AAAA,IAChB,aAAa,UAAU;AAAA,IACvB,8BAA8B;AAAA,EAChC;AACF;AAEA,SAAS,kBAAkB,SAA0B;AACnD,SAAO,YAAY,cAAc,YAAY,cAAc,YAAY;AACzE;AAEA,SAAS,gBAAgB,GAA0B;AACjD,MAAI,kBAAkB,EAAE,OAAO,GAAG;AAChC,UAAM,KAAK;AACX,UAAM,cAAc,GAAG,MAAM,UAAU,QAAQ,CAAC;AAChD,QAAI,CAAC,YAAa,OAAM,IAAI,MAAM,+BAA+B;AACjE,WAAO,YAAY;AAAA,EACrB;AACA,SAAQ,EAAmB,MAAM,OAAO;AAC1C;AAEA,eAAe,eACb,KACA,MACA,aAAa,GACM;AACnB,WAAS,UAAU,GAAG,WAAW,YAAY,WAAW;AACtD,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,GAAG;AAAA,MACH,QAAQ,YAAY,QAAQ,GAAM;AAAA,IACpC,CAAC;AACD,QAAI,SAAS,WAAW,OAAO,SAAS,SAAS,IAAK,QAAO;AAC7D,QAAI,YAAY,WAAY,QAAO;AAEnC,UAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,GAAG,OAAO,IAAI,KAAK,OAAO,IAAI,KAAK,GAAK;AAC9E,UAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,CAAC;AAAA,EAC3D;AACA,QAAM,IAAI,MAAM,aAAa;AAC/B;AAIO,IAAM,kBAAN,MAAiD;AAAA,EACtD,OAAqB;AACnB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,MAAM;AAAA,MACN,cAAc;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,iBAAiB,CAAC,MAAM,WAAW;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,MAAM,QAA6C;AACvD,UAAM,UAAU,WAAW;AAC3B,UAAM,UAAU,SAAS,EAAE;AAE3B,UAAM,OAAO;AAAA,MACX,SAAS,QAAQ;AAAA,MACjB,SAAS,OAAO;AAAA,MAChB,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO,OAAO;AAAA,MAC9B,iBAAiB,OAAO,OAAO;AAAA,MAC/B,QAAQ,OAAO,SAAS,SAAS;AAAA,MACjC,MAAM;AAAA,MACN,mBAAmB;AAAA,MACnB,mBAAmB;AAAA,IACrB;AAEA,UAAM,MAAM,MAAM,eAAe,GAAG,QAAQ,UAAU;AAAA,MACpD,QAAQ;AAAA,MACR,SAAS,WAAW;AAAA,MACpB,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,MAAM,MAAM,IAAI,KAAK;AAC3B,YAAM,IAAI,MAAM,yBAAyB,IAAI,MAAM,MAAM,GAAG,EAAE;AAAA,IAChE;AAEA,UAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,UAAM,YAAY,OAAO,gBAAgB,IAAI,CAAC;AAE9C,WAAO;AAAA,MACL;AAAA,MACA,aAAa;AAAA,MACb,OAAO,GAAG,KAAK,OAAO,KAAK,OAAO,QAAQ,MAAM,GAAG,CAAC,CAAC,SAAI,OAAO,SAAS,MAAM,GAAG,CAAC,CAAC;AAAA,IACtF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,QAKkE;AAChF,UAAM,UAAU,WAAW;AAC3B,UAAM,UAAU,SAAS,EAAE;AAE3B,UAAM,OAAO;AAAA,MACX,SAAS,QAAQ;AAAA,MACjB,SAAS,OAAO;AAAA,MAChB,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO,OAAO;AAAA,MAC9B,iBAAiB,OAAO,OAAO;AAAA,MAC/B,QAAQ,OAAO,SAAS,SAAS;AAAA,MACjC,MAAM;AAAA,MACN,mBAAmB,OAAO,qBAAqB;AAAA,MAC/C,mBAAmB;AAAA,IACrB;AAEA,UAAM,MAAM,MAAM,eAAe,GAAG,QAAQ,UAAU;AAAA,MACpD,QAAQ;AAAA,MACR,SAAS,WAAW;AAAA,MACpB,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,MAAM,MAAM,IAAI,KAAK;AAC3B,YAAM,IAAI,MAAM,yBAAyB,IAAI,MAAM,MAAM,GAAG,EAAE;AAAA,IAChE;AAEA,UAAM,gBAAiB,MAAM,IAAI,KAAK;AACtC,UAAM,YAAY,OAAO,gBAAgB,aAAa,CAAC;AACvD,WAAO,EAAE,eAAe,WAAW,SAAS,cAAc,QAAQ;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAAc,QAGF;AAChB,UAAM,UAAU,WAAW;AAC3B,UAAM,UAAU,SAAS,EAAE;AAC3B,UAAM,SAAS,gBAAgB;AAE/B,UAAM,MAAM,MAAM,eAAe,GAAG,QAAQ,mBAAmB;AAAA,MAC7D,QAAQ;AAAA,MACR,SAAS,WAAW;AAAA,MACpB,MAAM,KAAK,UAAU;AAAA,QACnB,eAAe,QAAQ;AAAA,QACvB,OAAO,OAAO;AAAA,QACd,QAAQ,OAAO,OAAO,SAAS;AAAA,QAC/B;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,MAAM,MAAM,IAAI,KAAK;AAC3B,YAAM,IAAI,MAAM,0BAA0B,IAAI,MAAM,MAAM,GAAG,EAAE;AAAA,IACjE;AAEA,UAAM,OAAQ,MAAM,IAAI,KAAK;AAE7B,QAAI,KAAK,UAAU;AAEjB,YAAM,eAAe,MAAM,gBAAgB;AAAA,QACzC,IAAI,KAAK,SAAS;AAAA,QAClB,MAAM,KAAK,SAAS;AAAA,QACpB,OAAO,OAAO,KAAK,SAAS,SAAS,GAAG;AAAA,QACxC;AAAA,QACA,OAAO,SAAS;AAAA,MAClB,CAAC;AACD,YAAM,eAAe,YAAY;AAAA,IACnC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,KAAK,QAAuC;AAChD,UAAM,UAAU,WAAW;AAC3B,UAAM,SAAS,gBAAgB;AAG/B,UAAM,cAAc;AACpB,QAAI,OAAO,YAAY,aAAa;AAClC,YAAM,KAAK,cAAc;AAAA,QACvB,OAAO,OAAO;AAAA,QACd,QAAQ,OAAO;AAAA,MACjB,CAAC;AAAA,IACH;AAGA,UAAM,EAAE,cAAc,IAAI,MAAM,KAAK,UAAU;AAAA,MAC7C,SAAS,OAAO;AAAA,MAChB,UAAU,OAAO;AAAA,MACjB,UAAU,OAAO;AAAA,MACjB,mBAAmB,OAAO,qBAAqB;AAAA,IACjD,CAAC;AAGD,UAAM,WAAW;AACjB,UAAM,EAAE,YAAY,GAAG,WAAW,IAAI;AACtC,UAAM,cAAuC,EAAE,GAAG,WAAW;AAK7D,QAAI,cAAc,OAAO,eAAe,UAAU;AAChD,YAAM,YAAY;AAKlB,YAAM,cACJ,OAAO,KAAK,UAAU,KAAK,EAAE,KAAK,CAAC,MAAM,MAAM,cAAc,KAAK;AACpE,YAAM,YAAY,MAAM,QAAQ,cAAc;AAAA,QAC5C,QAAQ,UAAU;AAAA,QAClB,OAAO,UAAU;AAAA,QACjB;AAAA,QACA,SAAS,UAAU;AAAA,MACrB,CAAC;AACD,kBAAY,YAAY;AAGxB,UAAI,CAAC,kBAAkB,cAAc,OAAO,GAAG;AAC7C,oBAAY,aAAa;AAAA,MAC3B;AAAA,IACF;AAGA,UAAM,UAAU,MAAM,eAAe,GAAG,QAAQ,SAAS;AAAA,MACvD,QAAQ;AAAA,MACR,SAAS,WAAW;AAAA,MACpB,MAAM,KAAK,UAAU,WAAW;AAAA,IAClC,CAAC;AAED,QAAI,CAAC,QAAQ,IAAI;AACf,YAAM,MAAM,MAAM,QAAQ,KAAK;AAC/B,YAAM,IAAI,MAAM,wBAAwB,QAAQ,MAAM,MAAM,GAAG,EAAE;AAAA,IACnE;AAEA,UAAM,WAAY,MAAM,QAAQ,KAAK;AAGrC,QAAI,CAAC,SAAS,MAAM,QAAQ,SAAS,KAAK,SAAU,MAAc,SAAS,KAAK,SAAS,MAAM;AAC7F,YAAM,IAAI,MAAM,2DAAsD;AAAA,IACxE;AACA,QAAI,CAAC,UAAU,SAAS,KAAK,EAAE,KAAK,CAAC,UAAU,SAAS,KAAK,IAAI,GAAG;AAClE,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACpD;AAKA,UAAM,WAAW,SAAS,KAAK,WAC1B,OAAO,SAAS,KAAK,QAAQ,IAAI,OAAQ,OAC1C;AACJ,UAAM,OAAO,MAAM,gBAAgB;AAAA,MACjC,IAAI,SAAS,KAAK;AAAA,MAClB,MAAM,SAAS,KAAK;AAAA,MACpB,OAAO,OAAO,SAAS,KAAK,SAAS,GAAG;AAAA,MACxC,KAAK;AAAA,MACL;AAAA,MACA,OAAO,SAAS;AAAA,IAClB,CAAC;AAED,UAAM,UAAU,MAAM,eAAe,IAAI;AACzC,WAAO;AAAA,MACL;AAAA,MACA,SAAS,QAAQ,WAAW;AAAA,MAC5B,SAAS,QAAQ;AAAA,IACnB;AAAA,EACF;AACF;;;ACrXA,SAAS,oBAAoB,sBAAsB,QAAQ,KAAK,mBAAmB;AAcnF,eAAsB,SAAS,QAKN;AACvB,QAAM,SAAS,gBAAgB;AAE/B,QAAM,WAAW,mBAAmB;AAAA,IAClC,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM;AAAA,MACJ;AAAA,QACE,SAAS,OAAO;AAAA,QAChB,UAAU,OAAO;AAAA,QACjB,UAAU,OAAO;AAAA,QACjB,KAAK,OAAO;AAAA,QACZ,mBAAmB;AAAA,MACrB;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,KAAK;AAAA,IACjC,IAAI,QAAQ,EAAE;AAAA,IACd,MAAM;AAAA,EACR,CAAC;AAED,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,qEAAgE;AAAA,EAClF;AAEA,QAAM,CAAC,WAAW,mBAAmB,EAAE,WAAW,IAAI,qBAAqB;AAAA,IACzE,KAAK;AAAA,IACL,cAAc;AAAA,IACd;AAAA,EACF,CAAC;AAED,SAAO,EAAE,WAAW,mBAAmB,YAAY;AACrD;AAMO,SAAS,cAAc,WAAmB,aAA6B;AAC5E,SAAQ,YAAY,OAAO,MAAQ,WAAW,IAAK;AACrD;AAMO,SAAS,eAAe,QAAmB,MAAqB;AACrE,MAAI,OAAO,SAAS,KAAK,KAAK,WAAW,OAAO,SAAS,GAAG;AAC1D,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AAEA,QAAM,QAAe,CAAC;AACtB,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AAEtC,UAAM,KAAK,OAAO,CAAC,EAAE,YAAY,CAAQ;AACzC,QAAI,IAAI,KAAK,QAAQ;AAEnB,YAAM,KAAK,IAAI,YAAY,KAAK,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAQ;AAAA,IAC1D;AAAA,EACF;AACA,SAAO,OAAO,KAAK;AACrB;AAKA,eAAsB,iBAAiB,QAGd;AACvB,QAAM,SAAS,gBAAgB;AAE/B,QAAM,WAAW,mBAAmB;AAAA,IAClC,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,OAAO,MAAM,OAAO,QAAQ;AAAA,EACrC,CAAC;AAED,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,KAAK;AAAA,IACjC,IAAI,QAAQ,EAAE;AAAA,IACd,MAAM;AAAA,EACR,CAAC;AAED,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,iEAA4D;AAAA,EAC9E;AAEA,QAAM,CAAC,WAAW,EAAE,EAAE,WAAW,IAAI,qBAAqB;AAAA,IACxD,KAAK;AAAA,IACL,cAAc;AAAA,IACd;AAAA,EACF,CAAC;AAED,SAAO,EAAE,WAAW,mBAAmB,IAAI,YAAY;AACzD;","names":[]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getChain,
|
|
3
3
|
getRpcUrls
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2LRC7I33.js";
|
|
5
5
|
import {
|
|
6
6
|
loadConfig
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-2W4KGGPU.js";
|
|
8
8
|
|
|
9
9
|
// src/lib/client.ts
|
|
10
10
|
import { createPublicClient, createWalletClient, fallback, http } from "viem";
|
|
@@ -489,4 +489,4 @@ export {
|
|
|
489
489
|
writeContractWithRetry,
|
|
490
490
|
waitForReceipt
|
|
491
491
|
};
|
|
492
|
-
//# sourceMappingURL=chunk-
|
|
492
|
+
//# sourceMappingURL=chunk-XDBRKW7I.js.map
|