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
23 changes: 15 additions & 8 deletions packages/contracts-bedrock/src/L2/SuperchainERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ contract SuperchainERC20 is ISuperchainERC20, ERC20, ISemver {
/// @notice Decimals of the token
uint8 private immutable DECIMALS;

/// @notice Address of the corresponding version of this token on the L1.
address public immutable L1_TOKEN;
/// @notice Address of the corresponding version of this token on the remote chain.
address public immutable REMOTE_TOKEN;

/// @notice Emitted whenever tokens are minted for an account.
/// @param account Address of the account tokens are being minted for.
Expand Down Expand Up @@ -68,12 +68,19 @@ contract SuperchainERC20 is ISuperchainERC20, ERC20, ISemver {
/// @custom:semver 1.0.0
string public constant version = "1.0.0";

/// @param _l1Token Address of the corresponding L1 token.
/// @param _name ERC20 name.
/// @param _symbol ERC20 symbol.
/// @param _decimals ERC20 decimals.
constructor(address _l1Token, string memory _name, string memory _symbol, uint8 _decimals) ERC20(_name, _symbol) {
L1_TOKEN = _l1Token;
/// @param _remoteToken Address of the corresponding remote token.
/// @param _name ERC20 name.
/// @param _symbol ERC20 symbol.
/// @param _decimals ERC20 decimals.
constructor(
address _remoteToken,
string memory _name,
string memory _symbol,
uint8 _decimals
)
ERC20(_name, _symbol)
{
REMOTE_TOKEN = _remoteToken;
DECIMALS = _decimals;
}

Expand Down
60 changes: 60 additions & 0 deletions packages/contracts-bedrock/src/L2/SuperchainERC20Factory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import { ISemver } from "src/universal/ISemver.sol";
import { Predeploys } from "src/libraries/Predeploys.sol";
import { BeaconProxy } from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
import { CREATE3 } from "@rari-capital/solmate/src/utils/CREATE3.sol";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

the repo remapping is using '@rari-capital/solmate/=lib/solmate' , should we add another solmate lib?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

we can also use CREATE3 from @solady/=lib/solady/src

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

hmm leave it then, apparently this links to t11s repo somehow


/// @custom:proxied
/// @title SuperchainERC20Factory
/// @notice SuperchainERC20Factory is a factory contract that deploys SuperchainERC20 Beacon Proxies using CREATE3.
contract SuperchainERC20Factory is ISemver {
/// @notice Mapping of the deployed SuperchainERC20 to the remote token address.
mapping(address superchainToken => address remoteToken) public deployments;

/// @notice Emitted when a SuperchainERC20 is deployed.
/// @param superchainERC20 Address of the SuperchainERC20 deployment.
/// @param remoteToken Address of the remote token.
/// @param name Name of the SuperchainERC20.
/// @param symbol Symbol of the SuperchainERC20.
/// @param decimals Decimals of the SuperchainERC20.
event SuperchainERC20Deployed(
address indexed superchainERC20, address indexed remoteToken, string name, string symbol, uint8 decimals
);

/// @notice Semantic version.
/// @custom:semver 1.0.0
string public constant version = "1.0.0";

/// @notice Deploys a SuperchainERC20 Beacon Proxy using CREATE3.
/// @param _remoteToken Address of the remote token.
/// @param _name Name of the SuperchainERC20.
/// @param _symbol Symbol of the SuperchainERC20.
/// @param _decimals Decimals of the SuperchainERC20.
/// @return _superchainERC20 Address of the SuperchainERC20 deployment.
function deploy(
address _remoteToken,
string memory _name,
string memory _symbol,
uint8 _decimals
)
external
returns (address _superchainERC20)
{
// Encode the BeaconProxy creation code with the beacon contract address and metadata
bytes memory _creationCode = abi.encodePacked(
type(BeaconProxy).creationCode,
abi.encode(Predeploys.SUPERCHAIN_ERC20_BEACON, abi.encode(_remoteToken, _name, _symbol, _decimals))
);

// Use CREATE3 for deterministic deployment
bytes32 _salt = keccak256(abi.encode(_remoteToken, _name, _symbol, _decimals));
_superchainERC20 = CREATE3.deploy({ salt: _salt, creationCode: _creationCode, value: 0 });

// Store SuperchainERC20 and remote token addresses
deployments[_superchainERC20] = _remoteToken;

emit SuperchainERC20Deployed(_superchainERC20, _remoteToken, _name, _symbol, _decimals);
}
}
8 changes: 7 additions & 1 deletion packages/contracts-bedrock/src/libraries/Predeploys.sol
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ library Predeploys {
/// @notice Address of the L2ToL2CrossDomainMessenger predeploy.
address internal constant L2_TO_L2_CROSS_DOMAIN_MESSENGER = 0x4200000000000000000000000000000000000023;

/// TODO: Replace with real predeploy address
/// @notice Address of the SuperchainERC20Beacon predeploy.
address internal constant SUPERCHAIN_ERC20_BEACON = 0x4200000000000000000000000000000000000024;

/// @notice Returns the name of the predeploy at the given address.
function getName(address _addr) internal pure returns (string memory out_) {
require(isPredeployNamespace(_addr), "Predeploys: address must be a predeploy");
Expand All @@ -115,6 +119,7 @@ library Predeploys {
if (_addr == LEGACY_ERC20_ETH) return "LegacyERC20ETH";
if (_addr == CROSS_L2_INBOX) return "CrossL2Inbox";
if (_addr == L2_TO_L2_CROSS_DOMAIN_MESSENGER) return "L2ToL2CrossDomainMessenger";
if (_addr == SUPERCHAIN_ERC20_BEACON) return "SuperchainERC20Beacon";
revert("Predeploys: unnamed predeploy");
}

Expand All @@ -131,7 +136,8 @@ library Predeploys {
|| _addr == L2_ERC721_BRIDGE || _addr == L1_BLOCK_ATTRIBUTES || _addr == L2_TO_L1_MESSAGE_PASSER
|| _addr == OPTIMISM_MINTABLE_ERC721_FACTORY || _addr == PROXY_ADMIN || _addr == BASE_FEE_VAULT
|| _addr == L1_FEE_VAULT || _addr == SCHEMA_REGISTRY || _addr == EAS || _addr == GOVERNANCE_TOKEN
|| (_useInterop && _addr == CROSS_L2_INBOX) || (_useInterop && _addr == L2_TO_L2_CROSS_DOMAIN_MESSENGER);
|| (_useInterop && _addr == CROSS_L2_INBOX) || (_useInterop && _addr == L2_TO_L2_CROSS_DOMAIN_MESSENGER)
|| (_useInterop && _addr == SUPERCHAIN_ERC20_BEACON);
}

function isPredeployNamespace(address _addr) internal pure returns (bool) {
Expand Down
16 changes: 8 additions & 8 deletions packages/contracts-bedrock/test/L2/SuperchainERC20.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { ISuperchainERC20 } from "src/L2/ISuperchainERC20.sol";
/// @dev Contract for testing the SuperchainERC20 contract.
contract SuperchainERC20Test is Test {
address internal constant ZERO_ADDRESS = address(0);
address internal constant L1_TOKEN = address(0x123);
address internal constant REMOTE_TOKEN = address(0x123);
string internal constant NAME = "SuperchainERC20";
string internal constant SYMBOL = "SCE";
uint8 internal constant DECIMALS = 18;
Expand All @@ -37,7 +37,7 @@ contract SuperchainERC20Test is Test {

/// @dev Sets up the test suite.
function setUp() public {
superchainERC20 = new SuperchainERC20(L1_TOKEN, NAME, SYMBOL, DECIMALS);
superchainERC20 = new SuperchainERC20(REMOTE_TOKEN, NAME, SYMBOL, DECIMALS);
}

/// @dev Helper function to setup a mock and expect a call to it.
Expand All @@ -51,7 +51,7 @@ contract SuperchainERC20Test is Test {
assertEq(superchainERC20.name(), NAME);
assertEq(superchainERC20.symbol(), SYMBOL);
assertEq(superchainERC20.decimals(), DECIMALS);
assertEq(superchainERC20.L1_TOKEN(), L1_TOKEN);
assertEq(superchainERC20.REMOTE_TOKEN(), REMOTE_TOKEN);
}

/// @dev Tests the `mint` function reverts when the caller is not the bridge.
Expand Down Expand Up @@ -286,13 +286,13 @@ contract SuperchainERC20Test is Test {

/// @dev Tests the `decimals` function always returns the correct value.
function testFuzz_decimals_succeeds(uint8 _decimals) public {
SuperchainERC20 _newSuperchainERC20 = new SuperchainERC20(L1_TOKEN, NAME, SYMBOL, _decimals);
SuperchainERC20 _newSuperchainERC20 = new SuperchainERC20(REMOTE_TOKEN, NAME, SYMBOL, _decimals);
assertEq(_newSuperchainERC20.decimals(), _decimals);
}

/// @dev Tests the `L1_TOKEN` function always returns the correct value.
function testFuzz_l1Token_succeeds(address _l1Token) public {
SuperchainERC20 _newSuperchainERC20 = new SuperchainERC20(_l1Token, NAME, SYMBOL, DECIMALS);
assertEq(_newSuperchainERC20.L1_TOKEN(), _l1Token);
/// @dev Tests the `REMOTE_TOKEN` function always returns the correct value.
function testFuzz_remoteToken_succeeds(address _remoteToken) public {
SuperchainERC20 _newSuperchainERC20 = new SuperchainERC20(_remoteToken, NAME, SYMBOL, DECIMALS);
assertEq(_newSuperchainERC20.REMOTE_TOKEN(), _remoteToken);
}
}