-
Notifications
You must be signed in to change notification settings - Fork 6
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: proxies and custom factory #23
Conversation
* chore: clean factory contract a bit * fix: factory errors
* feat: add salt as param * chore: polish factory contract and remove some notes
* feat: add more values on deploy values struct * fix: remove broken deploy create 2 and init function usage * chore: update deployment scripts values
* chore: polish contract and scripts
* feat: add deployment addresses returned struct * chore: update natspec based on changes * feat: create internal functions for salt logic * refactor: create common script contract and update mainnet and sepolia ones
* refactor: update some vars visibility and names on the contract * chore: update natspec based on changes
* chore: add natspec over unit tests * fix: one return value on factory contract * chore: remove unused createx contract
chore: undo changes over pkg json and remappings
* refactor: update l1 factory and scripts
…oyer * feat: create bytecode deployer * refactor: pre calculate all addresses in l1 factory constructor * refactor: update interfaces with new and needed methods * refactor: update deployment scripts based on new changes
…ded function to l1 factory * fix: imports over deleted files and unneccessary imports * chore: add some comments on vars natspec
…with create deploy on l2 * refacor: update deploy functions params and natspec
* feat: add init txs calls while sending a message and execution on l2 factory * fix: upgrade manager tests * chore: add some comments and stack vars
OPT-67 Implement the solution for deploying bridged usdc and l2 adapter to the same address
dependent on spike OPT-51 UpgradeManager:
|
Deployments info (precalculated addresses on the L1 Factory deployment): Deploying L1OpUSDCFactory ... L1:
L2:
The addresses were deployed to OP-Sepolia and Base Sepolia. The addresses are the same ✅
|
[profile.default] | ||
solc_version = '0.8.25' | ||
libs = ['node_modules'] | ||
optimizer_runs = 10_000 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After I added this to the toml:
[profile.optimized]
via_ir = true
out = 'out-via-ir'
forge build
asked me (with a warning) to run forge config --fix
. This was removed after running that command
[profile.default.optimizer_details] | ||
yul = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I needed this becasue the msize()
of the BytecodeDeployer
contract didn't due to Yul optimizer issues
src/contracts/L1OpUSDCFactory.sol
Outdated
bytes memory _usdcProxyCArgs = abi.encode(L2_USDC_IMPLEMENTATION); | ||
bytes memory _usdcProxyInitCode = bytes.concat(USDC_PROXY_BYTECODE, _usdcProxyCArgs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the proxy of USDC will be always the same, I think is better to just encode the implementation address as unique argument and deploy by the giving init code and not the bytecode.
* feat: add args to the expect deposit tx call on test
* fix: use expect call instead of mock call to avoid foundry issues
* feat: add unit test over bytecode deployer * chore: undo toml changes
* fix: revert the bytecode deployer to the previous version * fix: update tests based on new changes
src/contracts/BytecodeDeployer.sol
Outdated
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.25; | ||
|
||
contract BytecodeDeployer { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add natspec here describing that this is a wrapper contract etc
Also I think it would be good if this was inside utils
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes!
* @notice Factory contract for deploying the L2 USDC implementation, proxy, and `L2OpUSDCBridgeAdapter` contracts all | ||
* at once on the constructor | ||
*/ | ||
contract L2OpUSDCFactory is IL2OpUSDCFactory { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will the address of this L2 factory always be the same because of the aliased sender? If thats the case can we use CREATE2
for proxy and impl deployments, It will make the logic much simpler on L1 and cheaper to check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that'd be better. However I need to check what happens when the deployment on L2 reverts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should only revert if the address on L2 is already occupied, meaning we have already deployed our contracts on that given chain, according to OP team the portal shouldnt revert
src/contracts/L2OpUSDCFactory.sol
Outdated
emit DeployedUSDCProxy(_usdcProxy); | ||
|
||
// Deploy L2 adapter | ||
address _adapter = address(new BytecodeDeployer(_l2AdapterBytecode)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also need the L2 Adapter proxy deployed, we have the init code for this as its just the proxy contract with impl address as param
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, good catch
constructor(address _usdc, address _owner) { | ||
// Calculate L1 adapter | ||
uint256 _thisNonceFirstTx = 1; | ||
L1_ADAPTER = _precalculateCreateAddress(address(this), _thisNonceFirstTx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For these wouldnt CREATE2
be easier? For the L1 adapter and UpgradeManager? Probably also much cheaper to precalculate the address, and simpler
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree!
src/contracts/L1OpUSDCFactory.sol
Outdated
* @param _portal The address of the portal contract for the respective L2 chain | ||
* @param _minGasLimit The minimum gas limit for the L2 deployment | ||
*/ | ||
function deployL2UsdcAndAdapter(address _portal, uint32 _minGasLimit) external { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets send the _messenger
and get the portal from there as we will need the messenger address for permissioned checks and logic later
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where will the _messenger
be needed? on L2?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we would set it on an init tx when deployed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each op-chain has a unique _l1Messenger, which has the portal accessible through a variable iirc, we will only be able to deploy for a given whitelisted _messenger
which will be a check we will add in a future PR, you only need the _messenger
to get the portal for now
See tasks here:
https://linear.app/defi-wonderland/issue/OPT-70/add-upgrademanager-permissioned-functions-to-the-factory
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome. Yes, the portal will be accessible through the messenger
* fix: tests and deploy scripts based on new changes * chore: update interface and natspec based on changes
* refactor: update mock and expect usage on l1 factory deploy function tests due to foundry error * chore: removed unnecessary imports on mainnet script
address _upgradeManagerImplementation = address(new UpgradeManager(L1_ADAPTER)); | ||
// Deploy and initialize the upgrade manager proxy | ||
bytes memory _initializeTx = abi.encodeWithSelector(IUpgradeManager.initialize.selector, _owner); | ||
UpgradeManager(address(new ERC1967Proxy(address(_upgradeManagerImplementation), _initializeTx))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think using ERC1967Proxy
will left an incorrect name in Etherscan or any explorer... maybe is a good idea to wrap the proxy with a better name like UpgradeManagerProxy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is a good idea to check this when we'll be verifying the contracts. If etherscan set the name to ERC1967Proxy
, then makes sense to cast it to UpgradeManager
. The same happens on L2 when deploying the l2 adapter
src/contracts/L2OpUSDCFactory.sol
Outdated
// Execute the USDC initialization transactions | ||
if (_usdcImplInitTxs.length > 0) { | ||
// Initialize usdc implementation | ||
for (uint256 i = 0; i < _usdcImplInitTxs.length; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (uint256 i = 0; i < _usdcImplInitTxs.length; i++) { | |
for (uint256 i; i < _usdcImplInitTxs.length; i++) { |
emit DeployedL2AdapterImplementation(_adapterImplementation); | ||
|
||
// Deploy L2 adapter proxy | ||
bytes memory _adapterInitTx = _l2AdapterInitTxs.length > 0 ? _l2AdapterInitTxs[0] : bytes(''); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its better if we always send bytes('')
this will also effect CREATE2
later, and we can call the initialization functions in the loop later
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Important to keep in mind we currently call _disableInitializors
in the constructor of the L2 Adapter as well, do we need this call? Doesnt need to be in this PR but I wanted to point it out
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah good point. I'd do everything related to the CREATE2
update on that PR, but will create a note about this. Also, I don't think we should hardcode any call on that contract but instead receiving it from the init txs array.
We should research which calls do we need to do in order to properly setup the proxy - @hexshire Do you have the answer here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ye I agree, we should probably remove this call and handle initialization functions in future implementations imo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
100% agreed
test/unit/L1OpUSDCFactory.t.sol
Outdated
*/ | ||
function test_callBridgedUSDCImplementation(address _l1Messenger, uint32 _minGasLimit) public { | ||
// Mock all the `deployL2UsdcAndAdapter` function calls | ||
_mockDeployFunctionCalls(_l1Messenger); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe tests are failing because we are fuzzing the _l1Messenger address and foundry cant fuzz that logic cause of its vm, we can set something like this in the base
// cant fuzz this because of foundry's VM
address internal _messenger = makeAddr('messenger');
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ty ser!
* chore: don't define i to zero on loop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm!
🤖 Linear
Closes OPT-67