Skip to content

Commit

Permalink
fix: deployment code size too large (#65)
Browse files Browse the repository at this point in the history
# 🤖 Linear

Closes OPT-XXX
  • Loading branch information
excaliborr authored Jun 21, 2024
1 parent b3d746c commit 6b53a88
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 87 deletions.
3 changes: 2 additions & 1 deletion remappings.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
ds-test/=node_modules/ds-test/src
forge-std/=node_modules/forge-std/src
contracts/=src/contracts
interfaces/=src/interfaces
interfaces/=src/interfaces
libraries/=src/libraries
93 changes: 9 additions & 84 deletions src/contracts/L1OpUSDCFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
pragma solidity 0.8.25;

import {L1OpUSDCBridgeAdapter} from 'contracts/L1OpUSDCBridgeAdapter.sol';
import {L2OpUSDCFactory} from 'contracts/L2OpUSDCFactory.sol';
import {IL1OpUSDCFactory} from 'interfaces/IL1OpUSDCFactory.sol';
import {IL2OpUSDCFactory} from 'interfaces/IL2OpUSDCFactory.sol';
import {ICreate2Deployer} from 'interfaces/external/ICreate2Deployer.sol';
import {ICrossDomainMessenger} from 'interfaces/external/ICrossDomainMessenger.sol';

import {IUSDC} from 'interfaces/external/IUSDC.sol';
import {CrossChainDeployments} from 'libraries/CrossChainDeployments.sol';

/**
* @title L1OpUSDCFactory
Expand Down Expand Up @@ -78,7 +77,7 @@ contract L1OpUSDCFactory is IL1OpUSDCFactory {
uint256 _currentNonce = ++deploymentsSaltCounter;

// Precalculate the l1 adapter
_l1Adapter = _precalculateCreateAddress(address(this), _currentNonce);
_l1Adapter = CrossChainDeployments.precalculateCreateAddress(address(this), _currentNonce);

// Get the L1 USDC naming and decimals to ensure they are the same on the L2, guaranteeing the same standard
IL2OpUSDCFactory.USDCInitializeData memory _usdcInitializeData =
Expand All @@ -94,91 +93,17 @@ contract L1OpUSDCFactory is IL1OpUSDCFactory {
_usdcInitializeData,
_l2Deployments.usdcInitTxs
);
bytes memory _l2FactoryInitCode = bytes.concat(type(L2OpUSDCFactory).creationCode, _l2FactoryCArgs);
_l2Factory = _precalculateCreate2Address(_salt, keccak256(_l2FactoryInitCode), L2_CREATE2_DEPLOYER);

// Send the L2 factory deployment tx
_l2Factory = CrossChainDeployments.deployL2Factory(
_l2FactoryCArgs, _salt, _l1Messenger, L2_CREATE2_DEPLOYER, _l2Deployments.minGasLimitDeploy
);

// Precalculate the L2 adapter address
_l2Adapter = _precalculateCreateAddress(_l2Factory, _L2_ADAPTER_DEPLOYMENT_NONCE);
_l2Adapter = CrossChainDeployments.precalculateCreateAddress(_l2Factory, _L2_ADAPTER_DEPLOYMENT_NONCE);
// Deploy the L1 adapter
address(new L1OpUSDCBridgeAdapter(address(USDC), _l1Messenger, _l2Adapter, _l1AdapterOwner));

// Send the L2 factory deployment tx
bytes memory _l2FactoryDeploymentsTx =
abi.encodeWithSelector(ICreate2Deployer.deploy.selector, 0, _salt, _l2FactoryInitCode);
ICrossDomainMessenger(_l1Messenger).sendMessage(
L2_CREATE2_DEPLOYER, _l2FactoryDeploymentsTx, _l2Deployments.minGasLimitDeploy
);

emit L1AdapterDeployed(_l1Adapter);
}

/**
* @notice Precalculates the address of a contract that will be deployed thorugh `CREATE` opcode
* @param _deployer The deployer address
* @param _nonce The next nonce of the deployer address
* @return _precalculatedAddress The address where the contract will be stored
* @dev Only works for nonces between 1 and (2 ** 64 - 2), which is enough for this use case
*/
function _precalculateCreateAddress(
address _deployer,
uint256 _nonce
) internal pure returns (address _precalculatedAddress) {
bytes memory _data;
bytes1 _len = bytes1(0x94);

// A one-byte integer in the [0x00, 0x7f] range uses its own value as a length prefix, there is no
// additional "0x80 + length" prefix that precedes it.
// A one-byte integer in the [0x00, 0x7f] range uses its own value as a length prefix, there is no
// additional "0x80 + length" prefix that precedes it.
if (_nonce <= 0x7f) {
_data = abi.encodePacked(bytes1(0xd6), _len, _deployer, uint8(_nonce));
}
// In the case of `_nonce > 0x7f` and `_nonce <= type(uint8).max`, we have the following encoding scheme
// (the same calculation can be carried over for higher _nonce bytes):
// 0xda = 0xc0 (short RLP prefix) + 0x1a (= the bytes length of: 0x94 + address + 0x84 + _nonce, in hex),
// 0x94 = 0x80 + 0x14 (= the bytes length of an address, 20 bytes, in hex),
// 0x84 = 0x80 + 0x04 (= the bytes length of the _nonce, 4 bytes, in hex).
else if (_nonce <= type(uint8).max) {
_data = abi.encodePacked(bytes1(0xd7), _len, _deployer, bytes1(0x81), uint8(_nonce));
} else if (_nonce <= type(uint16).max) {
_data = abi.encodePacked(bytes1(0xd8), _len, _deployer, bytes1(0x82), uint16(_nonce));
} else if (_nonce <= type(uint24).max) {
_data = abi.encodePacked(bytes1(0xd9), _len, _deployer, bytes1(0x83), uint24(_nonce));
} else if (_nonce <= type(uint32).max) {
_data = abi.encodePacked(bytes1(0xda), _len, _deployer, bytes1(0x84), uint32(_nonce));
} else if (_nonce <= type(uint40).max) {
_data = abi.encodePacked(bytes1(0xdb), _len, _deployer, bytes1(0x85), uint40(_nonce));
} else if (_nonce <= type(uint48).max) {
_data = abi.encodePacked(bytes1(0xdc), _len, _deployer, bytes1(0x86), uint48(_nonce));
} else if (_nonce <= type(uint56).max) {
_data = abi.encodePacked(bytes1(0xdd), _len, _deployer, bytes1(0x87), uint56(_nonce));
} else {
_data = abi.encodePacked(bytes1(0xde), _len, _deployer, bytes1(0x88), uint64(_nonce));
}

_precalculatedAddress = address(uint160(uint256(keccak256(_data))));
}

/**
* @notice Precalculate and address to be deployed using the `CREATE2` opcode
* @param _salt The 32-byte random value used to create the contract address.
* @param _initCodeHash The 32-byte bytecode digest of the contract creation bytecode.
* @param _deployer The 20-byte _deployer address.
* @return _precalculatedAddress The 20-byte address where a contract will be stored.
*/
function _precalculateCreate2Address(
bytes32 _salt,
bytes32 _initCodeHash,
address _deployer
) internal pure returns (address _precalculatedAddress) {
assembly ("memory-safe") {
let _ptr := mload(0x40)
mstore(add(_ptr, 0x40), _initCodeHash)
mstore(add(_ptr, 0x20), _salt)
mstore(_ptr, _deployer)
let _start := add(_ptr, 0x0b)
mstore8(_start, 0xff)
_precalculatedAddress := keccak256(_start, 85)
}
}
}
101 changes: 101 additions & 0 deletions src/libraries/CrossChainDeployments.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
pragma solidity 0.8.25;

import {L2OpUSDCFactory} from 'contracts/L2OpUSDCFactory.sol';
import {ICreate2Deployer} from 'interfaces/external/ICreate2Deployer.sol';
import {ICrossDomainMessenger} from 'interfaces/external/ICrossDomainMessenger.sol';

library CrossChainDeployments {
/**
* @notice Deploys the L2 factory contract through the L1 messenger
* @param _args The initialization arguments for the L2 factory
* @param _salt The salt to be used to deploy the L2 factory
* @param _messenger The address of the L1 messenger
* @param _create2Deployer The address of the L2 create2 deployer
* @param _minGasLimit The minimum gas limit that the message can be executed with
* @return _l2Factory The address of the L2 factory
*/
function deployL2Factory(
bytes memory _args,
bytes32 _salt,
address _messenger,
address _create2Deployer,
uint32 _minGasLimit
) external returns (address _l2Factory) {
bytes memory _l2FactoryInitCode = bytes.concat(type(L2OpUSDCFactory).creationCode, _args);
_l2Factory = precalculateCreate2Address(_salt, keccak256(_l2FactoryInitCode), _create2Deployer);

bytes memory _l2FactoryDeploymentsTx =
abi.encodeWithSelector(ICreate2Deployer.deploy.selector, 0, _salt, _l2FactoryInitCode);
ICrossDomainMessenger(_messenger).sendMessage(_create2Deployer, _l2FactoryDeploymentsTx, _minGasLimit);
}

/**
* @notice Precalculate and address to be deployed using the `CREATE2` opcode
* @param _salt The 32-byte random value used to create the contract address.
* @param _initCodeHash The 32-byte bytecode digest of the contract creation bytecode.
* @param _deployer The 20-byte _deployer address.
* @return _precalculatedAddress The 20-byte address where a contract will be stored.
*/
function precalculateCreate2Address(
bytes32 _salt,
bytes32 _initCodeHash,
address _deployer
) internal pure returns (address _precalculatedAddress) {
assembly ("memory-safe") {
let _ptr := mload(0x40)
mstore(add(_ptr, 0x40), _initCodeHash)
mstore(add(_ptr, 0x20), _salt)
mstore(_ptr, _deployer)
let _start := add(_ptr, 0x0b)
mstore8(_start, 0xff)
_precalculatedAddress := keccak256(_start, 85)
}
}

/**
* @notice Precalculates the address of a contract that will be deployed thorugh `CREATE` opcode
* @param _deployer The deployer address
* @param _nonce The next nonce of the deployer address
* @return _precalculatedAddress The address where the contract will be stored
* @dev Only works for nonces between 1 and (2 ** 64 - 2), which is enough for this use case
*/
function precalculateCreateAddress(
address _deployer,
uint256 _nonce
) internal pure returns (address _precalculatedAddress) {
bytes memory _data;
bytes1 _len = bytes1(0x94);

// A one-byte integer in the [0x00, 0x7f] range uses its own value as a length prefix, there is no
// additional "0x80 + length" prefix that precedes it.
// A one-byte integer in the [0x00, 0x7f] range uses its own value as a length prefix, there is no
// additional "0x80 + length" prefix that precedes it.
if (_nonce <= 0x7f) {
_data = abi.encodePacked(bytes1(0xd6), _len, _deployer, uint8(_nonce));
}
// In the case of `_nonce > 0x7f` and `_nonce <= type(uint8).max`, we have the following encoding scheme
// (the same calculation can be carried over for higher _nonce bytes):
// 0xda = 0xc0 (short RLP prefix) + 0x1a (= the bytes length of: 0x94 + address + 0x84 + _nonce, in hex),
// 0x94 = 0x80 + 0x14 (= the bytes length of an address, 20 bytes, in hex),
// 0x84 = 0x80 + 0x04 (= the bytes length of the _nonce, 4 bytes, in hex).
else if (_nonce <= type(uint8).max) {
_data = abi.encodePacked(bytes1(0xd7), _len, _deployer, bytes1(0x81), uint8(_nonce));
} else if (_nonce <= type(uint16).max) {
_data = abi.encodePacked(bytes1(0xd8), _len, _deployer, bytes1(0x82), uint16(_nonce));
} else if (_nonce <= type(uint24).max) {
_data = abi.encodePacked(bytes1(0xd9), _len, _deployer, bytes1(0x83), uint24(_nonce));
} else if (_nonce <= type(uint32).max) {
_data = abi.encodePacked(bytes1(0xda), _len, _deployer, bytes1(0x84), uint32(_nonce));
} else if (_nonce <= type(uint40).max) {
_data = abi.encodePacked(bytes1(0xdb), _len, _deployer, bytes1(0x85), uint40(_nonce));
} else if (_nonce <= type(uint48).max) {
_data = abi.encodePacked(bytes1(0xdc), _len, _deployer, bytes1(0x86), uint48(_nonce));
} else if (_nonce <= type(uint56).max) {
_data = abi.encodePacked(bytes1(0xdd), _len, _deployer, bytes1(0x87), uint56(_nonce));
} else {
_data = abi.encodePacked(bytes1(0xde), _len, _deployer, bytes1(0x88), uint64(_nonce));
}

_precalculatedAddress = address(uint160(uint256(keccak256(_data))));
}
}
6 changes: 4 additions & 2 deletions test/unit/L1OpUSDCFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {IL1OpUSDCFactory} from 'interfaces/IL1OpUSDCFactory.sol';
import {ICreate2Deployer} from 'interfaces/external/ICreate2Deployer.sol';
import {ICrossDomainMessenger} from 'interfaces/external/ICrossDomainMessenger.sol';
import {IUSDC} from 'interfaces/external/IUSDC.sol';

import {CrossChainDeployments} from 'libraries/CrossChainDeployments.sol';
import {Helpers} from 'test/utils/Helpers.sol';

contract ForTestL1OpUSDCFactory is L1OpUSDCFactory {
Expand All @@ -19,15 +21,15 @@ contract ForTestL1OpUSDCFactory is L1OpUSDCFactory {
address _deployer,
uint256 _nonce
) public pure returns (address _precalculatedAddress) {
_precalculatedAddress = _precalculateCreateAddress(_deployer, _nonce);
_precalculatedAddress = CrossChainDeployments.precalculateCreateAddress(_deployer, _nonce);
}

function forTest_precalculateCreate2Address(
bytes32 _salt,
bytes32 _initCodeHash,
address _deployer
) public pure returns (address _precalculatedAddress) {
_precalculatedAddress = _precalculateCreate2Address(_salt, _initCodeHash, _deployer);
_precalculatedAddress = CrossChainDeployments.precalculateCreate2Address(_salt, _initCodeHash, _deployer);
}
}

Expand Down

0 comments on commit 6b53a88

Please sign in to comment.