-
Notifications
You must be signed in to change notification settings - Fork 165
feat: yield bearing bridge #177
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
base: main
Are you sure you want to change the base?
Changes from 13 commits
11e3993
4be3547
8bb6035
fb019c4
e2edd95
2fe0126
10a8d51
244c278
2952945
3f643a0
3cef66b
3fc04d3
e114255
5597e1f
b26c54c
ce02657
4aadcf0
520a371
1f3e22c
6bf9f42
2b0c724
de28387
6e0107d
0f8d4d3
3f49a2a
cc6c1b5
9654a8f
89a4dfa
fc59687
990ef5b
dd546bc
d074bf8
6ab1b86
77312db
b9ec81c
dde5aa9
4da7e91
e820d2f
3dc37d0
ae3147d
c94b7ed
b8ac8f3
1cad122
7044927
b4ae0ab
08c5321
778f1f4
e2e3dc5
ec1a72b
a3149d3
4eb1bf5
4a98dfb
51641a2
74626ed
fab56c8
455e979
0910434
e02ec94
e274e7c
0e61d92
3801a2d
990f01a
b7f0905
2a03d02
864d982
d5dae5b
50cfcdb
0cd8883
5f21f5a
15d44f0
21fd31b
abe121b
45197cc
a1ba0e6
b459155
da59267
ad6630a
60f4c0f
2a1b7bf
8f87592
0410682
44f4973
15a8474
f2e4b34
9986968
1a0eddd
618f4de
7d5e5cd
36a2a65
e96d3dc
04fc167
8f0def3
d29598b
052c65d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,202 @@ | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| pragma solidity ^0.8.4; | ||
|
|
||
| import {L1ERC20Gateway} from "./gateway/L1ERC20Gateway.sol"; | ||
| import {L1CustomGateway} from "./gateway/L1CustomGateway.sol"; | ||
| import {L1WethGateway} from "./gateway/L1WethGateway.sol"; | ||
| import {L1OrbitERC20Gateway} from "./gateway/L1OrbitERC20Gateway.sol"; | ||
| import {L1OrbitCustomGateway} from "./gateway/L1OrbitCustomGateway.sol"; | ||
| import {L1YbbERC20Gateway} from "./gateway/L1YbbERC20Gateway.sol"; | ||
| import {L1YbbCustomGateway} from "./gateway/L1YbbCustomGateway.sol"; | ||
| import {IMasterVaultFactory} from "../libraries/vault/IMasterVaultFactory.sol"; | ||
| import {IGatewayRouter} from "../libraries/gateway/IGatewayRouter.sol"; | ||
| import {ClonableBeaconProxy} from "../libraries/ClonableBeaconProxy.sol"; | ||
| import { | ||
| TransparentUpgradeableProxy | ||
| } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; | ||
|
|
||
| /** | ||
| * @title L1GatewayDeployer | ||
| * @notice Library for deploying all L1 gateway components (standard, custom, WETH, and YBB) | ||
| */ | ||
| library L1GatewayDeployer { | ||
| // ============ Standard Gateway Structs ============ | ||
|
|
||
| struct StandardDeploymentParams { | ||
| address inbox; | ||
| address proxyAdmin; | ||
| address upgradeExecutor; | ||
| address router; | ||
| address l2StandardGateway; | ||
| address l2CustomGateway; | ||
| address l2BeaconProxyFactory; | ||
| bool isFeeTokenBased; | ||
| } | ||
|
|
||
| struct StandardTemplates { | ||
| address standardGatewayTemplate; | ||
| address feeTokenBasedStandardGatewayTemplate; | ||
| address customGatewayTemplate; | ||
| address feeTokenBasedCustomGatewayTemplate; | ||
| } | ||
|
|
||
| struct StandardDeploymentResult { | ||
| address standardGateway; | ||
| address customGateway; | ||
| } | ||
|
|
||
| // ============ WETH Gateway Structs ============ | ||
|
|
||
| struct WethDeploymentParams { | ||
| address inbox; | ||
| address proxyAdmin; | ||
| address router; | ||
| address l2WethGateway; | ||
| address l1Weth; | ||
| address l2Weth; | ||
| } | ||
|
|
||
| struct WethDeploymentResult { | ||
| address wethGateway; | ||
| } | ||
|
|
||
| // ============ YBB Gateway Structs ============ | ||
|
|
||
| struct YbbDeploymentParams { | ||
| address inbox; | ||
| address proxyAdmin; | ||
| address upgradeExecutor; | ||
| address router; | ||
| address l2StandardGateway; | ||
| address l2CustomGateway; | ||
| address l2BeaconProxyFactory; | ||
| } | ||
|
|
||
| struct YbbTemplates { | ||
| address ybbStandardGatewayTemplate; | ||
| address ybbCustomGatewayTemplate; | ||
| address masterVaultFactoryTemplate; | ||
| } | ||
|
|
||
| struct YbbDeploymentResult { | ||
| address masterVaultFactory; | ||
| address standardGateway; | ||
| address customGateway; | ||
| } | ||
|
|
||
| // ============ Standard Gateway Deployment ============ | ||
|
|
||
| function deployStandardGateways( | ||
| StandardDeploymentParams memory params, | ||
| StandardTemplates memory templates, | ||
| bytes32 standardGatewaySalt, | ||
| bytes32 customGatewaySalt | ||
| ) external returns (StandardDeploymentResult memory result) { | ||
| { | ||
| address template = params.isFeeTokenBased | ||
| ? templates.feeTokenBasedStandardGatewayTemplate | ||
| : templates.standardGatewayTemplate; | ||
|
|
||
| result.standardGateway = _deployProxy(standardGatewaySalt, template, params.proxyAdmin); | ||
|
|
||
| L1ERC20Gateway(result.standardGateway) | ||
| .initialize( | ||
| params.l2StandardGateway, | ||
| params.router, | ||
| params.inbox, | ||
| keccak256(type(ClonableBeaconProxy).creationCode), | ||
| params.l2BeaconProxyFactory | ||
| ); | ||
| } | ||
|
|
||
| { | ||
| address template = params.isFeeTokenBased | ||
| ? templates.feeTokenBasedCustomGatewayTemplate | ||
| : templates.customGatewayTemplate; | ||
|
|
||
| result.customGateway = _deployProxy(customGatewaySalt, template, params.proxyAdmin); | ||
|
|
||
| L1CustomGateway(result.customGateway) | ||
| .initialize( | ||
| params.l2CustomGateway, params.router, params.inbox, params.upgradeExecutor | ||
| ); | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| // ============ WETH Gateway Deployment ============ | ||
|
|
||
| function deployWethGateway( | ||
| WethDeploymentParams memory params, | ||
| address wethGatewayTemplate, | ||
| bytes32 wethGatewaySalt | ||
| ) external returns (WethDeploymentResult memory result) { | ||
| result.wethGateway = _deployProxy(wethGatewaySalt, wethGatewayTemplate, params.proxyAdmin); | ||
|
|
||
| L1WethGateway(payable(result.wethGateway)) | ||
| .initialize( | ||
| params.l2WethGateway, params.router, params.inbox, params.l1Weth, params.l2Weth | ||
| ); | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| // ============ YBB Gateway Deployment ============ | ||
|
|
||
| function deployYbbGateways( | ||
| YbbDeploymentParams memory params, | ||
| YbbTemplates memory templates, | ||
| bytes32 masterVaultSalt, | ||
| bytes32 standardGatewaySalt, | ||
| bytes32 customGatewaySalt | ||
| ) external returns (YbbDeploymentResult memory result) { | ||
| result.masterVaultFactory = _deployProxy( | ||
| masterVaultSalt, templates.masterVaultFactoryTemplate, params.proxyAdmin | ||
| ); | ||
|
|
||
| result.standardGateway = _deployProxy( | ||
| standardGatewaySalt, templates.ybbStandardGatewayTemplate, params.proxyAdmin | ||
| ); | ||
|
|
||
| L1YbbERC20Gateway(result.standardGateway) | ||
| .initialize( | ||
| params.l2StandardGateway, | ||
| params.router, | ||
| params.inbox, | ||
| keccak256(type(ClonableBeaconProxy).creationCode), | ||
| params.l2BeaconProxyFactory, | ||
| result.masterVaultFactory | ||
| ); | ||
|
|
||
| result.customGateway = | ||
| _deployProxy(customGatewaySalt, templates.ybbCustomGatewayTemplate, params.proxyAdmin); | ||
|
|
||
| L1YbbCustomGateway(result.customGateway) | ||
| .initialize( | ||
| params.l2CustomGateway, | ||
| params.router, | ||
| params.inbox, | ||
| params.upgradeExecutor, | ||
| result.masterVaultFactory | ||
| ); | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| function initializeMasterVaultFactory( | ||
| address masterVaultFactory, | ||
| address rolesRegistry, | ||
| address beaconProxyFactory, | ||
| address router | ||
| ) external { | ||
| IMasterVaultFactory(masterVaultFactory) | ||
| .initialize(rolesRegistry, beaconProxyFactory, IGatewayRouter(router)); | ||
| } | ||
|
|
||
| // ============ Internal ============ | ||
|
|
||
| function _deployProxy(bytes32 salt, address logic, address admin) internal returns (address) { | ||
| return address(new TransparentUpgradeableProxy{salt: salt}(logic, admin, bytes(""))); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| pragma solidity ^0.8.0; | ||
|
|
||
| import {L1CustomGateway} from "./L1CustomGateway.sol"; | ||
| import {IMasterVault} from "../../libraries/vault/IMasterVault.sol"; | ||
| import {IMasterVaultFactory} from "../../libraries/vault/IMasterVaultFactory.sol"; | ||
| import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
| import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; | ||
|
|
||
| /** | ||
| * @title Layer 1 Gateway contract for bridging Custom ERC20s with YBB enabled | ||
| * @notice Escrows funds into MasterVaults for yield bearing bridging. | ||
| */ | ||
| contract L1YbbCustomGateway is L1CustomGateway { | ||
| using SafeERC20 for IERC20; | ||
|
|
||
| /// @notice Address of the MasterVaultFactory contract | ||
| address public masterVaultFactory; | ||
|
|
||
| function initialize( | ||
| address _l1Counterpart, | ||
| address _l1Router, | ||
| address _inbox, | ||
| address _owner, | ||
| address _masterVaultFactory | ||
| ) public virtual { | ||
| L1CustomGateway.initialize(_l1Counterpart, _l1Router, _inbox, _owner); | ||
| _setMasterVaultFactory(_masterVaultFactory); | ||
| } | ||
|
|
||
| function inboundEscrowTransfer(address _l1Token, address _dest, uint256 _amount) | ||
| internal | ||
| override | ||
| { | ||
| address masterVault = IMasterVaultFactory(masterVaultFactory).getVault(_l1Token); | ||
| IERC20(masterVault).safeTransfer(_dest, _amount); | ||
| } | ||
|
|
||
| function outboundEscrowTransfer(address _l1Token, address _from, uint256 _amount) | ||
| internal | ||
| override | ||
| returns (uint256 amountReceived) | ||
| { | ||
| uint256 prevBalance = IERC20(_l1Token).balanceOf(address(this)); | ||
| IERC20(_l1Token).safeTransferFrom(_from, address(this), _amount); | ||
| uint256 postBalance = IERC20(_l1Token).balanceOf(address(this)); | ||
| amountReceived = postBalance - prevBalance; | ||
|
|
||
| address masterVault = IMasterVaultFactory(masterVaultFactory).getVault(_l1Token); | ||
| IERC20(_l1Token).safeApprove(masterVault, amountReceived); | ||
| amountReceived = IMasterVault(masterVault).deposit(amountReceived); | ||
| } | ||
|
|
||
| function _setMasterVaultFactory(address _masterVaultFactory) internal { | ||
| require(_masterVaultFactory != address(0), "BAD_MASTER_VAULT_FACTORY"); | ||
| masterVaultFactory = _masterVaultFactory; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| pragma solidity ^0.8.0; | ||
|
|
||
| import {L1ERC20Gateway} from "./L1ERC20Gateway.sol"; | ||
| import {IMasterVault} from "../../libraries/vault/IMasterVault.sol"; | ||
| import {IMasterVaultFactory} from "../../libraries/vault/IMasterVaultFactory.sol"; | ||
| import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
| import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; | ||
|
|
||
| /** | ||
| * @title Layer 1 Gateway contract for bridging standard ERC20s with YBB enabled | ||
| * @notice Escrows funds into MasterVaults for yield bearing bridging. | ||
| */ | ||
| contract L1YbbERC20Gateway is L1ERC20Gateway { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. L2 token created with underlying token decimals, but MV share have +6 decimals and L2 token represent MV share instead of underlying so we need to adjust somewhere
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| using SafeERC20 for IERC20; | ||
|
|
||
| /// @notice Address of the MasterVaultFactory contract | ||
| address public masterVaultFactory; | ||
|
|
||
| function initialize( | ||
| address _l2Counterpart, | ||
| address _router, | ||
| address _inbox, | ||
| bytes32 _cloneableProxyHash, | ||
| address _l2BeaconProxyFactory, | ||
| address _masterVaultFactory | ||
| ) public { | ||
| L1ERC20Gateway.initialize( | ||
| _l2Counterpart, _router, _inbox, _cloneableProxyHash, _l2BeaconProxyFactory | ||
| ); | ||
| _setMasterVaultFactory(_masterVaultFactory); | ||
| } | ||
|
|
||
| function inboundEscrowTransfer(address _l1Token, address _dest, uint256 _amount) | ||
| internal | ||
| override | ||
| { | ||
| address masterVault = IMasterVaultFactory(masterVaultFactory).getVault(_l1Token); | ||
| IERC20(masterVault).safeTransfer(_dest, _amount); | ||
| } | ||
|
|
||
| function outboundEscrowTransfer(address _l1Token, address _from, uint256 _amount) | ||
| internal | ||
| override | ||
| returns (uint256 amountReceived) | ||
| { | ||
| uint256 prevBalance = IERC20(_l1Token).balanceOf(address(this)); | ||
| IERC20(_l1Token).safeTransferFrom(_from, address(this), _amount); | ||
| uint256 postBalance = IERC20(_l1Token).balanceOf(address(this)); | ||
| amountReceived = postBalance - prevBalance; | ||
|
|
||
| address masterVault = IMasterVaultFactory(masterVaultFactory).getVault(_l1Token); | ||
| IERC20(_l1Token).safeApprove(masterVault, amountReceived); | ||
| amountReceived = IMasterVault(masterVault).deposit(amountReceived); | ||
| } | ||
|
|
||
| function _setMasterVaultFactory(address _masterVaultFactory) internal { | ||
| require(_masterVaultFactory != address(0), "BAD_MASTER_VAULT_FACTORY"); | ||
| masterVaultFactory = _masterVaultFactory; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| pragma solidity ^0.8.0; | ||
|
|
||
| import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; | ||
|
|
||
| interface IMasterVault { | ||
| function setSubVault(IERC4626 subVault) external; | ||
| function deposit(uint256 assets) external returns (uint256 shares); | ||
| function redeem(uint256 shares, uint256 minAssets) external returns (uint256 assets); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| pragma solidity ^0.8.0; | ||
|
|
||
| import "../gateway/IGatewayRouter.sol"; | ||
|
|
||
| interface IMasterVaultFactory { | ||
| event VaultDeployed(address indexed token, address indexed vault); | ||
|
|
||
| function initialize( | ||
| address _rolesRegistry, | ||
| address _beaconProxyFactory, | ||
| IGatewayRouter _gatewayRouter | ||
| ) external; | ||
| function deployVault(address token) external returns (address vault); | ||
| function calculateVaultAddress(address token) external view returns (address); | ||
| function getVault(address token) external returns (address); | ||
| } |
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.
Lack fee token (Orbit) variant, same for the L1YbbERC20Gateway