wallet-agent-ai-radix 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 (55) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +284 -0
  3. package/dist/agent.d.ts +2 -0
  4. package/dist/agent.d.ts.map +1 -0
  5. package/dist/agent.js +158 -0
  6. package/dist/agent.js.map +1 -0
  7. package/dist/cli/derive.d.ts +5 -0
  8. package/dist/cli/derive.d.ts.map +1 -0
  9. package/dist/cli/derive.js +78 -0
  10. package/dist/cli/derive.js.map +1 -0
  11. package/dist/cli/index.d.ts +2 -0
  12. package/dist/cli/index.d.ts.map +1 -0
  13. package/dist/cli/index.js +32 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/cli/init.d.ts +2 -0
  16. package/dist/cli/init.d.ts.map +1 -0
  17. package/dist/cli/init.js +171 -0
  18. package/dist/cli/init.js.map +1 -0
  19. package/dist/cli/recover.d.ts +2 -0
  20. package/dist/cli/recover.d.ts.map +1 -0
  21. package/dist/cli/recover.js +112 -0
  22. package/dist/cli/recover.js.map +1 -0
  23. package/dist/cli/unlock.d.ts +3 -0
  24. package/dist/cli/unlock.d.ts.map +1 -0
  25. package/dist/cli/unlock.js +70 -0
  26. package/dist/cli/unlock.js.map +1 -0
  27. package/dist/core/AGGRClient.d.ts +19 -0
  28. package/dist/core/AGGRClient.d.ts.map +1 -0
  29. package/dist/core/AGGRClient.js +103 -0
  30. package/dist/core/AGGRClient.js.map +1 -0
  31. package/dist/core/AgentWallet.d.ts +64 -0
  32. package/dist/core/AgentWallet.d.ts.map +1 -0
  33. package/dist/core/AgentWallet.js +658 -0
  34. package/dist/core/AgentWallet.js.map +1 -0
  35. package/dist/core/RadixClient.d.ts +15 -0
  36. package/dist/core/RadixClient.d.ts.map +1 -0
  37. package/dist/core/RadixClient.js +112 -0
  38. package/dist/core/RadixClient.js.map +1 -0
  39. package/dist/index.d.ts +7 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +29 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/keystore/Keystore.d.ts +17 -0
  44. package/dist/keystore/Keystore.d.ts.map +1 -0
  45. package/dist/keystore/Keystore.js +97 -0
  46. package/dist/keystore/Keystore.js.map +1 -0
  47. package/dist/tools/LangChainTools.d.ts +19 -0
  48. package/dist/tools/LangChainTools.d.ts.map +1 -0
  49. package/dist/tools/LangChainTools.js +613 -0
  50. package/dist/tools/LangChainTools.js.map +1 -0
  51. package/dist/types/index.d.ts +104 -0
  52. package/dist/types/index.d.ts.map +1 -0
  53. package/dist/types/index.js +6 -0
  54. package/dist/types/index.js.map +1 -0
  55. package/package.json +44 -0
@@ -0,0 +1,658 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AgentWallet = void 0;
4
+ const AGGRClient_1 = require("./AGGRClient");
5
+ const RadixClient_1 = require("./RadixClient");
6
+ // Direcciones de los assets en cada red
7
+ const ASSET_ADDRESSES = {
8
+ mainnet: {
9
+ XRD: "resource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd",
10
+ HWBTC: "resource_rdx1t58kkcqdz0mavfz98m98qh9m4jexyl9tacsvlhns6yxs4r6hrm5re5",
11
+ HUSDC: "resource_rdx1thxj9m87sn5cc9ehgp9qxp6vzeqxtce90xm5cp33373tclyp4et4gv",
12
+ HETH: "resource_rdx1th09yvv7tgsrv708ffsgqjjf2mhy84mscmj5jwu4g670fh3e5zgef0",
13
+ HUSDT: "resource_rdx1th4v03gezwgzkuma6p38lnum8ww8t4ds9nvcrkr2p9ft6kxx3kxvhe",
14
+ },
15
+ stokenet: {
16
+ XRD: "resource_tdx_2_1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxtfd2jc",
17
+ HWBTC: "resource_tdx_2_1tkshqwxsg524asnfd5e6d27dwc27sywtdmlrpgp63uwdwk90e9sf7h",
18
+ HUSDC: "resource_tdx_2_1tkvlvu3zekq5dj8n34cg4swlnj6mwdkcrcal2wf54kwehwx02ly5my",
19
+ HETH: "resource_tdx_2_1tk76lm84jurun672nkn6893hjsfwyp9wd7qz0yxha5dvu5h72svtzq",
20
+ HUSDT: "resource_tdx_2_1tk6g9gwdph40v8sd8qfte0lgftc7g8xxqkz86dtynwm6x72zm6ezce",
21
+ },
22
+ localnet: {
23
+ XRD: "resource_sim1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxakj8n3",
24
+ HUSDC: "resource_sim1t_husdc",
25
+ HWBTC: "resource_sim1t_hwbtc",
26
+ HETH: "resource_sim1t_heth",
27
+ HUSDT: "resource_sim1t_husdt",
28
+ },
29
+ };
30
+ // Configuración de red
31
+ const NETWORK_CONFIG = {
32
+ mainnet: {
33
+ gatewayUrl: "https://mainnet.radixdlt.com",
34
+ networkId: 0x01,
35
+ },
36
+ stokenet: {
37
+ gatewayUrl: "https://stokenet.radixdlt.com",
38
+ networkId: 0x02,
39
+ },
40
+ localnet: {
41
+ gatewayUrl: "http://localhost:8080",
42
+ networkId: 0xf2,
43
+ },
44
+ };
45
+ class AgentWallet {
46
+ constructor(config) {
47
+ const network = config.network ?? "mainnet";
48
+ if (!NETWORK_CONFIG[network]) {
49
+ throw new Error(`[AgentWallet] Invalid network "${network}". Valid options: mainnet, stokenet, localnet`);
50
+ }
51
+ this.config = { ...config, network };
52
+ this.networkConfig = NETWORK_CONFIG[network];
53
+ this.assetAddresses = ASSET_ADDRESSES[network];
54
+ this.activeOrders = new Map();
55
+ this.customAssets = new Map();
56
+ if (config.aggrConfig) {
57
+ this.aggrClient = new AGGRClient_1.AGGRClient(config.aggrConfig);
58
+ }
59
+ if (config.privateKey) {
60
+ this.radixClient = new RadixClient_1.RadixClient(config.privateKey, this.networkConfig);
61
+ }
62
+ else {
63
+ this.radixClient = RadixClient_1.RadixClient.fromKeystore(this.networkConfig);
64
+ }
65
+ }
66
+ async checkFunds() {
67
+ try {
68
+ const config = await this.getConfig();
69
+ const balance = await this.getBalance();
70
+ const warnings = [];
71
+ const xrdBalance = balance.balances["XRD"] ?? 0;
72
+ const threshold = config.maxPerTransaction + 10;
73
+ if (xrdBalance < threshold) {
74
+ warnings.push(`Low funds in component: ${xrdBalance} XRD. Minimum recommended: ${threshold} XRD`);
75
+ }
76
+ if (warnings.length > 0 && this.config.onLowFunds) {
77
+ this.config.onLowFunds(warnings);
78
+ }
79
+ }
80
+ catch (err) {
81
+ console.error("[AgentWallet] checkFunds error:", err);
82
+ }
83
+ }
84
+ // Obtiene la dirección del resource de un asset
85
+ getAssetAddress(asset) {
86
+ // Primero busca en assets registrados por el usuario
87
+ const custom = this.customAssets.get(asset.toUpperCase());
88
+ if (custom) {
89
+ const address = custom[this.config.network];
90
+ if (address)
91
+ return address;
92
+ throw new Error(`[AgentWallet] Asset ${asset} has no address for network ${this.config.network}`);
93
+ }
94
+ // Si no encuentra busca en los assets por defecto
95
+ const defaults = ASSET_ADDRESSES[this.config.network];
96
+ const address = defaults[asset];
97
+ if (!address) {
98
+ throw new Error(`[AgentWallet] Asset ${asset} not found. Use registerAsset() to add custom assets.`);
99
+ }
100
+ return address;
101
+ }
102
+ // El usuario registra un asset custom con sus addresses por red
103
+ registerAsset(symbol, addresses) {
104
+ const upper = symbol.toUpperCase();
105
+ if (ASSET_ADDRESSES[this.config.network][upper]) {
106
+ throw new Error(`[AgentWallet] Asset ${upper} already exists as a default asset.`);
107
+ }
108
+ this.customAssets.set(upper, addresses);
109
+ console.log(`[AgentWallet] Asset ${upper} registered successfully.`);
110
+ }
111
+ // Lista todos los assets disponibles — default + custom
112
+ listAssets() {
113
+ const defaults = Object.keys(ASSET_ADDRESSES[this.config.network]);
114
+ const custom = Array.from(this.customAssets.keys());
115
+ return [...defaults, ...custom];
116
+ }
117
+ // Consulta el balance del PolicyVault
118
+ async getBalance() {
119
+ const response = await fetch(`${this.networkConfig.gatewayUrl}/state/entity/details`, {
120
+ method: "POST",
121
+ headers: { "Content-Type": "application/json" },
122
+ body: JSON.stringify({
123
+ addresses: [this.config.componentAddress],
124
+ aggregation_level: "Vault",
125
+ opt_ins: {
126
+ explicit_metadata: ["name", "symbol"]
127
+ }
128
+ }),
129
+ });
130
+ const data = await response.json();
131
+ const fungibles = data?.items?.[0]?.fungible_resources?.items || [];
132
+ const balances = {};
133
+ for (const resource of fungibles) {
134
+ const metadata = resource.explicit_metadata?.items || [];
135
+ const symbol = metadata.find((m) => m.key === "symbol")?.value?.typed?.value;
136
+ const amount = parseFloat(resource.vaults?.items?.[0]?.amount || "0");
137
+ if (symbol && amount > 0) {
138
+ balances[symbol] = amount;
139
+ }
140
+ }
141
+ return {
142
+ balances,
143
+ componentAddress: this.config.componentAddress,
144
+ timestamp: new Date(),
145
+ };
146
+ }
147
+ // Transfiere assets a una dirección — el agente presenta su badge automáticamente
148
+ async transfer(params) {
149
+ const assetAddress = this.getAssetAddress(params.asset);
150
+ const badgeLocalId = this.config.badgeLocalId ?? "#1#";
151
+ // 1. Obtener configuración actual del contrato
152
+ const config = await this.getConfig();
153
+ // 2. VALIDAR FROZEN
154
+ if (config.frozen) {
155
+ throw new Error(`[AgentWallet] Contract is frozen. No transfers allowed.`);
156
+ }
157
+ // 3. VALIDAR MULTISIG THRESHOLD PRIMERO
158
+ // Si supera el umbral del owner — necesita aprobación del owner
159
+ let manifest;
160
+ if (config.multisigThreshold && params.amount > config.multisigThreshold) {
161
+ console.log(`[AgentWallet] Amount ${params.amount} exceeds multisig threshold (${config.multisigThreshold}). Requesting owner approval...`);
162
+ await this.requestLargeTransfer({
163
+ to: params.to,
164
+ amount: params.amount,
165
+ asset: params.asset,
166
+ reason: params.reason,
167
+ });
168
+ return {
169
+ txId: "pending_owner_approval",
170
+ amount: params.amount,
171
+ asset: params.asset,
172
+ to: params.to,
173
+ reason: params.reason,
174
+ timestamp: new Date(),
175
+ success: false,
176
+ };
177
+ }
178
+ // 4. VALIDAR MAX PER TRANSACTION
179
+ // Si supera el límite del agente pero NO el del owner — rechazar
180
+ else if (params.amount > config.maxPerTransaction) {
181
+ throw new Error(`[AgentWallet] Amount ${params.amount} exceeds max per transaction (${config.maxPerTransaction}). ` +
182
+ `For larger transfers up to ${config.multisigThreshold}, owner approval is required. ` +
183
+ `Use requestOwnerApproval() instead.`);
184
+ }
185
+ // 5. TRANSFERENCIA NORMAL — dentro de los límites del agente
186
+ else {
187
+ console.log(`[AgentWallet] Amount ${params.amount} within agent limits. Normal transfer.`);
188
+ manifest = this.buildTransferManifest(params.to, assetAddress, params.amount, this.config.badgeResourceAddress, badgeLocalId);
189
+ }
190
+ // 5. Enviar la transacción
191
+ let txId;
192
+ try {
193
+ txId = await this.submitManifest(manifest);
194
+ console.log("[AgentWallet] TX submitted:", txId);
195
+ }
196
+ catch (err) {
197
+ console.error("[AgentWallet] submitManifest ERROR:", err);
198
+ throw err;
199
+ }
200
+ this.checkFunds().catch(console.error);
201
+ return {
202
+ txId,
203
+ amount: params.amount,
204
+ asset: params.asset,
205
+ to: params.to,
206
+ reason: params.reason,
207
+ timestamp: new Date(),
208
+ success: true,
209
+ };
210
+ }
211
+ // Agent need these to know the limits
212
+ async getConfig() {
213
+ try {
214
+ // Usar el endpoint correcto
215
+ const response = await fetch(`${this.networkConfig.gatewayUrl}/state/entity/details`, {
216
+ method: "POST",
217
+ headers: { "Content-Type": "application/json" },
218
+ body: JSON.stringify({
219
+ addresses: [this.config.componentAddress],
220
+ }),
221
+ });
222
+ const data = await response.json();
223
+ // Extraer los fields del state
224
+ const fields = data?.items?.[0]?.details?.state?.fields ?? [];
225
+ // Buscar los valores por field_name
226
+ let maxPerTransaction = 100;
227
+ let multisigThreshold = 500;
228
+ let dailyCap = 1000;
229
+ let frozen = false;
230
+ for (const field of fields) {
231
+ switch (field.field_name) {
232
+ case "max_per_transaction":
233
+ maxPerTransaction = parseFloat(field.value);
234
+ break;
235
+ case "multisig_threshold":
236
+ multisigThreshold = parseFloat(field.value);
237
+ break;
238
+ case "daily_cap":
239
+ dailyCap = parseFloat(field.value);
240
+ break;
241
+ case "frozen":
242
+ frozen = field.value === true;
243
+ break;
244
+ }
245
+ }
246
+ console.log(" ✅ Config get from agent component:");
247
+ console.log(` 📈 Max for transaction: ${maxPerTransaction}`);
248
+ console.log(` 🔐 Multisig level: ${multisigThreshold}`);
249
+ console.log(` 💰 Dairy limit: ${dailyCap}`);
250
+ console.log(` ❄️ Frozen: ${frozen}`);
251
+ return {
252
+ maxPerTransaction,
253
+ multisigThreshold,
254
+ dailyCap,
255
+ frozen,
256
+ };
257
+ }
258
+ catch (error) {
259
+ console.error("❌ Error when consult the endpoint:", error);
260
+ }
261
+ // Fallback en caso de error
262
+ return {
263
+ maxPerTransaction: 100,
264
+ multisigThreshold: 500,
265
+ dailyCap: 1000,
266
+ frozen: false,
267
+ };
268
+ }
269
+ // ─── Pending Transfer — Large TX que requiere aprobación del owner ─────────
270
+ async requestLargeTransfer(params) {
271
+ const assetAddress = this.getAssetAddress(params.asset);
272
+ const badgeLocalId = this.config.badgeLocalId ?? "#1#";
273
+ const notarizer = this.config.notarizerAddress ?? RadixClient_1.RadixClient.getAddress();
274
+ const manifest = `
275
+ CALL_METHOD
276
+ Address("${notarizer}")
277
+ "lock_fee"
278
+ Decimal("2")
279
+ ;
280
+ CALL_METHOD
281
+ Address("${this.config.componentAddress}")
282
+ "lock_fee"
283
+ Decimal("8")
284
+ ;
285
+ CALL_METHOD
286
+ Address("${notarizer}")
287
+ "create_proof_of_non_fungibles"
288
+ Address("${this.config.badgeResourceAddress}")
289
+ Array<NonFungibleLocalId>(NonFungibleLocalId("${badgeLocalId}"))
290
+ ;
291
+ POP_FROM_AUTH_ZONE
292
+ Proof("agent_proof")
293
+ ;
294
+ CALL_METHOD
295
+ Address("${this.config.componentAddress}")
296
+ "request_large_transfer"
297
+ Address("${params.to}")
298
+ Decimal("${params.amount}")
299
+ Address("${assetAddress}")
300
+ "${params.reason}"
301
+ Proof("agent_proof")
302
+ ;
303
+ `;
304
+ await this.submitManifest(manifest);
305
+ this.checkFunds().catch(console.error);
306
+ console.log(`[AgentWallet] Large transfer requested:`);
307
+ console.log(` To: ${params.to}`);
308
+ console.log(` Amount: ${params.amount} ${params.asset}`);
309
+ console.log(` Reason: ${params.reason}`);
310
+ console.log(` ⚠️ Owner approval required — check the web dashboard`);
311
+ return {
312
+ requested: true,
313
+ to: params.to,
314
+ amount: params.amount,
315
+ asset: params.asset,
316
+ reason: params.reason,
317
+ };
318
+ }
319
+ async getPendingTransfer() {
320
+ // CALL_METHOD
321
+ // Address("${this.config.agentAccountAddress}")
322
+ // "create_proof_of_amount"
323
+ // Address("${this.config.ownerBadgeAddress}")
324
+ // Decimal("1")
325
+ // ;
326
+ const manifest = `
327
+ CALL_METHOD
328
+ Address("${this.config.componentAddress}")
329
+ "get_pending_transfer"
330
+ ;
331
+ `;
332
+ const response = await fetch(`${this.networkConfig.gatewayUrl}/transaction/preview`, {
333
+ method: "POST",
334
+ headers: { "Content-Type": "application/json" },
335
+ body: JSON.stringify({
336
+ manifest,
337
+ start_epoch_inclusive: 1,
338
+ end_epoch_exclusive: 100,
339
+ nonce: 1,
340
+ signer_public_keys: [],
341
+ notary_public_key: {
342
+ key_type: "EddsaEd25519",
343
+ key_hex: "0000000000000000000000000000000000000000000000000000000000000001"
344
+ },
345
+ notary_is_signatory: true,
346
+ tip_percentage: 0,
347
+ flags: {
348
+ use_free_credit: true,
349
+ assume_all_signature_proofs: true,
350
+ skip_epoch_check: true
351
+ }
352
+ })
353
+ });
354
+ const data = await response.json();
355
+ //const output = data?.receipt?.output?.[1]?.programmatic_json;
356
+ const output = data?.receipt?.output?.[0]?.programmatic_json;
357
+ // variant_id "0" = None, "1" = Some
358
+ if (!output || output.variant_id === "0") {
359
+ return { hasPending: false };
360
+ }
361
+ const fields = output?.fields?.[0]?.fields;
362
+ return {
363
+ hasPending: true,
364
+ to: fields?.[0]?.value,
365
+ amount: fields?.[1]?.value,
366
+ asset: fields?.[2]?.value,
367
+ reason: fields?.[3]?.value,
368
+ requestedAtEpoch: fields?.[4]?.value,
369
+ };
370
+ }
371
+ //Ejecuta un swap a través del AGGR
372
+ async swap(params) {
373
+ if (!this.aggrClient) {
374
+ throw new Error("[AgentWallet] AGGR not configured. Pass aggrConfig to use swap.");
375
+ }
376
+ const fromAddress = this.getAssetAddress(params.fromAsset);
377
+ const toAddress = this.getAssetAddress(params.toAsset);
378
+ const badgeLocalId = this.config.badgeLocalId ?? "#1#";
379
+ // Descuentamos el fee del PolicyVault (0.1%) antes de llamar al AGGR
380
+ // para que el monto que llega al AGGR sea el real disponible
381
+ const FEE_RATE = 0.001;
382
+ const adjustedAmount = params.amount * (1 - FEE_RATE);
383
+ // Llamamos al AGGR con el monto ajustado y el PolicyVault como fromAddress
384
+ const quote = await this.aggrClient.getSwapQuote(fromAddress, toAddress, adjustedAmount, this.config.componentAddress);
385
+ // VERSION MOCK
386
+ //console.log("=== AGGR MANIFEST RAW ===");
387
+ //console.log(quote.manifest);
388
+ if (this.config.aggrConfig?.mockMode) {
389
+ console.log("[AgentWallet] SWAP MOCK — simulando resultado sin TX");
390
+ return {
391
+ txId: "mock_swap_" + Date.now(),
392
+ fromAsset: params.fromAsset,
393
+ toAsset: params.toAsset,
394
+ amountIn: params.amount,
395
+ amountOut: quote.outputTokens,
396
+ executedPrice: quote.outputTokens / params.amount,
397
+ reason: params.reason,
398
+ timestamp: new Date(),
399
+ success: true,
400
+ };
401
+ }
402
+ // FIN MOCK
403
+ const aggrManifest = quote.manifest;
404
+ //
405
+ const withdrawPattern = /CALL_METHOD\s+Address\("[^"]+"\)\s+"withdraw"[^;]+;/;
406
+ const manifestWithoutWithdraw = aggrManifest.replace(withdrawPattern, "");
407
+ const notarizer = this.config.notarizerAddress ?? RadixClient_1.RadixClient.getAddress();
408
+ // Construimos el resto manifiesto
409
+ const manifest = `
410
+ CALL_METHOD
411
+ Address("${notarizer}")
412
+ "lock_fee"
413
+ Decimal("10")
414
+ ;
415
+ CALL_METHOD
416
+ Address("${this.config.componentAddress}")
417
+ "lock_fee"
418
+ Decimal("8")
419
+ ;
420
+ CALL_METHOD
421
+ Address("${notarizer}")
422
+ "create_proof_of_non_fungibles"
423
+ Address("${this.config.badgeResourceAddress}")
424
+ Array<NonFungibleLocalId>(NonFungibleLocalId("${badgeLocalId}"))
425
+ ;
426
+ POP_FROM_AUTH_ZONE
427
+ Proof("agent_proof")
428
+ ;
429
+ CALL_METHOD
430
+ Address("${this.config.componentAddress}")
431
+ "transfer"
432
+ Address("${this.config.componentAddress}")
433
+ Decimal("${params.amount}")
434
+ Address("${fromAddress}")
435
+ "swap ${params.fromAsset} to ${params.toAsset}"
436
+ Proof("agent_proof")
437
+ ;
438
+ ${manifestWithoutWithdraw}
439
+ `;
440
+ const txId = await this.submitManifest(manifest);
441
+ this.checkFunds().catch(console.error);
442
+ return {
443
+ txId,
444
+ fromAsset: params.fromAsset,
445
+ toAsset: params.toAsset,
446
+ amountIn: params.amount,
447
+ amountOut: quote.outputTokens,
448
+ executedPrice: quote.outputTokens / params.amount,
449
+ reason: params.reason,
450
+ timestamp: new Date(),
451
+ success: true,
452
+ };
453
+ }
454
+ // Crea una orden condicional — ejecuta cuando se cumple el precio trigger
455
+ async createConditionalOrder(order) {
456
+ if (!this.aggrClient) {
457
+ throw new Error("[AgentWallet] AGGR not configured. Pass aggrConfig to use conditional orders.");
458
+ }
459
+ const orderId = `order_${Date.now()}`;
460
+ const fromAddress = this.getAssetAddress(order.asset);
461
+ const toAddress = this.getAssetAddress(order.againstAsset);
462
+ const cancelWatch = await this.aggrClient.watchPrice(fromAddress, toAddress, order.amount, this.config.componentAddress, order.triggerPrice, order.condition, 5000, async (quote) => {
463
+ console.log(`[AgentWallet] Order ${orderId} triggered at price ${quote.outputTokens / order.amount}`);
464
+ // Cancela el monitor antes de ejecutar
465
+ this.cancelOrder(orderId);
466
+ // Mock — no ejecutar swap real
467
+ if (this.config.aggrConfig?.mockMode) {
468
+ console.log(`[AgentWallet] MOCK order ${orderId} triggered`);
469
+ return;
470
+ }
471
+ // FIN MOCK
472
+ await this.swap({
473
+ fromAsset: order.asset,
474
+ toAsset: order.againstAsset,
475
+ amount: order.amount,
476
+ maxSlippage: order.maxSlippage,
477
+ reason: `conditional order ${orderId} triggered at price ${quote.outputTokens / order.amount}`,
478
+ });
479
+ });
480
+ // Guardamos la función de cancelación
481
+ this.activeOrders.set(orderId, cancelWatch);
482
+ return orderId;
483
+ }
484
+ // Cancela una orden condicional activa
485
+ cancelOrder(orderId) {
486
+ const cancel = this.activeOrders.get(orderId);
487
+ if (cancel) {
488
+ cancel();
489
+ this.activeOrders.delete(orderId);
490
+ return true;
491
+ }
492
+ return false;
493
+ }
494
+ // Lista las órdenes activas
495
+ listActiveOrders() {
496
+ return Array.from(this.activeOrders.keys());
497
+ }
498
+ // Construye el manifiesto de transferencia desde el PolicyVault
499
+ buildTransferManifest(to, assetAddress, amount, badgeResourceAddress, badgeLocalId = "#1#") {
500
+ const notarizer = this.config.notarizerAddress ?? RadixClient_1.RadixClient.getAddress();
501
+ return `
502
+ CALL_METHOD
503
+ Address("${notarizer}")
504
+ "lock_fee"
505
+ Decimal("2")
506
+ ;
507
+ CALL_METHOD
508
+ Address("${this.config.componentAddress}")
509
+ "lock_fee"
510
+ Decimal("8")
511
+ ;
512
+ CALL_METHOD
513
+ Address("${notarizer}")
514
+ "create_proof_of_non_fungibles"
515
+ Address("${badgeResourceAddress}")
516
+ Array<NonFungibleLocalId>(NonFungibleLocalId("${badgeLocalId}"))
517
+ ;
518
+ POP_FROM_AUTH_ZONE
519
+ Proof("agent_proof")
520
+ ;
521
+ CALL_METHOD
522
+ Address("${this.config.componentAddress}")
523
+ "transfer"
524
+ Address("${to}")
525
+ Decimal("${amount}")
526
+ Address("${assetAddress}")
527
+ "transfer"
528
+ Proof("agent_proof")
529
+ ;
530
+ CALL_METHOD
531
+ Address("${to}")
532
+ "try_deposit_batch_or_abort"
533
+ Expression("ENTIRE_WORKTOP")
534
+ None
535
+ ;`;
536
+ }
537
+ // Firma y envía un manifiesto a la red Radix
538
+ async submitManifest(manifest) {
539
+ return await this.radixClient.submitManifest(manifest);
540
+ }
541
+ waitForOwnerApproval(pendingDetails, intervalMs = 30000) {
542
+ let active = true;
543
+ let fromStateVersion = 0;
544
+ // Obtener state_version actual antes de arrancar el polling
545
+ const init = async () => {
546
+ try {
547
+ const response = await fetch(`${this.networkConfig.gatewayUrl}/stream/transactions`, {
548
+ method: "POST",
549
+ headers: { "Content-Type": "application/json" },
550
+ body: JSON.stringify({
551
+ affected_global_entities_filter: [this.config.componentAddress],
552
+ limit_per_page: 1,
553
+ order: "Desc",
554
+ })
555
+ });
556
+ const data = await response.json();
557
+ fromStateVersion = data?.items?.[0]?.state_version ?? 0;
558
+ console.log(`[AgentWallet] waitForOwnerApproval — starting from state_version: ${fromStateVersion}`);
559
+ }
560
+ catch (err) {
561
+ console.error("[AgentWallet] waitForOwnerApproval init error:", err);
562
+ }
563
+ setTimeout(checkResult, intervalMs);
564
+ };
565
+ const checkResult = async () => {
566
+ if (!active)
567
+ return;
568
+ try {
569
+ const response = await fetch(`${this.networkConfig.gatewayUrl}/stream/transactions`, {
570
+ method: "POST",
571
+ headers: { "Content-Type": "application/json" },
572
+ body: JSON.stringify({
573
+ affected_global_entities_filter: [this.config.componentAddress],
574
+ limit_per_page: 10,
575
+ order: "Desc",
576
+ opt_ins: { manifest_instructions: true }
577
+ })
578
+ });
579
+ const data = await response.json();
580
+ const items = data?.items || [];
581
+ // Solo mirar TXs posteriores al inicio del polling
582
+ const newItems = items.filter((tx) => tx.state_version > fromStateVersion);
583
+ for (const tx of newItems) {
584
+ const instructions = tx.manifest_instructions || "";
585
+ if (instructions.includes("approve_transfer")) {
586
+ active = false;
587
+ this.config.onTransferApproved?.(pendingDetails);
588
+ return;
589
+ }
590
+ if (instructions.includes("reject_transfer")) {
591
+ active = false;
592
+ this.config.onTransferRejected?.(pendingDetails);
593
+ return;
594
+ }
595
+ }
596
+ }
597
+ catch (err) {
598
+ console.error("[AgentWallet] waitForOwnerApproval error:", err);
599
+ }
600
+ if (active)
601
+ setTimeout(checkResult, intervalMs);
602
+ };
603
+ init();
604
+ return () => { active = false; };
605
+ }
606
+ async getWhitelist() {
607
+ const manifest = `
608
+ CALL_METHOD
609
+ Address("${this.config.componentAddress}")
610
+ "get_whitelist"
611
+ ;
612
+ `;
613
+ const response = await fetch(`${this.networkConfig.gatewayUrl}/transaction/preview`, {
614
+ method: "POST",
615
+ headers: { "Content-Type": "application/json" },
616
+ body: JSON.stringify({
617
+ manifest,
618
+ start_epoch_inclusive: 1,
619
+ end_epoch_exclusive: 100,
620
+ nonce: 1,
621
+ signer_public_keys: [],
622
+ notary_public_key: {
623
+ key_type: "EddsaEd25519",
624
+ key_hex: "0000000000000000000000000000000000000000000000000000000000000001"
625
+ },
626
+ notary_is_signatory: true,
627
+ tip_percentage: 0,
628
+ flags: {
629
+ use_free_credit: true,
630
+ assume_all_signature_proofs: true,
631
+ skip_epoch_check: true
632
+ }
633
+ })
634
+ });
635
+ const data = await response.json();
636
+ const output = data?.receipt?.output?.[0]?.programmatic_json;
637
+ if (!output || !output.elements)
638
+ return [];
639
+ return output.elements.map((item) => ({
640
+ name: item.fields?.[0]?.value ?? "",
641
+ address: item.fields?.[1]?.value ?? "",
642
+ }));
643
+ }
644
+ async getSwapQuote(fromAsset, toAsset, amount) {
645
+ if (!this.aggrClient) {
646
+ throw new Error("[AgentWallet] AGGR not configured. Pass aggrConfig to use swap quotes.");
647
+ }
648
+ const fromAddress = this.getAssetAddress(fromAsset);
649
+ const toAddress = this.getAssetAddress(toAsset);
650
+ const quote = await this.aggrClient.getSwapQuote(fromAddress, toAddress, amount, this.config.componentAddress);
651
+ return {
652
+ outputTokens: quote.outputTokens,
653
+ price: quote.outputTokens / amount,
654
+ };
655
+ }
656
+ }
657
+ exports.AgentWallet = AgentWallet;
658
+ //# sourceMappingURL=AgentWallet.js.map