Recommended resources
The freely available resources this lesson will direct you to.
Hello! Welcome back to our journey into Solidity and smart contract development.
In the last lesson, we focused on what functions are allowed to do with a contract's state during its lifetime, using the view and pure keywords. Now, we'll shift our attention to the very beginning of a contract's life: its creation.
Today's lesson addresses a fundamental part of a contract's lifecycle: how to implement a constructor to initialize contract state upon deployment. Given your background in backend development with languages like Java, the concept of a constructor should feel familiar. It's a special function that sets up an object's initial state—and in Solidity, it does the same for a smart contract.
What is a Constructor?
A constructor is an optional, special function that is executed only once, at the exact moment a smart contract is deployed to the blockchain. Its primary purpose is to set the initial values of your state variables.
Key properties of a constructor:
- It has the special name
constructor. - A contract can only have one constructor.
- It is executed only once and cannot be called again after deployment.
- It's the perfect place to set up permanent values, like the contract owner, the name of a token, or its initial supply.
To start, let's watch a quick, clear explanation of what a constructor is and how to define one. This video from Smart Contract Programmer covers the core concepts perfectly.
Watch the video from the beginning until 01:23. Pay close attention to the syntax, how it uses msg.sender to set an owner, and how it accepts an input parameter to initialize another state variable.
Initializing State: Simple vs. Parameterized
Constructors can be simple (taking no arguments) or parameterized (taking arguments).
1. Simple Constructor: Setting the Owner
A common and critical use case for a constructor is to permanently set the contract's owner. Inside the constructor, the global variable msg.sender refers to the address of the account that is deploying the contract.
Let's look at the official Hardhat tutorial's Token.sol example.
Writing and compiling smart contracts
This official Hardhat documentation provides a great example of a simple constructor in the context of a token contract.
In the code block for Token.sol, locate the constructor() function. Notice how it takes no arguments but uses msg.sender to initialize the owner state variable and assign the totalSupply to the deployer's balance.
Here is the relevant snippet from that contract:
// An address type variable is used to store ethereum accounts.
address public owner;
// A mapping is a key/value map. Here we store each account's balance.
mapping(address => uint256) balances;
uint256 public totalSupply = 1000000;
/**
* Contract initialization.
*/
constructor() {
// The totalSupply is assigned to the transaction sender, which is the
// account that is deploying the contract.
balances[msg.sender] = totalSupply;
owner = msg.sender;
}
In this case, whoever deploys this contract automatically becomes the owner and receives all the initial tokens.
2. Parameterized Constructor: Customizing at Deployment
The real power of constructors comes from their ability to accept arguments. This allows you to deploy multiple, uniquely configured instances of the same contract without changing the source code. For your goal of creating a token, this is how you'll set its name, symbol, and total supply at the moment of creation.

This is where the process connects to your development environment. When you deploy a contract using a tool like Hardhat, your deployment script will pass the required arguments to the constructor.
Let's see how this works in a more realistic token example.
Deploying ERC20 Token With Hardhat: A Step-by-Step Guide
This guide from Semaphore demonstrates deploying an ERC20 token and shows a constructor that takes arguments. It then shows the corresponding deployment script that passes those arguments.
First, read the section 'Creating the ERC20 Token' and find the MyToken.sol code. Pay close attention to the constructor which accepts cap and reward. Then, skip down to the section 'Creating Our Deploy Script' and examine the main function in the deploy.js script. Notice the line MyToken.deploy(100000000, 50). This is the key part that passes the values to the constructor during deployment.
As you saw in the article, the contract's constructor is defined to accept a cap and a reward:
// From MyToken.sol
constructor(uint256 cap, uint256 reward)
ERC20("MyToken", "MYT")
ERC20Capped(cap * (10 ** decimals())) {
owner = payable(msg.sender);
_mint(owner, 50000000 * (10 ** decimals()));
blockReward = reward * (10 ** decimals());
}
(Note: ERC20(...) and ERC20Capped(...) are calls to the constructors of parent contracts, a concept we'll cover later.)
And the deployment script passes these values in the deploy function call:
// From deploy.js
async function main() {
const MyToken = await hre.ethers.getContractFactory("MyToken");
// The arguments 100000000 and 50 are passed to the constructor here.
const myToken = await MyToken.deploy(100000000, 50);
await myToken.deployed();
console.log("MyToken deployed to: ", myToken.address);
}
This elegant mechanism allows you to configure your contract dynamically at the moment of creation.
Test your understanding!
- Can a smart contract have more than one constructor?
- You deploy a contract with
constructor() { owner = msg.sender; }. A week later, you call apublicfunction on that contract. What is the value ofmsg.senderinside that public function?
Show answer
- No. A contract can have at most one constructor. If no constructor is defined, a default empty constructor
constructor() public {}is used. - The value of
msg.senderwill be your address (the caller of the function).msg.senderalways refers to the immediate caller of the current function. It was the deployer's address during construction, but in subsequent calls, it reflects who is calling now. Theownerstate variable, however, remains set to the deployer's address.
Let's Practice
Now it's your turn to write a constructor.
- In your Hardhat project, create a new file in the
contractsdirectory calledConfigurable.sol. - Inside this file, define a contract named
Configurable. - Add the following state variables to the contract:
string public message;uint256 public initialValue;address public creator;
- Your task is to write a constructor that:
- Accepts a string argument
_messageand auint256argument_initialValue. - Sets the
messagestate variable to the value of_message. - Sets the
initialValuestate variable to the value of_initialValue. - Sets the
creatorstate variable tomsg.sender.
- Accepts a string argument
Once you've written the code, run npx hardhat compile in your terminal to ensure there are no syntax errors.
Conclusion
You've now mastered one of the most important functions in a smart contract's life. The constructor provides a secure and efficient way to initialize your contract's state, setting the foundation for all its future operations.
Key Takeaways:
- The
constructoris a special function that runs only once when a contract is deployed. - It's the ideal place to set initial values for state variables like the owner, token name, or total supply.
msg.senderinside the constructor always refers to the address of the account deploying the contract.- Arguments can be passed to the constructor from a deployment script (e.g.,
MyContract.deploy(arg1, arg2)), allowing for dynamic configuration.
Preview of the Next Lesson:
You've seen how a deployment script passes arguments to a constructor, but we've only scratched the surface of what those scripts do. In our next lesson, we will fully focus on how to write and execute a simple deployment script using Hardhat. You'll learn the standard structure of a deployment script and run one yourself to deploy a contract to a local test network.