Smart contracts are programs stored on the blockchain that run when certain conditions are predetermined or called. Smart contracts are used to automate agreements, eliminate intermediaries, and create a more decentralized network free from external influence.
In this article, we’ll look at a specific strategy referred to as nested contracts, or contracts with a contract. Specifically, we’ll review how to create multiple contracts and call functions from within a parent contract. We’ll demonstrate how to call a nested contract from the parent contract and also how to call it from an external contract. All of the smart contract examples used in this article are written in Solidity.
Let’s dive in.
Jump ahead:
In order to follow along with the tutorial portion of this article, you should have the following:
There are several reasons why it may be advantageous to include a smart contract within another smart contract:
Smart contracts are able to create or deploy other contracts. They can also call functions of other smart contracts. In this article, we’ll examine two examples of calling a nested smart contract:
For our first example, let’s create and then deploy a child contract within a parent contract.
To start, we’ll open Remix and create the parent contract. For this example, we’ll make a loan contract; anyone may call this contract and request a loan.
The first line of the contract is our License
. This is very important, as not calling it will raise an error:
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
We’re using Remix as a compiler, and it has different versions. Verify the version that you’re using; if the version does not tally with the compiler, you’ll get an error. In this example, we’re using Remix version ^0.8.0
and above. The ^
symbol signifies “above”.
As shown below, the ParentLoanCompany
contract takes a function called TakeLoan
that takes external
attributes. External modules can be used to introduce custom or third-party APIs to a Web3 instance. External modules are simply classes whose methods and properties can be made available within the Web3 instance.
contract ParentLoanCompany { function TakeLoan() external { LoanContract loan = new LoanContract (2000); } }
We used the external
attribute in order to call our child contract.
Before we do that, let’s create our child contract inside the parent contract:
contract ChildLoanContract { uint public amount; constructor(uint _amount) public{ amount = _amount; } }
Our ChildLoanContract
is the contract that the user directly interacts with, and we call the child contract into the parent contract. Let’s review the basic details of the child contract:
uint public amount; constructor(uint _amount) public{
We must make Solidity aware that this contract deals with money. To do so, we call the uint
, which is an unsigned integer, and we make it public
.
We create a constructor
that runs first, and once when the contract is called, we give an argument of _amount
, which means whoever calls this function must specify the amount they wish to borrow.
Finally, we call amount = _amount;
which means whatever amount the user puts in becomes the loan amount that is made public
.
Now, let’s go back to the ParentLoanCompany
contract and add the below code snippet to connect both contracts.
LoanContract loan = new LoanContract (2000);
We call the ChildLoanContract
by calling the LoanContract
and give it a name loan
. This is very important when we want to later call the address of the borrower. This is equivalent to new
which is the function that creates a new contract of type LoanContract
.
After deploying the ParentLoanCompany
contract with the Remix IDE, we should see two contracts on the Contract panel.
Now, let’s take a look at how an external contract can call a nested contract.
Just like the previous example, the first line of code is our License
. If we do not provide this, Remix will throw an error.
Next, we specify our version and compiler; Remix uses this compiler to test our project and if the compiler and the version are different, we’ll get an error.
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
We’ll create a contract, called scofield
, that allows the user to store an address in the string [] public user
array.
We also create an argument in the NameOfUser
function that stores the name that a caller of the contract provides inside the _user
.
contract scofield{ address owner; string [] public user; function NameOfUser(string memory _user ) public { user.push(_user); } }
Now, let’s create the nested contract.
We’ll create another contract inside the same file that mints our coin, LOGROCKET
. The coin’s symbol is LOG_COIN
. This coin will be minted using a contract we imported from OpenZeppelin.
In our scofield
contract, we’ll import the OpenZeppelin contract and paste the following command into our Remix editor:
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
Next, we call the external COINMAKER
contract. We specify that it is an ERC-20 contract, and then we call a constructor function
which we give an argument of name of coin
, LOGROCKET, and symbol of coin
, LOG-COIN.
Our constructor function
must run before any other function. It has a _mint
argument which tells the contract how many coins the msg.sender
can mint. We specified that the msg.sender
can mint 1000000000000000000
Wei, which is the smallest Ethereum unit.
As a side note, we should talk for a moment about Ethereum units. In this contract, we’re creating one Ether, but we’re using the smallest Ethereum unit (Wei) to represent the value.
Here’s a useful tool for converting different Ethereum units, such as Wei, Gwei, Finney, and Ether.
Now it’s time to deploy our contract. In the Remix DEPLOY & RUN panel, we see the contract dropdown and a list of contracts. These contracts are pulled in alongside our COINMAKER
and scofield
contracts, which are the two contracts we created.
Now, let’s deploy the COINMAKER
contract.
If you try to deploy without first installing your MetaMask wallet, you’ll see something like this:
Next, let’s talk about the gas fee and testnet faucet. To transact this contract, you can request test ETH from a testnet. In the article, I used Rinkeby, but it’s being depreciated. If you prefer, you can use Goerli instead.
As shown in the above image, you’ll get 0.1 ether
from the testnet, which will be more than enough to pay the gas fee. However, you can make the request a few times if you want to keep practicing.
Before deploying the contract, make sure you change the Environment
from Javascript VM
to Injected Web3
.
Now, let’s deploy the contract again. This time you should see the following MetaMask notification:
At the bottom of the panel, we see that the creation of COINMAKER
is pending.
Next, click on view on etherscan. This will open Etherscan, where we can see the coin we just created.
We can see the name of the token, LOGROCKET
, as well as the amount of gas that was used to deploy this contract.
Click on the name of the token to see more details:
Here we can see the number of people holding the token (just one right now).
Now, let’s get back to our contract.
Each function within our contract has a purpose. Here’s a summary:
Approve
: Allows the sender to keep a certain amount of funds on the blockchain with an address that can withdraw that specified amountDecreaseAllowance
: Allows us to decrease the amount we set in the Approve
function, so the contract created might reduce the specified amount if was scheduled too highIncreaseAllowance
: Increases the allocated funds in the blockchainTransfer
: Allows the contract owner to transfer funds in the contract to another userTransferFrom
: Allows the owner to transfer from the Approve
function, rather than from the owner funds, after being approved into the blockchainThat’s it; you just created your own Web3 coin!
Using multiple smart contracts can provide more security to projects. In this article, we used the example of a loan smart contract to demonstrate calling a nested contract from the parent contract. We also used the example of a custom coin minting contract to demonstrate calling an external contract from a nested contract.
Creating contracts within contracts, or nested smart contracts, is useful for limiting what a user can do, and what they can call.
LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.
Modernize how you debug web and mobile apps — Start monitoring for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to implement one-way and two-way data binding in Vue.js, using v-model and advanced techniques like defineModel for better apps.
Compare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
One Reply to "Nested smart contracts: Creating a contract within a contract"
Thank you for sharing this Informative post.