-
Notifications
You must be signed in to change notification settings - Fork 1
docs: L2 bridging doc #97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
WalkthroughAdds BaseSepolia network support, Alchemy/Etherscan configuration, new relay tooling (Hardhat task relay-op), viem/ethers5 updates, zksync proof script changes, bridging docs, metaevidence & deployment artifacts for baseSepolia, and related scripts/package updates. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant HTask as Hardhat Task (relay-op)
participant L2 as L2 RPC / Public Client
participant L1 as L1 RPC / Wallet Client
User->>HTask: run relay-op --txhash <tx>
HTask->>L2: fetchTransactionReceipt(tx)
L2-->>HTask: l2Receipt
alt waiting-to-prove
HTask->>HTask: waitToProve(poll)
Note right of HTask: polls until proof available
else ready-to-prove
HTask->>L2: buildProveWithdrawal(l2Receipt)
L2-->>HTask: proof
HTask->>L1: proveWithdrawal(proof)
L1-->>HTask: proofSubmitted
end
alt ready-to-finalize
HTask->>L1: finalizeWithdrawal()
L1-->>HTask: finalized
else waiting-to-finalize
HTask->>HTask: waitForFinalizationWindow()
end
HTask-->>User: log final status
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
contracts/scripts/get_event_properties.js (1)
29-44: Restore ethers v5-compatible helpers.
ethers.idandethers.AbiCoder.defaultAbiCoder()only exist in ethers v6. The repo still runs on ethers v5 (e.g.,contracts/tasks/relay-arbitrum.jsrequires"ethers5"and the docs stress the v5 requirement), so these calls will throw at runtime, breaking selector derivation and encoding. Please keep using the v5ethers.utilshelpers until the toolchain is upgraded.Apply this diff to fix the regression:
const topicHash = "0x3a36e47291f4201faf137fab081d92295bce2d53be2c6ca68ba82c7faa9ce241"; // L1MessageSent const eventLogs = receipt.logs.filter((log) => log.topics[0] === topicHash); @@ function getFunctionSelector(functionSignature) { - const hash = ethers.id(functionSignature); + const hash = ethers.utils.id(functionSignature); const selector = hash.slice(0, 10); // 0x + first 4 bytes return selector; } @@ - return ethers.AbiCoder.defaultAbiCoder().encode([param.type], [param.value]).slice(2); + return ethers.utils.defaultAbiCoder.encode([param.type], [param.value]).slice(2); });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (9)
contracts/.env.example(1 hunks)contracts/docs/Bridging.md(1 hunks)contracts/hardhat.config.ts(6 hunks)contracts/hardhat.config.zksync.ts(0 hunks)contracts/package.json(3 hunks)contracts/scripts/execute_proof.js(5 hunks)contracts/scripts/get_event_properties.js(2 hunks)contracts/tasks/relay-arbitrum.js(3 hunks)contracts/tasks/relay-op.js(1 hunks)
💤 Files with no reviewable changes (1)
- contracts/hardhat.config.zksync.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-03-24T14:46:25.118Z
Learnt from: jaybuidl
Repo: kleros/cross-chain-realitio-proxy PR: 68
File: dynamic-script/package.json:2-4
Timestamp: 2025-03-24T14:46:25.118Z
Learning: The kleros/cross-chain-realitio-dynamic-script package is distributed via IPFS CID, not through NPM, so package name changes don't create breaking changes for consumers.
Applied to files:
contracts/package.json
🧬 Code graph analysis (4)
contracts/tasks/relay-op.js (3)
contracts/scripts/execute_proof.js (4)
require(3-3)require(4-4)hre(1-1)chainId(16-16)contracts/tasks/relay-arbitrum.js (5)
require(1-1)require(2-2)require(3-3)chainId(25-25)receipt(43-43)contracts/scripts/get_event_properties.js (2)
receipt(2-2)receipt(57-57)
contracts/scripts/get_event_properties.js (1)
contracts/scripts/execute_proof.js (1)
ethers(2-2)
contracts/tasks/relay-arbitrum.js (3)
contracts/scripts/execute_proof.js (5)
require(3-3)require(4-4)l2Receipt(45-45)l2Receipt(49-49)l2Provider(19-19)contracts/tasks/relay-op.js (7)
require(1-1)require(3-7)require(9-9)require(11-16)require(17-17)receipt(69-69)l1Wallet(52-55)contracts/scripts/get_event_properties.js (2)
receipt(2-2)receipt(57-57)
contracts/scripts/execute_proof.js (4)
contracts/tasks/relay-arbitrum.js (8)
require(1-1)require(2-2)require(3-3)foreignNetworks(21-24)chainId(25-25)l1Provider(28-28)l2Provider(29-29)l2Receipt(44-44)contracts/tasks/relay-op.js (6)
require(1-1)require(3-7)require(9-9)require(11-16)require(17-17)chainId(39-39)contracts/tasks/update-deployments.js (4)
require(1-1)require(3-3)homeProxyContract(84-84)foreignProxyContract(143-143)contracts/deploy/home/polygon.js (1)
homeProxy(31-31)
🪛 dotenv-linter (4.0.0)
contracts/.env.example
[warning] 2-2: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
[warning] 2-2: [UnorderedKey] The ALCHEMY_API_KEY key should go before the PRIVATE_KEY key
(UnorderedKey)
🪛 markdownlint-cli2 (0.18.1)
contracts/docs/Bridging.md
9-9: Bare URL used
(MD034, no-bare-urls)
24-24: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
33-33: Bare URL used
(MD034, no-bare-urls)
40-40: Bare URL used
(MD034, no-bare-urls)
53-53: Bare URL used
(MD034, no-bare-urls)
62-62: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
73-73: Bare URL used
(MD034, no-bare-urls)
74-74: Bare URL used
(MD034, no-bare-urls)
80-80: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
97-97: Bare URL used
(MD034, no-bare-urls)
| const blockNumber = l1MessageSentEvent.blockNumber; | ||
| const homeProxy = `0x${BigInt(l1MessageSentEvent.address).toString(16)}`; | ||
| const msgHash = l1MessageSentEvent.msgHash; | ||
| const eventData = await getCalldata(txHash, l1Provider); | ||
| const homeProxyContract = new ethers.Contract(homeProxy, RealitioHomeArbitrationProxy.abi, l1Provider); | ||
| const eventData = await getCalldata(txHash, l2Provider); | ||
| const homeProxyContract = new ethers.Contract(homeProxy, RealitioHomeArbitrationProxy.abi, l2Provider); | ||
| console.log(await homeProxyContract.foreignProxy()); | ||
| const foreignProxyContract = new ethers.Contract( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Preserve the proxy address formatting
Casting l1MessageSentEvent.address to BigInt and back removes any leading zeros, so ethers.Contract will reject addresses whose high nibble is 0x0. Use the address string directly (normalized with ethers.getAddress) to avoid intermittent failures.
Apply this diff:
- const homeProxy = `0x${BigInt(l1MessageSentEvent.address).toString(16)}`;
+ const homeProxy = ethers.getAddress(l1MessageSentEvent.address);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const blockNumber = l1MessageSentEvent.blockNumber; | |
| const homeProxy = `0x${BigInt(l1MessageSentEvent.address).toString(16)}`; | |
| const msgHash = l1MessageSentEvent.msgHash; | |
| const eventData = await getCalldata(txHash, l1Provider); | |
| const homeProxyContract = new ethers.Contract(homeProxy, RealitioHomeArbitrationProxy.abi, l1Provider); | |
| const eventData = await getCalldata(txHash, l2Provider); | |
| const homeProxyContract = new ethers.Contract(homeProxy, RealitioHomeArbitrationProxy.abi, l2Provider); | |
| console.log(await homeProxyContract.foreignProxy()); | |
| const foreignProxyContract = new ethers.Contract( | |
| const blockNumber = l1MessageSentEvent.blockNumber; | |
| const homeProxy = ethers.getAddress(l1MessageSentEvent.address); | |
| const msgHash = l1MessageSentEvent.msgHash; | |
| const eventData = await getCalldata(txHash, l2Provider); | |
| const homeProxyContract = new ethers.Contract(homeProxy, RealitioHomeArbitrationProxy.abi, l2Provider); | |
| console.log(await homeProxyContract.foreignProxy()); | |
| const foreignProxyContract = new ethers.Contract( |
🤖 Prompt for AI Agents
In contracts/scripts/execute_proof.js around lines 27 to 33, the code converts
l1MessageSentEvent.address to BigInt and back which strips leading zeros and can
create invalid addresses for ethers.Contract; replace that conversion with the
original address string normalized via ethers.getAddress (or ensure it already
starts with "0x" and pass ethers.getAddress(l1MessageSentEvent.address)) so the
resulting homeProxy preserves leading zeros and is a checksummed valid address
for the Contract constructor.
| const l1Wallet = createWalletClient({ | ||
| account, | ||
| transport: http(l1RpcUrl), | ||
| }).extend(walletActionsL1()); | ||
|
|
||
| // L2 clients | ||
| const l2Public = createPublicClient({ | ||
| chain: chain.l2, | ||
| transport: http(l2RpcUrl), | ||
| }).extend(publicActionsL2()); | ||
|
|
||
| const l2Wallet = createWalletClient({ | ||
| account, | ||
| transport: http(l2RpcUrl), | ||
| }).extend(walletActionsL2()); | ||
|
|
||
| // Retrieve L2 tx | ||
| const receipt = await l2Public.getTransactionReceipt({ hash: txhash }); | ||
| const status = await l1Public.getWithdrawalStatus({ | ||
| receipt, | ||
| targetChain: l2Public.chain, | ||
| }); | ||
|
|
||
| console.log(`Withdrawal status: ${status}`); | ||
|
|
||
| const { output, withdrawal } = await l1Public.waitToProve({ | ||
| receipt, | ||
| targetChain: l2Public.chain, | ||
| }); | ||
|
|
||
| // Only prove if necessary | ||
| // Note that proving the message resets the 1 week timeout each time, so this condition is mandatory. | ||
| if (status === "waiting-to-prove" || status === "ready-to-prove") { | ||
| console.log("Proving withdrawal..."); | ||
|
|
||
| const proveArgs = await l2Public.buildProveWithdrawal({ | ||
| account, | ||
| output, | ||
| withdrawal | ||
| }); | ||
|
|
||
| // Note that proof cant be obtained with Infura RPC | ||
| await l1Wallet.proveWithdrawal(proveArgs); | ||
| console.log("Proven ✅"); | ||
| } | ||
|
|
||
| if (status === "ready-to-finalize") { | ||
| // Not required by this script but keep in case bots need it | ||
| /* | ||
| console.log("Waiting until message becomes relayable..."); | ||
| await l1Public.waitToFinalize({ | ||
| targetChain: l2Public.chain, | ||
| withdrawalHash: receipt.transactionHash | ||
| });*/ | ||
|
|
||
| console.log("Finalizing withdrawal..."); | ||
| await l1Wallet.finalizeWithdrawal({ | ||
| targetChain: l2Wallet.chain, | ||
| withdrawal, | ||
| }); | ||
| console.log("Done ✅"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Set wallet clients' chains to avoid undefined targetChain.
Both wallet clients are created without a chain, so l2Wallet.chain is undefined. When you reach the finalizeWithdrawal branch, targetChain: l2Wallet.chain ends up undefined and viem will reject the call at runtime. Provide the chain upfront (and reuse chain.l2 directly when finalizing) so the task can actually submit the finalization.
Apply this diff to fix the issue:
const l1Public = createPublicClient({
chain: chain.l1,
transport: http(l1RpcUrl),
}).extend(publicActionsL1());
const l1Wallet = createWalletClient({
account,
+ chain: chain.l1,
transport: http(l1RpcUrl),
}).extend(walletActionsL1());
// L2 clients
const l2Public = createPublicClient({
chain: chain.l2,
transport: http(l2RpcUrl),
}).extend(publicActionsL2());
const l2Wallet = createWalletClient({
account,
+ chain: chain.l2,
transport: http(l2RpcUrl),
}).extend(walletActionsL2());
@@
console.log("Finalizing withdrawal...");
await l1Wallet.finalizeWithdrawal({
- targetChain: l2Wallet.chain,
+ targetChain: chain.l2,
withdrawal,
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const l1Wallet = createWalletClient({ | |
| account, | |
| transport: http(l1RpcUrl), | |
| }).extend(walletActionsL1()); | |
| // L2 clients | |
| const l2Public = createPublicClient({ | |
| chain: chain.l2, | |
| transport: http(l2RpcUrl), | |
| }).extend(publicActionsL2()); | |
| const l2Wallet = createWalletClient({ | |
| account, | |
| transport: http(l2RpcUrl), | |
| }).extend(walletActionsL2()); | |
| // Retrieve L2 tx | |
| const receipt = await l2Public.getTransactionReceipt({ hash: txhash }); | |
| const status = await l1Public.getWithdrawalStatus({ | |
| receipt, | |
| targetChain: l2Public.chain, | |
| }); | |
| console.log(`Withdrawal status: ${status}`); | |
| const { output, withdrawal } = await l1Public.waitToProve({ | |
| receipt, | |
| targetChain: l2Public.chain, | |
| }); | |
| // Only prove if necessary | |
| // Note that proving the message resets the 1 week timeout each time, so this condition is mandatory. | |
| if (status === "waiting-to-prove" || status === "ready-to-prove") { | |
| console.log("Proving withdrawal..."); | |
| const proveArgs = await l2Public.buildProveWithdrawal({ | |
| account, | |
| output, | |
| withdrawal | |
| }); | |
| // Note that proof cant be obtained with Infura RPC | |
| await l1Wallet.proveWithdrawal(proveArgs); | |
| console.log("Proven ✅"); | |
| } | |
| if (status === "ready-to-finalize") { | |
| // Not required by this script but keep in case bots need it | |
| /* | |
| console.log("Waiting until message becomes relayable..."); | |
| await l1Public.waitToFinalize({ | |
| targetChain: l2Public.chain, | |
| withdrawalHash: receipt.transactionHash | |
| });*/ | |
| console.log("Finalizing withdrawal..."); | |
| await l1Wallet.finalizeWithdrawal({ | |
| targetChain: l2Wallet.chain, | |
| withdrawal, | |
| }); | |
| console.log("Done ✅"); | |
| const l1Wallet = createWalletClient({ | |
| account, | |
| chain: chain.l1, | |
| transport: http(l1RpcUrl), | |
| }).extend(walletActionsL1()); | |
| // L2 clients | |
| const l2Public = createPublicClient({ | |
| chain: chain.l2, | |
| transport: http(l2RpcUrl), | |
| }).extend(publicActionsL2()); | |
| const l2Wallet = createWalletClient({ | |
| account, | |
| chain: chain.l2, | |
| transport: http(l2RpcUrl), | |
| }).extend(walletActionsL2()); | |
| // Retrieve L2 tx | |
| const receipt = await l2Public.getTransactionReceipt({ hash: txhash }); | |
| const status = await l1Public.getWithdrawalStatus({ | |
| receipt, | |
| targetChain: l2Public.chain, | |
| }); | |
| console.log(`Withdrawal status: ${status}`); | |
| const { output, withdrawal } = await l1Public.waitToProve({ | |
| receipt, | |
| targetChain: l2Public.chain, | |
| }); | |
| // Only prove if necessary | |
| // Note that proving the message resets the 1 week timeout each time, so this condition is mandatory. | |
| if (status === "waiting-to-prove" || status === "ready-to-prove") { | |
| console.log("Proving withdrawal..."); | |
| const proveArgs = await l2Public.buildProveWithdrawal({ | |
| account, | |
| output, | |
| withdrawal | |
| }); | |
| // Note that proof cant be obtained with Infura RPC | |
| await l1Wallet.proveWithdrawal(proveArgs); | |
| console.log("Proven ✅"); | |
| } | |
| if (status === "ready-to-finalize") { | |
| // Not required by this script but keep in case bots need it | |
| /* | |
| console.log("Waiting until message becomes relayable..."); | |
| await l1Public.waitToFinalize({ | |
| targetChain: l2Public.chain, | |
| withdrawalHash: receipt.transactionHash | |
| });*/ | |
| console.log("Finalizing withdrawal..."); | |
| await l1Wallet.finalizeWithdrawal({ | |
| targetChain: chain.l2, | |
| withdrawal, | |
| }); | |
| console.log("Done ✅"); |
🤖 Prompt for AI Agents
In contracts/tasks/relay-op.js around lines 52 to 112, both wallet clients are
created without specifying the chain which leaves l2Wallet.chain undefined and
causes finalizeWithdrawal to be called with an undefined targetChain; set the
chain explicitly when creating the wallet clients (use chain.l1 for l1Wallet and
chain.l2 for l2Wallet) or, alternatively, pass chain.l2 directly to
finalizeWithdrawal as targetChain; update the createWalletClient calls to
include chain: chain.l1 and chain: chain.l2 respectively (or replace
targetChain: l2Wallet.chain with targetChain: chain.l2) so the finalization call
receives a valid chain object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
contracts/hardhat.config.ts(6 hunks)
🔇 Additional comments (4)
contracts/hardhat.config.ts (4)
7-7: LGTM!The relay-op task import follows the established pattern and enables the new relay functionality for OP Stack chains.
272-289: LGTM! Past issue resolved.The
customChainsconfiguration is correct. Both base and polygon entries now have properbrowserURLvalues pointing to their respective block explorers. The previous issue with Polygon'sbrowserURLincorrectly pointing to Base's Blockscout has been resolved.
88-88: ALCHEMY_API_KEY is already documented in setup instructions.Verification confirms that
ALCHEMY_API_KEYis documented incontracts/docs/Bridging.mdunder the Requirements section, satisfying the concern raised in the review comment.
153-153: Etherscan v2 API configuration is correct and compatible.The v2 API URLs with chainid parameters are properly configured:
- Mainnet:
chainid=1matches networkchainId: 1- Polygon:
chainid=137matches networkchainId: 137- Other networks follow the same pattern consistently
Etherscan V2 requires a chainid parameter for multichain calls and is supported by Hardhat's verification tooling. The implementation matches the official format and no changes are required.
| apiKey: { | ||
| // These are separate from Ethereum's etherscan API key | ||
| optimisticEthereum: process.env.OPTIMISM_API_KEY!, | ||
| mainnet: process.env.ETHERSCAN_API_KEY!, | ||
| polygon: process.env.ETHERSCAN_API_KEY!, | ||
| base: process.env.ETHERSCAN_API_KEY! | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Use optional chaining or default values instead of non-null assertions.
The non-null assertion operator (!) on lines 267-270 will throw runtime errors if the environment variables are undefined. This can cause Hardhat to fail even for tasks that don't require Etherscan verification.
Consider using optional chaining with fallback values:
etherscan: {
apiKey: {
// These are separate from Ethereum's etherscan API key
- optimisticEthereum: process.env.OPTIMISM_API_KEY!,
- mainnet: process.env.ETHERSCAN_API_KEY!,
- polygon: process.env.ETHERSCAN_API_KEY!,
- base: process.env.ETHERSCAN_API_KEY!
+ optimisticEthereum: process.env.OPTIMISM_API_KEY || "",
+ mainnet: process.env.ETHERSCAN_API_KEY || "",
+ polygon: process.env.ETHERSCAN_API_KEY || "",
+ base: process.env.ETHERSCAN_API_KEY || ""
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| apiKey: { | |
| // These are separate from Ethereum's etherscan API key | |
| optimisticEthereum: process.env.OPTIMISM_API_KEY!, | |
| mainnet: process.env.ETHERSCAN_API_KEY!, | |
| polygon: process.env.ETHERSCAN_API_KEY!, | |
| base: process.env.ETHERSCAN_API_KEY! | |
| }, | |
| apiKey: { | |
| // These are separate from Ethereum's etherscan API key | |
| optimisticEthereum: process.env.OPTIMISM_API_KEY || "", | |
| mainnet: process.env.ETHERSCAN_API_KEY || "", | |
| polygon: process.env.ETHERSCAN_API_KEY || "", | |
| base: process.env.ETHERSCAN_API_KEY || "" | |
| }, |
🤖 Prompt for AI Agents
In contracts/hardhat.config.ts around lines 265 to 271, the apiKey entries use
non-null assertions (process.env.VAR!) which will throw at runtime if those env
vars are missing; replace the non-null assertions with a safe fallback by using
optional chaining or default values (e.g., process.env.OPTIMISM_API_KEY ?? "" or
process.env.OPTIMISM_API_KEY || "") so the config loads even when keys are
undefined, ensuring tasks that don’t need Etherscan won’t fail.
| For Reality Cross-chain proxies L1 → L2 bridging is automatic for every bridge. | ||
| However, L2 → L1 bridging requires manual steps, which differ by chain. | ||
| Use this guide until bots are configured to handle everything automatically. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@unknownunknown1 this doc is very useful, thanks!
Would be nice if we can have the full cycle and specify all the methods that must be called until the bot is there.
For example, the L1->L2 usually is automatically bridged as you have said, but we need to call handleNotifiedRequest or handleRejectedRequest after receiveArbitrationRequest is automatically called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is not much to add to be honest. handleNotifiedRequest is the default function, while handleRejectedRequest is rather edge case. But I will add the steps for relaying the question back to Reality as it's a bit tricky
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
♻️ Duplicate comments (1)
contracts/hardhat.config.ts (1)
276-284: Non-null assertions on environment variables may cause runtime errors.As noted in a previous review, the non-null assertions (
!) on lines 278-283 will throw runtime errors if the environment variables are undefined, causing Hardhat to fail even for tasks that don't require Etherscan verification.Based on previous review feedback, apply this diff to use safe fallbacks:
etherscan: { apiKey: { // These are separate from Ethereum's etherscan API key - optimisticEthereum: process.env.OPTIMISM_API_KEY!, - mainnet: process.env.ETHERSCAN_API_KEY!, - polygon: process.env.ETHERSCAN_API_KEY!, - base: process.env.ETHERSCAN_API_KEY!, - baseSepolia: process.env.ETHERSCAN_API_KEY!, - sepolia: process.env.ETHERSCAN_API_KEY! + optimisticEthereum: process.env.OPTIMISM_API_KEY || "", + mainnet: process.env.ETHERSCAN_API_KEY || "", + polygon: process.env.ETHERSCAN_API_KEY || "", + base: process.env.ETHERSCAN_API_KEY || "", + baseSepolia: process.env.ETHERSCAN_API_KEY || "", + sepolia: process.env.ETHERSCAN_API_KEY || "" },
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
contracts/deploy/foreign/optimism.js(2 hunks)contracts/deploy/home/optimism.js(2 hunks)contracts/deployments/baseSepolia/.chainId(1 hunks)contracts/deployments/baseSepolia/RealitioHomeProxyBase.json(1 hunks)contracts/hardhat.config.ts(8 hunks)contracts/metaevidence-cids.json(1 hunks)contracts/package.json(5 hunks)contracts/scripts/chains.env(1 hunks)contracts/tasks/relay-op.js(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- contracts/deployments/baseSepolia/RealitioHomeProxyBase.json
- contracts/deployments/baseSepolia/.chainId
🚧 Files skipped from review as they are similar to previous changes (1)
- contracts/tasks/relay-op.js
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-03-24T14:46:25.118Z
Learnt from: jaybuidl
Repo: kleros/cross-chain-realitio-proxy PR: 68
File: dynamic-script/package.json:2-4
Timestamp: 2025-03-24T14:46:25.118Z
Learning: The kleros/cross-chain-realitio-dynamic-script package is distributed via IPFS CID, not through NPM, so package name changes don't create breaking changes for consumers.
Applied to files:
contracts/package.json
🧬 Code graph analysis (1)
contracts/deploy/home/optimism.js (5)
contracts/deploy/shared/chains.js (1)
homeChains(28-28)contracts/deploy/home/polygon.js (1)
homeChains(4-4)contracts/deploy/home/arbitrum.js (1)
homeChains(3-3)contracts/deploy/home/gnosis.js (1)
homeChains(3-3)contracts/deploy/home/zksync.js (1)
homeChains(4-4)
🔇 Additional comments (11)
contracts/scripts/chains.env (1)
14-14: LGTM! BaseSepolia testnet integration looks good.The additions follow the established pattern for testnet configurations, with the explorer URL correctly pointing to Base's Sepolia block explorer.
Also applies to: 22-22
contracts/metaevidence-cids.json (1)
16-16: LGTM! Metaevidence CID for baseSepolia added.The entry follows the same pattern as other network metaevidence mappings.
contracts/package.json (4)
17-25: New relay scripts added for multiple networks.The relay scripts follow a consistent pattern across staging, production, and various OP-stack networks.
34-34: BaseSepolia deployment and metaevidence scripts added.The scripts follow the established pattern for other testnet deployments.
Also applies to: 51-53
129-129: viem library is actively used in the codebase and necessary.viem (v2.38.3) is imported and used across multiple files including
sdk/src/lib.ts,sdk/src/contracts.ts, test files, andcontracts/tasks/relay-op.js. It provides essential Ethereum client utilities (createPublicClient, createWalletClient, getContract, Transport types) that serve a different purpose than ethers—viem offers low-level client operations while ethers provides higher-level abstractions. The dependency addition is justified.
106-106: Dual ethers versions serve distinct purposes and are actively used.The
ethers5alias is required by the Arbitrum relay task (contracts/tasks/relay-arbitrum.js), which uses ethers v5 APIs. The main codebase uses ethers v6 with TypeChain integration. This is a legitimate architectural choice for cross-chain operations, not unnecessary bloat.contracts/hardhat.config.ts (2)
7-7: New relay-op task imported.This task enables the relay operations for OP-stack networks including baseSepolia.
285-319: Etherscan custom chains configuration looks good.The custom chains configuration properly defines Base, BaseSepolia, Sepolia, and Polygon networks with their respective Etherscan v2 API endpoints and block explorer URLs.
contracts/deploy/home/optimism.js (1)
3-3: BaseSepolia added to home chains.The destructuring correctly includes baseSepolia alongside other OP-stack networks.
contracts/deploy/foreign/optimism.js (2)
11-16: BaseSepolia foreign proxy parameters added.The configuration follows the established pattern for testnet deployments with 1 juror and includes the proper Base Sepolia L1StandardBridge address with documentation reference.
43-43: Documentation URL updated for Base network.The comment now points to the correct Base documentation URL.
| [baseSepolia.chainId]: { | ||
| realitio: "0x86b653Dc9aa6d7311109276925927087573f91CB", | ||
| variant: "Base", | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, check if node_modules exists and examine the reality.eth config
if [ -f "node_modules/@reality.eth/contracts/config.json" ]; then
echo "=== Reality.eth config found ==="
cat node_modules/@reality.eth/contracts/config.json | jq '.' || cat node_modules/@reality.eth/contracts/config.json
else
echo "Config file not found at expected location"
# Try to find the package
find . -name "@reality.eth" -type d 2>/dev/null | head -5
fiRepository: kleros/cross-chain-realitio-proxy
Length of output: 119
🏁 Script executed:
# Examine the optimism.js file to understand the context and pattern
wc -l contracts/deploy/home/optimism.js
head -50 contracts/deploy/home/optimism.jsRepository: kleros/cross-chain-realitio-proxy
Length of output: 2021
🏁 Script executed:
# Search for realityETHConfig usage in the codebase
rg "realityETHConfig" -A 3 -B 1Repository: kleros/cross-chain-realitio-proxy
Length of output: 7137
🏁 Script executed:
# Verify the baseSepolia chainId and search for any comments about why it's hardcoded
rg "baseSepolia" -A 2 -B 2Repository: kleros/cross-chain-realitio-proxy
Length of output: 6398
🏁 Script executed:
# Check package.json for @reality.eth/contracts version and any related comments
cat contracts/package.json | jq '.dependencies | select(.["@reality.eth/contracts"])'Repository: kleros/cross-chain-realitio-proxy
Length of output: 59
🏁 Script executed:
# Search for any comments or documentation about baseSepolia or the hardcoded address
rg "0x86b653Dc9aa6d7311109276925927087573f91CB" -B 5 -A 5Repository: kleros/cross-chain-realitio-proxy
Length of output: 1856
🏁 Script executed:
# Look for any historical context or TODOs related to baseSepolia Realitio
rg "baseSepolia|Base.*Sepolia" contracts/deploy/home/ -A 3 -B 1Repository: kleros/cross-chain-realitio-proxy
Length of output: 839
Add documentation for the hardcoded baseSepolia Realitio address.
baseSepolia is the only network in this file using a hardcoded Realitio address (0x86b653Dc9aa6d7311109276925927087573f91CB) instead of realityETHConfig(chainId, "ETH", "3.0").address like unichainSepolia, optimismSepolia, and other networks. The address is confirmed deployed and active, but lacks explanation for why hardcoding is necessary. Add a comment clarifying whether this is due to baseSepolia being unsupported by the @reality.eth/contracts library or if this is an intentional custom deployment.
🤖 Prompt for AI Agents
In contracts/deploy/home/optimism.js around lines 16–19, the baseSepolia entry
uses a hardcoded Realitio address without explanation; add a concise comment
above that object explaining why it's hardcoded (state whether baseSepolia is
unsupported by @reality.eth/contracts, or this is a deliberate custom
deployment), include provenance (transaction/verification link or reference to
how the address was confirmed) and note whether switching to
realityETHConfig(chainId, "ETH", "3.0").address was considered and why it was
not used; ensure the comment is one or two lines and clear for future
maintainers.
| optimismSepolia: { | ||
| chainId: 11155420, | ||
| url: `https://optimism-sepolia.infura.io/v3/${process.env.INFURA_API_KEY}`, | ||
| url: `https://opt-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Check if .env.example exists and examine its contents
fd -t f '.env.example' --exec cat {}Repository: kleros/cross-chain-realitio-proxy
Length of output: 59
🏁 Script executed:
# Also check the hardhat.config.ts file to see the lines in question
wc -l contracts/hardhat.config.tsRepository: kleros/cross-chain-realitio-proxy
Length of output: 108
🏁 Script executed:
# Read the relevant sections of hardhat.config.ts (lines 85-95, 195-210, 225-240)
sed -n '85,95p;195,210p;225,240p' contracts/hardhat.config.ts | cat -nRepository: kleros/cross-chain-realitio-proxy
Length of output: 1754
🏁 Script executed:
# Search for any documentation that mentions ALCHEMY_API_KEY
rg 'ALCHEMY_API_KEY' --type-list | head -20Repository: kleros/cross-chain-realitio-proxy
Length of output: 466
🏁 Script executed:
# Search for ALCHEMY_API_KEY usage in the codebase
rg 'ALCHEMY_API_KEY' --type tsRepository: kleros/cross-chain-realitio-proxy
Length of output: 1042
🏁 Script executed:
# Get exact lines 201 and 231 with context
sed -n '195,210p' contracts/hardhat.config.ts | cat -n
echo "---"
sed -n '225,235p' contracts/hardhat.config.ts | cat -nRepository: kleros/cross-chain-realitio-proxy
Length of output: 1066
🏁 Script executed:
# Check for documentation files (README, setup guides, etc.)
fd -t f '(README|readme|SETUP|setup|\.env\.example)' --extension md --extension txt --extension rstRepository: kleros/cross-chain-realitio-proxy
Length of output: 106
🏁 Script executed:
# Check if any .env files or examples exist
fd -t f -e envRepository: kleros/cross-chain-realitio-proxy
Length of output: 105
🏁 Script executed:
# Check README.md for ALCHEMY_API_KEY
rg 'ALCHEMY_API_KEY' README.mdRepository: kleros/cross-chain-realitio-proxy
Length of output: 59
🏁 Script executed:
# Check contracts/README.md for ALCHEMY_API_KEY
rg 'ALCHEMY_API_KEY' contracts/README.mdRepository: kleros/cross-chain-realitio-proxy
Length of output: 59
🏁 Script executed:
# Check chains.env content
cat contracts/scripts/chains.envRepository: kleros/cross-chain-realitio-proxy
Length of output: 1431
🏁 Script executed:
# Look at the root README to understand setup instructions
head -100 README.mdRepository: kleros/cross-chain-realitio-proxy
Length of output: 5536
Add ALCHEMY_API_KEY to documentation and create .env.example.
ALCHEMY_API_KEY is used across multiple networks (optimismSepolia, optimism, base, baseSepolia, gnosis) in hardhat.config.ts and SDK tests, but is not documented in the project's setup instructions or .env guidance. Create a .env.example file with ALCHEMY_API_KEY listed, and update README.md (or contracts/README.md) to mention this requirement in the "Adding support for a new chain" and environment setup sections.
🤖 Prompt for AI Agents
In contracts/hardhat.config.ts around line 89, ALCHEMY_API_KEY is referenced for
network RPCs but is not documented; add ALCHEMY_API_KEY to project setup docs
and provide a .env.example. Update README.md (or contracts/README.md) to mention
ALCHEMY_API_KEY in the "Adding support for a new chain" and environment setup
sections, and create a top-level .env.example file that lists ALCHEMY_API_KEY
(with placeholder value and brief comment) alongside other env vars so
contributors know to set it before running tests or configuring networks.
| baseSepolia: { | ||
| chainId: 84532, | ||
| url: `https://base-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`, | ||
| // url: `http://127.0.0.1:8547`, // fork with `anvil --fork-url https://optimism-sepolia.infura.io/v3/${process.env.INFURA_API_KEY} --port 8547` | ||
| accounts: [process.env.PRIVATE_KEY as string], | ||
| tags: ["home"], | ||
| companionNetworks: { | ||
| foreign: "sepolia", | ||
| }, | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BaseSepolia network configuration missing verification settings.
Unlike other networks in the config (e.g., optimismSepolia at lines 96-101, arbitrumSepolia at lines 122-127), the baseSepolia network is missing the verify.etherscan configuration block. This will prevent contract verification on the Base Sepolia explorer.
Apply this diff to add verification settings:
baseSepolia: {
chainId: 84532,
url: `https://base-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`,
// url: `http://127.0.0.1:8547`, // fork with `anvil --fork-url https://optimism-sepolia.infura.io/v3/${process.env.INFURA_API_KEY} --port 8547`
accounts: [process.env.PRIVATE_KEY as string],
tags: ["home"],
companionNetworks: {
foreign: "sepolia",
},
+ verify: {
+ etherscan: {
+ apiUrl: "https://api-sepolia.basescan.org/api",
+ apiKey: process.env.BASESCAN_API_KEY,
+ },
+ },
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| baseSepolia: { | |
| chainId: 84532, | |
| url: `https://base-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`, | |
| // url: `http://127.0.0.1:8547`, // fork with `anvil --fork-url https://optimism-sepolia.infura.io/v3/${process.env.INFURA_API_KEY} --port 8547` | |
| accounts: [process.env.PRIVATE_KEY as string], | |
| tags: ["home"], | |
| companionNetworks: { | |
| foreign: "sepolia", | |
| }, | |
| }, | |
| baseSepolia: { | |
| chainId: 84532, | |
| url: `https://base-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`, | |
| // url: `http://127.0.0.1:8547`, // fork with `anvil --fork-url https://optimism-sepolia.infura.io/v3/${process.env.INFURA_API_KEY} --port 8547` | |
| accounts: [process.env.PRIVATE_KEY as string], | |
| tags: ["home"], | |
| companionNetworks: { | |
| foreign: "sepolia", | |
| }, | |
| verify: { | |
| etherscan: { | |
| apiUrl: "https://api-sepolia.basescan.org/api", | |
| apiKey: process.env.BASESCAN_API_KEY, | |
| }, | |
| }, | |
| }, |
🤖 Prompt for AI Agents
In contracts/hardhat.config.ts around lines 103 to 112, the baseSepolia network
is missing the verify.etherscan configuration needed for contract verification;
add a verify block under baseSepolia that configures etherscan verification by
referencing the appropriate API key env var (e.g., process.env.ETHERSCAN_API_KEY
or a BASE-specific key), and include a customChains entry for Base Sepolia with
network name 'base', chainId 84532, and the correct API and browser URLs for the
Base Sepolia explorer so Hardhat can locate the verification endpoints.
| baseSepolia: { | ||
| chainId: 84532, | ||
| url: `https://base-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`, | ||
| // url: `http://127.0.0.1:8547`, // fork with `anvil --fork-url https://optimism-sepolia.infura.io/v3/${process.env.INFURA_API_KEY} --port 8547` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix misleading comment for baseSepolia.
The comment references "optimism-sepolia" but this is the baseSepolia network configuration.
Apply this diff:
- // url: `http://127.0.0.1:8547`, // fork with `anvil --fork-url https://optimism-sepolia.infura.io/v3/${process.env.INFURA_API_KEY} --port 8547`
+ // url: `http://127.0.0.1:8547`, // fork with `anvil --fork-url https://base-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY} --port 8547`📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // url: `http://127.0.0.1:8547`, // fork with `anvil --fork-url https://optimism-sepolia.infura.io/v3/${process.env.INFURA_API_KEY} --port 8547` | |
| // url: `http://127.0.0.1:8547`, // fork with `anvil --fork-url https://base-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY} --port 8547` |
🤖 Prompt for AI Agents
In contracts/hardhat.config.ts around line 106, the inline comment mistakenly
references "optimism-sepolia" while this is the baseSepolia network config;
update the comment to reference base Sepolia (e.g., use sepolia.infura.io URL)
and adjust the example fork command to `anvil --fork-url
https://sepolia.infura.io/v3/${process.env.INFURA_API_KEY} --port 8547` (or
otherwise state "base Sepolia") so the comment accurately reflects the network
being forked.
| "dependencies": { | ||
| "@arbitrum/nitro-contracts": "^1.3.0", | ||
| "@arbitrum/sdk": "^v3.1.9", | ||
| "@arbitrum/sdk": "^4.0.4", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
@arbitrum/sdk v4.0.0 breaking changes migration guide
💡 Result:
Here’s a concise migration checklist for @arbitrum/sdk v3 → v4 with the main breaking changes and quick code notes.
- Terminology and API renames
- L1/L2 → parent/child terminology; many types/functions renamed accordingly. Use Parent/Child where appropriate. [1]
- Network types & registration
- L2Network → ArbitrumNetwork; getL2Network → getArbitrumNetwork; l2Networks → getArbitrumNetworks.
- L1Network, Network, getL1Network, getParentForNetwork removed.
- Only Arbitrum networks (Arbitrum One, Arbitrum testnets, Orbit chains) are registered; use registerCustomArbitrumNetwork and getArbitrumNetworks / getChildrenForNetwork. [1][2]
- Bridger classes updated
- AssetBridger/Erc20Bridger APIs changed; new bridgers named EthBridger, Erc20Bridger, EthL1L3Bridger, Erc20L1L3Bridger (see updated constructors/usage). Instantiate with an ArbitrumNetwork (not generic Network). [1][2]
- Message classes & lifecycle
- Message classes renamed/reshaped to ParentToChildMessage and ChildToParentMessage; creation/receipt parsing flows updated (constructors and helper methods changed). Review message creation from tx receipts. [1]
- Network helper functions
- New helpers: getArbitrumNetworks, getChildrenForNetwork. Use these instead of the removed getParentForNetwork/getL1Network. [1]
- Registration requirement
- registerCustomArbitrumNetwork must be used for custom Arbitrum chains before using bridgers or message utilities. [1][2]
- Code example (v4 pattern)
- Fetch network: const child = await getArbitrumNetwork(childChainId)
- Create bridger: const ethBridger = new EthBridger(child)
- Deposit: await ethBridger.deposit({ amount, parentSigner })
(See repo docs for full method signatures.) [2]
Where to read full details and examples
- Official migration doc (v3 → v4) — primary migration guide and detailed breaking-change list. [1]
- @arbitrum/sdk v4 repository and README (examples, API reference). [2]
References
[1] Arbitrum SDK migration guide (v3 → v4) — docs.arbitrum.io/sdk/migrate.
[2] OffchainLabs/arbitrum-sdk (v4) — GitHub README & repo.
Review @arbitrum/sdk v4 breaking changes before upgrade.
The update from v3.1.9 to v4.0.4 introduces substantial breaking changes:
- Terminology shift: L1/L2 → parent/child (affects types, functions, and method names)
- API changes:
L2Network→ArbitrumNetwork,getL2Network→getArbitrumNetwork, and several removed functions - Bridger classes restructured with updated constructors and signatures
- Message classes renamed:
Message→ParentToChildMessage/ChildToParentMessage - New requirement:
registerCustomArbitrumNetworkmust be called for custom chains
Ensure all SDK usage in this codebase is updated to match the v4 API. Refer to the migration guide at docs.arbitrum.io/sdk/migrate.
🤖 Prompt for AI Agents
In contracts/package.json around line 123, the dependency bump to
"@arbitrum/sdk": "^4.0.4" may break existing code because v4 renamed types and
methods (L1/L2 → parent/child, L2Network → ArbitrumNetwork, getL2Network →
getArbitrumNetwork), restructured Bridger constructors, renamed Message classes,
and requires registerCustomArbitrumNetwork for custom chains; update all
imports/usages across the codebase to the v4 API (rename
types/functions/classes, adjust constructor/signature calls, replace Message
usages with ParentToChildMessage/ChildToParentMessage, and call
registerCustomArbitrumNetwork where custom chains are used), run the migration
guide at docs.arbitrum.io/sdk/migrate to map each old API to its v4 equivalent,
and run tests to ensure no remaining references to v3 APIs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
contracts/tasks/relay-op.js (1)
101-118: Use consistent chain reference for clarity.Line 112 uses
l2Wallet.chainwhile the rest of the code usesl2Public.chain(lines 75, 82, 106). While both work now that the wallet has a chain, usingl2Public.chainorchain.l2would be more consistent.Apply this diff for consistency:
console.log("Finalizing withdrawal..."); await l1Wallet.finalizeWithdrawal({ - targetChain: l2Wallet.chain, + targetChain: chain.l2, withdrawal, });
🧹 Nitpick comments (1)
contracts/tasks/relay-op.js (1)
80-99: LGTM!The proving logic correctly:
- Waits for the withdrawal to be provable
- Only proves when status requires it (preventing unnecessary timeout resets)
- Includes helpful note about Infura RPC limitations
Consider wrapping the RPC calls and proof submission in try-catch blocks for better error reporting, especially since the Infura limitation (line 96) could cause failures.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
contracts/tasks/relay-op.js(1 hunks)
🔇 Additional comments (5)
contracts/tasks/relay-op.js (5)
1-17: LGTM!The imports are appropriate for an OP Stack withdrawal relay task, including all necessary viem modules and chain definitions.
21-29: LGTM!The task definition and PRIVATE_KEY validation are correct. Proper error handling for missing environment variable and normalization of the key format.
45-69: LGTM!The client creation is correct. Both wallet clients now include the
chainparameter (lines 55 and 67), which addresses the critical issue from the previous review aboutl2Wallet.chainbeing undefined.
71-78: LGTM!Transaction receipt retrieval and withdrawal status check are correct.
120-123: LGTM!Proper handling of the already-finalized case with early return.
| const chainId = hre.network.config.chainId; | ||
| const chain = CHAIN_MAP[chainId]; | ||
| const l1RpcUrl = hre.config.networks[chain.l1NetworkName].url; | ||
| const l2RpcUrl = hre.network.config.url; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add validation for chain configuration lookups.
Lines 41-42 perform lookups without validation:
- If
chainIdis not inCHAIN_MAP,chainwill beundefinedand cause errors when accessingchain.l1orchain.l2 - If
chain.l1NetworkNamedoesn't exist inhre.config.networks, the code will throw an unclear error
Add validation after the lookups:
const chainId = hre.network.config.chainId;
const chain = CHAIN_MAP[chainId];
+if (!chain) {
+ throw new Error(`Chain ${chainId} not supported. Supported chains: ${Object.keys(CHAIN_MAP).join(", ")}`);
+}
+
const l1RpcUrl = hre.config.networks[chain.l1NetworkName].url;
+if (!l1RpcUrl) {
+ throw new Error(`L1 network "${chain.l1NetworkName}" not configured in hardhat.config`);
+}
const l2RpcUrl = hre.network.config.url;Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In contracts/tasks/relay-op.js around lines 40 to 43, the code performs
CHAIN_MAP and network lookups without validation which can cause unclear runtime
errors; after retrieving chainId and chain, add checks that chain is defined
(throw or exit with a clear error including the chainId), then verify
chain.l1NetworkName exists and that hre.config.networks[chain.l1NetworkName] is
defined (throw/exit with a message naming chain.l1NetworkName and chainId), and
finally validate hre.network.config.url and
hre.config.networks[chain.l1NetworkName].url exist before using them, providing
explicit error text for each missing value so failures are deterministic and
debuggable.
Summary by CodeRabbit
New Features
Documentation
Refactor
Chores
✏️ Tip: You can customize this high-level summary in your review settings.