This repository has been archived by the owner on Apr 12, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 118
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create Unibridge for bridging any token to Optimism
- Loading branch information
Showing
17 changed files
with
2,223 additions
and
2 deletions.
There are no files selected for viewing
202 changes: 202 additions & 0 deletions
202
contracts/optimistic-ethereum/OVM/bridge/unibridge/OVM_L1TokenBridge.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
// SPDX-License-Identifier: MIT | ||
// @unsupported: ovm | ||
pragma solidity >0.5.0 <0.8.0; | ||
pragma experimental ABIEncoderV2; | ||
|
||
/* Interface Imports */ | ||
import { iOVM_L1TokenBridge } from "../../../iOVM/bridge/unibridge/iOVM_L1TokenBridge.sol"; | ||
import { iOVM_L2TokenBridge } from "../../../iOVM/bridge/unibridge/iOVM_L2TokenBridge.sol"; | ||
import { iOVM_ERC20 } from "../../../iOVM/precompiles/iOVM_ERC20.sol"; | ||
|
||
/* Library Imports */ | ||
import { OVM_CrossDomainEnabled } from "../../../libraries/bridge/OVM_CrossDomainEnabled.sol"; | ||
import { UniSafeERC20Namer } from "../../../libraries/standards/UniSafeERC20Namer.sol"; | ||
|
||
/** | ||
* @title OVM_L1TokenBridge | ||
* @dev The L1 Token Bridge is a contract which stores deposited L1 funds that are in use on L2. | ||
* It synchronizes a corresponding L2 ERC20 Bridge, informing it of deposits, and listening to it | ||
* for newly finalized withdrawals. | ||
* | ||
* Compiler used: solc | ||
* Runtime target: EVM | ||
*/ | ||
contract OVM_L1TokenBridge is iOVM_L1TokenBridge, OVM_CrossDomainEnabled { | ||
/******************************** | ||
* External Contract References * | ||
********************************/ | ||
|
||
address public immutable l2Bridge; | ||
bytes32 public immutable l2ERC20BytecodeHash; | ||
bytes32 public immutable l2ERC777BytecodeHash; | ||
|
||
/*************** | ||
* Constructor * | ||
***************/ | ||
|
||
/** | ||
* @param _l2Bridge L2 bridge contract address | ||
* @param _l1messenger L1 Messenger address being used for cross-chain communications. | ||
* @param _l2ERC20BytecodeHash Hash of the L2 ERC20 contract bytecode, used to calculate token addresses | ||
* @param _l2ERC777BytecodeHash Hash of the L2 ERC777 contract bytecode, used to calculate token addresses | ||
*/ | ||
constructor( | ||
address _l2Bridge, | ||
address _l1messenger, | ||
bytes32 _l2ERC20BytecodeHash, | ||
bytes32 _l2ERC777BytecodeHash | ||
) | ||
OVM_CrossDomainEnabled(_l1messenger) | ||
{ | ||
l2Bridge = _l2Bridge; | ||
l2ERC20BytecodeHash = _l2ERC20BytecodeHash; | ||
l2ERC777BytecodeHash = _l2ERC777BytecodeHash; | ||
} | ||
|
||
/********************** | ||
* L2 Token Addresses * | ||
**********************/ | ||
|
||
/** | ||
* Calculates the addres of a bridged ERC777 on L2 | ||
* @param _l1Token The ERC20 token on L1 | ||
* @return calculatedAddress The address of the bridged ERC777 on L2 | ||
*/ | ||
function calculateL2ERC777Address(address _l1Token) public view returns (address calculatedAddress) { | ||
calculatedAddress = address(uint(keccak256(abi.encodePacked( | ||
byte(0xff), | ||
l2Bridge, | ||
bytes32(uint(_l1Token)), | ||
l2ERC777BytecodeHash | ||
)))); | ||
} | ||
|
||
/** | ||
* Calculates the addres of a bridged ERC20 on L2 | ||
* @param _l1Token The ERC20 token on L1 | ||
* @return calculatedAddress The address of the bridged ERC20 on L2 | ||
*/ | ||
function calculateL2ERC20Address(address _l1Token) public view returns (address calculatedAddress) { | ||
calculatedAddress = address(uint(keccak256(abi.encodePacked( | ||
byte(0xff), | ||
l2Bridge, | ||
bytes32(uint(_l1Token)), | ||
l2ERC20BytecodeHash | ||
)))); | ||
} | ||
|
||
/************** | ||
* Depositing * | ||
**************/ | ||
|
||
/** | ||
* @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 depositAsERC20( | ||
address token, | ||
address _to, | ||
uint _amount | ||
) | ||
external | ||
override | ||
{ | ||
_initiateDeposit(iOVM_L2TokenBridge.depositAsERC20.selector, token, msg.sender, _to, _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 depositAsERC777( | ||
address _token, | ||
address _to, | ||
uint _amount | ||
) | ||
external | ||
override | ||
{ | ||
require(iOVM_ERC20(_token).decimals() <= 18, "Only "); | ||
_initiateDeposit(iOVM_L2TokenBridge.depositAsERC777.selector, _token, msg.sender, _to, _amount); | ||
} | ||
|
||
/** | ||
* @dev Performs the logic for deposits by storing the ERC20 and informing the L2 Deposited ERC20 contract 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( | ||
bytes4 _selector, | ||
address _token, | ||
address _from, | ||
address _to, | ||
uint _amount | ||
) | ||
internal | ||
{ | ||
// Hold on to the newly deposited funds | ||
iOVM_ERC20(_token).transferFrom( | ||
_from, | ||
address(this), | ||
_amount | ||
); | ||
|
||
uint8 _decimals = iOVM_ERC20(_token).decimals(); | ||
|
||
// Construct calldata for l2Bridge.finalizeDeposit(_to, _amount) | ||
bytes memory data = abi.encodeWithSelector(_selector, _token, _to, _amount, _decimals); | ||
|
||
// Send calldata into L2 | ||
sendCrossDomainMessage( | ||
l2Bridge, | ||
data, | ||
DEFAULT_FINALIZE_DEPOSIT_L2_GAS | ||
); | ||
|
||
emit DepositInitiated(_token, _from, _to, _amount); | ||
} | ||
|
||
/** | ||
* @dev L2 tokens have no name or symbol by default. This function passes that data to L2. | ||
* @param _l1Token Address of the L1 token | ||
*/ | ||
function updateTokenInfo(address _l1Token) external { | ||
bytes memory data = abi.encodeWithSelector( | ||
iOVM_L2TokenBridge.updateTokenInfo.selector, | ||
_l1Token, | ||
UniSafeERC20Namer.tokenName(_l1Token), | ||
UniSafeERC20Namer.tokenSymbol(_l1Token) | ||
); | ||
sendCrossDomainMessage(l2Bridge, data, DEFAULT_FINALIZE_DEPOSIT_L2_GAS); | ||
} | ||
|
||
/************************************* | ||
* 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 _token, | ||
address _to, | ||
uint _amount | ||
) | ||
external | ||
override | ||
onlyFromCrossDomainAccount(l2Bridge) | ||
{ | ||
iOVM_ERC20(_token).transfer(_to, _amount); | ||
|
||
emit WithdrawalFinalized(_token, _to, _amount); | ||
} | ||
} |
106 changes: 106 additions & 0 deletions
106
contracts/optimistic-ethereum/OVM/bridge/unibridge/OVM_L2ERC20.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >0.5.0 <0.8.0; | ||
pragma experimental ABIEncoderV2; | ||
|
||
/* Interface Imports */ | ||
import { iOVM_L2TokenBridge } from "../../../iOVM/bridge/unibridge/iOVM_L2TokenBridge.sol"; | ||
|
||
/* Contract Imports */ | ||
import { UniswapV2ERC20 } from "../../../libraries/standards/UniswapV2ERC20.sol"; | ||
|
||
/** | ||
* @title OVM_L2ERC20 | ||
* @dev The L2 Deposited ERC20 is an ERC20 implementation which represents L1 assets deposited into L2. | ||
* This contract mints new tokens when the token bridge receives deposit messages. | ||
* This contract also burns the tokens intended for withdrawal and calls the bridge contract. | ||
* The name & symbol will be empty by default, and can be set by calling updateTokenInfo on the L1 bridge. | ||
* | ||
* Compiler used: optimistic-solc | ||
* Runtime target: OVM | ||
*/ | ||
contract OVM_L2ERC20 is UniswapV2ERC20 { | ||
/******************************** | ||
* External Contract References * | ||
********************************/ | ||
|
||
address public immutable bridge; | ||
address public l1Address; | ||
|
||
/******************************** | ||
* Constructor & Initialization * | ||
********************************/ | ||
|
||
constructor() public UniswapV2ERC20(0, "", "") { | ||
bridge = msg.sender; | ||
} | ||
|
||
/** | ||
* @dev Initialize the contract immediately after construction, passing in the | ||
* L1 token address and the number of decimals. | ||
* | ||
* @param _l1Address Address of the corresponding token on L1 | ||
* @param _decimals Number of decimal places of the token | ||
*/ | ||
function initialize(address _l1Address, uint8 _decimals) external onlyBridge { | ||
l1Address = _l1Address; | ||
decimals = _decimals; | ||
} | ||
|
||
/********************** | ||
* Function Modifiers * | ||
**********************/ | ||
|
||
modifier onlyBridge { | ||
require(msg.sender == bridge, "May only be called by the bridge"); | ||
_; | ||
} | ||
|
||
/****************** | ||
* User Functions * | ||
******************/ | ||
|
||
/** | ||
* @dev Initiate a withdraw of some ERC20 to a recipient's account on L1 | ||
* @param _destination L1 adress to credit the withdrawal to | ||
* @param _amount Amount of the ERC20 to withdraw | ||
*/ | ||
function withdraw(address _destination, uint256 _amount) external { | ||
_burn(msg.sender, _amount); | ||
iOVM_L2TokenBridge(bridge).withdraw(l1Address, _destination, _amount); | ||
} | ||
|
||
/** | ||
* @dev Migrate tokens from ERC20 to ERC777 | ||
* @param _amount Amount of the ERC20 to migrate | ||
* @param _target The address of the ERC777 token | ||
*/ | ||
function migrate(uint256 _amount, address _target) external { | ||
_burn(msg.sender, _amount); | ||
iOVM_L2TokenBridge(bridge).migrate(l1Address, _target, msg.sender, _amount); | ||
} | ||
|
||
/******************** | ||
* Bridge functions * | ||
********************/ | ||
|
||
/** | ||
* @dev Receives the name & symbol of the token from the bridge. | ||
* | ||
* @param _newName The token's name | ||
* @param _newSymbol The token's symbol | ||
*/ | ||
function updateInfo(string memory _newName, string memory _newSymbol) external onlyBridge { | ||
name = _newName; | ||
symbol = _newSymbol; | ||
} | ||
|
||
/** | ||
* @dev Mints new tokens to a user. | ||
* | ||
* @param _recipient The address to receive the tokens. | ||
* @param _amount The amount of tokens to mint. | ||
*/ | ||
function mint(address _recipient, uint256 _amount) external onlyBridge { | ||
_mint(_recipient, _amount); | ||
} | ||
} |
Oops, something went wrong.