跳到主要内容

Contract Verification

Contract verification publishes your smart contract's source code on Monoscan, allowing anyone to read the code, audit it, and interact with it directly through the explorer. Verified contracts display a green checkmark and expose read/write interfaces.


Why Verify

BenefitDescription
TransparencyAnyone can inspect your contract's logic
TrustUsers can confirm the deployed bytecode matches the source
InteractionMonoscan provides a UI for calling read and write functions
ComposabilityOther developers can import your verified ABI
Best Practice

Always verify contracts after deployment. Unverified contracts are opaque to users and make debugging significantly harder.


Monoscan Web Verification

The simplest method is verifying directly through the Monoscan web interface.

Steps

  1. Navigate to your contract on Monoscan:
    https://testnet.monoscan.xyz/address/<your-contract-address>
  2. Click the Contract tab
  3. Click Verify & Publish
  4. Fill in the form:
    • Compiler version -- Must match the version used during compilation (e.g., v0.8.19+commit.7dd6d404)
    • Optimization -- Must match your compiler settings (enabled/disabled, number of runs)
    • License type -- Select the SPDX license identifier from your contract
  5. Paste your Solidity source code (or upload standard JSON input for multi-file contracts)
  6. If the contract has constructor arguments, enter them as ABI-encoded hex
  7. Click Verify and Publish

If successful, the contract page will display the source code with a green checkmark.


Hardhat Verify Plugin

The @nomicfoundation/hardhat-verify plugin (included in hardhat-toolbox) automates verification from the command line.

Configuration

Add the Monoscan endpoint to hardhat.config.ts:

import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";

const config: HardhatUserConfig = {
solidity: {
version: "0.8.19",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
networks: {
"monolythium-testnet": {
url: "https://evm.testnet.mononodes.xyz",
chainId: 6940,
accounts: [process.env.PRIVATE_KEY!],
},
"monolythium-mainnet": {
url: "https://evm.mainnet.mononodes.xyz",
chainId: 6941,
accounts: [process.env.PRIVATE_KEY!],
},
},
etherscan: {
apiKey: {
"monolythium-testnet": "",
"monolythium-mainnet": "",
},
customChains: [
{
network: "monolythium-testnet",
chainId: 6940,
urls: {
apiURL: "https://testnet.monoscan.xyz/api",
browserURL: "https://testnet.monoscan.xyz",
},
},
{
network: "monolythium-mainnet",
chainId: 6941,
urls: {
apiURL: "https://mainnet.monoscan.xyz/api",
browserURL: "https://mainnet.monoscan.xyz",
},
},
],
},
};

export default config;
信息

Monoscan does not require an API key for verification. Pass an empty string for the apiKey value.

Verify a Contract

# Basic verification (no constructor args)
npx hardhat verify --network monolythium-testnet <contract-address>

# With constructor arguments
npx hardhat verify --network monolythium-testnet <contract-address> <arg1> <arg2>

Example

For a contract deployed with constructor argument 10000000000000000 (0.01 LYTH in alyth):

npx hardhat verify --network monolythium-testnet 0x1234...abcd 10000000000000000

Complex Constructor Arguments

If your constructor takes complex types (arrays, structs, bytes), create an arguments file:

// arguments.js
module.exports = [
10000000000000000n, // minimumDeposit
"0x6149063DF73A0d4065C9083a3E731256Ed10dc95", // owner address
["0xabc...", "0xdef..."], // allowed addresses
];
npx hardhat verify --network monolythium-testnet \
--constructor-args arguments.js \
<contract-address>

Foundry Verify

Foundry's forge verify-contract command supports Monoscan verification.

Basic Verification

forge verify-contract <contract-address> src/MyContract.sol:MyContract \
--chain-id 6940 \
--verifier-url https://testnet.monoscan.xyz/api \
--etherscan-api-key ""

With Constructor Arguments

forge verify-contract <contract-address> src/MessageBoard.sol:MessageBoard \
--chain-id 6940 \
--verifier-url https://testnet.monoscan.xyz/api \
--etherscan-api-key "" \
--constructor-args $(cast abi-encode "constructor(uint256)" 10000000000000000)

With Compiler Settings

If you used specific optimizer settings, pass them explicitly:

forge verify-contract <contract-address> src/MyContract.sol:MyContract \
--chain-id 6940 \
--verifier-url https://testnet.monoscan.xyz/api \
--etherscan-api-key "" \
--num-of-optimizations 200 \
--compiler-version v0.8.19

Check Verification Status

forge verify-check <guid> \
--chain-id 6940 \
--verifier-url https://testnet.monoscan.xyz/api

Multi-File Contracts

Contracts that import from multiple files (e.g., OpenZeppelin) require either standard JSON input or flattened source.

Standard JSON input preserves the original file structure and is the most reliable method.

Hardhat: The verify plugin automatically uses standard JSON input. No extra steps needed.

Foundry: Generate the JSON input and submit it:

# Generate standard JSON input
forge verify-contract <address> src/MyContract.sol:MyContract \
--chain-id 6940 \
--verifier-url https://testnet.monoscan.xyz/api \
--etherscan-api-key "" \
--show-standard-json-input > standard-input.json

You can then paste the contents of standard-input.json into Monoscan's web verification form using the Standard JSON Input option.

Flattened Source

Flattening merges all imports into a single file. Use this as a fallback if standard JSON input fails.

# Hardhat
npx hardhat flatten contracts/MyContract.sol > Flattened.sol

# Foundry
forge flatten src/MyContract.sol > Flattened.sol
注意

Flattened files may contain duplicate SPDX license identifiers or pragma statements. Remove duplicates before submitting to Monoscan.


Proxy Contracts

If your contract uses a proxy pattern (UUPS, Transparent, or Beacon), you need to verify both the proxy and the implementation.

Transparent Proxy

  1. Verify the implementation contract using any method above
  2. Mark as proxy on Monoscan:
    • Go to the proxy contract address on Monoscan
    • Click More Options > Is this a proxy?
    • Monoscan will detect the implementation address from storage slot 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
    • Confirm the detected implementation address
  3. The proxy page will now show the implementation's read/write interface

UUPS Proxy

Same process as transparent proxy. The UUPS implementation address is stored in the same EIP-1967 storage slot.

After Upgrades

When you upgrade a proxy to a new implementation:

  1. Verify the new implementation contract
  2. Monoscan should automatically detect the change on the next page load
  3. If not, re-run the proxy detection process

Troubleshooting

Compiler Version Mismatch

Symptom: Verification fails with "bytecode does not match"

Fix: Ensure the exact compiler version matches. Check your compiled artifacts:

# Hardhat -- check artifacts
cat artifacts/build-info/*.json | jq '.solcLongVersion'

# Foundry -- check cache
cat out/MyContract.sol/MyContract.json | jq '.metadata.compiler.version'

Optimization Settings Mismatch

Symptom: Bytecodes differ despite matching source code

Fix: Optimization must match exactly:

SettingMust Match
Optimizer enabledYes/No must be identical
Optimizer runsExact number (commonly 200)
EVM versionMust match (Monolythium uses paris)
Via IRMust match if enabled

Constructor Argument Encoding

Symptom: "Unable to verify" or "constructor arguments do not match"

Fix: Constructor arguments are ABI-encoded and appended to the deployment bytecode. To extract them:

# Get the deployment transaction input data
cast tx <deploy-tx-hash> --rpc-url https://evm.testnet.mononodes.xyz input

# The constructor args are the trailing bytes after the contract bytecode
# Decode them:
cast abi-decode "constructor(uint256)" <trailing-hex>

Missing Libraries

Symptom: Verification fails for contracts that use external libraries

Fix: Provide library addresses during verification:

# Hardhat
npx hardhat verify --network monolythium-testnet <address> \
--libraries contracts/libs/MyLib.sol:MyLib:<lib-address>

# Foundry
forge verify-contract <address> src/MyContract.sol:MyContract \
--chain-id 6940 \
--verifier-url https://testnet.monoscan.xyz/api \
--etherscan-api-key "" \
--libraries src/libs/MyLib.sol:MyLib:<lib-address>

Verification Pending

Symptom: Verification submitted but status shows "pending"

Fix: Wait a few minutes. If it remains pending, resubmit. Monoscan processes verification requests asynchronously.


FAQ

Does Monoscan require an API key?

No. Use an empty string for the API key in Hardhat and Foundry configurations.

Can I verify a contract deployed on mainnet?

Yes. Replace the Monoscan URL with https://mainnet.monoscan.xyz/api and the chain ID with 6941.

What if my contract was deployed with a different tool than I am verifying with?

That is fine. Verification only compares compiled bytecode. As long as the source code, compiler version, and settings produce the same bytecode, verification will succeed regardless of the deployment tool.

Can I re-verify a contract?

Yes. Re-verification overwrites the previously published source. This is useful if you initially verified with flattened source and want to switch to standard JSON input.

What happens if I verify the wrong source code?

Monoscan compares the compiled bytecode of your submitted source against the on-chain bytecode. If they do not match, verification will fail. You cannot accidentally publish incorrect source for a contract.