Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ library OrbitSalts {
bytes internal constant L1_STANDARD_GATEWAY = bytes("L1SGW");
bytes internal constant L1_CUSTOM_GATEWAY = bytes("L1CGW");
bytes internal constant L1_WETH_GATEWAY = bytes("L1WGW");
bytes internal constant MASTER_VAULT_FACTORY = bytes("MVF");

bytes internal constant L2_PROXY_ADMIN = bytes("L2PA");
bytes internal constant L2_ROUTER = bytes("L2R");
Expand Down
99 changes: 21 additions & 78 deletions contracts/tokenbridge/ethereum/L1AtomicTokenBridgeCreator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,6 @@ contract L1AtomicTokenBridgeCreator is Initializable, OwnableUpgradeable {
MasterVaultFactory masterVaultFactory;
}

struct YieldBearingGatewayConfig {
bool enableYieldBearing;
address underlyingToken;
}

// use separate mapping to allow appending to the struct in the future
// and workaround some stack too deep issues
mapping(address => L1DeploymentAddresses) public inboxToL1Deployment;
Expand Down Expand Up @@ -197,33 +192,13 @@ contract L1AtomicTokenBridgeCreator is Initializable, OwnableUpgradeable {
* Warning: Due to asynchronous communication between parent and child chain, always check child chain contracts are
* fully deployed and initialized before sending tokens to the bridge. Otherwise tokens might be permanently lost.
*/
function createTokenBridge(
address inbox,
address rollupOwner,
uint256 maxGasForContracts,
uint256 gasPriceBid
) external payable {
YieldBearingGatewayConfig memory emptyConfig;
_createTokenBridge(inbox, rollupOwner, maxGasForContracts, gasPriceBid, emptyConfig);
}

function createTokenBridge(
address inbox,
address rollupOwner,
uint256 maxGasForContracts,
uint256 gasPriceBid,
YieldBearingGatewayConfig memory yieldBearingConfig
bool isYieldBearingBridge
) external payable {
_createTokenBridge(inbox, rollupOwner, maxGasForContracts, gasPriceBid, yieldBearingConfig);
}

function _createTokenBridge(
address inbox,
address rollupOwner,
uint256 maxGasForContracts,
uint256 gasPriceBid,
YieldBearingGatewayConfig memory yieldBearingConfig
) internal {
// templates have to be in place
if (address(l1Templates.routerTemplate) == address(0)) {
revert L1AtomicTokenBridgeCreator_TemplatesNotSet();
Expand Down Expand Up @@ -284,6 +259,15 @@ contract L1AtomicTokenBridgeCreator is Initializable, OwnableUpgradeable {

// if resend, we assume L1 contracts already exist
if (!isResend) {
if (isYieldBearingBridge) {
// deploy master vault factory
l1Deployment.masterVaultFactory = _deployProxyWithSalt(
_getL1Salt(OrbitSalts.MASTER_VAULT_FACTORY, inbox),
address(l1Templates.masterVaultFactory),
proxyAdmin
);
}

// l1 router deployment block
{
address routerTemplate = feeToken != address(0)
Expand All @@ -306,33 +290,14 @@ contract L1AtomicTokenBridgeCreator is Initializable, OwnableUpgradeable {
)
);

if (
yieldBearingConfig.enableYieldBearing &&
yieldBearingConfig.underlyingToken != address(0)
) {
L1ArbitrumGateway.YieldBearingConfig memory config = L1ArbitrumGateway
.YieldBearingConfig({
token: yieldBearingConfig.underlyingToken,
masterVaultFactory: address(l1Templates.masterVaultFactory),
isYieldBearingGateway: true
});
standardGateway.initialize(
l2Deployment.standardGateway,
l1Deployment.router,
inbox,
keccak256(type(ClonableBeaconProxy).creationCode),
l2Deployment.beaconProxyFactory,
config
);
} else {
standardGateway.initialize(
l2Deployment.standardGateway,
l1Deployment.router,
inbox,
keccak256(type(ClonableBeaconProxy).creationCode),
l2Deployment.beaconProxyFactory
);
}
standardGateway.initialize(
l2Deployment.standardGateway,
l1Deployment.router,
inbox,
keccak256(type(ClonableBeaconProxy).creationCode),
l2Deployment.beaconProxyFactory,
l1Deployment.masterVaultFactory
);

l1Deployment.standardGateway = address(standardGateway);
}
Expand All @@ -349,31 +314,9 @@ contract L1AtomicTokenBridgeCreator is Initializable, OwnableUpgradeable {
)
);

if (
yieldBearingConfig.enableYieldBearing &&
yieldBearingConfig.underlyingToken != address(0)
) {
L1ArbitrumGateway.YieldBearingConfig memory config = L1ArbitrumGateway
.YieldBearingConfig({
token: yieldBearingConfig.underlyingToken,
masterVaultFactory: address(l1Templates.masterVaultFactory),
isYieldBearingGateway: true
});
customGateway.initialize(
l2Deployment.customGateway,
l1Deployment.router,
inbox,
upgradeExecutor,
config
);
} else {
customGateway.initialize(
l2Deployment.customGateway,
l1Deployment.router,
inbox,
upgradeExecutor
);
}
customGateway.initialize(
l2Deployment.customGateway, l1Deployment.router, inbox, upgradeExecutor, l1Deployment.masterVaultFactory
);

l1Deployment.customGateway = address(customGateway);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ struct L1DeploymentAddresses {
address customGateway;
address wethGateway;
address weth;
address masterVaultFactory;
}

struct L2DeploymentAddresses {
Expand Down
49 changes: 14 additions & 35 deletions contracts/tokenbridge/ethereum/gateway/L1ArbitrumGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,8 @@ abstract contract L1ArbitrumGateway is
error BadVaultFactory();
error BadVaultCodeHash();

// considering moving this struct to different common file
struct YieldBearingConfig {
address token;
address masterVaultFactory;
bool isYieldBearingGateway; // could be redundant
}

address public override inbox;
address public masterVault;
address public masterVaultFactory;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the reason to have masterVaultFactory here instead of masterVault? isn't every L1*Gateway deals with only one master vault?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the gateways handle multiple tokens, so they'll need to deal with multiple vaults


event DepositInitiated(
address l1Token,
Expand Down Expand Up @@ -94,36 +87,18 @@ abstract contract L1ArbitrumGateway is
// this has no other logic since the current upgrade doesn't require this logic
}


function _initialize(
address _l2Counterpart,
address _router,
address _inbox
address _inbox,
address _masterVaultFactory
) internal {
TokenGateway._initialize(_l2Counterpart, _router);
// L1 gateway must have a router
require(_router != address(0), "BAD_ROUTER");
require(_inbox != address(0), "BAD_INBOX");
inbox = _inbox;
}

function _initialize(
address _l2Counterpart,
address _router,
address _inbox,
YieldBearingConfig memory _yieldBearingConfig
) internal {
_initialize(_l2Counterpart, _router, _inbox);
_initializeYieldBearing(_yieldBearingConfig);
}

function _initializeYieldBearing(YieldBearingConfig memory _config) internal {
if (_config.isYieldBearingGateway) {
if (_config.masterVaultFactory == address(0)) revert BadVaultFactory();
if (_config.token == address(0)) revert BadVaultCodeHash();

masterVault = MasterVaultFactory(_config.masterVaultFactory).deployVault(_config.token);
}
masterVaultFactory = _masterVaultFactory;
}

/**
Expand Down Expand Up @@ -175,9 +150,10 @@ abstract contract L1ArbitrumGateway is
uint256 _amount
) internal virtual {
// this method is virtual since different subclasses can handle escrow differently
if (masterVault != address(0)) {
// todo: approve shares to master vault
IMasterVault(masterVault).withdraw(_amount, _dest);
address _masterVaultFactory = masterVaultFactory;
if (_masterVaultFactory != address(0)) {
// todo: do we want to unwrap here or just transfer vault shares?
address masterVault = MasterVaultFactory(masterVaultFactory).getVault(_l1Token);
} else {
IERC20(_l1Token).safeTransfer(_dest, _amount);
}
Expand Down Expand Up @@ -341,9 +317,12 @@ abstract contract L1ArbitrumGateway is
uint256 postBalance = IERC20(_l1Token).balanceOf(address(this));
amountReceived = postBalance - prevBalance;

if (masterVault != address(0)) {
address subVault = IMasterVault(masterVault).getSubVault();
IERC20(_l1Token).safeApprove(subVault, amountReceived);
address _masterVaultFactory = masterVaultFactory;
if (_masterVaultFactory != address(0)) {
address masterVault = MasterVaultFactory(masterVaultFactory).getVault(_l1Token);
// todo: decide whether we want the master vault to act like its own vault, or whether it is just a pointer to the real vault
// this affects which address gets approved
// somewhat related to deciding whether we want to auto unwrap on withdrawals
amountReceived = IMasterVault(masterVault).deposit(amountReceived);
}
}
Expand Down
19 changes: 2 additions & 17 deletions contracts/tokenbridge/ethereum/gateway/L1CustomGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -92,29 +92,14 @@ contract L1CustomGateway is L1ArbitrumExtendedGateway, ICustomGateway {
super.finalizeInboundTransfer(_token, _from, _to, _amount, _data);
}

// todo: have only one initialize function
function initialize(
address _l1Counterpart,
address _l1Router,
address _inbox,
address _owner
) public {
L1ArbitrumGateway._initialize(_l1Counterpart, _l1Router, _inbox);
owner = _owner;
// disable whitelist by default
whitelist = address(0);
// reentrancy guard
_status = _NOT_ENTERED;
}

function initialize(
address _l1Counterpart,
address _l1Router,
address _inbox,
address _owner,
YieldBearingConfig memory _yieldBearingConfig
address _masterVaultFactory // todo: document that this switches the contracts behavior between YBB mode and normal mode
) public {
L1ArbitrumGateway._initialize(_l1Counterpart, _l1Router, _inbox, _yieldBearingConfig);
L1ArbitrumGateway._initialize(_l1Counterpart, _l1Router, _inbox, _masterVaultFactory);
owner = _owner;
// disable whitelist by default
whitelist = address(0);
Expand Down
24 changes: 3 additions & 21 deletions contracts/tokenbridge/ethereum/gateway/L1ERC20Gateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -86,34 +86,16 @@ contract L1ERC20Gateway is L1ArbitrumExtendedGateway {
super.finalizeInboundTransfer(_token, _from, _to, _amount, _data);
}

// todo: have only one initialize function
function initialize(
address _l2Counterpart,
address _router,
address _inbox,
bytes32 _cloneableProxyHash,
address _l2BeaconProxyFactory
) public {
L1ArbitrumGateway._initialize(_l2Counterpart, _router, _inbox);
require(_cloneableProxyHash != bytes32(0), "INVALID_PROXYHASH");
require(_l2BeaconProxyFactory != address(0), "INVALID_BEACON");
cloneableProxyHash = _cloneableProxyHash;
l2BeaconProxyFactory = _l2BeaconProxyFactory;
// disable whitelist by default
whitelist = address(0);
// reentrancy guard
_status = _NOT_ENTERED;
}

// todo: update initializers for orbit versions of gateways as well
function initialize(
address _l2Counterpart,
address _router,
address _inbox,
bytes32 _cloneableProxyHash,
address _l2BeaconProxyFactory,
YieldBearingConfig memory _yieldBearingConfig
address _masterVaultFactory
) public {
L1ArbitrumGateway._initialize(_l2Counterpart, _router, _inbox, _yieldBearingConfig);
L1ArbitrumGateway._initialize(_l2Counterpart, _router, _inbox, _masterVaultFactory);
require(_cloneableProxyHash != bytes32(0), "INVALID_PROXYHASH");
require(_l2BeaconProxyFactory != address(0), "INVALID_BEACON");
cloneableProxyHash = _cloneableProxyHash;
Expand Down
4 changes: 3 additions & 1 deletion contracts/tokenbridge/ethereum/gateway/L1USDCGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ contract L1USDCGateway is L1ArbitrumExtendedGateway {
if (_owner == address(0)) {
revert L1USDCGateway_InvalidOwner();
}
L1ArbitrumGateway._initialize(_l2Counterpart, _l1Router, _inbox);
// address(0) master vault factory indicates no YBB functionality
// todo: ensure this is what we want here
L1ArbitrumGateway._initialize(_l2Counterpart, _l1Router, _inbox, address(0));
l1USDC = _l1USDC;
l2USDC = _l2USDC;
owner = _owner;
Expand Down
4 changes: 3 additions & 1 deletion contracts/tokenbridge/ethereum/gateway/L1WethGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ contract L1WethGateway is L1ArbitrumExtendedGateway {
address _l1Weth,
address _l2Weth
) public {
L1ArbitrumGateway._initialize(_l2Counterpart, _l1Router, _inbox);
// address(0) master vault factory disables YBB functionality
// YBB is not relevant to this gateway since the asset is escrowed as ETH in the main Bridge contract
L1ArbitrumGateway._initialize(_l2Counterpart, _l1Router, _inbox, address(0));
require(_l1Weth != address(0), "INVALID_L1WETH");
require(_l2Weth != address(0), "INVALID_L2WETH");
l1Weth = _l1Weth;
Expand Down
1 change: 1 addition & 0 deletions contracts/tokenbridge/libraries/vault/IMasterVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity ^0.8.0;

interface IMasterVault {
// todo: add bytes param for slippage etc
function deposit(uint256 amount) external returns (uint256);

function withdraw(uint256 amount, address recipient) external;
Expand Down
1 change: 1 addition & 0 deletions contracts/tokenbridge/libraries/vault/MasterVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ contract MasterVault is IMasterVault, Ownable {
}

function setSubVault(address _subVault) external override onlyOwner {
// todo: need to make sure we transfer funds here
subVault = _subVault;
emit SubVaultSet(_subVault);
}
Expand Down
Loading
Loading