-
Notifications
You must be signed in to change notification settings - Fork 47
/
Copy pathdisputeRelayerBot.ts
114 lines (101 loc) · 4.87 KB
/
disputeRelayerBot.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import env from "./utils/env";
import loggerFactory from "./utils/logger";
import hre = require("hardhat");
import {
KlerosCore,
ForeignGateway__factory,
HomeGateway,
TestERC20,
IArbitrableV2__factory,
} from "../typechain-types";
import { DisputeRequestEventObject } from "../typechain-types/src/arbitration/interfaces/IArbitrableV2";
import { HttpNetworkConfig } from "hardhat/types";
import { DeploymentsExtension } from "hardhat-deploy/types";
const { ethers } = hre;
const HEARTBEAT_URL = env.optionalNoDefault("HEARTBEAT_URL_RELAYER_BOT");
const loggerOptions = env.optionalNoDefault("LOGTAIL_TOKEN_RELAYER_BOT")
? {
transportTargetOptions: {
target: "@logtail/pino",
options: { sourceToken: env.require("LOGTAIL_TOKEN_RELAYER_BOT") },
level: env.optional("LOG_LEVEL", "info"),
},
level: env.optional("LOG_LEVEL", "info"), // for pino-pretty
}
: {};
export default async function main(
foreignNetwork: HttpNetworkConfig,
foreignDeployments: DeploymentsExtension,
foreignGatewayArtifact: string,
homeGatewayArtifact: string,
feeTokenArtifact?: string
) {
const core = (await ethers.getContract("KlerosCore")) as KlerosCore;
const homeGateway = (await ethers.getContract(homeGatewayArtifact)) as HomeGateway;
const feeToken = feeTokenArtifact ? ((await ethers.getContract(feeTokenArtifact)) as TestERC20) : undefined;
const foreignChainProvider = new ethers.providers.JsonRpcProvider(foreignNetwork.url);
const foreignGatewayDeployment = await foreignDeployments.get(foreignGatewayArtifact);
const foreignGateway = await ForeignGateway__factory.connect(foreignGatewayDeployment.address, foreignChainProvider);
const foreignChainID = await foreignChainProvider.getNetwork().then((network) => network.chainId);
const arbitrableInterface = IArbitrableV2__factory.createInterface();
const logger = loggerFactory.createLogger(loggerOptions).child({ foreignChainId: foreignChainID });
logger.info(`Listening for events from ${foreignGatewayArtifact}...`);
if (HEARTBEAT_URL) {
logger.debug("Sending heartbeat");
fetch(HEARTBEAT_URL);
} else {
logger.debug("Heartbeat not set up, skipping");
}
// Event subscription
// WARNING: The callback might run more than once if the script is restarted in the same block
// type Listener = [ eventArg1, ...eventArgN, transactionReceipt ]
foreignGateway.on(
"CrossChainDisputeOutgoing",
async (foreignBlockHash, foreignArbitrable, foreignDisputeID, choices, extraData, txReceipt) => {
logger.info(
`CrossChainDisputeOutgoing: ${foreignBlockHash} ${foreignArbitrable} ${foreignDisputeID} ${choices} ${extraData}`
);
logger.debug(`tx receipt: ${JSON.stringify(txReceipt)}`);
// txReceipt is missing the full logs for this tx so we need to request it here
const fullTxReceipt = await foreignChainProvider.getTransactionReceipt(txReceipt.transactionHash);
// Retrieve the DisputeRequest event
const disputeRequests: DisputeRequestEventObject[] = fullTxReceipt.logs
.filter((log) => log.topics[0] === arbitrableInterface.getEventTopic("DisputeRequest"))
.map((log) => arbitrableInterface.parseLog(log).args as unknown as DisputeRequestEventObject);
logger.warn(`More than 1 DisputeRequest event: not supported yet, skipping the others events.`);
const disputeRequest = disputeRequests[0];
logger.info(`tx events DisputeRequest: ${JSON.stringify(disputeRequest)}`);
const relayCreateDisputeParams = {
foreignBlockHash,
foreignChainID,
foreignArbitrable,
foreignDisputeID,
externalDisputeID: disputeRequest._externalDisputeID,
templateId: disputeRequest._templateId,
templateUri: disputeRequest._templateUri,
choices,
extraData,
};
logger.info(`Relaying dispute to home chain... ${JSON.stringify(relayCreateDisputeParams)}`);
let tx;
if (feeToken === undefined) {
// Paying in native Arbitrum ETH
const cost = (await core.functions["arbitrationCost(bytes)"](extraData)).cost;
tx = await homeGateway.functions[
"relayCreateDispute((bytes32,uint256,address,uint256,uint256,uint256,string,uint256,bytes))"
](relayCreateDisputeParams, { value: cost });
} else {
// Paying in ERC20
const cost = (await core.functions["arbitrationCost(bytes,address)"](extraData, feeToken.address)).cost;
await (await feeToken.approve(homeGateway.address, cost)).wait();
tx = await homeGateway.functions[
"relayCreateDispute((bytes32,uint256,address,uint256,uint256,uint256,string,uint256,bytes),uint256)"
](relayCreateDisputeParams, cost);
}
tx = tx.wait();
logger.info(`relayCreateDispute txId: ${tx.transactionHash}`);
}
);
const delay = (ms) => new Promise((x) => setTimeout(x, ms));
await delay(60 * 60 * 1000); // 1 hour
}