mirror of
https://github.com/0xbow-io/privacy-pools-core.git
synced 2026-01-10 09:58:00 -05:00
Merge branch 'dev' of wonderland:0xbow-io/privacy-pools-core into fix/register-pool-check
This commit is contained in:
4
.github/workflows/contracts.yml
vendored
4
.github/workflows/contracts.yml
vendored
@@ -17,8 +17,8 @@ defaults:
|
||||
working-directory: packages/contracts
|
||||
|
||||
env:
|
||||
MAINNET_RPC: ${{ secrets.MAINNET_RPC }}
|
||||
SEPOLIA_RPC: ${{ secrets.SEPOLIA_RPC }}
|
||||
ETHEREUM_MAINNET_RPC: ${{ secrets.ETHEREUM_MAINNET_RPC }}
|
||||
ETHEREUM_SEPOLIA_RPC: ${{ secrets.ETHEREUM_SEPOLIA_RPC }}
|
||||
|
||||
jobs:
|
||||
unit-tests:
|
||||
|
||||
@@ -28,8 +28,9 @@ src = 'src/interfaces/'
|
||||
runs = 1000
|
||||
|
||||
[rpc_endpoints]
|
||||
mainnet = "${MAINNET_RPC}"
|
||||
sepolia = "${SEPOLIA_RPC}"
|
||||
mainnet = "${ETHEREUM_MAINNET_RPC}"
|
||||
sepolia = "${ETHEREUM_SEPOLIA_RPC}"
|
||||
gnosis = "${GNOSIS_RPC}"
|
||||
|
||||
[etherscan]
|
||||
mainnet = { key = "${ETHERSCAN_API_KEY}" }
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
"build": "forge build",
|
||||
"build:optimized": "FOUNDRY_PROFILE=optimized forge build",
|
||||
"coverage": "forge coverage --report summary --report lcov --match-path 'test/unit/*'",
|
||||
"deploy:mainnet": "bash -c 'source .env && forge script Deploy --rpc-url $MAINNET_RPC --account $MAINNET_DEPLOYER_NAME --broadcast --verify --chain mainnet -vvvvv'",
|
||||
"deploy:protocol:sepolia": "bash -c 'source .env && forge script script/Deploy.s.sol:EthereumSepolia --account $SEPOLIA_DEPLOYER_NAME --verify --rpc-url $SEPOLIA_RPC -vv $0'",
|
||||
"deploy:mainnet": "bash -c 'source .env && forge script script/Deploy.s.sol:EthereumMainnet --account DEPLOYER --rpc-url $ETHEREUM_MAINNET_RPC --slow -vv $0'",
|
||||
"deploy:protocol:chiado": "bash -c 'source .env && forge script script/Deploy.s.sol:GnosisChiado --account DEPLOYER --rpc-url $GNOSIS_CHIADO_RPC --slow -vv $0'",
|
||||
"deploy:protocol:sepolia": "bash -c 'source .env && forge script script/Deploy.s.sol:EthereumSepolia --verify --account DEPLOYER --rpc-url $ETHEREUM_SEPOLIA_RPC --slow -vv $0'",
|
||||
"lint:check": "yarn lint:sol && forge fmt --check",
|
||||
"lint:fix": "sort-package-json && forge fmt && yarn lint:sol --fix",
|
||||
"lint:natspec": "npx @defi-wonderland/natspec-smells --config natspec-smells.config.js",
|
||||
|
||||
169
packages/contracts/script/BaseDeploy.s.sol
Normal file
169
packages/contracts/script/BaseDeploy.s.sol
Normal file
@@ -0,0 +1,169 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
pragma solidity 0.8.28;
|
||||
|
||||
import {ERC1967Proxy} from '@oz/proxy/ERC1967/ERC1967Proxy.sol';
|
||||
import {IERC20} from '@oz/token/ERC20/ERC20.sol';
|
||||
import {Script} from 'forge-std/Script.sol';
|
||||
import {console} from 'forge-std/console.sol';
|
||||
|
||||
import {Constants} from 'contracts/lib/Constants.sol';
|
||||
import {DeployLib} from 'contracts/lib/DeployLib.sol';
|
||||
|
||||
import {IPrivacyPool} from 'interfaces/IPrivacyPool.sol';
|
||||
import {ICreateX} from 'interfaces/external/ICreateX.sol';
|
||||
|
||||
import {Entrypoint} from 'contracts/Entrypoint.sol';
|
||||
import {PrivacyPoolComplex} from 'contracts/implementations/PrivacyPoolComplex.sol';
|
||||
import {PrivacyPoolSimple} from 'contracts/implementations/PrivacyPoolSimple.sol';
|
||||
import {CommitmentVerifier} from 'contracts/verifiers/CommitmentVerifier.sol';
|
||||
import {WithdrawalVerifier} from 'contracts/verifiers/WithdrawalVerifier.sol';
|
||||
|
||||
/*///////////////////////////////////////////////////////////////
|
||||
BASE DEPLOY SCRIPT
|
||||
//////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @notice Abstract script to deploy the PrivacyPool protocol.
|
||||
* @dev Assets and chain specific configurations must be defined in a parent contract.
|
||||
*/
|
||||
abstract contract DeployProtocol is Script {
|
||||
// @notice Struct for Pool deployment and configuration
|
||||
struct PoolConfig {
|
||||
string symbol;
|
||||
IERC20 asset;
|
||||
uint256 minimumDepositAmount;
|
||||
uint256 vettingFeeBPS;
|
||||
uint256 maxRelayFeeBPS;
|
||||
}
|
||||
|
||||
error ChainIdAndRPCMismatch();
|
||||
|
||||
// @notice Deployed Entrypoint
|
||||
Entrypoint public entrypoint;
|
||||
// @notice Deployed Groth16 Withdrawal Verifier
|
||||
address public withdrawalVerifier;
|
||||
// @notice Deployed Groth16 Ragequit Verifier
|
||||
address public ragequitVerifier;
|
||||
|
||||
// @notice Initial Entrypoint `ONWER_ROLE`
|
||||
address public owner;
|
||||
// @notice Initial Entrypoint `POSTMAN_ROLE`
|
||||
address public postman;
|
||||
|
||||
address public deployer;
|
||||
|
||||
// @notice CreateX Singleton
|
||||
ICreateX public constant CreateX = ICreateX(0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed);
|
||||
|
||||
// @notice Native asset pool configuration
|
||||
PoolConfig internal _nativePoolConfig;
|
||||
// @notice ERC20 pools configurations
|
||||
PoolConfig[] internal _tokenPoolConfigs;
|
||||
|
||||
function setUp() public virtual {
|
||||
owner = vm.envAddress('OWNER_ADDRESS');
|
||||
postman = vm.envAddress('POSTMAN_ADDRESS');
|
||||
|
||||
deployer = vm.envAddress('DEPLOYER_ADDRESS');
|
||||
}
|
||||
|
||||
// @dev Must be called with the `--account` flag which acts as the caller
|
||||
function run() public virtual {
|
||||
vm.startBroadcast(deployer);
|
||||
|
||||
// Deploy verifiers
|
||||
_deployGroth16Verifiers();
|
||||
// Deploy Entrypoint
|
||||
_deployEntrypoint();
|
||||
|
||||
// Deploy the native asset pool
|
||||
_deploySimplePool(_nativePoolConfig);
|
||||
|
||||
// Deploy the ERC20 pools
|
||||
for (uint256 _i; _i < _tokenPoolConfigs.length; ++_i) {
|
||||
_deployComplexPool(_tokenPoolConfigs[_i]);
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function _deployGroth16Verifiers() private {
|
||||
// Deploy WithdrawalVerifier using Create2
|
||||
withdrawalVerifier = CreateX.deployCreate2(
|
||||
DeployLib.salt(deployer, DeployLib.WITHDRAWAL_VERIFIER_SALT),
|
||||
abi.encodePacked(type(WithdrawalVerifier).creationCode)
|
||||
);
|
||||
|
||||
console.log('Withdrawal Verifier deployed at: %s', withdrawalVerifier);
|
||||
|
||||
// Deploy CommitmentVerifier using Create2
|
||||
ragequitVerifier = CreateX.deployCreate2(
|
||||
DeployLib.salt(deployer, DeployLib.RAGEQUIT_VERIFIER_SALT),
|
||||
abi.encodePacked(type(CommitmentVerifier).creationCode)
|
||||
);
|
||||
|
||||
console.log('Ragequit Verifier deployed at: %s', ragequitVerifier);
|
||||
}
|
||||
|
||||
function _deployEntrypoint() private {
|
||||
// Deploy implementation at any address
|
||||
address _impl = address(new Entrypoint());
|
||||
|
||||
// Encode `initialize` call data
|
||||
bytes memory _intializationData = abi.encodeCall(Entrypoint.initialize, (owner, postman));
|
||||
|
||||
// Deploy proxy and initialize
|
||||
address _entrypoint = CreateX.deployCreate2(
|
||||
DeployLib.salt(deployer, DeployLib.ENTRYPOINT_SALT),
|
||||
abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(_impl, _intializationData))
|
||||
);
|
||||
|
||||
entrypoint = Entrypoint(payable(_entrypoint));
|
||||
|
||||
console.log('Entrypoint deployed at: %s', address(entrypoint));
|
||||
}
|
||||
|
||||
function _deploySimplePool(PoolConfig memory _config) private {
|
||||
// Deploy pool with Create2
|
||||
address _pool = CreateX.deployCreate2(
|
||||
DeployLib.salt(deployer, DeployLib.SIMPLE_POOL_SALT),
|
||||
abi.encodePacked(
|
||||
type(PrivacyPoolSimple).creationCode, abi.encode(address(entrypoint), withdrawalVerifier, ragequitVerifier)
|
||||
)
|
||||
);
|
||||
|
||||
// Register pool at entrypoint with defined configuration
|
||||
entrypoint.registerPool(
|
||||
IERC20(Constants.NATIVE_ASSET),
|
||||
IPrivacyPool(_pool),
|
||||
_config.minimumDepositAmount,
|
||||
_config.vettingFeeBPS,
|
||||
_config.maxRelayFeeBPS
|
||||
);
|
||||
|
||||
console.log('%s Pool deployed at: %s', _config.symbol, _pool);
|
||||
}
|
||||
|
||||
function _deployComplexPool(PoolConfig memory _config) private {
|
||||
// Deploy pool with Create2
|
||||
address _pool = CreateX.deployCreate2(
|
||||
DeployLib.salt(deployer, DeployLib.COMPLEX_POOL_SALT),
|
||||
abi.encodePacked(
|
||||
type(PrivacyPoolComplex).creationCode,
|
||||
abi.encode(address(entrypoint), withdrawalVerifier, ragequitVerifier, address(_config.asset))
|
||||
)
|
||||
);
|
||||
|
||||
// Register pool at entrypoint with defined configuration
|
||||
entrypoint.registerPool(
|
||||
_config.asset, IPrivacyPool(_pool), _config.minimumDepositAmount, _config.vettingFeeBPS, _config.maxRelayFeeBPS
|
||||
);
|
||||
|
||||
console.log('%s Pool deployed at: %s', _config.symbol, _pool);
|
||||
}
|
||||
|
||||
modifier chainId(uint256 _chainId) {
|
||||
if (block.chainid != _chainId) revert ChainIdAndRPCMismatch();
|
||||
_;
|
||||
}
|
||||
}
|
||||
@@ -1,174 +1,19 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pragma solidity 0.8.28;
|
||||
|
||||
import {ERC20, IERC20} from '@oz/token/ERC20/ERC20.sol';
|
||||
import {UnsafeUpgrades} from '@upgrades/Upgrades.sol';
|
||||
import {Script} from 'forge-std/Script.sol';
|
||||
import {console} from 'forge-std/console.sol';
|
||||
|
||||
import {DeployProtocol} from './BaseDeploy.s.sol';
|
||||
import {IERC20} from '@oz/token/ERC20/ERC20.sol';
|
||||
import {Constants} from 'contracts/lib/Constants.sol';
|
||||
|
||||
import {IPrivacyPool} from 'interfaces/IPrivacyPool.sol';
|
||||
|
||||
import {Entrypoint} from 'contracts/Entrypoint.sol';
|
||||
import {PrivacyPoolComplex} from 'contracts/implementations/PrivacyPoolComplex.sol';
|
||||
import {PrivacyPoolSimple} from 'contracts/implementations/PrivacyPoolSimple.sol';
|
||||
import {CommitmentVerifier} from 'contracts/verifiers/CommitmentVerifier.sol';
|
||||
import {WithdrawalVerifier} from 'contracts/verifiers/WithdrawalVerifier.sol';
|
||||
|
||||
/*///////////////////////////////////////////////////////////////
|
||||
TEST TOKEN
|
||||
//////////////////////////////////////////////////////////////*/
|
||||
|
||||
contract TestToken is ERC20 {
|
||||
constructor() ERC20('Test Token', 'TST') {
|
||||
_mint(msg.sender, 1_000_000 * 10 ** decimals());
|
||||
}
|
||||
}
|
||||
|
||||
/*///////////////////////////////////////////////////////////////
|
||||
BASE DEPLOY SCRIPT
|
||||
//////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @notice Abstract script to deploy the PrivacyPool protocol.
|
||||
* @dev Assets and chain specific configurations must be defined in a parent contract.
|
||||
*/
|
||||
abstract contract DeployProtocol is Script {
|
||||
// @notice Struct for Pool deployment and configuration
|
||||
struct PoolConfig {
|
||||
string symbol;
|
||||
IERC20 asset;
|
||||
uint256 minimumDepositAmount;
|
||||
uint256 vettingFeeBPS;
|
||||
uint256 maxRelayFeeBPS;
|
||||
}
|
||||
|
||||
// @notice Deployed Entrypoint
|
||||
Entrypoint public entrypoint;
|
||||
// @notice Deployed Groth16 Withdrawal Verifier
|
||||
WithdrawalVerifier public withdrawalVerifier;
|
||||
// @notice Deployed Groth16 Ragequit Verifier
|
||||
CommitmentVerifier public ragequitVerifier;
|
||||
|
||||
// @notice Initial Entrypoint `ONWER_ROLE`
|
||||
address public owner;
|
||||
// @notice Initial Entrypoint `POSTMAN_ROLE`
|
||||
address public postman;
|
||||
|
||||
// @notice Native asset pool configuration
|
||||
PoolConfig internal _simpleConfig;
|
||||
// @notice ERC20 pools configurations
|
||||
PoolConfig[] internal _poolConfigs;
|
||||
|
||||
function setUp() public virtual {
|
||||
owner = vm.envAddress('OWNER_ADDRESS');
|
||||
postman = vm.envAddress('POSTMAN_ADDRESS');
|
||||
}
|
||||
|
||||
// @dev Must be called with the `--account` flag which acts as the caller
|
||||
function run() public virtual {
|
||||
vm.startBroadcast();
|
||||
|
||||
// Deploy verifiers
|
||||
_deployGroth16Verifiers();
|
||||
// Deploy Entrypoint
|
||||
_deployEntrypoint();
|
||||
|
||||
// Deploy the native asset pool
|
||||
_deploySimplePool(
|
||||
_simpleConfig.symbol,
|
||||
_simpleConfig.minimumDepositAmount,
|
||||
_simpleConfig.vettingFeeBPS,
|
||||
_simpleConfig.maxRelayFeeBPS
|
||||
);
|
||||
|
||||
// Deploy the ERC20 pools
|
||||
// for (uint256 _i; _i < _poolConfigs.length; ++_i) {
|
||||
// PoolConfig memory _config = _poolConfigs[_i];
|
||||
// _deployComplexPool(_config.symbol, _config.asset, _config.minimumDepositAmount, _config.vettingFeeBPS, _config.maxRelayFeeBPS);
|
||||
// }
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
|
||||
function _deployGroth16Verifiers() private {
|
||||
withdrawalVerifier = new WithdrawalVerifier();
|
||||
ragequitVerifier = new CommitmentVerifier();
|
||||
|
||||
console.log('Withdrawal Verifier deployed at: %s', address(withdrawalVerifier));
|
||||
console.log('Ragequit Verifier deployed at: %s', address(ragequitVerifier));
|
||||
}
|
||||
|
||||
function _deployEntrypoint() private {
|
||||
// Deploy implementation
|
||||
address _impl = address(new Entrypoint());
|
||||
|
||||
// Deploy and initialize proxy
|
||||
entrypoint = Entrypoint(
|
||||
payable(UnsafeUpgrades.deployUUPSProxy(_impl, abi.encodeCall(Entrypoint.initialize, (owner, postman))))
|
||||
);
|
||||
|
||||
console.log('Entrypoint deployed at: %s', address(entrypoint));
|
||||
}
|
||||
|
||||
function _deploySimplePool(
|
||||
string memory _symbol,
|
||||
uint256 _minimumDepositAmount,
|
||||
uint256 _vettingFeeBPS,
|
||||
uint256 _maxRelayFeeBPS
|
||||
) private {
|
||||
// Deploy pool
|
||||
IPrivacyPool _pool = IPrivacyPool(
|
||||
address(new PrivacyPoolSimple(address(entrypoint), address(withdrawalVerifier), address(ragequitVerifier)))
|
||||
);
|
||||
|
||||
// Register pool at entrypoint with defined configuration
|
||||
entrypoint.registerPool(
|
||||
IERC20(Constants.NATIVE_ASSET), _pool, _minimumDepositAmount, _vettingFeeBPS, _maxRelayFeeBPS
|
||||
);
|
||||
|
||||
console.log('%s Pool deployed at: %s', _symbol, address(_pool));
|
||||
}
|
||||
|
||||
function _deployComplexPool(
|
||||
string memory _symbol,
|
||||
IERC20 _asset,
|
||||
uint256 _minimumDepositAmount,
|
||||
uint256 _vettingFeeBPS,
|
||||
uint256 _maxRelayFeeBPS
|
||||
) private {
|
||||
// Deploy pool
|
||||
IPrivacyPool _pool = IPrivacyPool(
|
||||
address(
|
||||
new PrivacyPoolComplex(
|
||||
address(entrypoint), address(withdrawalVerifier), address(ragequitVerifier), address(_asset)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Register pool at entrypoint with defined configuration
|
||||
entrypoint.registerPool(_asset, _pool, _minimumDepositAmount, _vettingFeeBPS, _maxRelayFeeBPS);
|
||||
|
||||
console.log('%s Pool deployed at: %s', _symbol, address(_pool));
|
||||
}
|
||||
|
||||
function _deployTestToken() internal returns (IERC20 _asset) {
|
||||
_asset = IERC20(address(new TestToken()));
|
||||
console.log('TestToken deployed at: %s', address(_asset));
|
||||
}
|
||||
}
|
||||
|
||||
/*///////////////////////////////////////////////////////////////
|
||||
ETHEREUM SEPOLIA
|
||||
TESTNETS
|
||||
//////////////////////////////////////////////////////////////*/
|
||||
|
||||
// @notice Protocol configuration for Ethereum Sepolia
|
||||
contract EthereumSepolia is DeployProtocol {
|
||||
function setUp() public override {
|
||||
function setUp() public override chainId(11_155_111) {
|
||||
// Native asset pool
|
||||
_simpleConfig = PoolConfig({
|
||||
_nativePoolConfig = PoolConfig({
|
||||
symbol: 'ETH',
|
||||
asset: IERC20(Constants.NATIVE_ASSET),
|
||||
minimumDepositAmount: 0.001 ether,
|
||||
@@ -178,61 +23,39 @@ contract EthereumSepolia is DeployProtocol {
|
||||
|
||||
super.setUp();
|
||||
}
|
||||
}
|
||||
|
||||
// Overriding `run` to deploy TestToken before deploying the protocol
|
||||
function run() public override {
|
||||
vm.startBroadcast();
|
||||
contract GnosisChiado is DeployProtocol {
|
||||
function setUp() public override chainId(10_200) {
|
||||
// Native asset pool
|
||||
_nativePoolConfig = PoolConfig({
|
||||
symbol: 'xDAI',
|
||||
asset: IERC20(Constants.NATIVE_ASSET),
|
||||
minimumDepositAmount: 100 ether, // 18 decimals -> 100 xDAI
|
||||
vettingFeeBPS: 100,
|
||||
maxRelayFeeBPS: 100
|
||||
});
|
||||
|
||||
// TestToken
|
||||
// _poolConfigs.push(
|
||||
// PoolConfig({symbol: 'TST', asset: _deployTestToken(), minimumDepositAmount: 100 ether, vettingFeeBPS: 100}) // 1%
|
||||
// );
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
super.run();
|
||||
super.setUp();
|
||||
}
|
||||
}
|
||||
|
||||
/*///////////////////////////////////////////////////////////////
|
||||
ETHEREUM MAINNET
|
||||
MAINNETS
|
||||
//////////////////////////////////////////////////////////////*/
|
||||
|
||||
// @notice Protocol configuration for Ethereum Mainnet
|
||||
// TODO: update with actual mainnet configuration
|
||||
contract EthereumMainnet is DeployProtocol {
|
||||
function setUp() public override {
|
||||
function setUp() public override chainId(1) {
|
||||
// Native asset pool
|
||||
_simpleConfig = PoolConfig({
|
||||
_nativePoolConfig = PoolConfig({
|
||||
symbol: 'ETH',
|
||||
asset: IERC20(Constants.NATIVE_ASSET),
|
||||
minimumDepositAmount: 0.001 ether,
|
||||
vettingFeeBPS: 100,
|
||||
maxRelayFeeBPS: 100
|
||||
vettingFeeBPS: 100, // 1%
|
||||
maxRelayFeeBPS: 100 // 1%
|
||||
});
|
||||
|
||||
// USDT
|
||||
_poolConfigs.push(
|
||||
PoolConfig({
|
||||
symbol: 'USDT',
|
||||
asset: IERC20(address(0)),
|
||||
minimumDepositAmount: 100 ether,
|
||||
vettingFeeBPS: 100,
|
||||
maxRelayFeeBPS: 100
|
||||
})
|
||||
);
|
||||
|
||||
// USDC
|
||||
_poolConfigs.push(
|
||||
PoolConfig({
|
||||
symbol: 'USDC',
|
||||
asset: IERC20(address(0)),
|
||||
minimumDepositAmount: 100 ether,
|
||||
vettingFeeBPS: 100,
|
||||
maxRelayFeeBPS: 100
|
||||
})
|
||||
);
|
||||
|
||||
super.setUp();
|
||||
}
|
||||
}
|
||||
|
||||
38
packages/contracts/src/contracts/lib/DeployLib.sol
Normal file
38
packages/contracts/src/contracts/lib/DeployLib.sol
Normal file
@@ -0,0 +1,38 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
pragma solidity 0.8.28;
|
||||
|
||||
/**
|
||||
* @title DeployLib
|
||||
* @dev A library for deterministic deployment of Privacy Pool contracts and related components
|
||||
* using CREATE2 via the CreateX contract.
|
||||
*
|
||||
* This library provides predefined salt values for deterministic deployments of:
|
||||
* - Entrypoint (as an UUPS proxy)
|
||||
* - Simple Privacy Pool (for native assets)
|
||||
* - Complex Privacy Pool (for ERC20 tokens)
|
||||
* - Commitment Verifier
|
||||
* - Withdrawal Verifier
|
||||
*
|
||||
* Each component can be deployed with a deterministic address based on these predefined salts.
|
||||
*/
|
||||
library DeployLib {
|
||||
/**
|
||||
* @dev Predefined salt values for each contract type
|
||||
* @notice These values ensure deterministic addresses across deployments
|
||||
*/
|
||||
bytes11 internal constant ENTRYPOINT_SALT = bytes11(keccak256('Entrypoint1'));
|
||||
bytes11 internal constant SIMPLE_POOL_SALT = bytes11(keccak256(abi.encodePacked('PrivacyPoolSimple1')));
|
||||
bytes11 internal constant COMPLEX_POOL_SALT = bytes11(keccak256(abi.encodePacked('PrivacyPoolComplex1')));
|
||||
bytes11 internal constant WITHDRAWAL_VERIFIER_SALT = bytes11(keccak256(abi.encodePacked('WithdrawalVerifier1')));
|
||||
bytes11 internal constant RAGEQUIT_VERIFIER_SALT = bytes11(keccak256(abi.encodePacked('RagequitVerifier1')));
|
||||
|
||||
/**
|
||||
* @dev Creates a custom salt for deterministic deployments
|
||||
* @param _deployer Address of the deployer
|
||||
* @param _custom Custom salt value
|
||||
* @return _customSalt The generated salt
|
||||
*/
|
||||
function salt(address _deployer, bytes11 _custom) internal pure returns (bytes32 _customSalt) {
|
||||
return bytes32(abi.encodePacked(_deployer, hex'00', _custom));
|
||||
}
|
||||
}
|
||||
153
packages/contracts/src/interfaces/external/ICreateX.sol
vendored
Normal file
153
packages/contracts/src/interfaces/external/ICreateX.sol
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
/**
|
||||
* @title CreateX Factory Interface Definition
|
||||
* @author pcaversaccio (https://web.archive.org/web/20230921103111/https://pcaversaccio.com/)
|
||||
* @custom:coauthor Matt Solomon (https://web.archive.org/web/20230921103335/https://mattsolomon.dev/)
|
||||
*/
|
||||
interface ICreateX {
|
||||
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
|
||||
/* TYPES */
|
||||
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
|
||||
|
||||
struct Values {
|
||||
uint256 constructorAmount;
|
||||
uint256 initCallAmount;
|
||||
}
|
||||
|
||||
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
|
||||
/* EVENTS */
|
||||
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
|
||||
|
||||
event ContractCreation(address indexed newContract, bytes32 indexed salt);
|
||||
event ContractCreation(address indexed newContract);
|
||||
event Create3ProxyContractCreation(address indexed newContract, bytes32 indexed salt);
|
||||
|
||||
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
|
||||
/* CUSTOM ERRORS */
|
||||
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
|
||||
|
||||
error FailedContractCreation(address emitter);
|
||||
error FailedContractInitialisation(address emitter, bytes revertData);
|
||||
error InvalidSalt(address emitter);
|
||||
error InvalidNonceValue(address emitter);
|
||||
error FailedEtherTransfer(address emitter, bytes revertData);
|
||||
|
||||
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
|
||||
/* CREATE */
|
||||
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
|
||||
|
||||
function deployCreate(bytes memory initCode) external payable returns (address newContract);
|
||||
|
||||
function deployCreateAndInit(
|
||||
bytes memory initCode,
|
||||
bytes memory data,
|
||||
Values memory values,
|
||||
address refundAddress
|
||||
) external payable returns (address newContract);
|
||||
|
||||
function deployCreateAndInit(
|
||||
bytes memory initCode,
|
||||
bytes memory data,
|
||||
Values memory values
|
||||
) external payable returns (address newContract);
|
||||
|
||||
function deployCreateClone(address implementation, bytes memory data) external payable returns (address proxy);
|
||||
|
||||
function computeCreateAddress(address deployer, uint256 nonce) external view returns (address computedAddress);
|
||||
|
||||
function computeCreateAddress(uint256 nonce) external view returns (address computedAddress);
|
||||
|
||||
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
|
||||
/* CREATE2 */
|
||||
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
|
||||
|
||||
function deployCreate2(bytes32 salt, bytes memory initCode) external payable returns (address newContract);
|
||||
|
||||
function deployCreate2(bytes memory initCode) external payable returns (address newContract);
|
||||
|
||||
function deployCreate2AndInit(
|
||||
bytes32 salt,
|
||||
bytes memory initCode,
|
||||
bytes memory data,
|
||||
Values memory values,
|
||||
address refundAddress
|
||||
) external payable returns (address newContract);
|
||||
|
||||
function deployCreate2AndInit(
|
||||
bytes32 salt,
|
||||
bytes memory initCode,
|
||||
bytes memory data,
|
||||
Values memory values
|
||||
) external payable returns (address newContract);
|
||||
|
||||
function deployCreate2AndInit(
|
||||
bytes memory initCode,
|
||||
bytes memory data,
|
||||
Values memory values,
|
||||
address refundAddress
|
||||
) external payable returns (address newContract);
|
||||
|
||||
function deployCreate2AndInit(
|
||||
bytes memory initCode,
|
||||
bytes memory data,
|
||||
Values memory values
|
||||
) external payable returns (address newContract);
|
||||
|
||||
function deployCreate2Clone(
|
||||
bytes32 salt,
|
||||
address implementation,
|
||||
bytes memory data
|
||||
) external payable returns (address proxy);
|
||||
|
||||
function deployCreate2Clone(address implementation, bytes memory data) external payable returns (address proxy);
|
||||
|
||||
function computeCreate2Address(
|
||||
bytes32 salt,
|
||||
bytes32 initCodeHash,
|
||||
address deployer
|
||||
) external pure returns (address computedAddress);
|
||||
|
||||
function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) external view returns (address computedAddress);
|
||||
|
||||
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
|
||||
/* CREATE3 */
|
||||
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
|
||||
|
||||
function deployCreate3(bytes32 salt, bytes memory initCode) external payable returns (address newContract);
|
||||
|
||||
function deployCreate3(bytes memory initCode) external payable returns (address newContract);
|
||||
|
||||
function deployCreate3AndInit(
|
||||
bytes32 salt,
|
||||
bytes memory initCode,
|
||||
bytes memory data,
|
||||
Values memory values,
|
||||
address refundAddress
|
||||
) external payable returns (address newContract);
|
||||
|
||||
function deployCreate3AndInit(
|
||||
bytes32 salt,
|
||||
bytes memory initCode,
|
||||
bytes memory data,
|
||||
Values memory values
|
||||
) external payable returns (address newContract);
|
||||
|
||||
function deployCreate3AndInit(
|
||||
bytes memory initCode,
|
||||
bytes memory data,
|
||||
Values memory values,
|
||||
address refundAddress
|
||||
) external payable returns (address newContract);
|
||||
|
||||
function deployCreate3AndInit(
|
||||
bytes memory initCode,
|
||||
bytes memory data,
|
||||
Values memory values
|
||||
) external payable returns (address newContract);
|
||||
|
||||
function computeCreate3Address(bytes32 salt, address deployer) external pure returns (address computedAddress);
|
||||
|
||||
function computeCreate3Address(bytes32 salt) external view returns (address computedAddress);
|
||||
}
|
||||
@@ -4,12 +4,15 @@ pragma solidity 0.8.28;
|
||||
import {Entrypoint, IEntrypoint} from 'contracts/Entrypoint.sol';
|
||||
import {IPrivacyPool} from 'contracts/PrivacyPool.sol';
|
||||
|
||||
import {DeployLib} from 'contracts/lib/DeployLib.sol';
|
||||
|
||||
import {PrivacyPoolComplex} from 'contracts/implementations/PrivacyPoolComplex.sol';
|
||||
import {PrivacyPoolSimple} from 'contracts/implementations/PrivacyPoolSimple.sol';
|
||||
|
||||
import {CommitmentVerifier} from 'contracts/verifiers/CommitmentVerifier.sol';
|
||||
import {WithdrawalVerifier} from 'contracts/verifiers/WithdrawalVerifier.sol';
|
||||
|
||||
import {ERC1967Proxy} from '@oz/proxy/ERC1967/ERC1967Proxy.sol';
|
||||
import {UnsafeUpgrades} from '@upgrades/Upgrades.sol';
|
||||
|
||||
import {IERC20} from '@oz/interfaces/IERC20.sol';
|
||||
@@ -22,6 +25,7 @@ import {PoseidonT2} from 'poseidon/PoseidonT2.sol';
|
||||
import {PoseidonT3} from 'poseidon/PoseidonT3.sol';
|
||||
import {PoseidonT4} from 'poseidon/PoseidonT4.sol';
|
||||
|
||||
import {ICreateX} from 'interfaces/external/ICreateX.sol';
|
||||
import {Constants} from 'test/helper/Constants.sol';
|
||||
|
||||
contract IntegrationBase is Test {
|
||||
@@ -81,14 +85,17 @@ contract IntegrationBase is Test {
|
||||
uint256 internal constant _FORK_BLOCK = 18_920_905;
|
||||
|
||||
// Core protocol contracts
|
||||
IEntrypoint internal _entrypoint;
|
||||
IPrivacyPool internal _ethPool;
|
||||
IPrivacyPool internal _daiPool;
|
||||
Entrypoint internal _entrypoint;
|
||||
PrivacyPoolSimple internal _ethPool;
|
||||
PrivacyPoolComplex internal _daiPool;
|
||||
|
||||
// Groth16 Verifiers
|
||||
CommitmentVerifier internal _commitmentVerifier;
|
||||
WithdrawalVerifier internal _withdrawalVerifier;
|
||||
|
||||
// CreateX Singleton
|
||||
ICreateX internal constant _CREATEX = ICreateX(0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed);
|
||||
|
||||
// Assets
|
||||
IERC20 internal constant _DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);
|
||||
IERC20 internal _ETH = IERC20(Constants.NATIVE_ASSET);
|
||||
@@ -127,43 +134,70 @@ contract IntegrationBase is Test {
|
||||
SETUP
|
||||
//////////////////////////////////////////////////////////////*/
|
||||
|
||||
//asd
|
||||
function setUp() public virtual {
|
||||
vm.createSelectFork(vm.rpcUrl('mainnet'));
|
||||
|
||||
vm.startPrank(_OWNER);
|
||||
|
||||
// Deploy Groth16 ragequit verifier
|
||||
_commitmentVerifier = new CommitmentVerifier();
|
||||
_commitmentVerifier = CommitmentVerifier(
|
||||
_CREATEX.deployCreate2(
|
||||
DeployLib.salt(_OWNER, DeployLib.RAGEQUIT_VERIFIER_SALT),
|
||||
abi.encodePacked(type(CommitmentVerifier).creationCode)
|
||||
)
|
||||
);
|
||||
|
||||
// Deploy Groth16 withdrawal verifier
|
||||
_withdrawalVerifier = new WithdrawalVerifier();
|
||||
_withdrawalVerifier = WithdrawalVerifier(
|
||||
_CREATEX.deployCreate2(
|
||||
DeployLib.salt(_OWNER, DeployLib.WITHDRAWAL_VERIFIER_SALT),
|
||||
abi.encodePacked(type(WithdrawalVerifier).creationCode)
|
||||
)
|
||||
);
|
||||
|
||||
// Deploy Entrypoint
|
||||
address _impl = address(new Entrypoint());
|
||||
_entrypoint = Entrypoint(
|
||||
payable(UnsafeUpgrades.deployUUPSProxy(_impl, abi.encodeCall(Entrypoint.initialize, (_OWNER, _POSTMAN))))
|
||||
bytes memory _intializationData = abi.encodeCall(Entrypoint.initialize, (_OWNER, _POSTMAN));
|
||||
address _entrypointAddr = _CREATEX.deployCreate2(
|
||||
DeployLib.salt(_OWNER, DeployLib.ENTRYPOINT_SALT),
|
||||
abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(_impl, _intializationData))
|
||||
);
|
||||
_entrypoint = Entrypoint(payable(_entrypointAddr));
|
||||
|
||||
// Deploy ETH pool
|
||||
_ethPool = PrivacyPoolSimple(
|
||||
_CREATEX.deployCreate2(
|
||||
DeployLib.salt(_OWNER, DeployLib.SIMPLE_POOL_SALT),
|
||||
abi.encodePacked(
|
||||
type(PrivacyPoolSimple).creationCode,
|
||||
abi.encode(address(_entrypoint), address(_withdrawalVerifier), address(_commitmentVerifier))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Deploy ETH Pool
|
||||
_ethPool = IPrivacyPool(
|
||||
address(new PrivacyPoolSimple(address(_entrypoint), address(_withdrawalVerifier), address(_commitmentVerifier)))
|
||||
);
|
||||
|
||||
// Deploy DAI Pool
|
||||
_daiPool = IPrivacyPool(
|
||||
address(
|
||||
new PrivacyPoolComplex(
|
||||
address(_entrypoint), address(_withdrawalVerifier), address(_commitmentVerifier), address(_DAI)
|
||||
// Deploy DAI pool
|
||||
_daiPool = PrivacyPoolComplex(
|
||||
_CREATEX.deployCreate2(
|
||||
DeployLib.salt(_OWNER, DeployLib.COMPLEX_POOL_SALT),
|
||||
abi.encodePacked(
|
||||
type(PrivacyPoolComplex).creationCode,
|
||||
abi.encode(address(_entrypoint), address(_withdrawalVerifier), address(_commitmentVerifier), address(_DAI))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Register ETH pool
|
||||
_entrypoint.registerPool(
|
||||
IERC20(Constants.NATIVE_ASSET), IPrivacyPool(_ethPool), _MIN_DEPOSIT, _VETTING_FEE_BPS, _MAX_RELAY_FEE_BPS
|
||||
IERC20(Constants.NATIVE_ASSET),
|
||||
IPrivacyPool(address(_ethPool)),
|
||||
_MIN_DEPOSIT,
|
||||
_VETTING_FEE_BPS,
|
||||
_MAX_RELAY_FEE_BPS
|
||||
);
|
||||
|
||||
// Register DAI pool
|
||||
_entrypoint.registerPool(_DAI, IPrivacyPool(_daiPool), _MIN_DEPOSIT, _VETTING_FEE_BPS, _MAX_RELAY_FEE_BPS);
|
||||
_entrypoint.registerPool(_DAI, IPrivacyPool(address(_daiPool)), _MIN_DEPOSIT, _VETTING_FEE_BPS, _MAX_RELAY_FEE_BPS);
|
||||
|
||||
vm.stopPrank();
|
||||
}
|
||||
@@ -183,7 +217,9 @@ contract IntegrationBase is Test {
|
||||
}
|
||||
|
||||
// Define pool to deposit to
|
||||
IPrivacyPool _pool = _params.asset == IERC20(Constants.NATIVE_ASSET) ? _ethPool : _daiPool;
|
||||
IPrivacyPool _pool = _params.asset == IERC20(Constants.NATIVE_ASSET)
|
||||
? IPrivacyPool(address(_ethPool))
|
||||
: IPrivacyPool(address(_daiPool));
|
||||
|
||||
// Fetch current nonce
|
||||
uint256 _currentNonce = _pool.nonce();
|
||||
@@ -248,7 +284,9 @@ contract IntegrationBase is Test {
|
||||
|
||||
function _selfWithdraw(WithdrawalParams memory _params) internal returns (Commitment memory _commitment) {
|
||||
// Define pool to deposit to
|
||||
IPrivacyPool _pool = _params.commitment.asset == IERC20(Constants.NATIVE_ASSET) ? _ethPool : _daiPool;
|
||||
IPrivacyPool _pool = _params.commitment.asset == IERC20(Constants.NATIVE_ASSET)
|
||||
? IPrivacyPool(address(_ethPool))
|
||||
: IPrivacyPool(address(_daiPool));
|
||||
|
||||
// Build `Withdrawal` object for direct withdrawal
|
||||
IPrivacyPool.Withdrawal memory _withdrawal = IPrivacyPool.Withdrawal({processooor: _params.recipient, data: ''});
|
||||
@@ -259,7 +297,9 @@ contract IntegrationBase is Test {
|
||||
|
||||
function _withdrawThroughRelayer(WithdrawalParams memory _params) internal returns (Commitment memory _commitment) {
|
||||
// Define pool to deposit to
|
||||
IPrivacyPool _pool = _params.commitment.asset == IERC20(Constants.NATIVE_ASSET) ? _ethPool : _daiPool;
|
||||
IPrivacyPool _pool = _params.commitment.asset == IERC20(Constants.NATIVE_ASSET)
|
||||
? IPrivacyPool(address(_ethPool))
|
||||
: IPrivacyPool(address(_daiPool));
|
||||
|
||||
// Build `Withdrawal` object for relayed withdrawal
|
||||
IPrivacyPool.Withdrawal memory _withdrawal = IPrivacyPool.Withdrawal({
|
||||
@@ -357,7 +397,9 @@ contract IntegrationBase is Test {
|
||||
|
||||
function _ragequit(address _depositor, Commitment memory _commitment) internal {
|
||||
// Define pool to ragequit from
|
||||
IPrivacyPool _pool = _commitment.asset == IERC20(Constants.NATIVE_ASSET) ? _ethPool : _daiPool;
|
||||
IPrivacyPool _pool = _commitment.asset == IERC20(Constants.NATIVE_ASSET)
|
||||
? IPrivacyPool(address(_ethPool))
|
||||
: IPrivacyPool(address(_daiPool));
|
||||
|
||||
uint256 _depositorInitialBalance = _balance(_depositor, _commitment.asset);
|
||||
uint256 _entrypointInitialBalance = _balance(address(_entrypoint), _commitment.asset);
|
||||
|
||||
256
packages/contracts/test/integration/IntegrationCreate2.t.sol
Normal file
256
packages/contracts/test/integration/IntegrationCreate2.t.sol
Normal file
@@ -0,0 +1,256 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
pragma solidity 0.8.28;
|
||||
|
||||
import {ERC1967Proxy} from '@oz/proxy/ERC1967/ERC1967Proxy.sol';
|
||||
import {DeployLib} from 'contracts/lib/DeployLib.sol';
|
||||
import {Test} from 'forge-std/Test.sol';
|
||||
import {ICreateX} from 'interfaces/external/ICreateX.sol';
|
||||
|
||||
import {Entrypoint} from 'contracts/Entrypoint.sol';
|
||||
import {PrivacyPoolComplex} from 'contracts/implementations/PrivacyPoolComplex.sol';
|
||||
import {PrivacyPoolSimple} from 'contracts/implementations/PrivacyPoolSimple.sol';
|
||||
import {CommitmentVerifier} from 'contracts/verifiers/CommitmentVerifier.sol';
|
||||
import {WithdrawalVerifier} from 'contracts/verifiers/WithdrawalVerifier.sol';
|
||||
|
||||
/**
|
||||
* @title IntegrationDeploy
|
||||
* @notice Integration test for verifying deterministic CREATE2 deployments across multiple chains
|
||||
* @dev This test ensures that Privacy Pool contracts are deployed to the same addresses
|
||||
* across different EVM-compatible chains (mainnet, sepolia, gnosis) using CREATE2
|
||||
*/
|
||||
contract IntegrationDeploy is Test {
|
||||
/**
|
||||
* @notice Structure to hold deployed contract addresses for a specific chain
|
||||
* @param commitmentVerifier Address of the CommitmentVerifier contract
|
||||
* @param withdrawalVerifier Address of the WithdrawalVerifier contract
|
||||
* @param entrypoint Address of the Entrypoint contract
|
||||
* @param nativePool Address of the PrivacyPoolSimple contract (for native assets)
|
||||
* @param tokenPool Address of the PrivacyPoolComplex contract (for ERC20 tokens)
|
||||
*/
|
||||
struct Contracts {
|
||||
address commitmentVerifier;
|
||||
address withdrawalVerifier;
|
||||
address entrypoint;
|
||||
address nativePool;
|
||||
address tokenPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Structure to hold chain-specific configuration
|
||||
* @param id Chain ID
|
||||
* @param name Chain name (used for forking)
|
||||
* @param native Native token symbol
|
||||
* @param token Address of the ERC20 token to use for testing
|
||||
* @param tokenSymbol Symbol of the ERC20 token
|
||||
*/
|
||||
struct ChainConfig {
|
||||
uint256 id;
|
||||
string name;
|
||||
string native;
|
||||
address token;
|
||||
string tokenSymbol;
|
||||
}
|
||||
|
||||
/*///////////////////////////////////////////////////////////////
|
||||
STATE VARIABLES
|
||||
//////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* @notice Array of chain configurations to test
|
||||
*/
|
||||
ChainConfig[] internal _chains;
|
||||
|
||||
/**
|
||||
* @notice Mapping from chain ID to deployed contract addresses
|
||||
*/
|
||||
mapping(uint256 _chainId => Contracts _contracts) internal _contracts;
|
||||
|
||||
/**
|
||||
* @notice Address used for deployment operations
|
||||
*/
|
||||
address internal immutable _DEPLOYER = makeAddr('DEPLOYER');
|
||||
|
||||
/**
|
||||
* @notice Mock token address used for testing
|
||||
*/
|
||||
address internal _TOKEN = makeAddr('singleton_token');
|
||||
|
||||
/**
|
||||
* @notice CreateX Singleton
|
||||
*/
|
||||
ICreateX internal constant _CREATEX = ICreateX(0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed);
|
||||
|
||||
/**
|
||||
* @notice Set up test environment with chain configurations
|
||||
* @dev Initializes configurations for mainnet, sepolia, and gnosis chains
|
||||
*/
|
||||
function setUp() public {
|
||||
_chains.push(ChainConfig(1, 'mainnet', 'ETH', _TOKEN, 'SYMBOL'));
|
||||
_chains.push(ChainConfig(11_155_111, 'sepolia', 'ETH', _TOKEN, 'SYMBOL'));
|
||||
_chains.push(ChainConfig(100, 'gnosis', 'xDAI', _TOKEN, 'SYMBOL'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Test deterministic CREATE2 deployments across multiple chains
|
||||
* @dev For each chain:
|
||||
* 1. Creates a fork of the chain
|
||||
* 2. Deploys all Privacy Pool contracts using DeployLib
|
||||
* 3. Stores the deployed addresses
|
||||
* Then verifies that all contracts are deployed to the same addresses across chains
|
||||
*/
|
||||
function test_create2() public virtual {
|
||||
for (uint256 _i; _i < _chains.length; ++_i) {
|
||||
ChainConfig memory _chain = _chains[_i];
|
||||
|
||||
// Fork the chain
|
||||
vm.createSelectFork(vm.rpcUrl(_chain.name));
|
||||
vm.startPrank(_DEPLOYER);
|
||||
|
||||
// Deploy all contracts for this chain
|
||||
_deployContractsForChain(_chain);
|
||||
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
// Verify that contract addresses are the same across all chains
|
||||
_verifyAddressesMatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deploy all contracts for a specific chain
|
||||
* @param _chain Chain configuration
|
||||
*/
|
||||
function _deployContractsForChain(ChainConfig memory _chain) private {
|
||||
// Deploy verifiers
|
||||
address _commitmentVerifier = _deployCommitmentVerifier();
|
||||
address _withdrawalVerifier = _deployWithdrawalVerifier();
|
||||
|
||||
// Store verifier addresses
|
||||
_contracts[_chain.id].commitmentVerifier = _commitmentVerifier;
|
||||
_contracts[_chain.id].withdrawalVerifier = _withdrawalVerifier;
|
||||
|
||||
// Deploy Entrypoint
|
||||
address _entrypoint = _deployEntrypoint();
|
||||
_contracts[_chain.id].entrypoint = _entrypoint;
|
||||
|
||||
// Deploy pools
|
||||
_contracts[_chain.id].nativePool = _deployNativePool(_entrypoint, _withdrawalVerifier, _commitmentVerifier);
|
||||
_contracts[_chain.id].tokenPool =
|
||||
_deployTokenPool(_entrypoint, _withdrawalVerifier, _commitmentVerifier, _chain.token);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deploy CommitmentVerifier contract
|
||||
* @return Address of the deployed CommitmentVerifier
|
||||
*/
|
||||
function _deployCommitmentVerifier() private returns (address) {
|
||||
return _CREATEX.deployCreate2(
|
||||
DeployLib.salt(_DEPLOYER, DeployLib.RAGEQUIT_VERIFIER_SALT),
|
||||
abi.encodePacked(type(CommitmentVerifier).creationCode)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deploy WithdrawalVerifier contract
|
||||
* @return Address of the deployed WithdrawalVerifier
|
||||
*/
|
||||
function _deployWithdrawalVerifier() private returns (address) {
|
||||
return _CREATEX.deployCreate2(
|
||||
DeployLib.salt(_DEPLOYER, DeployLib.WITHDRAWAL_VERIFIER_SALT),
|
||||
abi.encodePacked(type(WithdrawalVerifier).creationCode)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deploy Entrypoint contract
|
||||
* @return Address of the deployed Entrypoint
|
||||
*/
|
||||
function _deployEntrypoint() private returns (address) {
|
||||
address _owner = makeAddr('OWNER');
|
||||
address _postman = makeAddr('POSTMAN');
|
||||
address _impl = address(new Entrypoint());
|
||||
bytes memory _intializationData = abi.encodeCall(Entrypoint.initialize, (_owner, _postman));
|
||||
|
||||
return _CREATEX.deployCreate2(
|
||||
DeployLib.salt(_DEPLOYER, DeployLib.ENTRYPOINT_SALT),
|
||||
abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(_impl, _intializationData))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deploy PrivacyPoolSimple contract for native assets
|
||||
* @param _entrypoint Address of the Entrypoint contract
|
||||
* @param _withdrawalVerifier Address of the WithdrawalVerifier contract
|
||||
* @param _commitmentVerifier Address of the CommitmentVerifier contract
|
||||
* @return Address of the deployed PrivacyPoolSimple
|
||||
*/
|
||||
function _deployNativePool(
|
||||
address _entrypoint,
|
||||
address _withdrawalVerifier,
|
||||
address _commitmentVerifier
|
||||
) private returns (address) {
|
||||
return _CREATEX.deployCreate2(
|
||||
DeployLib.salt(_DEPLOYER, DeployLib.SIMPLE_POOL_SALT),
|
||||
abi.encodePacked(
|
||||
type(PrivacyPoolSimple).creationCode, abi.encode(_entrypoint, _withdrawalVerifier, _commitmentVerifier)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deploy PrivacyPoolComplex contract for ERC20 tokens
|
||||
* @param _entrypoint Address of the Entrypoint contract
|
||||
* @param _withdrawalVerifier Address of the WithdrawalVerifier contract
|
||||
* @param _commitmentVerifier Address of the CommitmentVerifier contract
|
||||
* @param _token Address of the ERC20 token
|
||||
* @return Address of the deployed PrivacyPoolComplex
|
||||
*/
|
||||
function _deployTokenPool(
|
||||
address _entrypoint,
|
||||
address _withdrawalVerifier,
|
||||
address _commitmentVerifier,
|
||||
address _token
|
||||
) private returns (address) {
|
||||
return _CREATEX.deployCreate2(
|
||||
DeployLib.salt(_DEPLOYER, DeployLib.COMPLEX_POOL_SALT),
|
||||
abi.encodePacked(
|
||||
type(PrivacyPoolComplex).creationCode, abi.encode(_entrypoint, _withdrawalVerifier, _commitmentVerifier, _token)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Verify that contract addresses match across all chains
|
||||
*/
|
||||
function _verifyAddressesMatch() private view {
|
||||
assertTrue(
|
||||
_contracts[1].commitmentVerifier == _contracts[11_155_111].commitmentVerifier
|
||||
&& _contracts[11_155_111].commitmentVerifier == _contracts[100].commitmentVerifier,
|
||||
"Commitment verifier addresses don't match"
|
||||
);
|
||||
|
||||
assertTrue(
|
||||
_contracts[1].withdrawalVerifier == _contracts[11_155_111].withdrawalVerifier
|
||||
&& _contracts[11_155_111].withdrawalVerifier == _contracts[100].withdrawalVerifier,
|
||||
"Withdrawal verifier addresses don't match"
|
||||
);
|
||||
|
||||
assertTrue(
|
||||
_contracts[1].entrypoint == _contracts[11_155_111].entrypoint
|
||||
&& _contracts[11_155_111].entrypoint == _contracts[100].entrypoint,
|
||||
"Entrypoint addresses don't match"
|
||||
);
|
||||
|
||||
assertTrue(
|
||||
_contracts[1].nativePool == _contracts[11_155_111].nativePool
|
||||
&& _contracts[11_155_111].nativePool == _contracts[100].nativePool,
|
||||
"Native pool addresses don't match"
|
||||
);
|
||||
|
||||
assertTrue(
|
||||
_contracts[1].tokenPool == _contracts[11_155_111].tokenPool
|
||||
&& _contracts[11_155_111].tokenPool == _contracts[100].tokenPool,
|
||||
"Complex pool addresses don't match"
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user