@sherwoodagent/cli 0.18.4 → 0.19.0
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/{chat-7CB4YGGP.js → chat-MUUC5L5W.js} +7 -7
- package/dist/{chunk-TWX6FSCM.js → chunk-B4BMCXWK.js} +11 -1
- package/dist/chunk-B4BMCXWK.js.map +1 -0
- package/dist/chunk-DCT3IDBS.js +458 -0
- package/dist/chunk-DCT3IDBS.js.map +1 -0
- package/dist/{chunk-MJMWA4LY.js → chunk-FEDSWXSD.js} +2 -2
- package/dist/{chunk-FR4LYDPJ.js → chunk-G2RQLZZI.js} +115 -4
- package/dist/chunk-G2RQLZZI.js.map +1 -0
- package/dist/{chunk-L24NGLKY.js → chunk-HRA2KPGW.js} +8 -3
- package/dist/{chunk-L24NGLKY.js.map → chunk-HRA2KPGW.js.map} +1 -1
- package/dist/{chunk-ARD44YTT.js → chunk-VZZ2V6EM.js} +5 -5
- package/dist/{chunk-TPE6ZTUI.js → chunk-W76CHVD3.js} +59 -5
- package/dist/chunk-W76CHVD3.js.map +1 -0
- package/dist/{chunk-5ZC2A7UP.js → chunk-WHCXQBPS.js} +4 -4
- package/dist/{chunk-Z2PNK3CC.js → chunk-ZXV4TBPE.js} +2 -2
- package/dist/client-I56MIQAM.js +21 -0
- package/dist/{config-LW4Q6NK5.js → config-2VMLHIXD.js} +6 -2
- package/dist/eas-YZF6MN65.js +29 -0
- package/dist/{governor-E6AU3UWV.js → governor-ZWKGLGMG.js} +6 -6
- package/dist/index.js +70 -296
- package/dist/index.js.map +1 -1
- package/dist/{network-C32G5D3J.js → network-3MVRM7O4.js} +3 -3
- package/dist/research-HC2UOLFT.js +14 -0
- package/dist/research-HC2UOLFT.js.map +1 -0
- package/dist/{research-MKI4RS2F.js → research-VZKLOTMU.js} +7 -7
- package/dist/{session-RAFLL5BD.js → session-X3QFFCJ7.js} +10 -10
- package/dist/trade-YCBFXOB3.js +874 -0
- package/dist/trade-YCBFXOB3.js.map +1 -0
- package/dist/{xmtp-ATRMY76G.js → xmtp-IH57GYSR.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-FR4LYDPJ.js.map +0 -1
- package/dist/chunk-TPE6ZTUI.js.map +0 -1
- package/dist/chunk-TWX6FSCM.js.map +0 -1
- package/dist/eas-DOC4QKDF.js +0 -23
- package/dist/research-V63URK4C.js +0 -14
- /package/dist/{chat-7CB4YGGP.js.map → chat-MUUC5L5W.js.map} +0 -0
- /package/dist/{chunk-MJMWA4LY.js.map → chunk-FEDSWXSD.js.map} +0 -0
- /package/dist/{chunk-ARD44YTT.js.map → chunk-VZZ2V6EM.js.map} +0 -0
- /package/dist/{chunk-5ZC2A7UP.js.map → chunk-WHCXQBPS.js.map} +0 -0
- /package/dist/{chunk-Z2PNK3CC.js.map → chunk-ZXV4TBPE.js.map} +0 -0
- /package/dist/{config-LW4Q6NK5.js.map → client-I56MIQAM.js.map} +0 -0
- /package/dist/{eas-DOC4QKDF.js.map → config-2VMLHIXD.js.map} +0 -0
- /package/dist/{governor-E6AU3UWV.js.map → eas-YZF6MN65.js.map} +0 -0
- /package/dist/{network-C32G5D3J.js.map → governor-ZWKGLGMG.js.map} +0 -0
- /package/dist/{research-V63URK4C.js.map → network-3MVRM7O4.js.map} +0 -0
- /package/dist/{research-MKI4RS2F.js.map → research-VZKLOTMU.js.map} +0 -0
- /package/dist/{session-RAFLL5BD.js.map → session-X3QFFCJ7.js.map} +0 -0
- /package/dist/{xmtp-ATRMY76G.js.map → xmtp-IH57GYSR.js.map} +0 -0
|
@@ -2,22 +2,22 @@ import {
|
|
|
2
2
|
getTextRecord,
|
|
3
3
|
resolveSyndicate,
|
|
4
4
|
setTextRecord
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-VZZ2V6EM.js";
|
|
6
|
+
import "./chunk-W76CHVD3.js";
|
|
7
7
|
import {
|
|
8
8
|
getAccount
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-HRA2KPGW.js";
|
|
10
|
+
import "./chunk-FEDSWXSD.js";
|
|
11
11
|
import {
|
|
12
12
|
cacheGroupId,
|
|
13
13
|
getCachedGroupId
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-B4BMCXWK.js";
|
|
15
15
|
|
|
16
16
|
// src/commands/chat.ts
|
|
17
17
|
import chalk from "chalk";
|
|
18
18
|
import ora from "ora";
|
|
19
19
|
async function loadXmtp() {
|
|
20
|
-
return import("./xmtp-
|
|
20
|
+
return import("./xmtp-IH57GYSR.js");
|
|
21
21
|
}
|
|
22
22
|
function formatTimestamp(date) {
|
|
23
23
|
return `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}`;
|
|
@@ -352,4 +352,4 @@ function registerChatCommands(program) {
|
|
|
352
352
|
export {
|
|
353
353
|
registerChatCommands
|
|
354
354
|
};
|
|
355
|
-
//# sourceMappingURL=chat-
|
|
355
|
+
//# sourceMappingURL=chat-MUUC5L5W.js.map
|
|
@@ -47,6 +47,14 @@ function setPrivateKey(key) {
|
|
|
47
47
|
function getPrivateKey() {
|
|
48
48
|
return loadConfig().privateKey;
|
|
49
49
|
}
|
|
50
|
+
function setUniswapApiKey(apiKey) {
|
|
51
|
+
const config = loadConfig();
|
|
52
|
+
config.uniswapApiKey = apiKey;
|
|
53
|
+
saveConfig(config);
|
|
54
|
+
}
|
|
55
|
+
function getUniswapApiKey() {
|
|
56
|
+
return loadConfig().uniswapApiKey ?? process.env.UNISWAP_API_KEY;
|
|
57
|
+
}
|
|
50
58
|
function getConfigRpcUrl(network) {
|
|
51
59
|
return loadConfig().rpc?.[network];
|
|
52
60
|
}
|
|
@@ -88,6 +96,8 @@ export {
|
|
|
88
96
|
getAgentId,
|
|
89
97
|
setPrivateKey,
|
|
90
98
|
getPrivateKey,
|
|
99
|
+
setUniswapApiKey,
|
|
100
|
+
getUniswapApiKey,
|
|
91
101
|
getConfigRpcUrl,
|
|
92
102
|
setConfigRpcUrl,
|
|
93
103
|
getChainContracts,
|
|
@@ -95,4 +105,4 @@ export {
|
|
|
95
105
|
setNotifyTo,
|
|
96
106
|
setChainContract
|
|
97
107
|
};
|
|
98
|
-
//# sourceMappingURL=chunk-
|
|
108
|
+
//# sourceMappingURL=chunk-B4BMCXWK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/config.ts"],"sourcesContent":["/**\n * Local config management — ~/.sherwood/config.json\n *\n * Stores group ID cache, per-chain contract addresses, and wallet config.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nconst CONFIG_DIR = path.join(os.homedir(), \".sherwood\");\nconst CONFIG_PATH = path.join(CONFIG_DIR, \"config.json\");\n\n/** Per-chain user-specific addresses (stored by chainId). */\nexport interface ChainContracts {\n vault?: string; // user's default vault address\n}\n\nexport interface SherwoodConfig {\n dbEncryptionKey?: string; // legacy — no longer used, XMTP CLI manages its own DB\n privateKey?: string; // wallet private key (0x-prefixed)\n xmtpInboxId?: string;\n groupCache: Record<string, string>; // subdomain → XMTP group ID\n veniceApiKey?: string; // Venice AI inference API key\n agentId?: number; // ERC-8004 identity token ID\n contracts?: Record<string, ChainContracts>; // chainId → user addresses\n rpc?: Record<string, string>; // network name → custom RPC URL\n notifyTo?: string; // destination for cron summaries (Telegram chat ID, phone, etc.)\n uniswapApiKey?: string; // Uniswap Trading API key (from developers.uniswap.org)\n positions?: unknown[]; // open trade positions (typed in positions.ts)\n closedPositions?: unknown[]; // historical closed positions\n}\n\nexport function loadConfig(): SherwoodConfig {\n if (fs.existsSync(CONFIG_PATH)) {\n return JSON.parse(fs.readFileSync(CONFIG_PATH, \"utf-8\"));\n }\n\n return { groupCache: {} };\n}\n\nexport function saveConfig(config: SherwoodConfig): void {\n fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });\n}\n\nexport function cacheGroupId(subdomain: string, groupId: string): void {\n const config = loadConfig();\n config.groupCache[subdomain] = groupId;\n saveConfig(config);\n}\n\nexport function getCachedGroupId(subdomain: string): string | undefined {\n const config = loadConfig();\n return config.groupCache[subdomain];\n}\n\nexport function setVeniceApiKey(apiKey: string): void {\n const config = loadConfig();\n config.veniceApiKey = apiKey;\n saveConfig(config);\n}\n\nexport function getVeniceApiKey(): string | undefined {\n return loadConfig().veniceApiKey;\n}\n\nexport function setAgentId(agentId: number): void {\n const config = loadConfig();\n config.agentId = agentId;\n saveConfig(config);\n}\n\nexport function getAgentId(): number | undefined {\n return loadConfig().agentId;\n}\n\nexport function setPrivateKey(key: string): void {\n const config = loadConfig();\n config.privateKey = key.startsWith(\"0x\") ? key : `0x${key}`;\n saveConfig(config);\n}\n\nexport function getPrivateKey(): string | undefined {\n return loadConfig().privateKey;\n}\n\n// ── Uniswap Trading API Key ──\n\nexport function setUniswapApiKey(apiKey: string): void {\n const config = loadConfig();\n config.uniswapApiKey = apiKey;\n saveConfig(config);\n}\n\nexport function getUniswapApiKey(): string | undefined {\n return loadConfig().uniswapApiKey ?? process.env.UNISWAP_API_KEY;\n}\n\n// ── Per-network RPC URLs ──\n\nexport function getConfigRpcUrl(network: string): string | undefined {\n return loadConfig().rpc?.[network];\n}\n\nexport function setConfigRpcUrl(network: string, url: string): void {\n const config = loadConfig();\n if (!config.rpc) config.rpc = {};\n config.rpc[network] = url;\n saveConfig(config);\n}\n\n// ── Per-chain contract addresses ──\n\nexport function getChainContracts(chainId: number): ChainContracts {\n const config = loadConfig();\n return config.contracts?.[String(chainId)] ?? {};\n}\n\nexport function getNotifyTo(): string | undefined {\n return loadConfig().notifyTo;\n}\n\nexport function setNotifyTo(id: string): void {\n const config = loadConfig();\n config.notifyTo = id;\n saveConfig(config);\n}\n\nexport function setChainContract(\n chainId: number,\n key: keyof ChainContracts,\n value: string,\n): void {\n const config = loadConfig();\n if (!config.contracts) config.contracts = {};\n const cid = String(chainId);\n if (!config.contracts[cid]) config.contracts[cid] = {};\n config.contracts[cid][key] = value;\n saveConfig(config);\n}\n"],"mappings":";AAMA,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,IAAM,aAAa,KAAK,KAAK,GAAG,QAAQ,GAAG,WAAW;AACtD,IAAM,cAAc,KAAK,KAAK,YAAY,aAAa;AAsBhD,SAAS,aAA6B;AAC3C,MAAI,GAAG,WAAW,WAAW,GAAG;AAC9B,WAAO,KAAK,MAAM,GAAG,aAAa,aAAa,OAAO,CAAC;AAAA,EACzD;AAEA,SAAO,EAAE,YAAY,CAAC,EAAE;AAC1B;AAEO,SAAS,WAAW,QAA8B;AACvD,KAAG,UAAU,YAAY,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AACzD,KAAG,cAAc,aAAa,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,EAAE,MAAM,IAAM,CAAC;AAChF;AAEO,SAAS,aAAa,WAAmB,SAAuB;AACrE,QAAM,SAAS,WAAW;AAC1B,SAAO,WAAW,SAAS,IAAI;AAC/B,aAAW,MAAM;AACnB;AAEO,SAAS,iBAAiB,WAAuC;AACtE,QAAM,SAAS,WAAW;AAC1B,SAAO,OAAO,WAAW,SAAS;AACpC;AAEO,SAAS,gBAAgB,QAAsB;AACpD,QAAM,SAAS,WAAW;AAC1B,SAAO,eAAe;AACtB,aAAW,MAAM;AACnB;AAEO,SAAS,kBAAsC;AACpD,SAAO,WAAW,EAAE;AACtB;AAEO,SAAS,WAAW,SAAuB;AAChD,QAAM,SAAS,WAAW;AAC1B,SAAO,UAAU;AACjB,aAAW,MAAM;AACnB;AAEO,SAAS,aAAiC;AAC/C,SAAO,WAAW,EAAE;AACtB;AAEO,SAAS,cAAc,KAAmB;AAC/C,QAAM,SAAS,WAAW;AAC1B,SAAO,aAAa,IAAI,WAAW,IAAI,IAAI,MAAM,KAAK,GAAG;AACzD,aAAW,MAAM;AACnB;AAEO,SAAS,gBAAoC;AAClD,SAAO,WAAW,EAAE;AACtB;AAIO,SAAS,iBAAiB,QAAsB;AACrD,QAAM,SAAS,WAAW;AAC1B,SAAO,gBAAgB;AACvB,aAAW,MAAM;AACnB;AAEO,SAAS,mBAAuC;AACrD,SAAO,WAAW,EAAE,iBAAiB,QAAQ,IAAI;AACnD;AAIO,SAAS,gBAAgB,SAAqC;AACnE,SAAO,WAAW,EAAE,MAAM,OAAO;AACnC;AAEO,SAAS,gBAAgB,SAAiB,KAAmB;AAClE,QAAM,SAAS,WAAW;AAC1B,MAAI,CAAC,OAAO,IAAK,QAAO,MAAM,CAAC;AAC/B,SAAO,IAAI,OAAO,IAAI;AACtB,aAAW,MAAM;AACnB;AAIO,SAAS,kBAAkB,SAAiC;AACjE,QAAM,SAAS,WAAW;AAC1B,SAAO,OAAO,YAAY,OAAO,OAAO,CAAC,KAAK,CAAC;AACjD;AAEO,SAAS,cAAkC;AAChD,SAAO,WAAW,EAAE;AACtB;AAEO,SAAS,YAAY,IAAkB;AAC5C,QAAM,SAAS,WAAW;AAC1B,SAAO,WAAW;AAClB,aAAW,MAAM;AACnB;AAEO,SAAS,iBACd,SACA,KACA,OACM;AACN,QAAM,SAAS,WAAW;AAC1B,MAAI,CAAC,OAAO,UAAW,QAAO,YAAY,CAAC;AAC3C,QAAM,MAAM,OAAO,OAAO;AAC1B,MAAI,CAAC,OAAO,UAAU,GAAG,EAAG,QAAO,UAAU,GAAG,IAAI,CAAC;AACrD,SAAO,UAAU,GAAG,EAAE,GAAG,IAAI;AAC7B,aAAW,MAAM;AACnB;","names":[]}
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ERC20_ABI,
|
|
3
|
+
UNISWAP,
|
|
4
|
+
UNISWAP_QUOTER_V2_ABI
|
|
5
|
+
} from "./chunk-W76CHVD3.js";
|
|
6
|
+
import {
|
|
7
|
+
getAccount,
|
|
8
|
+
getPublicClient,
|
|
9
|
+
writeContractWithRetry
|
|
10
|
+
} from "./chunk-HRA2KPGW.js";
|
|
11
|
+
import {
|
|
12
|
+
getChain
|
|
13
|
+
} from "./chunk-FEDSWXSD.js";
|
|
14
|
+
import {
|
|
15
|
+
getUniswapApiKey,
|
|
16
|
+
getVeniceApiKey,
|
|
17
|
+
setVeniceApiKey
|
|
18
|
+
} from "./chunk-B4BMCXWK.js";
|
|
19
|
+
|
|
20
|
+
// src/providers/uniswap.ts
|
|
21
|
+
import { isAddress } from "viem";
|
|
22
|
+
import { base, baseSepolia } from "viem/chains";
|
|
23
|
+
var API_BASE = "https://trade-api.gateway.uniswap.org/v1";
|
|
24
|
+
function getApiKey() {
|
|
25
|
+
const key = getUniswapApiKey();
|
|
26
|
+
if (!key) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
"Uniswap API key not configured. Run 'sherwood config set --uniswap-api-key <key>' or set UNISWAP_API_KEY env var.\nGet your key at https://developers.uniswap.org/"
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return key;
|
|
32
|
+
}
|
|
33
|
+
function apiHeaders() {
|
|
34
|
+
return {
|
|
35
|
+
"Content-Type": "application/json",
|
|
36
|
+
"x-api-key": getApiKey(),
|
|
37
|
+
"x-universal-router-version": "2.0"
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function isUniswapXRouting(routing) {
|
|
41
|
+
return routing === "DUTCH_V2" || routing === "DUTCH_V3" || routing === "PRIORITY";
|
|
42
|
+
}
|
|
43
|
+
function getOutputAmount(q) {
|
|
44
|
+
if (isUniswapXRouting(q.routing)) {
|
|
45
|
+
const ux = q;
|
|
46
|
+
const firstOutput = ux.quote.orderInfo.outputs[0];
|
|
47
|
+
if (!firstOutput) throw new Error("UniswapX quote has no outputs");
|
|
48
|
+
return firstOutput.startAmount;
|
|
49
|
+
}
|
|
50
|
+
return q.quote.output.amount;
|
|
51
|
+
}
|
|
52
|
+
async function fetchWithRetry(url, init, maxRetries = 3) {
|
|
53
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
54
|
+
const response = await fetch(url, {
|
|
55
|
+
...init,
|
|
56
|
+
signal: AbortSignal.timeout(3e4)
|
|
57
|
+
});
|
|
58
|
+
if (response.status !== 429 && response.status < 500) return response;
|
|
59
|
+
if (attempt === maxRetries) return response;
|
|
60
|
+
const delay = Math.min(200 * Math.pow(2, attempt) + Math.random() * 100, 1e4);
|
|
61
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
62
|
+
}
|
|
63
|
+
throw new Error("Unreachable");
|
|
64
|
+
}
|
|
65
|
+
var UniswapProvider = class {
|
|
66
|
+
info() {
|
|
67
|
+
return {
|
|
68
|
+
name: "uniswap",
|
|
69
|
+
type: "trading",
|
|
70
|
+
capabilities: [
|
|
71
|
+
"swap.exact-input",
|
|
72
|
+
"swap.quote",
|
|
73
|
+
"swap.check-approval"
|
|
74
|
+
],
|
|
75
|
+
supportedChains: [base, baseSepolia]
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get a quote from the Uniswap Trading API.
|
|
80
|
+
* Returns the optimal route (CLASSIC, PRIORITY, or UniswapX).
|
|
81
|
+
*/
|
|
82
|
+
async quote(params) {
|
|
83
|
+
const account = getAccount();
|
|
84
|
+
const chainId = getChain().id;
|
|
85
|
+
const body = {
|
|
86
|
+
swapper: account.address,
|
|
87
|
+
tokenIn: params.tokenIn,
|
|
88
|
+
tokenOut: params.tokenOut,
|
|
89
|
+
tokenInChainId: String(chainId),
|
|
90
|
+
tokenOutChainId: String(chainId),
|
|
91
|
+
amount: params.amountIn.toString(),
|
|
92
|
+
type: "EXACT_INPUT",
|
|
93
|
+
slippageTolerance: 0.5,
|
|
94
|
+
routingPreference: "BEST_PRICE"
|
|
95
|
+
};
|
|
96
|
+
const res = await fetchWithRetry(`${API_BASE}/quote`, {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: apiHeaders(),
|
|
99
|
+
body: JSON.stringify(body)
|
|
100
|
+
});
|
|
101
|
+
if (!res.ok) {
|
|
102
|
+
const err = await res.text();
|
|
103
|
+
throw new Error(`Uniswap quote failed (${res.status}): ${err}`);
|
|
104
|
+
}
|
|
105
|
+
const data = await res.json();
|
|
106
|
+
const amountOut = BigInt(getOutputAmount(data));
|
|
107
|
+
return {
|
|
108
|
+
amountOut,
|
|
109
|
+
priceImpact: 0,
|
|
110
|
+
route: `${data.routing}: ${params.tokenIn.slice(0, 8)}\u2192${params.tokenOut.slice(0, 8)}`
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get a full quote response (preserving the raw API response for swap execution).
|
|
115
|
+
*/
|
|
116
|
+
async fullQuote(params) {
|
|
117
|
+
const account = getAccount();
|
|
118
|
+
const chainId = getChain().id;
|
|
119
|
+
const body = {
|
|
120
|
+
swapper: account.address,
|
|
121
|
+
tokenIn: params.tokenIn,
|
|
122
|
+
tokenOut: params.tokenOut,
|
|
123
|
+
tokenInChainId: String(chainId),
|
|
124
|
+
tokenOutChainId: String(chainId),
|
|
125
|
+
amount: params.amountIn.toString(),
|
|
126
|
+
type: "EXACT_INPUT",
|
|
127
|
+
slippageTolerance: params.slippageTolerance ?? 0.5,
|
|
128
|
+
routingPreference: "BEST_PRICE"
|
|
129
|
+
};
|
|
130
|
+
const res = await fetchWithRetry(`${API_BASE}/quote`, {
|
|
131
|
+
method: "POST",
|
|
132
|
+
headers: apiHeaders(),
|
|
133
|
+
body: JSON.stringify(body)
|
|
134
|
+
});
|
|
135
|
+
if (!res.ok) {
|
|
136
|
+
const err = await res.text();
|
|
137
|
+
throw new Error(`Uniswap quote failed (${res.status}): ${err}`);
|
|
138
|
+
}
|
|
139
|
+
const quoteResponse = await res.json();
|
|
140
|
+
const amountOut = BigInt(getOutputAmount(quoteResponse));
|
|
141
|
+
return { quoteResponse, amountOut, routing: quoteResponse.routing };
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Check and handle token approval for Uniswap.
|
|
145
|
+
* Uses the Trading API's /check_approval endpoint.
|
|
146
|
+
*/
|
|
147
|
+
async checkApproval(params) {
|
|
148
|
+
const account = getAccount();
|
|
149
|
+
const chainId = getChain().id;
|
|
150
|
+
const client = getPublicClient();
|
|
151
|
+
const res = await fetchWithRetry(`${API_BASE}/check_approval`, {
|
|
152
|
+
method: "POST",
|
|
153
|
+
headers: apiHeaders(),
|
|
154
|
+
body: JSON.stringify({
|
|
155
|
+
walletAddress: account.address,
|
|
156
|
+
token: params.token,
|
|
157
|
+
amount: params.amount.toString(),
|
|
158
|
+
chainId
|
|
159
|
+
})
|
|
160
|
+
});
|
|
161
|
+
if (!res.ok) {
|
|
162
|
+
const err = await res.text();
|
|
163
|
+
throw new Error(`Approval check failed (${res.status}): ${err}`);
|
|
164
|
+
}
|
|
165
|
+
const data = await res.json();
|
|
166
|
+
if (data.approval) {
|
|
167
|
+
const hash = await writeContractWithRetry({
|
|
168
|
+
address: data.approval.to,
|
|
169
|
+
abi: ERC20_ABI,
|
|
170
|
+
functionName: "approve",
|
|
171
|
+
// Decode the approval data — the API returns the full calldata
|
|
172
|
+
// but we need to send the raw transaction
|
|
173
|
+
args: [],
|
|
174
|
+
// unused — we send raw data
|
|
175
|
+
account,
|
|
176
|
+
chain: getChain()
|
|
177
|
+
});
|
|
178
|
+
const { getWalletClient } = await import("./client-I56MIQAM.js");
|
|
179
|
+
const wallet = getWalletClient();
|
|
180
|
+
const approvalHash = await wallet.sendTransaction({
|
|
181
|
+
to: data.approval.to,
|
|
182
|
+
data: data.approval.data,
|
|
183
|
+
value: BigInt(data.approval.value || "0"),
|
|
184
|
+
account,
|
|
185
|
+
chain: getChain()
|
|
186
|
+
});
|
|
187
|
+
await client.waitForTransactionReceipt({ hash: approvalHash });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Execute a swap via the Uniswap Trading API.
|
|
192
|
+
*
|
|
193
|
+
* Full flow: check_approval → quote → swap → sign & broadcast.
|
|
194
|
+
*/
|
|
195
|
+
async swap(params) {
|
|
196
|
+
const account = getAccount();
|
|
197
|
+
const client = getPublicClient();
|
|
198
|
+
const ETH_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
199
|
+
if (params.tokenIn !== ETH_ADDRESS) {
|
|
200
|
+
await this.checkApproval({
|
|
201
|
+
token: params.tokenIn,
|
|
202
|
+
amount: params.amountIn
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
const slippageBps = params.fee;
|
|
206
|
+
const { quoteResponse } = await this.fullQuote({
|
|
207
|
+
tokenIn: params.tokenIn,
|
|
208
|
+
tokenOut: params.tokenOut,
|
|
209
|
+
amountIn: params.amountIn,
|
|
210
|
+
slippageTolerance: 0.5
|
|
211
|
+
// 0.5%
|
|
212
|
+
});
|
|
213
|
+
const quoteRaw = quoteResponse;
|
|
214
|
+
const { permitData, ...cleanQuote } = quoteRaw;
|
|
215
|
+
const swapRequest = { ...cleanQuote };
|
|
216
|
+
if (isUniswapXRouting(quoteResponse.routing)) {
|
|
217
|
+
if (permitData && typeof permitData === "object") {
|
|
218
|
+
const typedData = permitData;
|
|
219
|
+
const signature = await account.signTypedData({
|
|
220
|
+
domain: typedData.domain,
|
|
221
|
+
types: typedData.types,
|
|
222
|
+
primaryType: Object.keys(typedData.types).find((k) => k !== "EIP712Domain") ?? "PermitWitnessTransferFrom",
|
|
223
|
+
message: typedData.values
|
|
224
|
+
});
|
|
225
|
+
swapRequest.signature = signature;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const swapRes = await fetchWithRetry(`${API_BASE}/swap`, {
|
|
229
|
+
method: "POST",
|
|
230
|
+
headers: apiHeaders(),
|
|
231
|
+
body: JSON.stringify(swapRequest)
|
|
232
|
+
});
|
|
233
|
+
if (!swapRes.ok) {
|
|
234
|
+
const err = await swapRes.text();
|
|
235
|
+
throw new Error(`Uniswap swap failed (${swapRes.status}): ${err}`);
|
|
236
|
+
}
|
|
237
|
+
const swapData = await swapRes.json();
|
|
238
|
+
if (!swapData.swap?.data || swapData.swap.data === "" || swapData.swap.data === "0x") {
|
|
239
|
+
throw new Error("Empty swap data \u2014 quote may have expired. Try again.");
|
|
240
|
+
}
|
|
241
|
+
if (!isAddress(swapData.swap.to) || !isAddress(swapData.swap.from)) {
|
|
242
|
+
throw new Error("Invalid address in swap response");
|
|
243
|
+
}
|
|
244
|
+
const { getWalletClient } = await import("./client-I56MIQAM.js");
|
|
245
|
+
const wallet = getWalletClient();
|
|
246
|
+
const hash = await wallet.sendTransaction({
|
|
247
|
+
to: swapData.swap.to,
|
|
248
|
+
data: swapData.swap.data,
|
|
249
|
+
value: BigInt(swapData.swap.value || "0"),
|
|
250
|
+
account,
|
|
251
|
+
chain: getChain()
|
|
252
|
+
});
|
|
253
|
+
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
254
|
+
return {
|
|
255
|
+
hash,
|
|
256
|
+
success: receipt.status === "success",
|
|
257
|
+
gasUsed: receipt.gasUsed
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// src/lib/venice.ts
|
|
263
|
+
var VENICE_API_BASE = "https://api.venice.ai/api/v1";
|
|
264
|
+
async function provisionApiKey() {
|
|
265
|
+
const account = getAccount();
|
|
266
|
+
const tokenRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {
|
|
267
|
+
signal: AbortSignal.timeout(15e3)
|
|
268
|
+
});
|
|
269
|
+
if (!tokenRes.ok) {
|
|
270
|
+
throw new Error(`Failed to get validation token: ${tokenRes.status} ${tokenRes.statusText}`);
|
|
271
|
+
}
|
|
272
|
+
const tokenData = await tokenRes.json();
|
|
273
|
+
const token = tokenData?.data?.token;
|
|
274
|
+
if (!token) {
|
|
275
|
+
throw new Error("Venice API returned no validation token");
|
|
276
|
+
}
|
|
277
|
+
const signature = await account.signMessage({ message: token });
|
|
278
|
+
const keyRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {
|
|
279
|
+
method: "POST",
|
|
280
|
+
headers: {
|
|
281
|
+
"Content-Type": "application/json",
|
|
282
|
+
Authorization: `Bearer ${token}`
|
|
283
|
+
},
|
|
284
|
+
signal: AbortSignal.timeout(15e3),
|
|
285
|
+
body: JSON.stringify({
|
|
286
|
+
address: account.address,
|
|
287
|
+
signature,
|
|
288
|
+
token,
|
|
289
|
+
apiKeyType: "INFERENCE",
|
|
290
|
+
description: "Sherwood syndicate agent"
|
|
291
|
+
})
|
|
292
|
+
});
|
|
293
|
+
if (!keyRes.ok) {
|
|
294
|
+
const body = await keyRes.text();
|
|
295
|
+
throw new Error(`Failed to generate API key: ${keyRes.status} ${body}`);
|
|
296
|
+
}
|
|
297
|
+
const keyData = await keyRes.json();
|
|
298
|
+
const apiKey = keyData?.data?.apiKey;
|
|
299
|
+
if (!apiKey) {
|
|
300
|
+
throw new Error("Venice API returned no API key");
|
|
301
|
+
}
|
|
302
|
+
setVeniceApiKey(apiKey);
|
|
303
|
+
return apiKey;
|
|
304
|
+
}
|
|
305
|
+
async function checkApiKeyValid() {
|
|
306
|
+
const apiKey = getVeniceApiKey();
|
|
307
|
+
if (!apiKey) return false;
|
|
308
|
+
try {
|
|
309
|
+
const res = await fetch(`${VENICE_API_BASE}/models`, {
|
|
310
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
311
|
+
signal: AbortSignal.timeout(15e3)
|
|
312
|
+
});
|
|
313
|
+
return res.ok;
|
|
314
|
+
} catch {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
async function chatCompletion(opts) {
|
|
319
|
+
const apiKey = getVeniceApiKey();
|
|
320
|
+
if (!apiKey) {
|
|
321
|
+
throw new Error("No Venice API key configured. Run 'sherwood venice provision' first.");
|
|
322
|
+
}
|
|
323
|
+
const body = {
|
|
324
|
+
model: opts.model,
|
|
325
|
+
messages: opts.messages
|
|
326
|
+
};
|
|
327
|
+
if (opts.temperature !== void 0) body.temperature = opts.temperature;
|
|
328
|
+
if (opts.maxTokens !== void 0) body.max_tokens = opts.maxTokens;
|
|
329
|
+
const veniceParams = {};
|
|
330
|
+
if (opts.enableWebSearch) veniceParams.enable_web_search = "on";
|
|
331
|
+
if (opts.disableThinking) veniceParams.disable_thinking = true;
|
|
332
|
+
if (Object.keys(veniceParams).length > 0) body.venice_parameters = veniceParams;
|
|
333
|
+
const res = await fetch(`${VENICE_API_BASE}/chat/completions`, {
|
|
334
|
+
method: "POST",
|
|
335
|
+
headers: {
|
|
336
|
+
"Content-Type": "application/json",
|
|
337
|
+
Authorization: `Bearer ${apiKey}`
|
|
338
|
+
},
|
|
339
|
+
signal: AbortSignal.timeout(12e4),
|
|
340
|
+
// inference can be slow
|
|
341
|
+
body: JSON.stringify(body)
|
|
342
|
+
});
|
|
343
|
+
if (!res.ok) {
|
|
344
|
+
const errBody = await res.text();
|
|
345
|
+
throw new Error(`Venice inference failed: ${res.status} ${errBody}`);
|
|
346
|
+
}
|
|
347
|
+
const data = await res.json();
|
|
348
|
+
const choice = data.choices?.[0];
|
|
349
|
+
if (!choice) {
|
|
350
|
+
throw new Error("Venice returned no choices");
|
|
351
|
+
}
|
|
352
|
+
return {
|
|
353
|
+
content: choice.message?.content ?? "",
|
|
354
|
+
model: data.model ?? opts.model,
|
|
355
|
+
usage: {
|
|
356
|
+
promptTokens: data.usage?.prompt_tokens ?? 0,
|
|
357
|
+
completionTokens: data.usage?.completion_tokens ?? 0,
|
|
358
|
+
totalTokens: data.usage?.total_tokens ?? 0
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
async function listModels() {
|
|
363
|
+
const apiKey = getVeniceApiKey();
|
|
364
|
+
if (!apiKey) {
|
|
365
|
+
throw new Error("No Venice API key configured. Run 'sherwood venice provision' first.");
|
|
366
|
+
}
|
|
367
|
+
const res = await fetch(`${VENICE_API_BASE}/models`, {
|
|
368
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
369
|
+
signal: AbortSignal.timeout(15e3)
|
|
370
|
+
});
|
|
371
|
+
if (!res.ok) {
|
|
372
|
+
throw new Error(`Failed to list Venice models: ${res.status} ${res.statusText}`);
|
|
373
|
+
}
|
|
374
|
+
const data = await res.json();
|
|
375
|
+
return (data.data ?? []).map((m) => m.id);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// src/lib/quote.ts
|
|
379
|
+
import { encodeFunctionData, decodeFunctionResult, concat, pad, numberToHex } from "viem";
|
|
380
|
+
async function getQuote(params) {
|
|
381
|
+
const client = getPublicClient();
|
|
382
|
+
const calldata = encodeFunctionData({
|
|
383
|
+
abi: UNISWAP_QUOTER_V2_ABI,
|
|
384
|
+
functionName: "quoteExactInputSingle",
|
|
385
|
+
args: [
|
|
386
|
+
{
|
|
387
|
+
tokenIn: params.tokenIn,
|
|
388
|
+
tokenOut: params.tokenOut,
|
|
389
|
+
amountIn: params.amountIn,
|
|
390
|
+
fee: params.fee,
|
|
391
|
+
sqrtPriceLimitX96: 0n
|
|
392
|
+
}
|
|
393
|
+
]
|
|
394
|
+
});
|
|
395
|
+
const { data } = await client.call({
|
|
396
|
+
to: UNISWAP().QUOTER_V2,
|
|
397
|
+
data: calldata
|
|
398
|
+
});
|
|
399
|
+
if (!data) {
|
|
400
|
+
throw new Error("Quoter returned no data \u2014 pool may not exist for this pair/fee");
|
|
401
|
+
}
|
|
402
|
+
const [amountOut, sqrtPriceX96After, , gasEstimate] = decodeFunctionResult({
|
|
403
|
+
abi: UNISWAP_QUOTER_V2_ABI,
|
|
404
|
+
functionName: "quoteExactInputSingle",
|
|
405
|
+
data
|
|
406
|
+
});
|
|
407
|
+
return { amountOut, sqrtPriceX96After, gasEstimate };
|
|
408
|
+
}
|
|
409
|
+
function applySlippage(amountOut, slippageBps) {
|
|
410
|
+
return amountOut * BigInt(1e4 - slippageBps) / 10000n;
|
|
411
|
+
}
|
|
412
|
+
function encodeSwapPath(tokens, fees) {
|
|
413
|
+
if (tokens.length < 2 || fees.length !== tokens.length - 1) {
|
|
414
|
+
throw new Error("Invalid path: need at least 2 tokens and (tokens-1) fees");
|
|
415
|
+
}
|
|
416
|
+
const parts = [];
|
|
417
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
418
|
+
parts.push(tokens[i].toLowerCase());
|
|
419
|
+
if (i < fees.length) {
|
|
420
|
+
parts.push(pad(numberToHex(fees[i]), { size: 3 }));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return concat(parts);
|
|
424
|
+
}
|
|
425
|
+
async function getMultiHopQuote(params) {
|
|
426
|
+
const client = getPublicClient();
|
|
427
|
+
const calldata = encodeFunctionData({
|
|
428
|
+
abi: UNISWAP_QUOTER_V2_ABI,
|
|
429
|
+
functionName: "quoteExactInput",
|
|
430
|
+
args: [params.path, params.amountIn]
|
|
431
|
+
});
|
|
432
|
+
const { data } = await client.call({
|
|
433
|
+
to: UNISWAP().QUOTER_V2,
|
|
434
|
+
data: calldata
|
|
435
|
+
});
|
|
436
|
+
if (!data) {
|
|
437
|
+
throw new Error("Quoter returned no data \u2014 pool may not exist for this path");
|
|
438
|
+
}
|
|
439
|
+
const [amountOut, , , gasEstimate] = decodeFunctionResult({
|
|
440
|
+
abi: UNISWAP_QUOTER_V2_ABI,
|
|
441
|
+
functionName: "quoteExactInput",
|
|
442
|
+
data
|
|
443
|
+
});
|
|
444
|
+
return { amountOut, sqrtPriceX96After: 0n, gasEstimate };
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
export {
|
|
448
|
+
UniswapProvider,
|
|
449
|
+
provisionApiKey,
|
|
450
|
+
checkApiKeyValid,
|
|
451
|
+
chatCompletion,
|
|
452
|
+
listModels,
|
|
453
|
+
getQuote,
|
|
454
|
+
applySlippage,
|
|
455
|
+
encodeSwapPath,
|
|
456
|
+
getMultiHopQuote
|
|
457
|
+
};
|
|
458
|
+
//# sourceMappingURL=chunk-DCT3IDBS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/uniswap.ts","../src/lib/venice.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 } from \"../lib/client.js\";\nimport { getChain } from \"../lib/network.js\";\nimport { getUniswapApiKey } from \"../lib/config.js\";\nimport { ERC20_ABI } from \"../lib/abis.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 // Submit the approval transaction\n const hash = await writeContractWithRetry({\n address: data.approval.to,\n abi: ERC20_ABI,\n functionName: \"approve\",\n // Decode the approval data — the API returns the full calldata\n // but we need to send the raw transaction\n args: [], // unused — we send raw data\n account,\n chain: getChain(),\n });\n\n // Actually, the API returns a ready-to-send transaction, so use sendTransaction\n // Let's use the wallet client directly\n const { getWalletClient } = await import(\"../lib/client.js\");\n const wallet = getWalletClient();\n const approvalHash = await wallet.sendTransaction({\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 client.waitForTransactionReceipt({ hash: 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 slippageBps = params.fee; // repurpose fee field for slippage in API mode\n const { quoteResponse } = await this.fullQuote({\n tokenIn: params.tokenIn,\n tokenOut: params.tokenOut,\n amountIn: params.amountIn,\n slippageTolerance: 0.5, // 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 // UniswapX routes: permitData is for local signing only, must NOT be sent to /swap\n // For CLASSIC routes without Permit2: omit both signature and permitData\n // (We use direct approval via /check_approval, not Permit2)\n if (isUniswapXRouting(quoteResponse.routing)) {\n // UniswapX: sign the order with permitData locally\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 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: Object.keys(typedData.types).find((k) => k !== \"EIP712Domain\") ?? \"PermitWitnessTransferFrom\",\n message: typedData.values,\n });\n swapRequest.signature = signature;\n }\n }\n // For CLASSIC: no signature/permitData needed (we use /check_approval)\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\n const { getWalletClient } = await import(\"../lib/client.js\");\n const wallet = getWalletClient();\n const hash = await wallet.sendTransaction({\n to: swapData.swap.to,\n data: swapData.swap.data,\n value: BigInt(swapData.swap.value || \"0\"),\n account,\n chain: getChain(),\n });\n\n const receipt = await client.waitForTransactionReceipt({ hash });\n return {\n hash,\n success: receipt.status === \"success\",\n gasUsed: receipt.gasUsed,\n };\n }\n}\n","/**\n * Venice AI API integration — web3 key generation, validation, and inference.\n *\n * Key provisioning flow:\n * 1. GET /api_keys/generate_web3_key → validation token\n * 2. Sign token with agent wallet (EIP-191)\n * 3. POST /api_keys/generate_web3_key → API key\n *\n * Inference:\n * POST /chat/completions with Bearer auth → chat completion response\n *\n * The API key is stored in ~/.sherwood/config.json.\n * Venice requires the signing wallet to hold staked VVV (sVVV).\n */\n\nimport { getAccount } from \"./client.js\";\nimport { setVeniceApiKey, getVeniceApiKey } from \"./config.js\";\n\nconst VENICE_API_BASE = \"https://api.venice.ai/api/v1\";\n\n/**\n * Provision a Venice API key via web3 wallet signature.\n * The wallet must hold sVVV for this to succeed.\n */\nexport async function provisionApiKey(): Promise<string> {\n const account = getAccount();\n\n // 1. Get validation token\n const tokenRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {\n signal: AbortSignal.timeout(15_000),\n });\n if (!tokenRes.ok) {\n throw new Error(`Failed to get validation token: ${tokenRes.status} ${tokenRes.statusText}`);\n }\n const tokenData = await tokenRes.json();\n const token = tokenData?.data?.token;\n if (!token) {\n throw new Error(\"Venice API returned no validation token\");\n }\n\n // 2. Sign token with wallet (EIP-191)\n const signature = await account.signMessage({ message: token });\n\n // 3. Generate API key\n const keyRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n signal: AbortSignal.timeout(15_000),\n body: JSON.stringify({\n address: account.address,\n signature,\n token,\n apiKeyType: \"INFERENCE\",\n description: \"Sherwood syndicate agent\",\n }),\n });\n\n if (!keyRes.ok) {\n const body = await keyRes.text();\n throw new Error(`Failed to generate API key: ${keyRes.status} ${body}`);\n }\n\n const keyData = await keyRes.json();\n const apiKey = keyData?.data?.apiKey;\n if (!apiKey) {\n throw new Error(\"Venice API returned no API key\");\n }\n\n // Store in config\n setVeniceApiKey(apiKey);\n\n return apiKey;\n}\n\n/**\n * Check if the stored Venice API key is still valid.\n */\nexport async function checkApiKeyValid(): Promise<boolean> {\n const apiKey = getVeniceApiKey();\n if (!apiKey) return false;\n\n try {\n const res = await fetch(`${VENICE_API_BASE}/models`, {\n headers: { Authorization: `Bearer ${apiKey}` },\n signal: AbortSignal.timeout(15_000),\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\n// ── Inference ──\n\nexport interface ChatCompletionMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n}\n\nexport interface ChatCompletionOptions {\n model: string;\n messages: ChatCompletionMessage[];\n temperature?: number;\n maxTokens?: number;\n enableWebSearch?: boolean;\n disableThinking?: boolean;\n}\n\nexport interface ChatCompletionResult {\n content: string;\n model: string;\n usage: {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n };\n}\n\n/**\n * Call Venice chat completions API for private inference.\n * Requires a provisioned API key (run `sherwood venice provision` first).\n */\nexport async function chatCompletion(opts: ChatCompletionOptions): Promise<ChatCompletionResult> {\n const apiKey = getVeniceApiKey();\n if (!apiKey) {\n throw new Error(\"No Venice API key configured. Run 'sherwood venice provision' first.\");\n }\n\n const body: Record<string, unknown> = {\n model: opts.model,\n messages: opts.messages,\n };\n if (opts.temperature !== undefined) body.temperature = opts.temperature;\n if (opts.maxTokens !== undefined) body.max_tokens = opts.maxTokens;\n\n const veniceParams: Record<string, unknown> = {};\n if (opts.enableWebSearch) veniceParams.enable_web_search = \"on\";\n if (opts.disableThinking) veniceParams.disable_thinking = true;\n if (Object.keys(veniceParams).length > 0) body.venice_parameters = veniceParams;\n\n const res = await fetch(`${VENICE_API_BASE}/chat/completions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n signal: AbortSignal.timeout(120_000), // inference can be slow\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const errBody = await res.text();\n throw new Error(`Venice inference failed: ${res.status} ${errBody}`);\n }\n\n const data = await res.json();\n const choice = data.choices?.[0];\n if (!choice) {\n throw new Error(\"Venice returned no choices\");\n }\n\n return {\n content: choice.message?.content ?? \"\",\n model: data.model ?? opts.model,\n usage: {\n promptTokens: data.usage?.prompt_tokens ?? 0,\n completionTokens: data.usage?.completion_tokens ?? 0,\n totalTokens: data.usage?.total_tokens ?? 0,\n },\n };\n}\n\n/**\n * List available Venice models.\n * Requires a provisioned API key.\n */\nexport async function listModels(): Promise<string[]> {\n const apiKey = getVeniceApiKey();\n if (!apiKey) {\n throw new Error(\"No Venice API key configured. Run 'sherwood venice provision' first.\");\n }\n\n const res = await fetch(`${VENICE_API_BASE}/models`, {\n headers: { Authorization: `Bearer ${apiKey}` },\n signal: AbortSignal.timeout(15_000),\n });\n\n if (!res.ok) {\n throw new Error(`Failed to list Venice models: ${res.status} ${res.statusText}`);\n }\n\n const data = await res.json();\n return (data.data ?? []).map((m: { id: string }) => m.id);\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":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getConfigRpcUrl
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-B4BMCXWK.js";
|
|
4
4
|
|
|
5
5
|
// src/lib/network.ts
|
|
6
6
|
import { defineChain } from "viem";
|
|
@@ -104,4 +104,4 @@ export {
|
|
|
104
104
|
getExplorerUrl,
|
|
105
105
|
isTestnet
|
|
106
106
|
};
|
|
107
|
-
//# sourceMappingURL=chunk-
|
|
107
|
+
//# sourceMappingURL=chunk-FEDSWXSD.js.map
|