@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.
Files changed (96) hide show
  1. package/.openclaw/AGENTS.md +98 -0
  2. package/.openclaw/extensions/agent-wallet/README.md +127 -0
  3. package/.openclaw/extensions/agent-wallet/index.ts +1520 -0
  4. package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +184 -0
  5. package/.openclaw/extensions/agent-wallet/package.json +11 -0
  6. package/.openclaw/extensions/agent-wallet/skills/wallet-operator/SKILL.md +20 -0
  7. package/CHANGELOG.md +42 -0
  8. package/LICENSE +104 -0
  9. package/README.md +332 -0
  10. package/RELEASING.md +204 -0
  11. package/agent-wallet/.env.example +62 -0
  12. package/agent-wallet/AGENTS.md +129 -0
  13. package/agent-wallet/README.md +527 -0
  14. package/agent-wallet/agent_wallet/__init__.py +11 -0
  15. package/agent-wallet/agent_wallet/approval.py +161 -0
  16. package/agent-wallet/agent_wallet/bootstrap.py +178 -0
  17. package/agent-wallet/agent_wallet/btc_user_wallets.py +217 -0
  18. package/agent-wallet/agent_wallet/config.py +382 -0
  19. package/agent-wallet/agent_wallet/encrypted_storage.py +161 -0
  20. package/agent-wallet/agent_wallet/evm_user_wallets.py +370 -0
  21. package/agent-wallet/agent_wallet/exceptions.py +9 -0
  22. package/agent-wallet/agent_wallet/file_ops.py +34 -0
  23. package/agent-wallet/agent_wallet/http_client.py +25 -0
  24. package/agent-wallet/agent_wallet/models.py +66 -0
  25. package/agent-wallet/agent_wallet/nonce_registry.py +59 -0
  26. package/agent-wallet/agent_wallet/openclaw_adapter.py +5128 -0
  27. package/agent-wallet/agent_wallet/openclaw_cli.py +626 -0
  28. package/agent-wallet/agent_wallet/openclaw_runtime.py +272 -0
  29. package/agent-wallet/agent_wallet/plugin_bundle.py +42 -0
  30. package/agent-wallet/agent_wallet/providers/__init__.py +1 -0
  31. package/agent-wallet/agent_wallet/providers/bags.py +259 -0
  32. package/agent-wallet/agent_wallet/providers/evm_portfolio.py +470 -0
  33. package/agent-wallet/agent_wallet/providers/jupiter.py +567 -0
  34. package/agent-wallet/agent_wallet/providers/kamino.py +215 -0
  35. package/agent-wallet/agent_wallet/providers/lifi.py +277 -0
  36. package/agent-wallet/agent_wallet/providers/solana_rpc.py +470 -0
  37. package/agent-wallet/agent_wallet/providers/wdk_btc_local.py +114 -0
  38. package/agent-wallet/agent_wallet/providers/wdk_evm_local.py +205 -0
  39. package/agent-wallet/agent_wallet/sealed_keys.py +61 -0
  40. package/agent-wallet/agent_wallet/solana_stake.py +103 -0
  41. package/agent-wallet/agent_wallet/solana_tx.py +93 -0
  42. package/agent-wallet/agent_wallet/spending_limits.py +101 -0
  43. package/agent-wallet/agent_wallet/transaction_policy.py +518 -0
  44. package/agent-wallet/agent_wallet/user_wallets.py +355 -0
  45. package/agent-wallet/agent_wallet/validation.py +31 -0
  46. package/agent-wallet/agent_wallet/wallet_layer/__init__.py +1 -0
  47. package/agent-wallet/agent_wallet/wallet_layer/base.py +808 -0
  48. package/agent-wallet/agent_wallet/wallet_layer/base58.py +44 -0
  49. package/agent-wallet/agent_wallet/wallet_layer/factory.py +102 -0
  50. package/agent-wallet/agent_wallet/wallet_layer/solana.py +4252 -0
  51. package/agent-wallet/agent_wallet/wallet_layer/wdk_btc.py +272 -0
  52. package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +1628 -0
  53. package/agent-wallet/examples/bootstrap_wallet.py +21 -0
  54. package/agent-wallet/examples/openclaw_runtime_onboarding.py +28 -0
  55. package/agent-wallet/examples/openclaw_user_wallet_example.py +31 -0
  56. package/agent-wallet/examples/openclaw_wallet_adapter_example.py +33 -0
  57. package/agent-wallet/openclaw.plugin.json +138 -0
  58. package/agent-wallet/pyproject.toml +31 -0
  59. package/agent-wallet/scripts/bootstrap_openclaw_btc.py +278 -0
  60. package/agent-wallet/scripts/build_release_bundle.py +188 -0
  61. package/agent-wallet/scripts/finalize_openclaw_local_wallet_config.py +121 -0
  62. package/agent-wallet/scripts/install_agent_wallet.py +505 -0
  63. package/agent-wallet/scripts/install_openclaw_local_config.py +226 -0
  64. package/agent-wallet/scripts/install_openclaw_sealed_keys.py +105 -0
  65. package/agent-wallet/scripts/manage_openclaw_btc_wallet.py +244 -0
  66. package/agent-wallet/scripts/reveal_btc_seed.sh +130 -0
  67. package/agent-wallet/scripts/security_utils.py +37 -0
  68. package/agent-wallet/scripts/setup_btc_wallet.sh +146 -0
  69. package/agent-wallet/scripts/switch_openclaw_wallet_network.py +106 -0
  70. package/agent-wallet/skills/wallet-operator/SKILL.md +128 -0
  71. package/bin/openclaw-agent-wallet.mjs +487 -0
  72. package/install-from-github.sh +134 -0
  73. package/package.json +61 -0
  74. package/setup.sh +40 -0
  75. package/wdk-btc-wallet/README.md +325 -0
  76. package/wdk-btc-wallet/bootstrap.sh +22 -0
  77. package/wdk-btc-wallet/package-lock.json +1839 -0
  78. package/wdk-btc-wallet/package.json +18 -0
  79. package/wdk-btc-wallet/run-local.sh +21 -0
  80. package/wdk-btc-wallet/src/config.js +160 -0
  81. package/wdk-btc-wallet/src/json.js +35 -0
  82. package/wdk-btc-wallet/src/local_vault.js +432 -0
  83. package/wdk-btc-wallet/src/network_state.js +84 -0
  84. package/wdk-btc-wallet/src/server.js +257 -0
  85. package/wdk-btc-wallet/src/wdk_btc_wallet.js +332 -0
  86. package/wdk-evm-wallet/README.md +183 -0
  87. package/wdk-evm-wallet/bootstrap.sh +8 -0
  88. package/wdk-evm-wallet/package-lock.json +2340 -0
  89. package/wdk-evm-wallet/package.json +23 -0
  90. package/wdk-evm-wallet/run-local.sh +12 -0
  91. package/wdk-evm-wallet/src/config.js +274 -0
  92. package/wdk-evm-wallet/src/json.js +35 -0
  93. package/wdk-evm-wallet/src/local_vault.js +430 -0
  94. package/wdk-evm-wallet/src/network_state.js +92 -0
  95. package/wdk-evm-wallet/src/server.js +575 -0
  96. package/wdk-evm-wallet/src/wdk_evm_wallet.js +4981 -0
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "wdk-evm-wallet",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "description": "Separate EVM wallet service built on Tether WDK.",
7
+ "scripts": {
8
+ "bootstrap": "sh ./bootstrap.sh",
9
+ "start:local": "sh ./run-local.sh",
10
+ "start": "node src/server.js",
11
+ "check": "node --check src/server.js && node --check src/wdk_evm_wallet.js && node --check src/config.js && node --check src/json.js && node --check src/local_vault.js && node --check src/network_state.js",
12
+ "test:swap-runtime": "node --test --test-concurrency=1 tests/smoke_swap_runtime.mjs",
13
+ "test:aave-runtime": "node --test --test-concurrency=1 tests/smoke_aave_runtime.mjs",
14
+ "test:lido-runtime": "node --test --test-concurrency=1 tests/smoke_lido_runtime.mjs"
15
+ },
16
+ "dependencies": {
17
+ "@tetherto/wdk": "^1.0.0-beta.6",
18
+ "@tetherto/wdk-protocol-lending-aave-evm": "^1.0.0-beta.3",
19
+ "@tetherto/wdk-protocol-swap-velora-evm": "^1.0.0-beta.4",
20
+ "@tetherto/wdk-wallet-evm": "^1.0.0-beta.4",
21
+ "dotenv": "^16.4.5"
22
+ }
23
+ }
@@ -0,0 +1,12 @@
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ if [ ! -f .env ]; then
5
+ cp .env.example .env
6
+ fi
7
+
8
+ if [ ! -d node_modules ]; then
9
+ npm install
10
+ fi
11
+
12
+ npm start
@@ -0,0 +1,274 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+
6
+ const DEFAULTS = {
7
+ host: "127.0.0.1",
8
+ port: 8081,
9
+ network: "sepolia",
10
+ unlockTimeoutSeconds: 0,
11
+ };
12
+ const DEFAULT_PROVIDER_GATEWAY_URL = "https://agent-layer-production.up.railway.app";
13
+
14
+ const DEFAULT_NETWORK_PROFILES = {
15
+ ethereum: {
16
+ chainId: 1,
17
+ providerUrl: "https://eth.drpc.org",
18
+ nativeSymbol: "ETH",
19
+ },
20
+ sepolia: {
21
+ chainId: 11155111,
22
+ providerUrl: "https://sepolia.drpc.org",
23
+ nativeSymbol: "ETH",
24
+ },
25
+ base: {
26
+ chainId: 8453,
27
+ providerUrl: "https://mainnet.base.org",
28
+ nativeSymbol: "ETH",
29
+ },
30
+ "base-sepolia": {
31
+ chainId: 84532,
32
+ providerUrl: "https://sepolia.base.org",
33
+ nativeSymbol: "ETH",
34
+ },
35
+ };
36
+
37
+ const SUPPORTED_GATEWAY_PROVIDERS = new Set(["auto", "shared", "alchemy"]);
38
+
39
+ function parseProviderMode(value, fallback = "public") {
40
+ const normalized = String(value ?? "").trim().toLowerCase();
41
+ if (!normalized) {
42
+ return fallback;
43
+ }
44
+ if (!["public", "gateway"].includes(normalized)) {
45
+ throw new Error("WDK_EVM_RPC_PROVIDER_MODE must be either 'public' or 'gateway'.");
46
+ }
47
+ return normalized;
48
+ }
49
+
50
+ function parseGatewayProvider(value, fallback = "alchemy") {
51
+ const normalized = String(value ?? "").trim().toLowerCase();
52
+ if (!normalized) {
53
+ return fallback;
54
+ }
55
+ if (!SUPPORTED_GATEWAY_PROVIDERS.has(normalized)) {
56
+ throw new Error("WDK_EVM_RPC_GATEWAY_PROVIDER must be one of: auto, shared, alchemy.");
57
+ }
58
+ return normalized;
59
+ }
60
+
61
+ function parseInteger(value, fallback, fieldName) {
62
+ const normalized = String(value ?? "").trim();
63
+ if (!normalized) {
64
+ return fallback;
65
+ }
66
+ const parsed = Number.parseInt(normalized, 10);
67
+ if (!Number.isFinite(parsed) || parsed <= 0) {
68
+ throw new Error(`${fieldName} must be a positive integer.`);
69
+ }
70
+ return parsed;
71
+ }
72
+
73
+ function parseNonNegativeInteger(value, fallback, fieldName) {
74
+ const normalized = String(value ?? "").trim();
75
+ if (!normalized) {
76
+ return fallback;
77
+ }
78
+ const parsed = Number.parseInt(normalized, 10);
79
+ if (!Number.isFinite(parsed) || parsed < 0) {
80
+ throw new Error(`${fieldName} must be a non-negative integer.`);
81
+ }
82
+ return parsed;
83
+ }
84
+
85
+ function parseOptionalBigInt(value, fieldName) {
86
+ const normalized = String(value ?? "").trim();
87
+ if (!normalized) {
88
+ return null;
89
+ }
90
+ if (!/^[0-9]+$/.test(normalized)) {
91
+ throw new Error(`${fieldName} must be a base-10 integer string.`);
92
+ }
93
+ return BigInt(normalized);
94
+ }
95
+
96
+ function resolveOpenClawHome(env) {
97
+ const configured = String(env.OPENCLAW_HOME ?? "").trim();
98
+ if (!configured) {
99
+ return path.join(os.homedir(), ".openclaw");
100
+ }
101
+ if (configured === "~") {
102
+ return os.homedir();
103
+ }
104
+ if (configured.startsWith("~/")) {
105
+ return path.join(os.homedir(), configured.slice(2));
106
+ }
107
+ return configured;
108
+ }
109
+
110
+ function ensureLocalAuthToken(tokenPath, configuredToken = "") {
111
+ const direct = String(configuredToken ?? "").trim();
112
+ if (direct) {
113
+ return direct;
114
+ }
115
+ fs.mkdirSync(path.dirname(tokenPath), { recursive: true, mode: 0o700 });
116
+ try {
117
+ const existing = fs.readFileSync(tokenPath, "utf8").trim();
118
+ if (existing) {
119
+ fs.chmodSync(tokenPath, 0o600);
120
+ return existing;
121
+ }
122
+ } catch {
123
+ // Generate a new token below.
124
+ }
125
+
126
+ const generated = crypto.randomBytes(32).toString("hex");
127
+ fs.writeFileSync(tokenPath, `${generated}\n`, {
128
+ encoding: "utf8",
129
+ mode: 0o600,
130
+ });
131
+ fs.chmodSync(tokenPath, 0o600);
132
+ return generated;
133
+ }
134
+
135
+ function normalizeNetworkKey(value) {
136
+ const normalized = String(value ?? "").trim().toLowerCase();
137
+ const aliases = {
138
+ mainnet: "ethereum",
139
+ eth: "ethereum",
140
+ "eth-mainnet": "ethereum",
141
+ "base-mainnet": "base",
142
+ base_sepolia: "base-sepolia",
143
+ };
144
+ return aliases[normalized] || normalized;
145
+ }
146
+
147
+ function joinUrl(base, pathname) {
148
+ const normalizedBase = String(base || "").trim();
149
+ if (!normalizedBase) {
150
+ return "";
151
+ }
152
+ const url = new URL(pathname.replace(/^\//, ""), normalizedBase.endsWith("/") ? normalizedBase : `${normalizedBase}/`);
153
+ return url;
154
+ }
155
+
156
+ function buildGatewayEvmRpcUrl(baseUrl, network, provider, token) {
157
+ const url = joinUrl(baseUrl, `/v1/evm/rpc/${network}`);
158
+ if (!url) {
159
+ return "";
160
+ }
161
+ if (provider && provider !== "auto") {
162
+ url.searchParams.set("provider", provider);
163
+ }
164
+ if (String(token || "").trim()) {
165
+ url.searchParams.set("token", String(token).trim());
166
+ }
167
+ return url.toString();
168
+ }
169
+
170
+ export function loadConfig(env = process.env) {
171
+ const host = String(env.HOST ?? DEFAULTS.host).trim() || DEFAULTS.host;
172
+ const network = normalizeNetworkKey(env.WDK_EVM_NETWORK ?? DEFAULTS.network) || DEFAULTS.network;
173
+ if (!Object.hasOwn(DEFAULT_NETWORK_PROFILES, network)) {
174
+ throw new Error(
175
+ "WDK_EVM_NETWORK must be one of: ethereum, sepolia, base, base-sepolia."
176
+ );
177
+ }
178
+
179
+ const openClawHome = resolveOpenClawHome(env);
180
+ const dataDir =
181
+ String(env.WDK_EVM_DATA_DIR ?? "").trim() ||
182
+ path.join(openClawHome, "wdk-evm-wallet");
183
+ const authTokenPath =
184
+ String(env.WDK_EVM_LOCAL_TOKEN_PATH ?? "").trim() ||
185
+ path.join(openClawHome, "wdk-evm-wallet", "local-auth-token");
186
+ const providerMode = parseProviderMode(env.WDK_EVM_RPC_PROVIDER_MODE, "gateway");
187
+ const providerGatewayUrl =
188
+ String(env.PROVIDER_GATEWAY_URL ?? "").trim() || DEFAULT_PROVIDER_GATEWAY_URL;
189
+ const providerGatewayToken = String(env.PROVIDER_GATEWAY_BEARER_TOKEN ?? "").trim();
190
+ const gatewayProvider = parseGatewayProvider(env.WDK_EVM_RPC_GATEWAY_PROVIDER, "alchemy");
191
+
192
+ function resolveProviderUrl(networkKey, envValue, fallbackUrl) {
193
+ const direct = String(envValue ?? "").trim();
194
+ if (direct) {
195
+ return direct;
196
+ }
197
+ if (
198
+ providerMode === "gateway" &&
199
+ providerGatewayUrl &&
200
+ ["ethereum", "base"].includes(networkKey)
201
+ ) {
202
+ return (
203
+ buildGatewayEvmRpcUrl(providerGatewayUrl, networkKey, gatewayProvider, providerGatewayToken) ||
204
+ fallbackUrl
205
+ );
206
+ }
207
+ return fallbackUrl;
208
+ }
209
+
210
+ const networkProfiles = {
211
+ ethereum: {
212
+ ...DEFAULT_NETWORK_PROFILES.ethereum,
213
+ providerUrl: resolveProviderUrl(
214
+ "ethereum",
215
+ env.WDK_EVM_ETHEREUM_RPC_URL,
216
+ DEFAULT_NETWORK_PROFILES.ethereum.providerUrl
217
+ ),
218
+ },
219
+ sepolia: {
220
+ ...DEFAULT_NETWORK_PROFILES.sepolia,
221
+ providerUrl: resolveProviderUrl(
222
+ "sepolia",
223
+ env.WDK_EVM_SEPOLIA_RPC_URL,
224
+ DEFAULT_NETWORK_PROFILES.sepolia.providerUrl
225
+ ),
226
+ },
227
+ base: {
228
+ ...DEFAULT_NETWORK_PROFILES.base,
229
+ providerUrl: resolveProviderUrl(
230
+ "base",
231
+ env.WDK_EVM_BASE_RPC_URL,
232
+ DEFAULT_NETWORK_PROFILES.base.providerUrl
233
+ ),
234
+ },
235
+ "base-sepolia": {
236
+ ...DEFAULT_NETWORK_PROFILES["base-sepolia"],
237
+ providerUrl: resolveProviderUrl(
238
+ "base-sepolia",
239
+ env.WDK_EVM_BASE_SEPOLIA_RPC_URL,
240
+ DEFAULT_NETWORK_PROFILES["base-sepolia"].providerUrl
241
+ ),
242
+ },
243
+ };
244
+
245
+ return {
246
+ host,
247
+ port: parseInteger(env.PORT, DEFAULTS.port, "PORT"),
248
+ network,
249
+ openClawHome,
250
+ dataDir,
251
+ authRequired: true,
252
+ authTokenPath,
253
+ authToken: ensureLocalAuthToken(authTokenPath, env.WDK_EVM_LOCAL_TOKEN),
254
+ rpcProviderMode: providerMode,
255
+ rpcGatewayUrl: providerGatewayUrl,
256
+ rpcGatewayProvider: gatewayProvider,
257
+ unlockTimeoutSeconds: parseNonNegativeInteger(
258
+ env.WDK_EVM_UNLOCK_TIMEOUT_SECONDS,
259
+ DEFAULTS.unlockTimeoutSeconds,
260
+ "WDK_EVM_UNLOCK_TIMEOUT_SECONDS"
261
+ ),
262
+ transferMaxFeeWei: parseOptionalBigInt(
263
+ env.WDK_EVM_TRANSFER_MAX_FEE_WEI,
264
+ "WDK_EVM_TRANSFER_MAX_FEE_WEI"
265
+ ),
266
+ lifiApiBaseUrl: String(env.LIFI_API_BASE_URL ?? "").trim() || "https://li.quest/v1",
267
+ lifiApiKey: String(env.LIFI_API_KEY ?? "").trim(),
268
+ lifiIntegrator: String(env.LIFI_INTEGRATOR ?? "").trim() || "openclaw",
269
+ lifiDefaultDenyBridges: String(env.LIFI_DEFAULT_DENY_BRIDGES ?? "").trim() || "mayan",
270
+ lidoApiBaseUrl: String(env.LIDO_API_BASE_URL ?? "").trim() || "https://eth-api.lido.fi/v1",
271
+ lidoReferralAddress: String(env.LIDO_REFERRAL_ADDRESS ?? "").trim(),
272
+ networkProfiles,
273
+ };
274
+ }
@@ -0,0 +1,35 @@
1
+ export function jsonSafe(value) {
2
+ if (typeof value === "bigint") {
3
+ return value.toString();
4
+ }
5
+ if (Array.isArray(value)) {
6
+ return value.map((item) => jsonSafe(item));
7
+ }
8
+ if (value && typeof value === "object") {
9
+ return Object.fromEntries(
10
+ Object.entries(value).map(([key, item]) => [key, jsonSafe(item)])
11
+ );
12
+ }
13
+ return value;
14
+ }
15
+
16
+ export function sendJson(response, statusCode, payload) {
17
+ const body = JSON.stringify(jsonSafe(payload));
18
+ response.writeHead(statusCode, {
19
+ "Content-Type": "application/json",
20
+ "Content-Length": Buffer.byteLength(body),
21
+ });
22
+ response.end(body);
23
+ }
24
+
25
+ export async function readJsonBody(request) {
26
+ const chunks = [];
27
+ for await (const chunk of request) {
28
+ chunks.push(chunk);
29
+ }
30
+ const raw = Buffer.concat(chunks).toString("utf8").trim();
31
+ if (!raw) {
32
+ return {};
33
+ }
34
+ return JSON.parse(raw);
35
+ }