Skip to content

Commit ada4710

Browse files
committed
chore(validator-bot): upgraded arbToGnosis validator bot
1 parent 332a539 commit ada4710

File tree

2 files changed

+107
-111
lines changed

2 files changed

+107
-111
lines changed

validator-cli/src/ArbToEth/watcherArbToGnosis.ts

Lines changed: 90 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import {
2-
getVeaOutboxArbToGnosisProvider,
3-
getVeaInboxArbToGnosisProvider,
4-
getWETHProvider,
5-
getWalletRPC,
6-
getVeaRouterArbToGnosisProvider,
7-
getAMBProvider,
2+
getVeaOutboxArbToGnosis,
3+
getVeaInboxArbToGnosis,
4+
getWETH,
5+
getWallet,
6+
getVeaRouterArbToGnosis,
7+
getAMB,
88
} from "../utils/ethers";
99
import { JsonRpcProvider } from "@ethersproject/providers";
10+
import { Wallet } from "@ethersproject/wallet";
1011
import { ChildToParentMessageStatus, ChildTransactionReceipt, getArbitrumNetwork } from "@arbitrum/sdk";
1112
import { NODE_INTERFACE_ADDRESS } from "@arbitrum/sdk/dist/lib/dataEntities/constants";
1213
import { NodeInterface__factory } from "@arbitrum/sdk/dist/lib/abi/factories/NodeInterface__factory";
1314
import { SequencerInbox__factory } from "@arbitrum/sdk/dist/lib/abi/factories/SequencerInbox__factory";
14-
import { BigNumber, ContractTransaction, Wallet, constants, ethers } from "ethers";
15+
import { ethers, ContractTransactionResponse } from "ethers";
1516
import { Block, Log } from "@ethersproject/abstract-provider";
1617
import { SequencerInbox } from "@arbitrum/sdk/dist/lib/abi/SequencerInbox";
1718
import { NodeInterface } from "@arbitrum/sdk/dist/lib/abi/NodeInterface";
@@ -21,7 +22,6 @@ import {
2122
VeaInboxArbToGnosis,
2223
VeaOutboxArbToGnosis,
2324
} from "@kleros/vea-contracts/typechain-types";
24-
import { ClaimStruct } from "@kleros/vea-contracts/typechain-types/arbitrumToEth/VeaInboxArbToEth";
2525
import { messageExecutor } from "../utils/arbMsgExecutor";
2626

2727
require("dotenv").config();
@@ -96,52 +96,44 @@ const watch = async () => {
9696
const providerGnosis = new JsonRpcProvider(process.env.RPC_GNOSIS);
9797
const providerArb = new JsonRpcProvider(process.env.RPC_ARB);
9898

99-
const watcherAddress = getWalletRPC(process.env.PRIVATE_KEY, providerGnosis).address;
99+
const watcherAddress = getWallet(process.env.PRIVATE_KEY, process.env.RPC_GNOSIS).address;
100100

101101
// use typechain generated contract factories for vea outbox and inbox
102-
const veaOutbox = getVeaOutboxArbToGnosisProvider(veaOutboxAddress, process.env.PRIVATE_KEY, providerGnosis);
103-
const veaInbox = getVeaInboxArbToGnosisProvider(veaInboxAddress, process.env.PRIVATE_KEY, providerArb);
104-
const veaRouter = getVeaRouterArbToGnosisProvider(veaRouterAddress, process.env.PRIVATE_KEY, providerEth);
105-
const amb = getAMBProvider(gnosisAMBAddress, process.env.PRIVATE_KEY, providerGnosis);
102+
const veaOutbox = getVeaOutboxArbToGnosis(veaOutboxAddress, process.env.PRIVATE_KEY, process.env.RPC_GNOSIS);
103+
const veaInbox = getVeaInboxArbToGnosis(veaInboxAddress, process.env.PRIVATE_KEY, process.env.RPC_ARB);
104+
const veaRouter = getVeaRouterArbToGnosis(veaRouterAddress, process.env.PRIVATE_KEY, process.env.RPC_ETH);
105+
const amb = getAMB(gnosisAMBAddress, process.env.PRIVATE_KEY, process.env.RPC_GNOSIS);
106106

107107
const wethAddress = (await retryOperation(() => veaOutbox.weth(), 1000, 10)) as string;
108-
const weth = getWETHProvider(wethAddress, process.env.PRIVATE_KEY, providerGnosis);
109-
const balance = (await retryOperation(() => weth.balanceOf(watcherAddress), 1000, 10)) as BigNumber;
110-
const allowance = (await retryOperation(
111-
() => weth.allowance(watcherAddress, veaOutboxAddress),
112-
1000,
113-
10
114-
)) as BigNumber;
108+
const weth = getWETH(wethAddress, process.env.PRIVATE_KEY, process.env.RPC_GNOSIS);
109+
const balance = (await retryOperation(() => weth.balanceOf(watcherAddress), 1000, 10)) as BigInt;
110+
const allowance = (await retryOperation(() => weth.allowance(watcherAddress, veaOutboxAddress), 1000, 10)) as BigInt;
115111

116112
// get Arb sequencer params
117113
const l2Network = await getArbitrumNetwork(providerArb);
118114
const sequencer = SequencerInbox__factory.connect(l2Network.ethBridge.sequencerInbox, providerEth);
119-
const maxDelaySeconds = (
120-
(await retryOperation(() => sequencer.maxTimeVariation(), 1000, 10))[1] as BigNumber
121-
).toNumber();
115+
const maxDelaySeconds = Number((await retryOperation(() => sequencer.maxTimeVariation(), 1000, 10))[1] as BigInt);
122116

123117
// get vea outbox params
124-
const deposit = (await retryOperation(() => veaOutbox.deposit(), 1000, 10)) as BigNumber;
125-
const epochPeriod = ((await retryOperation(() => veaOutbox.epochPeriod(), 1000, 10)) as BigNumber).toNumber();
126-
const sequencerDelayLimit = (
127-
(await retryOperation(() => veaOutbox.sequencerDelayLimit(), 1000, 10)) as BigNumber
128-
).toNumber();
118+
const deposit = await retryOperation(() => veaOutbox.deposit(), 1000, 10);
119+
const epochPeriod = Number(await retryOperation(() => veaOutbox.epochPeriod(), 1000, 10));
120+
const sequencerDelayLimit = Number(await retryOperation(() => veaOutbox.sequencerDelayLimit(), 1000, 10));
129121

130-
const inactive = balance.lt(deposit);
122+
const inactive = balance < deposit;
131123
if (inactive) {
132124
console.error(
133125
"insufficient weth balance to run an active watcher. Try bridging eth to gnosis with https://omni.gnosischain.com/bridge"
134126
);
135127
console.log("running watcher in passive mode (no challenges)");
136128
}
137129

138-
if (allowance.lt(constants.MaxUint256.div(2))) {
130+
if (BigInt(allowance.toString()) < ethers.MaxUint256 / BigInt(2)) {
139131
console.log("setting infinite weth approval to vea outbox to prepare to challenge. . .");
140132
const approvalTxn = (await retryOperation(
141-
() => weth.approve(veaOutboxAddress, constants.MaxUint256),
133+
() => weth.approve(veaOutboxAddress, ethers.MaxUint256),
142134
1000,
143135
10
144-
)) as ContractTransaction;
136+
)) as ContractTransactionResponse;
145137
await approvalTxn.wait();
146138
console.log("weth approval txn hash: " + approvalTxn.hash);
147139
}
@@ -241,7 +233,7 @@ const watch = async () => {
241233
)) as string;
242234

243235
// no claim
244-
if (claimHash == constants.HashZero) {
236+
if (claimHash == ethers.ZeroHash) {
245237
// if epoch is not claimable anymore, remove from array
246238
if (veaEpochOutboxCheck <= veaEpochOutboxClaimableFinalized) {
247239
console.log(
@@ -281,12 +273,11 @@ const watch = async () => {
281273
const logClaimed: Log = (
282274
await retryOperation(
283275
() =>
284-
providerGnosis.getLogs({
285-
address: veaOutboxAddress,
286-
topics: veaOutbox.filters.Claimed(null, [veaEpochOutboxCheck], null).topics,
287-
fromBlock: blockNumberOutboxLowerBound,
288-
toBlock: blockTagGnosis,
289-
}),
276+
veaOutbox.queryFilter(
277+
veaOutbox.filters.Claimed(null, veaEpochOutboxCheck, null),
278+
blockNumberOutboxLowerBound,
279+
blockTagGnosis
280+
),
290281
1000,
291282
10
292283
)
@@ -342,13 +333,13 @@ const watch = async () => {
342333
);
343334
//TODO : check profitablity of the whole dispute resolution
344335
//const profitablity = await calculateDisputeResolutionProfitability(veaEpochOutboxCheck,claim,veaOutbox,veaInbox,providerGnosis,providerArb,providerEth);
345-
if (claim.challenger == constants.AddressZero) {
336+
if (claim.challenger == ethers.ZeroAddress) {
346337
if (challengeProgress?.challenge.status == "pending") continue;
347338
const txnChallenge = (await retryOperation(
348339
() => veaOutbox.challenge(veaEpochOutboxCheck, claim),
349340
1000,
350341
10
351-
)) as ContractTransaction;
342+
)) as ContractTransactionResponse;
352343
console.log("Epoch " + veaEpochOutboxCheck + " challenged with txn " + txnChallenge.hash);
353344
challengeProgress.challenge = {
354345
status: "pending",
@@ -368,7 +359,7 @@ const watch = async () => {
368359
() => veaInbox.sendSnapshot(veaEpochOutboxCheck, 200000, claim), // execute transaction required around 142000 gas so we set gas limit to 200000
369360
1000,
370361
10
371-
)) as ContractTransaction;
362+
)) as ContractTransactionResponse;
372363
console.log("Epoch " + veaEpochOutboxCheck + " sendSnapshot called with txn " + txnSendSnapshot.hash);
373364
challengeProgress.snapshot = {
374365
status: "pending",
@@ -395,7 +386,7 @@ const watch = async () => {
395386
() => veaOutbox.withdrawChallengeDeposit(veaEpochOutboxCheck, claim),
396387
1000,
397388
10
398-
)) as ContractTransaction;
389+
)) as ContractTransactionResponse;
399390

400391
if (txnWithdrawalDeposit.hash) {
401392
console.log(
@@ -588,7 +579,7 @@ const ArbBlockToL1Block = async (
588579
.findBatchContainingBlock(L2Block.number, { blockTag: "latest" })
589580
.catch((e) => {
590581
console.error("Error finding batch containing block:", JSON.parse(JSON.stringify(e)).error.body);
591-
})) as [BigNumber] & { batch: BigNumber };
582+
})) as any;
592583

593584
if (!result) {
594585
if (!fallbackLatest) {
@@ -657,7 +648,7 @@ async function getClaimForEpoch(
657648
const claimHash = (await retryOperation(() => veaOutbox.claimHashes(epoch), 1000, 10)) as any;
658649

659650
// If there's no claim, return null
660-
if (claimHash === constants.HashZero) {
651+
if (claimHash === ethers.ZeroHash) {
661652
return null;
662653
}
663654

@@ -694,7 +685,7 @@ async function getClaimForEpoch(
694685
timestampVerification: 0,
695686
blocknumberVerification: 0,
696687
honest: 0, // 0 for None, 1 for Claimer, 2 for Challenger
697-
challenger: constants.AddressZero,
688+
challenger: ethers.ZeroAddress,
698689
};
699690
let other = {} as any;
700691
let calculatedHash = hashClaim(claim);
@@ -755,58 +746,58 @@ async function getClaimForEpoch(
755746
return null;
756747
}
757748

758-
async function calculateDisputeResolutionProfitability(
759-
epoch: number,
760-
claim: ClaimStruct,
761-
veaOutbox: VeaOutboxArbToGnosis,
762-
veaInbox: VeaInboxArbToGnosis,
763-
providerGnosis: JsonRpcProvider,
764-
providerArb: JsonRpcProvider,
765-
providerEth: JsonRpcProvider
766-
): Promise<{ profitable: boolean; estimatedProfit: BigNumber }> {
767-
try {
768-
const deposit = (await retryOperation(() => veaOutbox.deposit(), 1000, 10)) as BigNumber;
769-
const totalReward = deposit;
770-
const minimumProfit = totalReward.mul(40).div(100); // 40% of total reward
771-
let maximumAllowableCost = totalReward.sub(minimumProfit);
772-
let totalCost = BigNumber.from(0);
773-
774-
// 1. Costs on Gnosis Chain
775-
const gnosisGasEstimate = await veaOutbox.estimateGas.challenge(epoch, claim);
776-
777-
const gnosisGasPrice = await providerGnosis.getGasPrice();
778-
const gnosisCost = gnosisGasEstimate.mul(gnosisGasPrice);
779-
780-
if (gnosisCost.gt(maximumAllowableCost)) {
781-
return { profitable: false, estimatedProfit: constants.Zero };
782-
}
783-
totalCost = totalCost.add(gnosisCost);
784-
maximumAllowableCost = maximumAllowableCost.sub(gnosisCost);
785-
786-
const l2Network = await getArbitrumNetwork(providerArb);
787-
788-
const arbGasEstimate = (await retryOperation(
789-
() => veaInbox.estimateGas.sendSnapshot(epoch, 200000, claim),
790-
1000,
791-
10
792-
)) as BigNumber;
793-
794-
const arbGasPrice = (await retryOperation(() => providerArb.getGasPrice(), 1000, 10)) as BigNumber;
795-
const arbCost = arbGasEstimate.mul(arbGasPrice);
796-
797-
if (arbCost.gt(maximumAllowableCost)) {
798-
return { profitable: false, estimatedProfit: constants.Zero };
799-
}
800-
totalCost = totalCost.add(arbCost);
801-
maximumAllowableCost = maximumAllowableCost.sub(arbCost);
802-
803-
// 3. Costs on Ethereum (for Arbitrum -> Ethereum message)
804-
//TODO : L2 to L1 message execution gas cost
805-
} catch (error) {
806-
console.error("Error calculating profitability:", error);
807-
return { profitable: false, estimatedProfit: constants.Zero };
808-
}
809-
}
749+
// async function calculateDisputeResolutionProfitability(
750+
// epoch: number,
751+
// claim: ClaimStruct,
752+
// veaOutbox: VeaOutboxArbToGnosis,
753+
// veaInbox: VeaInboxArbToGnosis,
754+
// providerGnosis: JsonRpcProvider,
755+
// providerArb: JsonRpcProvider,
756+
// providerEth: JsonRpcProvider
757+
// ): Promise<{ profitable: boolean; estimatedProfit: BigInt }> {
758+
// try {
759+
// const deposit = await retryOperation(() => veaOutbox.deposit(), 1000, 10) as bigint;
760+
// const totalReward = deposit;
761+
// const minimumProfit = totalReward * BigInt(40) / BigInt(100); // 40% of total reward
762+
// let maximumAllowableCost = totalReward - minimumProfit;
763+
// let totalCost = BigInt(0);
764+
765+
// // 1. Costs on Gnosis Chain
766+
// const gnosisGasEstimate = await veaOutbox.challenge.estimateGas(epoch, claim);
767+
768+
// const gnosisGasPrice = await providerGnosis.getGasPrice();
769+
// const gnosisCost = gnosisGasEstimate * gnosisGasPrice;
770+
771+
// if (gnosisCost > maximumAllowableCost) {
772+
// return { profitable: false, estimatedProfit: BigInt(0) };
773+
// }
774+
// totalCost = totalCost + gnosisCost;
775+
// maximumAllowableCost = maximumAllowableCost - gnosisCost;
776+
777+
// const l2Network = await getArbitrumNetwork(providerArb);
778+
779+
// const arbGasEstimate = (await retryOperation(
780+
// () => veaInbox.sendSnapshot.estimateGas(epoch, 200000, claim),
781+
// 1000,
782+
// 10
783+
// )) as BigInt;
784+
785+
// const arbGasPrice = (await retryOperation(() => providerArb.getGasPrice(), 1000, 10)) as BigInt;
786+
// const arbCost = arbGasEstimate * arbGasPrice;
787+
788+
// if (arbCost > maximumAllowableCost) {
789+
// return { profitable: false, estimatedProfit: BigInt(0) };
790+
// }
791+
// totalCost = totalCost + arbCost;
792+
// maximumAllowableCost = maximumAllowableCost - arbCost;
793+
794+
// // 3. Costs on Ethereum (for Arbitrum -> Ethereum message)
795+
// //TODO : L2 to L1 message execution gas cost
796+
// } catch (error) {
797+
// console.error("Error calculating profitability:", error);
798+
// return { profitable: false, estimatedProfit: BigInt(0) };
799+
// }
800+
// }
810801

811802
function needsRetry(current: ChallengeProgress, previous: ChallengeProgress | undefined): boolean {
812803
if (!previous) return false;
@@ -1112,7 +1103,7 @@ async function reconstructChallengeProgress(
11121103
}
11131104

11141105
const hashClaim = (claim) => {
1115-
return ethers.utils.solidityKeccak256(
1106+
return ethers.solidityPackedKeccak256(
11161107
["bytes32", "address", "uint32", "uint32", "uint32", "uint8", "address"],
11171108
[
11181109
claim.stateRoot,

validator-cli/src/utils/ethers.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ function getVeaInboxArbToGnosisProvider(veaInboxAddress: string, privateKey: str
4444
return VeaInboxArbToGnosis__factory.connect(veaInboxAddress, getWalletRPC(privateKey, rpc));
4545
}
4646

47-
function getWETHProvider(WETH: string, privateKey: string, rpc: JsonRpcProvider) {
48-
return IWETH__factory.connect(WETH, getWalletRPC(privateKey, rpc));
47+
function getWETH(WETH: string, privateKey: string, web3ProviderURL: string) {
48+
return IWETH__factory.connect(WETH, getWallet(privateKey, web3ProviderURL));
4949
}
5050

5151
function getVeaOutboxArbToEth(veaOutboxAddress: string, privateKey: string, web3ProviderURL: string) {
@@ -61,26 +61,31 @@ function getVeaOutboxArbToEthDevnet(veaOutboxAddress: string, privateKey: string
6161
}
6262

6363
function getVeaOutboxArbToGnosis(veaOutboxAddress: string, privateKey: string, web3ProviderURL: string) {
64-
return VeaOutboxArbToGnosisDevnet__factory.connect(veaOutboxAddress, getWallet(privateKey, web3ProviderURL));
64+
return VeaOutboxArbToGnosis__factory.connect(veaOutboxAddress, getWallet(privateKey, web3ProviderURL));
6565
}
6666

67-
function getVeaRouterArbToGnosisProvider(veaRouterAddress: string, privateKey: string, rpc: JsonRpcProvider) {
68-
return RouterArbToGnosis__factory.connect(veaRouterAddress, getWalletRPC(privateKey, rpc));
67+
function getVeaInboxArbToGnosis(veaInboxAddress: string, privateKey: string, web3ProviderURL: string) {
68+
return VeaInboxArbToGnosis__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
6969
}
7070

71-
function getAMBProvider(ambAddress: string, privateKey: string, rpc: JsonRpcProvider) {
72-
return IAMB__factory.connect(ambAddress, getWalletRPC(privateKey, rpc));
71+
function getVeaRouterArbToGnosis(veaRouterAddress: string, privateKey: string, web3ProviderURL: string) {
72+
return RouterArbToGnosis__factory.connect(veaRouterAddress, getWallet(privateKey, web3ProviderURL));
73+
}
74+
75+
function getAMB(ambAddress: string, privateKey: string, web3ProviderURL: string) {
76+
return IAMB__factory.connect(ambAddress, getWallet(privateKey, web3ProviderURL));
7377
}
7478
export {
7579
getVeaOutboxArbToEth,
7680
getWalletRPC,
81+
getWallet,
7782
getVeaOutboxArbToEthDevnetProvider,
7883
getVeaInboxArbToEth,
7984
getVeaInboxArbToEthProvider,
8085
getVeaOutboxArbToEthProvider,
81-
getVeaOutboxArbToGnosisProvider,
82-
getVeaInboxArbToGnosisProvider,
83-
getVeaRouterArbToGnosisProvider,
84-
getWETHProvider,
85-
getAMBProvider,
86+
getVeaOutboxArbToGnosis,
87+
getVeaInboxArbToGnosis,
88+
getVeaRouterArbToGnosis,
89+
getWETH,
90+
getAMB,
8691
};

0 commit comments

Comments
 (0)