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 }