Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

/* Contract Imports */
import { L1StandardERC20 } from "../../standards/L1StandardERC20.sol";
import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol";

/**
* @title L1StandardTokenFactory
* @dev Factory contract for creating standard L1 token representations of L2 ERC20s
* compatible with and working on the standard bridge.
*/
contract L1StandardTokenFactory {
event StandardL1TokenCreated(address indexed _l2Token, address indexed _l1Token);

/**
* @dev Creates an instance of the standard ERC20 token on L1.
* @param _l2Token Address of the corresponding L2 token.
* @param _name ERC20 name.
* @param _symbol ERC20 symbol.
*/
function createStandardL1Token(
address _l2Token,
string memory _name,
string memory _symbol
) external {
require(_l2Token != address(0), "Must provide L2 token address");

L1StandardERC20 l1Token = new L1StandardERC20(
Lib_PredeployAddresses.L1_STANDARD_BRIDGE,
_l2Token,
_name,
_symbol
);

emit StandardL1TokenCreated(_l2Token, address(l1Token));
}
}
16 changes: 16 additions & 0 deletions packages/contracts/contracts/standards/IL1StandardERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

interface IL1StandardERC20 is IERC20, IERC165 {
function l2Token() external returns (address);

function mint(address _to, uint256 _amount) external;

function burn(address _from, uint256 _amount) external;

event Mint(address indexed _account, uint256 _amount);
event Burn(address indexed _account, uint256 _amount);
}
54 changes: 54 additions & 0 deletions packages/contracts/contracts/standards/L1StandardERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "./IL1StandardERC20.sol";

contract L1StandardERC20 is IL1StandardERC20, ERC20 {
address public l2Token;
address public l1Bridge;

/**
* @param _l2Bridge Address of the L2 standard bridge.
* @param _l1Token Address of the corresponding L1 token.
* @param _name ERC20 name.
* @param _symbol ERC20 symbol.
*/
constructor(
address _l1Bridge,
address _l2Token,
string memory _name,
string memory _symbol
) ERC20(_name, _symbol) {
l1Token = _l1Token;
l2Bridge = _l2Bridge;
}

modifier onlyL1Bridge() {
require(msg.sender == l1Bridge, "Only L1 Bridge can mint and burn");
_;
}

// slither-disable-next-line external-function
function supportsInterface(bytes4 _interfaceId) public pure returns (bool) {
bytes4 firstSupportedInterface = bytes4(keccak256("supportsInterface(bytes4)")); // ERC165
bytes4 secondSupportedInterface = IL1StandardERC20.l2Token.selector ^
IL1StandardERC20.mint.selector ^
IL1StandardERC20.burn.selector;
return _interfaceId == firstSupportedInterface || _interfaceId == secondSupportedInterface;
}

// slither-disable-next-line external-function
function mint(address _to, uint256 _amount) public virtual onlyL1Bridge {
_mint(_to, _amount);

emit Mint(_to, _amount);
}

// slither-disable-next-line external-function
function burn(address _from, uint256 _amount) public virtual onlyL1Bridge {
_burn(_from, _amount);

emit Burn(_from, _amount);
}
}