Deploy and Verify Smart Contracts with Hardhat 3
Hardhat is a development environment for compiling, testing, deploying, and verifying EVM smart contracts.
This guide shows how to deploy a contract to Telos with Hardhat 3 and verify it with Sourcify. It uses the current Telos RPC endpoints and the current Hardhat verification plugin. It does not use the legacy hardhat-deploy Sourcify task.
What you will do
- Create a Hardhat 3 project.
- Configure Telos mainnet and testnet.
- Deploy a
Greetercontract. - Verify the deployed contract with Sourcify.
Prerequisites
- Node.js 22 or newer
- A Telos EVM wallet with TLOS for gas
- A private key for the network you want to deploy to
Never commit private keys. Store them in .env, add .env to .gitignore, and use a funded testnet wallet while learning.
Create the project
mkdir telos-hardhat
cd telos-hardhat
npm init -y
npm pkg set type=module
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox-mocha-ethers dotenv
Create these folders:
mkdir contracts scripts
Configure Telos networks
Create hardhat.config.ts in the project root:
import "dotenv/config";
import { defineConfig } from "hardhat/config";
import hardhatToolboxMochaEthers from "@nomicfoundation/hardhat-toolbox-mocha-ethers";
const telosPrivateKey = process.env.TELOS_PRIVATE_KEY;
const telosTestnetPrivateKey = process.env.TELOS_TESTNET_PRIVATE_KEY;
export default defineConfig({
plugins: [hardhatToolboxMochaEthers],
solidity: {
version: "0.8.28",
},
networks: {
telos: {
type: "http",
url: "https://rpc.telos.net",
chainId: 40,
accounts: telosPrivateKey ? [telosPrivateKey] : [],
},
telosTestnet: {
type: "http",
url: "https://rpc.testnet.telos.net",
chainId: 41,
accounts: telosTestnetPrivateKey ? [telosTestnetPrivateKey] : [],
},
},
});
Create .env and add the private key for the network you will use:
TELOS_TESTNET_PRIVATE_KEY=0xYOUR_TESTNET_PRIVATE_KEY
TELOS_PRIVATE_KEY=0xYOUR_MAINNET_PRIVATE_KEY
Add .env to .gitignore:
printf "\n.env\n" >> .gitignore
Add the contract
Create contracts/Greeter.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
contract Greeter {
string private greeting;
constructor(string memory initialGreeting) {
greeting = initialGreeting;
}
function greet() public view returns (string memory) {
return greeting;
}
}
Compile the contract:
npx hardhat compile
Expected result:
Compiled 1 Solidity file with solc 0.8.28
Add the deploy script
Create scripts/deploy.ts:
import { network } from "hardhat";
const { ethers } = await network.create();
const greeter = await ethers.deployContract("Greeter", ["Hello, Telos!"]);
await greeter.waitForDeployment();
console.log(`Greeter deployed to ${await greeter.getAddress()}`);
Deploy to Telos testnet
Run the deployment script against Telos testnet:
npx hardhat --network telosTestnet run scripts/deploy.ts
Expected result:
Greeter deployed to 0x...
Save the deployed address. You need it for verification.
To deploy to mainnet instead, use:
npx hardhat --network telos run scripts/deploy.ts
Verify with Sourcify
Verify the testnet deployment:
npx hardhat --network telosTestnet verify sourcify DEPLOYED_CONTRACT_ADDRESS "Hello, Telos!"
Verify the mainnet deployment:
npx hardhat --network telos verify sourcify DEPLOYED_CONTRACT_ADDRESS "Hello, Telos!"
Replace DEPLOYED_CONTRACT_ADDRESS with the address printed by the deployment script.
The constructor arguments passed to verify sourcify must exactly match the constructor arguments used during deployment. In this guide, the constructor argument is "Hello, Telos!".
Check the contract in the explorer
- Mainnet explorer: https://www.teloscan.io/
- Testnet explorer: https://testnet.teloscan.io/
Paste the deployed address into the explorer search bar. After verification is indexed, the contract source and ABI should be visible on the contract page.
Telos network reference
| Network | RPC URL | Chain ID | Explorer |
|---|---|---|---|
| Telos mainnet | https://rpc.telos.net | 40 | https://www.teloscan.io/ |
| Telos testnet | https://rpc.testnet.telos.net | 41 | https://testnet.teloscan.io/ |
Troubleshooting
https://testnet.telos.net/evm or https://mainnet.telos.net/evm returns 404
Those are legacy endpoints. Use the current RPC URLs:
- Mainnet:
https://rpc.telos.net - Testnet:
https://rpc.testnet.telos.net
Hardhat cannot find an account
Check that your .env file exists, the variable name matches the network, and the private key starts with 0x.
telosTestnetusesTELOS_TESTNET_PRIVATE_KEYtelosusesTELOS_PRIVATE_KEY
Sourcify says the bytecode does not match
Recompile and verify with the same Solidity version and constructor arguments used for deployment. If you changed compiler settings after deploying, restore the deployment settings before verifying.
Verification is accepted but the explorer does not show the source immediately
Wait a few minutes and refresh the contract page. Indexing can lag behind the Sourcify response.