github.com/codingfuture/orig-energi3@v0.8.4/energi/contracts/src/Gen2Migration.sol (about)

     1  // Copyright 2019 The Energi Core Authors
     2  // This file is part of Energi Core.
     3  //
     4  // Energi Core is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // Energi Core is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with Energi Core. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Energi Governance system is the fundamental part of Energi Core.
    18  
    19  // NOTE: It's not allowed to change the compiler due to byte-to-byte
    20  //       match requirement.
    21  pragma solidity 0.5.16;
    22  //pragma experimental SMTChecker;
    23  
    24  import { GlobalConstants } from "./constants.sol";
    25  import { IDelegatedPoS } from "./IDelegatedPoS.sol";
    26  import { IGovernedProxy } from "./IGovernedProxy.sol";
    27  import { IBlacklistRegistry } from "./IBlacklistRegistry.sol";
    28  
    29  /**
    30   * Genesis hardcoded version of Gen 2 Migration
    31   *
    32   * NOTE: it MUST NOT change after blockchain launch!
    33   */
    34  contract Gen2Migration is
    35  	GlobalConstants,
    36  	IDelegatedPoS
    37  {
    38      struct UnspentCoins {
    39          bytes20 owner; // Gen 2 P2PKH
    40          uint amount;
    41      }
    42  
    43      event Migrated(
    44          uint item_id,
    45          address destination,
    46          uint amount
    47      );
    48  
    49      IGovernedProxy public blacklist_proxy;
    50      uint public chain_id;
    51      address public signerAddress; // IDelegatedPoS
    52      uint public totalAmount;
    53      UnspentCoins[] public coins;
    54      mapping(bytes20 => bool) hard_blacklist;
    55  
    56      // NOTE: this c-tor is used during testing
    57      constructor(IGovernedProxy _blacklist_proxy, uint _chain_id, address _signer) public {
    58          blacklist_proxy = _blacklist_proxy;
    59          chain_id = _chain_id;
    60          signerAddress = _signer;
    61      }
    62  
    63      function setSnapshot(
    64          bytes20[] calldata _owners,
    65          uint[] calldata _amounts,
    66          bytes20[] calldata _blacklist
    67      ) external {
    68          require(coins.length == 0, "Already set");
    69          require(msg.sender == signerAddress, "Invalid sender");
    70          require(_owners.length == _amounts.length, "match length");
    71          require(_owners.length > 0, "has data");
    72  
    73          coins.length = _owners.length;
    74          uint total;
    75  
    76          for (uint i = _owners.length; i-- > 0;) {
    77              coins[i].owner = _owners[i];
    78              coins[i].amount = _amounts[i];
    79              total += _amounts[i];
    80          }
    81  
    82          totalAmount = total;
    83          // NOTE: there is a special consensus procedure to setup account balance based on
    84          //       totalAmount().
    85  
    86          for (uint i = _blacklist.length; i-- > 0;) {
    87              hard_blacklist[_blacklist[i]] = true;
    88          }
    89      }
    90  
    91      function itemCount() external view returns(uint) {
    92          return coins.length;
    93      }
    94  
    95      function hashToSign(address payable _destination)
    96          public view
    97          returns(bytes32)
    98      {
    99          return keccak256(
   100              abi.encodePacked(
   101                  _destination,
   102                  "||Energi Gen 2 migration claim||",
   103                  chain_id
   104              )
   105          );
   106      }
   107  
   108      function verifyClaim(uint _item_id, address payable _destination, uint8 sig_v, bytes32 sig_r, bytes32 sig_s)
   109          public view
   110          returns(uint amount)
   111      {
   112          // Check ID
   113          require(_item_id < coins.length, "Invalid ID");
   114  
   115          // Recover owner
   116          bytes32 hash = hashToSign(_destination);
   117          bytes20 owner = bytes20(ecrecover(hash, sig_v, sig_r, sig_s));
   118  
   119          // Validate Owner
   120          require(coins[_item_id].owner == owner, "Invalid signature");
   121  
   122          // Check if blacklisted
   123          IBlacklistRegistry blacklist = IBlacklistRegistry(address(blacklist_proxy.impl()));
   124          require(!blacklist.isBlacklisted(address(owner)), "Owner is blacklisted");
   125          require(!hard_blacklist[owner], "Owner is hard blacklisted");
   126  
   127          // Validate amount
   128          amount = coins[_item_id].amount;
   129      }
   130  
   131      function claim(uint _item_id, address payable _destination, uint8 sig_v, bytes32 sig_r, bytes32 sig_s)
   132          external
   133      {
   134          uint amount = verifyClaim(_item_id, _destination, sig_v, sig_r, sig_s);
   135          require(amount > 0, "Already spent");
   136  
   137          // Spend
   138          coins[_item_id].amount = 0;
   139  
   140          emit Migrated(
   141              _item_id,
   142              _destination,
   143              amount
   144          );
   145  
   146          _destination.transfer(amount);
   147      }
   148  
   149      // SECURITY: emergency drain procedure has to be implemented as blacklist
   150      //           followed by consensus-level drain to Blacklist registry.
   151  
   152      function blacklistClaim(uint _item_id, bytes20 _owner) external {
   153          require(_item_id < coins.length, "Invalid ID");
   154  
   155          uint amount = coins[_item_id].amount;
   156          require(amount > 0, "Already spent");
   157  
   158          require(coins[_item_id].owner == _owner, "Invalid Owner");
   159  
   160          IBlacklistRegistry blacklist = IBlacklistRegistry(address(blacklist_proxy.impl()));
   161          require(msg.sender == address(blacklist), "Not blacklist registry");
   162  
   163          // Spend
   164          coins[_item_id].amount = 0;
   165  
   166          blacklist.compensation_fund().contribute.value(amount)();
   167      }
   168  
   169      // Safety
   170      //---------------------------------
   171      function () external payable {
   172          revert("Not supported");
   173      }
   174  }