-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add bridge monitor example #9
Conversation
const handler: (bridgeMonitorService: BridgeMonitorService) => Handler = | ||
() => async (_runtime, _message, _state, _options, callback) => { | ||
try { | ||
callback?.({ | ||
text: "The IQ bridge monitor is running and automatically funding users who bridge IQ tokens to Fraxtal. It monitors the L1 Standard Bridge (0x34c0bd5877a5ee7099d0f5688d65f4bb9158bde2) for deposits of 1500+ IQ tokens and sends 0.0001 ETH to users who need it.", | ||
}); | ||
return true; | ||
} catch (error) { | ||
callback?.({ | ||
text: `❌ Error with bridge monitor: ${(error as Error).message}`, | ||
}); | ||
return false; | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this, I think instead of using action, you can create a service and have a cron job running to check for transactions and fund user wallets automatically. I think a heartbeat is not needed for this as it's not very dependent on LLM making decisions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.

"dependencies": { | ||
"@elizaos/adapter-sqlite": "0.1.9", | ||
"@elizaos/client-direct": "0.1.9", | ||
"@elizaos/core": "0.1.9", | ||
"@elizaos/plugin-bootstrap": "0.1.9", | ||
"@iqai/agent": "^0.0.5", | ||
"@iqai/plugin-atp": "^0.1.9", | ||
"@iqai/plugin-heartbeat": "^0.1.10", | ||
"@iqai/plugin-sequencer": "^0.1.10", | ||
"@types/better-sqlite3": "^7.6.12", | ||
"better-sqlite3": "11.8.1", | ||
"dedent": "^1.5.3", | ||
"dotenv": "^16.4.7", | ||
"sharp": "^0.33.5", | ||
"viem": "^2.23.3" | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we don't need database adapter, direct client, atp and heartbeat if you are directly using service
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okkk, perhaps its needed for bridge status action
const bridgeMonitorService = new BridgeMonitorService(opts.funderPrivateKey); | ||
|
||
try { | ||
await bridgeMonitorService.startMonitoring(); | ||
elizaLogger.info("🚀 IQ Bridge Monitor started successfully"); | ||
} catch (error) { | ||
elizaLogger.error("❌ Failed to start IQ Bridge Monitor", { error }); | ||
throw error; | ||
} | ||
|
||
return { | ||
name: "IQ Bridge Monitor", | ||
description: | ||
"Monitors IQ token bridge transactions and automatically funds Fraxtal addresses with ETH", | ||
providers: [], | ||
evaluators: [], | ||
services: [], | ||
actions: [getBridgeStatusAction(bridgeMonitorService)], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually i think you can send BridgeMonitorService service inside services: []
This would also allow you to access the service inside the actions without passing to it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried to use runtime to pass access service inside actions using
const bridgeMonitorService = runtime.getService<BridgeMonitorService>("MY_SERVICE")
But getService Only accepts an enum members from @eliza/core
ServiceType
which has predefined official services like evm, image gen etc.
reference
|
||
if (config?.fundingAmount) this.fundingAmount = config.fundingAmount; | ||
if (config?.minIQThreshold) this.minIQThreshold = config.minIQThreshold; | ||
if (config?.checkIntervalMs) this.checkIntervalMs = config.checkIntervalMs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are we using this checkIntervalMs
? cuz i can see you are tracking events by using watchContractEvent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh forgot to update, you can specify the interval for watchContract
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh thats cool
} | ||
}; | ||
|
||
// Initial attempt | ||
let success = await attemptFunding(); | ||
|
||
// Retry logic with exponential backoff | ||
while (!success && retryCount < this.maxRetries) { | ||
retryCount++; | ||
elizaLogger.info(`Retrying funding (attempt ${retryCount}/${this.maxRetries}) in ${backoffMs}ms...`); | ||
|
||
// Wait with exponential backoff | ||
await new Promise(resolve => setTimeout(resolve, backoffMs)); | ||
backoffMs *= 2; // Exponential backoff | ||
|
||
success = await attemptFunding(); | ||
} | ||
|
||
if (!success && retryCount >= this.maxRetries) { | ||
elizaLogger.error(`Failed to fund ${userAddress} after ${this.maxRetries} attempts`); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can abstract this retry logic to its own function
abi: BRIDGE_EVENT_ABI, | ||
eventName: "ERC20BridgeInitiated", | ||
onLogs: (logs) => this.handleBridgeEvents(logs), | ||
pollingInterval: this.checkIntervalMs, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should use the heartbeat, we need to use it our own plugins to show how they work
ModelProviderName.OPENAI, | ||
process.env.OPENAI_API_KEY as string, | ||
) | ||
.withPlugins([bootstrapPlugin, iqBridgeMonitorPlugin]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need bootstrap plugin?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Included for bridge control (start/stop) via chat
username: "brainbot", | ||
messageExamples: [], | ||
lore: [], | ||
style: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to always define this? Example would look cleaner without all this unused metadata.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup we don't need for this agent
Agent to listen to IQ ETH_FRAXTAL bridge transactions
closes https://github.com/IQAIcom/issues/issues/65