-
Notifications
You must be signed in to change notification settings - Fork 1
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
uses arb test mint token as example for updated contracts #4
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,38 +9,93 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; | |
import {IInbox} from "interfaces/IInbox.sol"; | ||
import {IOutbox} from "interfaces/IOutbox.sol"; | ||
import {IBridge} from "interfaces/IBridge.sol"; | ||
import {IL1CustomGateway} from "interfaces/IL1CustomGateway.sol"; | ||
import {L1MintableToken, ICustomToken} from "interfaces/ICustomToken.sol"; | ||
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol"; | ||
import {TransferAndCallToken} from "./TransferAndCallToken.sol"; | ||
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; | ||
|
||
contract Dev is ERC20Upgradeable, ReentrancyGuardUpgradeable { | ||
// https://github.com/OffchainLabs/arbitrum/blob/master/packages/arb-bridge-peripherals/contracts/tokenbridge/libraries/aeERC20.sol#L21 | ||
// removes _setupDecimals since it is no longer used in OZ 0.4 | ||
|
||
contract aeERC20 is ERC20PermitUpgradeable, TransferAndCallToken, ReentrancyGuardUpgradeable { | ||
using AddressUpgradeable for address; | ||
|
||
function _initialize( | ||
string memory name_, | ||
string memory symbol_ | ||
) internal initializer { | ||
__ERC20Permit_init(name_); | ||
__ERC20_init(name_, symbol_); | ||
} | ||
} | ||
|
||
contract ArbDEVTokenL1 is aeERC20, ICustomToken { | ||
using SafeERC20 for IERC20; | ||
|
||
address public l2Token; | ||
address public gateway; | ||
address public inbox; | ||
address public bridge; | ||
bool private shouldRegisterGateway; | ||
address public devAddress; | ||
address public gateway; | ||
|
||
event EscrowMint(address indexed minter, uint256 amount); | ||
// uint8 public constant TEST = uint8(0xa4b1); | ||
|
||
function initialize(address _l2TokenAddr, address _gatewayAddr, address _inbox, address _devAddress) public initializer { | ||
__ERC20_init("Dev", "DEV"); | ||
l2Token = _l2TokenAddr; | ||
gateway = _gatewayAddr; | ||
inbox = _inbox; | ||
constructor(address _bridge, address _devAddress, address _gateway) public { | ||
bridge = _bridge; | ||
aeERC20._initialize("Dev", "DEV"); | ||
devAddress = _devAddress; | ||
gateway = _gateway; | ||
} | ||
|
||
function mint() external { | ||
_mint(msg.sender, 50000000); | ||
} | ||
Comment on lines
+50
to
+52
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. I don't think this function is needed. Maybe for testing or something? 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. If such an interface is required, we can upgrade this implementation contract later. Therefore, we can remove functions that we think are unnecessary. |
||
|
||
function transferFrom( | ||
address sender, | ||
address recipient, | ||
uint256 amount | ||
) public virtual override(ERC20Upgradeable, ICustomToken) returns (bool) { | ||
return ERC20Upgradeable.transferFrom(sender, recipient, amount); | ||
} | ||
|
||
function balanceOf(address account) | ||
public | ||
view | ||
virtual | ||
override(ERC20Upgradeable, ICustomToken) | ||
returns (uint256) | ||
{ | ||
return ERC20Upgradeable.balanceOf(account); | ||
} | ||
|
||
function escrowMint(uint256 amount) external { | ||
address msgSender = _l2Sender(); | ||
require(msgSender == l2Token, "sender must be l2 token"); | ||
_mint(gateway, amount); | ||
emit EscrowMint(msgSender, amount); | ||
/// @dev we only set shouldRegisterGateway to true when in `registerTokenOnL2` | ||
function isArbitrumEnabled() external view override returns (uint16) { | ||
require(shouldRegisterGateway, "NOT_EXPECTED_CALL"); | ||
// uint8 public constant TEST = uint8(0xa4b1); | ||
return uint16(0xa4b1); | ||
// return TEST; | ||
} | ||
|
||
function _l2Sender() private view returns (address) { | ||
IBridge _bridge = IInbox(inbox).bridge(); | ||
require(address(_bridge) != address(0), "bridge is zero address"); | ||
IOutbox outbox = IOutbox(_bridge.activeOutbox()); | ||
require(address(outbox) != address(0), "outbox is zero address"); | ||
return outbox.l2ToL1Sender(); | ||
|
||
function registerTokenOnL2( | ||
address l2CustomTokenAddress, | ||
uint256 maxSubmissionCost, | ||
uint256 maxGas, | ||
uint256 gasPriceBid | ||
// address creditBackAddress | ||
) public { | ||
// we temporarily set `shouldRegisterGateway` to true for the callback in registerTokenToL2 to succeed | ||
bool prev = shouldRegisterGateway; | ||
shouldRegisterGateway = true; | ||
|
||
IL1CustomGateway(bridge).registerTokenToL2( | ||
l2CustomTokenAddress, | ||
maxGas, | ||
gasPriceBid, | ||
maxSubmissionCost | ||
); | ||
|
||
shouldRegisterGateway = prev; | ||
} | ||
|
||
/** | ||
|
@@ -73,4 +128,30 @@ contract Dev is ERC20Upgradeable, ReentrancyGuardUpgradeable { | |
IERC20(devAddress).transfer(msg.sender, _amount); | ||
return true; | ||
} | ||
} | ||
} | ||
|
||
contract MintableArbDEVL1 is L1MintableToken, ArbDEVTokenL1 { | ||
|
||
constructor(address _bridge, address _devAddress, address _gatewayAddress) public ArbDEVTokenL1(_bridge, _devAddress, _gatewayAddress) {} | ||
|
||
function bridgeMint(address account, uint256 amount) public override(L1MintableToken) { | ||
_mint(account, amount); | ||
} | ||
|
||
function balanceOf(address account) | ||
public | ||
view | ||
override(ArbDEVTokenL1, ICustomToken) | ||
returns (uint256 amount) | ||
{ | ||
return super.balanceOf(account); | ||
} | ||
|
||
function transferFrom( | ||
address sender, | ||
address recipient, | ||
uint256 amount | ||
) public override(ArbDEVTokenL1, ICustomToken) returns (bool) { | ||
return super.transferFrom(sender, recipient, amount); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// SPDX-License-Identifier: MPL-2.0 | ||
pragma solidity ^0.8.9; | ||
|
||
// https://github.com/OffchainLabs/arbitrum/blob/master/packages/arb-bridge-peripherals/contracts/tokenbridge/libraries/TransferAndCallToken.sol | ||
|
||
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; | ||
import "../interfaces/ITransferAndCall.sol"; | ||
|
||
// Implementation from https://github.com/smartcontractkit/LinkToken/blob/master/contracts/v0.6/TransferAndCallToken.sol | ||
/** | ||
* @notice based on Implementation from https://github.com/smartcontractkit/LinkToken/blob/master/contracts/v0.6/ERC677Token.sol | ||
* The implementation doesn't return a bool on onTokenTransfer. This is similar to the proposed 677 standard, but still incompatible - thus we don't refer to it as such. | ||
*/ | ||
abstract contract TransferAndCallToken is ERC20Upgradeable, ITransferAndCall { | ||
/** | ||
* @dev transfer token to a contract address with additional data if the recipient is a contact. | ||
* @param _to The address to transfer to. | ||
* @param _value The amount to be transferred. | ||
* @param _data The extra data to be passed to the receiving contract. | ||
*/ | ||
function transferAndCall( | ||
address _to, | ||
uint256 _value, | ||
bytes memory _data | ||
) public virtual override returns (bool success) { | ||
super.transfer(_to, _value); | ||
emit Transfer(msg.sender, _to, _value, _data); | ||
if (isContract(_to)) { | ||
contractFallback(_to, _value, _data); | ||
} | ||
return true; | ||
} | ||
|
||
// PRIVATE | ||
|
||
function contractFallback( | ||
address _to, | ||
uint256 _value, | ||
bytes memory _data | ||
) private { | ||
ITransferAndCallReceiver receiver = ITransferAndCallReceiver(_to); | ||
receiver.onTokenTransfer(msg.sender, _value, _data); | ||
} | ||
|
||
function isContract(address _addr) private view returns (bool hasCode) { | ||
uint256 length; | ||
assembly { | ||
length := extcodesize(_addr) | ||
} | ||
return length > 0; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// SPDX-License-Identifier: MPL-2.0 | ||
pragma solidity ^0.8.0; | ||
|
||
// taken from https://github.com/OffchainLabs/arbitrum/blob/001bdeecdefbc4eda9a824ef7b39452b46faeb86/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/ICustomToken.sol | ||
|
||
interface ArbitrumEnabledToken { | ||
/// @notice should return `0xa4b1` if token is enabled for arbitrum gateways | ||
function isArbitrumEnabled() external view returns (uint16); | ||
} | ||
|
||
/** | ||
* @title Minimum expected interface for L1 custom token (see TestCustomTokenL1.sol for an example implementation) | ||
*/ | ||
interface ICustomToken is ArbitrumEnabledToken { | ||
/** | ||
* @notice Should make an external call to EthERC20Bridge.registerCustomL2Token | ||
*/ | ||
function registerTokenOnL2( | ||
address l2CustomTokenAddress, | ||
uint256 maxSubmissionCost, | ||
uint256 maxGas, | ||
uint256 gasPriceBid, | ||
address creditBackAddress | ||
) external; | ||
|
||
function transferFrom( | ||
address sender, | ||
address recipient, | ||
uint256 amount | ||
) external returns (bool); | ||
|
||
function balanceOf(address account) external view returns (uint256); | ||
} | ||
|
||
interface L1MintableToken is ICustomToken { | ||
function bridgeMint(address account, uint256 amount) external; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// SPDX-License-Identifier: MPL-2.0 | ||
pragma solidity ^0.8.0; | ||
|
||
/* | ||
* @title Minimum expected interface for L1 custom gateway used https://github.com/OffchainLabs/arbitrum/blob/001bdeecdefbc4eda9a824ef7b39452b46faeb86/packages/arb-bridge-peripherals/contracts/tokenbridge/ethereum/gateway/L1CustomGateway.sol#L100 | ||
*/ | ||
interface IL1CustomGateway { | ||
function registerTokenToL2(address _l2Address, | ||
uint256 _maxGas, | ||
uint256 _gasPriceBid, | ||
uint256 _maxSubmissionCost | ||
) external payable returns (uint256); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// SPDX-License-Identifier: MPL-2.0 | ||
pragma solidity ^0.8.9; | ||
|
||
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; | ||
|
||
interface ITransferAndCall is IERC20Upgradeable { | ||
function transferAndCall( | ||
address to, | ||
uint256 value, | ||
bytes memory data | ||
) external returns (bool success); | ||
|
||
event Transfer(address indexed from, address indexed to, uint256 value, bytes data); | ||
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. The name is duplicated in the Transfer event of IERC20Upgradeable, is that OK? 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. If the interface is declared duplicate, I think you need to remove one or the other. |
||
} | ||
|
||
/** | ||
* @notice note that implementation of ITransferAndCallReceiver is not expected to return a success bool | ||
*/ | ||
interface ITransferAndCallReceiver { | ||
function onTokenTransfer( | ||
address _sender, | ||
uint256 _value, | ||
bytes memory _data | ||
) 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.
Do you need not to create this contract in upgradable?
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 this contract should be upgradeable. Because Arbitrum is still unstable, and the requirements may change.