Skip to content
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

Merged
merged 7 commits into from
Mar 12, 2025
Merged

add bridge monitor example #9

merged 7 commits into from
Mar 12, 2025

Conversation

SidharthK2
Copy link
Contributor

Agent to listen to IQ ETH_FRAXTAL bridge transactions

  • Checks if l1 token is IQ and amount sent is over 1500 tokens
  • If user has below 0.001 frxEth, top up balance

closes https://github.com/IQAIcom/issues/issues/65

Comment on lines 17 to 30
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;
}
};
Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense

Copy link
Contributor Author

@SidharthK2 SidharthK2 Mar 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image (used previous blocks to test) @Royal-lobster

Comment on lines +14 to +29
"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"
},
Copy link
Member

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

Copy link
Member

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

Comment on lines 14 to 31
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)],
Copy link
Member

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

Copy link
Contributor Author

@SidharthK2 SidharthK2 Mar 12, 2025

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;
Copy link
Member

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

Copy link
Contributor Author

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

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh thats cool

Comment on lines 282 to 303
}
};

// 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`);
}
}
Copy link
Member

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

@SidharthK2 SidharthK2 merged commit 001ef36 into main Mar 12, 2025
@SidharthK2 SidharthK2 deleted the bridge-example branch March 12, 2025 11:11
abi: BRIDGE_EVENT_ABI,
eventName: "ERC20BridgeInitiated",
onLogs: (logs) => this.handleBridgeEvents(logs),
pollingInterval: this.checkIntervalMs,
Copy link
Member

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])
Copy link
Member

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?

Copy link
Contributor Author

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: {
Copy link
Member

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.

Copy link
Contributor Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants