How to Deploy Your First Smart Contract on Ethereum With Hardhat and Tenderly
Ready to deploy your first Ethereum smart contract to the blockchain? Follow a step-by-step guide to smart contract deployment with Hardhat and Tenderly and learn what actually happens in the process.
In this post

In this tutorial, you’ll learn how to create and deploy a smart contract to a test blockchain network.
First, you’ll set up Hardhat, a smart contract development environment, and write a smart contract in Solidity. Next, you’ll acquire some ETH from a faucet so you can deploy a smart contract to a test network. Finally, you’ll simulate contract execution with updated parameters using Tenderly to see detailed execution information in a human-readable format.
As an all-in-one Web3 development platform, Tenderly enables you to troubleshoot, debug, optimize, and deploy smart contracts. Tenderly is complementary to Hardhat, so you have all the powerful tools you need to build reliable, foolproof smart contracts.
So, let’s get started!
1. Go to Tenderly Web3 Gateway
For this tutorial, we’ll use Tenderly Web3 Gateway to access the blockchain. If you recently tried to send some ETH via Tenderly Web3 Gateway, you already have a Tenderly account, so just navigate to the Gateway page.
If not, go to the Tenderly sign-up page and fill in the details to create an account. You can either use your email or sign up with Google or GitHub. Tenderly will send you a verification email. Once your email is verified, you’re good to go.
Once you log in, you’ll land on the Web3 Gateway page. Here, you can take note of your Sepolia RPC URL.
ℹ️ Note: At the time of writing this blog post, Sepolia is the recommended testnet, but feel free to use a different one if it suits your project better.
ℹ️ Note: The RPC URL contains your security access token that you shouldn’t share publicly. You can reset it in the Access Control section if needed.
2. Get some ETH on a testnet
Before you proceed:
- Smart contract creation and testing isn’t typically done on the Ethereum Mainnet, but on one of its test networks.
- This allows you to address potential bugs and ensure that your code executes as expected before you deploy a smart contract to the Mainnet.
- You have to pay a gas fee whenever you run a transaction or execute a smart contract on the main Ethereum network or its testnets.
- Testnets don’t offer the same level of reliability, but they simulate everything that happens on the Mainnet and don’t require real ETH.
- You pay gas fees in ETH on the Mainnet and test ETH on testnets.
- You can acquire testnet ETH through so-called “faucets”, a type of tool that provides these tokens for testing and troubleshooting purposes.
Feel free to proceed:
In the next step, get some free ETH for testing on the selected testnet so you can pay gas fees for deploying your smart contract. Tenderly supports a range of testnets, including Sepolia and Goerli.
At the time of writing this article, you can get testnet funds for Sepolia or go with Goerli instead. If these faucets aren’t active, you can look for an active one on the official Ethereum website.
3. Compile and deploy a smart contract
With the basic setup now complete, you can dive into creating a blockchain smart contract.
3.1. Install Hardhat
To set up Hardhat, you need to install the following two packages on your system:
- node.js (we used v18.9.0)
- npm (we used v8.19.1)
Fire up a terminal and complete the following steps:
- Create a directory for your project
mkdir tenderly_deploy_tutorial && cd tenderly_deploy_tutorial
- Initialize the project (this will create the package.json file)
npm init -y
- Install Hardhat
npm install hardhat
- Create a Hardhat project
npx hardhat Select the “empty hardhat.config.js” option:
6. Add libraries to your project. We’ll use ethers to interact with the blockchain and dotenv to hide our secrets. 🤫npm install @nomiclabs/hardhat-ethers ethers dotenv
7. Let’s also add the Tenderly plugin for Hardhat that automatically verifies your smart contract and uploads it to the Tenderly platform. It’s important to verify your smart contract to enable all the functionalities of Tenderly features.
npm install @tenderly/hardhat-tenderly
3.2 Prepare the Ethereum smart contract code
Create a directory for smart contracts and create a contract file:
mkdir contracts && touch contracts/Greeter.sol
Instead of writing a smart contract from scratch, let’s use a ready-made smart contract example for this tutorial. Paste the following code in your newly created Greeter.sol file:
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
contract Greeter {
string private greeting;
constructor(string memory _greeting) {
greeting = _greeting;
}
function greet() public view returns (string memory) {
return greeting;
}
function setGreeting(string memory _greeting) public {
greeting = _greeting;
}
}
3.3. Complete the Hardhat config
Create a .env file that will contain secret information such as your private key and the Tenderly Gateway RPC URL.
touch .env
Open up the .env file in your text editor of choice and add your private key and the Tenderly URL to it like so:
PRIVATE_KEY = # remove this comment and add your wallet’s private key here
TENDERLY_URL = # remove this comment and add the Tenderly Gateway RPC URL you got from step 1 of this tutorial
This file should be added to your .gitignore
list if you’re versioning this project. It’s very important that both your private key and Tenderly Gateway RPC URL do not become public. This way, you can share your project configuration, without worrying about others knowing your secrets.
Next, let's modify the hardhat.config.js file.
It should import the ethers library, set up the network we’re going to use, and prepare our private key for later.
We’ll also call setup
to initialize the Tenderly plugin for automatic smart contract verification. We need to configure hardhat-tenderly
plugin to perform verification automatically and add the verified contract directly to your project.
ℹ️ Aside from configuring the plugin, you also need to authenticate with Tenderly. To do this, either use Tenderly CLI or generate an API key in the Dashboard and place it in ~/.tenderly/config.yaml
under access_key
.
require("@nomiclabs/hardhat-ethers");
require("dotenv").config();
// initialize hardhat-tenderly plugin for automatic contract verification
var tdly = require("@tenderly/hardhat-tenderly");
tdly.setup({automaticVerifications: true});
// we read the private key and tenderly gateway URL
// from the .env file using the dotenv package.
// The .env file should not be pushed or shared!
// This way, we can push the code to git and/or share publicly.
// tenderly gateway url (which contains a secret id)
const tenderlyUrl = process.env.TENDERLY_URL;
//your private key. Make sure this address has some ETH on sepolia
const privateKey = process.env.PRIVATE_KEY;
module.exports = {
solidity: "0.8.17",
networks: {
sepolia_via_tenderly: {
url: tenderlyUrl,
// this will allow us to use our private key for signing TX later
accounts: [`0x${privateKey}`],
// this is the sepolia chain id
// change it if you are using a different network
chainId: 11155111
},
},
tenderly: {
// replace with project slug in Tenderly
project: "project",
// replace with your Tenderly username
username: "my-username",
// perform contract verification in private mode
privateVerification: true,
}
};
3.4. Compile the code
To compile your smart contract, run the following command:
npx hardhat compile
Hardhat will look for smart contracts in your contracts directory, use the compiler version we specified in the hardhat.config.js
file, and store the compilation result in a newly created “artifacts” directory. Again, if you’re versioning your project, you might want to add the artifacts
directory to your .gitignore
list.
You may have already been through this process before, but what really happens when you compile a smart contract?
First, the Solidity compiler identifies all functions, events, and errors in your smart contract and makes an ABI (Application Binary Interface) based on them. Anyone (on- or off-chain) can use the ABI to interact with the smart contract once it’s deployed. You can think of the smart contract ABI as the interface of the contract directed at the outside world. You can see the ABI for your smart contract in artifacts/contracts/Greeter.sol/Greeter.json
.
{
"abi": [
{
"inputs": [
{
"internalType": "string",
"name": "_greeting",
"type": "string"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "greet",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "_greeting",
"type": "string"
}
],
"name": "setGreeting",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
}
Another thing you will find in this file is the bytecode of your contract. In fact, the main purpose of compilation is translating the Solidity source code into EVM bytecode that can be stored on an Ethereum-based blockchain. Each instruction in EVM bytecode can be represented numerically. This is why the generated bytecode is represented as a long string of numbers in base 16.
Compiling a smart contract is essentially translating it from human-readable Solidity source code into this bytecode which is optimized for EVM execution. Functionally, both types of code describe identical behavior for the contract. Now that we have our bytecode prepared, it’s time to put it on the blockchain for everyone to see and use.
3.5. Deploy the smart contract
For Ethereum smart contract deployment, we need to make a simple JS script that will use Tenderly Web3 Gateway to access the blockchain and publish our compiled bytecode. First, create the deployment script:
mkdir scripts && touch scripts/deploy.js
This script contains the procedure for deploying the smart contract. It references our configuration to get the private key of the deployer. The script also targets Tenderly Web3 Gateway to get access to the blockchain. The deployment process consists of signing and sending a transaction that contains the contract bytecode without specifying the recipient.
During the deployment procedure, the address for the contract is determined based on the sender’s address and current nonce, so it’s always unique. Once the smart contract deployment is completed, we’ll print out the address at which it’s stored so we can inspect and interact with it.
Next, edit the deployment script scripts/deploy.js
with your editor of choice:
const { ethers } = require("hardhat");
require("dotenv").config();
async function main() {
// Prepare the deployer wallet -
// this will be based on the private key we set up in config
const [deployer] = await ethers.getSigners();
// Prepare the provider -
// this will give us access to the blockchain via Tenderly Web3 Gateway
provider = new ethers.providers.JsonRpcProvider(process.env.TENDERLY_URL);
// Greeter will be an ethers internal representation
// of the compiled contract
const Greeter = await ethers.getContractFactory("Greeter", deployer);
console.log("Deploying Greeter...");
// greeter will be the instance of our contract that we are about to deploy
const greeter = await Greeter.deploy("Hello from Tenderly!");
// We wait for the deployment to be completed and confirmed
await greeter.deployed();
// This will tell us the address at which the contract was deployed
console.log("Greeter deployed to:", greeter.address);
}
// Do the thing!
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
Finally, run the script:
npx hardhat run --network sepolia_via_tenderly scripts/deploy.js
The script will output the address of your newly deployed contract. The smart contract address in this example is 0x8E69bC733367D80D758080fD12DFc8e6dBAE5185
.
However, since we used automatic contract verification, you don’t need to remember the address. Instead, your contract is automatically added to Tenderly and ready to go.
Congrats! 🎉 Your smart contract is up and running. You can find it in the list of contracts in your Tenderly Dashboard.
You can now use numerous Tenderly features to optimize your smart contract, reduce gas fees, and debug potential errors. So, let’s get playful!
4. Simulate transactions with Transaction Simulator
If you want to further adjust and optimize your contract, you can use Transaction Simulator. It allows you to preview contract execution and inspect the outputs in high detail, without using a testnet.
When you use Transaction Simulator, you give it a contract, a function, the inputs, and other transaction details. In return, it gives you an insight into how that transaction would execute on a real network, without ever having to actually use one.
Transaction Simulator enables you to:
- Avoid waiting and try out your smart contract swiftly during development, without actually using a test network you deployed it to.
- Replay a failed transaction to gain a deeper understanding of its execution and what went wrong i.e. catch the bug.
- Play around with, test, and validate your bug fixes to make sure your updated contract runs as expected in production.
- Simulate a transaction with updated contract source and/or parameters, including the block number, transaction indexes, address, gas, and value.
Cool, right? 😎 Why not give it a try?
4.1. Run a simulation
To run a simulation, select Contracts in the menu on your left and choose your Greeter contract from the list.
In the next view, select Simulate Transaction.
This opens the simulation window. Here, select the setGreeting
function in the Function dropdown menu for a basic interaction. Under Input Parameters, type in a string such as “Hello world!”
Run the simulation by clicking Simulate Transaction.
4.2. Check the simulation output
Next, you can see whether your transaction simulation executed successfully or not. You can also find any related information, such as how much gas your transaction used, transaction index, nonce, and other details. By clicking View input data, you can check out the transaction input.
You can run the transaction again by clicking Re-Simulate in the top right corner.
5. Edit the contract source
Before re-simulating the transaction, you can change the contract source code by clicking Edit Contract Source.
This opens the Editing Source view where you can see and edit the source.
Next, change the greet()
function and replace the return value with a string. Once done, click the Apply Changes button in the bottom left corner and then Simulate Transaction.
Again, you can find the details about your successful transaction in the next view. In the output data section, you’ll find the string you added to the source code.
6. Deploy your smart contract to start experimenting
In just a few steps, you can learn how to create and deploy a smart contract to the blockchain, as well as what’s going on under the hood. The Tenderly platform gives you all the needed tools for developing smart contracts. Plus, it's complementary to the Hardhat environment, fully supporting your development flow.
Ready to level up? Try to build a real multi-signature wallet to send and secure your ETH. Start by using the all-in-one Tenderly platform to build, test, optimize, and monitor your smart contracts in one place. So, join Tenderly for free and discover the easy way of developing and deploying smart contracts.
Use Tenderly Node Extensions to build custom RPC endpoints that fit your dapp without changing its existing logic. Optimize dapp performance, improve user experience, and get greater control and flexibility both on-chain and during development.
Try Tenderly Node ExtensionsSubscribe to our newsletter