Creating a contract with a smart contract

Kseniya Lifanova
Upstate Interactive
7 min readMar 13, 2019

There are two ways a contract can be created in Solidity.

  1. They can be created “from outside” by a creator — a developer who is deploying the contract or a user that is interacting with a dApp which deploys the contract on their behalf.
  2. They can also be created by another smart contract.

Today I’m going to focus on #2.

There are a lot of great articles out there about using a factory to create smart contracts. These articles focus on creating multiple instances of the same contract. In my case, I needed a very simple factory. A parent contract that would deploy one instance of a child contract. Just once. We don’t want twins, triplets, quadruplets… that is more then we can handle.

Whether you want to create many instances of the same contract or you only want to create one, you can use the new keyword as described briefly here in the Solidity docs. In my case, I decided to have my parent contract create the child contract in it’s constructor. That way it would all happen at once on deployment.

A family example

Let’s take a look at an example.

In this example, we are going to have our parent contract that we will call MomContract deploy a child contract called DaughterContract.

:)

pragma solidity ^0.5.0;import "./DaughterContract.sol";contract MomContract { string public name;
uint public age;
DaughterContract public daughter; constructor(
string memory _momsName,
uint _momsAge,
string memory _daughtersName,
uint _daughtersAge
)
public
{
daughter = new DaughterContract(_daughtersName, _daughtersAge);
name = _momsName;
age = _momsAge;
}
}

We are starting with the MomContract and creating the DaughterContract using the new keyword. We pass the parameters needed to create the DaughterContract to the MomContract so we can pass them on. We have a variable daughterof type DaughterContract, which will allow us to call that contract.

Now let’s take a look at the DaughterContract.

pragma solidity ^0.5.0;contract DaughterContract { string public name;
uint public age;
constructor(
string memory _daughtersName,
uint _daughtersAge
)
public
{
name = _daughtersName;
age = _daughtersAge;
}
}

The name and age that is passed from the MomContract is used to create the DaughterContract, and we set those arguments to the name and age variable.

Now we know how a contract can create another contract. Great.

Let’s take it a step further.

Creating a contract from another contract is particularly useful when you want to restrict access of the child contract functions to it’s parent contract. To do this, I recommend using Open Zeppelin’s library. They have several ways you can control access, as written in this guide. I’m going to use the well known and popular Ownable.sol file, which is perfect when you only need to provide access to one address. To use the Ownable.sol file, you’ll need to import it and inherit it in your child contract.

pragma solidity ^0.5.0;import "openzeppelin-solidity/contracts/ownership/Ownable.sol";contract DaughterContract is Ownable {
// contract code
}

Let’s add a function that is restricted to the MomContract.

pragma solidity ^0.5.0;import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import "./MomContract.sol";
contract DaughterContract is Ownable {

string public name;
uint public age;
bool public canDate;
constructor(
string memory _daughtersName,
uint _daughtersAge
)
public
{
name = _daughtersName;
age = _daughtersAge;
canDate = false;
}
}
function permissionToDate() onlyOwner {
canDate = true;
}

We added acanDate variable and set it false (we don’t want the daughter to date without her mom’s permission). Next, we added a permissionToDate function and added the onlyOwner modifier available to us from the Ownable contract. Now, the only contract that can call this function is the MomContract. To test this, I added a function in the MomContract that calls the permissionToDate function in the DaughterContract.

function allowDaughterToDate() public {
daughter.permissionToDate();
}

Now, when you call the allowDaughterToDate function in the MomContract, it will call the permissionToDate function and update the canDate variable to true. If you try to call the permissionToDate function from any other contract or address, the function will revert. Yay!

Now, let’s say we want our MomContract to create another contract and we want that contract to access functions in the MomContract and theDaughterContract. This scenario is possible!

We will call our second child contract SonContract (of course).

We will import it into MomContract, pass additional parameters, and use new to create it. Along with the name and age variables, we are going to pass it the instance of the DaughterContract that we created right before creating the SonContract and we are going to pass it address(this). address(this) is the address of the contract itself. Yes, you can access the address of the contract you are creating in it’s constructor. You won’t be able to access its functions because the contract has not finished initializing, but you can at least pass around its address (look here).

pragma solidity ^0.5.0;import "./DaughterContract.sol";
import "./SonContract.sol";
contract MomContract { string public name;
uint public age;
DaughterContract public daughter;
SonContract public son;
constructor(
string memory _momsName,
uint _momsAge,
string memory _daughtersName,
uint _daughtersAge,
string memory _sonsName,
uint _sonsAge
)
public
{
daughter = new DaughterContract(_daughtersName, _daughtersAge);
son = new SonContract(_sonsName, _sonsAge, daughter,
address(this));
name = _momsName;
age = _momsAge;
}
}

Now, let’s take a look at the SonContract.

pragma solidity ^0.5.0;import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import "./MomContract.sol";
import "./DaughterContract.sol";
contract SonContract is Ownable {

string public name;
uint public age;
DaughterContract public daughter;
MomContract public mom;
constructor(
string memory _sonsName,
uint _sonsAge
DaughterContract _daughter,
address _mom
)
public
{
name = _sonsName;
age = _sonsAge;
daughter = _daughter;
mom = MomContract(_mom);
}
}

Because we are passing the instance of DaughterContract, we can simply set our daughter variable to the _daughter that is being passed in the constructor. Because we are passing the address of the MomContract rather than the instance itself, we need to set it using MomContract(_mom).

Now, the MomContract can access functions in the SonContract and the SonContract can access functions in the MomContract and the DaughterContract. Let’s see an example of this. Add these three functions to the SonContract:

function permissionToDate() public onlyOwner {
canDate = true;
}
function howMuchIsYourAllowance() public returns (uint) {
return daughter.howMuch();
}
function howOldAreYou() public returns (uint) {
return mom.getAge();
}

We’ll add the permissionToDate function that only the owner (Mom) can call. The son, ever so rudely, wants to know how much his sister’s allowance is and how old his mom is because he forgot. Since we have access to both the MomContract and the DaughterContract, he is able to access functions within those contracts.

In the MomContract I’ve added:

function getAge() public returns (uint) {
return age;
}

And in the DaughterContract I’ve added a variable called allowance, and set it to equal 100. I’ve also added:

function howMuch() public returns (uint) {
return allowance;
}

The son can call those functions and find out the age of his Mom and the allowance of his Sister.

You can see the code for all three contracts and the tests here.

Let’s get real

Maybe some of you are thinking — why would you ever need to do this? You can simply access the functions of another contract by passing its address in the constructor of your contract. In the example above, we could have deployed the DaughterContract and SonContract first, and passed the addresses to the MomContract so she could call their functions.

I initially used this method because I wanted to use the onlyOwner modifier. In our real world project, we had a MultiSig contract that would call the functions of ContractA and ContractB once everyone signed off. In ContractA and ContractB, we wanted to check that only the MultiSig wallet was calling those functions. So I thought, great, let’s use the Ownable contract provided by OpenZepplin and have the MultiSig contract deploy those children contracts.

However…

As we added functions to the MultiSig contract and the child contracts that the MultiSig contract was creating, the gas cost to deploy the MultiSig contract was increasing. I learned that the CREATE opcode is one of the most expensive opcodes, and we were using it twice in our MultiSig constructor. Eventually, we got to a point where the contracts had gotten so large that we could not add any new functions. The gas cost was to high.

Going back to our Family factory example — when the MomContract uses new to create the DaughterContract and SonContract, she stores all of their bytecode. That means, any function you add to the those child contracts adds to the bytecode size of the MomContract.

Deploying the DaughterContract and SonContract first, and passing them into the MomContract will save on gas since the MomContract will not store the bytecode of the child contracts. However, the son will not be able to find out how old his mom is because he won’t have her address to call the getAge function (since he is created first).

This is what happened with our project. We had 6 smart contracts that all needed to call each other’s functions and we wanted modifiers in several of those contracts to restrict access to specific contracts. How can all contracts know about each other at the time of deployment? Sometimes you can’t line them up perfectly.

Our solution…a registry. Stay tuned for my next post where I will be writing about how we used a registry to keep track of our smart contracts.

If you want to learn more about using factories to create multiple instances of contracts, I recommend the following articles:

Solidity DelegateProxy Contracts

Solidity Smart Contracts Design Patterns

I hope you found this article useful. Please don’t hesitate to reach out if you have additional questions or thoughts you’d like to discuss further with our team — team@upstateinteractive.io

☞ To stay up to date with our work with smart contract development, follow us on Medium and Twitter.

--

--