- Ideally, a smart contract we deploy should serve a specific functionality, for example is like AMM. Ideally we should have a different contract for each money market (e.g. BUSD-BNB, CAKE-BNB, etc) so the state would not be too complicated and the contract can be more secured.
- The problem with that approach is we need to manually deploy the contract for each money market, which can cost us a lot, since deploying a contract requires gas fee
Factory
can solve the problems mentioned above
- We don't need to deploy many contract manually anymore, we can just call a function from our
Factory
contract to deploy another contract - We spend less on gas fee from deploying many similar contracts
- With this approach, we can first create our main contract. Let's call it
Contract.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
contract Contract {
function add(uint256 a, uint256 b) external pure returns (uint256 c) {
c = a + b;
// return a + b
}
function sub(uint256 a, uint256 b) external pure returns (uint256 c) {
c = a - b;
}
function mul(uint256 a, uint256 b) external pure returns (uint256 c) {
c = a * b;
}
}
- We will not deploy
Contract.sol
to the blockchain - Next, we create another contract called
Factory.sol
- Import our main contract inside
Factory.sol
import { Contract } from "./Contract.sol";
- Create a function that will deploy our main contract with
new
keyword from solidity
function deployContract() external returns (address c) {
c = address(new Contract());
}
Note:
- Verifying contract in etherscan can be quite tricky with this approach, since the bytecode (output from compilation process) generated by EVM and etherscan could be different sometimes and causing failed verification.
- The address of contract deployed with this approach is not predictable, so the address could be different every deployment.
- The fee we spent on deployment is cheaper than doing manual deployment
- With this approach, we can first create our main contract, which is
Contract.sol
that have the same code as in previous approach. - In this approach, we will call
Contract.sol
as ourimplementation contract
- We need to deploy this
implementation contract
to the blockchain - Next, we can create the
factory contract
. Let's call itFactoryWithClone.sol
- In this contract, we will be using
Clone
from OpenZeppelin
import { Clones } from "openzeppelin/proxy/Clones.sol";
- Unlike the previous approach, we are not importing the
Contract.sol
in ourfactory contract
- After that, we can create a function that will deploy our main contract. We will be using
clone
function fromClones
here
function deployContract(address _implementation) external returns (address c)
{
// Clone implementation
c = Clones.clone(_implementation);
}
- When we call a function inside a contract that is deployed with this implementation, it will be executed as
delegate call
, which mean it refer the code from ourimplementation contract
to execute the function. Note: - The fee we spent on deployment with this approach is cheaper that the previous one (with
new
keyword from solidity) - The contract deployed with this approach will be automatically verified in etherscan and marked as
Minimal Proxy Contract