@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,272 @@
1
+ """Local BTC backend backed by the wdk-btc-wallet service."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from agent_wallet.providers.wdk_btc_local import WdkBtcLocalClient
8
+ from agent_wallet.wallet_layer.base import AgentWalletBackend, WalletBackendError, WalletCapabilities
9
+
10
+
11
+ def _sats_to_btc(value: Any) -> float:
12
+ return int(value) / 100_000_000
13
+
14
+
15
+ def _normalize_btc_network(value: str | None) -> str:
16
+ network = str(value or "").strip().lower()
17
+ aliases = {
18
+ "mainnet": "bitcoin",
19
+ }
20
+ network = aliases.get(network, network)
21
+ if network not in {"bitcoin", "testnet", "regtest"}:
22
+ return "bitcoin"
23
+ return network
24
+
25
+
26
+ class WdkBtcLocalWalletBackend(AgentWalletBackend):
27
+ """Bitcoin backend that delegates signing and execution to a local WDK service."""
28
+
29
+ name = "wdk_btc_local"
30
+
31
+ def __init__(
32
+ self,
33
+ *,
34
+ service_url: str,
35
+ wallet_id: str,
36
+ network: str,
37
+ account_index: int = 0,
38
+ sign_only: bool = False,
39
+ address: str | None = None,
40
+ ):
41
+ self.client = WdkBtcLocalClient(service_url)
42
+ self.wallet_id = str(wallet_id or "").strip()
43
+ if not self.wallet_id:
44
+ raise WalletBackendError("WDK BTC wallet id is not configured.")
45
+ self.network = _normalize_btc_network(network)
46
+ self.account_index = int(account_index)
47
+ self.sign_only = bool(sign_only)
48
+ self.address = address.strip() if isinstance(address, str) and address.strip() else None
49
+ self.chain = "bitcoin"
50
+ self.custody_model = "local_service_vault"
51
+
52
+ async def get_address(self) -> str | None:
53
+ if self.address:
54
+ return self.address
55
+ data = await self.client.post(
56
+ "/v1/btc/address/resolve",
57
+ {
58
+ "walletId": self.wallet_id,
59
+ "accountIndex": self.account_index,
60
+ "network": self.network,
61
+ },
62
+ )
63
+ address = str(data.get("address") or "").strip()
64
+ if not address:
65
+ raise WalletBackendError("wdk-btc-wallet did not return an address.")
66
+ self.address = address
67
+ return address
68
+
69
+ async def get_balance(self, address: str | None = None) -> dict[str, Any]:
70
+ resolved_address = await self.get_address()
71
+ if address is not None and address.strip() and address.strip() != resolved_address:
72
+ raise WalletBackendError(
73
+ "wdk_btc_local only supports the configured default BTC account address."
74
+ )
75
+ data = await self.client.post(
76
+ "/v1/btc/balance/get",
77
+ {
78
+ "walletId": self.wallet_id,
79
+ "accountIndex": self.account_index,
80
+ "network": self.network,
81
+ },
82
+ )
83
+ balance_sats = int(data.get("balance") or 0)
84
+ return {
85
+ "chain": self.chain,
86
+ "network": self.network,
87
+ "address": str(data.get("address") or resolved_address or ""),
88
+ "balance_sats": balance_sats,
89
+ "balance_native": _sats_to_btc(balance_sats),
90
+ "asset": "BTC",
91
+ "source": "wdk-btc-wallet",
92
+ }
93
+
94
+ async def get_btc_transfer_history(
95
+ self,
96
+ *,
97
+ direction: str = "all",
98
+ limit: int = 10,
99
+ skip: int = 0,
100
+ ) -> dict[str, Any]:
101
+ data = await self.client.post(
102
+ "/v1/btc/transfers/get",
103
+ {
104
+ "walletId": self.wallet_id,
105
+ "accountIndex": self.account_index,
106
+ "network": self.network,
107
+ "direction": direction,
108
+ "limit": limit,
109
+ "skip": skip,
110
+ },
111
+ )
112
+ return {
113
+ "chain": self.chain,
114
+ "network": self.network,
115
+ "address": str(data.get("address") or await self.get_address() or ""),
116
+ "direction": direction,
117
+ "limit": limit,
118
+ "skip": skip,
119
+ "transfers": list(data.get("transfers") or []),
120
+ "source": "wdk-btc-wallet",
121
+ }
122
+
123
+ async def get_btc_fee_rates(self) -> dict[str, Any]:
124
+ data = await self.client.post(
125
+ "/v1/btc/fee-rates/get",
126
+ {"network": self.network},
127
+ )
128
+ return {
129
+ "chain": self.chain,
130
+ "network": self.network,
131
+ "fee_rates": data.get("feeRates") or {},
132
+ "source": "wdk-btc-wallet",
133
+ }
134
+
135
+ async def get_btc_max_spendable(
136
+ self,
137
+ *,
138
+ fee_rate: int | None = None,
139
+ ) -> dict[str, Any]:
140
+ payload: dict[str, Any] = {
141
+ "walletId": self.wallet_id,
142
+ "accountIndex": self.account_index,
143
+ "network": self.network,
144
+ }
145
+ if fee_rate is not None:
146
+ payload["feeRate"] = int(fee_rate)
147
+ data = await self.client.post("/v1/btc/max-spendable/get", payload)
148
+ max_spendable = dict(data.get("maxSpendable") or {})
149
+ amount_sats = int(max_spendable.get("amount") or 0)
150
+ fee_sats = int(max_spendable.get("fee") or 0)
151
+ change_sats = int(max_spendable.get("changeValue") or 0)
152
+ return {
153
+ "chain": self.chain,
154
+ "network": self.network,
155
+ "address": str(data.get("address") or await self.get_address() or ""),
156
+ "fee_rate": fee_rate,
157
+ "amount_sats": amount_sats,
158
+ "amount_btc": _sats_to_btc(amount_sats),
159
+ "estimated_fee_sats": fee_sats,
160
+ "estimated_fee_btc": _sats_to_btc(fee_sats),
161
+ "change_sats": change_sats,
162
+ "change_btc": _sats_to_btc(change_sats),
163
+ "raw": max_spendable,
164
+ "source": "wdk-btc-wallet",
165
+ }
166
+
167
+ async def preview_native_transfer(
168
+ self,
169
+ recipient: str,
170
+ amount_native: float,
171
+ ) -> dict[str, Any]:
172
+ raise WalletBackendError(
173
+ "wdk_btc_local expects transfer_btc with amount_sats, not preview_native_transfer."
174
+ )
175
+
176
+ async def preview_btc_transfer(
177
+ self,
178
+ *,
179
+ recipient: str,
180
+ amount_sats: int,
181
+ fee_rate: int | None = None,
182
+ confirmation_target: int | None = None,
183
+ ) -> dict[str, Any]:
184
+ payload: dict[str, Any] = {
185
+ "walletId": self.wallet_id,
186
+ "accountIndex": self.account_index,
187
+ "network": self.network,
188
+ "to": recipient,
189
+ "value": int(amount_sats),
190
+ }
191
+ if fee_rate is not None:
192
+ payload["feeRate"] = int(fee_rate)
193
+ if confirmation_target is not None:
194
+ payload["confirmationTarget"] = int(confirmation_target)
195
+ data = await self.client.post("/v1/btc/transfer/quote", payload)
196
+ quote = dict(data.get("quote") or {})
197
+ fee_sats = int(quote.get("fee") or 0)
198
+ return {
199
+ "chain": self.chain,
200
+ "network": self.network,
201
+ "asset_type": "btc-transfer",
202
+ "asset": "BTC",
203
+ "wallet": self.wallet_id,
204
+ "from_address": await self.get_address(),
205
+ "recipient": recipient,
206
+ "amount_sats": int(amount_sats),
207
+ "amount_btc": _sats_to_btc(amount_sats),
208
+ "fee_rate": fee_rate,
209
+ "confirmation_target": confirmation_target,
210
+ "estimated_fee_sats": fee_sats,
211
+ "estimated_fee_btc": _sats_to_btc(fee_sats),
212
+ "source": "wdk-btc-wallet",
213
+ }
214
+
215
+ async def send_btc_transfer(
216
+ self,
217
+ *,
218
+ recipient: str,
219
+ amount_sats: int,
220
+ fee_rate: int | None = None,
221
+ confirmation_target: int | None = None,
222
+ ) -> dict[str, Any]:
223
+ if self.sign_only:
224
+ raise WalletBackendError("wdk_btc_local is configured as sign_only.")
225
+ payload: dict[str, Any] = {
226
+ "walletId": self.wallet_id,
227
+ "accountIndex": self.account_index,
228
+ "network": self.network,
229
+ "to": recipient,
230
+ "value": int(amount_sats),
231
+ }
232
+ if fee_rate is not None:
233
+ payload["feeRate"] = int(fee_rate)
234
+ if confirmation_target is not None:
235
+ payload["confirmationTarget"] = int(confirmation_target)
236
+ data = await self.client.post("/v1/btc/transfer/send", payload)
237
+ result = dict(data.get("result") or {})
238
+ fee_sats = int(result.get("fee") or 0)
239
+ return {
240
+ "chain": self.chain,
241
+ "network": self.network,
242
+ "asset_type": "btc-transfer",
243
+ "asset": "BTC",
244
+ "wallet": self.wallet_id,
245
+ "from_address": await self.get_address(),
246
+ "recipient": recipient,
247
+ "amount_sats": int(amount_sats),
248
+ "amount_btc": _sats_to_btc(amount_sats),
249
+ "fee_rate": fee_rate,
250
+ "confirmation_target": confirmation_target,
251
+ "estimated_fee_sats": fee_sats,
252
+ "estimated_fee_btc": _sats_to_btc(fee_sats),
253
+ "hash": result.get("hash"),
254
+ "broadcasted": True,
255
+ "confirmed": False,
256
+ "source": "wdk-btc-wallet",
257
+ }
258
+
259
+ def get_capabilities(self) -> WalletCapabilities:
260
+ return WalletCapabilities(
261
+ backend=self.name,
262
+ chain=self.chain,
263
+ custody_model=self.custody_model,
264
+ sign_only=self.sign_only,
265
+ has_signer=True,
266
+ can_get_address=True,
267
+ can_get_balance=True,
268
+ can_sign_message=False,
269
+ can_sign_transaction=not self.sign_only,
270
+ can_send_transaction=not self.sign_only,
271
+ external_dependencies=["wdk-btc-wallet", "electrum"],
272
+ )