Scofield Idehen Smart contract/Solidity || cyber security || React || Every other thing is just hobbies.

Nested smart contracts: Creating a contract within a contract

5 min read 1658

Solidity Logo Over Pink Background and Nested Bowls

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:

Prerequisites

In order to follow along with the tutorial portion of this article, you should have the following:

Why nest a contract inside a contract?

There are several reasons why it may be advantageous to include a smart contract within another smart contract:

  • Security: Nesting contracts can help isolate the risk of vulnerabilities; when all contract variables are included within one smart contract, it’s easier to miss an error or weaknesses that could be exploited by a bad actor
  • Segmentation: Multiple contracts enable us to break the main contract into smaller pieces with less complex logic
  • Reusable code: Many basic contract functions are readily available in the form of open source, reusable logic through companies like OpenZeppelin; taking advantage of their code can provide significant development time savings

Can smart contracts interact with each other?

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:

  • Contract within a contract: When contracts are nested within one main contract, they or their functions can be called from one of the other contracts
  • Calling a nested contract from an external contract: Contracts can also be called externally; for example, you could use a constructor function to call an external contract

Demo: Calling a nested smart contract from the parent contract

For our first example, let’s create and then deploy a child contract within a parent contract.

Creating the nested 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.

Loan Contract



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.

External Modules

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:


More great articles from LogRocket:


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.

Deploying the nested contract

After deploying the ParentLoanCompany contract with the Remix IDE, we should see two contracts on the Contract panel.

Contract Dropdown

Demo: Calling a nested smart contract from an external contract

Now, let’s take a look at how an external contract can call a nested contract.

Deploy Run Transactions

Creating the contracts

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.

Wei, Gwei, and Ether

Converting Ethereum currencies

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.

Deploying and calling the nested contract

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.

Coinmaker Contract

Now, let’s deploy the COINMAKER contract.

If you try to deploy without first installing your MetaMask wallet, you’ll see something like this:

Creation of Coinmaker Pending

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.

Receive Eth

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:

Metamask Notification

At the bottom of the panel, we see that the creation of COINMAKER is pending.

Coinmaker 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.

Token Name and Gas

Click on the name of the token to see more details:

Token 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 amount
  • DecreaseAllowance: 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 high
  • IncreaseAllowance: Increases the allocated funds in the blockchain
  • Transfer: Allows the contract owner to transfer funds in the contract to another user
  • TransferFrom: Allows the owner to transfer from the Approve function, rather than from the owner funds, after being approved into the blockchain

Coin Menu

That’s it; you just created your own Web3 coin!

Conclusion

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.

Join organizations like Bitso and Coinsquare who use LogRocket to proactively monitor their Web3 apps

Client-side issues that impact users’ ability to activate and transact in your apps can drastically affect your bottom line. If you’re interested in monitoring UX issues, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.https://logrocket.com/signup/

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 — .

Scofield Idehen Smart contract/Solidity || cyber security || React || Every other thing is just hobbies.

Leave a Reply