agentvault 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/.dfx/local/network-id +4 -0
- package/.next/trace +2 -0
- package/.vercel/README.txt +11 -0
- package/.vercel/project.json +1 -0
- package/AGENTS.md +43 -0
- package/CHANGELOG.md +196 -0
- package/LICENSE +21 -0
- package/PLAN_VAULT_INTEGRATION.md +318 -0
- package/README.md +253 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T17-54-28-967Z.json +28 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T17-54-29-032Z.backup +1 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T17-57-42-373Z.json +28 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T17-57-42-428Z.backup +1 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T18-52-25-132Z.json +28 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T18-52-25-247Z.backup +1 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T18-54-09-216Z.json +28 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T18-54-09-283Z.backup +1 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T22-18-22-772Z.backup +1 -0
- package/backups/agentvault-backup-test-agent-2026-02-12T22-18-22-793Z.json +28 -0
- package/backups/test-backup.json +28 -0
- package/dist/cli/commands/approve.d.ts +4 -0
- package/dist/cli/commands/approve.js +232 -0
- package/dist/cli/commands/archive.d.ts +4 -0
- package/dist/cli/commands/archive.js +192 -0
- package/dist/cli/commands/backup.d.ts +4 -0
- package/dist/cli/commands/backup.js +164 -0
- package/dist/cli/commands/cloud-backup.d.ts +4 -0
- package/dist/cli/commands/cloud-backup.js +221 -0
- package/dist/cli/commands/cycles.d.ts +8 -0
- package/dist/cli/commands/cycles.js +83 -0
- package/dist/cli/commands/decrypt.d.ts +16 -0
- package/dist/cli/commands/decrypt.js +101 -0
- package/dist/cli/commands/deploy.d.ts +32 -0
- package/dist/cli/commands/deploy.js +208 -0
- package/dist/cli/commands/exec.d.ts +26 -0
- package/dist/cli/commands/exec.js +109 -0
- package/dist/cli/commands/fetch.d.ts +23 -0
- package/dist/cli/commands/fetch.js +164 -0
- package/dist/cli/commands/health.d.ts +8 -0
- package/dist/cli/commands/health.js +72 -0
- package/dist/cli/commands/identity.d.ts +8 -0
- package/dist/cli/commands/identity.js +140 -0
- package/dist/cli/commands/inference.d.ts +4 -0
- package/dist/cli/commands/inference.js +225 -0
- package/dist/cli/commands/info.d.ts +8 -0
- package/dist/cli/commands/info.js +59 -0
- package/dist/cli/commands/init.d.ts +19 -0
- package/dist/cli/commands/init.js +135 -0
- package/dist/cli/commands/instrument.d.ts +8 -0
- package/dist/cli/commands/instrument.js +35 -0
- package/dist/cli/commands/list.d.ts +36 -0
- package/dist/cli/commands/list.js +173 -0
- package/dist/cli/commands/logs.d.ts +8 -0
- package/dist/cli/commands/logs.js +96 -0
- package/dist/cli/commands/monitor.d.ts +8 -0
- package/dist/cli/commands/monitor.js +84 -0
- package/dist/cli/commands/network.d.ts +14 -0
- package/dist/cli/commands/network.js +258 -0
- package/dist/cli/commands/package.d.ts +36 -0
- package/dist/cli/commands/package.js +188 -0
- package/dist/cli/commands/profile.d.ts +8 -0
- package/dist/cli/commands/profile.js +76 -0
- package/dist/cli/commands/promote.d.ts +8 -0
- package/dist/cli/commands/promote.js +89 -0
- package/dist/cli/commands/rebuild.d.ts +21 -0
- package/dist/cli/commands/rebuild.js +140 -0
- package/dist/cli/commands/rollback.d.ts +8 -0
- package/dist/cli/commands/rollback.js +120 -0
- package/dist/cli/commands/show.d.ts +36 -0
- package/dist/cli/commands/show.js +200 -0
- package/dist/cli/commands/stats.d.ts +8 -0
- package/dist/cli/commands/stats.js +34 -0
- package/dist/cli/commands/status.d.ts +14 -0
- package/dist/cli/commands/status.js +83 -0
- package/dist/cli/commands/test.d.ts +8 -0
- package/dist/cli/commands/test.js +109 -0
- package/dist/cli/commands/tokens.d.ts +8 -0
- package/dist/cli/commands/tokens.js +62 -0
- package/dist/cli/commands/trace.d.ts +8 -0
- package/dist/cli/commands/trace.js +68 -0
- package/dist/cli/commands/wallet-export.d.ts +13 -0
- package/dist/cli/commands/wallet-export.js +140 -0
- package/dist/cli/commands/wallet-history.d.ts +10 -0
- package/dist/cli/commands/wallet-history.js +127 -0
- package/dist/cli/commands/wallet-import.d.ts +10 -0
- package/dist/cli/commands/wallet-import.js +209 -0
- package/dist/cli/commands/wallet-multi-send.d.ts +17 -0
- package/dist/cli/commands/wallet-multi-send.js +195 -0
- package/dist/cli/commands/wallet-process-queue.d.ts +19 -0
- package/dist/cli/commands/wallet-process-queue.js +209 -0
- package/dist/cli/commands/wallet-sign.d.ts +13 -0
- package/dist/cli/commands/wallet-sign.js +207 -0
- package/dist/cli/commands/wallet.d.ts +12 -0
- package/dist/cli/commands/wallet.js +794 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/index.js +96 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.js +14 -0
- package/fixup_1_0_OSS_release.md +136 -0
- package/fixup_REALEASE_PRD.md +136 -0
- package/package.json +79 -0
- package/pnpm-workspace.yaml +5 -0
- package/scripts/dev-dashboard.mjs +84 -0
- package/site/README.md +63 -0
- package/site/docusaurus.config.ts +148 -0
- package/site/package-lock.json +18383 -0
- package/site/package.json +47 -0
- package/site/sidebars.ts +86 -0
- package/site/static/.gitkeep +0 -0
- package/site/static/img/logo.svg +28 -0
- package/site/static/img/og-image.svg +35 -0
- package/src/archival/archive-manager.ts +372 -0
- package/src/archival/arweave-client.ts +289 -0
- package/src/archival/index.ts +8 -0
- package/src/backup/backup.ts +315 -0
- package/src/backup/index.ts +7 -0
- package/src/cloud-storage/cloud-sync.ts +461 -0
- package/src/cloud-storage/index.ts +11 -0
- package/src/cloud-storage/provider-detector.ts +198 -0
- package/src/cloud-storage/types.ts +104 -0
- package/src/debugging/index.ts +6 -0
- package/src/debugging/logs.ts +193 -0
- package/src/debugging/types.ts +100 -0
- package/src/deployment/deployer.ts +274 -0
- package/src/deployment/icpClient.ts +620 -0
- package/src/deployment/index.ts +46 -0
- package/src/deployment/promotion.ts +161 -0
- package/src/deployment/types.ts +111 -0
- package/src/icp/batch.ts +374 -0
- package/src/icp/cycles.ts +50 -0
- package/src/icp/environment.ts +215 -0
- package/src/icp/icpcli.ts +438 -0
- package/src/icp/icwasm.ts +222 -0
- package/src/icp/identity.ts +77 -0
- package/src/icp/index.ts +94 -0
- package/src/icp/optimization.ts +242 -0
- package/src/icp/tokens.ts +36 -0
- package/src/icp/tool-detector.ts +110 -0
- package/src/icp/types.ts +574 -0
- package/src/index.ts +25 -0
- package/src/inference/bittensor-client.ts +304 -0
- package/src/inference/index.ts +8 -0
- package/src/inference/inference-manager.ts +327 -0
- package/src/metrics/index.ts +7 -0
- package/src/metrics/metrics.ts +186 -0
- package/src/monitoring/alerting.ts +190 -0
- package/src/monitoring/health.ts +197 -0
- package/src/monitoring/index.ts +38 -0
- package/src/monitoring/info.ts +114 -0
- package/src/monitoring/types.ts +99 -0
- package/src/network/index.ts +5 -0
- package/src/network/network-config.ts +129 -0
- package/src/packaging/compiler.ts +647 -0
- package/src/packaging/config-persistence.ts +135 -0
- package/src/packaging/config-schemas.ts +156 -0
- package/src/packaging/detector.ts +220 -0
- package/src/packaging/index.ts +90 -0
- package/src/packaging/packager.ts +118 -0
- package/src/packaging/parsers/clawdbot.ts +278 -0
- package/src/packaging/parsers/cline.ts +223 -0
- package/src/packaging/parsers/generic.ts +266 -0
- package/src/packaging/parsers/goose.ts +214 -0
- package/src/packaging/parsers/index.ts +11 -0
- package/src/packaging/serializer.ts +260 -0
- package/src/packaging/types.ts +144 -0
- package/src/packaging/wasmedge-compiler.ts +406 -0
- package/src/security/index.ts +17 -0
- package/src/security/multisig.ts +415 -0
- package/src/security/types.ts +416 -0
- package/src/security/vetkeys.ts +655 -0
- package/src/testing/index.ts +6 -0
- package/src/testing/local-runner.ts +264 -0
- package/src/testing/types.ts +104 -0
- package/src/wallet/cbor-serializer.ts +323 -0
- package/src/wallet/chain-dispatcher.ts +313 -0
- package/src/wallet/cross-chain-aggregator.ts +346 -0
- package/src/wallet/index.ts +76 -0
- package/src/wallet/key-derivation.ts +425 -0
- package/src/wallet/providers/base-provider.ts +154 -0
- package/src/wallet/providers/cketh-provider.ts +434 -0
- package/src/wallet/providers/polkadot-provider.ts +503 -0
- package/src/wallet/providers/solana-provider.ts +490 -0
- package/src/wallet/transaction-queue.ts +284 -0
- package/src/wallet/types.ts +178 -0
- package/src/wallet/vetkeys-adapter.ts +431 -0
- package/src/wallet/wallet-manager.ts +597 -0
- package/src/wallet/wallet-storage.ts +380 -0
- package/vercel.json +8 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chain Dispatcher (Phase 5C)
|
|
3
|
+
*
|
|
4
|
+
* Routes transactions to appropriate blockchain providers.
|
|
5
|
+
* Supports ckETH, Polkadot, and Solana chains.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { WalletData, TransactionRequest, Transaction, ChainType } from './types.js';
|
|
9
|
+
import { CkEthProvider } from './providers/cketh-provider.js';
|
|
10
|
+
import { PolkadotProvider } from './providers/polkadot-provider.js';
|
|
11
|
+
import { SolanaProvider } from './providers/solana-provider.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Chain dispatcher configuration
|
|
15
|
+
*/
|
|
16
|
+
export interface ChainDispatcherConfig {
|
|
17
|
+
isTestnet?: boolean;
|
|
18
|
+
apiKey?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Chain dispatcher
|
|
23
|
+
*
|
|
24
|
+
* Routes transactions to appropriate blockchain providers based on wallet chain.
|
|
25
|
+
*/
|
|
26
|
+
export class ChainDispatcher {
|
|
27
|
+
private providers: Map<ChainType, any>;
|
|
28
|
+
private config: ChainDispatcherConfig;
|
|
29
|
+
|
|
30
|
+
constructor(config: ChainDispatcherConfig = {}) {
|
|
31
|
+
this.config = {
|
|
32
|
+
isTestnet: config.isTestnet ?? false,
|
|
33
|
+
apiKey: config.apiKey,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
this.providers = new Map();
|
|
37
|
+
|
|
38
|
+
this.providers.set('cketh', new CkEthProvider({
|
|
39
|
+
chain: 'cketh',
|
|
40
|
+
rpcUrl: '',
|
|
41
|
+
isTestnet: this.config.isTestnet,
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
this.providers.set('polkadot', new PolkadotProvider({
|
|
45
|
+
chain: 'polkadot',
|
|
46
|
+
rpcUrl: '',
|
|
47
|
+
isTestnet: this.config.isTestnet,
|
|
48
|
+
}));
|
|
49
|
+
|
|
50
|
+
this.providers.set('solana', new SolanaProvider({
|
|
51
|
+
chain: 'solana',
|
|
52
|
+
rpcUrl: '',
|
|
53
|
+
isTestnet: this.config.isTestnet,
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Dispatch transaction to appropriate provider
|
|
59
|
+
*
|
|
60
|
+
* @param wallet - Wallet to use for signing
|
|
61
|
+
* @param request - Transaction request
|
|
62
|
+
* @returns Transaction result
|
|
63
|
+
*/
|
|
64
|
+
async dispatchTransaction(
|
|
65
|
+
wallet: WalletData,
|
|
66
|
+
request: TransactionRequest
|
|
67
|
+
): Promise<Transaction> {
|
|
68
|
+
const provider = this.getProvider(wallet.chain);
|
|
69
|
+
|
|
70
|
+
if (!provider) {
|
|
71
|
+
throw new Error(`Unsupported chain: ${wallet.chain}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
await provider.connect();
|
|
75
|
+
|
|
76
|
+
const tx = await provider.sendTransaction(wallet.address, request);
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
hash: tx.hash,
|
|
80
|
+
from: wallet.address,
|
|
81
|
+
to: request.to,
|
|
82
|
+
amount: request.amount,
|
|
83
|
+
chain: wallet.chain,
|
|
84
|
+
timestamp: Date.now(),
|
|
85
|
+
status: 'pending',
|
|
86
|
+
fee: tx.fee,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Sign transaction without broadcasting
|
|
92
|
+
*
|
|
93
|
+
* @param wallet - Wallet to use for signing
|
|
94
|
+
* @param request - Transaction request
|
|
95
|
+
* @returns Signed transaction
|
|
96
|
+
*/
|
|
97
|
+
async signTransaction(
|
|
98
|
+
wallet: WalletData,
|
|
99
|
+
request: TransactionRequest
|
|
100
|
+
): Promise<{ signedTx: string; signature: string }> {
|
|
101
|
+
const provider = this.getProvider(wallet.chain);
|
|
102
|
+
|
|
103
|
+
if (!provider) {
|
|
104
|
+
throw new Error(`Unsupported chain: ${wallet.chain}`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
await provider.connect();
|
|
108
|
+
|
|
109
|
+
const signed = await provider.signTransaction(request, wallet.privateKey);
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
signedTx: signed.signedTx,
|
|
113
|
+
signature: signed.signature || '',
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Get wallet balance
|
|
119
|
+
*
|
|
120
|
+
* @param wallet - Wallet to query
|
|
121
|
+
* @returns Wallet balance
|
|
122
|
+
*/
|
|
123
|
+
async getBalance(wallet: WalletData): Promise<{ amount: string; denomination: string }> {
|
|
124
|
+
const provider = this.getProvider(wallet.chain);
|
|
125
|
+
|
|
126
|
+
if (!provider) {
|
|
127
|
+
throw new Error(`Unsupported chain: ${wallet.chain}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
await provider.connect();
|
|
131
|
+
|
|
132
|
+
const balance = await provider.getBalance(wallet.address);
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
amount: balance.amount,
|
|
136
|
+
denomination: balance.denomination,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Get transaction history
|
|
142
|
+
*
|
|
143
|
+
* @param wallet - Wallet to query
|
|
144
|
+
* @param limit - Maximum number of transactions
|
|
145
|
+
* @returns Transaction history
|
|
146
|
+
*/
|
|
147
|
+
async getTransactionHistory(
|
|
148
|
+
wallet: WalletData,
|
|
149
|
+
limit: number = 20
|
|
150
|
+
): Promise<Transaction[]> {
|
|
151
|
+
const provider = this.getProvider(wallet.chain);
|
|
152
|
+
|
|
153
|
+
if (!provider) {
|
|
154
|
+
throw new Error(`Unsupported chain: ${wallet.chain}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
await provider.connect();
|
|
158
|
+
|
|
159
|
+
const history = await provider.getTransactionHistory(wallet.address);
|
|
160
|
+
|
|
161
|
+
return history.slice(0, limit);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Estimate transaction fee
|
|
166
|
+
*
|
|
167
|
+
* @param wallet - Wallet to use
|
|
168
|
+
* @param request - Transaction request
|
|
169
|
+
* @returns Estimated fee
|
|
170
|
+
*/
|
|
171
|
+
async estimateFee(
|
|
172
|
+
wallet: WalletData,
|
|
173
|
+
request: TransactionRequest
|
|
174
|
+
): Promise<string> {
|
|
175
|
+
const provider = this.getProvider(wallet.chain);
|
|
176
|
+
|
|
177
|
+
if (!provider) {
|
|
178
|
+
throw new Error(`Unsupported chain: ${wallet.chain}`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
await provider.connect();
|
|
182
|
+
|
|
183
|
+
const fee = await provider.estimateFee(request);
|
|
184
|
+
|
|
185
|
+
return fee;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Validate address
|
|
190
|
+
*
|
|
191
|
+
* @param address - Address to validate
|
|
192
|
+
* @param chain - Chain to validate against
|
|
193
|
+
* @returns True if valid
|
|
194
|
+
*/
|
|
195
|
+
async validateAddress(address: string, chain: ChainType): Promise<boolean> {
|
|
196
|
+
const provider = this.getProvider(chain);
|
|
197
|
+
|
|
198
|
+
if (!provider) {
|
|
199
|
+
throw new Error(`Unsupported chain: ${chain}`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return await provider.validateAddress(address);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Get current block number
|
|
207
|
+
*
|
|
208
|
+
* @param chain - Chain to query
|
|
209
|
+
* @returns Current block number
|
|
210
|
+
*/
|
|
211
|
+
async getBlockNumber(chain: ChainType): Promise<number> {
|
|
212
|
+
const provider = this.getProvider(chain);
|
|
213
|
+
|
|
214
|
+
if (!provider) {
|
|
215
|
+
throw new Error(`Unsupported chain: ${chain}`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
await provider.connect();
|
|
219
|
+
|
|
220
|
+
const block = await provider.getBlockNumber();
|
|
221
|
+
|
|
222
|
+
return block;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Get transaction by hash
|
|
227
|
+
*
|
|
228
|
+
* @param chain - Chain to query
|
|
229
|
+
* @param txHash - Transaction hash
|
|
230
|
+
* @returns Transaction details
|
|
231
|
+
*/
|
|
232
|
+
async getTransaction(chain: ChainType, txHash: string): Promise<Transaction | null> {
|
|
233
|
+
const provider = this.getProvider(chain);
|
|
234
|
+
|
|
235
|
+
if (!provider) {
|
|
236
|
+
throw new Error(`Unsupported chain: ${chain}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
await provider.connect();
|
|
240
|
+
|
|
241
|
+
const tx = await provider.getTransaction(txHash);
|
|
242
|
+
|
|
243
|
+
if (!tx) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
hash: tx.hash,
|
|
249
|
+
from: tx.from,
|
|
250
|
+
to: tx.to,
|
|
251
|
+
amount: tx.amount,
|
|
252
|
+
chain,
|
|
253
|
+
timestamp: tx.timestamp,
|
|
254
|
+
status: tx.status,
|
|
255
|
+
fee: tx.fee,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Get provider for chain
|
|
261
|
+
*/
|
|
262
|
+
private getProvider(chain: ChainType): any {
|
|
263
|
+
const provider = this.providers.get(chain);
|
|
264
|
+
|
|
265
|
+
if (!provider) {
|
|
266
|
+
throw new Error(`No provider found for chain: ${chain}`);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return provider;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Connect all providers
|
|
274
|
+
*/
|
|
275
|
+
async connectAll(): Promise<void> {
|
|
276
|
+
const connections = Array.from(this.providers.entries()).map(async ([chain, provider]) => {
|
|
277
|
+
try {
|
|
278
|
+
await provider.connect();
|
|
279
|
+
return { chain, success: true };
|
|
280
|
+
} catch (error) {
|
|
281
|
+
return { chain, success: false, error };
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
await Promise.all(connections);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Disconnect all providers
|
|
290
|
+
*/
|
|
291
|
+
async disconnectAll(): Promise<void> {
|
|
292
|
+
const disconnections = Array.from(this.providers.entries()).map(async ([chain, provider]) => {
|
|
293
|
+
try {
|
|
294
|
+
await provider.disconnect();
|
|
295
|
+
return { chain, success: true };
|
|
296
|
+
} catch (error) {
|
|
297
|
+
return { chain, success: false, error };
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
await Promise.all(disconnections);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Create chain dispatcher
|
|
307
|
+
*
|
|
308
|
+
* @param config - Dispatcher configuration
|
|
309
|
+
* @returns Chain dispatcher instance
|
|
310
|
+
*/
|
|
311
|
+
export function createChainDispatcher(config?: ChainDispatcherConfig): ChainDispatcher {
|
|
312
|
+
return new ChainDispatcher(config);
|
|
313
|
+
}
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Chain Aggregator (Phase 5C)
|
|
3
|
+
*
|
|
4
|
+
* Executes multiple blockchain transactions in parallel.
|
|
5
|
+
* Supports independent execution (no atomic rollback) as per user preference.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { WalletData, TransactionRequest, Transaction, ChainType } from './types.js';
|
|
9
|
+
import { ChainDispatcher } from './chain-dispatcher.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Multi-chain action
|
|
13
|
+
*/
|
|
14
|
+
export interface MultiChainAction {
|
|
15
|
+
walletId: string;
|
|
16
|
+
chain: ChainType;
|
|
17
|
+
request: TransactionRequest;
|
|
18
|
+
priority?: 'low' | 'normal' | 'high';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Cross-chain execution result
|
|
23
|
+
*/
|
|
24
|
+
export interface CrossChainResult {
|
|
25
|
+
action: MultiChainAction;
|
|
26
|
+
success: boolean;
|
|
27
|
+
txHash?: string;
|
|
28
|
+
error?: string;
|
|
29
|
+
executedAt: number;
|
|
30
|
+
duration?: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Aggregated execution results
|
|
35
|
+
*/
|
|
36
|
+
export interface AggregatedResults {
|
|
37
|
+
total: number;
|
|
38
|
+
succeeded: number;
|
|
39
|
+
failed: number;
|
|
40
|
+
results: CrossChainResult[];
|
|
41
|
+
duration: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Cross-chain aggregator options
|
|
46
|
+
*/
|
|
47
|
+
export interface AggregatorOptions {
|
|
48
|
+
maxConcurrency?: number;
|
|
49
|
+
timeout?: number;
|
|
50
|
+
continueOnError?: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Cross-chain aggregator
|
|
55
|
+
*
|
|
56
|
+
* Executes transactions across multiple blockchains in parallel.
|
|
57
|
+
* Independent execution: No rollback on partial failure.
|
|
58
|
+
*/
|
|
59
|
+
export class CrossChainAggregator {
|
|
60
|
+
private dispatcher: ChainDispatcher;
|
|
61
|
+
private options: AggregatorOptions;
|
|
62
|
+
|
|
63
|
+
constructor(options?: AggregatorOptions) {
|
|
64
|
+
this.dispatcher = new ChainDispatcher();
|
|
65
|
+
this.options = {
|
|
66
|
+
maxConcurrency: options?.maxConcurrency ?? 5,
|
|
67
|
+
timeout: options?.timeout ?? 30000,
|
|
68
|
+
continueOnError: options?.continueOnError ?? true,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Execute multiple cross-chain actions
|
|
74
|
+
*
|
|
75
|
+
* @param actions - Array of multi-chain actions
|
|
76
|
+
* @returns Aggregated results
|
|
77
|
+
*/
|
|
78
|
+
async execute(actions: MultiChainAction[]): Promise<AggregatedResults> {
|
|
79
|
+
const startTime = Date.now();
|
|
80
|
+
|
|
81
|
+
if (actions.length === 0) {
|
|
82
|
+
return {
|
|
83
|
+
total: 0,
|
|
84
|
+
succeeded: 0,
|
|
85
|
+
failed: 0,
|
|
86
|
+
results: [],
|
|
87
|
+
duration: 0,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
console.log(`Executing ${actions.length} cross-chain actions...`);
|
|
92
|
+
|
|
93
|
+
const results = await this.executeParallel(actions);
|
|
94
|
+
|
|
95
|
+
const succeeded = results.filter((r) => r.success).length;
|
|
96
|
+
const failed = results.filter((r) => !r.success).length;
|
|
97
|
+
|
|
98
|
+
const duration = Date.now() - startTime;
|
|
99
|
+
|
|
100
|
+
console.log(
|
|
101
|
+
`Execution complete: ${succeeded} succeeded, ${failed} failed (${duration}ms)`
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
total: results.length,
|
|
106
|
+
succeeded,
|
|
107
|
+
failed,
|
|
108
|
+
results,
|
|
109
|
+
duration,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Execute actions in parallel with concurrency limit
|
|
115
|
+
*/
|
|
116
|
+
private async executeParallel(
|
|
117
|
+
actions: MultiChainAction[]
|
|
118
|
+
): Promise<CrossChainResult[]> {
|
|
119
|
+
const results: CrossChainResult[] = [];
|
|
120
|
+
|
|
121
|
+
const chunks = this.chunkArray(
|
|
122
|
+
actions,
|
|
123
|
+
this.options.maxConcurrency ?? 5
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
for (const chunk of chunks) {
|
|
127
|
+
const chunkResults = await Promise.all(
|
|
128
|
+
chunk.map((action) => this.executeAction(action))
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
results.push(...chunkResults);
|
|
132
|
+
|
|
133
|
+
if (!this.options.continueOnError) {
|
|
134
|
+
const hasFailure = chunkResults.some((r) => !r.success);
|
|
135
|
+
if (hasFailure) {
|
|
136
|
+
console.log('Stopping due to failure (continueOnError = false)');
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return results;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Execute a single cross-chain action
|
|
147
|
+
*/
|
|
148
|
+
private async executeAction(
|
|
149
|
+
action: MultiChainAction
|
|
150
|
+
): Promise<CrossChainResult> {
|
|
151
|
+
const startTime = Date.now();
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
const { getWallet } = await import('./wallet-manager.js');
|
|
155
|
+
const wallet = getWallet('', action.walletId);
|
|
156
|
+
|
|
157
|
+
if (!wallet) {
|
|
158
|
+
throw new Error(`Wallet not found: ${action.walletId}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const tx = await this.dispatcher.dispatchTransaction(
|
|
162
|
+
wallet,
|
|
163
|
+
action.request
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const duration = Date.now() - startTime;
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
action,
|
|
170
|
+
success: true,
|
|
171
|
+
txHash: tx.hash,
|
|
172
|
+
executedAt: Date.now(),
|
|
173
|
+
duration,
|
|
174
|
+
};
|
|
175
|
+
} catch (error) {
|
|
176
|
+
const duration = Date.now() - startTime;
|
|
177
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
action,
|
|
181
|
+
success: false,
|
|
182
|
+
error: message,
|
|
183
|
+
executedAt: Date.now(),
|
|
184
|
+
duration,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Split array into chunks
|
|
191
|
+
*/
|
|
192
|
+
private chunkArray<T>(array: T[], size: number): T[][] {
|
|
193
|
+
const chunks: T[][] = [];
|
|
194
|
+
|
|
195
|
+
for (let i = 0; i < array.length; i += size) {
|
|
196
|
+
chunks.push(array.slice(i, i + size));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return chunks;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Get balances across multiple chains
|
|
204
|
+
*
|
|
205
|
+
* @param wallets - Array of wallets to query
|
|
206
|
+
* @returns Array of balances
|
|
207
|
+
*/
|
|
208
|
+
async getBalances(
|
|
209
|
+
wallets: WalletData[]
|
|
210
|
+
): Promise<Array<{ wallet: WalletData; amount: string; denomination: string }>> {
|
|
211
|
+
const results = await Promise.all(
|
|
212
|
+
wallets.map(async (wallet) => {
|
|
213
|
+
try {
|
|
214
|
+
const balance = await this.dispatcher.getBalance(wallet);
|
|
215
|
+
return {
|
|
216
|
+
wallet,
|
|
217
|
+
amount: balance.amount,
|
|
218
|
+
denomination: balance.denomination,
|
|
219
|
+
success: true,
|
|
220
|
+
};
|
|
221
|
+
} catch (error) {
|
|
222
|
+
return {
|
|
223
|
+
wallet,
|
|
224
|
+
amount: '0',
|
|
225
|
+
denomination: 'N/A',
|
|
226
|
+
success: false,
|
|
227
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
})
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
return results;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Get transaction history across multiple chains
|
|
238
|
+
*
|
|
239
|
+
* @param wallets - Array of wallets to query
|
|
240
|
+
* @param limit - Maximum transactions per wallet
|
|
241
|
+
* @returns Array of transactions
|
|
242
|
+
*/
|
|
243
|
+
async getMultiChainHistory(
|
|
244
|
+
wallets: WalletData[],
|
|
245
|
+
limit: number = 20
|
|
246
|
+
): Promise<Transaction[]> {
|
|
247
|
+
const results = await Promise.all(
|
|
248
|
+
wallets.map(async (wallet) => {
|
|
249
|
+
try {
|
|
250
|
+
return await this.dispatcher.getTransactionHistory(wallet, limit);
|
|
251
|
+
} catch (error) {
|
|
252
|
+
console.error(
|
|
253
|
+
`Failed to get history for ${wallet.id}:`,
|
|
254
|
+
error
|
|
255
|
+
);
|
|
256
|
+
return [];
|
|
257
|
+
}
|
|
258
|
+
})
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
return results.flat().slice(0, wallets.length * limit);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Estimate fees across multiple chains
|
|
266
|
+
*
|
|
267
|
+
* @param actions - Array of actions to estimate
|
|
268
|
+
* @returns Array of fee estimates
|
|
269
|
+
*/
|
|
270
|
+
async estimateFees(
|
|
271
|
+
actions: MultiChainAction[]
|
|
272
|
+
): Promise<Array<{ action: MultiChainAction; fee: string }>> {
|
|
273
|
+
const results = await Promise.all(
|
|
274
|
+
actions.map(async (action) => {
|
|
275
|
+
try {
|
|
276
|
+
const { getWallet } = await import('./wallet-manager.js');
|
|
277
|
+
const wallet = getWallet('', action.walletId);
|
|
278
|
+
|
|
279
|
+
if (!wallet) {
|
|
280
|
+
throw new Error(`Wallet not found: ${action.walletId}`);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const fee = await this.dispatcher.estimateFee(wallet, action.request);
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
action,
|
|
287
|
+
fee,
|
|
288
|
+
success: true,
|
|
289
|
+
};
|
|
290
|
+
} catch (error) {
|
|
291
|
+
return {
|
|
292
|
+
action,
|
|
293
|
+
fee: 'N/A',
|
|
294
|
+
success: false,
|
|
295
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
})
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
return results;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Create cross-chain batch summary
|
|
306
|
+
*
|
|
307
|
+
* @param results - Aggregated execution results
|
|
308
|
+
* @returns Formatted summary
|
|
309
|
+
*/
|
|
310
|
+
createSummary(results: AggregatedResults): string {
|
|
311
|
+
const lines: string[] = [];
|
|
312
|
+
|
|
313
|
+
lines.push('Cross-Chain Execution Summary');
|
|
314
|
+
lines.push('============================');
|
|
315
|
+
lines.push(`Total Actions: ${results.total}`);
|
|
316
|
+
lines.push(`Succeeded: ${results.succeeded}`);
|
|
317
|
+
lines.push(`Failed: ${results.failed}`);
|
|
318
|
+
lines.push(`Success Rate: ${results.total > 0 ? ((results.succeeded / results.total) * 100).toFixed(2) : 0}%`);
|
|
319
|
+
lines.push(`Total Duration: ${results.duration}ms`);
|
|
320
|
+
|
|
321
|
+
if (results.failed > 0) {
|
|
322
|
+
lines.push('');
|
|
323
|
+
lines.push('Failed Actions:');
|
|
324
|
+
results.results
|
|
325
|
+
.filter((r) => !r.success)
|
|
326
|
+
.forEach((r) => {
|
|
327
|
+
lines.push(` [${r.action.chain}] ${r.action.walletId}`);
|
|
328
|
+
lines.push(` Error: ${r.error}`);
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return lines.join('\n');
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Create cross-chain aggregator
|
|
338
|
+
*
|
|
339
|
+
* @param options - Aggregator options
|
|
340
|
+
* @returns Cross-chain aggregator instance
|
|
341
|
+
*/
|
|
342
|
+
export function createCrossChainAggregator(
|
|
343
|
+
options?: AggregatorOptions
|
|
344
|
+
): CrossChainAggregator {
|
|
345
|
+
return new CrossChainAggregator(options);
|
|
346
|
+
}
|