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.
- package/README.md +757 -0
- package/dist/__mocks__/@sodax/sdk.d.ts +24 -0
- package/dist/__mocks__/@sodax/sdk.d.ts.map +1 -0
- package/dist/__mocks__/@sodax/sdk.js +24 -0
- package/dist/__mocks__/@sodax/sdk.js.map +1 -0
- package/dist/__tests__/setup.d.ts +4 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/__tests__/setup.js +32 -0
- package/dist/__tests__/setup.js.map +1 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +281 -0
- package/dist/index.js.map +1 -0
- package/dist/policy/policyEngine.d.ts +119 -0
- package/dist/policy/policyEngine.d.ts.map +1 -0
- package/dist/policy/policyEngine.js +322 -0
- package/dist/policy/policyEngine.js.map +1 -0
- package/dist/providers/spokeProviderFactory.d.ts +38 -0
- package/dist/providers/spokeProviderFactory.d.ts.map +1 -0
- package/dist/providers/spokeProviderFactory.js +212 -0
- package/dist/providers/spokeProviderFactory.js.map +1 -0
- package/dist/sodax/client.d.ts +34 -0
- package/dist/sodax/client.d.ts.map +1 -0
- package/dist/sodax/client.js +99 -0
- package/dist/sodax/client.js.map +1 -0
- package/dist/tools/bridge.d.ts +105 -0
- package/dist/tools/bridge.d.ts.map +1 -0
- package/dist/tools/bridge.js +334 -0
- package/dist/tools/bridge.js.map +1 -0
- package/dist/tools/discovery.d.ts +141 -0
- package/dist/tools/discovery.d.ts.map +1 -0
- package/dist/tools/discovery.js +777 -0
- package/dist/tools/discovery.js.map +1 -0
- package/dist/tools/moneyMarket.d.ts +227 -0
- package/dist/tools/moneyMarket.d.ts.map +1 -0
- package/dist/tools/moneyMarket.js +867 -0
- package/dist/tools/moneyMarket.js.map +1 -0
- package/dist/tools/portfolio.d.ts +43 -0
- package/dist/tools/portfolio.d.ts.map +1 -0
- package/dist/tools/portfolio.js +538 -0
- package/dist/tools/portfolio.js.map +1 -0
- package/dist/tools/swap.d.ts +71 -0
- package/dist/tools/swap.d.ts.map +1 -0
- package/dist/tools/swap.js +762 -0
- package/dist/tools/swap.js.map +1 -0
- package/dist/tools/walletManagement.d.ts +80 -0
- package/dist/tools/walletManagement.d.ts.map +1 -0
- package/dist/tools/walletManagement.js +289 -0
- package/dist/tools/walletManagement.js.map +1 -0
- package/dist/types.d.ts +205 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/errorUtils.d.ts +2 -0
- package/dist/utils/errorUtils.d.ts.map +1 -0
- package/dist/utils/errorUtils.js +19 -0
- package/dist/utils/errorUtils.js.map +1 -0
- package/dist/utils/errors.d.ts +144 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +310 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/positionAggregator.d.ts +122 -0
- package/dist/utils/positionAggregator.d.ts.map +1 -0
- package/dist/utils/positionAggregator.js +377 -0
- package/dist/utils/positionAggregator.js.map +1 -0
- package/dist/utils/priceService.d.ts +45 -0
- package/dist/utils/priceService.d.ts.map +1 -0
- package/dist/utils/priceService.js +108 -0
- package/dist/utils/priceService.js.map +1 -0
- package/dist/utils/sodaxApi.d.ts +92 -0
- package/dist/utils/sodaxApi.d.ts.map +1 -0
- package/dist/utils/sodaxApi.js +143 -0
- package/dist/utils/sodaxApi.js.map +1 -0
- package/dist/utils/tokenResolver.d.ts +54 -0
- package/dist/utils/tokenResolver.d.ts.map +1 -0
- package/dist/utils/tokenResolver.js +252 -0
- package/dist/utils/tokenResolver.js.map +1 -0
- package/dist/wallet/backendConfig.d.ts +37 -0
- package/dist/wallet/backendConfig.d.ts.map +1 -0
- package/dist/wallet/backendConfig.js +125 -0
- package/dist/wallet/backendConfig.js.map +1 -0
- package/dist/wallet/backends/BankrBackend.d.ts +73 -0
- package/dist/wallet/backends/BankrBackend.d.ts.map +1 -0
- package/dist/wallet/backends/BankrBackend.js +315 -0
- package/dist/wallet/backends/BankrBackend.js.map +1 -0
- package/dist/wallet/backends/BankrWalletProvider.d.ts +75 -0
- package/dist/wallet/backends/BankrWalletProvider.d.ts.map +1 -0
- package/dist/wallet/backends/BankrWalletProvider.js +243 -0
- package/dist/wallet/backends/BankrWalletProvider.js.map +1 -0
- package/dist/wallet/backends/EnvBackend.d.ts +50 -0
- package/dist/wallet/backends/EnvBackend.d.ts.map +1 -0
- package/dist/wallet/backends/EnvBackend.js +114 -0
- package/dist/wallet/backends/EnvBackend.js.map +1 -0
- package/dist/wallet/backends/EvmWalletSkillBackend.d.ts +40 -0
- package/dist/wallet/backends/EvmWalletSkillBackend.d.ts.map +1 -0
- package/dist/wallet/backends/EvmWalletSkillBackend.js +81 -0
- package/dist/wallet/backends/EvmWalletSkillBackend.js.map +1 -0
- package/dist/wallet/backends/index.d.ts +10 -0
- package/dist/wallet/backends/index.d.ts.map +1 -0
- package/dist/wallet/backends/index.js +10 -0
- package/dist/wallet/backends/index.js.map +1 -0
- package/dist/wallet/index.d.ts +9 -0
- package/dist/wallet/index.d.ts.map +1 -0
- package/dist/wallet/index.js +12 -0
- package/dist/wallet/index.js.map +1 -0
- package/dist/wallet/providers/AmpedWalletProvider.d.ts +107 -0
- package/dist/wallet/providers/AmpedWalletProvider.d.ts.map +1 -0
- package/dist/wallet/providers/AmpedWalletProvider.js +208 -0
- package/dist/wallet/providers/AmpedWalletProvider.js.map +1 -0
- package/dist/wallet/providers/BankrBackend.d.ts +105 -0
- package/dist/wallet/providers/BankrBackend.d.ts.map +1 -0
- package/dist/wallet/providers/BankrBackend.js +327 -0
- package/dist/wallet/providers/BankrBackend.js.map +1 -0
- package/dist/wallet/providers/LocalKeyBackend.d.ts +62 -0
- package/dist/wallet/providers/LocalKeyBackend.d.ts.map +1 -0
- package/dist/wallet/providers/LocalKeyBackend.js +152 -0
- package/dist/wallet/providers/LocalKeyBackend.js.map +1 -0
- package/dist/wallet/providers/chainConfig.d.ts +209 -0
- package/dist/wallet/providers/chainConfig.d.ts.map +1 -0
- package/dist/wallet/providers/chainConfig.js +175 -0
- package/dist/wallet/providers/chainConfig.js.map +1 -0
- package/dist/wallet/providers/index.d.ts +30 -0
- package/dist/wallet/providers/index.d.ts.map +1 -0
- package/dist/wallet/providers/index.js +32 -0
- package/dist/wallet/providers/index.js.map +1 -0
- package/dist/wallet/providers/types.d.ts +156 -0
- package/dist/wallet/providers/types.d.ts.map +1 -0
- package/dist/wallet/providers/types.js +11 -0
- package/dist/wallet/providers/types.js.map +1 -0
- package/dist/wallet/skillWalletAdapter.d.ts +96 -0
- package/dist/wallet/skillWalletAdapter.d.ts.map +1 -0
- package/dist/wallet/skillWalletAdapter.js +280 -0
- package/dist/wallet/skillWalletAdapter.js.map +1 -0
- package/dist/wallet/types.d.ts +134 -0
- package/dist/wallet/types.d.ts.map +1 -0
- package/dist/wallet/types.js +138 -0
- package/dist/wallet/types.js.map +1 -0
- package/dist/wallet/walletManager.d.ts +111 -0
- package/dist/wallet/walletManager.d.ts.map +1 -0
- package/dist/wallet/walletManager.js +476 -0
- package/dist/wallet/walletManager.js.map +1 -0
- package/dist/wallet/walletRegistry.d.ts +95 -0
- package/dist/wallet/walletRegistry.d.ts.map +1 -0
- package/dist/wallet/walletRegistry.js +184 -0
- package/dist/wallet/walletRegistry.js.map +1 -0
- package/index.js +2 -0
- package/openclaw.plugin.json +37 -0
- package/package.json +69 -0
- package/src/__mocks__/@sodax/sdk.ts +28 -0
- package/src/__tests__/errors.test.ts +238 -0
- package/src/__tests__/policyEngine.test.ts +354 -0
- package/src/__tests__/positionAggregator.test.ts +271 -0
- package/src/__tests__/setup.ts +35 -0
- package/src/__tests__/sodaxApi.test.ts +203 -0
- package/src/__tests__/walletRegistry.test.ts +155 -0
- package/src/index.ts +376 -0
- package/src/policy/policyEngine.ts +389 -0
- package/src/providers/spokeProviderFactory.ts +283 -0
- package/src/sodax/client.ts +113 -0
- package/src/tools/bridge.ts +425 -0
- package/src/tools/discovery.ts +989 -0
- package/src/tools/moneyMarket.ts +1265 -0
- package/src/tools/portfolio.ts +697 -0
- package/src/tools/swap.ts +926 -0
- package/src/tools/walletManagement.ts +359 -0
- package/src/types.ts +228 -0
- package/src/utils/errorUtils.ts +16 -0
- package/src/utils/errors.ts +396 -0
- package/src/utils/positionAggregator.ts +559 -0
- package/src/utils/priceService.ts +153 -0
- package/src/utils/sodaxApi.ts +261 -0
- package/src/utils/tokenResolver.ts +286 -0
- package/src/wallet/backendConfig.ts +151 -0
- package/src/wallet/backends/BankrBackend.ts +399 -0
- package/src/wallet/backends/BankrWalletProvider.ts +329 -0
- package/src/wallet/backends/EnvBackend.ts +149 -0
- package/src/wallet/backends/EvmWalletSkillBackend.ts +110 -0
- package/src/wallet/backends/index.ts +10 -0
- package/src/wallet/index.ts +14 -0
- package/src/wallet/providers/AmpedWalletProvider.ts +267 -0
- package/src/wallet/providers/BankrBackend.ts +407 -0
- package/src/wallet/providers/LocalKeyBackend.ts +184 -0
- package/src/wallet/providers/chainConfig.ts +194 -0
- package/src/wallet/providers/index.ts +62 -0
- package/src/wallet/providers/types.ts +186 -0
- package/src/wallet/skillWalletAdapter.ts +335 -0
- package/src/wallet/types.ts +248 -0
- package/src/wallet/walletManager.ts +561 -0
- 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';
|