-
Notifications
You must be signed in to change notification settings - Fork 46
Bungee chains #422
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?
Bungee chains #422
Conversation
WalkthroughAdds MONAD (chain ID 143) across enums, RPC/config mappings, deployment addresses and verification data; introduces EIP-1559 overrides and a MONAD RPC env var; and adds four admin scripts for querying and sending attest/execute transactions. Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as CLI (npm_config_*)
participant Addrs as Addresses (deployments/prod_addresses.json)
participant Provider as JSON-RPC Provider
participant KMS as AWS KMS Signer
participant Contract as Target Contract (Switchboard/Socket)
rect rgba(0,128,0,0.06)
CLI->>Addrs: load chain & integration addresses
CLI->>Provider: create provider for chain
CLI->>Contract: instantiate contract ABI + address
end
rect rgba(0,64,128,0.06)
CLI->>KMS: request signature for message/hash
KMS-->>CLI: signature
CLI->>Contract: prepare calldata (encode)
end
alt --sendtx
CLI->>Provider: send transaction (signed by key or via Wallet)
Provider-->>CLI: txHash / receipt
else dry-run
CLI-->>CLI: print calldata & instructions
end
Note right of CLI: scripts support block-range event queries (chunked) and optional tx broadcast
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes This should be reviewed with focus on:
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Tip 📝 Customizable high-level summaries are now available in beta!You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.
Example instruction:
Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later. 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: 13
♻️ Duplicate comments (1)
scripts/admin/get-seal-events.ts (1)
32-54: Validate and convert chain slugs to numbers immediately after extraction.Same issue as in
get-outbound-txs.ts. The env vars are strings but need to be numeric ChainSlug values.Apply this diff:
const sourceChainSlug = process.env.npm_config_source; if (!sourceChainSlug) { console.error("Error: source flag is required"); process.exit(1); } +const sourceChainSlugNum = parseInt(sourceChainSlug); +if (isNaN(sourceChainSlugNum)) { + console.error(`Error: source must be a valid number, got: ${sourceChainSlug}`); + process.exit(1); +} const destinationChainSlug = process.env.npm_config_destination; if (!destinationChainSlug) { console.error("Error: destination flag is required"); process.exit(1); } +const destinationChainSlugNum = parseInt(destinationChainSlug); +if (isNaN(destinationChainSlugNum)) { + console.error(`Error: destination must be a valid number, got: ${destinationChainSlug}`); + process.exit(1); +}Then update lines 59-60 and 98 to use the numeric versions:
- const sourceChain = sourceChainSlug; - const destinationChain = destinationChainSlug; + const sourceChain = sourceChainSlugNum as ChainSlug; + const destinationChain = destinationChainSlugNum as ChainSlug;- const provider = getProviderFromChainSlug(parseInt(sourceChain) as ChainSlug); + const provider = getProviderFromChainSlug(sourceChain);
🧹 Nitpick comments (2)
scripts/admin/send-attest.ts (1)
128-130: Cache the parsed destination chain valueThe destinationChain is parsed multiple times (lines 129, 142, 186) with
parseInt(destinationChain). Parse once at the beginning of main().Apply this refactor after line 92:
export const main = async () => { const sourceChain = sourceChainSlug; - const destinationChain = destinationChainSlug; + const destinationChain = parseInt(destinationChainSlug) as ChainSlug; - console.log(`\nProcessing attest for path: ${sourceChain} -> ${destinationChain}\n`); + console.log(`\nProcessing attest for path: ${sourceChain} -> ${destinationChain}\n`);Then remove parseInt calls at lines 129, 142, and 186.
scripts/rpcConfig/constants/icons.ts (1)
45-45: Consider adding a MONAD icon.The icon is currently an empty string, consistent with other chains, but adding a proper icon URL would improve the UI experience.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (25)
.env.example(1 hunks)deployments/prod_addresses.json(27 hunks)deployments/prod_verification.json(1 hunks)scripts/admin/get-outbound-txs.ts(1 hunks)scripts/admin/get-seal-events.ts(1 hunks)scripts/admin/send-attest.ts(1 hunks)scripts/admin/send-execute.ts(1 hunks)scripts/constants/overrides.ts(4 hunks)scripts/deploy/scripts/registerSwitchboard.ts(1 hunks)scripts/rpcConfig/constants/batcherSupportedChainSlug.ts(1 hunks)scripts/rpcConfig/constants/explorers.ts(1 hunks)scripts/rpcConfig/constants/icons.ts(1 hunks)scripts/rpcConfig/constants/rpc.ts(1 hunks)scripts/rpcConfig/constants/version.ts(1 hunks)src/enums/chainId.ts(1 hunks)src/enums/chainSlug.ts(1 hunks)src/enums/chainSlugToHardhatChainName.ts(1 hunks)src/enums/chainSlugToId.ts(1 hunks)src/enums/chainSlugToKey.ts(1 hunks)src/enums/currency.ts(1 hunks)src/enums/ethLikeChains.ts(1 hunks)src/enums/hardhatChainName.ts(1 hunks)src/enums/hardhatChainNameToSlug.ts(1 hunks)src/enums/mainnetIds.ts(1 hunks)src/enums/native-tokens.ts(1 hunks)
👮 Files not reviewed due to content moderation or server errors (1)
- deployments/prod_addresses.json
🧰 Additional context used
🧬 Code graph analysis (5)
scripts/admin/send-execute.ts (4)
scripts/admin/tripCommon.ts (2)
sendTx(61-61)addresses(50-50)src/socket-types.ts (1)
DeploymentAddresses(115-117)scripts/deploy/config/config.ts (1)
mode(20-22)scripts/constants/networks.ts (1)
getProviderFromChainSlug(54-57)
scripts/admin/send-attest.ts (3)
scripts/admin/tripCommon.ts (2)
sendTx(61-61)addresses(50-50)scripts/deploy/config/config.ts (2)
mode(20-22)overrides(133-154)scripts/constants/networks.ts (1)
getProviderFromChainSlug(54-57)
scripts/admin/get-outbound-txs.ts (4)
src/socket-types.ts (1)
DeploymentAddresses(115-117)scripts/deploy/config/config.ts (1)
mode(20-22)scripts/admin/get-seal-events.ts (1)
main(58-142)scripts/constants/networks.ts (1)
getProviderFromChainSlug(54-57)
scripts/constants/overrides.ts (1)
scripts/deploy/config/config.ts (1)
overrides(133-154)
scripts/admin/get-seal-events.ts (4)
src/socket-types.ts (1)
DeploymentAddresses(115-117)src/addresses.ts (1)
getAllAddresses(173-173)scripts/deploy/config/config.ts (1)
mode(20-22)scripts/constants/networks.ts (1)
getProviderFromChainSlug(54-57)
🔇 Additional comments (25)
scripts/rpcConfig/constants/version.ts (1)
5-5: This version jump requires manual verification of the team's versioning strategy.The PROD version skips from 1.0.106 to 1.0.110 for a single chain addition (MONAD). While the version strings exist only in
scripts/rpcConfig/constants/version.tsand aren't used for compatibility checks or feature logic elsewhere, the jump is unusual. Git history shows frequent version bumps, but no documented versioning scheme exists in the repository to validate whether the +4 increment is intentional or a mistake. Confirm with the maintainers that this aligns with the project's versioning practice.scripts/deploy/scripts/registerSwitchboard.ts (1)
56-59: LGTM - Improved observabilityThe enhanced logging now includes the chain ID, which helps with debugging multi-chain deployments. The additional async call is negligible overhead for a logging operation.
scripts/admin/send-attest.ts (2)
139-144: Message hash construction looks correctThe ABI encoding matches the expected signature verification pattern for FastSwitchboard attest function. Parameters are properly ordered and typed.
169-193: Transaction sending is properly gated and includes overridesThe sendTx flag correctly gates transaction submission, and the transaction includes proper overrides for the destination chain. Good separation between signature generation and transaction submission.
scripts/admin/send-execute.ts (1)
110-124: Hasher contract integration is correctly implementedThe hasher address is retrieved from the Socket contract and used to pack the message with proper parameter ordering. The ABI definition matches the expected packMessage signature.
src/enums/chainSlugToHardhatChainName.ts (1)
79-79: LGTM - Consistent enum mappingThe MONAD mapping follows the established pattern for chain slug to hardhat name mappings.
src/enums/hardhatChainName.ts (1)
76-76: LGTM - Consistent hardhat chain nameThe MONAD hardhat chain name follows the established lowercase naming convention.
src/enums/chainSlug.ts (1)
78-78: LGTM - Chain slug properly linked to chain IDThe MONAD chain slug correctly references ChainId.MONAD (143), maintaining consistency with the chain ID enum.
src/enums/chainId.ts (1)
76-76: MONAD chain ID 143 is correctThe official chain ID for Monad mainnet is 143. The enum value matches the specification and no changes are needed.
scripts/rpcConfig/constants/explorers.ts (1)
47-47: Verify the explorer URL stability.The explorer URL contains "mainnet-beta" which suggests the network or explorer may still be in beta. Ensure this is production-ready and won't cause issues with block explorers or verification flows.
src/enums/mainnetIds.ts (1)
49-49: LGTM!MONAD correctly added to the mainnet identifiers list.
src/enums/ethLikeChains.ts (1)
34-34: LGTM!MONAD correctly added to the eth-like chains with constant gas limits.
src/enums/chainSlugToKey.ts (1)
79-79: LGTM!MONAD mapping correctly added to ChainSlugToKey.
scripts/rpcConfig/constants/rpc.ts (1)
80-80: LGTM!MONAD RPC configuration correctly added using the standard checkEnvValue pattern.
src/enums/hardhatChainNameToSlug.ts (1)
79-79: LGTM!Reverse mapping from HardhatChainName.MONAD to ChainSlug.MONAD correctly added.
.env.example (1)
142-143: Remove duplicate MONAD_RPC definition.The MONAD_RPC environment variable is defined twice (lines 142 and 143). Remove one of these duplicate entries.
Apply this diff to remove the duplicate:
- -MONAD_RPC=' 'Likely an incorrect or invalid review comment.
scripts/rpcConfig/constants/batcherSupportedChainSlug.ts (1)
68-69: All required infrastructure is in place—safe to merge.Verification confirms MONAD support is fully wired:
- Enums defined across all required files (chainId, chainSlug, hardhatChainName, key mappings, ethLikeChains)
- RPC endpoint configured with env var check:
checkEnvValue("MONAD_RPC")- Gas overrides present:
gasLimit: 3_00_000- Explorer and icon URLs configured
The batcher can ship with this change.
src/enums/chainSlugToId.ts (1)
79-80: Mapping verified and unique.ChainId.MONAD = 143 confirmed at src/enums/chainId.ts:76, and the value is unique across all ChainId enum members. The ChainSlugToId mapping correctly pairs ChainSlug.MONAD with ChainId.MONAD. Change is sound.
deployments/prod_verification.json (1)
975-1120: This review comment is based on false assumptions and should be disregarded.The verification script correctly failed at step 4. The data does not conform to the stated invariants:
- Optimistic/Fast/Transmit/Exec do NOT reference Socket at
[3][0]: They reference0xB0BBff631...(unknown). Socket appears at different indices.- External address dependency: The block references
0xB0BBff631...,0x8c36353d..., and0xA49f876C...which are NOT defined in block 143. These addresses are external dependencies not validated by the proposed checks.- Incomplete coverage: The data integrity assumptions are fundamentally broken—the verification cannot succeed as designed because the data structure does not match the claimed invariants.
The original review proposed `` based on validations that fail. Discard the suggested jq checks and approve/reject based on actual business requirements for the "143" configuration, not on assumptions about internal referential integrity that don't hold.
Likely an incorrect or invalid review comment.
scripts/admin/get-outbound-txs.ts (1)
65-77: Fix type mismatch in address lookup.After applying the fix above, this code will correctly use numeric ChainSlug values as keys. The DeploymentAddresses type expects numeric keys, not strings.
scripts/admin/get-seal-events.ts (1)
65-77: Fix type mismatch in address lookup.After applying the fix above, this code will correctly use numeric ChainSlug values as keys.
scripts/constants/overrides.ts (4)
29-33: LGTM - EIP-1559 enabled for MAINNET.The addition of
type: 2correctly enables EIP-1559 transactions for MAINNET while preserving existing gas configuration.
35-39: LGTM - EIP-1559 enabled for POLYGON_MAINNET.The addition of
type: 2correctly enables EIP-1559 transactions for Polygon mainnet.
124-128: Verify the switch from dynamic to fixed gas pricing.PLASMA now uses a fixed
gasPrice: 100_000_000instead of the previous multiplier-based calculation. This could cause issues if network conditions change significantly.Confirm that a fixed gas price is appropriate for PLASMA, or if dynamic pricing should be retained.
143-150: LGTM - Clear EIP-1559 documentation.The documentation accurately describes the EIP-1559 parameter handling and helps users understand the new behavior.
| import { config as dotenvConfig } from "dotenv"; | ||
| import { | ||
| ChainSlug, | ||
| DeploymentAddresses, | ||
| IntegrationTypes, | ||
| getAllAddresses, | ||
| } from "../../src"; | ||
| import { mode } from "../deploy/config/config"; | ||
| import SingleCapacitorArtifact from "../../out/SingleCapacitor.sol/SingleCapacitor.json"; | ||
| import { getProviderFromChainSlug } from "../constants"; | ||
| import { ethers } from "ethers"; | ||
|
|
||
| dotenvConfig(); | ||
|
|
||
| /** | ||
| * Usage | ||
| * | ||
| * --source Specify the source chain slug. | ||
| * This flag is required. | ||
| * Eg. npx --source=1 --destination=10 --startblock=12345 --endblock=12456 ts-node scripts/admin/get-outbound-txs.ts | ||
| * | ||
| * --destination Specify the destination chain slug. | ||
| * This flag is required. | ||
| * | ||
| * --startblock Specify the start block number. | ||
| * This flag is required. | ||
| * | ||
| * --endblock Specify the end block number. | ||
| * This flag is required. | ||
| */ | ||
|
|
||
| const sourceChainSlug = process.env.npm_config_source; | ||
| if (!sourceChainSlug) { | ||
| console.error("Error: source flag is required"); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const destinationChainSlug = process.env.npm_config_destination; | ||
| if (!destinationChainSlug) { | ||
| console.error("Error: destination flag is required"); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const startBlock = process.env.npm_config_startblock; | ||
| if (!startBlock) { | ||
| console.error("Error: startblock flag is required"); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const endBlock = process.env.npm_config_endblock; | ||
| if (!endBlock) { | ||
| console.error("Error: endblock flag is required"); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const addresses: DeploymentAddresses = getAllAddresses(mode); | ||
|
|
||
| export const main = async () => { | ||
| const sourceChain = sourceChainSlug; | ||
| const destinationChain = destinationChainSlug; | ||
|
|
||
| console.log(`\nProcessing path: ${sourceChain} -> ${destinationChain}\n`); | ||
|
|
||
| // Get addresses from prod_addresses.json | ||
| const sourceAddresses = addresses[sourceChain]; | ||
| if (!sourceAddresses) { | ||
| console.error(`Error: No addresses found for source chain ${sourceChain}`); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const integration = sourceAddresses.integrations?.[destinationChain]; | ||
| if (!integration) { | ||
| console.error( | ||
| `Error: No integration found for ${sourceChain} -> ${destinationChain}` | ||
| ); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| // Get FAST integration addresses (switchboard, socket, capacitor) | ||
| const fastIntegration = integration[IntegrationTypes.fast]; | ||
| if (!fastIntegration) { | ||
| console.error( | ||
| `Error: No FAST integration found for ${sourceChain} -> ${destinationChain}` | ||
| ); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const switchboardAddress = fastIntegration.switchboard; | ||
| const capacitorAddress = fastIntegration.capacitor; | ||
| const socketAddress = sourceAddresses.Socket; | ||
|
|
||
| console.log("Addresses:"); | ||
| console.log(` Switchboard: ${switchboardAddress}`); | ||
| console.log(` Socket: ${socketAddress}`); | ||
| console.log(` Capacitor: ${capacitorAddress}\n`); | ||
|
|
||
| // Get provider and query events | ||
| const provider = getProviderFromChainSlug(parseInt(sourceChain) as ChainSlug); | ||
|
|
||
| const capacitorContract = new ethers.Contract( | ||
| capacitorAddress, | ||
| SingleCapacitorArtifact.abi, | ||
| provider | ||
| ); | ||
|
|
||
| const fromBlock = parseInt(startBlock); | ||
| const toBlock = parseInt(endBlock); | ||
|
|
||
| console.log(`Querying events from block ${fromBlock} to ${toBlock}\n`); | ||
|
|
||
| // Query MessageAdded events in chunks of 5000 blocks | ||
| const CHUNK_SIZE = 5000; | ||
| const messageAddedEvents = []; | ||
|
|
||
| for (let currentBlock = fromBlock; currentBlock <= toBlock; currentBlock += CHUNK_SIZE) { | ||
| const chunkEnd = Math.min(currentBlock + CHUNK_SIZE - 1, toBlock); | ||
| console.log(`Querying chunk: ${currentBlock} to ${chunkEnd}`); | ||
|
|
||
| const events = await capacitorContract.queryFilter( | ||
| capacitorContract.filters.MessageAdded(), | ||
| currentBlock, | ||
| chunkEnd | ||
| ); | ||
|
|
||
| messageAddedEvents.push(...events); | ||
| } | ||
|
|
||
| console.log(`Found ${messageAddedEvents.length} outbound transactions:\n`); | ||
|
|
||
| for (const event of messageAddedEvents) { | ||
| console.log(`Block: ${event.blockNumber}`); | ||
| console.log(` Transaction Hash: ${event.transactionHash}`); | ||
| console.log(` Packed Message: ${event.args?.packedMessage}`); | ||
| console.log(` Packet Count: ${event.args?.packetCount?.toString()}`); | ||
| console.log(` Root Hash: ${event.args?.newRootHash}`); | ||
| console.log(""); | ||
| } | ||
|
|
||
| console.log("Script completed."); | ||
| }; | ||
|
|
||
| main() | ||
| .then(() => process.exit(0)) | ||
| .catch((error: Error) => { | ||
| console.error(error); | ||
| process.exit(1); | ||
| }); |
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
Eliminate code duplication with get-seal-events.ts.
This script shares ~95% identical code with get-seal-events.ts. Extract the common logic (env parsing, validation, address resolution, chunked querying) into a shared utility function or base class. The only differences are the contract artifact and event filter.
Consider creating a shared helper like:
// scripts/admin/utils/query-events.ts
export async function queryEventsForPath(
sourceChain: ChainSlug,
destinationChain: ChainSlug,
startBlock: number,
endBlock: number,
contractType: 'Socket' | 'SingleCapacitor',
eventName: string
) {
// Common logic here
}Then both scripts become simple wrappers:
// get-outbound-txs.ts
const result = await queryEventsForPath(
sourceChain,
destinationChain,
startBlock,
endBlock,
'SingleCapacitor',
'MessageAdded'
);🤖 Prompt for AI Agents
In scripts/admin/get-outbound-txs.ts around lines 1-147, the file duplicates
~95% of the logic from get-seal-events.ts; extract the common logic (env flag
parsing and validation, address resolution via getAllAddresses(mode), provider
creation, chunked query loop and result aggregation) into a shared helper (e.g.,
scripts/admin/utils/query-events.ts) that accepts parameters for sourceChain,
destinationChain, startBlock, endBlock, contract artifact/ABI or a contract
factory, and the event filter name or filter function; change this script to
validate flags then call the helper with the SingleCapacitor artifact and
MessageAdded event, returning the matched events; ensure the helper returns
event objects and that error handling/logging stays consistent; update
get-seal-events.ts to call the same helper with its respective artifact and
event name so both scripts are thin wrappers.
| const sourceChainSlug = process.env.npm_config_source; | ||
| if (!sourceChainSlug) { | ||
| console.error("Error: source flag is required"); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const destinationChainSlug = process.env.npm_config_destination; | ||
| if (!destinationChainSlug) { | ||
| console.error("Error: destination flag is required"); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const startBlock = process.env.npm_config_startblock; | ||
| if (!startBlock) { | ||
| console.error("Error: startblock flag is required"); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const endBlock = process.env.npm_config_endblock; | ||
| if (!endBlock) { | ||
| console.error("Error: endblock flag is required"); | ||
| process.exit(1); | ||
| } |
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.
Validate and convert chain slugs to numbers immediately after extraction.
The env vars are strings but need to be numeric ChainSlug values. Convert and validate them right after extraction to fail fast and ensure type safety throughout the script.
Apply this diff:
const sourceChainSlug = process.env.npm_config_source;
if (!sourceChainSlug) {
console.error("Error: source flag is required");
process.exit(1);
}
+const sourceChainSlugNum = parseInt(sourceChainSlug);
+if (isNaN(sourceChainSlugNum)) {
+ console.error(`Error: source must be a valid number, got: ${sourceChainSlug}`);
+ process.exit(1);
+}
const destinationChainSlug = process.env.npm_config_destination;
if (!destinationChainSlug) {
console.error("Error: destination flag is required");
process.exit(1);
}
+const destinationChainSlugNum = parseInt(destinationChainSlug);
+if (isNaN(destinationChainSlugNum)) {
+ console.error(`Error: destination must be a valid number, got: ${destinationChainSlug}`);
+ process.exit(1);
+}Then update lines 59-60 and 98 to use the numeric versions:
- const sourceChain = sourceChainSlug;
- const destinationChain = destinationChainSlug;
+ const sourceChain = sourceChainSlugNum as ChainSlug;
+ const destinationChain = destinationChainSlugNum as ChainSlug;- const provider = getProviderFromChainSlug(parseInt(sourceChain) as ChainSlug);
+ const provider = getProviderFromChainSlug(sourceChain);Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In scripts/admin/get-outbound-txs.ts around lines 32 to 54, the extracted
npm_config_* environment variables are left as strings but are expected to be
numeric ChainSlug values; convert and validate sourceChainSlug,
destinationChainSlug, startBlock, and endBlock to numbers immediately after
extraction (parseInt or Number), check for NaN and out-of-range/invalid values,
and exit with a clear error if validation fails so the script fails fast; then
update the usages at lines 59-60 and line 98 to reference the new numeric
variables (e.g., sourceChain, destinationChain, startBlockNum/endBlockNum)
instead of the original string variables.
| const destinationChainSlug = process.env.npm_config_destination; | ||
| if (!destinationChainSlug) { | ||
| console.error("Error: destination flag is required"); | ||
| process.exit(1); | ||
| } |
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 numeric chain slug
The script validates presence but not format of destinationChainSlug. This could cause runtime errors at lines 129, 142, and 186 when calling parseInt.
Add validation after line 53:
const destinationChainSlug = process.env.npm_config_destination;
if (!destinationChainSlug) {
console.error("Error: destination flag is required");
process.exit(1);
}
+if (isNaN(parseInt(destinationChainSlug))) {
+ console.error("Error: destination must be a numeric chain slug");
+ process.exit(1);
+}📝 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 destinationChainSlug = process.env.npm_config_destination; | |
| if (!destinationChainSlug) { | |
| console.error("Error: destination flag is required"); | |
| process.exit(1); | |
| } | |
| const destinationChainSlug = process.env.npm_config_destination; | |
| if (!destinationChainSlug) { | |
| console.error("Error: destination flag is required"); | |
| process.exit(1); | |
| } | |
| if (isNaN(parseInt(destinationChainSlug))) { | |
| console.error("Error: destination must be a numeric chain slug"); | |
| process.exit(1); | |
| } |
🤖 Prompt for AI Agents
In scripts/admin/send-attest.ts around lines 50 to 54, the destinationChainSlug
environment value is only checked for presence but not validated as a numeric
slug; add a validation after line 53 that ensures destinationChainSlug
represents an integer (e.g., test with a /^\d+$/ or attempt parseInt(base 10)
and check for NaN) and if invalid print a clear error to stderr and exit
non-zero so later parseInt calls at lines 129, 142, and 186 cannot receive
malformed input.
| const EXECUTION_CONFIG = { | ||
| executionDetails: { | ||
| packetId: "0x0000a4b129ebc834d24af22b9466a4150425354998c3e800000000000000cbe6", // Replace with actual packet ID | ||
| proposalCount: "0", // Replace with actual proposal count | ||
| executionGasLimit: "200000", // Replace with actual gas limit | ||
| decapacitorProof: "0x", // Replace with actual proof | ||
| }, | ||
| messageDetails: { | ||
| msgId: "0x0000a4b126e5ce884875ea3776a57f0b225b1ea8d2e9beeb00000000000608cb", // Replace with actual message ID | ||
| executionFee: "0", // Replace with actual execution fee | ||
| minMsgGasLimit: "100000", // Replace with actual min gas limit | ||
| executionParams: "0x0000000000000000000000000000000000000000000000000000000000000000", // Replace with actual execution params | ||
| payload: "0x0000000000000000000000008cb4c89cc297e07c7a309af8b16cc2f5f62a3b1300000000000000000000000000000000000000000000000000000000062ebe4d", // Replace with actual payload | ||
| }, | ||
| msgValue: "0", // ETH value to send with transaction (in wei) | ||
| }; |
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.
Hardcoded execution config is a critical design flaw
This EXECUTION_CONFIG object contains placeholder values that must be manually edited before each script execution. This defeats the purpose of an admin script and introduces human error risk.
Convert these to CLI flags similar to send-attest.ts:
--packetid--proposalcount--executiongaslimit--decapacitorproof--msgid--executionfee--minmsggaslimit--executionparams--payload--msgvalue
This makes the script safer and scriptable for automation.
🤖 Prompt for AI Agents
In scripts/admin/send-execute.ts around lines 32 to 47, the EXECUTION_CONFIG is
hardcoded with placeholder values which must be converted to CLI flags; update
the script to parse command-line options (matching send-attest.ts style) for
--packetid, --proposalcount, --executiongaslimit, --decapacitorproof, --msgid,
--executionfee, --minmsggaslimit, --executionparams, --payload and --msgvalue,
validate required flags and provide helpful usage/errors, then build
EXECUTION_CONFIG from those parsed flag values (using sensible defaults where
applicable) before using it in the transaction flow; also update help/usage text
and ensure values are passed as strings and any numeric fields are
validated/converted appropriately.
| const destinationChainSlug = process.env.npm_config_destination; | ||
| if (!destinationChainSlug) { | ||
| console.error("Error: destination flag is required"); | ||
| process.exit(1); | ||
| } |
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 numeric chain slug
Same issue as send-attest.ts - destinationChainSlug should be validated as numeric before parseInt calls at lines 72, 186, and 216.
Add after line 52:
const destinationChainSlug = process.env.npm_config_destination;
if (!destinationChainSlug) {
console.error("Error: destination flag is required");
process.exit(1);
}
+if (isNaN(parseInt(destinationChainSlug))) {
+ console.error("Error: destination must be a numeric chain slug");
+ process.exit(1);
+}🤖 Prompt for AI Agents
In scripts/admin/send-execute.ts around lines 49 to 53, destinationChainSlug is
only checked for presence but not that it is numeric; add validation immediately
after line 52 to ensure destinationChainSlug contains only digits (e.g. /^\d+$/
or Number parsing + Number.isInteger) and if not, print a clear error and exit;
this prevents unsafe parseInt calls later at lines 72, 186, and 216 by
guaranteeing a valid numeric slug before those parses.
| let maxFeePerGas = overrides.gasPrice; | ||
| if (!maxFeePerGas) { | ||
| const feeData = await provider.getFeeData(); | ||
| const baseGasPrice = | ||
| feeData.maxFeePerGas || (await provider.getGasPrice()); | ||
| const multiplier = | ||
| overrides.gasPriceMultiplier || DEFAULT_GAS_PRICE_MULTIPLIER; | ||
| maxFeePerGas = baseGasPrice | ||
| .mul(Math.round(multiplier * 100000)) | ||
| .div(100000) | ||
| .toNumber(); | ||
| } |
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.
Risk: BigNumber.toNumber() can overflow for large gas prices.
Lines 171 and 190 use .toNumber() on BigNumber values. This throws an error if the value exceeds Number.MAX_SAFE_INTEGER (approximately 9 × 10^15). High gas prices during network congestion could trigger this.
Keep values as BigNumber instead:
const multiplier =
overrides.gasPriceMultiplier || DEFAULT_GAS_PRICE_MULTIPLIER;
- maxFeePerGas = baseGasPrice
+ maxFeePerGas = baseGasPrice
.mul(Math.round(multiplier * 100000))
- .div(100000)
- .toNumber();
+ .div(100000);Apply similar fix to the legacy transaction branch (lines 187-190).
Also applies to: 182-191
🤖 Prompt for AI Agents
scripts/constants/overrides.ts lines 161-172 (and similarly 182-191 / legacy
branch): the code calls .toNumber() on a BigNumber which can overflow; instead
keep and return a BigNumber throughout. Compute the scaled value using BigNumber
arithmetic (multiply by a BigNumber factor and div the same factor) and assign
the resulting BigNumber to maxFeePerGas (and the legacy maxGasPrice variable)
rather than converting to Number; if downstream expects a primitive, convert to
a string there or change the type to accept BigNumber.
| // Get base fee to calculate maxPriorityFeePerGas | ||
| const block = await provider.getBlock("latest"); | ||
| const baseFee = block.baseFeePerGas?.toNumber() || 0; | ||
| const maxPriorityFeePerGas = Math.max(maxFeePerGas - baseFee, 0); |
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 base fee calculation and priority fee logic.
Multiple issues:
-
Fallback to 0: If
baseFeePerGasis undefined, defaulting to 0 is incorrect. All blocks post-EIP-1559 have a base fee; undefined indicates a provider error or pre-EIP-1559 chain. -
Priority fee can be 0:
Math.max(maxFeePerGas - baseFee, 0)can result in 0 ifmaxFeePerGas ≤ baseFee. Transactions withmaxPriorityFeePerGas = 0may never be included or face severe delays.
Apply this diff:
- // Get base fee to calculate maxPriorityFeePerGas
- const block = await provider.getBlock("latest");
- const baseFee = block.baseFeePerGas?.toNumber() || 0;
- const maxPriorityFeePerGas = Math.max(maxFeePerGas - baseFee, 0);
+ // Calculate maxPriorityFeePerGas
+ const feeData = await provider.getFeeData();
+ const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas?.toNumber() ||
+ Math.floor(maxFeePerGas * 0.1); // Fallback: 10% of maxFeePerGasThis uses the provider's recommended priority fee with a reasonable fallback.
📝 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.
| // Get base fee to calculate maxPriorityFeePerGas | |
| const block = await provider.getBlock("latest"); | |
| const baseFee = block.baseFeePerGas?.toNumber() || 0; | |
| const maxPriorityFeePerGas = Math.max(maxFeePerGas - baseFee, 0); | |
| // Calculate maxPriorityFeePerGas | |
| const feeData = await provider.getFeeData(); | |
| const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas?.toNumber() || | |
| Math.floor(maxFeePerGas * 0.1); // Fallback: 10% of maxFeePerGas |
🤖 Prompt for AI Agents
In scripts/constants/overrides.ts around lines 174-177, the code naively
defaults block.baseFeePerGas to 0 and sets maxPriorityFeePerGas =
Math.max(maxFeePerGas - baseFee, 0), which is incorrect; instead fetch the
latest block and assert baseFeePerGas is present (throw or surface an error if
undefined), then call provider.getFeeData() to get the
providerRecommendedPriority = feeData.maxPriorityFeePerGas; compute
desiredPriority = providerRecommendedPriority ?? a sensible fallback (e.g. 1.5
gwei), then set maxPriorityFeePerGas to the lesser of desiredPriority and
(maxFeePerGas - baseFee) but if that difference is <= 0 use the fallback
desiredPriority and ensure maxFeePerGas is adjusted or reject the tx; in short:
fail on missing baseFeePerGas, prefer provider.getFeeData().maxPriorityFeePerGas
with a small gwei fallback, and clamp priority to not exceed maxFeePerGas -
baseFee while avoiding a zero priority.
| const block = await provider.getBlock("latest"); | ||
| const baseFee = block.baseFeePerGas?.toNumber() || 0; | ||
| const maxPriorityFeePerGas = Math.max(maxFeePerGas - baseFee, 0); | ||
| console.log(chainSlug, gasLimit, maxFeePerGas, maxPriorityFeePerGas, type); |
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.
Remove debug console.log statement.
This console.log should not be in production code.
Apply this diff:
const baseFee = block.baseFeePerGas?.toNumber() || 0;
const maxPriorityFeePerGas = Math.max(maxFeePerGas - baseFee, 0);
-console.log(chainSlug, gasLimit, maxFeePerGas, maxPriorityFeePerGas, type);
return { gasLimit, maxFeePerGas, maxPriorityFeePerGas, type };📝 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.
| console.log(chainSlug, gasLimit, maxFeePerGas, maxPriorityFeePerGas, type); | |
| const baseFee = block.baseFeePerGas?.toNumber() || 0; | |
| const maxPriorityFeePerGas = Math.max(maxFeePerGas - baseFee, 0); | |
| return { gasLimit, maxFeePerGas, maxPriorityFeePerGas, type }; |
🤖 Prompt for AI Agents
In scripts/constants/overrides.ts around line 178, remove the debug
console.log(chainSlug, gasLimit, maxFeePerGas, maxPriorityFeePerGas, type) from
production code; either delete the statement entirely or replace it with the
project’s proper logging call at debug level (e.g., logger.debug with the same
structured message) and ensure no leftover console.* calls remain.
| [ChainSlug.PLASMA]: NativeTokens["plasma"], | ||
| [ChainSlug.MONAD]: NativeTokens["wormhole"], | ||
| }; |
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
MONAD currency mapping is likely wrong.
This should map to MONAD’s native token, not “wormhole”. MONAD_TESTNET maps to NativeTokens["monad"], but MONAD maps to NativeTokens["wormhole"], which will misprice gas/fees wherever Currency is used.
Action:
- Replace with the correct MONAD mainnet token id (e.g., the same "monad" entry or a distinct MON mainnet key) once confirmed in native-tokens.ts.
- Keep PLASMA -> "plasma" only if NativeTokens defines it.
Quick checks:
Consider typing Currency for safety:
export const Currency = { ... } as const satisfies Partial<Record<ChainSlug, keyof typeof NativeTokens>>;
This should catch wrong keys at compile time.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Verify NativeTokens keys exist:"
rg -nP 'export\s+const\s+NativeTokens' src/enums/native-tokens.ts -n -C3
rg -nP '"monad"|\"wormhole\"|\"plasma\"' src/enums/native-tokens.ts -n -C2Length of output: 31
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Finding native-tokens.ts and currency.ts files ==="
fd -type f -name "native-tokens.ts"
fd -type f -name "currency.ts"
echo ""
echo "=== Checking currency.ts around lines 28-30 ==="
fd -type f -name "currency.ts" -exec cat {} \;
echo ""
echo "=== Checking for NativeTokens definition ==="
fd -type f -name "*.ts" | xargs rg -l "NativeTokens" | head -5Length of output: 225
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Finding files ==="
fd currency.ts
fd native-tokens.ts
echo ""
echo "=== Search for MONAD and wormhole in TS files ==="
rg -n "MONAD.*wormhole|wormhole.*MONAD" --type ts -C2
echo ""
echo "=== Search for Currency enum ==="
rg -n "ChainSlug.MONAD\|ChainSlug.PLASMA" --type ts -C3
echo ""
echo "=== Search for NativeTokens definition ==="
rg -n "NativeTokens\s*=" --type ts -A10 | head -50Length of output: 399
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== View native-tokens.ts ==="
cat src/enums/native-tokens.ts
echo ""
echo "=== Search for MONAD_TESTNET in currency.ts ==="
rg -n "MONAD_TESTNET" src/enums/currency.ts -C3Length of output: 1112
Fix PLASMA and MONAD token mappings—both are broken.
-
Line 28 (PLASMA): Maps to
NativeTokens["plasma"], but "plasma" is not defined in the NativeTokens enum. This will fail at runtime. Remove this entry or add "plasma" to NativeTokens if it's a valid coingecko ID. -
Line 29 (MONAD): Maps to
NativeTokens["wormhole"], but MONAD_TESTNET correctly usesNativeTokens["monad"]. Mainnet MONAD should use the same "monad" token for consistent native gas pricing. Change toNativeTokens["monad"].
[ChainSlug.PLASMA]: NativeTokens["plasma"], // ❌ "plasma" doesn't exist in NativeTokens
[ChainSlug.MONAD]: NativeTokens["wormhole"], // ❌ Should be NativeTokens["monad"]
🤖 Prompt for AI Agents
In src/enums/currency.ts around lines 28 to 30, the PLASMA and MONAD token
mappings are incorrect: PLASMA maps to NativeTokens["plasma"] which does not
exist (remove the PLASMA entry or add "plasma" to NativeTokens only if it's a
valid coingecko ID), and MONAD maps to NativeTokens["wormhole"] but should map
to NativeTokens["monad"] to match MONAD_TESTNET and ensure consistent native gas
token usage; update the PLASMA mapping accordingly (preferably remove it) and
change MONAD to NativeTokens["monad"].
| "hyperliquid" = "hyperliquid", | ||
| "sei-network" = "sei-network", | ||
| "dogwifcoin" = "dogwifcoin", | ||
| "wormhole" = "wormhole", |
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
Verify wormhole is the correct native token for MONAD
Confirm that "wormhole" (from CoinGecko) is the correct native token identifier for the MONAD blockchain. Token mappings must be accurate for pricing and display.
🌐 Web query:
What is the native token for MONAD blockchain and its CoinGecko identifier?
💡 Result:
- Native token: MON (Monad). [1]
- CoinGecko identifier (API / page ID): monad. [2]
Sources: CoinGecko coin page for Monad and CoinGecko overview article. [1][2]
References
[1] CoinGecko — Monad coin page (API ID: monad). (coingecko.com)
[2] CoinGecko — What Is Monad? overview (refers to the MON token). (coingecko.com)
Citations:
- 1: https://www.coingecko.com/id/coins/monad?utm_source=openai
- 2: https://www.coingecko.com/learn/what-is-monad-crypto?utm_source=openai
Remove incorrect wormhole token mapping
The native token for MONAD is MON, with CoinGecko identifier "monad", not "wormhole". Wormhole is a cross-chain messaging protocol, not MONAD's native token. This mapping will cause incorrect pricing lookups and display. Remove the wormhole entry from this enum.
🤖 Prompt for AI Agents
In src/enums/native-tokens.ts around line 23, the enum contains an incorrect
mapping '"wormhole" = "wormhole"'; remove this wormhole entry so MONAD's native
token mapping remains correct (ensure the enum retains the correct "monad" /
"MON" mapping elsewhere and update any references that depended on the removed
key to use the proper "monad" identifier), then run type checks and a quick grep
to fix any broken imports/usages.
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 (6)
src/enums/currency.ts (1)
28-30: Verify token mappings exist in NativeTokens enum.Past review flagged that
NativeTokens["plasma"]doesn't exist and would fail at runtime. MONAD mapping toNativeTokens["monad"]appears correct if "monad" is defined in the NativeTokens enum.Run this script to verify both token IDs exist:
#!/bin/bash # Description: Verify PLASMA and MONAD tokens exist in NativeTokens enum echo "=== Checking NativeTokens enum definition ===" cat src/enums/native-tokens.ts echo "" echo "=== Searching for 'plasma' token ===" rg -n '"plasma"' src/enums/native-tokens.ts echo "" echo "=== Searching for 'monad' token ===" rg -n '"monad"' src/enums/native-tokens.ts echo "" echo "=== All NativeTokens keys ===" rg -n '^\s+[a-zA-Z0-9_-]+:' src/enums/native-tokens.tsIf "plasma" doesn't exist, either:
- Remove the PLASMA currency mapping, or
- Add "plasma" to NativeTokens with the correct CoinGecko ID
scripts/constants/overrides.ts (5)
124-131: Fix gas limit formatting for MONAD.Line 130 uses
3_00_000which is inconsistent with the formatting pattern used throughout the file (e.g.,6_000_000,3_000_000). This should be300_000to clearly represent three hundred thousand.Apply this diff:
[ChainSlug.MONAD]: { - gasLimit: 3_00_000, + gasLimit: 300_000, },
159-180: Critical: Return type breaks consuming code + multiple calculation issues.This EIP-1559 implementation has several problems already flagged in previous reviews:
Return type incompatibility: Returns
{ gasLimit, maxFeePerGas, maxPriorityFeePerGas, type }but consumers likescripts/deploy/helpers/send-msg/utils.ts:127expectgasPrice. This breaks relay transactions.BigNumber overflow: Lines 171 and 190 use
.toNumber()which throws on values exceedingNumber.MAX_SAFE_INTEGER. Keep values as BigNumber.Invalid priority fee calculation: Lines 174-177 default
baseFeePerGasto 0 and can result inmaxPriorityFeePerGas = 0, which causes transactions to stall. Useprovider.getFeeData()for proper priority fee.Debug statement: Line 178 has a console.log that must be removed.
161-172: BigNumber.toNumber() overflow risk.Line 171 (and 190 in the legacy branch) converts BigNumber to number, which throws if gas price exceeds
Number.MAX_SAFE_INTEGER(~9 × 10^15). During network congestion, this can fail.Keep BigNumber throughout and convert only at the final usage point if needed.
174-177: Fix base fee fallback and priority fee calculation.Issues:
- Defaulting
baseFeePerGasto 0 is incorrect - all post-EIP-1559 blocks have a base feemaxPriorityFeePerGas = Math.max(maxFeePerGas - baseFee, 0)can be 0, causing transactions to stallUse
provider.getFeeData().maxPriorityFeePerGaswith a sensible fallback (e.g., 1.5 gwei).
178-178: Remove debug console.log.Production code should not contain debug console statements.
Apply this diff:
const baseFee = block.baseFeePerGas?.toNumber() || 0; const maxPriorityFeePerGas = Math.max(maxFeePerGas - baseFee, 0); -console.log(chainSlug, gasLimit, maxFeePerGas, maxPriorityFeePerGas, type); return { gasLimit, maxFeePerGas, maxPriorityFeePerGas, type };
🧹 Nitpick comments (1)
scripts/constants/overrides.ts (1)
124-128: PLASMA configuration mixes legacy and EIP-1559 semantics.Using
gasPricewithtype: 2is confusing. For EIP-1559 transactions (type 2), the property should be namedmaxFeePerGasin the override config to match the transaction type semantics. While this works because line 161 readsoverrides.gasPriceintomaxFeePerGas, it creates confusion for maintainers.Consider renaming the field in the ChainOverride type to clarify intent:
type ChainOverride = { type?: number; gasLimit?: number; gasPrice?: number; + maxFeePerGas?: number; // For EIP-1559 chains (type 2) gasPriceMultiplier?: number; };Then update PLASMA:
[ChainSlug.PLASMA]: { gasLimit: 5_000_000, - gasPrice: 1_000_000_000, + maxFeePerGas: 1_000_000_000, type: 2, },And update line 161 to check both:
- let maxFeePerGas = overrides.gasPrice; + let maxFeePerGas = overrides.maxFeePerGas || overrides.gasPrice;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
deployments/prod_addresses.json(28 hunks)hardhat.config.ts(3 hunks)scripts/constants/overrides.ts(4 hunks)scripts/rpcConfig/constants/version.ts(1 hunks)src/enums/currency.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- scripts/rpcConfig/constants/version.ts
👮 Files not reviewed due to content moderation or server errors (1)
- deployments/prod_addresses.json
🔇 Additional comments (3)
scripts/constants/overrides.ts (1)
31-31: LGTM - EIP-1559 enabled for Ethereum and Polygon.Enabling type 2 transactions on MAINNET and POLYGON_MAINNET is correct, as both chains support EIP-1559. This allows the code to use
maxFeePerGasandmaxPriorityFeePerGasinstead of legacygasPrice.Also applies to: 37-37
hardhat.config.ts (2)
134-134: LGTM - MONAD network added to production networks.The network configuration correctly maps MONAD to its chain config and will be available when
NODE_ENV=production.
198-198: API key mapping aligns with Etherscan endpoint.Using
ETHERSCAN_API_KEYis consistent with the apiURL configuration that routes throughapi.etherscan.io. If the endpoint verification confirms MONAD support, this mapping is correct.Note: This approval is contingent on verifying that Etherscan actually supports MONAD chain ID 143 (see comment on lines 449-456).
| { | ||
| network: "monad", | ||
| chainId: ChainId.MONAD, | ||
| urls: { | ||
| apiURL: "https://api.etherscan.io/v2/api?chainid=143", | ||
| browserURL: "https://monadscan.com/", | ||
| }, | ||
| }, |
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
Verify Etherscan API endpoint supports MONAD chain ID 143.
The apiURL uses https://api.etherscan.io/v2/api?chainid=143, which routes through Etherscan's infrastructure. MONAD is a separate L1 blockchain - verify that Etherscan actually indexes MONAD (chain ID 143) before contracts can be verified on mainnet.
If Etherscan doesn't support MONAD yet, this configuration will fail during contract verification with hardhat verify.
Alternatively, search for Etherscan's supported chains:
🏁 Script executed:
#!/bin/bash
# Verify if Etherscan API v2 supports MONAD chain ID 143
echo "=== Testing Etherscan API for MONAD (chain ID 143) ==="
curl -s "https://api.etherscan.io/v2/api?chainid=143&module=proxy&action=eth_blockNumber" | jq '.'
echo ""
echo "=== Check if monadscan.com is reachable ==="
curl -s -o /dev/null -w "%{http_code}" "https://monadscan.com/"
echo ""
echo "=== Check Etherscan supported chains documentation ==="
echo "Verify at: https://docs.etherscan.io/v/etherscan-v2/"Length of output: 292
🌐 Web query:
Does Etherscan API v2 support MONAD chain ID 143?
💡 Result:
Short answer: No — Etherscan API v2 does not list Monad mainnet (chain ID 143) as a supported chain; it lists Monad testnet (chain ID 10143). [1][2][3]
Sources:
- Etherscan supported-chains (shows Monad Testnet 10143, not 143). [1]
- Etherscan API V2 multichain overview. [2]
- Monad docs (confirming Monad mainnet chain ID = 143). [3]
This configuration will fail contract verification—Etherscan API v2 doesn't support MONAD mainnet (chain ID 143).
Etherscan API v2 only supports Monad testnet (chain ID 10143), not mainnet (chain ID 143). The apiURL pointing to Etherscan will return errors when users attempt hardhat verify for MONAD mainnet contracts. Either:
- Use a different verification service that supports MONAD, or
- Remove the Etherscan configuration for MONAD until it's officially supported, or
- Clarify in documentation that contract verification isn't available via Etherscan for MONAD mainnet
🤖 Prompt for AI Agents
In hardhat.config.ts around lines 449 to 456, the MONAD network block uses an
Etherscan v2 apiURL for chainId 143 which is unsupported and will break hardhat
verify; either remove the Etherscan configuration for MONAD, replace the apiURL
with a supported verification endpoint (or correct testnet chainId 10143 if you
intended testnet), or switch to a verification service that supports MONAD
mainnet; update the config accordingly and add a short comment explaining why
the Etherscan entry was removed/changed.
Summary by CodeRabbit
New Features
Infrastructure
Chores
✏️ Tip: You can customize this high-level summary in your review settings.