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
Uniswap
set the addresses oftoken0
andtoken1
in theconstructor
?Answer: Because
Uniswap
usescreate2
creating new smart contracts, parameters is not allowed in the constructor when using create2. When usingcreate
, it is allowed to have parameters inPair
contract, and you can set the addresses oftoken0
andtoken1
in 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
createPair
with the arguments of the addresses ofWBNB
andPEOPLE
, we will have the address ofPair
contract: 0x5C9eb5D6a6C2c1B3EFc52255C0b356f116f6f66D
- Check the state variables of
Pair
contract
- Use debug to check
create
opcode
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
.