amped-defi 1.0.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 (189) hide show
  1. package/README.md +757 -0
  2. package/dist/__mocks__/@sodax/sdk.d.ts +24 -0
  3. package/dist/__mocks__/@sodax/sdk.d.ts.map +1 -0
  4. package/dist/__mocks__/@sodax/sdk.js +24 -0
  5. package/dist/__mocks__/@sodax/sdk.js.map +1 -0
  6. package/dist/__tests__/setup.d.ts +4 -0
  7. package/dist/__tests__/setup.d.ts.map +1 -0
  8. package/dist/__tests__/setup.js +32 -0
  9. package/dist/__tests__/setup.js.map +1 -0
  10. package/dist/index.d.ts +66 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +281 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/policy/policyEngine.d.ts +119 -0
  15. package/dist/policy/policyEngine.d.ts.map +1 -0
  16. package/dist/policy/policyEngine.js +322 -0
  17. package/dist/policy/policyEngine.js.map +1 -0
  18. package/dist/providers/spokeProviderFactory.d.ts +38 -0
  19. package/dist/providers/spokeProviderFactory.d.ts.map +1 -0
  20. package/dist/providers/spokeProviderFactory.js +212 -0
  21. package/dist/providers/spokeProviderFactory.js.map +1 -0
  22. package/dist/sodax/client.d.ts +34 -0
  23. package/dist/sodax/client.d.ts.map +1 -0
  24. package/dist/sodax/client.js +99 -0
  25. package/dist/sodax/client.js.map +1 -0
  26. package/dist/tools/bridge.d.ts +105 -0
  27. package/dist/tools/bridge.d.ts.map +1 -0
  28. package/dist/tools/bridge.js +334 -0
  29. package/dist/tools/bridge.js.map +1 -0
  30. package/dist/tools/discovery.d.ts +141 -0
  31. package/dist/tools/discovery.d.ts.map +1 -0
  32. package/dist/tools/discovery.js +777 -0
  33. package/dist/tools/discovery.js.map +1 -0
  34. package/dist/tools/moneyMarket.d.ts +227 -0
  35. package/dist/tools/moneyMarket.d.ts.map +1 -0
  36. package/dist/tools/moneyMarket.js +867 -0
  37. package/dist/tools/moneyMarket.js.map +1 -0
  38. package/dist/tools/portfolio.d.ts +43 -0
  39. package/dist/tools/portfolio.d.ts.map +1 -0
  40. package/dist/tools/portfolio.js +538 -0
  41. package/dist/tools/portfolio.js.map +1 -0
  42. package/dist/tools/swap.d.ts +71 -0
  43. package/dist/tools/swap.d.ts.map +1 -0
  44. package/dist/tools/swap.js +762 -0
  45. package/dist/tools/swap.js.map +1 -0
  46. package/dist/tools/walletManagement.d.ts +80 -0
  47. package/dist/tools/walletManagement.d.ts.map +1 -0
  48. package/dist/tools/walletManagement.js +289 -0
  49. package/dist/tools/walletManagement.js.map +1 -0
  50. package/dist/types.d.ts +205 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +5 -0
  53. package/dist/types.js.map +1 -0
  54. package/dist/utils/errorUtils.d.ts +2 -0
  55. package/dist/utils/errorUtils.d.ts.map +1 -0
  56. package/dist/utils/errorUtils.js +19 -0
  57. package/dist/utils/errorUtils.js.map +1 -0
  58. package/dist/utils/errors.d.ts +144 -0
  59. package/dist/utils/errors.d.ts.map +1 -0
  60. package/dist/utils/errors.js +310 -0
  61. package/dist/utils/errors.js.map +1 -0
  62. package/dist/utils/positionAggregator.d.ts +122 -0
  63. package/dist/utils/positionAggregator.d.ts.map +1 -0
  64. package/dist/utils/positionAggregator.js +377 -0
  65. package/dist/utils/positionAggregator.js.map +1 -0
  66. package/dist/utils/priceService.d.ts +45 -0
  67. package/dist/utils/priceService.d.ts.map +1 -0
  68. package/dist/utils/priceService.js +108 -0
  69. package/dist/utils/priceService.js.map +1 -0
  70. package/dist/utils/sodaxApi.d.ts +92 -0
  71. package/dist/utils/sodaxApi.d.ts.map +1 -0
  72. package/dist/utils/sodaxApi.js +143 -0
  73. package/dist/utils/sodaxApi.js.map +1 -0
  74. package/dist/utils/tokenResolver.d.ts +54 -0
  75. package/dist/utils/tokenResolver.d.ts.map +1 -0
  76. package/dist/utils/tokenResolver.js +252 -0
  77. package/dist/utils/tokenResolver.js.map +1 -0
  78. package/dist/wallet/backendConfig.d.ts +37 -0
  79. package/dist/wallet/backendConfig.d.ts.map +1 -0
  80. package/dist/wallet/backendConfig.js +125 -0
  81. package/dist/wallet/backendConfig.js.map +1 -0
  82. package/dist/wallet/backends/BankrBackend.d.ts +73 -0
  83. package/dist/wallet/backends/BankrBackend.d.ts.map +1 -0
  84. package/dist/wallet/backends/BankrBackend.js +315 -0
  85. package/dist/wallet/backends/BankrBackend.js.map +1 -0
  86. package/dist/wallet/backends/BankrWalletProvider.d.ts +75 -0
  87. package/dist/wallet/backends/BankrWalletProvider.d.ts.map +1 -0
  88. package/dist/wallet/backends/BankrWalletProvider.js +243 -0
  89. package/dist/wallet/backends/BankrWalletProvider.js.map +1 -0
  90. package/dist/wallet/backends/EnvBackend.d.ts +50 -0
  91. package/dist/wallet/backends/EnvBackend.d.ts.map +1 -0
  92. package/dist/wallet/backends/EnvBackend.js +114 -0
  93. package/dist/wallet/backends/EnvBackend.js.map +1 -0
  94. package/dist/wallet/backends/EvmWalletSkillBackend.d.ts +40 -0
  95. package/dist/wallet/backends/EvmWalletSkillBackend.d.ts.map +1 -0
  96. package/dist/wallet/backends/EvmWalletSkillBackend.js +81 -0
  97. package/dist/wallet/backends/EvmWalletSkillBackend.js.map +1 -0
  98. package/dist/wallet/backends/index.d.ts +10 -0
  99. package/dist/wallet/backends/index.d.ts.map +1 -0
  100. package/dist/wallet/backends/index.js +10 -0
  101. package/dist/wallet/backends/index.js.map +1 -0
  102. package/dist/wallet/index.d.ts +9 -0
  103. package/dist/wallet/index.d.ts.map +1 -0
  104. package/dist/wallet/index.js +12 -0
  105. package/dist/wallet/index.js.map +1 -0
  106. package/dist/wallet/providers/AmpedWalletProvider.d.ts +107 -0
  107. package/dist/wallet/providers/AmpedWalletProvider.d.ts.map +1 -0
  108. package/dist/wallet/providers/AmpedWalletProvider.js +208 -0
  109. package/dist/wallet/providers/AmpedWalletProvider.js.map +1 -0
  110. package/dist/wallet/providers/BankrBackend.d.ts +105 -0
  111. package/dist/wallet/providers/BankrBackend.d.ts.map +1 -0
  112. package/dist/wallet/providers/BankrBackend.js +327 -0
  113. package/dist/wallet/providers/BankrBackend.js.map +1 -0
  114. package/dist/wallet/providers/LocalKeyBackend.d.ts +62 -0
  115. package/dist/wallet/providers/LocalKeyBackend.d.ts.map +1 -0
  116. package/dist/wallet/providers/LocalKeyBackend.js +152 -0
  117. package/dist/wallet/providers/LocalKeyBackend.js.map +1 -0
  118. package/dist/wallet/providers/chainConfig.d.ts +209 -0
  119. package/dist/wallet/providers/chainConfig.d.ts.map +1 -0
  120. package/dist/wallet/providers/chainConfig.js +175 -0
  121. package/dist/wallet/providers/chainConfig.js.map +1 -0
  122. package/dist/wallet/providers/index.d.ts +30 -0
  123. package/dist/wallet/providers/index.d.ts.map +1 -0
  124. package/dist/wallet/providers/index.js +32 -0
  125. package/dist/wallet/providers/index.js.map +1 -0
  126. package/dist/wallet/providers/types.d.ts +156 -0
  127. package/dist/wallet/providers/types.d.ts.map +1 -0
  128. package/dist/wallet/providers/types.js +11 -0
  129. package/dist/wallet/providers/types.js.map +1 -0
  130. package/dist/wallet/skillWalletAdapter.d.ts +96 -0
  131. package/dist/wallet/skillWalletAdapter.d.ts.map +1 -0
  132. package/dist/wallet/skillWalletAdapter.js +280 -0
  133. package/dist/wallet/skillWalletAdapter.js.map +1 -0
  134. package/dist/wallet/types.d.ts +134 -0
  135. package/dist/wallet/types.d.ts.map +1 -0
  136. package/dist/wallet/types.js +138 -0
  137. package/dist/wallet/types.js.map +1 -0
  138. package/dist/wallet/walletManager.d.ts +111 -0
  139. package/dist/wallet/walletManager.d.ts.map +1 -0
  140. package/dist/wallet/walletManager.js +476 -0
  141. package/dist/wallet/walletManager.js.map +1 -0
  142. package/dist/wallet/walletRegistry.d.ts +95 -0
  143. package/dist/wallet/walletRegistry.d.ts.map +1 -0
  144. package/dist/wallet/walletRegistry.js +184 -0
  145. package/dist/wallet/walletRegistry.js.map +1 -0
  146. package/index.js +2 -0
  147. package/openclaw.plugin.json +37 -0
  148. package/package.json +69 -0
  149. package/src/__mocks__/@sodax/sdk.ts +28 -0
  150. package/src/__tests__/errors.test.ts +238 -0
  151. package/src/__tests__/policyEngine.test.ts +354 -0
  152. package/src/__tests__/positionAggregator.test.ts +271 -0
  153. package/src/__tests__/setup.ts +35 -0
  154. package/src/__tests__/sodaxApi.test.ts +203 -0
  155. package/src/__tests__/walletRegistry.test.ts +155 -0
  156. package/src/index.ts +376 -0
  157. package/src/policy/policyEngine.ts +389 -0
  158. package/src/providers/spokeProviderFactory.ts +283 -0
  159. package/src/sodax/client.ts +113 -0
  160. package/src/tools/bridge.ts +425 -0
  161. package/src/tools/discovery.ts +989 -0
  162. package/src/tools/moneyMarket.ts +1265 -0
  163. package/src/tools/portfolio.ts +697 -0
  164. package/src/tools/swap.ts +926 -0
  165. package/src/tools/walletManagement.ts +359 -0
  166. package/src/types.ts +228 -0
  167. package/src/utils/errorUtils.ts +16 -0
  168. package/src/utils/errors.ts +396 -0
  169. package/src/utils/positionAggregator.ts +559 -0
  170. package/src/utils/priceService.ts +153 -0
  171. package/src/utils/sodaxApi.ts +261 -0
  172. package/src/utils/tokenResolver.ts +286 -0
  173. package/src/wallet/backendConfig.ts +151 -0
  174. package/src/wallet/backends/BankrBackend.ts +399 -0
  175. package/src/wallet/backends/BankrWalletProvider.ts +329 -0
  176. package/src/wallet/backends/EnvBackend.ts +149 -0
  177. package/src/wallet/backends/EvmWalletSkillBackend.ts +110 -0
  178. package/src/wallet/backends/index.ts +10 -0
  179. package/src/wallet/index.ts +14 -0
  180. package/src/wallet/providers/AmpedWalletProvider.ts +267 -0
  181. package/src/wallet/providers/BankrBackend.ts +407 -0
  182. package/src/wallet/providers/LocalKeyBackend.ts +184 -0
  183. package/src/wallet/providers/chainConfig.ts +194 -0
  184. package/src/wallet/providers/index.ts +62 -0
  185. package/src/wallet/providers/types.ts +186 -0
  186. package/src/wallet/skillWalletAdapter.ts +335 -0
  187. package/src/wallet/types.ts +248 -0
  188. package/src/wallet/walletManager.ts +561 -0
  189. package/src/wallet/walletRegistry.ts +216 -0
@@ -0,0 +1,329 @@
1
+ /**
2
+ * Bankr Wallet Provider for SODAX SDK
3
+ *
4
+ * Implements IEvmWalletProvider interface to allow SODAX SDK
5
+ * to execute transactions through Bankr's API.
6
+ *
7
+ * Instead of signing locally, transactions are submitted to Bankr
8
+ * which signs and broadcasts them server-side.
9
+ *
10
+ * Supported chains: Ethereum (1), Polygon (137), Base (8453)
11
+ */
12
+
13
+ import type { Address, Hash, PublicClient } from 'viem';
14
+ import { createPublicClient, http } from 'viem';
15
+ import { mainnet, polygon, base } from 'viem/chains';
16
+ import type {
17
+ IEvmWalletProvider,
18
+ EvmRawTransaction,
19
+ EvmRawTransactionReceipt
20
+ } from '@sodax/types';
21
+
22
+ /**
23
+ * Chain configurations for Bankr
24
+ */
25
+ const BANKR_CHAINS: Record<number, { chain: any; name: string }> = {
26
+ 1: { chain: mainnet, name: 'ethereum' },
27
+ 137: { chain: polygon, name: 'polygon' },
28
+ 8453: { chain: base, name: 'base' },
29
+ };
30
+
31
+ /**
32
+ * Bankr API response types
33
+ */
34
+ interface BankrJobSubmitResponse {
35
+ success: boolean;
36
+ jobId: string;
37
+ status: 'pending';
38
+ message?: string;
39
+ error?: string;
40
+ }
41
+
42
+ interface BankrJobStatusResponse {
43
+ success: boolean;
44
+ jobId: string;
45
+ status: 'pending' | 'processing' | 'completed' | 'failed' | 'cancelled';
46
+ prompt: string;
47
+ response?: string;
48
+ error?: string;
49
+ richData?: Array<{
50
+ type?: string;
51
+ transactionHash?: string;
52
+ txHash?: string;
53
+ hash?: string;
54
+ [key: string]: unknown;
55
+ }>;
56
+ statusUpdates?: Array<{ message: string; timestamp: string }>;
57
+ }
58
+
59
+ /**
60
+ * Configuration for BankrWalletProvider
61
+ */
62
+ export interface BankrWalletProviderConfig {
63
+ apiKey: string;
64
+ apiUrl?: string;
65
+ chainId: number;
66
+ rpcUrl?: string;
67
+ /** Pre-cached address (avoids initial API call) */
68
+ cachedAddress?: Address;
69
+ }
70
+
71
+ /**
72
+ * Bankr Wallet Provider
73
+ *
74
+ * Implements IEvmWalletProvider for use with SODAX SDK's SpokeProvider.
75
+ * Transactions are signed and broadcast via Bankr's Agent API.
76
+ */
77
+ export class BankrWalletProvider implements IEvmWalletProvider {
78
+ readonly publicClient: PublicClient;
79
+
80
+ private readonly apiUrl: string;
81
+ private readonly apiKey: string;
82
+ private readonly chainId: number;
83
+ private cachedAddress: Address | null;
84
+
85
+ // Polling configuration
86
+ private readonly pollIntervalMs = 2000;
87
+ private readonly maxPollAttempts = 150; // 5 minutes max
88
+
89
+ constructor(config: BankrWalletProviderConfig) {
90
+ this.apiKey = config.apiKey;
91
+ this.apiUrl = config.apiUrl || 'https://api.bankr.bot';
92
+ this.chainId = config.chainId;
93
+ this.cachedAddress = config.cachedAddress || null;
94
+
95
+ // Validate chain support
96
+ const chainConfig = BANKR_CHAINS[config.chainId];
97
+ if (!chainConfig) {
98
+ throw new Error(
99
+ `Bankr does not support chainId ${config.chainId}. ` +
100
+ `Supported: Ethereum (1), Polygon (137), Base (8453)`
101
+ );
102
+ }
103
+
104
+ // Create public client for read operations
105
+ this.publicClient = createPublicClient({
106
+ chain: chainConfig.chain,
107
+ transport: http(config.rpcUrl),
108
+ }) as PublicClient;
109
+
110
+ console.log(`[BankrWalletProvider] Initialized for ${chainConfig.name} (${config.chainId})`);
111
+ }
112
+
113
+ /**
114
+ * Get the Bankr wallet address
115
+ */
116
+ async getWalletAddress(): Promise<Address> {
117
+ if (this.cachedAddress) return this.cachedAddress;
118
+
119
+ console.log('[BankrWalletProvider] Fetching wallet address from Bankr...');
120
+
121
+ try {
122
+ const response = await this.submitAndWait('What is my EVM wallet address?');
123
+
124
+ // Extract address from response
125
+ const addressMatch = response.match(/0x[a-fA-F0-9]{40}/);
126
+ if (!addressMatch) {
127
+ throw new Error('Could not parse wallet address from Bankr response');
128
+ }
129
+
130
+ this.cachedAddress = addressMatch[0] as Address;
131
+ console.log(`[BankrWalletProvider] Wallet address: ${this.cachedAddress}`);
132
+
133
+ return this.cachedAddress;
134
+ } catch (error) {
135
+ console.error('[BankrWalletProvider] Failed to get address:', error);
136
+ throw error;
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Send a transaction via Bankr
142
+ *
143
+ * This is the key method - it receives raw transaction data from SODAX SDK
144
+ * and submits it to Bankr for signing and broadcasting.
145
+ */
146
+ async sendTransaction(evmRawTx: EvmRawTransaction): Promise<Hash> {
147
+ console.log('[BankrWalletProvider] Sending transaction via Bankr');
148
+ console.log(`[BankrWalletProvider] To: ${evmRawTx.to}`);
149
+ console.log(`[BankrWalletProvider] Value: ${evmRawTx.value}`);
150
+ console.log(`[BankrWalletProvider] Data: ${evmRawTx.data.slice(0, 20)}...`);
151
+
152
+ // Format transaction for Bankr's arbitrary transaction endpoint
153
+ const txJson = JSON.stringify({
154
+ to: evmRawTx.to,
155
+ data: evmRawTx.data,
156
+ value: evmRawTx.value.toString(),
157
+ chainId: this.chainId,
158
+ }, null, 2);
159
+
160
+ // Use the documented prompt format
161
+ const prompt = `Submit this transaction:
162
+ ${txJson}`;
163
+
164
+ console.log('[BankrWalletProvider] Submitting to Bankr API...');
165
+
166
+ const result = await this.submitAndWaitForJob(prompt);
167
+
168
+ // Extract transaction hash from response
169
+ const txHash = this.extractTransactionHash(result);
170
+
171
+ if (!txHash) {
172
+ const errorMsg = result.error || result.response || 'Unknown error';
173
+ throw new Error(`Transaction failed: ${errorMsg}`);
174
+ }
175
+
176
+ console.log(`[BankrWalletProvider] Transaction hash: ${txHash}`);
177
+ return txHash;
178
+ }
179
+
180
+ /**
181
+ * Wait for transaction receipt
182
+ *
183
+ * Uses the public client to query the blockchain directly.
184
+ */
185
+ async waitForTransactionReceipt(txHash: Hash): Promise<EvmRawTransactionReceipt> {
186
+ console.log(`[BankrWalletProvider] Waiting for receipt: ${txHash}`);
187
+
188
+ const receipt = await this.publicClient.waitForTransactionReceipt({
189
+ hash: txHash,
190
+ timeout: 120_000, // 2 minutes
191
+ });
192
+
193
+ // Convert viem receipt to SODAX format
194
+ return {
195
+ transactionHash: receipt.transactionHash,
196
+ transactionIndex: `0x${receipt.transactionIndex.toString(16)}`,
197
+ blockHash: receipt.blockHash,
198
+ blockNumber: `0x${receipt.blockNumber.toString(16)}`,
199
+ from: receipt.from,
200
+ to: receipt.to,
201
+ cumulativeGasUsed: `0x${receipt.cumulativeGasUsed.toString(16)}`,
202
+ gasUsed: `0x${receipt.gasUsed.toString(16)}`,
203
+ contractAddress: receipt.contractAddress,
204
+ logs: receipt.logs.map(log => ({
205
+ address: log.address as Address,
206
+ topics: (log as any).topics || [],
207
+ data: log.data,
208
+ blockHash: log.blockHash,
209
+ blockNumber: log.blockNumber ? `0x${log.blockNumber.toString(16)}` : null,
210
+ logIndex: log.logIndex !== null ? `0x${log.logIndex.toString(16)}` : null,
211
+ transactionHash: log.transactionHash,
212
+ transactionIndex: log.transactionIndex !== null ? `0x${log.transactionIndex.toString(16)}` : null,
213
+ removed: log.removed,
214
+ })) as any,
215
+ logsBloom: receipt.logsBloom,
216
+ status: receipt.status === 'success' ? '0x1' : '0x0',
217
+ type: receipt.type,
218
+ effectiveGasPrice: receipt.effectiveGasPrice ? `0x${receipt.effectiveGasPrice.toString(16)}` : undefined,
219
+ };
220
+ }
221
+
222
+ /**
223
+ * Submit prompt and wait for text response
224
+ */
225
+ private async submitAndWait(prompt: string): Promise<string> {
226
+ const result = await this.submitAndWaitForJob(prompt);
227
+ return result.response || '';
228
+ }
229
+
230
+ /**
231
+ * Submit prompt and wait for job completion
232
+ */
233
+ private async submitAndWaitForJob(prompt: string): Promise<BankrJobStatusResponse> {
234
+ // Submit job
235
+ const submitResponse = await fetch(`${this.apiUrl}/agent/prompt`, {
236
+ method: 'POST',
237
+ headers: {
238
+ 'X-API-Key': this.apiKey,
239
+ 'Content-Type': 'application/json',
240
+ },
241
+ body: JSON.stringify({ prompt }),
242
+ });
243
+
244
+ if (!submitResponse.ok) {
245
+ const error = await submitResponse.text();
246
+ throw new Error(`Failed to submit job: ${submitResponse.status} ${error}`);
247
+ }
248
+
249
+ const submitData = await submitResponse.json() as BankrJobSubmitResponse;
250
+
251
+ if (!submitData.success || !submitData.jobId) {
252
+ throw new Error(`Invalid job response: ${JSON.stringify(submitData)}`);
253
+ }
254
+
255
+ const jobId = submitData.jobId;
256
+ console.log(`[BankrWalletProvider] Job submitted: ${jobId}`);
257
+
258
+ // Poll for completion
259
+ let lastStatus = '';
260
+
261
+ for (let attempt = 0; attempt < this.maxPollAttempts; attempt++) {
262
+ await this.sleep(this.pollIntervalMs);
263
+
264
+ const statusResponse = await fetch(`${this.apiUrl}/agent/job/${jobId}`, {
265
+ method: 'GET',
266
+ headers: { 'X-API-Key': this.apiKey },
267
+ });
268
+
269
+ if (!statusResponse.ok) {
270
+ const error = await statusResponse.text();
271
+ throw new Error(`Failed to get job status: ${statusResponse.status} ${error}`);
272
+ }
273
+
274
+ const result = await statusResponse.json() as BankrJobStatusResponse;
275
+
276
+ // Log status changes
277
+ if (result.status !== lastStatus) {
278
+ console.log(`[BankrWalletProvider] Job ${jobId}: ${result.status}`);
279
+ lastStatus = result.status;
280
+ }
281
+
282
+ // Check terminal states
283
+ switch (result.status) {
284
+ case 'completed':
285
+ return result;
286
+ case 'failed':
287
+ throw new Error(`Job failed: ${result.error || 'Unknown error'}`);
288
+ case 'cancelled':
289
+ throw new Error(`Job was cancelled`);
290
+ }
291
+ }
292
+
293
+ throw new Error(`Job ${jobId} timed out`);
294
+ }
295
+
296
+ /**
297
+ * Extract transaction hash from Bankr response
298
+ */
299
+ private extractTransactionHash(result: BankrJobStatusResponse): Hash | null {
300
+ // Check richData for transaction info
301
+ if (result.richData) {
302
+ for (const item of result.richData) {
303
+ if (item.transactionHash) return item.transactionHash as Hash;
304
+ if (item.txHash) return item.txHash as Hash;
305
+ if (item.hash) return item.hash as Hash;
306
+ }
307
+ }
308
+
309
+ // Try to extract from response text
310
+ if (result.response) {
311
+ // Look for 0x + 64 hex chars
312
+ const hashMatch = result.response.match(/0x[a-fA-F0-9]{64}/);
313
+ if (hashMatch) return hashMatch[0] as Hash;
314
+ }
315
+
316
+ return null;
317
+ }
318
+
319
+ private sleep(ms: number): Promise<void> {
320
+ return new Promise(resolve => setTimeout(resolve, ms));
321
+ }
322
+ }
323
+
324
+ /**
325
+ * Create a BankrWalletProvider
326
+ */
327
+ export function createBankrWalletProvider(config: BankrWalletProviderConfig): BankrWalletProvider {
328
+ return new BankrWalletProvider(config);
329
+ }
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Environment Variable Backend
3
+ *
4
+ * Loads wallet from environment variables:
5
+ * - AMPED_OC_WALLETS_JSON: JSON with wallet configs
6
+ * - Or individual env vars for address/privateKey
7
+ */
8
+
9
+ import type { Address } from 'viem';
10
+ import type { IWalletBackend } from '../types';
11
+ import { SODAX_SUPPORTED_CHAINS } from '../types';
12
+
13
+ /**
14
+ * Wallet entry from AMPED_OC_WALLETS_JSON
15
+ */
16
+ interface EnvWalletEntry {
17
+ address: string;
18
+ privateKey: string;
19
+ }
20
+
21
+ /**
22
+ * Environment variable backend configuration
23
+ */
24
+ export interface EnvBackendConfig {
25
+ nickname: string;
26
+ address?: Address;
27
+ privateKey?: `0x${string}`;
28
+ envVar?: string; // Name of env var containing JSON
29
+ chains?: string[];
30
+ }
31
+
32
+ /**
33
+ * Environment variable wallet backend
34
+ * Supports all SODAX chains (local key signing)
35
+ */
36
+ export class EnvBackend implements IWalletBackend {
37
+ readonly type = 'env' as const;
38
+ readonly nickname: string;
39
+ readonly supportedChains: readonly string[];
40
+
41
+ private address: Address | null = null;
42
+ private privateKey: `0x${string}` | null = null;
43
+ private envVar: string | null = null;
44
+
45
+ constructor(config: EnvBackendConfig) {
46
+ this.nickname = config.nickname;
47
+ this.supportedChains = config.chains || [...SODAX_SUPPORTED_CHAINS];
48
+
49
+ if (config.address && config.privateKey) {
50
+ // Direct address/key provided
51
+ this.address = config.address;
52
+ this.privateKey = config.privateKey;
53
+ } else if (config.envVar) {
54
+ // Will load from env var
55
+ this.envVar = config.envVar;
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Load wallet from environment variable if needed
61
+ */
62
+ private loadFromEnv(): { address: Address; privateKey: `0x${string}` } {
63
+ if (this.address && this.privateKey) {
64
+ return { address: this.address, privateKey: this.privateKey };
65
+ }
66
+
67
+ if (this.envVar) {
68
+ const envValue = process.env[this.envVar];
69
+ if (!envValue) {
70
+ throw new Error(`Environment variable ${this.envVar} not set`);
71
+ }
72
+
73
+ try {
74
+ const data = JSON.parse(envValue) as EnvWalletEntry;
75
+ this.address = data.address as Address;
76
+ this.privateKey = (data.privateKey.startsWith('0x')
77
+ ? data.privateKey
78
+ : `0x${data.privateKey}`) as `0x${string}`;
79
+ return { address: this.address, privateKey: this.privateKey };
80
+ } catch (error) {
81
+ throw new Error(`Failed to parse ${this.envVar}: ${error}`);
82
+ }
83
+ }
84
+
85
+ throw new Error(`No wallet configuration for "${this.nickname}"`);
86
+ }
87
+
88
+ async getAddress(): Promise<Address> {
89
+ const { address } = this.loadFromEnv();
90
+ return address;
91
+ }
92
+
93
+ supportsChain(chainId: string): boolean {
94
+ return this.supportedChains.includes(chainId);
95
+ }
96
+
97
+ async getPrivateKey(): Promise<`0x${string}`> {
98
+ const { privateKey } = this.loadFromEnv();
99
+ return privateKey;
100
+ }
101
+
102
+ async isReady(): Promise<boolean> {
103
+ try {
104
+ this.loadFromEnv();
105
+ return true;
106
+ } catch {
107
+ return false;
108
+ }
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Create env backend from direct config
114
+ */
115
+ export function createEnvBackend(config: EnvBackendConfig): EnvBackend {
116
+ return new EnvBackend(config);
117
+ }
118
+
119
+ /**
120
+ * Load wallets from AMPED_OC_WALLETS_JSON environment variable
121
+ * Returns multiple backends keyed by wallet name
122
+ */
123
+ export function loadWalletsFromEnv(): Map<string, EnvBackend> {
124
+ const wallets = new Map<string, EnvBackend>();
125
+
126
+ const walletsJson = process.env.AMPED_OC_WALLETS_JSON;
127
+ if (!walletsJson) return wallets;
128
+
129
+ try {
130
+ const parsed = JSON.parse(walletsJson) as Record<string, EnvWalletEntry>;
131
+
132
+ for (const [name, wallet] of Object.entries(parsed)) {
133
+ const backend = new EnvBackend({
134
+ nickname: name,
135
+ address: wallet.address as Address,
136
+ privateKey: (wallet.privateKey.startsWith('0x')
137
+ ? wallet.privateKey
138
+ : `0x${wallet.privateKey}`) as `0x${string}`,
139
+ });
140
+ wallets.set(name.toLowerCase(), backend);
141
+ }
142
+
143
+ console.log(`[EnvBackend] Loaded ${wallets.size} wallet(s) from AMPED_OC_WALLETS_JSON`);
144
+ } catch (error) {
145
+ console.warn(`[EnvBackend] Failed to parse AMPED_OC_WALLETS_JSON: ${error}`);
146
+ }
147
+
148
+ return wallets;
149
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * EVM Wallet Skill Backend
3
+ *
4
+ * Loads wallet from ~/.evm-wallet.json (created by evm-wallet-skill)
5
+ */
6
+
7
+ import { existsSync, readFileSync } from 'fs';
8
+ import { join } from 'path';
9
+ import { homedir } from 'os';
10
+ import type { Address } from 'viem';
11
+ import type { IWalletBackend } from '../types';
12
+ import { SODAX_SUPPORTED_CHAINS } from '../types';
13
+
14
+ /**
15
+ * Default path to evm-wallet-skill wallet file
16
+ */
17
+ const DEFAULT_WALLET_PATH = join(homedir(), '.evm-wallet.json');
18
+
19
+ /**
20
+ * EVM Wallet Skill wallet file structure
21
+ */
22
+ interface EvmWalletFile {
23
+ address: string;
24
+ privateKey: string;
25
+ }
26
+
27
+ /**
28
+ * Backend for evm-wallet-skill wallets
29
+ * Supports all SODAX chains (local key signing)
30
+ */
31
+ export class EvmWalletSkillBackend implements IWalletBackend {
32
+ readonly type = 'evm-wallet-skill' as const;
33
+ readonly nickname: string;
34
+ readonly supportedChains: readonly string[];
35
+
36
+ private walletPath: string;
37
+ private cachedWallet: EvmWalletFile | null = null;
38
+
39
+ constructor(options: {
40
+ nickname: string;
41
+ path?: string;
42
+ chains?: string[];
43
+ }) {
44
+ this.nickname = options.nickname;
45
+ this.walletPath = options.path || DEFAULT_WALLET_PATH;
46
+ this.supportedChains = options.chains || [...SODAX_SUPPORTED_CHAINS];
47
+ }
48
+
49
+ /**
50
+ * Load wallet from file (cached)
51
+ */
52
+ private loadWallet(): EvmWalletFile {
53
+ if (this.cachedWallet) return this.cachedWallet;
54
+
55
+ if (!existsSync(this.walletPath)) {
56
+ throw new Error(
57
+ `Wallet file not found: ${this.walletPath}\n` +
58
+ `Run: git clone https://github.com/amped-finance/evm-wallet-skill.git ~/.openclaw/skills/evm-wallet-skill\n` +
59
+ ` cd ~/.openclaw/skills/evm-wallet-skill && npm install && node src/setup.js`
60
+ );
61
+ }
62
+
63
+ try {
64
+ const content = readFileSync(this.walletPath, 'utf-8');
65
+ this.cachedWallet = JSON.parse(content) as EvmWalletFile;
66
+ return this.cachedWallet;
67
+ } catch (error) {
68
+ throw new Error(`Failed to load wallet from ${this.walletPath}: ${error}`);
69
+ }
70
+ }
71
+
72
+ async getAddress(): Promise<Address> {
73
+ const wallet = this.loadWallet();
74
+ return wallet.address as Address;
75
+ }
76
+
77
+ supportsChain(chainId: string): boolean {
78
+ return this.supportedChains.includes(chainId);
79
+ }
80
+
81
+ async getPrivateKey(): Promise<`0x${string}`> {
82
+ const wallet = this.loadWallet();
83
+ const key = wallet.privateKey;
84
+ return key.startsWith('0x') ? key as `0x${string}` : `0x${key}` as `0x${string}`;
85
+ }
86
+
87
+ async isReady(): Promise<boolean> {
88
+ try {
89
+ this.loadWallet();
90
+ return true;
91
+ } catch {
92
+ return false;
93
+ }
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Create an evm-wallet-skill backend
99
+ */
100
+ export function createEvmWalletSkillBackend(options: {
101
+ nickname?: string;
102
+ path?: string;
103
+ chains?: string[];
104
+ } = {}): EvmWalletSkillBackend {
105
+ return new EvmWalletSkillBackend({
106
+ nickname: options.nickname || 'main',
107
+ path: options.path,
108
+ chains: options.chains,
109
+ });
110
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Wallet Backends
3
+ *
4
+ * Export all wallet backend implementations
5
+ */
6
+
7
+ export { EvmWalletSkillBackend, createEvmWalletSkillBackend } from './EvmWalletSkillBackend';
8
+ export { BankrBackend, createBankrBackend, type BankrBackendConfig } from './BankrBackend';
9
+ export { EnvBackend, createEnvBackend, loadWalletsFromEnv, type EnvBackendConfig } from './EnvBackend';
10
+ export { BankrWalletProvider, createBankrWalletProvider, type BankrWalletProviderConfig } from './BankrWalletProvider';
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Wallet Module
3
+ *
4
+ * Multi-source wallet management with nicknames
5
+ */
6
+
7
+ // Types
8
+ export * from './types';
9
+
10
+ // Backends
11
+ export * from './backends';
12
+
13
+ // Manager
14
+ export { WalletManager, getWalletManager, resetWalletManager } from './walletManager';