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,399 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bankr Backend - Transaction Execution via Bankr API
|
|
3
|
+
*
|
|
4
|
+
* Submits raw transactions to Bankr's Agent API using the
|
|
5
|
+
* arbitrary transaction format documented at:
|
|
6
|
+
* https://github.com/BankrBot/openclaw-skills/blob/main/bankr/references/arbitrary-transaction.md
|
|
7
|
+
*
|
|
8
|
+
* Supported chains: Ethereum (1), Polygon (137), Base (8453)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { Address, Hash } from 'viem';
|
|
12
|
+
import type { IWalletBackend, RawTransaction } from '../types';
|
|
13
|
+
import { BANKR_SUPPORTED_CHAINS, isBankrSupportedChain } from '../types';
|
|
14
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
15
|
+
import { join, dirname } from 'path';
|
|
16
|
+
import { homedir } from 'os';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Disk cache path for bankr address
|
|
20
|
+
*/
|
|
21
|
+
const BANKR_CACHE_DIR = join(homedir(), '.openclaw', 'cache');
|
|
22
|
+
const getBankrCachePath = (nickname: string) => join(BANKR_CACHE_DIR, `bankr-${nickname}-address.json`);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Bankr API response types
|
|
26
|
+
*/
|
|
27
|
+
interface BankrJobSubmitResponse {
|
|
28
|
+
success: boolean;
|
|
29
|
+
jobId: string;
|
|
30
|
+
status: 'pending';
|
|
31
|
+
message?: string;
|
|
32
|
+
error?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface BankrJobStatusResponse {
|
|
36
|
+
success: boolean;
|
|
37
|
+
jobId: string;
|
|
38
|
+
status: 'pending' | 'processing' | 'completed' | 'failed' | 'cancelled';
|
|
39
|
+
prompt: string;
|
|
40
|
+
response?: string;
|
|
41
|
+
error?: string;
|
|
42
|
+
richData?: Array<{
|
|
43
|
+
type?: string;
|
|
44
|
+
transactionHash?: string;
|
|
45
|
+
txHash?: string;
|
|
46
|
+
hash?: string;
|
|
47
|
+
[key: string]: unknown;
|
|
48
|
+
}>;
|
|
49
|
+
statusUpdates?: Array<{ message: string; timestamp: string }>;
|
|
50
|
+
createdAt: string;
|
|
51
|
+
completedAt?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Bankr backend configuration
|
|
56
|
+
*/
|
|
57
|
+
export interface BankrBackendConfig {
|
|
58
|
+
nickname?: string;
|
|
59
|
+
apiKey: string;
|
|
60
|
+
apiUrl?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Bankr wallet backend
|
|
65
|
+
* Submits raw transactions via Bankr Agent API
|
|
66
|
+
*/
|
|
67
|
+
export class BankrBackend implements IWalletBackend {
|
|
68
|
+
readonly type = 'bankr' as const;
|
|
69
|
+
readonly nickname: string;
|
|
70
|
+
readonly supportedChains = BANKR_SUPPORTED_CHAINS;
|
|
71
|
+
|
|
72
|
+
private readonly apiUrl: string;
|
|
73
|
+
private readonly apiKey: string;
|
|
74
|
+
private cachedAddress: Address | null = null;
|
|
75
|
+
private cachedSolanaAddress: string | null = null;
|
|
76
|
+
|
|
77
|
+
// Polling configuration
|
|
78
|
+
private readonly pollIntervalMs = 2000;
|
|
79
|
+
private readonly maxPollAttempts = 150; // 5 minutes max
|
|
80
|
+
|
|
81
|
+
constructor(config: BankrBackendConfig) {
|
|
82
|
+
this.nickname = config.nickname || 'bankr';
|
|
83
|
+
this.apiUrl = config.apiUrl || 'https://api.bankr.bot';
|
|
84
|
+
this.apiKey = config.apiKey;
|
|
85
|
+
|
|
86
|
+
// Try to load cached address from disk
|
|
87
|
+
this.loadCachedAddress();
|
|
88
|
+
|
|
89
|
+
console.log(`[BankrBackend] Initialized as "${this.nickname}"`);
|
|
90
|
+
console.log(`[BankrBackend] Supported chains: ${this.supportedChains.join(', ')}`);
|
|
91
|
+
if (this.cachedAddress) {
|
|
92
|
+
console.log(`[BankrBackend] Loaded cached address: ${this.cachedAddress}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Load cached address from disk
|
|
98
|
+
*/
|
|
99
|
+
private loadCachedAddress(): void {
|
|
100
|
+
const cachePath = getBankrCachePath(this.nickname);
|
|
101
|
+
if (existsSync(cachePath)) {
|
|
102
|
+
try {
|
|
103
|
+
const data = JSON.parse(readFileSync(cachePath, 'utf-8'));
|
|
104
|
+
if (data.address && data.address.match(/^0x[a-fA-F0-9]{40}$/)) {
|
|
105
|
+
this.cachedAddress = data.address as Address;
|
|
106
|
+
}
|
|
107
|
+
} catch (e) {
|
|
108
|
+
console.warn(`[BankrBackend] Failed to load cached address: ${e}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Save address to disk cache
|
|
115
|
+
*/
|
|
116
|
+
private saveCachedAddress(address: Address): void {
|
|
117
|
+
const cachePath = getBankrCachePath(this.nickname);
|
|
118
|
+
try {
|
|
119
|
+
if (!existsSync(BANKR_CACHE_DIR)) {
|
|
120
|
+
mkdirSync(BANKR_CACHE_DIR, { recursive: true });
|
|
121
|
+
}
|
|
122
|
+
writeFileSync(cachePath, JSON.stringify({ address, timestamp: Date.now() }));
|
|
123
|
+
console.log(`[BankrBackend] Cached address to ${cachePath}`);
|
|
124
|
+
} catch (e) {
|
|
125
|
+
console.warn(`[BankrBackend] Failed to cache address: ${e}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async getAddress(): Promise<Address> {
|
|
130
|
+
if (this.cachedAddress) return this.cachedAddress;
|
|
131
|
+
|
|
132
|
+
// Query Bankr for the wallet address
|
|
133
|
+
console.log('[BankrBackend] Fetching wallet address from Bankr...');
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const response = await this.submitAndWait('What is my EVM wallet address?');
|
|
137
|
+
|
|
138
|
+
// Extract address from response
|
|
139
|
+
const addressMatch = response.match(/0x[a-fA-F0-9]{40}/);
|
|
140
|
+
if (!addressMatch) {
|
|
141
|
+
console.warn('[BankrBackend] Could not parse address from response:', response.slice(0, 100));
|
|
142
|
+
throw new Error('[BankrBackend] Could not determine wallet address from Bankr');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
this.cachedAddress = addressMatch[0] as Address;
|
|
146
|
+
|
|
147
|
+
// Save to disk for next time
|
|
148
|
+
this.saveCachedAddress(this.cachedAddress);
|
|
149
|
+
|
|
150
|
+
console.log(`[BankrBackend] Wallet address: ${this.cachedAddress}`);
|
|
151
|
+
|
|
152
|
+
return this.cachedAddress;
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.error('[BankrBackend] Failed to get address:', error);
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get the Solana wallet address from Bankr
|
|
161
|
+
*/
|
|
162
|
+
async getSolanaAddress(): Promise<string | null> {
|
|
163
|
+
if (this.cachedSolanaAddress) return this.cachedSolanaAddress;
|
|
164
|
+
|
|
165
|
+
// Check for cached address on disk
|
|
166
|
+
const cachePath = `${process.env.HOME}/.openclaw/cache/bankr-${this.nickname}-solana-address.json`;
|
|
167
|
+
try {
|
|
168
|
+
const fs = await import('fs');
|
|
169
|
+
if (fs.existsSync(cachePath)) {
|
|
170
|
+
const cached = JSON.parse(fs.readFileSync(cachePath, 'utf8'));
|
|
171
|
+
if (cached.address && Date.now() - cached.timestamp < 86400000) {
|
|
172
|
+
this.cachedSolanaAddress = cached.address;
|
|
173
|
+
console.log(`[BankrBackend] Loaded cached Solana address: ${this.cachedSolanaAddress}`);
|
|
174
|
+
return this.cachedSolanaAddress;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
} catch (e) {
|
|
178
|
+
// Cache miss, continue to query
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
console.log('[BankrBackend] Fetching Solana wallet address from Bankr...');
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
const response = await this.submitAndWait('What is my Solana wallet address?');
|
|
185
|
+
|
|
186
|
+
// Solana addresses are base58, typically 32-44 chars, no 0x prefix
|
|
187
|
+
const solanaMatch = response.match(/[1-9A-HJ-NP-Za-km-z]{32,44}/);
|
|
188
|
+
if (!solanaMatch) {
|
|
189
|
+
console.warn('[BankrBackend] Could not parse Solana address from response');
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
this.cachedSolanaAddress = solanaMatch[0];
|
|
194
|
+
console.log(`[BankrBackend] Solana address: ${this.cachedSolanaAddress}`);
|
|
195
|
+
|
|
196
|
+
// Cache to disk
|
|
197
|
+
try {
|
|
198
|
+
const fs = await import('fs');
|
|
199
|
+
const path = await import('path');
|
|
200
|
+
const cacheDir = path.dirname(cachePath);
|
|
201
|
+
if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, { recursive: true });
|
|
202
|
+
fs.writeFileSync(cachePath, JSON.stringify({ address: this.cachedSolanaAddress, timestamp: Date.now() }));
|
|
203
|
+
} catch (e) {
|
|
204
|
+
console.warn('[BankrBackend] Failed to cache Solana address:', e);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return this.cachedSolanaAddress;
|
|
208
|
+
} catch (error) {
|
|
209
|
+
console.error('[BankrBackend] Failed to get Solana address:', error);
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
supportsChain(chainId: string): boolean {
|
|
215
|
+
// Normalize chain ID to handle SODAX format (0x2105.base -> base)
|
|
216
|
+
return isBankrSupportedChain(chainId);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async isReady(): Promise<boolean> {
|
|
220
|
+
if (!this.apiKey) return false;
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
// Test API connectivity
|
|
224
|
+
const response = await fetch(`${this.apiUrl}/agent/prompt`, {
|
|
225
|
+
method: 'POST',
|
|
226
|
+
headers: {
|
|
227
|
+
'X-API-Key': this.apiKey,
|
|
228
|
+
'Content-Type': 'application/json',
|
|
229
|
+
},
|
|
230
|
+
body: JSON.stringify({ prompt: 'ping' }),
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
return response.status !== 503 && response.status !== 502;
|
|
234
|
+
} catch {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Send raw transaction via Bankr
|
|
241
|
+
* Uses the arbitrary transaction format
|
|
242
|
+
*/
|
|
243
|
+
async sendRawTransaction(tx: RawTransaction): Promise<Hash> {
|
|
244
|
+
console.log(`[BankrBackend] Sending raw transaction`);
|
|
245
|
+
console.log(`[BankrBackend] To: ${tx.to}`);
|
|
246
|
+
console.log(`[BankrBackend] Chain: ${tx.chainId}`);
|
|
247
|
+
console.log(`[BankrBackend] Value: ${tx.value}`);
|
|
248
|
+
console.log(`[BankrBackend] Data: ${tx.data.slice(0, 20)}...`);
|
|
249
|
+
|
|
250
|
+
// Format as documented in arbitrary-transaction.md
|
|
251
|
+
const txJson = JSON.stringify({
|
|
252
|
+
to: tx.to,
|
|
253
|
+
data: tx.data,
|
|
254
|
+
value: tx.value,
|
|
255
|
+
chainId: tx.chainId,
|
|
256
|
+
}, null, 2);
|
|
257
|
+
|
|
258
|
+
// Use the documented prompt format
|
|
259
|
+
const prompt = `Submit this transaction:
|
|
260
|
+
${txJson}`;
|
|
261
|
+
|
|
262
|
+
console.log(`[BankrBackend] Submitting to Bankr API...`);
|
|
263
|
+
|
|
264
|
+
const result = await this.submitAndWaitForJob(prompt);
|
|
265
|
+
|
|
266
|
+
// Extract transaction hash from response
|
|
267
|
+
const txHash = this.extractTransactionHash(result);
|
|
268
|
+
|
|
269
|
+
if (!txHash) {
|
|
270
|
+
const errorMsg = result.error || result.response || 'Unknown error';
|
|
271
|
+
throw new Error(`[BankrBackend] Transaction failed: ${errorMsg}`);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
console.log(`[BankrBackend] Transaction hash: ${txHash}`);
|
|
275
|
+
return txHash;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Submit prompt and wait for text response
|
|
280
|
+
*/
|
|
281
|
+
private async submitAndWait(prompt: string): Promise<string> {
|
|
282
|
+
const result = await this.submitAndWaitForJob(prompt);
|
|
283
|
+
return result.response || '';
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Submit prompt and wait for job completion
|
|
288
|
+
*/
|
|
289
|
+
private async submitAndWaitForJob(prompt: string): Promise<BankrJobStatusResponse> {
|
|
290
|
+
// Submit job
|
|
291
|
+
const submitResponse = await fetch(`${this.apiUrl}/agent/prompt`, {
|
|
292
|
+
method: 'POST',
|
|
293
|
+
headers: {
|
|
294
|
+
'X-API-Key': this.apiKey,
|
|
295
|
+
'Content-Type': 'application/json',
|
|
296
|
+
},
|
|
297
|
+
body: JSON.stringify({ prompt }),
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
if (!submitResponse.ok) {
|
|
301
|
+
const error = await submitResponse.text();
|
|
302
|
+
throw new Error(`[BankrBackend] Failed to submit job: ${submitResponse.status} ${error}`);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const submitData = await submitResponse.json() as BankrJobSubmitResponse;
|
|
306
|
+
|
|
307
|
+
if (!submitData.success || !submitData.jobId) {
|
|
308
|
+
throw new Error(`[BankrBackend] Invalid job response: ${JSON.stringify(submitData)}`);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const jobId = submitData.jobId;
|
|
312
|
+
console.log(`[BankrBackend] Job submitted: ${jobId}`);
|
|
313
|
+
|
|
314
|
+
// Poll for completion
|
|
315
|
+
let lastStatus = '';
|
|
316
|
+
|
|
317
|
+
for (let attempt = 0; attempt < this.maxPollAttempts; attempt++) {
|
|
318
|
+
await this.sleep(this.pollIntervalMs);
|
|
319
|
+
|
|
320
|
+
const statusResponse = await fetch(`${this.apiUrl}/agent/job/${jobId}`, {
|
|
321
|
+
method: 'GET',
|
|
322
|
+
headers: { 'X-API-Key': this.apiKey },
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
if (!statusResponse.ok) {
|
|
326
|
+
const error = await statusResponse.text();
|
|
327
|
+
throw new Error(`[BankrBackend] Failed to get job status: ${statusResponse.status} ${error}`);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const result = await statusResponse.json() as BankrJobStatusResponse;
|
|
331
|
+
|
|
332
|
+
// Log status changes
|
|
333
|
+
if (result.status !== lastStatus) {
|
|
334
|
+
console.log(`[BankrBackend] Job ${jobId}: ${result.status}`);
|
|
335
|
+
lastStatus = result.status;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Log progress updates
|
|
339
|
+
if (result.statusUpdates && result.statusUpdates.length > 0) {
|
|
340
|
+
const lastUpdate = result.statusUpdates[result.statusUpdates.length - 1];
|
|
341
|
+
console.log(`[BankrBackend] Progress: ${lastUpdate.message}`);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Check terminal states
|
|
345
|
+
switch (result.status) {
|
|
346
|
+
case 'completed':
|
|
347
|
+
return result;
|
|
348
|
+
case 'failed':
|
|
349
|
+
throw new Error(`[BankrBackend] Job failed: ${result.error || 'Unknown error'}`);
|
|
350
|
+
case 'cancelled':
|
|
351
|
+
throw new Error(`[BankrBackend] Job was cancelled`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
throw new Error(`[BankrBackend] Job ${jobId} timed out`);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Extract transaction hash from Bankr response
|
|
360
|
+
*/
|
|
361
|
+
private extractTransactionHash(result: BankrJobStatusResponse): Hash | null {
|
|
362
|
+
// Check richData for transaction info
|
|
363
|
+
if (result.richData) {
|
|
364
|
+
for (const item of result.richData) {
|
|
365
|
+
if (item.transactionHash) return item.transactionHash as Hash;
|
|
366
|
+
if (item.txHash) return item.txHash as Hash;
|
|
367
|
+
if (item.hash) return item.hash as Hash;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Try to extract from response text
|
|
372
|
+
if (result.response) {
|
|
373
|
+
// Look for 0x + 64 hex chars
|
|
374
|
+
const hashMatch = result.response.match(/0x[a-fA-F0-9]{64}/);
|
|
375
|
+
if (hashMatch) return hashMatch[0] as Hash;
|
|
376
|
+
|
|
377
|
+
// Check for failure indicators
|
|
378
|
+
if (result.response.toLowerCase().includes('reverted') ||
|
|
379
|
+
result.response.toLowerCase().includes('failed') ||
|
|
380
|
+
result.response.toLowerCase().includes('insufficient')) {
|
|
381
|
+
console.error(`[BankrBackend] Transaction failed: ${result.response}`);
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
private sleep(ms: number): Promise<void> {
|
|
390
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Create a Bankr backend from API key
|
|
396
|
+
*/
|
|
397
|
+
export function createBankrBackend(config: BankrBackendConfig): BankrBackend {
|
|
398
|
+
return new BankrBackend(config);
|
|
399
|
+
}
|