我部署了一个
CREATE2
智能合约,用作部署其他代码的工厂。目前仅部署一种合约:
import { MyERC1155 } from "./MyERC1155.sol";
contract MyCreate2Factory {
event ContractDeployed(address contractAddress);
function deployContract(
string calldata name,
string calldata symbol,
string calldata baseURI,
string calldata contractURI,
bytes32 salt
) external {
address contractAddress;
bytes memory deploymentCode = bytes.concat(
type(MyERC1155).creationCode,
abi.encode(name, symbol, baseURI, contractURI)
);
assembly {
contractAddress := create2(0, add(deploymentCode, 0x20), mload(deploymentCode), salt)
if iszero(extcodesize(contractAddress)) {
revert(0, 0)
}
}
emit ContractDeployed(contractAddress);
}
}
这效果很好,我可以在 ethers.js 中将参数发送给它,如下所示:
const proxy = await ethers.getContractFactory('MyCreate2Factory');
const factory = (await proxy.deploy()) as unknown as MyCreate2Factory;
await factory.deployTransaction.wait();
await expect(factory.deployContract(name, symbol, baseURI, contractURI, salt))
.to.emit(factory, 'ContractDeployed')
.withArgs(expectedContractAddress); // Pass
但现在我想制作一个新的
CREATE2
合约,能够部署任何合约,所以我将其更改为:
contract AnyCreate2Factory {
event ContractDeployed(address contractAddress);
function deployContract(bytes32 salt, bytes memory bytecode) external {
address contractAddress;
assembly {
contractAddress := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
if iszero(extcodesize(contractAddress)) {
revert(0, 0)
}
}
emit ContractDeployed(contractAddress);
}
}
但是我很难复制 Solidity 如何在 ethers.js 中生成
deploymentCode
。我在本地有 ABI 和字节码,所以我想用它来发送到部署函数,但出现一些错误。这就是我正在尝试的:
import myERC1155Interface from '../artifacts/contracts/MyERC1155.sol/MyERC1155.json';
const { abi, bytecode } = myERC1155Interface;
const constructorTypes = ['string', 'string', 'string', 'string'];
const constructorArgs = [name, symbol, baseURI, contractURI];
const initCode = ethers.utils.concat([
bytecode,
ethers.utils.defaultAbiCoder.encode(constructorTypes, constructorArgs)
]);
await expect(factory.deployContract(salt, initCode))
.to.emit(factory, 'ContractDeployed')
.withArgs(expectedContractAddress);
但是,我收到有关交易块大小的错误:
InvalidInputError: Transaction gas limit is 1000395544 and exceeds block gas limit of 1000000000
我是否错过了实现此目标的步骤,或者这是不可能的?
您是正确的,initCode 变量中的字节码对于单个事务来说太大。区块 Gas 上限为 100,000,000,您的交易使用超过 100,000,000 Gas。
要使用 CREATE2 和大字节码部署合约,可以使用以下步骤:
*将字节码分割成多个块。
*部署存储字节码块的合约。
*使用 CREATE2 和存储字节码块的合约地址部署目标合约。
以下是如何在 ethers.js 中执行此操作的示例:
import { ethers } from 'ethers';
// Split the bytecode into chunks.
const bytecodeChunks = bytecode.split('\n');
// Deploy a contract that stores the bytecode chunks.
class BytecodeStore {
constructor(bytecodeChunks) {
this.bytecodeChunks = bytecodeChunks;
}
async deploy(signer) {
const contractFactory = await ethers.getContractFactory(BytecodeStore, { signer });
const contract = await contractFactory.deploy(this.bytecodeChunks);
return contract;
}
}
// Deploy your target contract using CREATE2 and the address of the contract that stores the bytecode chunks.
class MyERC1155 {
constructor(bytecodeStoreAddress) {
this.bytecodeStoreAddress = bytecodeStoreAddress;
}
async deploy(signer, salt) {
const bytecode = bytecodeChunks.reduce((a, b) => a + b, '');
const initCode = ethers.utils.concat([
bytecode,
ethers.utils.defaultAbiCoder.encode(constructorTypes, constructorArgs)
]);
const contractFactory = await ethers.getContractFactory(MyERC1155, { signer });
const contract = await contractFactory.deploy(salt, this.bytecodeStoreAddress);
return contract;
}
}
// Deploy the bytecode store contract.
const bytecodeStore = await new BytecodeStore(bytecodeChunks).deploy(signer);
// Deploy the target contract.
const myERC1155 = await new MyERC1155(bytecodeStore.address).deploy(signer, salt);
这种方法将允许您部署具有大字节码的合约,而不会超过区块气体限制。