mirror of
https://github.com/tornadocash/tornado-nova
synced 2024-02-02 14:53:56 +01:00
add create2 deploy
This commit is contained in:
parent
b37d6d459f
commit
d6919f2797
@ -4,3 +4,5 @@ XDAI_RPC=https://
|
||||
BSC_RPC=https://
|
||||
MINIMUM_WITHDRAWAL_AMOUNT=0.05
|
||||
MAXIMUM_DEPOSIT_AMOUNT=1
|
||||
ALCHEMY_KEY=
|
||||
INFURA_API_KEY=
|
||||
|
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -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()
|
||||
|
27
README.md
27
README.md
@ -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
26
config.js
Normal 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',
|
||||
}
|
@ -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);
|
||||
|
||||
|
28
contracts/libraries/SingletonFactory.sol
Normal file
28
contracts/libraries/SingletonFactory.sol
Normal 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
|
@ -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
|
||||
|
@ -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)
|
||||
})
|
28
scripts/deployL1Unwrapper.js
Normal file
28
scripts/deployL1Unwrapper.js
Normal 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)
|
||||
})
|
28
scripts/deployTornadoUpgrade.js
Normal file
28
scripts/deployTornadoUpgrade.js
Normal 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)
|
||||
})
|
68
src/0_generateAddresses.js
Normal file
68
src/0_generateAddresses.js
Normal 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,
|
||||
}
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user