WTF Solidity: 24. Creating a new smart contract in an existed smart contract
Recently, I have been revisiting Solidity, consolidating the finer details, and writing "WTF Solidity" tutorials for newbies.
Twitter: @0xAA_Science | @WTFAcademy_
Community: Discord|Wechat|Website wtf.academy
Codes and tutorials are open source on GitHub: github.com/AmazingAng/WTFSolidity
On Ethereum, user (Externally-owned account, EOA) can create smart contracts, a smart contract can also create new smart contracts. The decentralized exchange Uniswap creates an infinite number of Pair contracts with its Factory contract. In this lecture, I will explain how to create new smart contracts in an existed smart contract by using a simplied version of Uniswap.
create and create2
There are two ways to create a new contract in an existed contract, create and create2, this lecture will introduce create, next lecture will introduce create2.
The usage of create is very simple, creating a contract with new keyword, and passing the arguments required by the constructor of the new smart contract:
Contract x = new Contract{value: _value}(params)
Contract is the name of the smart contract to be created, x is the smart contract object (address), if the constructor is payable, the creator can transfer _value ETH to the new smart contract, params are the parameters of the constructor of the new smart cotnract.
Simplified Uniswap
The core smart contracts of Uniswap V2 include 2 smart contracts:
- UniswapV2Pair: Pair contract, used to manage token addresses, liquidity, swap.
- UniswapV2Factory: Factory contract, used to create new Pair contracts, and manage Pair address.
Below we will implement a simplified Uniswap with create: Pair contract is used to manage token addresses, PairFactory contract is used to create new Pair contract, and manage Pair addresses.
Pair contract
contract Pair{
address public factory; // factory contract address
address public token0; // token1
address public token1; // token2
constructor() payable {
factory = msg.sender;
}
// called once by the factory at time of deployment
function initialize(address _token0, address _token1) external {
require(msg.sender == factory, 'UniswapV2: FORBIDDEN'); // sufficient check
token0 = _token0;
token1 = _token1;
}
}
Pair contract is very simple, including 3 state variables: factory, token0 and token1.
The constructor assigns Factory contract's address to factory at the time of delpoyment. initialize function will be called once by the Factory contract when the Pair contract is created, and update token0 and token1 with the addresses of 2 tokens in the token pair.
Ask: Why doesn't
Uniswapset the addresses oftoken0andtoken1in theconstructor?Answer: Because
Uniswapusescreate2creating new smart contracts, parameters is not allowed in the constructor when using create2. When usingcreate, it is allowed to have parameters inPaircontract, and you can set the addresses oftoken0andtoken1in theconstructor.
PairFactory
contract PairFactory{
mapping(address => mapping(address => address)) public getPair; // get Pair's address based on 2 tokens' addresses
address[] public allPairs; // store all Pair addresses
function createPair(address tokenA, address tokenB) external returns (address pairAddr) {
// create a new contract
Pair pair = new Pair();
// call initialize function of the new contract
pair.initialize(tokenA, tokenB);
// update getPair and allPairs
pairAddr = address(pair);
allPairs.push(pairAddr);
getPair[tokenA][tokenB] = pairAddr;
getPair[tokenB][tokenA] = pairAddr;
}
}
Factory contract (PairFactory) has 2 state variables, getPair is a map of 2 token address and Pair contract address, and is used to find Pair contract address based on 2 token addresses. allPairs is an array of Pair contract addresses, which is used to store all Pair contract addresses.
There's only one function in PairFactory, createPair, which creates a new Pair contract based on 2 token addresses tokenA and tokenB.``
Pair pair = new Pair();
The above code is used to create a new smart contract, very straightforward. You can deploy PairFactory contract first, then call createPair with the following 2 addresses as arguments, and find out what is the address of the new Pair contract.
WBNB address: 0x2c44b726ADF1963cA47Af88B284C06f30380fC78
PEOPLE address on BSC: 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c
Verify on Remix
- Call
createPairwith the arguments of the addresses ofWBNBandPEOPLE, we will have the address ofPaircontract: 0x5C9eb5D6a6C2c1B3EFc52255C0b356f116f6f66D

- Check the state variables of
Paircontract

- Use debug to check
createopcode

Summary
In this lecture, we introduce how to create a new smart contract in an existed smart contract with create method by using a simplified version of Uniswap, in next lecture we will introduce how to implement a simplified Uniswap with create2.