Verify source code with Sourcify
Overview
This guide explain how to verify a smart contract on Ronin by submitting the source code and metadata to Ronin's internal Sourcify service.
Verify using hardhat-deploy
There are two options to verify the contract using hardhat-deploy
:
invoke the command-line tool and integrate in the deployment script.
Option 1. Command-line tool
If your smart contract project uses hardhat-deploy
as a dependency,
specify the endpoint and network before verifying by
using the hardhat sourcify
command:
hardhat sourcify --endpoint https://sourcify.roninchain.com/server --network <ronin>
For more information, see hardhat-sourcify.
Option 2. Script
- Save the following script into
deploy/verify-contract.ts
.
import { TASK_SOURCIFY } from 'hardhat-deploy';
import { network } from 'hardhat';
import { HardhatRuntimeEnvironment } from 'hardhat/types';
const deploy = async (hre: HardhatRuntimeEnvironment) => {
if (network.name == 'ronin' || network.name == 'saigon') {
await hre.run(TASK_SOURCIFY, {
endpoint: 'https://sourcify.roninchain.com/server',
});
}
};
deploy.tags = ['VerifyContracts'];
deploy.runAtTheEnd = true;
export default deploy;
- Include this script in the actual deployment script's dependencies. For example:
deploy.dependencies = ['VerifyContracts'];
Verify using Sourcify UI
Step 1. Locate smart contract metadata
Smart contract's metadata is automatically generated by the Solidity compiler in the
form of a .json
file. It contains information about the compiled smart contract.
The metadata is located in different locations depending on the tool you use to
compile smart contracts.
Solidity compiler contract metadata
If you use solc
for compiling, then run solc
with the --metadata
option to print the contract's metadata.
The following command prints out the metadata for the Token.sol
file.
solc Token.sol --metadata
The output in the terminal is as follows:
======= Token.sol:Token =======
Metadata:
{"compiler":{"version":"0.8.20+commit.a1b79de6"},"language":"Solidity","output":{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{"balanceOf(address)":{"notice":"Read only function to retrieve the token balance of a given account. The `view` modifier indicates that it doesn't modify the contract's state, which allows us to call it without executing a transaction."},"constructor":{"notice":"Contract initialization."},"transfer(address,uint256)":{"notice":"A function to transfer tokens. The `external` modifier makes a function *only* callable from *outside* the contract."}},"version":1}},"settings":{"compilationTarget":{"Token.sol":"Token"},"evmVersion":"shanghai","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":false,"runs":200},"remappings":[]},"sources":{"Token.sol":{"keccak256":"0xa79117cae1147d7d93c6e5653e26d2ce4a6669f211a7de27ffc2ac61c57a115b","license":"UNLICENSED","urls":["bzz-raw://1b28ac474b44450104fc99400a70947517e0869274a3537c9d0ea8047d7b8146","dweb:/ipfs/QmYreFmttckn7Mru8z1oe89sVbWVUBd2WxvX8w12yreaFF"]}},"version":1}
Copy the JSON object starting at {”compiler”:...
to a new file and save it as metadata.json
.
The metadata.json
generated this way doesn't include the source code.
You need to upload both the source code in .sol
and the
metadata.json
file to Sourcify.
Hardhat contract metadata
If you use Hardhat for compiling your smart contract, then after running the
hardhat compile
command,
you can find the metadata file in the artifacts/build-info
directory.
Hardhat includes the source code in the metadata file. You can upload just this
.json
file to Sourcify.
Step 2. Submit information
After you find the metadata and source code, upload them to Sourcify. If your files are valid, a contract's details form is displayed on the right side of the page.
To complete the verification process, fill out the smart contract address and select the chain to which it is deployed.
When verification is complete, a Verification successful!
message appears (pictured).

To interact with the example contract on the Ronin app and view its source code, visit https://saigon-app.roninchain.com/address/ronin:6df3a52ca77b2b785b9d9cb454725969e006c718?t=contract.
Verify using the API
The API endpoint of verification is public and available to all users. This endpoint can be used to verify the authenticity and integrity of data related to your contracts.
Endpoints:
POST https://sourcify.roninchain.com/server/verify
POST https://sourcify.roninchain.com/server/verify/create2
For further information and instructions on how to use the verify API endpoint, see Verification API.