ByAUJay
Smart Contract Verification: Source Code, Bytecode, and On‑Chain Metadata
Startups and enterprises can really only consider a deployed contract a “known good” binary when its source code, compiler settings, and the resulting bytecode are all clearly tied together. This guide takes that idea and turns it into a practical playbook for decision-makers, offering you some 2025-ready strategies for EVM chains.
Summary (meta description)
Here's a handy playbook to get you ready for 2025 when it comes to enterprise-level smart contract verification on platforms like Etherscan, Sourcify, and Blockscout. We’ll cover everything from source and bytecode linkage, CBOR metadata, proxies, and immutables to constructor arguments. Plus, we'll dive into some of the latest practices, including ethdebug, cross-chain sharing, and attested build provenance. Check it out here: (hardhat.org)
Why verification matters more in 2025
- Ethereum’s Pectra upgrade officially launched on May 7, 2025 (epoch 364,032). This upgrade introduced EIP‑7702, also known as “EOA code,” which offers a cool feature: it allows externally owned accounts to temporarily pass off execution to deployed code. This really emphasizes the importance of clarity when it comes to authorizing code--users need to know exactly what they're getting into! (ethereum.org)
- While the EVM Object Format (EOF) hasn't made it to the mainnet yet, Solidity 0.8.29 rolled out with some experimental EOF support. Plus, the core developers are hinting that EOF will be part of future hard forks. It's a good idea for verification tools and processes to get ready for what EOF will bring, especially in terms of code/data separation and new validation rules. (soliditylang.org)
Takeaway: Verification isn't just a "nice to have" anymore; it's become a crucial operational control that supports secure wallets, smooth upgrade processes, and cross-chain deployments.
The three pillars: Source code, bytecode, on‑chain metadata
- Source Code and Compiler Settings
- The Solidity compiler generates a metadata JSON that records sources, the compiler version, optimizer runs, EVM version, libraries, and ABI. It's a good idea to make this your go-to build artifact in your CI. Check out the details here.
2) Bytecode (creation vs runtime)
- The creation (init) code is executed just once when you deploy your contract, while the runtime code lives on the blockchain and is what users interact with. When verifying, we compare the bytecode we recompile locally to the runtime bytecode on-chain, and sometimes even the init code. Check out more details in the Sourcify documentation.
3) On-chain metadata (CBOR auxdata)
- By default, Solidity sticks a CBOR-encoded trailer onto the bytecode. This trailer includes the IPFS (or Swarm) content hash of the metadata along with the solc version. Plus, the last two bytes of the deployed bytecode actually encode the CBOR length, which makes it easier to parse reliably. (docs.soliditylang.org)
Why this matters: When the runtime bytecode has the metadata hash and it lines up with your metadata.json, you create a solid cryptographic link that connects the chain to the metadata and the precise sources/settings you used to build. (docs.soliditylang.org)
“Exact match” vs “match”: what your status really means
- Sourcify has two levels of verification:
- exact_match: This means the runtime/creation bytecode and the metadata hash all match up perfectly with your sources and settings (this was previously known as “full/perfect match”).
- match: Here, the bytecodes match up, but we ignore any differences in metadata hashes. This comes in handy when metadata is either missing or has been changed.
- Right now, Vyper contracts can't achieve an exact_match since Vyper doesn't include metadata hashes in the bytecode. You can read more about this here.
Blockscout and other explorers make great use of Sourcify data to show the verification status right in their user interface and APIs. Plus, Blockscout's verification pipeline and EBD microservice go the extra mile by sharing verified artifacts across different chains. Check out more details in the Blockscout documentation!
What’s inside Solidity’s CBOR metadata section (and how to read it)
Solidity uses a default trailer that encodes keys such as ipfs, bzzr1, experimental, and solc. It's actually CBOR-encoded, so instead of hardcoding the prefix, it’s better to read the last two bytes to figure out the CBOR length and then decode from there. You’ll come across some example values in real-life situations, especially on Sourcify repository pages. These include the raw trailer hex and the decoded IPFS multihash. Check it out here: (docs.soliditylang.org).
Minimal Decoding Approach:
When it comes to decoding, a minimal approach can often simplify the process while still getting the job done. Here’s how you can tackle it effectively:
Steps to Implement Minimal Decoding
- Identify the Data: Start by figuring out exactly what kind of data you’re working with. Is it text, binary, or something else?
- Choose the Right Method: Depending on your data type, select a decoding method that requires the least overhead. For example, if you're dealing with simple text, UTF-8 decoding might be enough.
- Use Efficient Libraries: Leverage libraries that are lightweight yet effective. For Python, something like
codecsorbase64can be super handy.import base64 # Example of simple base64 decoding encoded_data = "SGVsbG8sIFdvcmxkIQ==" decoded_data = base64.b64decode(encoded_data).decode('utf-8') print(decoded_data) # Outputs: Hello, World! - Test Your Output: Always check that your decoded data looks right. It’s easy to miss an error in the process, so validation is key.
- Optimize for Performance: If you're working with large datasets, consider ways to streamline your approach. Batch processing can save loads of time.
Benefits of a Minimal Decoding Approach
- Simplicity: Fewer steps mean less room for errors.
- Speed: By cutting out unnecessary processes, you’ll likely see quicker results.
- Ease of Maintenance: Simpler code is easier to read and update down the line.
By keeping it straightforward and focusing on what’s essential, you can achieve effective decoding without unnecessary complexity!
Conclusion
The minimal decoding approach isn’t just about getting by; it’s about maximizing efficiency and keeping things as seamless as possible. Embrace the simplicity, and you might just find that it opens up new possibilities for your projects!
// Given deployed runtime bytecode as a hex string "0x...":
const hex = deployedBytecode.slice(2);
const len = parseInt(hex.slice(-4), 16); // last 2 bytes = CBOR length (big-endian)
const cborHex = hex.slice(hex.length - (len*2 + 4), hex.length - 4);
// Decode cborHex with a CBOR lib, e.g. 'cbor-x', to get { ipfs, bzzr1, solc, experimental }
If you're looking for a handy reference implementation that can turn the “ipfs” multihash into a CIDv0/v1 and grab that metadata.json, check out some community tools like solc‑metadata. You can find more info here.
Practical implications:
- Make sure that
settings.metadata.bytecodeHashis set to “ipfs” (which is the default) and keepsettings.metadata.appendCBORset to true to maintain the exact match potential. Just a heads up: Solidity version 0.8.18 introduced flags that let you skip CBOR, but it's best to avoid those in production unless you're totally clear on the trade-offs involved. (docs.soliditylang.org)
Constructor arguments, immutables, and libraries: the usual verification pain points
- When you deploy a contract, the constructor arguments get ABI-encoded and tacked on to the end of the creation code. If you're using explorers like Etherscan, you'll need to submit these for your verification to go through smoothly. So, make sure to grab and save them when you deploy! (info.etherscan.com)
- Immutable variables get inlined right into the deployed runtime bytecode at specific offsets. For verification, you'll need the compiler’s immutableReferences map to reset those offsets before you start comparing bytecode. Just a heads up, the exact_match check will only pass if these positions and values are in sync. (docs.solidity.org)
- Don’t forget, libraries need to be linked in a deterministic way! If the library addresses are mismatched or not linked, you’ll end up with different bytecode. Make sure your Standard JSON includes the libraries mapping, or your framework should handle injecting them for you. (docs.soliditylang.org)
Decision‑maker checklist:
- Make sure your deploy scripts store important details: constructor arguments (ABI-encoded), solc version, optimizer runs, evmVersion, libraries used, and the build hash (commit SHA, artifact digest). It’s a good idea to keep these alongside metadata.json. Check out the details here.
Proxy and upgradeable systems: verify both proxy and logic
- Keep in mind that a proxy’s address is different from the logic you’re actually calling. The EIP‑1967 standard has set up specific storage slots for implementation, admin, and beacon addresses. Explorers and tools look at these slots to show you the implementation. So, it's essential for your process to check the proxy, the implementation, and (if it’s in use) the beacon. (eips.ethereum.org)
- Platforms like Etherscan and Blockscout are pretty good at spotting common patterns like EIP‑1967, Beacon, UUPS, and Diamond. They’ll give you both the proxy and implementation views. But don’t just take “proxy is verified” at face value--make sure the current implementation contract is also verified. (medium.com)
Operational Pitfalls
- Attackers might mask harmful logic by using layers of proxies or custom slots. It’s a good idea for institutional policies to mandate checking the standardized storage slots and confirming the source/bytecode link of the current implementation before diving in. (eips.ethereum.org)
Cross‑chain and cross‑explorer verification
- A lot of contracts tend to use the same runtime across EVM chains by making use of CREATE2 or factory patterns. To tackle the issue of fragmentation, Blockscout’s Ethereum Bytecode Database (EBD) comes into play by sharing verified contract information across different chains. It’s a smart move to use tools that tap into these shared datasets. (docs.blockscout.com)
- CREATE2 is pretty nifty since it enables you to derive addresses in a predictable way using salt, deployer, and init code. Make sure your verification process keeps track of the salt and the hash of the init code; it’ll make things way easier when you need to reproduce or audit later on. (eips.ethereum.org)
- Etherscan is handy too--it provides “Cross‑Chain Similar Match Verification” along with a single API key that works across its explorers. This is particularly useful for businesses juggling multiple chain deployments. (info.etherscan.com)
Practical, step‑by‑step verification flows
A) Hardhat (multi-provider programmatic verification)
- Check out
@nomicfoundation/hardhat-verify. It works seamlessly with Etherscan, Sourcify, and Blockscout. Just make sure your build profile matches up when you’re compiling and verifying to steer clear of any sneaky mismatches. (hardhat.org)
// hardhat.config.ts
import { defineConfig } from "hardhat/config";
import hardhatVerify from "@nomicfoundation/hardhat-verify";
export default defineConfig({
plugins: [hardhatVerify],
etherscan: { apiKey: process.env.ETHERSCAN_API_KEY },
sourcify: { enabled: true }, // optional
});
// Verify a deployment
npx hardhat build --build-profile production
npx hardhat verify --network mainnet DEPLOYED_ADDRESS "arg1" "arg2"
B) Foundry (one-shot deploy + verify)
- When you use
forge create, make sure to include--verifyand pick your verifier--either etherscan, sourcify, or blockscout. If you're working with existing contracts,forge verify-contractlets you support various chains and even custom verifier URLs. You can also automate this process right from your CI/CD setup. Check out the details in the Etherscan documentation.
forge create --broadcast \
--rpc-url $RPC_URL --private-key $PK \
src/MyContract.sol:MyContract \
--constructor-args "Name" "SYM" 18 \
--verify --verifier etherscan --etherscan-api-key $ETHERSCAN_API_KEY
C) Sourcify API v2 and UI
- Our shiny new API v2 now gives you access to “exact_match” vs “match,” ABIs, and specific details for each contract. Plus, the verify.sourcify.dev UI makes life easier by letting you import directly from Etherscan (just use your API key locally in your browser). You can also upload your Hardhat/Foundry build-info and check out bytecode diff views whenever there are failures. Check it out here: (docs.sourcify.dev)
D) Blockscout
- Blockscout uses Sourcify for verifying contracts, so you can check the match status and get sources/ABI if everything checks out. Just a heads-up, the constructor arguments aren’t included in the metadata, so you might need the creation input to piece it all together. (docs.blockscout.com)
Recommended compiler settings for verifiability
In your Standard JSON input (or whatever framework you're using), make sure to set the following options:
settings.metadata.bytecodeHash: "ipfs" (this is the default setting)settings.metadata.appendCBOR: true (if you're using Solidity version 0.8.18 or higher, you can turn this off, but it's best to leave it on unless you really have to)settings.metadata.useLiteralContent: true (this helps avoid those confusing opaque URLs in your metadata)- Don't forget to specify the
evmVersionthat matches your target fork (like "paris", "shanghai", "cancun"). For EOF experiments, you’ll use "Osaka" in version 0.8.29, but remember, it's not available on mainnet--stick to sandboxes for that one. (docs.soliditylang.org)
Security Note
Hey, just a quick tip: try not to flatten sources for verification unless it’s absolutely necessary. It’s better to stick with Standard JSON or build-info so you can keep the original compiler inputs intact. You can check out more details here.
Metadata hosting and availability
- In the past, Solidity documentation needed you to publish a metadata.json file to IPFS or Swarm, so others could fetch it using its hash. But now, with Sourcify’s repository, verified contracts and their metadata are mirrored, making it way easier to access them long-term -- even if IPFS pins go away. (docs.soliditylang.org)
Enterprise Practice
- Make sure to pin
metadata.jsonand all your sources to IPFS during the build process. Don’t forget to record the CID(s) in your release notes, and verify everything on Sourcify so that the repo keeps a copy too. Check out the details here: (docs.sourcify.dev)
EOF is coming: what will change for verification?
EOF (EIP‑3540 and friends, all bundled up under EIP‑7692) brings some cool new features, like code/data sections and validation at deployment time. You’ll notice that some introspection opcodes work a bit differently with EOF contracts--check out the EXTCODE* semantics for example. Plus, relative jump families are taking over from the old-school flows.
Make sure your explorers and verifiers can handle parsing EOF containers and can pull out metadata for each section once it hits the mainnet. It's a good idea to start testing on devnets or using the experimental backends in the compiler. You can find more details here.
Governance and compliance: institutionalizing verification
- Start by using the OWASP Smart Contract Security Verification Standard (SCSVS) as your starting point. Don't forget to add those "exact_match or fail" gates for any production deployments. You can check it out here.
- Keep an eye on the Verifier Alliance’s shared database exports to ensure you're tracking cross-ecosystem provenance. It's also a good idea to favor explorers that either contribute to or utilize these shared datasets. More info can be found here.
- If you've been using OpenZeppelin Defender for your post-deployment operations or monitoring, make sure you plan to migrate by July 1, 2026. You’ll want to align your verification and monitoring pipelines with their open-source alternatives. Check out the details here.
Optional Provenance Layer
- You can publish an attestation (like through EAS) that connects the contract address to the metadata CID, commit SHA, and build system fingerprint. This way, auditors can check the provenance without having to rely on any centralized records. (github.com)
Emerging best practices that materially reduce risk
- Aim for exact_match whenever you can
- When it comes to Solidity, go for that exact_match (you know, runtime bytecode + metadata hash proven). If you can only manage a match (like with Vyper), make sure to explain why, and step it up with a more thorough review. (docs.sourcify.dev)
2) Verify proxy + implementation + beacon
- Make sure to check all three components and include reading EIP‑1967 slots during those risk assessments. It’s a good idea to automate this in your explorer tools and dashboards. You can find more details here: (eips.ethereum.org)
- Make constructor arguments first-class citizens
- Keep the ABI-encoded constructor arguments and the transaction that deployed the contract. Store them with your build artifacts so that verification is never held up by the need to reverse-engineer them. (info.etherscan.com)
- Lock compiler/toolchain versions
- Make sure to pin the solc version (go for the exact build instead of just “latest”), along with your optimizer settings and evmVersion. Don’t forget to archive the Standard JSON and build-info, too. Using mixed or floating versions can lead to annoying mismatches. (docs.soliditylang.org)
- Use multi-provider verification in CI
- During your deployments, make sure to run Hardhat/Foundry verification for Etherscan, Sourcify, and Blockscout. If any of these providers can’t match the exact output for Solidity, your pipeline should fail. For more details, check out the documentation at hardhat.org.
- Get Ready for EOF
- Throw in some tests that work with the solc EOF backend (Osaka) in your non-prod profiles. This way, you can spot any tooling issues before they become a hassle. Also, keep an eye on the progress of the EOF meta EIP. Check it out here: (soliditylang.org).
7) Cross‑chain reproducibility
- When you're working with CREATE2 deployments, make sure to keep a record of the salt and the
keccak256(init_code). For factory deployments, it’s super important to hang onto the determinism rules. This step is vital if regulators or partners need you to reproduce specific addresses. (eips.ethereum.org)
Example: end‑to‑end verification with proxies and immutables
Scenario: You set up a Transparent (EIP‑1967) proxy that points to Implementation v1, which utilizes immutable variables and libraries.
- First things first, build using Standard JSON with these settings:
metadata.bytecodeHash=ipfs,appendCBOR=true, anduseLiteralContent=true. Don't forget to archive yourmetadata.json, ABI, build info, constructor arguments, and library addresses. You can find more details here. - Next up, you'll want to verify your implementation on Sourcify. Make sure to expect an exact match here, and don’t forget about Etherscan! If your implementation uses immutables, just a heads up: the verifier needs to zero out
immutableReferencesbefore you compare. Check out the specifics here. - Now, let’s verify the proxy. Typically, your constructor arguments will include the implementation address along with the initialization calldata. Make sure that the explorer recognizes the proxy and clearly shows the implementation/admin slots. You can dive into the details here.
- After deployment, you’ll want to assert the exact match using the Sourcify API v2. Also, remember to take a snapshot of the ABI from your
metadata.json(that'soutput.abi) for any downstream systems you might be working with. More info can be found here.
Byte‑level sanity check: recognize the metadata trailer
You might come across deployed bytecode that often ends with a pattern like this:
... a2646970667358 2212 <34 bytes> 64 736f6c63 4300 08xx 0033
Check out the CBOR map (like “a2” or “a4” etc.) that includes the “ipfs” and “solc” keys, which are then followed by a 2-byte length. Just a heads-up: don’t count on a fixed prefix! Always make sure to read that 2-byte length at the end to properly locate and decode the CBOR. (docs.soliditylang.org)
What about “verification = safety”?
- Verification shows “code equivalence,” but it doesn’t guarantee “code correctness.” Just because a proxy is verified doesn’t mean it’s free from malicious logic; the same goes for a verified implementation, which could still harbor harmful functions. Make sure to educate users and internal approvers about this. (medium.com)
A procurement‑grade checklist you can enforce today
- Compiler and Build
- Make sure to pin the exact version of
solc; archive both the Standard JSON and build info. - Update
metadata.bytecodeHash=ipfs, useappendCBOR=true, and setuseLiteralContent=true. Check out the details here.
- Make sure to pin the exact version of
- Arguments and Libraries
- Keep a record of ABI-encoded constructor arguments; it’s important to pin down library addresses and names. More info on that can be found here.
- Verification Gates
- You’ll need to ensure an exact match on Sourcify for Solidity--if it doesn’t match, the deployment will fail (but don't worry, there's a waiver for Vyper). Here are the specifics here.
- Remember to verify on at least two different platforms (like Etherscan and Sourcify).
- Proxies
- Make sure to verify the proxy, the implementation, and the beacon (if you've got one). It's good to read the EIP-1967 slots and keep track of the admin and implementation during both deployment and upgrades. For more information, check this link.
- Cross-Chain
- Don’t forget to save CREATE2 salts and the init code hashes. Keep an eye on verification across different explorers (when possible, use Etherscan’s cross-chain similar match; also, keep watch on Blockscout EBD). More on that can be found here.
- Attest Provenance
- Publish EAS attestations that link the address to the metadata CID and the commit SHA for consumer-verifiable provenance. Check out the details here.
- Compliance
- Make sure to align with OWASP SCSVS and document the verification evidence for each release. You can find more about it here.
Closing thought
Verification is like your cryptographic chain of custody, tracking everything from Git commits to what happens on-chain. By 2025, once Pectra is up and running and EOF is just around the corner, the teams that nail down exact_match verification, keep proxy/implementation parity in check, and provide solid provenance attestations are going to make life a lot easier. They'll cut down on operational risks and speed up audits across every EVM they interact with. (ethereum.org)
References and further reading
- Check out the scoop on Solidity metadata and CBOR auxdata, plus some handy compiler options for metadata hash and the CBOR appendix. (docs.soliditylang.org)
- Dive into Sourcify's exact_match vs match features, API v2 endpoints, and the verification UI. (docs.sourcify.dev)
- Need help with Etherscan verification? Don't miss their docs on constructor arguments. (info.etherscan.com)
- Explore Blockscout’s verification pipeline and the Ethereum Bytecode Database--it’s pretty cool! (docs.blockscout.com)
- Get a grip on proxy standards with EIP‑1967. (eips.ethereum.org)
- Learn about CREATE2 determinism in EIP‑1014. (eips.ethereum.org)
- Check out Solidity immutables and their verification implications. (docs.solidity.org)
- Pectra's mainnet activation and EIP‑7702 are on the horizon--get ready! (ethereum.org)
- Keep an eye on EOF meta/EIPs and experimental compiler support. (eips.ethereum.org)
- Don’t forget to check the OWASP SCSVS baseline. (owasp.org)
7Block Labs is here to assist teams in putting these controls into action--whether it’s through build pipelines, cross-explorer verification, or provenance attestations--on Ethereum and the leading Layer 2s. If you're looking for a quick readiness assessment to check out your verification posture, just reach out! We’d love to help.
Like what you're reading? Let's build together.
Get a free 30-minute consultation with our engineering team.
Related Posts
ByAUJay
Building 'Private Social Networks' with Onchain Keys
Creating Private Social Networks with Onchain Keys
ByAUJay
Tokenizing Intellectual Property for AI Models: A Simple Guide
## How to Tokenize “Intellectual Property” for AI Models ### Summary: A lot of AI teams struggle to show what their models have been trained on or what licenses they comply with. With the EU AI Act set to kick in by 2026 and new publisher standards like RSL 1.0 making things more transparent, it's becoming more crucial than ever to get this right.
ByAUJay
Creating 'Meme-Utility' Hybrids on Solana: A Simple Guide
## How to Create “Meme‑Utility” Hybrids on Solana Dive into this handy guide on how to blend Solana’s Token‑2022 extensions, Actions/Blinks, Jito bundles, and ZK compression. We’ll show you how to launch a meme coin that’s not just fun but also packs a punch with real utility, slashes distribution costs, and gets you a solid go-to-market strategy.

