The Ethereum blockchain will be hard-forked this coming Tuesday on block 2463000 with the main changes being the gas repricing of opcodes (EIP 150 version 1c). A concerned redditor asked There is over $12,000 USD in this contract! Please can somebody tell me what the chances of it being able to be withdrawn after the hardfork are?….
EtherDelta is a decentralised ether and ERC20 token exchange – I’ll have to try using it some day. There is not much trading activity on the exchange at the moment.
Following is a screenshot of EtherDelta running in the Mist browser, loaded from https://etherdelta.github.io and you can find the guides here:
Let’s have a look at the EtherDelta source code at 0x4aea7cf559f67cedcad07e12ae6bc00f07e8cf65:
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 236 237 238 239 240 241 242 243 244 245 246 |
//last compiled with soljson-v0.3.6-2016-08-29-b8060c5.js contract SafeMath { //internals function safeMul(uint a, uint b) internal returns (uint) { uint c = a * b; assert(a == 0 || c / a == b); return c; } function safeSub(uint a, uint b) internal returns (uint) { assert(b <= a); return a - b; } function safeAdd(uint a, uint b) internal returns (uint) { uint c = a + b; assert(c>=a && c>=b); return c; } function assert(bool assertion) internal { if (!assertion) throw; } } contract Token { /// @return total amount of tokens function totalSupply() constant returns (uint256 supply) {} /// @param _owner The address from which the balance will be retrieved /// @return The balance function balanceOf(address _owner) constant returns (uint256 balance) {} /// @notice send `_value` token to `_to` from `msg.sender` /// @param _to The address of the recipient /// @param _value The amount of token to be transferred /// @return Whether the transfer was successful or not function transfer(address _to, uint256 _value) returns (bool success) {} /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` /// @param _from The address of the sender /// @param _to The address of the recipient /// @param _value The amount of token to be transferred /// @return Whether the transfer was successful or not function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {} /// @notice `msg.sender` approves `_addr` to spend `_value` tokens /// @param _spender The address of the account able to transfer the tokens /// @param _value The amount of wei to be approved for transfer /// @return Whether the approval was successful or not function approve(address _spender, uint256 _value) returns (bool success) {} /// @param _owner The address of the account owning tokens /// @param _spender The address of the account able to transfer the tokens /// @return Amount of remaining tokens allowed to spent function allowance(address _owner, address _spender) constant returns (uint256 remaining) {} event Transfer(address indexed _from, address indexed _to, uint256 _value); event Approval(address indexed _owner, address indexed _spender, uint256 _value); uint public decimals; string public name; } contract StandardToken is Token { function transfer(address _to, uint256 _value) returns (bool success) { //Default assumes totalSupply can't be over max (2^256 - 1). //If your token leaves out totalSupply and can issue more tokens as time goes on, you need to check if it doesn't wrap. //Replace the if with this one instead. if (balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]) { //if (balances[msg.sender] >= _value && _value > 0) { balances[msg.sender] -= _value; balances[_to] += _value; Transfer(msg.sender, _to, _value); return true; } else { return false; } } function transferFrom(address _from, address _to, uint256 _value) returns (bool success) { //same as above. Replace this line with the following if you want to protect against wrapping uints. if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]) { //if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) { balances[_to] += _value; balances[_from] -= _value; allowed[_from][msg.sender] -= _value; Transfer(_from, _to, _value); return true; } else { return false; } } function balanceOf(address _owner) constant returns (uint256 balance) { return balances[_owner]; } function approve(address _spender, uint256 _value) returns (bool success) { allowed[msg.sender][_spender] = _value; Approval(msg.sender, _spender, _value); return true; } function allowance(address _owner, address _spender) constant returns (uint256 remaining) { return allowed[_owner][_spender]; } mapping(address => uint256) balances; mapping (address => mapping (address => uint256)) allowed; uint256 public totalSupply; } contract ReserveToken is StandardToken, SafeMath { address public minter; function ReserveToken() { minter = msg.sender; } function create(address account, uint amount) { if (msg.sender != minter) throw; balances[account] = safeAdd(balances[account], amount); totalSupply = safeAdd(totalSupply, amount); } function destroy(address account, uint amount) { if (msg.sender != minter) throw; if (balances[account] < amount) throw; balances[account] = safeSub(balances[account], amount); totalSupply = safeSub(totalSupply, amount); } } contract EtherDelta is SafeMath { mapping (address => mapping (address => uint)) tokens; //mapping of token addresses to mapping of account balances //ether balances are held in the token=0 account mapping (bytes32 => uint) orderFills; address public feeAccount; uint public feeMake; //percentage times (1 ether) uint public feeTake; //percentage times (1 ether) event Order(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s); event Cancel(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s); event Trade(address tokenGet, uint amountGet, address tokenGive, uint amountGive, address get, address give); event Deposit(address token, address user, uint amount, uint balance); event Withdraw(address token, address user, uint amount, uint balance); function EtherDelta(address feeAccount_, uint feeMake_, uint feeTake_) { feeAccount = feeAccount_; feeMake = feeMake_; feeTake = feeTake_; } function() { throw; } function deposit() { tokens[0][msg.sender] = safeAdd(tokens[0][msg.sender], msg.value); Deposit(0, msg.sender, msg.value, tokens[0][msg.sender]); } function withdraw(uint amount) { if (msg.value>0) throw; if (tokens[0][msg.sender] < amount) throw; tokens[0][msg.sender] = safeSub(tokens[0][msg.sender], amount); if (!msg.sender.call.value(amount)()) throw; Withdraw(0, msg.sender, amount, tokens[0][msg.sender]); } function depositToken(address token, uint amount) { //remember to call Token(address).approve(this, amount) or this contract will not be able to do the transfer on your behalf. if (msg.value>0 || token==0) throw; if (!Token(token).transferFrom(msg.sender, this, amount)) throw; tokens[token][msg.sender] = safeAdd(tokens[token][msg.sender], amount); Deposit(token, msg.sender, amount, tokens[token][msg.sender]); } function withdrawToken(address token, uint amount) { if (msg.value>0 || token==0) throw; if (tokens[token][msg.sender] < amount) throw; tokens[token][msg.sender] = safeSub(tokens[token][msg.sender], amount); if (!Token(token).transfer(msg.sender, amount)) throw; Withdraw(token, msg.sender, amount, tokens[token][msg.sender]); } function balanceOf(address token, address user) constant returns (uint) { return tokens[token][user]; } function order(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, uint8 v, bytes32 r, bytes32 s) { if (msg.value>0) throw; Order(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, msg.sender, v, r, s); } function trade(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s, uint amount) { //amount is in amountGet terms if (msg.value>0) throw; bytes32 hash = sha256(tokenGet, amountGet, tokenGive, amountGive, expires, nonce); if (!( ecrecover(hash,v,r,s) == user && block.number <= expires && safeAdd(orderFills[hash], amount) <= amountGet && tokens[tokenGet][msg.sender] >= amount && tokens[tokenGive][user] >= safeMul(amountGive, amount) / amountGet )) throw; tokens[tokenGet][msg.sender] = safeSub(tokens[tokenGet][msg.sender], amount); tokens[tokenGet][user] = safeAdd(tokens[tokenGet][user], safeMul(amount, ((1 ether) - feeMake)) / (1 ether)); tokens[tokenGet][feeAccount] = safeAdd(tokens[tokenGet][feeAccount], safeMul(amount, feeMake) / (1 ether)); tokens[tokenGive][user] = safeSub(tokens[tokenGive][user], safeMul(amountGive, amount) / amountGet); tokens[tokenGive][msg.sender] = safeAdd(tokens[tokenGive][msg.sender], safeMul(safeMul(((1 ether) - feeTake), amountGive), amount) / amountGet / (1 ether)); tokens[tokenGive][feeAccount] = safeAdd(tokens[tokenGive][feeAccount], safeMul(safeMul(feeTake, amountGive), amount) / amountGet / (1 ether)); orderFills[hash] = safeAdd(orderFills[hash], amount); Trade(tokenGet, amount, tokenGive, amountGive * amount / amountGet, user, msg.sender); } function testTrade(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s, uint amount, address sender) constant returns(bool) { if (!( tokens[tokenGet][sender] >= amount && availableVolume(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, user, v, r, s) >= amount )) return false; return true; } function availableVolume(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s) constant returns(uint) { bytes32 hash = sha256(tokenGet, amountGet, tokenGive, amountGive, expires, nonce); if (!( ecrecover(hash,v,r,s) == user && block.number <= expires )) return 0; uint available1 = safeSub(amountGet, orderFills[hash]); uint available2 = safeMul(tokens[tokenGive][user], amountGet) / amountGive; if (available1<available2) return available1; return available2; } function cancelOrder(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, uint8 v, bytes32 r, bytes32 s) { if (msg.value>0) throw; bytes32 hash = sha256(tokenGet, amountGet, tokenGive, amountGive, expires, nonce); if (ecrecover(hash,v,r,s) != msg.sender) throw; orderFills[hash] = amountGet; Cancel(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, msg.sender, v, r, s); } } |
The main concern would be the msg.sender.call.value(amount)()
call in the withdraw(...)
method. From a brief look at this method, there should be no problems with withdrawing the ethers from this contract. Gas cost for the call
function would increase by 660, if the message sender is a regular externally owned account. If the message sender is a smart contract (wallet contract), some opcodes in this wallet contract may raise the amount of gas required for a successful send. The transaction sent to the withdraw(...)
method of this contract just has to increase the supplied gas by this amount.
This contract withdrawal should be safe from this hard-fork change.
Relevant to this question is A quick note on how the CALL gas cost increase will affect contracts.