Skip to content

Commit

Permalink
feat: netlify relayer
Browse files Browse the repository at this point in the history
  • Loading branch information
shotaronowhere committed Oct 20, 2023
1 parent ff5db2c commit e070f23
Show file tree
Hide file tree
Showing 21 changed files with 1,175 additions and 363 deletions.
15 changes: 6 additions & 9 deletions relayer-cli/.env.dist
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
PRIVATE_KEY=

RPC_CHIADO=https://rpc.chiadochain.net
RPC_GOERLI=
RPC_CHIADO=https://rpc.chiado.gnosis.gateway.fm
RPC_GOERLI=https://goerli.infura.io/v3/

VEAINBOX_ARBGOERLI_TO_GOERLI_ADDRESS=0x906dE43dBef27639b1688Ac46532a16dc07Ce410
VEAINBOX_ARBGOERLI_TO_CHIADO_ADDRESS=0xAb53e341121448Ae259Da8fa17f216Cb0e21199C
VEAOUTBOX_ARBGOERLI_TO_GOERLI_ADDRESS=0x906dE43dBef27639b1688Ac46532a16dc07Ce410
VEAOUTBOX_ARBGOERLI_TO_CHIADO_ADDRESS=0xAb53e341121448Ae259Da8fa17f216Cb0e21199C

TRANSACTION_BATCHER_CONTRACT_ADDRESS_GOERLI=0xe7953da7751063d0a41ba727c32c762d3523ade8
TRANSACTION_BATCHER_CONTRACT_ADDRESS_CHIADO=0xcC0a08D4BCC5f91ee9a1587608f7a2975EA75d73
VEAINBOX_ARBGOERLI_TO_GOERLI_ADDRESS=0xA3FefC6FeE3fc66B9d9a8BEE794736ab71a74c55
VEAINBOX_ARBGOERLI_TO_CHIADO_ADDRESS=0x660daB9A6436A814a6ae3a6f27b309356a4bE78c
VEAOUTBOX_ARBGOERLI_TO_GOERLI_ADDRESS=0x9235A379950B9f01fb3e2961C06912A96DCcef0e
VEAOUTBOX_ARBGOERLI_TO_CHIADO_ADDRESS=0xdFd7aDEb43d46FA3f16FB3e27F7fe85c3f5BD89D
9 changes: 9 additions & 0 deletions relayer-cli/codegen.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
overwrite: true
generates:
./generated/vea-inbox.ts:
schema: "https://api.thegraph.com/subgraphs/name/shotaronowhere/vea-inbox-arbitrum"
documents: "graphql/inbox/*.gql"
plugins:
- "typescript"
- "typescript-operations"
- "typescript-graphql-request"
16 changes: 0 additions & 16 deletions relayer-cli/ecosystem.config.js

This file was deleted.

19 changes: 19 additions & 0 deletions relayer-cli/functions/relayer-devnet-chiado-background.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { schedule } from "@netlify/functions";
import { relayAllFor } from "./utils/relay";
import { StatusCodes } from "http-status-codes";

const relayer = async () => {
try {
await relayAllFor(10200, 0, "0xe6aC8CfF97199A67b8121a3Ce3aC98772f90B94b");
} catch (e) {
console.error(e);
return {
statusCode: StatusCodes.BAD_REQUEST,
};
}

return {
statusCode: StatusCodes.OK,
};
};
export const handler = schedule("@hourly", relayer);
19 changes: 19 additions & 0 deletions relayer-cli/functions/relayer-devnet-goerli-background.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { schedule } from "@netlify/functions";
import { relayAllFor } from "./utils/relay";
import { StatusCodes } from "http-status-codes";

const relayer = async () => {
try {
await relayAllFor(5, 0, "0xe6aC8CfF97199A67b8121a3Ce3aC98772f90B94b");
} catch (e) {
console.error(e);
return {
statusCode: StatusCodes.BAD_REQUEST,
};
}

return {
statusCode: StatusCodes.OK,
};
};
export const handler = schedule("@hourly", relayer);
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,42 @@ import {
VeaInboxArbToEth__factory,
} from "@kleros/vea-contracts/typechain-types";

function getWallet(privateKey: string, web3ProviderURL: string) {
export function getWallet(privateKey: string, web3ProviderURL: string) {
return new Wallet(privateKey, new JsonRpcProvider(web3ProviderURL));
}

function getWalletRPC(privateKey: string, rpc: JsonRpcProvider) {
export function getWalletRPC(privateKey: string, rpc: JsonRpcProvider) {
return new Wallet(privateKey, rpc);
}

function getVeaInboxArbToEth(veaInboxAddress: string, privateKey: string, web3ProviderURL: string) {
export function getVeaInboxArbToEth(veaInboxAddress: string, privateKey: string, web3ProviderURL: string) {
return VeaInboxArbToEth__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
}

function getVeaInboxArbToEthProvider(veaInboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
export function getVeaInboxArbToEthProvider(veaInboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
return VeaInboxArbToEth__factory.connect(veaInboxAddress, getWalletRPC(privateKey, rpc));
}

function getVeaOutboxArbToEthProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
export function getVeaOutboxArbToEthProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
return VeaOutboxArbToEth__factory.connect(veaOutboxAddress, getWalletRPC(privateKey, rpc));
}

function getVeaOutboxArbToEth(veaOutboxAddress: string, privateKey: string, web3ProviderURL: string) {
export function getVeaOutboxArbToEth(veaOutboxAddress: string, privateKey: string, web3ProviderURL: string) {
return VeaOutboxArbToEth__factory.connect(veaOutboxAddress, getWallet(privateKey, web3ProviderURL));
}

function getVeaOutboxArbToEthDevnetProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
export function getVeaOutboxArbToEthDevnetProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
return VeaOutboxArbToEthDevnet__factory.connect(veaOutboxAddress, getWalletRPC(privateKey, rpc));
}

function getVeaOutboxArbToEthDevnet(veaOutboxAddress: string, privateKey: string, web3ProviderURL: string) {
export function getVeaOutboxArbToEthDevnet(veaOutboxAddress: string, privateKey: string, web3ProviderURL: string) {
return VeaOutboxArbToEthDevnet__factory.connect(veaOutboxAddress, getWallet(privateKey, web3ProviderURL));
}

function getVeaOutboxArbToGnosisProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
export function getVeaOutboxArbToGnosisProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
return VeaOutboxArbToGnosisDevnet__factory.connect(veaOutboxAddress, getWalletRPC(privateKey, rpc));
}

function getVeaOutboxArbToGnosis(veaOutboxAddress: string, privateKey: string, web3ProviderURL: string) {
export function getVeaOutboxArbToGnosis(veaOutboxAddress: string, privateKey: string, web3ProviderURL: string) {
return VeaOutboxArbToGnosisDevnet__factory.connect(veaOutboxAddress, getWallet(privateKey, web3ProviderURL));
}

export {
getVeaOutboxArbToEth,
getWalletRPC,
getVeaOutboxArbToEthDevnetProvider,
getVeaInboxArbToEth,
getVeaInboxArbToEthProvider,
getVeaOutboxArbToEthProvider,
};
38 changes: 38 additions & 0 deletions relayer-cli/functions/utils/proof.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Supported } from "../../types";
import { getProof, supportedChainIdsOutbox } from "./subgraph";

const getProofAtCount = async (
chainid: Supported<typeof supportedChainIdsOutbox>,
nonce: number,
count: number
): Promise<string[]> => {
const proofIndices = getProofIndices(nonce, count);
const rawProof = await getProof(chainid, { proofIndices });
//rawproof is ordered by id, we want same order as proofIndices
rawProof.nodes.sort((a, b) => proofIndices.indexOf(a.id) - proofIndices.indexOf(b.id));
return rawProof.nodes.reduce((acc, node) => {
acc.push(node);
return acc;
}, []);
};

const getProofIndices = (nonce: number, count: number): string[] => {
let proof: string[] = [];
if (nonce >= count) return proof;

const treeDepth = Math.ceil(Math.log2(count));

for (let i = 0; i < treeDepth; i++) {
if (i == 0 && (nonce ^ 1) < count) proof.push((nonce ^ 1).toString()); // sibling
else {
const low = ((nonce >> i) ^ 1) << i;
const high = Math.min(low + Math.pow(2, i) - 1, count - 1);
if (low < count - 1) proof.push(low.toString() + "," + high.toString());
else if (low == count - 1) proof.push(low.toString());
}
}

return proof;
};

export { getProofAtCount };
36 changes: 36 additions & 0 deletions relayer-cli/functions/utils/relay.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { getProofAtCount } from "./proof";
import {
getInboxCount,
supportedChainIdsOutbox,
getInboxMsgData,
getInboxNonceFromSender,
rpcUrlOutbox,
veaOutboxFromArbGoerliTo,
} from "./subgraph";
import { getVeaOutboxArbToEth } from "./ethers";
import { Supported } from "../../types";

export const relay = async (chainIdOutbox: Supported<typeof supportedChainIdsOutbox>, nonce: number) => {
const veaOutbox = getVeaOutboxArbToEth(
veaOutboxFromArbGoerliTo[chainIdOutbox],
process.env.PRIVATE_KEY,
rpcUrlOutbox[chainIdOutbox]
);
const stateRoot = await veaOutbox.stateRoot();
const count = await getInboxCount(chainIdOutbox, { stateRoot });
const proof = await getProofAtCount(chainIdOutbox, nonce, count.snapshotSaveds[0].count);
const msgData = await getInboxMsgData(chainIdOutbox, { nonce: [nonce] });
const txn = await veaOutbox.sendMessage(proof, nonce, msgData.messageSents[0].to.id, msgData.messageSents[0].data);
await txn.wait();
};

export const relayAllFor = async (
chainIdOutbox: Supported<typeof supportedChainIdsOutbox>,
nonce: number,
sender: string
) => {
const nonces = await getInboxNonceFromSender(chainIdOutbox, { nonce, msgSender: sender });
for (const n of nonces.messageSents) {
await relay(chainIdOutbox, n.nonce);
}
};
108 changes: 108 additions & 0 deletions relayer-cli/functions/utils/subgraph.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { GraphQLClient } from "graphql-request";
import { arbitrumGoerli, goerli, gnosisChiado } from "viem/chains";
import {
GetCountQuery,
GetMsgDataQuery,
GetProofQuery,
GetNonceFromQuery,
Sdk,
getSdk,
} from "../../generated/vea-inbox";

import { Supported } from "../../types";

const subgraphInboxArbGoerliFrom = {
[arbitrumGoerli.id]: "https://api.thegraph.com/subgraphs/name/shotaronowhere/vea-inbox-arbgoerli-to-goerli",
[gnosisChiado.id]: "https://api.thegraph.com/subgraphs/name/shotaronowhere/vea-inbox-arbgoerli-to-chiado",
} as const;

export const sdksInboxArbGoerliFrom = Object.entries(subgraphInboxArbGoerliFrom).reduce((acc, [chainId, url]) => {
return {
...acc,
[+chainId]: getSdk(new GraphQLClient(url)),
};
}, {} as Record<Supported<(keyof typeof subgraphInboxArbGoerliFrom)[]>, Sdk>);

export const supportedChainIdsInbox = [arbitrumGoerli.id];

export const supportedChainIdsOutbox = [gnosisChiado.id, goerli.id];

require("dotenv").config();
const {
RPC_URL_CHIADO,
RPC_URL_GOERLI,
RPC_URL_ARB_GOERLI,
VEAOUTBOX_ARBGOERLI_TO_GOERLI_ADDRESS,
VEAOUTBOX_ARBGOERLI_TO_CHIADO_ADDRESS,
} = process.env;

export const rpcUrlInbox = {
[arbitrumGoerli.id]: RPC_URL_ARB_GOERLI,
};

export const rpcUrlOutbox = {
[gnosisChiado.id]: RPC_URL_CHIADO,
[goerli.id]: RPC_URL_GOERLI,
};

export const veaOutboxFromArbGoerliTo = {
[gnosisChiado.id]: VEAOUTBOX_ARBGOERLI_TO_CHIADO_ADDRESS,
[goerli.id]: VEAOUTBOX_ARBGOERLI_TO_GOERLI_ADDRESS,
};

export const getInboxCount = async (chainId: Supported<typeof supportedChainIdsOutbox>, params: { stateRoot: any }) => {
let res: GetCountQuery | undefined = undefined;
try {
res = await sdksInboxArbGoerliFrom[chainId as Supported<(keyof typeof subgraphInboxArbGoerliFrom)[]>]["GetCount"](
params
);
} catch (e) {
console.error(e);
}
return res;
};

export const getInboxMsgData = async (
chainId: Supported<typeof supportedChainIdsOutbox>,
params: { nonce: number[] }
) => {
let res: GetMsgDataQuery | undefined = undefined;
try {
res = await sdksInboxArbGoerliFrom[chainId as Supported<(keyof typeof subgraphInboxArbGoerliFrom)[]>]["GetMsgData"](
params
);
} catch (e) {
console.error(e);
}
return res;
};

export const getInboxNonceFromSender = async (
chainId: Supported<typeof supportedChainIdsOutbox>,
params: { nonce: any; msgSender: any }
) => {
let res: GetNonceFromQuery | undefined = undefined;
try {
res = await sdksInboxArbGoerliFrom[chainId as Supported<(keyof typeof subgraphInboxArbGoerliFrom)[]>][
"GetNonceFrom"
](params);
} catch (e) {
console.error(e);
}
return res;
};

export const getProof = async (
chainId: Supported<typeof supportedChainIdsOutbox>,
params: { proofIndices: string | string[] }
) => {
let res: GetProofQuery | undefined = undefined;
try {
res = await sdksInboxArbGoerliFrom[chainId as Supported<(keyof typeof subgraphInboxArbGoerliFrom)[]>]["GetProof"](
params
);
} catch (e) {
console.error(e);
}
return res;
};
Loading

0 comments on commit e070f23

Please sign in to comment.