Table of contents
介绍
solidity 中的 new
关键字允许使用模板创建和部署新的合约实例。“XxxContractFactory”是一种命名约定和用于创建“XxxContract”合约的模式。
本文的目的是了解制作简单合约工厂的过程,同时了解它的工作原理并想象一些潜在的用例。让我们直接开始。
合约工厂是一种基于模板创建合约的设计模式。用户可以在字段中引入值,作为输入来初始化新部署的合约的状态变量。为什么这很有用?根据一些用例,你可以做一些很酷的事情,例如:
允许用户创建流动资金池:Uniswap
利用每个地址的 Adidas 2 NFT 铸币限制:交易
无代码平台以帮助用户创建自己的代币:ThirdWeb
其他例子:业务流程管理和医疗保健
实现原理
对于这个例子,我将使用我编写的 Bank 合约(模板)和 BankFactory 合约(工厂)。目的是部署一次工厂Factory合约,并根据需要创建多个银行Bank合约,而无需自己部署每个合约。
1、首先是银行 Bank(模板):
构造函数初始化由 BankFactory 传递的状态变量。在这里,我们传递Bank拥有的资金数量,谁是Bank的所有者以及谁创建了Bank合约。
// 这是一个模板合约, 拥有初始化 Bank 及其变量
contract Bank {
uint256 public bank_funds;
address public owner;
address public deployer;
constructor(address _owner, uint256 _funds) {
bank_funds = _funds;
owner = _owner;
deployer = msg.sender;
}
}
2、第二个 BankFactory(工厂):
在这里,我们实例化银行合约 Bank,创建一个类型为银行的列表 Bank[] public list_of_banks
来跟踪新创建的合约,最后是createBank()
一个将银行的构造函数参数作为参数的函数。
这是创建新合约的行:
bank = new Bank(_owner, _funds)
数组中索引 0 处的值list_of_banks
成为创建合约的地址!
contract BankFactory {
// instantiate Bank contract
Bank bank;
//keep track of created Bank addresses in array
Bank[] public list_of_banks;
// function arguments are passed to the constructor of the new created contract
function createBank(address _owner, uint256 _funds) external {
bank = new Bank(_owner, _funds);
list_of_banks.push(bank);
}
}
这就是全部。现在,当 Factory 已部署后,createBank(.., ..)
使用所需值作为参数调用函数将导致新Bank合约保存这些值!
想看看如何用 HardHat 做到这一点?
使用 HardHat 进行测试
1、创建一个新目录并安装安全帽:
npm install --save-dev hardhat
2、创建一个新项目并安装依赖项:
npx hardhat
3、使用你选择的文本编辑器打开文件夹。我喜欢 Visual Studio 代码:
4、创建一个新的 Solidity 文件并将代码复制到其中:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "hardhat/console.sol";
// Template used to initialize state variables
contract Bank {
uint256 public bank_funds;
address public owner;
address public deployer;
constructor(address _owner, uint256 _funds) {
bank_funds = _funds;
owner = _owner;
deployer = msg.sender;
}
}
contract BankFactory {
// instantiate Bank contract
Bank bank;
//keep track of created Bank addresses in array
Bank[] public list_of_banks;
// function arguments are passed to the constructor of the new created contract
function createBank(address _owner, uint256 _funds) external {
bank = new Bank(_owner, _funds);
list_of_banks.push(bank);
}
}
5、编译合约:
npx hardhat compile
6、测试它!注意测试脚本。将代码复制粘贴到其中并运行它!
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("Deploying a BankFactory and creating Bank instances ", function () {
it("Should instantiate the created Bank and call its functions", async () => {
// ContractFactory in ethers.js is an abstraction used to deploy new smart contracts, so Token here is a factory for instances of our token contract.
const BF = await ethers.getContractFactory('BankFactory');
const Bank = await ethers.getContractFactory('Bank');
// deploy bank factory
const bf = await BF.deploy();
await bf.deployed();
const owner = "0x0d8D32B83aaBBB675333468E4794eE0cDE666666"
// call function with (address owner, uint256 number) parameters
const tx1_receipt = await bf.createBank(owner, 69420);
const tx2_receipt = await bf.createBank(owner, 00100);
const tx3_receipt = await bf.createBank(owner, 113377);
console.log("BankFactory address at: ", tx1_receipt.to);
console.log("\n")
// Get the addresses of the deployed bank contracts
const bank1_address = await bf.list_of_banks(0);
const bank2_address = await bf.list_of_banks(1);
const bank3_address = await bf.list_of_banks(2);
console.log("BankFactory array of banks, address at (index 0): ", bank1_address);
console.log("BankFactory array of banks, address at (index 1): ", bank2_address);
console.log("BankFactory array of banks, address at (index 2): ", bank3_address);
console.log("\n")
// Attach the created Bank instance to the address it's located at. Call functions.
const bank1 = await Bank.attach(bank1_address);
const bank2 = await Bank.attach(bank2_address);
const bank3 = await Bank.attach(bank3_address);
// Get Bank 1 variables
const bank1_owner = await bank1.owner();
const bank1_bank_funds = await bank1.bank_funds();
const bank1_deployer = await bank1.deployer()
console.log(`Bank 1 \nowner: ${bank1_owner}\nbank_funds: ${bank1_bank_funds}\ndeployer: ${bank1_deployer}`)
console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
// Get Bank 2 variables
const bank2_owner = await bank2.owner();
const bank2_bank_funds = await bank2.bank_funds();
const bank2_deployer = await bank2.deployer()
console.log(`Bank 2 \nowner: ${bank2_owner}\nbank_funds: ${bank2_bank_funds}\ndeployer: ${bank2_deployer}`)
console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
// Get Bank 3 variables
const bank3_owner = await bank3.owner();
const bank3_bank_funds = await bank3.bank_funds();
const bank3_deployer = await bank3.deployer()
console.log(`Bank 3 \nowner: ${bank3_owner}\nbank_funds: ${bank3_bank_funds}\ndeployer: ${bank3_deployer}`)
console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
})
});
希望你和我一样完成的这个挑战!
参考链接:
docs.uniswap.org/protocol/V2/reference/smar..
research.csiro.au/blockchainpatterns/genera..
researchgate.net/publication/303996559_Untr..
docs.openzeppelin.com/learn/developing-smar..
关注我们, 获得更多优质内容
Twitter: @AntCaveClub
蚁穴Web3社区: https://antcave.club/
Youtube: 链求君