63 lines
2.3 KiB
JavaScript
63 lines
2.3 KiB
JavaScript
/**
|
|
* Etherlink custom relay: monitor source for messages to 42793, queue, call EtherlinkRelayReceiver.relayMintOrUnlock.
|
|
* When CCIP does not support Etherlink. See docs/bridge/ETHERLINK_RELAY_RUNBOOK.md.
|
|
*/
|
|
import { ethers } from 'ethers';
|
|
import { config } from './config.js';
|
|
import { EtherlinkRelayReceiverABI } from './abis.js';
|
|
import * as metrics from './metrics.js';
|
|
|
|
export class EtherlinkRelayService {
|
|
constructor(logger) {
|
|
this.logger = logger;
|
|
this.queue = [];
|
|
this.inFlight = 0;
|
|
}
|
|
|
|
async start() {
|
|
if (!config.etherlinkRelayBridge) {
|
|
throw new Error('ETHERLINK_RELAY_BRIDGE required');
|
|
}
|
|
if (!config.relayPrivateKey) {
|
|
throw new Error('ETHERLINK_RELAY_PRIVATE_KEY or PRIVATE_KEY required');
|
|
}
|
|
this.etherlinkProvider = new ethers.JsonRpcProvider(config.etherlinkRpcUrl);
|
|
this.signer = new ethers.Wallet(config.relayPrivateKey, this.etherlinkProvider);
|
|
this.receiver = new ethers.Contract(config.etherlinkRelayBridge, EtherlinkRelayReceiverABI, this.signer);
|
|
this.logger.info('Etherlink relay started', { receiver: config.etherlinkRelayBridge });
|
|
setInterval(() => this.processQueue(), config.pollIntervalMs);
|
|
}
|
|
|
|
async pushMessage(messageId, token, recipient, amount) {
|
|
if (this.queue.length + this.inFlight >= config.queueDepthLimit) {
|
|
this.logger.warn('Queue depth limit reached', { limit: config.queueDepthLimit });
|
|
return;
|
|
}
|
|
this.queue.push({ messageId, token, recipient, amount });
|
|
metrics.incrementDetected();
|
|
metrics.setQueueDepth(this.queue.length + this.inFlight);
|
|
}
|
|
|
|
async processQueue() {
|
|
while (this.queue.length > 0 && this.inFlight < config.maxConcurrent) {
|
|
const msg = this.queue.shift();
|
|
this.inFlight++;
|
|
metrics.setQueueDepth(this.queue.length + this.inFlight);
|
|
this.submit(msg).finally(() => {
|
|
this.inFlight--;
|
|
metrics.setQueueDepth(this.queue.length + this.inFlight);
|
|
});
|
|
}
|
|
}
|
|
|
|
async submit({ messageId, token, recipient, amount }) {
|
|
try {
|
|
await this.receiver.relayMintOrUnlock(messageId, token, recipient, amount);
|
|
metrics.incrementSuccess();
|
|
} catch (err) {
|
|
this.logger.error('relayMintOrUnlock failed', { messageId, error: err.message });
|
|
metrics.incrementFailed();
|
|
}
|
|
}
|
|
}
|