Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add factories integration test to check deployments #66

Merged
merged 5 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 2 additions & 17 deletions src/contracts/utils/USDCInitTxs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,10 @@ pragma solidity 0.8.25;
* by Circle.
*/
library USDCInitTxs {
/**
* @dev The `initialize()` transaction data for the USDC implementation contract.
*/
bytes public constant INITIALIZE = abi.encodeWithSignature(
'initialize(string,string,string,uint8,address,address,address,address)',
'',
'',
'',
0,
address(1),
address(1),
address(1),
address(1)
);

/**
* @dev The `initializeV2()` transaction data for the USDC implementation contract.
*/
bytes public constant INITIALIZEV2 = abi.encodeWithSignature('initializeV2(string)', 'USDC');
bytes public constant INITIALIZEV2 = abi.encodeWithSignature('initializeV2(string)', 'Bridged USDC');

/**
* @dev The `initializeV2_1()` transaction data for the USDC implementation contract.
Expand All @@ -35,5 +20,5 @@ library USDCInitTxs {
* @dev The `initializeV2_2()` transaction data for the USDC implementation contract.
*/
bytes public constant INITIALIZEV2_2 =
abi.encodeWithSignature('initializeV2_2(address[],string)', new address[](0), '');
abi.encodeWithSignature('initializeV2_2(address[],string)', new address[](0), 'USDC.e');
}
7 changes: 7 additions & 0 deletions src/interfaces/IL2OpUSDCBridgeAdapter.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {FallbackProxyAdmin} from 'contracts/utils/FallbackProxyAdmin.sol';

interface IL2OpUSDCBridgeAdapter {
/*///////////////////////////////////////////////////////////////
EVENTS
Expand Down Expand Up @@ -49,4 +51,9 @@
* @return _isMessagingDisabled Whether messaging is disabled
*/
function isMessagingDisabled() external view returns (bool _isMessagingDisabled);

/**
* @return _fallbackProxyAdmin The address of the fallback proxy admin
*/
function FALLBACK_PROXY_ADMIN() external view returns (FallbackProxyAdmin _fallbackProxyAdmin);

Check warning on line 58 in src/interfaces/IL2OpUSDCBridgeAdapter.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

Function name must be in mixedCase
hexshire marked this conversation as resolved.
Show resolved Hide resolved
}
42 changes: 42 additions & 0 deletions src/interfaces/external/IUSDC.sol
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,46 @@ interface IUSDC is IERC20 {
* @return _decimals The decimals of the token
*/
function decimals() external view returns (uint8 _decimals);

/**
* @return _name The name of the token
*/
function name() external view returns (string memory _name);

/**
* @return _symbol The symbol of the token
*/
function symbol() external view returns (string memory _symbol);

/**
* @notice Checks if an account is a minter.
* @param _account The address to check.
* @return _isMinter True if the account is a minter, false if the account is not a minter.
*/
function isMinter(address _account) external view returns (bool _isMinter);

/**
* @notice Returns the allowance of a minter
* @param _minter The address of the minter
* @return _allowance The minting amount allowed for the minter
*/
function minterAllowance(address _minter) external view returns (uint256 _allowance);

/**
* @notice Returns the address of the current pauser
* @return _pauser Address of the current pauser
*/
function pauser() external view returns (address _pauser);

/**
* @notice Returns the address of the current blacklister
* @return _blacklister Address of the current blacklister
*/
function blacklister() external view returns (address _blacklister);

/**
* @notice Returns the address of the current admin
* @return _admin Address of the current admin
*/
function admin() external view returns (address _admin);
}
97 changes: 97 additions & 0 deletions test/integration/Factories.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {IntegrationBase} from './IntegrationBase.sol';

import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
import {L1OpUSDCFactory} from 'contracts/L1OpUSDCFactory.sol';

Check warning on line 7 in test/integration/Factories.t.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

Variable "L1OpUSDCFactory" is unused
import {StdStorage, stdStorage} from 'forge-std/StdStorage.sol';

Check warning on line 8 in test/integration/Factories.t.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

Variable "StdStorage" is unused

Check warning on line 8 in test/integration/Factories.t.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

Variable "stdStorage" is unused
import {IL1OpUSDCBridgeAdapter} from 'interfaces/IL1OpUSDCBridgeAdapter.sol';

Check warning on line 9 in test/integration/Factories.t.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

Variable "IL1OpUSDCBridgeAdapter" is unused

import {IL2OpUSDCBridgeAdapter} from 'interfaces/IL2OpUSDCBridgeAdapter.sol';
import {IOpUSDCBridgeAdapter} from 'interfaces/IOpUSDCBridgeAdapter.sol';
import {IUSDC} from 'interfaces/external/IUSDC.sol';

contract Integration_Factories is IntegrationBase {
/**
* @notice Check all the L1 and L2 contracts are properly deployed and initialized
*/
function test_deployAllContracts() public {
vm.selectFork(mainnet);

// Deploy the contracts
vm.prank(_user);
(address _l1Adapter, address _l2Factory, address _l2Adapter) =
l1Factory.deploy(address(OPTIMISM_L1_MESSENGER), _owner, l2Deployments);

// Check the adapter was properly deployed on L1
assertEq(IOpUSDCBridgeAdapter(_l1Adapter).USDC(), address(MAINNET_USDC));
assertEq(IOpUSDCBridgeAdapter(_l1Adapter).MESSENGER(), address(OPTIMISM_L1_MESSENGER));
assertEq(IOpUSDCBridgeAdapter(_l1Adapter).LINKED_ADAPTER(), _l2Adapter);
assertEq(Ownable(_l1Adapter).owner(), _owner);

bytes32 _salt = bytes32(l1Factory.deploymentsSaltCounter());

// Get the L1 values needed to assert the proper deployments on L2
string memory _usdcName = l1Factory.USDC_NAME();
string memory _usdcSymbol = l1Factory.USDC_SYMBOL();
uint8 _usdcDecimals = MAINNET_USDC.decimals();
string memory _usdcCurrency = MAINNET_USDC.currency();

vm.selectFork(optimism);
// Relay the L2 deployments message through the factory on L2
_relayL2Deployments(_salt, _l1Adapter, usdcInitializeData, l2Deployments);

// Check the adapter was properly deployed on L2
IUSDC _l2Usdc = IUSDC(IOpUSDCBridgeAdapter(_l2Adapter).USDC());
assertEq(IOpUSDCBridgeAdapter(_l2Adapter).MESSENGER(), address(L2_MESSENGER));
assertEq(IOpUSDCBridgeAdapter(_l2Adapter).LINKED_ADAPTER(), _l1Adapter);
assertEq(Ownable(_l2Adapter).owner(), _owner);

// Check the L2 factory was deployed
assertGt(_l2Factory.code.length, 0);

// Check the USDC was properly deployed on L2
assertEq(_l2Usdc.name(), _usdcName);
assertEq(_l2Usdc.symbol(), _usdcSymbol);
assertEq(_l2Usdc.decimals(), _usdcDecimals);
assertEq(_l2Usdc.currency(), _usdcCurrency);
assertGt(_l2Usdc.implementation().code.length, 0);

// Check the USDC permissions and allowances were properly set
assertEq(_l2Usdc.admin(), address(IL2OpUSDCBridgeAdapter(_l2Adapter).FALLBACK_PROXY_ADMIN()));
assertEq(_l2Usdc.masterMinter(), _l2Adapter);
assertEq(_l2Usdc.pauser(), _l2Adapter);
assertEq(_l2Usdc.blacklister(), _l2Adapter);
assertEq(_l2Usdc.isMinter(_l2Adapter), true);
assertEq(_l2Usdc.minterAllowance(_l2Adapter), type(uint256).max);
}

/**
* @notice Check the L1 and L2 contracts are deployed on different addresses on different triggered deployments
*/
function test_deployOnDifferentAddresses() public {
vm.selectFork(mainnet);

// Trigger another deployment
(address _secondL1Adapter, address _secondL2Factory, address _secondL2Adapter) =
l1Factory.deploy(address(OPTIMISM_L1_MESSENGER), _owner, l2Deployments);
bytes32 _secondSalt = bytes32(l1Factory.deploymentsSaltCounter());
vm.stopPrank();

vm.selectFork(optimism);

// Relay the second triggered L2 deployments message
_relayL2Deployments(_secondSalt, _secondL1Adapter, usdcInitializeData, l2Deployments);

// Get the usdc proxy and implementation addresses
IUSDC _secondL2Usdc = IUSDC(IOpUSDCBridgeAdapter(_secondL2Adapter).USDC());

// Check the deployed addresses always differ
assertTrue(_secondL1Adapter != address(l1Adapter));
assertTrue(_secondL2Factory != address(l2Factory));
assertTrue(_secondL2Adapter != address(l2Adapter));
assertTrue(_secondL2Usdc != bridgedUSDC);
assertTrue(_secondL2Usdc.implementation() != IUSDC(bridgedUSDC).implementation());
}
}
23 changes: 14 additions & 9 deletions test/integration/IntegrationBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,36 +51,39 @@ contract IntegrationBase is Helpers {

// OpUSDC Protocol
L1OpUSDCBridgeAdapter public l1Adapter;
L1OpUSDCFactory public factory;
L1OpUSDCFactory public l1Factory;
L2OpUSDCFactory public l2Factory;
L2OpUSDCBridgeAdapter public l2Adapter;
IUSDC public bridgedUSDC;
IL2OpUSDCFactory.USDCInitializeData public usdcInitializeData;
IL1OpUSDCFactory.L2Deployments public l2Deployments;

function setUp() public virtual {
mainnet = vm.createFork(vm.rpcUrl('mainnet'), _MAINNET_FORK_BLOCK);
optimism = vm.createFork(vm.rpcUrl('optimism'), _OPTIMISM_FORK_BLOCK);

factory = new L1OpUSDCFactory(address(MAINNET_USDC));
l1Factory = new L1OpUSDCFactory(address(MAINNET_USDC));

// Define the initialization transactions
usdcInitTxns[0] = USDCInitTxs.INITIALIZEV2;
usdcInitTxns[1] = USDCInitTxs.INITIALIZEV2_1;
usdcInitTxns[2] = USDCInitTxs.INITIALIZEV2_2;
// Define the L2 deployments data
IL1OpUSDCFactory.L2Deployments memory _l2Deployments =
l2Deployments =
IL1OpUSDCFactory.L2Deployments(_owner, USDC_IMPLEMENTATION_CREATION_CODE, usdcInitTxns, MIN_GAS_LIMIT_DEPLOY);

vm.selectFork(mainnet);

vm.prank(_owner);
(address _l1Adapter,, address _l2Adapter) = factory.deploy(address(OPTIMISM_L1_MESSENGER), _owner, _l2Deployments);
(address _l1Adapter, address _l2Factory, address _l2Adapter) =
l1Factory.deploy(address(OPTIMISM_L1_MESSENGER), _owner, l2Deployments);

l1Adapter = L1OpUSDCBridgeAdapter(_l1Adapter);

// Get salt and initialize data for l2 deployments
bytes32 _salt = bytes32(factory.deploymentsSaltCounter());
bytes32 _salt = bytes32(l1Factory.deploymentsSaltCounter());
usdcInitializeData = IL2OpUSDCFactory.USDCInitializeData(
factory.USDC_NAME(), factory.USDC_SYMBOL(), MAINNET_USDC.currency(), MAINNET_USDC.decimals()
l1Factory.USDC_NAME(), l1Factory.USDC_SYMBOL(), MAINNET_USDC.currency(), MAINNET_USDC.decimals()
);

// Give max minting power to the master minter
Expand All @@ -89,16 +92,18 @@ contract IntegrationBase is Helpers {
MAINNET_USDC.configureMinter(_masterMinter, type(uint256).max);

vm.selectFork(optimism);
_relayL2Deployments(_salt, _l1Adapter, usdcInitializeData, _l2Deployments);
_relayL2Deployments(_salt, _l1Adapter, usdcInitializeData, l2Deployments);

l2Adapter = L2OpUSDCBridgeAdapter(_l2Adapter);
bridgedUSDC = IUSDC(l2Adapter.USDC());
l2Factory = L2OpUSDCFactory(_l2Factory);

// Make foundry know these two address exist on both forks
vm.makePersistent(address(_l1Adapter));
vm.makePersistent(address(l1Adapter));
vm.makePersistent(address(l2Adapter));
vm.makePersistent(address(bridgedUSDC));
vm.makePersistent(address(l2Adapter.FALLBACK_PROXY_ADMIN()));
vm.makePersistent(address(l2Factory));
}

function _relayL2Deployments(
Expand All @@ -120,7 +125,7 @@ contract IntegrationBase is Helpers {
vm.prank(ALIASED_L1_MESSENGER);
L2_MESSENGER.relayMessage(
_messageNonce + 1,
address(factory),
address(l1Factory),
L2_CREATE2_DEPLOYER,
_ZERO_VALUE,
_l2Deployments.minGasLimitDeploy,
Expand Down
Loading