@agentlayer.tech/wallet 0.1.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/.openclaw/AGENTS.md +98 -0
- package/.openclaw/extensions/agent-wallet/README.md +127 -0
- package/.openclaw/extensions/agent-wallet/index.ts +1520 -0
- package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +184 -0
- package/.openclaw/extensions/agent-wallet/package.json +11 -0
- package/.openclaw/extensions/agent-wallet/skills/wallet-operator/SKILL.md +20 -0
- package/CHANGELOG.md +42 -0
- package/LICENSE +104 -0
- package/README.md +332 -0
- package/RELEASING.md +204 -0
- package/agent-wallet/.env.example +62 -0
- package/agent-wallet/AGENTS.md +129 -0
- package/agent-wallet/README.md +527 -0
- package/agent-wallet/agent_wallet/__init__.py +11 -0
- package/agent-wallet/agent_wallet/approval.py +161 -0
- package/agent-wallet/agent_wallet/bootstrap.py +178 -0
- package/agent-wallet/agent_wallet/btc_user_wallets.py +217 -0
- package/agent-wallet/agent_wallet/config.py +382 -0
- package/agent-wallet/agent_wallet/encrypted_storage.py +161 -0
- package/agent-wallet/agent_wallet/evm_user_wallets.py +370 -0
- package/agent-wallet/agent_wallet/exceptions.py +9 -0
- package/agent-wallet/agent_wallet/file_ops.py +34 -0
- package/agent-wallet/agent_wallet/http_client.py +25 -0
- package/agent-wallet/agent_wallet/models.py +66 -0
- package/agent-wallet/agent_wallet/nonce_registry.py +59 -0
- package/agent-wallet/agent_wallet/openclaw_adapter.py +5128 -0
- package/agent-wallet/agent_wallet/openclaw_cli.py +626 -0
- package/agent-wallet/agent_wallet/openclaw_runtime.py +272 -0
- package/agent-wallet/agent_wallet/plugin_bundle.py +42 -0
- package/agent-wallet/agent_wallet/providers/__init__.py +1 -0
- package/agent-wallet/agent_wallet/providers/bags.py +259 -0
- package/agent-wallet/agent_wallet/providers/evm_portfolio.py +470 -0
- package/agent-wallet/agent_wallet/providers/jupiter.py +567 -0
- package/agent-wallet/agent_wallet/providers/kamino.py +215 -0
- package/agent-wallet/agent_wallet/providers/lifi.py +277 -0
- package/agent-wallet/agent_wallet/providers/solana_rpc.py +470 -0
- package/agent-wallet/agent_wallet/providers/wdk_btc_local.py +114 -0
- package/agent-wallet/agent_wallet/providers/wdk_evm_local.py +205 -0
- package/agent-wallet/agent_wallet/sealed_keys.py +61 -0
- package/agent-wallet/agent_wallet/solana_stake.py +103 -0
- package/agent-wallet/agent_wallet/solana_tx.py +93 -0
- package/agent-wallet/agent_wallet/spending_limits.py +101 -0
- package/agent-wallet/agent_wallet/transaction_policy.py +518 -0
- package/agent-wallet/agent_wallet/user_wallets.py +355 -0
- package/agent-wallet/agent_wallet/validation.py +31 -0
- package/agent-wallet/agent_wallet/wallet_layer/__init__.py +1 -0
- package/agent-wallet/agent_wallet/wallet_layer/base.py +808 -0
- package/agent-wallet/agent_wallet/wallet_layer/base58.py +44 -0
- package/agent-wallet/agent_wallet/wallet_layer/factory.py +102 -0
- package/agent-wallet/agent_wallet/wallet_layer/solana.py +4252 -0
- package/agent-wallet/agent_wallet/wallet_layer/wdk_btc.py +272 -0
- package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +1628 -0
- package/agent-wallet/examples/bootstrap_wallet.py +21 -0
- package/agent-wallet/examples/openclaw_runtime_onboarding.py +28 -0
- package/agent-wallet/examples/openclaw_user_wallet_example.py +31 -0
- package/agent-wallet/examples/openclaw_wallet_adapter_example.py +33 -0
- package/agent-wallet/openclaw.plugin.json +138 -0
- package/agent-wallet/pyproject.toml +31 -0
- package/agent-wallet/scripts/bootstrap_openclaw_btc.py +278 -0
- package/agent-wallet/scripts/build_release_bundle.py +188 -0
- package/agent-wallet/scripts/finalize_openclaw_local_wallet_config.py +121 -0
- package/agent-wallet/scripts/install_agent_wallet.py +505 -0
- package/agent-wallet/scripts/install_openclaw_local_config.py +226 -0
- package/agent-wallet/scripts/install_openclaw_sealed_keys.py +105 -0
- package/agent-wallet/scripts/manage_openclaw_btc_wallet.py +244 -0
- package/agent-wallet/scripts/reveal_btc_seed.sh +130 -0
- package/agent-wallet/scripts/security_utils.py +37 -0
- package/agent-wallet/scripts/setup_btc_wallet.sh +146 -0
- package/agent-wallet/scripts/switch_openclaw_wallet_network.py +106 -0
- package/agent-wallet/skills/wallet-operator/SKILL.md +128 -0
- package/bin/openclaw-agent-wallet.mjs +487 -0
- package/install-from-github.sh +134 -0
- package/package.json +61 -0
- package/setup.sh +40 -0
- package/wdk-btc-wallet/README.md +325 -0
- package/wdk-btc-wallet/bootstrap.sh +22 -0
- package/wdk-btc-wallet/package-lock.json +1839 -0
- package/wdk-btc-wallet/package.json +18 -0
- package/wdk-btc-wallet/run-local.sh +21 -0
- package/wdk-btc-wallet/src/config.js +160 -0
- package/wdk-btc-wallet/src/json.js +35 -0
- package/wdk-btc-wallet/src/local_vault.js +432 -0
- package/wdk-btc-wallet/src/network_state.js +84 -0
- package/wdk-btc-wallet/src/server.js +257 -0
- package/wdk-btc-wallet/src/wdk_btc_wallet.js +332 -0
- package/wdk-evm-wallet/README.md +183 -0
- package/wdk-evm-wallet/bootstrap.sh +8 -0
- package/wdk-evm-wallet/package-lock.json +2340 -0
- package/wdk-evm-wallet/package.json +23 -0
- package/wdk-evm-wallet/run-local.sh +12 -0
- package/wdk-evm-wallet/src/config.js +274 -0
- package/wdk-evm-wallet/src/json.js +35 -0
- package/wdk-evm-wallet/src/local_vault.js +430 -0
- package/wdk-evm-wallet/src/network_state.js +92 -0
- package/wdk-evm-wallet/src/server.js +575 -0
- package/wdk-evm-wallet/src/wdk_evm_wallet.js +4981 -0
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
import { createServer } from "node:http";
|
|
5
|
+
|
|
6
|
+
import { loadConfig } from "./config.js";
|
|
7
|
+
import { readJsonBody, sendJson } from "./json.js";
|
|
8
|
+
import { LocalEvmVault } from "./local_vault.js";
|
|
9
|
+
import { EvmNetworkState } from "./network_state.js";
|
|
10
|
+
import { WdkEvmWalletService } from "./wdk_evm_wallet.js";
|
|
11
|
+
|
|
12
|
+
const config = loadConfig();
|
|
13
|
+
const service = new WdkEvmWalletService(config);
|
|
14
|
+
const vault = new LocalEvmVault(config);
|
|
15
|
+
const networkState = new EvmNetworkState(config);
|
|
16
|
+
|
|
17
|
+
function normalizeErrorCode(errorCode, pathname, message) {
|
|
18
|
+
const code = String(errorCode || "").trim().toLowerCase();
|
|
19
|
+
const lower = String(message || "").toLowerCase();
|
|
20
|
+
const isTokenPath = pathname.includes("/token");
|
|
21
|
+
const isTokenReadPath =
|
|
22
|
+
pathname.includes("/token-balance/") || pathname.includes("/token-metadata/");
|
|
23
|
+
|
|
24
|
+
if (code === "insufficient_funds") {
|
|
25
|
+
return "insufficient_funds";
|
|
26
|
+
}
|
|
27
|
+
if (code === "network_unavailable") {
|
|
28
|
+
return "network_unavailable";
|
|
29
|
+
}
|
|
30
|
+
if (
|
|
31
|
+
code === "swap_quote_changed" ||
|
|
32
|
+
code === "swap_simulation_failed" ||
|
|
33
|
+
code === "swap_approval_required" ||
|
|
34
|
+
code === "swap_approval_failed" ||
|
|
35
|
+
code === "swap_approval_timeout" ||
|
|
36
|
+
code === "swap_cleanup_failed" ||
|
|
37
|
+
code === "aave_quote_changed" ||
|
|
38
|
+
code === "aave_approval_required" ||
|
|
39
|
+
code === "aave_fee_unavailable" ||
|
|
40
|
+
code === "aave_cleanup_failed" ||
|
|
41
|
+
code === "token_transfer_failed" ||
|
|
42
|
+
code === "fee_limit_exceeded" ||
|
|
43
|
+
code === "token_read_failed"
|
|
44
|
+
) {
|
|
45
|
+
return code;
|
|
46
|
+
}
|
|
47
|
+
if (
|
|
48
|
+
code === "call_exception" ||
|
|
49
|
+
code === "bad_data" ||
|
|
50
|
+
code === "execution_reverted" ||
|
|
51
|
+
code === "contract_not_found"
|
|
52
|
+
) {
|
|
53
|
+
if (isTokenReadPath) {
|
|
54
|
+
return "token_not_found";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (
|
|
58
|
+
code === "econnrefused" ||
|
|
59
|
+
code === "enotfound" ||
|
|
60
|
+
code === "etimedout" ||
|
|
61
|
+
code === "fetch_failed"
|
|
62
|
+
) {
|
|
63
|
+
return "network_unavailable";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (lower.includes("wallet is locked")) {
|
|
67
|
+
return "wallet_locked";
|
|
68
|
+
}
|
|
69
|
+
if (lower.includes("insufficient funds")) {
|
|
70
|
+
return "insufficient_funds";
|
|
71
|
+
}
|
|
72
|
+
if (
|
|
73
|
+
lower.includes("recipient must be a valid") ||
|
|
74
|
+
lower.includes("recipient must not be the zero address") ||
|
|
75
|
+
lower.includes("to must be a valid") ||
|
|
76
|
+
lower.includes("to must not be the zero address") ||
|
|
77
|
+
lower.includes("invalid address") ||
|
|
78
|
+
lower.includes("bad address checksum")
|
|
79
|
+
) {
|
|
80
|
+
return "recipient_invalid";
|
|
81
|
+
}
|
|
82
|
+
if (
|
|
83
|
+
isTokenReadPath &&
|
|
84
|
+
(lower.includes("missing revert data") ||
|
|
85
|
+
lower.includes("call exception") ||
|
|
86
|
+
lower.includes("could not decode result data") ||
|
|
87
|
+
lower.includes("no contract code") ||
|
|
88
|
+
lower.includes("execution reverted"))
|
|
89
|
+
) {
|
|
90
|
+
return "token_not_found";
|
|
91
|
+
}
|
|
92
|
+
if (
|
|
93
|
+
lower.includes("rpc network unavailable") ||
|
|
94
|
+
lower.includes("rpc request failed") ||
|
|
95
|
+
lower.includes("rpc returned invalid json") ||
|
|
96
|
+
lower.includes("fetch failed") ||
|
|
97
|
+
lower.includes("network unavailable") ||
|
|
98
|
+
lower.includes("timeout")
|
|
99
|
+
) {
|
|
100
|
+
return "network_unavailable";
|
|
101
|
+
}
|
|
102
|
+
if (lower.includes("unknown walletid")) {
|
|
103
|
+
return "wallet_not_found";
|
|
104
|
+
}
|
|
105
|
+
if (lower.includes("invalid password")) {
|
|
106
|
+
return "invalid_password";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function errorStatusCode(errorCode, fallback = 400) {
|
|
113
|
+
if (errorCode === "wallet_locked" || errorCode === "insufficient_funds") {
|
|
114
|
+
return 409;
|
|
115
|
+
}
|
|
116
|
+
if (errorCode === "swap_quote_changed") {
|
|
117
|
+
return 409;
|
|
118
|
+
}
|
|
119
|
+
if (errorCode === "aave_quote_changed") {
|
|
120
|
+
return 409;
|
|
121
|
+
}
|
|
122
|
+
if (
|
|
123
|
+
errorCode === "swap_simulation_failed" ||
|
|
124
|
+
errorCode === "swap_approval_required" ||
|
|
125
|
+
errorCode === "swap_approval_failed" ||
|
|
126
|
+
errorCode === "swap_approval_timeout" ||
|
|
127
|
+
errorCode === "swap_cleanup_failed" ||
|
|
128
|
+
errorCode === "aave_approval_required" ||
|
|
129
|
+
errorCode === "aave_fee_unavailable" ||
|
|
130
|
+
errorCode === "aave_cleanup_failed" ||
|
|
131
|
+
errorCode === "token_transfer_failed" ||
|
|
132
|
+
errorCode === "fee_limit_exceeded"
|
|
133
|
+
) {
|
|
134
|
+
return 400;
|
|
135
|
+
}
|
|
136
|
+
if (errorCode === "token_read_failed") {
|
|
137
|
+
return 502;
|
|
138
|
+
}
|
|
139
|
+
if (errorCode === "network_unavailable") {
|
|
140
|
+
return 503;
|
|
141
|
+
}
|
|
142
|
+
if (errorCode === "wallet_not_found" || errorCode === "token_not_found") {
|
|
143
|
+
return 404;
|
|
144
|
+
}
|
|
145
|
+
return fallback;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function sanitizeProviderUrl(value) {
|
|
149
|
+
const raw = String(value || "").trim();
|
|
150
|
+
if (!raw) {
|
|
151
|
+
return raw;
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
const url = new URL(raw);
|
|
155
|
+
if (url.searchParams.has("token")) {
|
|
156
|
+
url.searchParams.set("token", "***");
|
|
157
|
+
}
|
|
158
|
+
return url.toString();
|
|
159
|
+
} catch {
|
|
160
|
+
return raw;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function sanitizeProfiles(profiles = {}) {
|
|
165
|
+
return Object.fromEntries(
|
|
166
|
+
Object.entries(profiles).map(([network, profile]) => [
|
|
167
|
+
network,
|
|
168
|
+
{
|
|
169
|
+
...profile,
|
|
170
|
+
providerUrl: sanitizeProviderUrl(profile?.providerUrl),
|
|
171
|
+
},
|
|
172
|
+
])
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function toErrorResponse(error, pathname, fallbackStatus = 400) {
|
|
177
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
178
|
+
const explicitCode =
|
|
179
|
+
(typeof error?.errorCode === "string" && error.errorCode.trim()) ||
|
|
180
|
+
(typeof error?.code === "string" && error.code.trim()) ||
|
|
181
|
+
"";
|
|
182
|
+
const errorCode = normalizeErrorCode(explicitCode, pathname, message);
|
|
183
|
+
const details =
|
|
184
|
+
error && typeof error === "object" && error.errorDetails && typeof error.errorDetails === "object"
|
|
185
|
+
? { ...error.errorDetails }
|
|
186
|
+
: {};
|
|
187
|
+
details.source = "wdk-evm-wallet";
|
|
188
|
+
details.path = pathname;
|
|
189
|
+
return {
|
|
190
|
+
statusCode: errorStatusCode(errorCode, fallbackStatus),
|
|
191
|
+
payload: {
|
|
192
|
+
ok: false,
|
|
193
|
+
error: message,
|
|
194
|
+
...(errorCode ? { error_code: errorCode } : {}),
|
|
195
|
+
error_details: details,
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function notFound(response) {
|
|
201
|
+
sendJson(response, 404, { ok: false, error: "Not Found" });
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function unauthorized(response) {
|
|
205
|
+
response.setHeader("WWW-Authenticate", 'Bearer realm="wdk-evm-wallet"');
|
|
206
|
+
sendJson(response, 401, { ok: false, error: "Unauthorized." });
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function pathRequiresAuth(pathname) {
|
|
210
|
+
return pathname !== "/health";
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function isAuthorized(request) {
|
|
214
|
+
const header = String(request.headers.authorization || "").trim();
|
|
215
|
+
if (!header.startsWith("Bearer ")) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
const provided = Buffer.from(header.slice("Bearer ".length).trim(), "utf8");
|
|
219
|
+
const expected = Buffer.from(String(config.authToken || ""), "utf8");
|
|
220
|
+
if (provided.length === 0 || provided.length !== expected.length) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
return crypto.timingSafeEqual(provided, expected);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async function withResolvedSeed(body = {}) {
|
|
227
|
+
const resolved = await vault.resolveSeedPhrase({
|
|
228
|
+
walletId: body.walletId,
|
|
229
|
+
seedPhrase: body.seedPhrase,
|
|
230
|
+
});
|
|
231
|
+
return {
|
|
232
|
+
...body,
|
|
233
|
+
seedPhrase: resolved.seedPhrase,
|
|
234
|
+
walletId: resolved.walletId ?? body.walletId ?? null,
|
|
235
|
+
credentialSource: resolved.source,
|
|
236
|
+
unlockExpiresAt: resolved.unlockExpiresAt ?? null,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async function withResolvedSeedOrAddress(body = {}) {
|
|
241
|
+
const address = typeof body.address === "string" ? body.address.trim() : "";
|
|
242
|
+
if (address) {
|
|
243
|
+
return {
|
|
244
|
+
...body,
|
|
245
|
+
address,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
return withResolvedSeed(body);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async function withResolvedNetwork(body = {}) {
|
|
252
|
+
const runtimeConfig = await networkState.resolveRuntimeConfig(body.network);
|
|
253
|
+
return {
|
|
254
|
+
...body,
|
|
255
|
+
network: runtimeConfig.network,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async function handleRequest(request, response) {
|
|
260
|
+
try {
|
|
261
|
+
const url = new URL(request.url || "/", "http://localhost");
|
|
262
|
+
const { method = "GET" } = request;
|
|
263
|
+
|
|
264
|
+
if (pathRequiresAuth(url.pathname) && !isAuthorized(request)) {
|
|
265
|
+
return unauthorized(response);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (method === "GET" && url.pathname === "/health") {
|
|
269
|
+
const runtimeConfig = await networkState.resolveRuntimeConfig();
|
|
270
|
+
const networkInfo = await networkState.getNetworkInfo();
|
|
271
|
+
return sendJson(response, 200, {
|
|
272
|
+
ok: true,
|
|
273
|
+
service: "wdk-evm-wallet",
|
|
274
|
+
version: "0.1.0",
|
|
275
|
+
wallet: "evm",
|
|
276
|
+
network: runtimeConfig.network,
|
|
277
|
+
chainId: runtimeConfig.chainId,
|
|
278
|
+
host: config.host,
|
|
279
|
+
dataDir: config.dataDir,
|
|
280
|
+
authRequired: config.authRequired,
|
|
281
|
+
unlockTimeoutSeconds: config.unlockTimeoutSeconds,
|
|
282
|
+
availableNetworks: Object.keys(config.networkProfiles),
|
|
283
|
+
provider: sanitizeProviderUrl(runtimeConfig.providerUrl),
|
|
284
|
+
networkProfiles: sanitizeProfiles(networkInfo.profiles),
|
|
285
|
+
source: "wdk",
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (method === "POST" && url.pathname === "/v1/evm/seed-phrase/generate") {
|
|
290
|
+
const body = await readJsonBody(request);
|
|
291
|
+
return sendJson(response, 200, {
|
|
292
|
+
ok: true,
|
|
293
|
+
data: service.generateSeedPhrase(body.words ?? 12),
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (method === "GET" && url.pathname === "/v1/evm/wallets") {
|
|
298
|
+
const activeNetwork = await networkState.getActiveNetwork();
|
|
299
|
+
return sendJson(response, 200, {
|
|
300
|
+
ok: true,
|
|
301
|
+
data: (await vault.listWallets()).map((wallet) => ({
|
|
302
|
+
...wallet,
|
|
303
|
+
activeNetwork,
|
|
304
|
+
})),
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (method === "GET" && url.pathname === "/v1/evm/network") {
|
|
309
|
+
return sendJson(response, 200, {
|
|
310
|
+
ok: true,
|
|
311
|
+
data: await networkState.getNetworkInfo(),
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (method === "POST" && url.pathname === "/v1/evm/network/set") {
|
|
316
|
+
const body = await readJsonBody(request);
|
|
317
|
+
return sendJson(response, 200, {
|
|
318
|
+
ok: true,
|
|
319
|
+
data: await networkState.setActiveNetwork(body),
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (method === "POST" && url.pathname === "/v1/evm/wallets/get") {
|
|
324
|
+
const body = await readJsonBody(request);
|
|
325
|
+
const activeNetwork = await networkState.getActiveNetwork();
|
|
326
|
+
return sendJson(response, 200, {
|
|
327
|
+
ok: true,
|
|
328
|
+
data: {
|
|
329
|
+
...(await vault.getWallet(body)),
|
|
330
|
+
activeNetwork,
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (method === "POST" && url.pathname === "/v1/evm/wallets/create") {
|
|
336
|
+
const body = await withResolvedNetwork(await readJsonBody(request));
|
|
337
|
+
return sendJson(response, 200, {
|
|
338
|
+
ok: true,
|
|
339
|
+
data: await vault.createWallet(body),
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (method === "POST" && url.pathname === "/v1/evm/wallets/import") {
|
|
344
|
+
const body = await withResolvedNetwork(await readJsonBody(request));
|
|
345
|
+
return sendJson(response, 200, {
|
|
346
|
+
ok: true,
|
|
347
|
+
data: await vault.importWallet(body),
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (method === "POST" && url.pathname === "/v1/evm/wallets/unlock") {
|
|
352
|
+
const body = await readJsonBody(request);
|
|
353
|
+
return sendJson(response, 200, {
|
|
354
|
+
ok: true,
|
|
355
|
+
data: await vault.unlockWallet(body),
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (method === "POST" && url.pathname === "/v1/evm/wallets/lock") {
|
|
360
|
+
const body = await readJsonBody(request);
|
|
361
|
+
return sendJson(response, 200, {
|
|
362
|
+
ok: true,
|
|
363
|
+
data: await vault.lockWallet(body),
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (method === "POST" && url.pathname === "/v1/evm/wallets/reveal-seed") {
|
|
368
|
+
const body = await readJsonBody(request);
|
|
369
|
+
return sendJson(response, 200, {
|
|
370
|
+
ok: true,
|
|
371
|
+
data: await vault.revealSeedPhrase(body),
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (method === "POST" && url.pathname === "/v1/evm/wallets/change-password") {
|
|
376
|
+
const body = await readJsonBody(request);
|
|
377
|
+
return sendJson(response, 200, {
|
|
378
|
+
ok: true,
|
|
379
|
+
data: await vault.changePassword(body),
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (method === "POST" && url.pathname === "/v1/evm/address/resolve") {
|
|
384
|
+
const body = await withResolvedNetwork(await withResolvedSeed(await readJsonBody(request)));
|
|
385
|
+
const data = await service.resolveAddress(body);
|
|
386
|
+
return sendJson(response, 200, { ok: true, data });
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (method === "POST" && url.pathname === "/v1/evm/balance/get") {
|
|
390
|
+
const body = await withResolvedNetwork(await withResolvedSeedOrAddress(await readJsonBody(request)));
|
|
391
|
+
const data = await service.getBalance(body);
|
|
392
|
+
return sendJson(response, 200, { ok: true, data });
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (method === "POST" && url.pathname === "/v1/evm/token-balance/get") {
|
|
396
|
+
const body = await withResolvedNetwork(await withResolvedSeedOrAddress(await readJsonBody(request)));
|
|
397
|
+
const data = await service.getTokenBalance(body);
|
|
398
|
+
return sendJson(response, 200, { ok: true, data });
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (method === "POST" && url.pathname === "/v1/evm/token-metadata/get") {
|
|
402
|
+
const body = await withResolvedNetwork(await readJsonBody(request));
|
|
403
|
+
const data = await service.getTokenMetadata(body);
|
|
404
|
+
return sendJson(response, 200, { ok: true, data });
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (method === "POST" && url.pathname === "/v1/evm/fee-rates/get") {
|
|
408
|
+
const body = await withResolvedNetwork(await readJsonBody(request));
|
|
409
|
+
const data = await service.getFeeRates(body);
|
|
410
|
+
return sendJson(response, 200, { ok: true, data });
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (method === "POST" && url.pathname === "/v1/evm/transaction/receipt/get") {
|
|
414
|
+
const body = await withResolvedNetwork(await readJsonBody(request));
|
|
415
|
+
const data = await service.getTransactionReceipt(body);
|
|
416
|
+
return sendJson(response, 200, { ok: true, data });
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (method === "POST" && url.pathname === "/v1/evm/aave/account/get") {
|
|
420
|
+
const body = await withResolvedNetwork(await withResolvedSeedOrAddress(await readJsonBody(request)));
|
|
421
|
+
const data = await service.getAaveAccountData(body);
|
|
422
|
+
return sendJson(response, 200, { ok: true, data });
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (method === "POST" && url.pathname === "/v1/evm/aave/reserves/get") {
|
|
426
|
+
const body = await withResolvedNetwork(await withResolvedSeedOrAddress(await readJsonBody(request)));
|
|
427
|
+
const data = await service.getAaveReserves(body);
|
|
428
|
+
return sendJson(response, 200, { ok: true, data });
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (method === "POST" && url.pathname === "/v1/evm/aave/positions/get") {
|
|
432
|
+
const body = await withResolvedNetwork(await withResolvedSeedOrAddress(await readJsonBody(request)));
|
|
433
|
+
const data = await service.getAavePositions(body);
|
|
434
|
+
return sendJson(response, 200, { ok: true, data });
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (method === "POST" && url.pathname === "/v1/evm/lido/overview/get") {
|
|
438
|
+
const body = await withResolvedNetwork(await withResolvedSeedOrAddress(await readJsonBody(request)));
|
|
439
|
+
const data = await service.getLidoOverview(body);
|
|
440
|
+
return sendJson(response, 200, { ok: true, data });
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (method === "POST" && url.pathname === "/v1/evm/lido/positions/get") {
|
|
444
|
+
const body = await withResolvedNetwork(await withResolvedSeedOrAddress(await readJsonBody(request)));
|
|
445
|
+
const data = await service.getLidoPositions(body);
|
|
446
|
+
return sendJson(response, 200, { ok: true, data });
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (method === "POST" && url.pathname === "/v1/evm/lido/withdrawals/get") {
|
|
450
|
+
const body = await withResolvedNetwork(await withResolvedSeedOrAddress(await readJsonBody(request)));
|
|
451
|
+
const data = await service.getLidoWithdrawalRequests(body);
|
|
452
|
+
return sendJson(response, 200, { ok: true, data });
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const aaveOperationMatch = url.pathname.match(
|
|
456
|
+
/^\/v1\/evm\/aave\/(supply|withdraw|borrow|repay)\/(quote|send)$/
|
|
457
|
+
);
|
|
458
|
+
if (method === "POST" && aaveOperationMatch) {
|
|
459
|
+
const operation = aaveOperationMatch[1];
|
|
460
|
+
const action = aaveOperationMatch[2];
|
|
461
|
+
const rawBody = await readJsonBody(request);
|
|
462
|
+
const body =
|
|
463
|
+
action === "quote"
|
|
464
|
+
? await withResolvedNetwork(await withResolvedSeedOrAddress(rawBody))
|
|
465
|
+
: await withResolvedNetwork(await withResolvedSeed(rawBody));
|
|
466
|
+
const data =
|
|
467
|
+
action === "quote"
|
|
468
|
+
? await service.quoteAaveOperation({ ...body, operation })
|
|
469
|
+
: await service.sendAaveOperation({ ...body, operation });
|
|
470
|
+
return sendJson(response, 200, { ok: true, data });
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const lidoOperationMatch = url.pathname.match(
|
|
474
|
+
/^\/v1\/evm\/lido\/(stake_eth_for_wsteth|wrap_steth|unwrap_wsteth)\/(quote|send)$/
|
|
475
|
+
);
|
|
476
|
+
if (method === "POST" && lidoOperationMatch) {
|
|
477
|
+
const operation = lidoOperationMatch[1];
|
|
478
|
+
const action = lidoOperationMatch[2];
|
|
479
|
+
const rawBody = await readJsonBody(request);
|
|
480
|
+
const body =
|
|
481
|
+
action === "quote"
|
|
482
|
+
? await withResolvedNetwork(await withResolvedSeedOrAddress(rawBody))
|
|
483
|
+
: await withResolvedNetwork(await withResolvedSeed(rawBody));
|
|
484
|
+
const data =
|
|
485
|
+
action === "quote"
|
|
486
|
+
? await service.quoteLidoOperation({ ...body, operation })
|
|
487
|
+
: await service.sendLidoOperation({ ...body, operation });
|
|
488
|
+
return sendJson(response, 200, { ok: true, data });
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
const lidoWithdrawalOperationMatch = url.pathname.match(
|
|
492
|
+
/^\/v1\/evm\/lido\/(request_withdrawal_steth|request_withdrawal_wsteth|claim_withdrawal)\/(quote|send)$/
|
|
493
|
+
);
|
|
494
|
+
if (method === "POST" && lidoWithdrawalOperationMatch) {
|
|
495
|
+
const operation = lidoWithdrawalOperationMatch[1];
|
|
496
|
+
const action = lidoWithdrawalOperationMatch[2];
|
|
497
|
+
const rawBody = await readJsonBody(request);
|
|
498
|
+
const body =
|
|
499
|
+
action === "quote"
|
|
500
|
+
? await withResolvedNetwork(await withResolvedSeedOrAddress(rawBody))
|
|
501
|
+
: await withResolvedNetwork(await withResolvedSeed(rawBody));
|
|
502
|
+
const data =
|
|
503
|
+
action === "quote"
|
|
504
|
+
? await service.quoteLidoWithdrawalOperation({ ...body, operation })
|
|
505
|
+
: await service.sendLidoWithdrawalOperation({ ...body, operation });
|
|
506
|
+
return sendJson(response, 200, { ok: true, data });
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (method === "POST" && url.pathname === "/v1/evm/swap/quote") {
|
|
510
|
+
const body = await withResolvedNetwork(await withResolvedSeedOrAddress(await readJsonBody(request)));
|
|
511
|
+
const data = await service.quoteSwap(body);
|
|
512
|
+
return sendJson(response, 200, { ok: true, data });
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (method === "POST" && url.pathname === "/v1/evm/swap/send") {
|
|
516
|
+
const body = await withResolvedNetwork(await withResolvedSeed(await readJsonBody(request)));
|
|
517
|
+
const data = await service.swap(body);
|
|
518
|
+
return sendJson(response, 200, { ok: true, data });
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (method === "POST" && url.pathname === "/v1/evm/lifi/quote") {
|
|
522
|
+
const body = await withResolvedNetwork(await withResolvedSeedOrAddress(await readJsonBody(request)));
|
|
523
|
+
const data = await service.quoteLifiSwap(body);
|
|
524
|
+
return sendJson(response, 200, { ok: true, data });
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (method === "POST" && url.pathname === "/v1/evm/lifi/send") {
|
|
528
|
+
const body = await withResolvedNetwork(await withResolvedSeed(await readJsonBody(request)));
|
|
529
|
+
const data = await service.sendLifiSwap(body);
|
|
530
|
+
return sendJson(response, 200, { ok: true, data });
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (method === "POST" && url.pathname === "/v1/evm/transfer/quote") {
|
|
534
|
+
const body = await withResolvedNetwork(await withResolvedSeed(await readJsonBody(request)));
|
|
535
|
+
const data = await service.quoteNativeTransfer(body);
|
|
536
|
+
return sendJson(response, 200, { ok: true, data });
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (method === "POST" && url.pathname === "/v1/evm/transfer/send") {
|
|
540
|
+
const body = await withResolvedNetwork(await withResolvedSeed(await readJsonBody(request)));
|
|
541
|
+
const data = await service.sendNativeTransfer(body);
|
|
542
|
+
return sendJson(response, 200, { ok: true, data });
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (method === "POST" && url.pathname === "/v1/evm/token-transfer/quote") {
|
|
546
|
+
const body = await withResolvedNetwork(await withResolvedSeed(await readJsonBody(request)));
|
|
547
|
+
const data = await service.quoteTokenTransfer(body);
|
|
548
|
+
return sendJson(response, 200, { ok: true, data });
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (method === "POST" && url.pathname === "/v1/evm/token-transfer/send") {
|
|
552
|
+
const body = await withResolvedNetwork(await withResolvedSeed(await readJsonBody(request)));
|
|
553
|
+
const data = await service.sendTokenTransfer(body);
|
|
554
|
+
return sendJson(response, 200, { ok: true, data });
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
return notFound(response);
|
|
558
|
+
} catch (error) {
|
|
559
|
+
const shaped = toErrorResponse(error, new URL(request.url || "/", "http://localhost").pathname, 400);
|
|
560
|
+
return sendJson(response, shaped.statusCode, shaped.payload);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
const server = createServer((request, response) => {
|
|
565
|
+
handleRequest(request, response).catch((error) => {
|
|
566
|
+
const shaped = toErrorResponse(error, new URL(request.url || "/", "http://localhost").pathname, 500);
|
|
567
|
+
sendJson(response, shaped.statusCode, shaped.payload);
|
|
568
|
+
});
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
server.listen(config.port, config.host, () => {
|
|
572
|
+
console.log(
|
|
573
|
+
`wdk-evm-wallet listening on ${config.host}:${config.port} (${config.network})`
|
|
574
|
+
);
|
|
575
|
+
});
|