const { ethers } = require('ethers'); const { expectEvent } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const { expectRevertCustomError } = require('../helpers/customError'); const shouldBehaveLikeClone = require('./Clones.behaviour'); const Clones = artifacts.require('$Clones'); contract('Clones', function (accounts) { const [deployer] = accounts; describe('clone', function () { shouldBehaveLikeClone(async (implementation, initData, opts = {}) => { const factory = await Clones.new(); const receipt = await factory.$clone(implementation); const address = receipt.logs.find(({ event }) => event === 'return$clone').args.instance; await web3.eth.sendTransaction({ from: deployer, to: address, value: opts.value, data: initData }); return { address }; }); }); describe('cloneDeterministic', function () { shouldBehaveLikeClone(async (implementation, initData, opts = {}) => { const salt = web3.utils.randomHex(32); const factory = await Clones.new(); const receipt = await factory.$cloneDeterministic(implementation, salt); const address = receipt.logs.find(({ event }) => event === 'return$cloneDeterministic').args.instance; await web3.eth.sendTransaction({ from: deployer, to: address, value: opts.value, data: initData }); return { address }; }); it('address already used', async function () { const implementation = web3.utils.randomHex(20); const salt = web3.utils.randomHex(32); const factory = await Clones.new(); // deploy once expectEvent(await factory.$cloneDeterministic(implementation, salt), 'return$cloneDeterministic'); // deploy twice await expectRevertCustomError(factory.$cloneDeterministic(implementation, salt), 'ERC1167FailedCreateClone', []); }); it('address prediction', async function () { const implementation = web3.utils.randomHex(20); const salt = web3.utils.randomHex(32); const factory = await Clones.new(); const predicted = await factory.$predictDeterministicAddress(implementation, salt); const creationCode = [ '0x3d602d80600a3d3981f3363d3d373d3d3d363d73', implementation.replace(/0x/, '').toLowerCase(), '5af43d82803e903d91602b57fd5bf3', ].join(''); expect(ethers.getCreate2Address(factory.address, salt, ethers.keccak256(creationCode))).to.be.equal(predicted); expectEvent(await factory.$cloneDeterministic(implementation, salt), 'return$cloneDeterministic', { instance: predicted, }); }); }); });