In Solidity, there are two main methods to utilize the functionalities of other contracts. In this tutorial, we will explain these two methods: inheritance and instantiation.
Inheritance
Inheritance involves creating a parent-child relationship between two contracts, allowing the child to inherit functionalities from the parent. In other words, inheritance enables sharing functionalities between contracts. Through inheritance, functions and variables of the parent contract can be used in the child contract.
On Day 7, we had the following code, which uses inheritance. The line ‘MyToken is ERC20’ indicates that ‘MyToken’ inherits functionalities from ‘ERC20’ (with ERC20 being the parent and MyToken the child).
ERC20 defines various functionalities, one of which is the ‘mint’ function for issuing tokens. This function takes the address of the caller and the amount to be issued as arguments, meaning it issues tokens equivalent to the ‘initialSupply’ to the person who called the _mint function. This functionality is also available in MyToken (hence, MyToken can call the _mint function even though it’s not explicitly described in MyToken itself).
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor(string memory _name, string memory _symbol, uint256 initialSupply) ERC20(_name, _symbol) {
_mint(msg.sender, initialSupply);
}
}
Constructor
The “constructor” is a block that defines the initial processes to be executed when an instance is instantiated. In other words, it’s about the initial procedures when the instance is actualized (instantiation refers to when something is defined and used as a variable and becomes a physical entity).
In the mentioned example, the constructor takes three input variables (the token’s name, symbol, and issuance amount) as arguments and calls the _mint function.
* In the context of Ethereum, for instance, the name and symbol would correspond to “Ether” and “ETH”, respectively. The symbol is usually a three-letter alphabetic abbreviation.
When using a contract, you must provide the arguments defined in the constructor. Suppose you want to use the MyToken contract as a variable; in that case, you would need to pass the three variables mentioned earlier. The following code is an example of how to define a contract for use. Here, a variable of the MyToken type, as defined in the earlier example, is being declared.
In Solidity, contracts can be defined as variables in the following way: <ContractName> <VariableName> = new <ContractName>(constructor's defined arguments)
.
For instance:
import "path/to/contract/MyToken.sol"; // Specify the path to MyToken.sol
contract TokenVillageToken {
MyToken tokenVillage = new MyToken("TokenVillageToken", "TVT", 1000000000000000000);
// Define the contract variable as <ContractName> <VariableName> = new <ContractName>(constructor's defined arguments)
function getName() public view returns (string memory) {
return tokenVillage.name(); // name() function from ERC20 returns the token's name
}
function getSymbol() public view returns (string memory) {
return tokenVillage.symbol(); // symbol() function from ERC20 returns the token's symbol
}
}
When the MyToken
variable is defined, the constructor’s process is executed. In this case, “TokenVillageToken” is the name and “TVT” is the symbol of the token, and 1000000000000000000
units of the token are minted.
Contract Instantiation and Invocation
Instantiation
Instantiation refers to the act of generating an instance (a real entity) from a contract (a blueprint). If you want to use another contract within your own implemented contract, you first need to instantiate that contract. By instantiating it, you can access and use the functions and variables of the other contract.
The following example defines the variable newToken
of the ERC20 type, which appeared in the previous example. During initialization in the constructor, the variable newToken
is given the address of a token that has already been deployed. This allows the use of the already deployed contract within this contract (deployed = having an actual instance).
You can call it with the syntax <variable> = <desired contract>(contract's address)
.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract NewToken {
ERC20 public newToken;
constructor(address _newTokenAddress) {
newToken = ERC20(_newTokenAddress);
}
function getNewTokenName() public view returns (string memory) {
return newToken.name();
}
}
The following image is an example of deploying the NewToken contract. In the textbox to the right of the “Deploy” button, enter the address 0xE73… of an already deployed ERC20 type contract, and then deploy it. As a result, NewToken is deployed. If you press getNewTokenName, the name of the already deployed token (TokenVillageToken) is displayed.
Comments