账户
0xf0...57eb
0xf0...57Eb

0xf0...57Eb

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.8.4+commit.c7e474f2
语言
Solidity
合同源代码
文件 1 的 1:TokenMigrator.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.4;

interface IERC20 {
    function totalSupply() external view returns (uint);
    function balanceOf(address account) external view returns (uint);
    function transfer(address recipient, uint amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint);
    function approve(address spender, uint amount) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);
}

contract Ownable {
    
    /// @notice The owner of the contract
    address public owner;
    
    /// @notice Event to notify when the ownership of this contract changed
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /// @notice Set the owner of this contract to its creator
    constructor () {
        owner = msg.sender;
        emit OwnershipTransferred(address(0), msg.sender);
    }
    
    modifier onlyOwner() {
        require(owner == msg.sender, "caller is not the owner");
        _;
    }

    /**
     * @notice Transfer ownership to `newOwner`
     * @param newOwner The address to transfer the ownership to
     */
    function transferOwnership(address newOwner) public onlyOwner {
        require(newOwner != address(0), "new owner is the zero address");
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }
}

contract TokenMigrator is Ownable {
    
    /// @notice Token to migrate from
    IERC20 public fromToken;
    
    /// @notice Token to migrate to
    IERC20 public toToken;
    
    /// @notice The address where fromToken should be burned
    address public constant BURN_ADDRESS = 0x0000000000000000000000000000000000000008;
    
    /// @notice Notice period before migration can be closed
    uint256 public constant endMigrationNoticePeriod = 2 weeks;

    /// @notice Flag that indicates whether migration is possible
    bool public migrationEnabled = false;
    
    /// @notice The migration end date
    uint256 public endMigrationDate = type(uint256).max;
    
    /// @notice Event to notify when the endMigrationDate is set
    event CloseMigrationNotice(uint256 epochTime);
    
    /**
     * @notice Construct a Migration contract
     * @param migrateFromToken The token to migrate from
     * @param migrateToToken The token to migrate into
     */
    constructor(address migrateFromToken, address migrateToToken) {
        fromToken = IERC20(migrateFromToken);
        toToken = IERC20(migrateToToken);
    }
    
    modifier whenMigrationEnabled() {
        require(migrationEnabled, "migration not enabled");
        _;
    }
    
    /**
     * @notice Start the migration. Can only be called if this contract has enough balance of toToken
     */
    function startMigration() public {
        uint256 requiredToTokenBalance = fromToken.totalSupply() - fromToken.balanceOf(BURN_ADDRESS);
        
        require(toToken.balanceOf(address(this)) >= requiredToTokenBalance, "not enough toToken balance");
        
        migrationEnabled = true;
    }
    
    /**
     * @notice Migrate `amount` of tokens
     * @param amount How many tokens to migrate
     */
    function migrate(uint256 amount) public whenMigrationEnabled returns (bool success) {
        require(fromToken.transferFrom(msg.sender, BURN_ADDRESS, amount), "burning fromToken failed");
        require(toToken.transfer(msg.sender, amount), "sending toToken failed");
        
        return true;
    }
    
    /**
     * @notice Announce the migration can be closed after `endMigrationNoticePeriod` 
     */
    function announceMigrationEnd() public onlyOwner whenMigrationEnabled {
        endMigrationDate = block.timestamp + endMigrationNoticePeriod;
        emit CloseMigrationNotice(endMigrationDate);
    }
    
    /**
     * @notice End the migration period. Can only be called after `endMigrationDate`
     *  This also transfers the remainingBalance of toToken back to the owner
     */
    function closeMigration() public onlyOwner whenMigrationEnabled {
        require(block.timestamp > endMigrationDate, "migration cannot be closed yet");
        migrationEnabled = false;
        uint256 remainingBalance = toToken.balanceOf(address(this));
        require(toToken.transfer(owner, remainingBalance), "recovering toToken failed");
    }
}
设置
{
  "compilationTarget": {
    "TokenMigrator.sol": "TokenMigrator"
  },
  "evmVersion": "istanbul",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[{"internalType":"address","name":"migrateFromToken","type":"address"},{"internalType":"address","name":"migrateToToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"epochTime","type":"uint256"}],"name":"CloseMigrationNotice","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"BURN_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"announceMigrationEnd","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"closeMigration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endMigrationDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endMigrationNoticePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fromToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"migrate","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"migrationEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startMigration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]