add create2 deploy

This commit is contained in:
Drygin 2022-02-11 23:53:36 +03:00
parent b37d6d459f
commit d6919f2797
12 changed files with 248 additions and 25 deletions

View File

@ -4,3 +4,5 @@ XDAI_RPC=https://
BSC_RPC=https://
MINIMUM_WITHDRAWAL_AMOUNT=0.05
MAXIMUM_DEPOSIT_AMOUNT=1
ALCHEMY_KEY=
INFURA_API_KEY=

View File

@ -19,6 +19,8 @@ jobs:
- run: yarn lint
- run: yarn build
- run: yarn test
env:
ALCHEMY_KEY: ${{ secrets.ALCHEMY_KEY }}
- name: Telegram Failure Notification
uses: appleboy/telegram-action@0.0.7
if: failure()

View File

@ -20,3 +20,30 @@ yarn download
yarn build
yarn test
```
## Deploy
Check config.js for actual values.
With `salt` = `0x0000000000000000000000000000000000000000000000000000000047941987` addresses must be:
1. `L1Unwrapper` - `0xfEADF5e7e453c664D903d1b1945c524c4328e1c5`
2. `TornadoPool` - `0xEb314843E39A2D67c7bA31150fA243b30b70e97c`
Check addresses with current config:
```shell
node -e 'require("./src/0_generateAddresses").generateWithLog()'
```
Deploy L1Unwrapper:
```shell
npx hardhat run scripts/deployL1Unwrapper.js --network mainnet
```
Deploy TornadoPool:
```shell
npx hardhat run scripts/deployTornadoUpgrade.js --network xdai
```

26
config.js Normal file
View File

@ -0,0 +1,26 @@
module.exports = {
//// L1 -------------------
// ETH
multisig: '0xb04E030140b30C27bcdfaafFFA98C57d80eDa7B4',
omniBridge: '0x88ad09518695c6c3712AC10a214bE5109a655671',
weth: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
// BSC
// multisig: '0xBAE5aBfa98466Dbe68836763B087f2d189f4D28f'
// omniBridge: '0xf0b456250dc9990662a6f25808cc74a6d1131ea9'
// weth: '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c' // WBNB
singletonFactory: '0xce0042B868300000d44A59004Da54A005ffdcf9f',
salt: '0x0000000000000000000000000000000000000000000000000000000047941987',
//// L2 -------------------
// Gnosis chain
verifier2: '0xdf3a408c53e5078af6e8fb2a85088d46ee09a61b',
verifier16: '0x743494b60097a2230018079c02fe21a7b687eaa5',
MERKLE_TREE_HEIGHT: 23,
hasher: '0x94c92f096437ab9958fc0a37f09348f30389ae79',
gcWeth: '0x6a023ccd1ff6f2045c3309768ead9e68f978f6e1',
gcOmniBridge: '0xf6a78083ca3e2a662d6dd1703c939c8ace2e268d',
l1Unwrapper: '0xfEADF5e7e453c664D903d1b1945c524c4328e1c5',
govAddress: '0x5efda50f22d34f262c29268506c5fa42cb56a1ce',
l1ChainId: 1,
gcMultisig: '0x1f727de610030a88863d7da45bdea4eb84655b52',
}

View File

@ -79,9 +79,9 @@ contract L1Unwrapper is WETHOmnibridgeRouter {
uint256 _value,
bytes memory _data
) external override {
require(_token == address(WETH));
require(msg.sender == address(bridge));
require(_data.length == 52);
require(_token == address(WETH), "only WETH token");
require(msg.sender == address(bridge), "only from bridge address");
require(_data.length == 52, "incorrect data length");
WETH.withdraw(_value);

View File

@ -0,0 +1,28 @@
// SPDX-License-Identifier: MIT
/**
*Submitted for verification at Etherscan.io on 2020-03-30
*/
pragma solidity 0.6.2;
/**
* @title Singleton Factory (EIP-2470)
* @notice Exposes CREATE2 (EIP-1014) to deploy bytecode on deterministic addresses based on initialization code and salt.
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
*/
contract SingletonFactory {
/**
* @notice Deploys `_initCode` using `_salt` for defining the deterministic address.
* @param _initCode Initialization code.
* @param _salt Arbitrary value to modify resulting address.
* @return createdContract Created contract address.
*/
function deploy(bytes memory _initCode, bytes32 _salt) public returns (address payable createdContract) {
assembly {
createdContract := create2(0, add(_initCode, 0x20), mload(_initCode), _salt)
}
}
}
// IV is a value changed to generate the vanity address.
// IV: 6583047

View File

@ -21,6 +21,15 @@ const config = {
},
},
},
{
version: '0.6.2',
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
{
version: '0.7.5',
settings: {
@ -42,6 +51,21 @@ const config = {
],
},
networks: {
hardhat: {
forking: {
url: `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_KEY}`,
blockNumber: 13685625,
},
chainId: 1,
initialBaseFeePerGas: 5,
loggingEnabled: false,
allowUnlimitedContractSize: false,
blockGasLimit: 50000000,
},
rinkeby: {
url: `https://rinkeby.infura.io/v3/${process.env.INFURA_API_KEY}`,
accounts: [process.env.PRIVATE_KEY],
},
xdai: {
url: process.env.ETH_RPC || 'https://rpc.xdaichain.com/',
accounts: process.env.PRIVATE_KEY

View File

@ -1,21 +0,0 @@
const { ethers } = require('hardhat')
// This script deploys L1Helper to FOREIGN chain (mainnet)
async function main() {
const owner = '0xBAE5aBfa98466Dbe68836763B087f2d189f4D28f'
const omniBridge = '0xf0b456250dc9990662a6f25808cc74a6d1131ea9'
const token = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c' // WBNB
const Helper = await ethers.getContractFactory('L1Unwrapper')
const helper = await Helper.deploy(omniBridge, token, owner)
await helper.deployed()
console.log(`L1Helper address: ${helper.address}`)
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})

View File

@ -0,0 +1,28 @@
const { ethers } = require('hardhat')
const config = require('../config')
const { generate } = require('../src/0_generateAddresses')
// This script deploys L1Helper to FOREIGN chain (mainnet)
async function deploy({ address, bytecode, singletonFactory }) {
const contractCode = await ethers.provider.getCode(address)
if (contractCode !== '0x') {
console.log(`Contract ${address} already deployed. Skipping...`)
return
}
await singletonFactory.deploy(bytecode, config.salt, { gasLimit: 3000000 })
}
async function main() {
const singletonFactory = await ethers.getContractAt('SingletonFactory', config.singletonFactory)
const contracts = await generate()
await deploy({ ...contracts.unwrapperContract, singletonFactory })
console.log(`L1 unwrapper contract have been deployed on ${contracts.unwrapperContract.address} address`)
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})

View File

@ -0,0 +1,28 @@
const { ethers } = require('hardhat')
const config = require('../config')
const { generate } = require('../src/0_generateAddresses')
// This script deploys Tornado Pool upgrade to L2 (Gnosis Chain)
async function deploy({ address, bytecode, singletonFactory }) {
const contractCode = await ethers.provider.getCode(address)
if (contractCode !== '0x') {
console.log(`Contract ${address} already deployed. Skipping...`)
return
}
await singletonFactory.deploy(bytecode, config.salt, { gasLimit: 5000000 })
}
async function main() {
const singletonFactory = await ethers.getContractAt('SingletonFactory', config.singletonFactory)
const contracts = await generate()
await deploy({ ...contracts.poolContract, singletonFactory })
console.log(`Upgraded pool contract have been deployed on ${contracts.poolContract.address} address`)
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})

View File

@ -0,0 +1,68 @@
const { ethers } = require('hardhat')
const defaultConfig = require('../config')
async function generate(config = defaultConfig) {
const singletonFactory = await ethers.getContractAt('SingletonFactory', config.singletonFactory)
const UnwrapperFactory = await ethers.getContractFactory('L1Unwrapper')
const deploymentBytecodeUnwrapper =
UnwrapperFactory.bytecode +
UnwrapperFactory.interface.encodeDeploy([config.omniBridge, config.weth, config.multisig]).slice(2)
const unwrapperAddress = ethers.utils.getCreate2Address(
singletonFactory.address,
config.salt,
ethers.utils.keccak256(deploymentBytecodeUnwrapper),
)
const PoolFactory = await ethers.getContractFactory('TornadoPool')
const deploymentBytecodePool =
PoolFactory.bytecode +
PoolFactory.interface
.encodeDeploy([
config.verifier2,
config.verifier16,
config.MERKLE_TREE_HEIGHT,
config.hasher,
config.gcWeth,
config.gcOmniBridge,
config.l1Unwrapper,
config.govAddress,
config.l1ChainId,
config.gcMultisig,
])
.slice(2)
const poolAddress = ethers.utils.getCreate2Address(
singletonFactory.address,
config.salt,
ethers.utils.keccak256(deploymentBytecodePool),
)
const result = {
unwrapperContract: {
address: unwrapperAddress,
bytecode: deploymentBytecodeUnwrapper,
isProxy: false,
},
poolContract: {
address: poolAddress,
bytecode: deploymentBytecodePool,
isProxy: false,
},
}
return result
}
async function generateWithLog() {
const contracts = await generate()
console.log('L1 unwrapper contract: ', contracts.unwrapperContract.address)
console.log('Upgraded pool contract: ', contracts.poolContract.address)
return contracts
}
module.exports = {
generate,
generateWithLog,
}

View File

@ -9,6 +9,8 @@ const { transaction, registerAndTransact, prepareTransaction, buildMerkleTree }
const { toFixedHex, poseidonHash } = require('../src/utils')
const { Keypair } = require('../src/keypair')
const { encodeDataForBridge } = require('./utils')
const config = require('../config')
const { generate } = require('../src/0_generateAddresses')
const MERKLE_TREE_HEIGHT = 5
const l1ChainId = 1
@ -39,7 +41,16 @@ describe('TornadoPool', function () {
const amb = await deploy('MockAMB', gov.address, l1ChainId)
const omniBridge = await deploy('MockOmniBridge', amb.address)
const l1Unwrapper = await deploy('L1Unwrapper', amb.address, l1Token.address, gov.address)
// deploy L1Unwrapper with CREATE2
const singletonFactory = await ethers.getContractAt('SingletonFactory', config.singletonFactory)
let customConfig = Object.assign({}, config)
customConfig.omniBridge = amb.address
customConfig.weth = l1Token.address
const contracts = await generate(customConfig)
await singletonFactory.deploy(contracts.unwrapperContract.bytecode, config.salt)
const l1Unwrapper = await ethers.getContractAt('L1Unwrapper', contracts.unwrapperContract.address)
/** @type {TornadoPool} */
const tornadoPoolImpl = await deploy(