I’ve just finished reconciling the Goodies’ The DAO Token Balance contact that they are planning to use to refund ETCs to The DAO token holders on the Ethereum Classic blockchain.
See:
- github.com/bokkypoobah/TheDAOETCTokenBalance
- How can I verify that my The DAO token balance is correct when the Goodies provide an ETC refund on the Ethereum Classic chain? (Ethereum.StackExchange.com)
- How can I verify that my The DAO token balance is correct when the Goodies provide an ETC refund on the Ethereum Classic chain? (Reddit)
DAOBalanceSnapShot Contract
From dao_balance_snapshot.sol:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
// This contract publishes the balances of the DAO at the moment of the hardfork // After the deployment of the contract the function fill is called many times // in order to fill the balance of each account. contract DAOBalanceSnapShot { uint constant D160 = 0x10000000000000000000000000000000000000000; mapping (address => uint) public balanceOf; address public owner; function DAOBalanceSnapShot() { owner = msg.sender; } uint public totalSupply; uint public totalAccounts; bool public sealed; // The 160 LSB is the address of the balance // The 96 MSB is the balance of that address. function fill(uint[] data) { if ((msg.sender != owner)||(sealed)) throw; for (uint i=0; i<data.length; i++) { address a = address( data[i] & (D160-1) ); uint amount = data[i] / D160; if (balanceOf[a] == 0) { // In case it's filled two times, it only increments once totalAccounts ++; balanceOf[a] = amount; totalSupply += amount; } } } function seal() { if ((msg.sender != owner)||(sealed)) throw; sealed= true; } } |
WhitehatWithdraw Contract
From whetcwithdraw.sol
.sol:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
// The contract that allows DTH to withdraw funds that the white hat // group has managed to retrieve. // // There are 2 ways to use the contract: // 1. withdraw() // 2. proxyWithdraw() // // For a description of each method, take a look at the docstrings. // // License: BSD3 contract DAOBalanceSnapShot { function balanceOf(address _dth) constant returns(uint); function totalSupply() constant returns(uint ); } contract Owned { /// Prevents methods from perfoming any value transfer modifier noEther() {if (msg.value > 0) throw; _} /// Allows only the owner to call a function modifier onlyOwner { if (msg.sender != owner) throw; _ } address owner; function Owned() { owner = msg.sender;} function changeOwner(address _newOwner) onlyOwner { owner = _newOwner; } function getOwner() noEther constant returns (address) { return owner; } } contract WhitehatWithdraw is Owned { uint constant WithdrawType_DIRECT = 1; uint constant WithdrawType_PROXY = 2; DAOBalanceSnapShot daoBalance; mapping (address => uint) paidOut; mapping (bytes32 => bool) usedSignatures; uint totalFunds; uint deployTime; uint closingTime; address whg_donation; address escape; address remainingBeneficary; bool sealed; event Withdraw(address indexed dth, address indexed beneficiary, uint256 amount, uint256 percentageWHG, uint256 withdrawType); event CertifiedDepositorsChanged(address indexed _depositor, bool _allowed); event Deposit(uint amount); event EscapeCalled(uint amount); event RemainingClaimed(uint amount); function fill(uint[] data) onlyOwner { if ((msg.sender != owner)||(sealed)) throw; for (uint i=0; i< data.length; i+= 2) { address dth = address(data[i]); uint amount = uint(data[i+1]); paidOut[dth] = amount; totalFunds += amount; } } function seal() { if ((msg.sender != owner)||(sealed)) throw; sealed= true; } function WhitehatWithdraw(address _whg_donation, address _daoBalanceSnapshotAddress, address _escapeAddress, address _remainingBeneficiary) { whg_donation = _whg_donation; daoBalance = DAOBalanceSnapShot(_daoBalanceSnapshotAddress); escape = _escapeAddress; remainingBeneficary = _remainingBeneficiary; totalFunds = msg.value; deployTime = now; closingTime = 24 weeks; } /// Calculates the remaining funds available for a DTH to withdraw /// /// @param _dth The address of the DAO Token Holder for whom /// to get the funds remaining for withdrawal /// @return The amount of funds remaining for withdrawal function calculateWithdraw(address _dth) constant noEther returns(uint) { uint tokens = daoBalance.balanceOf(_dth); uint acumulatedReward = tokens * totalFunds / daoBalance.totalSupply(); if (acumulatedReward < paidOut[_dth]) { return 0; } return acumulatedReward - paidOut[_dth]; } /// The core of the withdraw functionality. It is called by all other withdraw functions /// /// @param _dth The address of the DAO token holder for whom the /// withdrawal is going to happen /// @param _beneficiary The address that will receive the _percentage of /// the funds corresponding to the _dth. /// @param _percentageWHG The percentage of the funds that will be donated to the /// White Hat Group. It should be a number ranging from 0 /// to 100. Anything not claimed by the DTH will be going /// as a donation to the Whitehat Group. /// @param _withdrawType method used to withdraw (1) Direct (2) Proxy (3) bot (4) owner function commonWithdraw(address _dth, address _beneficiary, uint _percentageWHG, uint _withdrawType) internal { if (_percentageWHG > 100) { throw; } uint toPay = calculateWithdraw(_dth); if (toPay == 0) { return; } if (toPay > this.balance) { toPay = this.balance; } uint portionWhg = toPay * _percentageWHG / 100; uint portionDth = toPay - portionWhg; paidOut[_dth] += toPay; // re-entrancy is not possible due to the use of send() which limits // the forwarded gas thanks to the gas stipend if (portionWhg > 0) { if ( !whg_donation.send(portionWhg) ) { throw; } } if (portionDth > 0) { if (!_beneficiary.send(portionDth) ) { throw; } } Withdraw(_dth, _beneficiary, toPay, _percentageWHG, _withdrawType); } /// The simple withdraw function, where the message sender is considered as /// the DAO token holder whose ratio needs to be retrieved. function withdraw(address _beneficiary, uint _percentageWHG ) noEther { commonWithdraw(msg.sender, _beneficiary, _percentageWHG, WithdrawType_DIRECT); } /// The proxy withdraw function. Anyone can call this for someone else as long /// as he includes signed data retrieved by using web3.eth.sign(address, hash). /// The DAO token holder whose ratio needs to be retrieved is determined by /// performing ecrecover on the signed data. /// /// This function will also allow people to use the ETH chain to give an /// approval for withdrawal in the ETC chain without having to sync the /// ETC chain. The only requirement is that the account that gives the /// approval needs to be an end-user account. Multisig wallets can't do that. function proxyWithdraw(address _beneficiary, uint _percentageWHG, uint8 _v, bytes32 _r, bytes32 _s) noEther { if (usedSignatures[_r]) { throw; } bytes32 _hash = sha3("Withdraw DAOETC to ", _beneficiary, _percentageWHG); address _dth = ecrecover(_hash, _v, _r, _s); usedSignatures[_r] = true; commonWithdraw(_dth, _beneficiary, _percentageWHG, WithdrawType_PROXY); } /// This is the only way to send money to the contract, adding to the total /// amount of ETH to be refunded. function deposit() returns (bool) { totalFunds += msg.value; Deposit(msg.value); return true; } /// Last Resort call, to allow for a reaction if something bad happens to /// the contract or if some security issue is uncovered. function escapeHatch() noEther onlyOwner returns (bool) { uint total = this.balance; if (!escape.send(total)) { throw; } EscapeCalled(total); } /// Allows the claiming of the remaining funds after a given amount of time /// Amount is set to 6 months for now but may still change in the future. function claimRemaining() noEther returns (bool) { if (now < deployTime + closingTime) { throw; } uint total = this.balance; if (!remainingBeneficary.send(total)) { throw; } RemainingClaimed(total); } /// Allows the option to extend (but not shorten!) the closingTime of the /// contract to more than 6 months, perhaps even to infinity if that is /// deemed as the best choice for the DAO Token holders. function extendClosingTime(uint _additionalSeconds) noEther onlyOwner { closingTime += _additionalSeconds; } function () { //no donations throw; } function getPaidOut(address _account) noEther constant returns (uint) { return paidOut[_account]; } function getMyBalance(address _account) noEther constant returns (uint) { return daoBalance.balanceOf(_account); } function getTotalFunds() noEther constant returns (uint) { return totalFunds; } function getWHGDonationAddress() noEther constant returns (address) { return whg_donation; } } |