Skip to content
This repository has been archived by the owner on Apr 12, 2021. It is now read-only.

Commit

Permalink
Standardized ETH and ERC20 Gateways (#222)
Browse files Browse the repository at this point in the history
* initial

* get .calls test working

* add assertions to withdrawal tests

* add missing finalizeDeposit tests

* clean up tests

* clean up crosschain library

* further clean up tests

* clean up L1 Gateway, fix bug

* further clean up contracts

* quick save

* quick save

* Add unsupported to fix compiler bug, need to remove this

* fix constructor inputs

* build fixes

* improve test case names

* l1 gateway testing WIP

* add comment on init

* Add withdraw tests

* temp only

* All tests implemented, 2 still failing, needs polish

* All tests implemented, 2 still failing, needs polish

* add failing test for finalizeWithdrawAndCall

* Add univ2erc20, broken build tho

* get contracts building

* clean up tests and interface

* updates

* move to uniswap ERC20

* more updates, fix gateway tests with uniswap

* finish deploy config?

* Add ETH deposit gateway (OVM_L1ETHGateway) (#225)

* OVM_L1ETHGateway almost working

* OVM_L1ETHGateway tests all passing

* clean up unused stuff

* lower gaslimit

* lower gas further

* typo

* break out helper

* resolve messenger

* update deploy config

* renaming

* lint

* update tests to use AM

* restructure fs layout

* clean unused envar

* remove interface version bound

* remove todo

* various minor cleanups

* add safemath to contract account

* update naming conventions

* fix test config and test name

* cleanup for consistency

* fix eth send test

* remove .only

* clean up, add deposit gas limit

* lint

* add gas config and tests

* fix indent

Co-authored-by: ben <[email protected]>
Co-authored-by: Maurelian <[email protected]>
Co-authored-by: Matt Masurka <[email protected]>
  • Loading branch information
4 people authored Feb 23, 2021
1 parent 5516771 commit 1b26510
Show file tree
Hide file tree
Showing 32 changed files with 1,612 additions and 156 deletions.
3 changes: 0 additions & 3 deletions bin/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,6 @@ const RELAYER_PRIVATE_KEY = env.RELAYER_PRIVATE_KEY;
owner: WHITELIST_OWNER,
allowArbitraryContractDeployment: WHITELIST_ALLOW_ARBITRARY_CONTRACT_DEPLOYMENT
},
ethConfig: {
initialAmount: 0,
},
deployOverrides: {
gasLimit: DEPLOY_TX_GAS_LIMIT
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount {

// Transfer fee to relayer.
address relayer = Lib_SafeExecutionManagerWrapper.safeCALLER();
uint256 fee = decodedTx.gasLimit * decodedTx.gasPrice;
uint256 fee = Lib_SafeMathWrapper.mul(decodedTx.gasLimit, decodedTx.gasPrice);
(bool success, ) = Lib_SafeExecutionManagerWrapper.safeCALL(
gasleft(),
ETH_ERC20_ADDRESS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;

/* Interface Imports */
import { iAbs_BaseCrossDomainMessenger } from "../../iOVM/bridge/iAbs_BaseCrossDomainMessenger.sol";
import { iAbs_BaseCrossDomainMessenger } from "../../../iOVM/bridge/messenging/iAbs_BaseCrossDomainMessenger.sol";

/* Library Imports */
import { Lib_ReentrancyGuard } from "../../libraries/utils/Lib_ReentrancyGuard.sol";
import { Lib_ReentrancyGuard } from "../../../libraries/utils/Lib_ReentrancyGuard.sol";

/**
* @title Abs_BaseCrossDomainMessenger
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;

/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_AddressManager } from "../../libraries/resolver/Lib_AddressManager.sol";
import { Lib_SecureMerkleTrie } from "../../libraries/trie/Lib_SecureMerkleTrie.sol";
import { Lib_ReentrancyGuard } from "../../libraries/utils/Lib_ReentrancyGuard.sol";
import { Lib_OVMCodec } from "../../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressResolver } from "../../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_AddressManager } from "../../../libraries/resolver/Lib_AddressManager.sol";
import { Lib_SecureMerkleTrie } from "../../../libraries/trie/Lib_SecureMerkleTrie.sol";
import { Lib_ReentrancyGuard } from "../../../libraries/utils/Lib_ReentrancyGuard.sol";

/* Interface Imports */
import { iOVM_L1CrossDomainMessenger } from "../../iOVM/bridge/iOVM_L1CrossDomainMessenger.sol";
import { iOVM_CanonicalTransactionChain } from "../../iOVM/chain/iOVM_CanonicalTransactionChain.sol";
import { iOVM_StateCommitmentChain } from "../../iOVM/chain/iOVM_StateCommitmentChain.sol";
import { iOVM_L1CrossDomainMessenger } from "../../../iOVM/bridge/messenging/iOVM_L1CrossDomainMessenger.sol";
import { iOVM_CanonicalTransactionChain } from "../../../iOVM/chain/iOVM_CanonicalTransactionChain.sol";
import { iOVM_StateCommitmentChain } from "../../../iOVM/chain/iOVM_StateCommitmentChain.sol";

/* Contract Imports */
import { Abs_BaseCrossDomainMessenger } from "./Abs_BaseCrossDomainMessenger.sol";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_L1CrossDomainMessenger } from "../../iOVM/bridge/iOVM_L1CrossDomainMessenger.sol";
import { iOVM_L1MultiMessageRelayer } from "../../iOVM/bridge/iOVM_L1MultiMessageRelayer.sol";
import { iOVM_L1CrossDomainMessenger } from "../../../iOVM/bridge/messenging/iOVM_L1CrossDomainMessenger.sol";
import { iOVM_L1MultiMessageRelayer } from "../../../iOVM/bridge/messenging/iOVM_L1MultiMessageRelayer.sol";

/* Contract Imports */
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_AddressResolver } from "../../../libraries/resolver/Lib_AddressResolver.sol";


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;

/* Library Imports */
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_ReentrancyGuard } from "../../libraries/utils/Lib_ReentrancyGuard.sol";
import { Lib_AddressResolver } from "../../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_ReentrancyGuard } from "../../../libraries/utils/Lib_ReentrancyGuard.sol";

/* Interface Imports */
import { iOVM_L2CrossDomainMessenger } from "../../iOVM/bridge/iOVM_L2CrossDomainMessenger.sol";
import { iOVM_L1MessageSender } from "../../iOVM/precompiles/iOVM_L1MessageSender.sol";
import { iOVM_L2ToL1MessagePasser } from "../../iOVM/precompiles/iOVM_L2ToL1MessagePasser.sol";
import { iOVM_L2CrossDomainMessenger } from "../../../iOVM/bridge/messenging/iOVM_L2CrossDomainMessenger.sol";
import { iOVM_L1MessageSender } from "../../../iOVM/precompiles/iOVM_L1MessageSender.sol";
import { iOVM_L2ToL1MessagePasser } from "../../../iOVM/precompiles/iOVM_L2ToL1MessagePasser.sol";

/* Contract Imports */
import { Abs_BaseCrossDomainMessenger } from "./Abs_BaseCrossDomainMessenger.sol";
Expand Down
146 changes: 146 additions & 0 deletions contracts/optimistic-ethereum/OVM/bridge/tokens/OVM_L1ERC20Gateway.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// SPDX-License-Identifier: MIT
// @unsupported: ovm
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;

/* Interface Imports */
import { iOVM_L1ERC20Gateway } from "../../../iOVM/bridge/tokens/iOVM_L1ERC20Gateway.sol";
import { iOVM_L2DepositedERC20 } from "../../../iOVM/bridge/tokens/iOVM_L2DepositedERC20.sol";
import { iOVM_ERC20 } from "../../../iOVM/precompiles/iOVM_ERC20.sol";

/* Library Imports */
import { OVM_CrossDomainEnabled } from "../../../libraries/bridge/OVM_CrossDomainEnabled.sol";

/**
* @title OVM_L1ERC20Gateway
* @dev The L1 ERC20 Gateway is a contract which stores deposited L1 funds that are in use on L2.
* It synchronizes a corresponding L2 ERC20 Gateway, informing it of deposits, and listening to it
* for newly finalized withdrawals.
*
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_L1ERC20Gateway is iOVM_L1ERC20Gateway, OVM_CrossDomainEnabled {

/********************************
* External Contract References *
********************************/

iOVM_ERC20 public l1ERC20;
address public l2ERC20Gateway;

/***************
* Constructor *
***************/

/**
* @param _l1ERC20 L1 ERC20 address this contract stores deposits for
* @param _l2ERC20Gateway L2 Gateway address on the chain being deposited into
* @param _l1messenger L1 Messenger address being used for cross-chain communications.
*/
constructor(
iOVM_ERC20 _l1ERC20,
address _l2ERC20Gateway,
address _l1messenger
)
OVM_CrossDomainEnabled(_l1messenger)
{
l1ERC20 = _l1ERC20;
l2ERC20Gateway = _l2ERC20Gateway;
}

/**************
* Depositing *
**************/

/**
* @dev deposit an amount of the ERC20 to the caller's balance on L2
* @param _amount Amount of the ERC20 to deposit
*/
function deposit(
uint _amount
)
external
override
{
_initiateDeposit(msg.sender, msg.sender, _amount);
}

/**
* @dev deposit an amount of ERC20 to a recipients's balance on L2
* @param _to L2 address to credit the withdrawal to
* @param _amount Amount of the ERC20 to deposit
*/
function depositTo(
address _to,
uint _amount
)
external
override
{
_initiateDeposit(msg.sender, _to, _amount);
}

/**
* @dev Performs the logic for deposits by storing the ERC20 and informing the L2 ERC20 Gateway of the deposit.
*
* @param _from Account to pull the deposit from on L1
* @param _to Account to give the deposit to on L2
* @param _amount Amount of the ERC20 to deposit.
*/
function _initiateDeposit(
address _from,
address _to,
uint _amount
)
internal
{
// Hold on to the newly deposited funds
l1ERC20.transferFrom(
_from,
address(this),
_amount
);

// Construct calldata for l2ERC20Gateway.finalizeDeposit(_to, _amount)
bytes memory data = abi.encodeWithSelector(
iOVM_L2DepositedERC20.finalizeDeposit.selector,
_to,
_amount
);

// Send calldata into L2
sendCrossDomainMessage(
l2ERC20Gateway,
data,
DEFAULT_FINALIZE_DEPOSIT_L2_GAS
);

emit DepositInitiated(_from, _to, _amount);
}

/*************************************
* Cross-chain Function: Withdrawing *
*************************************/

/**
* @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the
* L1 ERC20 token.
* This call will fail if the initialized withdrawal from L2 has not been finalized.
*
* @param _to L1 address to credit the withdrawal to
* @param _amount Amount of the ERC20 to withdraw
*/
function finalizeWithdrawal(
address _to,
uint _amount
)
external
override
onlyFromCrossDomainAccount(l2ERC20Gateway)
{
l1ERC20.transfer(_to, _amount);

emit WithdrawalFinalized(_to, _amount);
}
}
160 changes: 160 additions & 0 deletions contracts/optimistic-ethereum/OVM/bridge/tokens/OVM_L1ETHGateway.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// SPDX-License-Identifier: MIT
// @unsupported: ovm
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;

/* Interface Imports */
import { iOVM_L1ETHGateway } from "../../../iOVM/bridge/tokens/iOVM_L1ETHGateway.sol";
import { iOVM_L2DepositedERC20 } from "../../../iOVM/bridge/tokens/iOVM_L2DepositedERC20.sol";
import { iOVM_ERC20 } from "../../../iOVM/precompiles/iOVM_ERC20.sol";

/* Library Imports */
import { OVM_CrossDomainEnabled } from "../../../libraries/bridge/OVM_CrossDomainEnabled.sol";
import { Lib_AddressResolver } from "../../../libraries/resolver/Lib_AddressResolver.sol";

/**
* @title OVM_L1ETHGateway
* @dev The L1 ETH Gateway is a contract which stores deposited ETH that is in use on L2.
*
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_L1ETHGateway is iOVM_L1ETHGateway, OVM_CrossDomainEnabled, Lib_AddressResolver {
/********************************
* External Contract References *
********************************/

address public l2ERC20Gateway;

/***************
* Constructor *
***************/

/**
* @param _libAddressManager Address manager for this OE deployment
*/
constructor(
address _libAddressManager,
address _l2ERC20Gateway
)
OVM_CrossDomainEnabled(address(0)) // overridden in constructor code
Lib_AddressResolver(_libAddressManager)
{
l2ERC20Gateway = _l2ERC20Gateway;
messenger = resolve("Proxy__OVM_L1CrossDomainMessenger"); // overrides OVM_CrossDomainEnabled constructor setting because resolve() is not yet accessible
}

/**************
* Depositing *
**************/

/**
* @dev deposit an amount of the ERC20 to the caller's balance on L2
*/
function deposit()
external
override
payable
{
_initiateDeposit(msg.sender, msg.sender);
}

/**
* @dev deposit an amount of ERC20 to a recipients's balance on L2
* @param _to L2 address to credit the withdrawal to
*/
function depositTo(
address _to
)
external
override
payable
{
_initiateDeposit(msg.sender, _to);
}

/**
* @dev Performs the logic for deposits by storing the ERC20 and informing the L2 ERC20 Gateway of the deposit.
*
* @param _from Account to pull the deposit from on L1
* @param _to Account to give the deposit to on L2
*/
function _initiateDeposit(
address _from,
address _to
)
internal
{
// Construct calldata for l2ERC20Gateway.finalizeDeposit(_to, _amount)
bytes memory data =
abi.encodeWithSelector(
iOVM_L2DepositedERC20.finalizeDeposit.selector,
_to,
msg.value
);

// Send calldata into L2
sendCrossDomainMessage(
l2ERC20Gateway,
data,
DEFAULT_FINALIZE_DEPOSIT_L2_GAS
);

emit DepositInitiated(_from, _to, msg.value);
}

/*************************
* Cross-chain Functions *
*************************/

/**
* @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the
* L1 ERC20 token.
* This call will fail if the initialized withdrawal from L2 has not been finalized.
*
* @param _to L1 address to credit the withdrawal to
* @param _amount Amount of the ERC20 to withdraw
*/
function finalizeWithdrawal(
address _to,
uint256 _amount
)
external
override
onlyFromCrossDomainAccount(l2ERC20Gateway)
{
_safeTransferETH(_to, _amount);

emit WithdrawalFinalized(_to, _amount);
}

/**********************************
* Internal Functions: Accounting *
**********************************/

/**
* @dev Internal accounting function for moving around L1 ETH.
*
* @param _to L1 address to transfer ETH to
* @param _value Amount of ETH to send to
*/
function _safeTransferETH(
address _to,
uint256 _value
)
internal
{
(bool success, ) = _to.call{value: _value}(new bytes(0));
require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
}

/**
* @dev Prevent users from sending ETH directly to this contract without calling deposit
*/
receive()
external
payable
{
revert("Deposits must be initiated via deposit() or depositTo()");
}
}
Loading

0 comments on commit 1b26510

Please sign in to comment.