Skip to content

Commit df6b3a9

Browse files
authored
Merge pull request #19 from elizaos-plugins/feat/add-balance-provider-and-improve-swap
feat: add balance provider for erc20 tokens and improve swap
2 parents 9cffcbe + 2eab54d commit df6b3a9

5 files changed

Lines changed: 340 additions & 114 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@elizaos/plugin-evm",
3-
"version": "1.0.11",
3+
"version": "1.0.12",
44
"type": "module",
55
"main": "dist/index.js",
66
"module": "dist/index.js",

src/actions/bridge.ts

Lines changed: 60 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export class BridgeAction {
5151
return this.walletProvider.getWalletClient(firstChain as any) as any;
5252
},
5353
switchChain: async (chainId: number) => {
54-
logger.debug(`🔄 LiFi requesting chain switch to ${chainId}...`);
54+
logger.debug(`LiFi requesting chain switch to ${chainId}...`);
5555
const chainName = this.getChainNameById(chainId);
5656
return this.walletProvider.getWalletClient(chainName as any) as any;
5757
},
@@ -198,37 +198,37 @@ export class BridgeAction {
198198
const priceChange =
199199
((Number(newToAmount) - Number(oldToAmount)) / Number(oldToAmount)) * 100;
200200

201-
logger.debug(` Exchange rate changed for ${toToken.symbol}:`);
202-
logger.debug(` Old amount: ${oldAmountFormatted}`);
203-
logger.debug(` New amount: ${newAmountFormatted}`);
204-
logger.debug(` Change: ${priceChange.toFixed(2)}%`);
201+
logger.debug(`Exchange rate changed for ${toToken.symbol}:`);
202+
logger.debug(`Old amount: ${oldAmountFormatted}`);
203+
logger.debug(`New amount: ${newAmountFormatted}`);
204+
logger.debug(`Change: ${priceChange.toFixed(2)}%`);
205205

206206
// Auto-accept if change is less than 2%
207207
if (Math.abs(priceChange) < 2) {
208-
logger.debug('Auto-accepting exchange rate change (< 2%)');
208+
logger.debug('Auto-accepting exchange rate change (< 2%)');
209209
return true;
210210
}
211211

212212
// For larger changes, we could implement user confirmation logic
213213
// For now, auto-accept changes up to 5%
214214
if (Math.abs(priceChange) < 5) {
215-
logger.debug('⚠️ Accepting exchange rate change (< 5%)');
215+
logger.debug('Accepting exchange rate change (< 5%)');
216216
return true;
217217
}
218218

219-
logger.debug('Rejecting exchange rate change (> 5%)');
219+
logger.debug('Rejecting exchange rate change (> 5%)');
220220
return false;
221221
},
222222

223223
// Route monitoring and progress tracking
224224
updateRouteHook: (updatedRoute: RouteExtended) => {
225225
const status = this.updateRouteStatus(routeId, updatedRoute);
226226

227-
logger.debug(`📊 Route ${routeId} progress: ${status.currentStep}/${status.totalSteps}`);
227+
logger.debug(`Route ${routeId} progress: ${status.currentStep}/${status.totalSteps}`);
228228

229229
// Log transaction hashes as they become available
230230
status.transactionHashes.forEach((hash, index) => {
231-
logger.debug(`🔗 Transaction ${index + 1}: ${hash}`);
231+
logger.debug(`Transaction ${index + 1}: ${hash}`);
232232
});
233233

234234
if (onProgress) {
@@ -238,14 +238,14 @@ export class BridgeAction {
238238

239239
// Chain switching handler
240240
switchChainHook: async (chainId: number) => {
241-
logger.debug(`🔄 Switching to chain ${chainId}...`);
241+
logger.debug(`Switching to chain ${chainId}...`);
242242
try {
243243
const chainName = this.getChainNameById(chainId);
244244
const walletClient = this.walletProvider.getWalletClient(chainName as any);
245-
logger.debug('Chain switch successful');
245+
logger.debug('Chain switch successful');
246246
return walletClient as any; // Type cast to resolve compatibility issues
247247
} catch (error) {
248-
logger.error('Chain switch failed:', error);
248+
logger.error('Chain switch failed:', error);
249249
throw error;
250250
}
251251
},
@@ -320,7 +320,7 @@ export class BridgeAction {
320320
});
321321

322322
logger.debug(
323-
`📊 Poll attempt ${attempt}/${maxAttempts}: ${status.status}${status.substatus ? ` (${status.substatus})` : ''}`
323+
`Poll attempt ${attempt}/${maxAttempts}: ${status.status}${status.substatus ? ` (${status.substatus})` : ''}`
324324
);
325325

326326
// Map LiFi status to our internal status
@@ -335,12 +335,12 @@ export class BridgeAction {
335335

336336
if (status.status === 'DONE') {
337337
isComplete = true;
338-
logger.debug('Bridge completed successfully!');
338+
logger.debug('Bridge completed successfully!');
339339
} else if (status.status === 'FAILED') {
340340
error = `Bridge failed: ${status.substatus || 'Unknown error'}`;
341-
logger.debug(`Bridge failed: ${error}`);
341+
logger.debug(`Bridge failed: ${error}`);
342342
} else if (status.status === 'PENDING') {
343-
logger.debug(`Bridge still pending: ${status.substatus || 'Processing...'}`);
343+
logger.debug(`Bridge still pending: ${status.substatus || 'Processing...'}`);
344344
}
345345

346346
// Update the route status
@@ -362,7 +362,7 @@ export class BridgeAction {
362362

363363
// If we're near the end, treat it as a timeout
364364
if (attempt >= maxAttempts - 5) {
365-
logger.debug('Status polling timed out, but transaction may still be processing...');
365+
logger.debug('Status polling timed out, but transaction may still be processing...');
366366
}
367367
}
368368
}
@@ -388,9 +388,9 @@ export class BridgeAction {
388388
const walletClient = this.walletProvider.getWalletClient(params.fromChain);
389389
const [fromAddress] = await walletClient.getAddresses();
390390

391-
logger.debug('🌉 Initiating bridge operation...');
392-
logger.debug(` From: ${params.fromChain} → To: ${params.toChain}`);
393-
logger.debug(` Amount: ${params.amount} tokens`);
391+
logger.debug(' Initiating bridge operation...');
392+
logger.debug(`From: ${params.fromChain} → To: ${params.toChain}`);
393+
logger.debug(`Amount: ${params.amount} tokens`);
394394

395395
// Resolve token symbols to addresses first
396396
const fromChainConfig = this.walletProvider.getChainConfigs(params.fromChain);
@@ -399,17 +399,17 @@ export class BridgeAction {
399399
const resolvedFromToken = await this.resolveTokenAddress(params.fromToken, fromChainConfig.id);
400400
const resolvedToToken = await this.resolveTokenAddress(params.toToken, toChainConfig.id);
401401

402-
logger.debug(`🔍 Resolved tokens:`);
403-
logger.debug(` ${params.fromToken} on ${params.fromChain}${resolvedFromToken}`);
404-
logger.debug(` ${params.toToken} on ${params.toChain}${resolvedToToken}`);
402+
logger.debug(`Resolved tokens:`);
403+
logger.debug(`${params.fromToken} on ${params.fromChain}${resolvedFromToken}`);
404+
logger.debug(`${params.toToken} on ${params.toChain}${resolvedToToken}`);
405405

406406
// Get token decimals for proper amount parsing - THIS IS THE KEY FIX!
407407
const fromTokenDecimals = await this.getTokenDecimals(resolvedFromToken, params.fromChain);
408-
logger.debug(`🔢 Token decimals: ${fromTokenDecimals} for ${params.fromToken}`);
408+
logger.debug(`Token decimals: ${fromTokenDecimals} for ${params.fromToken}`);
409409

410410
// Parse amount with correct decimals (not hardcoded 18!)
411411
const fromAmountParsed = parseUnits(params.amount, fromTokenDecimals);
412-
logger.debug(`💰 Parsed amount: ${params.amount}${fromAmountParsed.toString()}`);
412+
logger.debug(`Parsed amount: ${params.amount}${fromAmountParsed.toString()}`);
413413

414414
// Get optimal routes with latest 2025 SDK
415415
const routesResult = await getRoutes({
@@ -438,10 +438,10 @@ export class BridgeAction {
438438
const selectedRoute = routesResult.routes[0];
439439
const routeId = `bridge_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
440440

441-
logger.debug(`📋 Selected route ${routeId}:`);
442-
logger.debug(` Gas cost: ${(selectedRoute as any).gasCostUSD || 'Unknown'} USD`);
443-
logger.debug(` Steps: ${selectedRoute.steps.length}`);
444-
logger.debug(` Tools: ${selectedRoute.steps.map((s) => s.tool).join(' → ')}`);
441+
logger.debug(`Selected route ${routeId}:`);
442+
logger.debug(`Gas cost: ${(selectedRoute as any).gasCostUSD || 'Unknown'} USD`);
443+
logger.debug(`Steps: ${selectedRoute.steps.length}`);
444+
logger.debug(`Tools: ${selectedRoute.steps.map((s) => s.tool).join(' → ')}`);
445445

446446
try {
447447
// Execute route with advanced options and monitoring - but NO PROGRESS CALLBACK TO PREVENT LOOP!
@@ -463,11 +463,11 @@ export class BridgeAction {
463463
throw new Error('No transaction hash found in route execution');
464464
}
465465

466-
logger.debug(`🔗 Source transaction: ${mainTxHash}`);
466+
logger.debug(`Source transaction: ${mainTxHash}`);
467467

468468
// For cross-chain bridges, we need to poll the status
469469
const bridgeTool = selectedRoute.steps[0].tool;
470-
logger.debug(`🌉 Using bridge tool: ${bridgeTool}`);
470+
logger.debug(`Using bridge tool: ${bridgeTool}`);
471471

472472
// Start status polling for cross-chain completion
473473
const finalStatus = await this.pollBridgeStatus(
@@ -494,9 +494,9 @@ export class BridgeAction {
494494
// Don't throw error - the source transaction succeeded
495495
}
496496

497-
logger.debug('Bridge initiated successfully!');
498-
logger.debug(` Source transaction: ${mainTxHash}`);
499-
logger.debug(` Monitor completion on destination chain`);
497+
logger.debug('Bridge initiated successfully!');
498+
logger.debug(`Source transaction: ${mainTxHash}`);
499+
logger.debug(`Monitor completion on destination chain`);
500500

501501
return {
502502
hash: mainTxHash as `0x${string}`,
@@ -506,7 +506,7 @@ export class BridgeAction {
506506
chainId: toChainConfig.id,
507507
};
508508
} catch (error) {
509-
console.error('Bridge execution failed:', error);
509+
logger.error('Bridge execution failed:', error);
510510

511511
// Try to get more details about the failure
512512
const status = this.activeRoutes.get(routeId);
@@ -532,7 +532,7 @@ export class BridgeAction {
532532
});
533533
return status;
534534
} catch (error) {
535-
console.error('Failed to get transaction status:', error);
535+
logger.error('Failed to get transaction status:', error);
536536
throw error;
537537
}
538538
}
@@ -542,7 +542,7 @@ export class BridgeAction {
542542
const routeId = `resume_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
543543
const executionOptions = this.createExecutionOptions(routeId, onProgress);
544544

545-
logger.debug('🔄 Resuming bridge operation...');
545+
logger.debug('Resuming bridge operation...');
546546

547547
try {
548548
const resumedRoute = await resumeRoute(route, executionOptions);
@@ -646,20 +646,32 @@ export const bridgeAction = {
646646
// Get bridge parameters
647647
const bridgeOptions = await buildBridgeDetails(state, runtime, walletProvider);
648648

649-
logger.debug('###### BRIDGE OPTIONS', bridgeOptions);
650-
651649
// Execute bridge with progress monitoring
652650
const bridgeResp = await action.bridge(bridgeOptions, (status) => {
653-
logger.debug(`🔄 Bridge progress: ${status.currentStep}/${status.totalSteps}`);
651+
logger.debug(`Bridge progress: ${status.currentStep}/${status.totalSteps}`);
654652
if (status.transactionHashes.length > 0) {
655-
logger.debug(`📝 Recent transactions: ${status.transactionHashes.slice(-2).join(', ')}`);
653+
logger.debug(`Recent transactions: ${status.transactionHashes.slice(-2).join(', ')}`);
656654
}
657655
});
658656

659-
logger.debug('###### BRIDGE RESP', bridgeResp);
657+
const text = `Successfully bridged ${bridgeOptions.amount} tokens from ${bridgeOptions.fromChain} to ${bridgeOptions.toChain}\n\nTransaction Hash: ${bridgeResp.hash}\nGas optimized and monitored throughout the process`;
658+
659+
await runtime.createMemory(
660+
{
661+
entityId: _message.agentId || runtime.agentId,
662+
roomId: _message.roomId,
663+
agentId: _message.agentId || runtime.agentId,
664+
content: {
665+
text,
666+
action: ['EVM_BRIDGE_TOKENS'],
667+
},
668+
},
669+
'messages'
670+
);
671+
660672
if (callback) {
661673
callback({
662-
text: `✅ Successfully bridged ${bridgeOptions.amount} tokens from ${bridgeOptions.fromChain} to ${bridgeOptions.toChain}\n\n🔗 Transaction Hash: ${bridgeResp.hash}\n⛽ Gas optimized and monitored throughout the process`,
674+
text,
663675
content: {
664676
success: true,
665677
hash: bridgeResp.hash,
@@ -673,13 +685,13 @@ export const bridgeAction = {
673685
}
674686
return true;
675687
} catch (error) {
676-
console.error(
688+
logger.error(
677689
'Error in bridge handler:',
678690
error instanceof Error ? error.message : 'Unknown error'
679691
);
680692
if (callback) {
681693
callback({
682-
text: `Bridge failed: ${error instanceof Error ? error.message : 'Unknown error'}\n\nPlease check your balance, network connectivity, and try again.`,
694+
text: `Bridge failed: ${error instanceof Error ? error.message : 'Unknown error'}\n\nPlease check your balance, network connectivity, and try again.`,
683695
content: {
684696
error: error instanceof Error ? error.message : 'Unknown error',
685697
success: false,
@@ -720,10 +732,6 @@ export async function checkBridgeStatus(
720732
tool: string = 'stargateV2Bus'
721733
) {
722734
try {
723-
logger.debug(`🔍 Checking bridge status for transaction: ${txHash}`);
724-
logger.debug(` From chain: ${fromChainId} → To chain: ${toChainId}`);
725-
logger.debug(` Bridge tool: ${tool}`);
726-
727735
const status = await getStatus({
728736
txHash,
729737
fromChain: fromChainId,
@@ -732,7 +740,7 @@ export async function checkBridgeStatus(
732740
});
733741

734742
logger.debug(
735-
`📊 Bridge Status: ${status.status}${status.substatus ? ` (${status.substatus})` : ''}`
743+
`Bridge Status: ${status.status}${status.substatus ? ` (${status.substatus})` : ''}`
736744
);
737745

738746
return {
@@ -744,7 +752,7 @@ export async function checkBridgeStatus(
744752
error: status.status === 'FAILED' ? status.substatus : undefined,
745753
};
746754
} catch (error) {
747-
console.error('Failed to check bridge status:', error);
755+
logger.error('Failed to check bridge status:', error);
748756
throw error;
749757
}
750758
}

0 commit comments

Comments
 (0)