Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions validator-cli/src/consts/bridgeRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import veaOutboxArbToGnosisDevnet from "@kleros/vea-contracts/deployments/chiado
import veaInboxArbToGnosisTestnet from "@kleros/vea-contracts/deployments/arbitrumSepolia/VeaInboxArbToGnosisTestnet.json";
import veaOutboxArbToGnosisTestnet from "@kleros/vea-contracts/deployments/chiado/VeaOutboxArbToGnosisTestnet.json";
import veaRouterArbToGnosisTestnet from "@kleros/vea-contracts/deployments/sepolia/RouterArbToGnosisTestnet.json";
interface Bridge {
export interface Bridge {
chain: string;
minChallengePeriod: number;
sequencerDelayLimit: number;
Expand All @@ -30,7 +30,7 @@ type RouteConfigs = {
deposit: bigint;
};

export enum Network {
enum Network {
DEVNET = "devnet",
TESTNET = "testnet",
}
Expand All @@ -39,7 +39,7 @@ const arbToEthConfigs: { [key in Network]: RouteConfigs } = {
[Network.DEVNET]: {
veaInbox: veaInboxArbToEthDevnet,
veaOutbox: veaOutboxArbToEthDevnet,
epochPeriod: 1800,
epochPeriod: 300,
deposit: BigInt("1000000000000000000"),
},
[Network.TESTNET]: {
Expand All @@ -54,7 +54,7 @@ const arbToGnosisConfigs: { [key in Network]: RouteConfigs } = {
[Network.DEVNET]: {
veaInbox: veaInboxArbToGnosisDevnet,
veaOutbox: veaOutboxArbToGnosisDevnet,
epochPeriod: 1800,
epochPeriod: 300,
deposit: BigInt("100000000000000000"),
},
[Network.TESTNET]: {
Expand All @@ -66,7 +66,7 @@ const arbToGnosisConfigs: { [key in Network]: RouteConfigs } = {
},
};

export const bridges: { [chainId: number]: Bridge } = {
const bridges: { [chainId: number]: Bridge } = {
11155111: {
chain: "sepolia",
minChallengePeriod: 10800,
Expand All @@ -87,10 +87,16 @@ export const bridges: { [chainId: number]: Bridge } = {
},
};

// For the remaining time in an epoch the bot should save snapshots
const snapshotSavingPeriod = {
[Network.DEVNET]: 90, // 1m 30s
[Network.TESTNET]: 600, // 10 mins
};

const getBridgeConfig = (chainId: number): Bridge => {
const bridge = bridges[chainId];
if (!bridge) throw new Error(`Bridge not found for chain`);
return bridges[chainId];
};

export { getBridgeConfig, Bridge };
export { bridges, getBridgeConfig, Network, snapshotSavingPeriod };
7 changes: 4 additions & 3 deletions validator-cli/src/helpers/snapshot.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Network } from "../consts/bridgeRoutes";
import { Network, snapshotSavingPeriod } from "../consts/bridgeRoutes";
import { isSnapshotNeeded, saveSnapshot } from "./snapshot";
import { MockEmitter } from "../utils/emitter";

Expand Down Expand Up @@ -184,15 +184,16 @@ describe("snapshot", () => {
expect(res).toEqual({ transactionHandler, latestCount: currentCount });
});

it("should save snapshot if snapshot is needed at anytime for devnet", async () => {
it("should save snapshot in time limit for devnet", async () => {
const savingPeriod = snapshotSavingPeriod[Network.DEVNET];
const currentCount = 6;
count = -1;
veaInbox.count.mockResolvedValue(currentCount);
const isSnapshotNeededMock = jest.fn().mockResolvedValue({
snapshotNeeded: true,
latestCount: currentCount,
});
const now = 1801; // 600 seconds after the epoch started
const now = epochPeriod + epochPeriod - savingPeriod; // 60 seconds before the second epoch ends
const transactionHandler = {
saveSnapshot: jest.fn(),
};
Expand Down
19 changes: 8 additions & 11 deletions validator-cli/src/helpers/snapshot.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Network } from "../consts/bridgeRoutes";
import { Network, snapshotSavingPeriod } from "../consts/bridgeRoutes";
import { getLastMessageSaved } from "../utils/graphQueries";
import { BotEvents } from "../utils/botEvents";
import { defaultEmitter } from "../utils/emitter";

interface SnapshotCheckParams {
chainId: number;
veaInbox: any;
Expand Down Expand Up @@ -33,14 +32,12 @@ export const saveSnapshot = async ({
toSaveSnapshot = isSnapshotNeeded,
now = Math.floor(Date.now() / 1000),
}: SaveSnapshotParams): Promise<any> => {
if (network != Network.DEVNET) {
const timeElapsed = now % epochPeriod;
const timeLeftForEpoch = epochPeriod - timeElapsed;
// Saving snapshots in last 10 minutes of the epoch on testnet
if (timeLeftForEpoch > 600) {
emitter.emit(BotEvents.SNAPSHOT_WAITING, timeLeftForEpoch);
return { transactionHandler, latestCount: count };
}
const timeElapsed = now % epochPeriod;
const timeLeftForEpoch = epochPeriod - timeElapsed;

if (timeLeftForEpoch > snapshotSavingPeriod[network]) {
emitter.emit(BotEvents.SNAPSHOT_WAITING, timeLeftForEpoch);
return { transactionHandler, latestCount: count };
}
const { snapshotNeeded, latestCount } = await toSaveSnapshot({
chainId,
Expand Down Expand Up @@ -71,7 +68,7 @@ export const isSnapshotNeeded = async ({
const lastSavedMessageId = await fetchLastSavedMessage(veaInboxAddress, chainId);
const messageIndex = extractMessageIndex(lastSavedMessageId);
// adding 1 to the message index to get the last saved count
lastSavedCount = messageIndex + 1;
lastSavedCount = messageIndex;
}
if (currentCount > lastSavedCount) {
return { snapshotNeeded: true, latestCount: currentCount };
Expand Down
31 changes: 11 additions & 20 deletions validator-cli/src/utils/transactionHandlers/arbToEthHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ export class ArbToEthTransactionHandler extends BaseTransactionHandler<VeaInboxA
public async makeClaim(stateRoot: string): Promise<void> {
this.emitter.emit(BotEvents.CLAIMING, this.epoch);
const now = Date.now();
const status = await this.checkTransactionStatus(this.transactions.claimTxn, ContractType.OUTBOX, now);
if (status !== TransactionStatus.NOT_MADE && status !== TransactionStatus.EXPIRED) {
return;
}

const toSubmit = await this.toSubmitTransaction(this.transactions.claimTxn, ContractType.OUTBOX, now);
if (!toSubmit) return;

const { routeConfig } = getBridgeConfig(this.chainId);
const { deposit } = routeConfig[this.network];
Expand All @@ -51,10 +50,8 @@ export class ArbToEthTransactionHandler extends BaseTransactionHandler<VeaInboxA
this.emitter.emit(BotEvents.CHALLENGING, this.epoch);
if (!this.claim) throw new ClaimNotSetError();
const now = Date.now();
const status = await this.checkTransactionStatus(this.transactions.challengeTxn, ContractType.OUTBOX, now);
if (status !== TransactionStatus.NOT_MADE && status !== TransactionStatus.EXPIRED) {
return;
}
const toSubmit = await this.toSubmitTransaction(this.transactions.challengeTxn, ContractType.OUTBOX, now);
if (!toSubmit) return;

const { routeConfig } = getBridgeConfig(this.chainId);
const { deposit } = routeConfig[this.network];
Expand Down Expand Up @@ -92,10 +89,8 @@ export class ArbToEthTransactionHandler extends BaseTransactionHandler<VeaInboxA
if (!this.claim) throw new ClaimNotSetError();

const now = Date.now();
const status = await this.checkTransactionStatus(this.transactions.sendSnapshotTxn, ContractType.INBOX, now);
if (status !== TransactionStatus.NOT_MADE && status !== TransactionStatus.EXPIRED) {
return;
}
const toSubmit = await this.toSubmitTransaction(this.transactions.sendSnapshotTxn, ContractType.INBOX, now);
if (!toSubmit) return;

const tx = await this.veaInbox.sendSnapshot(this.epoch, this.claim);
this.emitter.emit(BotEvents.TXN_MADE, tx.hash, this.epoch, "Send Snapshot");
Expand All @@ -108,10 +103,8 @@ export class ArbToEthTransactionHandler extends BaseTransactionHandler<VeaInboxA
public async resolveChallengedClaim(sendSnapshotHash: string, execFn = messageExecutor): Promise<void> {
this.emitter.emit(BotEvents.EXECUTING_SNAPSHOT, this.epoch);
const now = Date.now();
const status = await this.checkTransactionStatus(this.transactions.executeSnapshotTxn, ContractType.OUTBOX, now);
if (status !== TransactionStatus.NOT_MADE && status !== TransactionStatus.EXPIRED) {
return;
}
const toSubmit = await this.toSubmitTransaction(this.transactions.executeSnapshotTxn, ContractType.OUTBOX, now);
if (!toSubmit) return;

const result = await execFn(sendSnapshotHash, this.veaInboxProvider, this.veaOutboxProvider);
this.emitter.emit(BotEvents.TXN_MADE, result.hash, this.epoch, "Execute Snapshot");
Expand Down Expand Up @@ -142,10 +135,8 @@ export class ArbToEthDevnetTransactionHandler extends ArbToEthTransactionHandler
public async devnetAdvanceState(stateRoot: string): Promise<void> {
this.emitter.emit(BotEvents.ADV_DEVNET, this.epoch);
const now = Date.now();
const status = await this.checkTransactionStatus(this.transactions.devnetAdvanceStateTxn, ContractType.OUTBOX, now);
if (status !== TransactionStatus.NOT_MADE && status !== TransactionStatus.EXPIRED) {
return;
}
const toSubmit = await this.toSubmitTransaction(this.transactions.devnetAdvanceStateTxn, ContractType.OUTBOX, now);
if (!toSubmit) return;
const { routeConfig } = getBridgeConfig(this.chainId);
const { deposit } = routeConfig[Network.DEVNET];
const tx = await this.veaOutboxDevnet.devnetAdvanceState(this.epoch, stateRoot, {
Expand Down
20 changes: 10 additions & 10 deletions validator-cli/src/utils/transactionHandlers/arbToGnosisHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ export class ArbToGnosisTransactionHandler extends BaseTransactionHandler<VeaInb
public async makeClaim(stateRoot: string): Promise<void> {
this.emitter.emit(BotEvents.CLAIMING, this.epoch);
const now = Date.now();
const status = await this.checkTransactionStatus(this.transactions.claimTxn, ContractType.OUTBOX, now);
if (status !== TransactionStatus.NOT_MADE && status !== TransactionStatus.EXPIRED) return;
const toSubmit = await this.toSubmitTransaction(this.transactions.claimTxn, ContractType.OUTBOX, now);
if (!toSubmit) return;

// Approves WETH for the claim if not already approved
await this.approveWeth();
Expand All @@ -57,8 +57,8 @@ export class ArbToGnosisTransactionHandler extends BaseTransactionHandler<VeaInb
this.emitter.emit(BotEvents.CHALLENGING, this.epoch);
if (!this.claim) throw new ClaimNotSetError();
const now = Date.now();
const status = await this.checkTransactionStatus(this.transactions.challengeTxn, ContractType.OUTBOX, now);
if (status !== TransactionStatus.NOT_MADE && status !== TransactionStatus.EXPIRED) return;
const toSubmit = await this.toSubmitTransaction(this.transactions.challengeTxn, ContractType.OUTBOX, now);
if (!toSubmit) return;

const gasEstimate = await this.veaOutbox[
"challenge(uint256,(bytes32,address,uint32,uint32,uint32,uint8,address))"
Expand All @@ -85,8 +85,8 @@ export class ArbToGnosisTransactionHandler extends BaseTransactionHandler<VeaInb
this.emitter.emit(BotEvents.SENDING_SNAPSHOT, this.epoch);
if (!this.claim) throw new ClaimNotSetError();
const now = Date.now();
const status = await this.checkTransactionStatus(this.transactions.sendSnapshotTxn, ContractType.INBOX, now);
if (status !== TransactionStatus.NOT_MADE && status !== TransactionStatus.EXPIRED) return;
const toSubmit = await this.toSubmitTransaction(this.transactions.sendSnapshotTxn, ContractType.INBOX, now);
if (!toSubmit) return;

const ambGasLimit = BigInt(3000000);
const tx = await this.veaInbox.sendSnapshot(this.epoch, ambGasLimit, this.claim);
Expand All @@ -98,8 +98,8 @@ export class ArbToGnosisTransactionHandler extends BaseTransactionHandler<VeaInb
this.emitter.emit(BotEvents.EXECUTING_SNAPSHOT, this.epoch);
if (!this.claim) throw new ClaimNotSetError();
const now = Date.now();
const status = await this.checkTransactionStatus(this.transactions.executeSnapshotTxn, ContractType.ROUTER, now);
if (status !== TransactionStatus.NOT_MADE && status !== TransactionStatus.EXPIRED) return;
const toSubmit = await this.toSubmitTransaction(this.transactions.executeSnapshotTxn, ContractType.ROUTER, now);
if (!toSubmit) return;
const msgExecuteTrnx = await messageExecutor(sendSnapshotTxn, this.veaInboxProvider, this.veaRouterProvider);
this.emitter.emit(BotEvents.TXN_MADE, msgExecuteTrnx.hash, this.epoch, "Execute Snapshot");
this.transactions.executeSnapshotTxn = {
Expand Down Expand Up @@ -134,8 +134,8 @@ export class ArbToGnosisDevnetTransactionHandler extends ArbToGnosisTransactionH
public async devnetAdvanceState(stateRoot: string): Promise<void> {
this.emitter.emit(BotEvents.ADV_DEVNET, this.epoch);
const now = Date.now();
const status = await this.checkTransactionStatus(this.transactions.devnetAdvanceStateTxn, ContractType.OUTBOX, now);
if (status !== TransactionStatus.NOT_MADE && status !== TransactionStatus.EXPIRED) return;
const toSubmit = await this.toSubmitTransaction(this.transactions.devnetAdvanceStateTxn, ContractType.OUTBOX, now);
if (!toSubmit) return;
await this.approveWeth();
const { routeConfig } = getBridgeConfig(this.chainId);
const { deposit } = routeConfig[Network.DEVNET];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,23 @@ export abstract class BaseTransactionHandler<Inbox, Outbox> implements ITransact
return TransactionStatus.NOT_FINAL;
}

public async toSubmitTransaction(
trnx: Transaction | null,
contract: ContractType,
currentTime: number
): Promise<boolean> {
const status = await this.checkTransactionStatus(trnx, contract, currentTime);
if (status === TransactionStatus.PENDING || status === TransactionStatus.NOT_FINAL) return false;
return true;
}

public async startVerification(currentTimestamp: number) {
this.emitter.emit(BotEvents.STARTING_VERIFICATION, this.epoch);
if (!this.claim) throw new ClaimNotSetError();

const now = Date.now();
const status = await this.checkTransactionStatus(this.transactions.startVerificationTxn, ContractType.OUTBOX, now);
if (status !== TransactionStatus.NOT_MADE && status !== TransactionStatus.EXPIRED) return;
const toSubmit = await this.toSubmitTransaction(this.transactions.startVerificationTxn, ContractType.OUTBOX, now);
if (!toSubmit) return;

const cfg = getBridgeConfig(this.chainId);
const timeOver =
Expand All @@ -222,8 +232,8 @@ export abstract class BaseTransactionHandler<Inbox, Outbox> implements ITransact
if (!this.claim) throw new ClaimNotSetError();

const now = Date.now();
const status = await this.checkTransactionStatus(this.transactions.verifySnapshotTxn, ContractType.OUTBOX, now);
if (status !== TransactionStatus.NOT_MADE && status !== TransactionStatus.EXPIRED) return;
const toSubmit = await this.toSubmitTransaction(this.transactions.verifySnapshotTxn, ContractType.OUTBOX, now);
if (!toSubmit) return;

const cfg = getBridgeConfig(this.chainId);
const timeLeft = currentTimestamp - Number(this.claim.timestampVerification) - cfg.minChallengePeriod;
Expand All @@ -246,12 +256,12 @@ export abstract class BaseTransactionHandler<Inbox, Outbox> implements ITransact
if (!this.claim) throw new ClaimNotSetError();

const now = Date.now();
const status = await this.checkTransactionStatus(
const toSubmit = await this.toSubmitTransaction(
this.transactions.withdrawClaimDepositTxn,
ContractType.OUTBOX,
now
);
if (status !== TransactionStatus.NOT_MADE && status !== TransactionStatus.EXPIRED) return;
if (!toSubmit) return;

const tx = await (this.veaOutbox as any).withdrawClaimDeposit(this.epoch, this.claim);
this.emitter.emit(BotEvents.TXN_MADE, tx.hash, this.epoch, "Withdraw Claim Deposit");
Expand All @@ -266,12 +276,12 @@ export abstract class BaseTransactionHandler<Inbox, Outbox> implements ITransact
if (!this.claim) throw new ClaimNotSetError();

const now = Date.now();
const status = await this.checkTransactionStatus(
const toSubmit = await this.toSubmitTransaction(
this.transactions.withdrawChallengeDepositTxn,
ContractType.OUTBOX,
now
);
if (status !== TransactionStatus.NOT_MADE && status !== TransactionStatus.EXPIRED) return;
if (!toSubmit) return;

const tx = await (this.veaOutbox as any).withdrawChallengeDeposit(this.epoch, this.claim);
this.emitter.emit(BotEvents.TXN_MADE, tx.hash, this.epoch, "Withdraw Challenge Deposit");
Expand All @@ -285,8 +295,8 @@ export abstract class BaseTransactionHandler<Inbox, Outbox> implements ITransact
this.emitter.emit(BotEvents.SAVING_SNAPSHOT, this.epoch);

const now = Date.now();
const status = await this.checkTransactionStatus(this.transactions.saveSnapshotTxn, ContractType.INBOX, now);
if (status !== TransactionStatus.NOT_MADE && status !== TransactionStatus.EXPIRED) return;
const toSubmit = await this.toSubmitTransaction(this.transactions.saveSnapshotTxn, ContractType.INBOX, now);
if (!toSubmit) return;

const tx = await (this.veaInbox as any).saveSnapshot();
this.emitter.emit(BotEvents.TXN_MADE, tx.hash, this.epoch, "Save Snapshot");
Expand Down
Loading