115 lines
4.2 KiB
Solidity
115 lines
4.2 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
// Compatible with OpenZeppelin Contracts ^5.0.0
|
|
pragma solidity ^0.8.28;
|
|
|
|
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
|
import {ERC20FlashMint} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.sol";
|
|
import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
|
|
import {ERC20Votes} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
|
|
import {Nonces} from "@openzeppelin/contracts/utils/Nonces.sol";
|
|
import {ERC20Capped} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol";
|
|
|
|
import { IERC7802, IERC165 } from "./interfaces/IERC7802.sol";
|
|
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
|
|
import { Predeploys } from "./libraries/SuperChainPredeploys.sol";
|
|
import { TransitionMintLib } from "./libraries/TransitionMintLib.sol";
|
|
|
|
/// @notice Error for an unauthorized CALLER.
|
|
error Unauthorized();
|
|
|
|
/// @notice Error for an invalid signature.
|
|
error InvalidSignature();
|
|
|
|
/// @notice Error for an already minted address.
|
|
error AlreadyMinted();
|
|
|
|
/// @notice Error for an invalid chain.
|
|
error InvalidChain();
|
|
|
|
/// @notice Error for an invalid initial supply.
|
|
error InvalidInitialSupply();
|
|
|
|
/// @custom:security-contact moon.eth
|
|
contract TenGransToken is ERC20, ERC20Permit, ERC20Votes, ERC20FlashMint, ERC20Capped, IERC7802 {
|
|
address public signer;
|
|
mapping(address => bool) public transitionMinted;
|
|
uint256 public immutable nativeChainId;
|
|
|
|
event TransitionMint(address indexed holder, uint256 amount);
|
|
|
|
constructor(
|
|
string memory name,
|
|
string memory symbol,
|
|
uint256 initialSupplyWei,
|
|
uint256 capWei,
|
|
address _signer,
|
|
uint256 _nativeChainId
|
|
) ERC20(name, symbol) ERC20Permit(name) ERC20Capped(capWei) {
|
|
require(initialSupplyWei <= capWei, InvalidInitialSupply());
|
|
_mint(msg.sender, initialSupplyWei);
|
|
signer = _signer;
|
|
nativeChainId = _nativeChainId;
|
|
}
|
|
|
|
/// @notice Allows the SuperchainTokenBridge to mint tokens.
|
|
/// @param _to Address to mint tokens to.
|
|
/// @param _amount Amount of tokens to mint.
|
|
function crosschainMint(address _to, uint256 _amount) external {
|
|
if (msg.sender != Predeploys.SUPERCHAIN_TOKEN_BRIDGE) revert Unauthorized();
|
|
|
|
_mint(_to, _amount);
|
|
|
|
emit CrosschainMint(_to, _amount, msg.sender);
|
|
}
|
|
|
|
/// @notice Allows the SuperchainTokenBridge to burn tokens.
|
|
/// @param _from Address to burn tokens from.
|
|
/// @param _amount Amount of tokens to burn.
|
|
function crosschainBurn(address _from, uint256 _amount) external {
|
|
if (msg.sender != Predeploys.SUPERCHAIN_TOKEN_BRIDGE) revert Unauthorized();
|
|
|
|
_burn(_from, _amount);
|
|
|
|
emit CrosschainBurn(_from, _amount, msg.sender);
|
|
}
|
|
|
|
/// @inheritdoc IERC165
|
|
function supportsInterface(bytes4 _interfaceId) public view virtual returns (bool) {
|
|
return _interfaceId == type(IERC7802).interfaceId || _interfaceId == type(IERC20).interfaceId
|
|
|| _interfaceId == type(IERC165).interfaceId;
|
|
}
|
|
|
|
/// @notice Allows a wallet to mint tokens using a signature, based on the snapshot quantity.
|
|
/// @param holder Address to mint tokens to.
|
|
/// @param snapshotQuantity Amount of tokens to mint.
|
|
/// @param signature Signature of the holder.
|
|
function transitionMint(address holder, uint256 snapshotQuantity, bytes memory signature) external {
|
|
require(block.chainid == nativeChainId, InvalidChain());
|
|
require(!transitionMinted[holder], AlreadyMinted());
|
|
require(TransitionMintLib.verifyMintSignature(holder, snapshotQuantity, signature, signer), InvalidSignature());
|
|
|
|
transitionMinted[holder] = true;
|
|
_mint(holder, snapshotQuantity);
|
|
emit TransitionMint(holder, snapshotQuantity);
|
|
}
|
|
|
|
// The following functions are overrides required by Solidity.
|
|
|
|
function _update(address from, address to, uint256 value)
|
|
internal
|
|
override(ERC20, ERC20Votes, ERC20Capped)
|
|
{
|
|
super._update(from, to, value);
|
|
}
|
|
|
|
function nonces(address owner)
|
|
public
|
|
view
|
|
override(ERC20Permit, Nonces)
|
|
returns (uint256)
|
|
{
|
|
return super.nonces(owner);
|
|
}
|
|
}
|