Bytecode Verification
June 26, 2026 · View on GitHub
This guide explains how to verify that a USDC deployment's on-chain bytecode matches Circle's reference implementation in this repository.
Prerequisites
Set up the repository by following the instructions in the README. All steps in this guide assume the repository is fully set up.
Setup
Copy the template by running the following command:
cp verification_artifacts/input.template.json verification_artifacts/input.json
Providing Input
Fill in verification_artifacts/input.json with details for the latest
FiatToken implementation contract (FiatTokenV2_2 as of writing), FiatTokenProxy,
and the SignatureChecker library contract.
-
Fill in the
input.jsonfile that you created. For each contract, the required fields are:contractAddresscontractCreationTxHash
You must also provide a standard EVM-compatible node URL in the field:
rpcUrl
There are additional optional parameters for each contract that should only be used if a contract cannot be verified using the required parameters alone. The purpose of each optional parameter is described below:
verificationType: by default, the verification type will be "partial". This means that the metadata hash at the end of the runtime bytecode will be verified separately via the metadata files generated below. Alternatively, this field can be set to "full", but in that case, your contract's metadata must match the metadata in this repo exactly. If this parameter is set to "full", you may skip the metadata extraction described in step 2.useTracesForCreationBytecode: a boolean value for whether or not to use traces for pulling contract creation code. Setting this parameter totrueis only necessary if the contract was deployed within a transaction, i.e. it was deployed from another contract. Note that if this parameter is set totrue, the providedrpcUrlmust support thedebug_traceTransactionJSON RPC method.artifactType: a string to indicate what artifact to use for verification if the contract deployment does not match the current artifacts in the repo. The options for this value can be found in alternativeArtifacts.ts.optimizerRuns: an integer indicating the number of optimizer runs specified when compiling the contract. This is only necessary to include if your value does not match the one in foundry.toml.
-
Follow the steps here to extract metadata for each of the following contracts:
- extract FiatTokenV2_2 metadata to
verification_artifacts/FiatTokenV2_2.json - extract FiatTokenProxy metadata to
verification_artifacts/FiatTokenProxy.json - extract SignatureChecker metadata to
verification_artifacts/SignatureChecker.json
After this step, your local directory should look like
stablecoin-evm ├── verification_artifacts │ ├── FiatTokenV2_2.json │ ├── FiatTokenProxy.json │ ├── SignatureChecker.json │ └── input.json ├── ...Note that the namings are strictly enforced by the verification script.
- extract FiatTokenV2_2 metadata to
Running Verification
Compile the contracts and run the verification script locally:
yarn compile
yarn hardhat run scripts/verifyMainnetTokenBytecode.ts --network mainnet
The script will print a comparison result for each contract. It exits with a non-zero code if any verification fails.
Common Issues
Compiler Settings
Please check your compiler settings and make sure everything, including optimizer runs, matches ours.
Metadata mismatch
Do not format the metadata files--leave them as extracted. Formatting the file will result in a mismatching hash.