mirror of https://github.com/ConsenSys/mythril
parent
3c3a74336f
commit
2c96300d93
@ -1,91 +0,0 @@ |
||||
from mythril.ether import util |
||||
from mythril.rpc.client import EthJsonRpc |
||||
from mythril.ether.contractstorage import get_persistent_storage |
||||
from mythril.disassembler.disassembly import Disassembly |
||||
from ethereum.abi import encode_abi |
||||
import re |
||||
import os |
||||
|
||||
|
||||
# Discover contract functions that write the sender address, or an address passed as an argument, to storage. |
||||
# Needs testrpc running on port 8546 |
||||
|
||||
# testrpc --port 8546 --gasLimit 0xFFFFFF --account 0x0b6f3fd29ca0e570faf9d0bb8945858b9c337cd2a2ff89d65013eec412a4a811,500000000000000000000 --account 0x2194ac1cd3b9ca6cccc1a90aa2c6f944994b80bb50c82b973adce7f288734d5c,500000000000000000000 |
||||
|
||||
|
||||
addr_knupper= "0xe2beffc4bc7ebb9eae43d59d2b555749d9ce7c54" |
||||
addr_schnupper = "0xadc2f8617191ff60a36c3c136170cc69c03e64cd" |
||||
|
||||
contract_storage = get_persistent_storage(os.path.join(os.path.expanduser('~'), ".mythril")) |
||||
testrpc = EthJsonRpc("localhost", 8546) |
||||
|
||||
testargs1 = [ |
||||
([], []), |
||||
(['address'], [addr_schnupper]), |
||||
(['address', 'uint256'], [addr_schnupper, 1 ]), |
||||
(['address', 'uint256', 'uint256'], [addr_schnupper, 1, 1]), |
||||
(['address[]'], [[addr_schnupper]]), |
||||
(['address[]', 'uint256'], [[addr_schnupper], 1 ]), |
||||
(['address[]', 'uint256', 'uint256'], [[addr_schnupper], 1, 1]), |
||||
] |
||||
|
||||
|
||||
def testCase(contract_addr, function_selector, arg_types, args): |
||||
|
||||
if re.match(r'^UNK_0x', function_selector): |
||||
args = encode_abi(['address'], [addr_schnupper]) |
||||
data= function_selector[4:] + args.hex() |
||||
else: |
||||
data = util.encode_calldata(function_selector, arg_types, args) |
||||
|
||||
tx = testrpc.eth_sendTransaction(to_address=contract_addr, from_address=addr_schnupper, gas=5000000, value=0, data=data) |
||||
|
||||
trace = testrpc.traceTransaction(tx) |
||||
|
||||
if trace: |
||||
for t in trace['structLogs']: |
||||
if t['op'] == 'SSTORE': |
||||
if addr_schnupper[2:] in t['stack'][-2]: |
||||
return True |
||||
|
||||
return False |
||||
|
||||
|
||||
def testDynamic(contract_hash, contract, addresses, balances): |
||||
|
||||
ret = testrpc.eth_sendTransaction(from_address=addr_knupper, gas=5000000, value=0, data=contract.creation_code) |
||||
receipt = testrpc.eth_getTransactionReceipt(ret) |
||||
contract_addr = receipt['contractAddress'] |
||||
|
||||
try: |
||||
disas = Disassembly(contract.code) |
||||
except: |
||||
return |
||||
|
||||
found = False |
||||
|
||||
for function_selector in disas.func_to_addr: |
||||
|
||||
try: |
||||
for t in testargs1: |
||||
if(testCase(contract_addr, function_selector, t[0], t[1])): |
||||
print("Possible write!") |
||||
print("Contract hash: " + contract_hash) |
||||
print("Selector: " + function_selector) |
||||
print("Input data: " + str(t[1])) |
||||
|
||||
for i in range(0, len(addresses)): |
||||
print("Address: " + addresses[i] + ", balance: " + str(balances[i])) |
||||
|
||||
found = True |
||||
break |
||||
|
||||
if found: |
||||
break |
||||
except: |
||||
break |
||||
|
||||
|
||||
print("Searching " +str(len(list(contract_storage.contracts))) + " contracts...") |
||||
|
||||
contract_storage.search("code#PUSH#", testDynamic) # Returns all contracts |
@ -1,72 +0,0 @@ |
||||
from mythril.ether import evm |
||||
from mythril.ether.contractstorage import get_persistent_storage |
||||
from mythril.disassembler.disassembly import Disassembly |
||||
from mythril.rpc.client import EthJsonRpc |
||||
from mythril.disassembler.callgraph import generate_callgraph |
||||
import os |
||||
|
||||
|
||||
contract_storage = get_persistent_storage() |
||||
contract_keys = list(contract_storage.contracts) |
||||
homestead = EthJsonRpc() |
||||
|
||||
# Iterate over all contracts in the database |
||||
|
||||
for k in contract_keys: |
||||
|
||||
contract = contract_storage.contracts[k] |
||||
|
||||
# Run each contract in the PyEthereum EVM trace to check whether DELEGATECALL is reached |
||||
# To execute the fallback function, we don't provide any input data |
||||
|
||||
ret = evm.trace(contract.code) |
||||
|
||||
if 'DELEGATECALL' in ret: |
||||
|
||||
print("DELEGATECALL in fallback function: Contract 0x" + k.hex() + " deployed at: ") |
||||
|
||||
instance_list = contract_storage.instance_lists[k] |
||||
|
||||
for i in range(1, len(instance_list.addresses)): |
||||
print("Address: " + instance_list.addresses[i] + ", balance: " + str(instance_list.balances[i])) |
||||
|
||||
# contract.get_xrefs() should contain the delegateCall() target (library contract) |
||||
|
||||
print("Referenced contracts:") |
||||
|
||||
xrefs = contract.get_xrefs() |
||||
|
||||
print ("\n".join(xrefs)) |
||||
|
||||
''' |
||||
from here on are many different options! |
||||
|
||||
In this example, we'll only check one of the refernced contracts contains the initWallet() function |
||||
If it does, we save the disassembly and callgraph for further analysis |
||||
|
||||
''' |
||||
|
||||
for xref in xrefs: |
||||
code = homestead.eth_getCode(xref) |
||||
|
||||
disassembly = Disassembly(code) |
||||
|
||||
if contract.matches_expression("func#initWallet(address[],uint256,uint256)#"): |
||||
print ("initWallet() in referenced library contract: " + xref) |
||||
|
||||
# Save list of contracts that forward calls to this library contract |
||||
|
||||
cwd = os.getcwd() |
||||
|
||||
with open("contracts_calling_" + xref + ".txt", "w") as f: |
||||
addresses = contract_storage.instance_lists[k].addresses |
||||
|
||||
f.write("\n".join(addresses)) |
||||
|
||||
easm = disassembly.get_easm() |
||||
|
||||
with open("library_" + xref + ".easm", "w") as f: |
||||
f.write(easm) |
||||
|
||||
generate_callgraph(disassembly, os.path.join(cwd, "library_" + xref)) |
||||
|
@ -1,464 +0,0 @@ |
||||
//sol Wallet |
||||
// Multi-sig, daily-limited account proxy/wallet. |
||||
// @authors: |
||||
// Gav Wood <g@ethdev.com> |
||||
// inheritable "property" contract that enables methods to be protected by requiring the acquiescence of either a |
||||
// single, or, crucially, each of a number of, designated owners. |
||||
// usage: |
||||
// use modifiers onlyowner (just own owned) or onlymanyowners(hash), whereby the same hash must be provided by |
||||
// some number (specified in constructor) of the set of owners (specified in the constructor, modifiable) before the |
||||
// interior is executed. |
||||
|
||||
pragma solidity ^0.4.9; |
||||
|
||||
contract WalletEvents { |
||||
// EVENTS |
||||
|
||||
// this contract only has six types of events: it can accept a confirmation, in which case |
||||
// we record owner and operation (hash) alongside it. |
||||
event Confirmation(address owner, bytes32 operation); |
||||
event Revoke(address owner, bytes32 operation); |
||||
|
||||
// some others are in the case of an owner changing. |
||||
event OwnerChanged(address oldOwner, address newOwner); |
||||
event OwnerAdded(address newOwner); |
||||
event OwnerRemoved(address oldOwner); |
||||
|
||||
// the last one is emitted if the required signatures change |
||||
event RequirementChanged(uint newRequirement); |
||||
|
||||
// Funds has arrived into the wallet (record how much). |
||||
event Deposit(address _from, uint value); |
||||
// Single transaction going out of the wallet (record who signed for it, how much, and to whom it's going). |
||||
event SingleTransact(address owner, uint value, address to, bytes data, address created); |
||||
// Multi-sig transaction going out of the wallet (record who signed for it last, the operation hash, how much, and to whom it's going). |
||||
event MultiTransact(address owner, bytes32 operation, uint value, address to, bytes data, address created); |
||||
// Confirmation still needed for a transaction. |
||||
event ConfirmationNeeded(bytes32 operation, address initiator, uint value, address to, bytes data); |
||||
} |
||||
|
||||
contract WalletAbi { |
||||
// Revokes a prior confirmation of the given operation |
||||
function revoke(bytes32 _operation) external; |
||||
|
||||
// Replaces an owner `_from` with another `_to`. |
||||
function changeOwner(address _from, address _to) external; |
||||
|
||||
function addOwner(address _owner) external; |
||||
|
||||
function removeOwner(address _owner) external; |
||||
|
||||
function changeRequirement(uint _newRequired) external; |
||||
|
||||
function isOwner(address _addr) constant returns (bool); |
||||
|
||||
function hasConfirmed(bytes32 _operation, address _owner) external constant returns (bool); |
||||
|
||||
// (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today. |
||||
function setDailyLimit(uint _newLimit) external; |
||||
|
||||
function execute(address _to, uint _value, bytes _data) external returns (bytes32 o_hash); |
||||
function confirm(bytes32 _h) returns (bool o_success); |
||||
} |
||||
|
||||
contract WalletLibrary is WalletEvents { |
||||
// TYPES |
||||
|
||||
// struct for the status of a pending operation. |
||||
struct PendingState { |
||||
uint yetNeeded; |
||||
uint ownersDone; |
||||
uint index; |
||||
} |
||||
|
||||
// Transaction structure to remember details of transaction lest it need be saved for a later call. |
||||
struct Transaction { |
||||
address to; |
||||
uint value; |
||||
bytes data; |
||||
} |
||||
|
||||
// MODIFIERS |
||||
|
||||
// simple single-sig function modifier. |
||||
modifier onlyowner { |
||||
if (isOwner(msg.sender)) |
||||
_; |
||||
} |
||||
// multi-sig function modifier: the operation must have an intrinsic hash in order |
||||
// that later attempts can be realised as the same underlying operation and |
||||
// thus count as confirmations. |
||||
modifier onlymanyowners(bytes32 _operation) { |
||||
if (confirmAndCheck(_operation)) |
||||
_; |
||||
} |
||||
|
||||
// METHODS |
||||
|
||||
// gets called when no other function matches |
||||
function() payable { |
||||
// just being sent some cash? |
||||
if (msg.value > 0) |
||||
Deposit(msg.sender, msg.value); |
||||
} |
||||
|
||||
// constructor is given number of sigs required to do protected "onlymanyowners" transactions |
||||
// as well as the selection of addresses capable of confirming them. |
||||
function initMultiowned(address[] _owners, uint _required) only_uninitialized { |
||||
m_numOwners = _owners.length + 1; |
||||
m_owners[1] = uint(msg.sender); |
||||
m_ownerIndex[uint(msg.sender)] = 1; |
||||
for (uint i = 0; i < _owners.length; ++i) |
||||
{ |
||||
m_owners[2 + i] = uint(_owners[i]); |
||||
m_ownerIndex[uint(_owners[i])] = 2 + i; |
||||
} |
||||
m_required = _required; |
||||
} |
||||
|
||||
// Revokes a prior confirmation of the given operation |
||||
function revoke(bytes32 _operation) external { |
||||
uint ownerIndex = m_ownerIndex[uint(msg.sender)]; |
||||
// make sure they're an owner |
||||
if (ownerIndex == 0) return; |
||||
uint ownerIndexBit = 2**ownerIndex; |
||||
var pending = m_pending[_operation]; |
||||
if (pending.ownersDone & ownerIndexBit > 0) { |
||||
pending.yetNeeded++; |
||||
pending.ownersDone -= ownerIndexBit; |
||||
Revoke(msg.sender, _operation); |
||||
} |
||||
} |
||||
|
||||
// Replaces an owner `_from` with another `_to`. |
||||
function changeOwner(address _from, address _to) onlymanyowners(sha3(msg.data)) external { |
||||
if (isOwner(_to)) return; |
||||
uint ownerIndex = m_ownerIndex[uint(_from)]; |
||||
if (ownerIndex == 0) return; |
||||
|
||||
clearPending(); |
||||
m_owners[ownerIndex] = uint(_to); |
||||
m_ownerIndex[uint(_from)] = 0; |
||||
m_ownerIndex[uint(_to)] = ownerIndex; |
||||
OwnerChanged(_from, _to); |
||||
} |
||||
|
||||
function addOwner(address _owner) onlymanyowners(sha3(msg.data)) external { |
||||
if (isOwner(_owner)) return; |
||||
|
||||
clearPending(); |
||||
if (m_numOwners >= c_maxOwners) |
||||
reorganizeOwners(); |
||||
if (m_numOwners >= c_maxOwners) |
||||
return; |
||||
m_numOwners++; |
||||
m_owners[m_numOwners] = uint(_owner); |
||||
m_ownerIndex[uint(_owner)] = m_numOwners; |
||||
OwnerAdded(_owner); |
||||
} |
||||
|
||||
function removeOwner(address _owner) onlymanyowners(sha3(msg.data)) external { |
||||
uint ownerIndex = m_ownerIndex[uint(_owner)]; |
||||
if (ownerIndex == 0) return; |
||||
if (m_required > m_numOwners - 1) return; |
||||
|
||||
m_owners[ownerIndex] = 0; |
||||
m_ownerIndex[uint(_owner)] = 0; |
||||
clearPending(); |
||||
reorganizeOwners(); //make sure m_numOwner is equal to the number of owners and always points to the optimal free slot |
||||
OwnerRemoved(_owner); |
||||
} |
||||
|
||||
function changeRequirement(uint _newRequired) onlymanyowners(sha3(msg.data)) external { |
||||
if (_newRequired > m_numOwners) return; |
||||
m_required = _newRequired; |
||||
clearPending(); |
||||
RequirementChanged(_newRequired); |
||||
} |
||||
|
||||
// Gets an owner by 0-indexed position (using numOwners as the count) |
||||
function getOwner(uint ownerIndex) external constant returns (address) { |
||||
return address(m_owners[ownerIndex + 1]); |
||||
} |
||||
|
||||
function isOwner(address _addr) constant returns (bool) { |
||||
return m_ownerIndex[uint(_addr)] > 0; |
||||
} |
||||
|
||||
function hasConfirmed(bytes32 _operation, address _owner) external constant returns (bool) { |
||||
var pending = m_pending[_operation]; |
||||
uint ownerIndex = m_ownerIndex[uint(_owner)]; |
||||
|
||||
// make sure they're an owner |
||||
if (ownerIndex == 0) return false; |
||||
|
||||
// determine the bit to set for this owner. |
||||
uint ownerIndexBit = 2**ownerIndex; |
||||
return !(pending.ownersDone & ownerIndexBit == 0); |
||||
} |
||||
|
||||
// constructor - stores initial daily limit and records the present day's index. |
||||
function initDaylimit(uint _limit) only_uninitialized { |
||||
m_dailyLimit = _limit; |
||||
m_lastDay = today(); |
||||
} |
||||
// (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today. |
||||
function setDailyLimit(uint _newLimit) onlymanyowners(sha3(msg.data)) external { |
||||
m_dailyLimit = _newLimit; |
||||
} |
||||
// resets the amount already spent today. needs many of the owners to confirm. |
||||
function resetSpentToday() onlymanyowners(sha3(msg.data)) external { |
||||
m_spentToday = 0; |
||||
} |
||||
|
||||
// throw unless the contract is not yet initialized. |
||||
modifier only_uninitialized { if (m_numOwners > 0) throw; _; } |
||||
|
||||
// constructor - just pass on the owner array to the multiowned and |
||||
// the limit to daylimit |
||||
function initWallet(address[] _owners, uint _required, uint _daylimit) only_uninitialized { |
||||
initDaylimit(_daylimit); |
||||
initMultiowned(_owners, _required); |
||||
} |
||||
|
||||
// kills the contract sending everything to `_to`. |
||||
function kill(address _to) onlymanyowners(sha3(msg.data)) external { |
||||
suicide(_to); |
||||
} |
||||
|
||||
// Outside-visible transact entry point. Executes transaction immediately if below daily spend limit. |
||||
// If not, goes into multisig process. We provide a hash on return to allow the sender to provide |
||||
// shortcuts for the other confirmations (allowing them to avoid replicating the _to, _value |
||||
// and _data arguments). They still get the option of using them if they want, anyways. |
||||
function execute(address _to, uint _value, bytes _data) external onlyowner returns (bytes32 o_hash) { |
||||
// first, take the opportunity to check that we're under the daily limit. |
||||
if ((_data.length == 0 && underLimit(_value)) || m_required == 1) { |
||||
// yes - just execute the call. |
||||
address created; |
||||
if (_to == 0) { |
||||
created = create(_value, _data); |
||||
} else { |
||||
if (!_to.call.value(_value)(_data)) |
||||
throw; |
||||
} |
||||
SingleTransact(msg.sender, _value, _to, _data, created); |
||||
} else { |
||||
// determine our operation hash. |
||||
o_hash = sha3(msg.data, block.number); |
||||
// store if it's new |
||||
if (m_txs[o_hash].to == 0 && m_txs[o_hash].value == 0 && m_txs[o_hash].data.length == 0) { |
||||
m_txs[o_hash].to = _to; |
||||
m_txs[o_hash].value = _value; |
||||
m_txs[o_hash].data = _data; |
||||
} |
||||
if (!confirm(o_hash)) { |
||||
ConfirmationNeeded(o_hash, msg.sender, _value, _to, _data); |
||||
} |
||||
} |
||||
} |
||||
|
||||
function create(uint _value, bytes _code) internal returns (address o_addr) { |
||||
assembly { |
||||
o_addr := create(_value, add(_code, 0x20), mload(_code)) |
||||
jumpi(invalidJumpLabel, iszero(extcodesize(o_addr))) |
||||
} |
||||
} |
||||
|
||||
// confirm a transaction through just the hash. we use the previous transactions map, m_txs, in order |
||||
// to determine the body of the transaction from the hash provided. |
||||
function confirm(bytes32 _h) onlymanyowners(_h) returns (bool o_success) { |
||||
if (m_txs[_h].to != 0 || m_txs[_h].value != 0 || m_txs[_h].data.length != 0) { |
||||
address created; |
||||
if (m_txs[_h].to == 0) { |
||||
created = create(m_txs[_h].value, m_txs[_h].data); |
||||
} else { |
||||
if (!m_txs[_h].to.call.value(m_txs[_h].value)(m_txs[_h].data)) |
||||
throw; |
||||
} |
||||
|
||||
MultiTransact(msg.sender, _h, m_txs[_h].value, m_txs[_h].to, m_txs[_h].data, created); |
||||
delete m_txs[_h]; |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
// INTERNAL METHODS |
||||
|
||||
function confirmAndCheck(bytes32 _operation) internal returns (bool) { |
||||
// determine what index the present sender is: |
||||
uint ownerIndex = m_ownerIndex[uint(msg.sender)]; |
||||
// make sure they're an owner |
||||
if (ownerIndex == 0) return; |
||||
|
||||
var pending = m_pending[_operation]; |
||||
// if we're not yet working on this operation, switch over and reset the confirmation status. |
||||
if (pending.yetNeeded == 0) { |
||||
// reset count of confirmations needed. |
||||
pending.yetNeeded = m_required; |
||||
// reset which owners have confirmed (none) - set our bitmap to 0. |
||||
pending.ownersDone = 0; |
||||
pending.index = m_pendingIndex.length++; |
||||
m_pendingIndex[pending.index] = _operation; |
||||
} |
||||
// determine the bit to set for this owner. |
||||
uint ownerIndexBit = 2**ownerIndex; |
||||
// make sure we (the message sender) haven't confirmed this operation previously. |
||||
if (pending.ownersDone & ownerIndexBit == 0) { |
||||
Confirmation(msg.sender, _operation); |
||||
// ok - check if count is enough to go ahead. |
||||
if (pending.yetNeeded <= 1) { |
||||
// enough confirmations: reset and run interior. |
||||
delete m_pendingIndex[m_pending[_operation].index]; |
||||
delete m_pending[_operation]; |
||||
return true; |
||||
} |
||||
else |
||||
{ |
||||
// not enough: record that this owner in particular confirmed. |
||||
pending.yetNeeded--; |
||||
pending.ownersDone |= ownerIndexBit; |
||||
} |
||||
} |
||||
} |
||||
|
||||
function reorganizeOwners() private { |
||||
uint free = 1; |
||||
while (free < m_numOwners) |
||||
{ |
||||
while (free < m_numOwners && m_owners[free] != 0) free++; |
||||
while (m_numOwners > 1 && m_owners[m_numOwners] == 0) m_numOwners--; |
||||
if (free < m_numOwners && m_owners[m_numOwners] != 0 && m_owners[free] == 0) |
||||
{ |
||||
m_owners[free] = m_owners[m_numOwners]; |
||||
m_ownerIndex[m_owners[free]] = free; |
||||
m_owners[m_numOwners] = 0; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// checks to see if there is at least `_value` left from the daily limit today. if there is, subtracts it and |
||||
// returns true. otherwise just returns false. |
||||
function underLimit(uint _value) internal onlyowner returns (bool) { |
||||
// reset the spend limit if we're on a different day to last time. |
||||
if (today() > m_lastDay) { |
||||
m_spentToday = 0; |
||||
m_lastDay = today(); |
||||
} |
||||
// check to see if there's enough left - if so, subtract and return true. |
||||
// overflow protection // dailyLimit check |
||||
if (m_spentToday + _value >= m_spentToday && m_spentToday + _value <= m_dailyLimit) { |
||||
m_spentToday += _value; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
// determines today's index. |
||||
function today() private constant returns (uint) { return now / 1 days; } |
||||
|
||||
function clearPending() internal { |
||||
uint length = m_pendingIndex.length; |
||||
|
||||
for (uint i = 0; i < length; ++i) { |
||||
delete m_txs[m_pendingIndex[i]]; |
||||
|
||||
if (m_pendingIndex[i] != 0) |
||||
delete m_pending[m_pendingIndex[i]]; |
||||
} |
||||
|
||||
delete m_pendingIndex; |
||||
} |
||||
|
||||
// FIELDS |
||||
address constant _walletLibrary = 0xcafecafecafecafecafecafecafecafecafecafe; |
||||
|
||||
// the number of owners that must confirm the same operation before it is run. |
||||
uint public m_required; |
||||
// pointer used to find a free slot in m_owners |
||||
uint public m_numOwners; |
||||
|
||||
uint public m_dailyLimit; |
||||
uint public m_spentToday; |
||||
uint public m_lastDay; |
||||
|
||||
// list of owners |
||||
uint[256] m_owners; |
||||
|
||||
uint constant c_maxOwners = 250; |
||||
// index on the list of owners to allow reverse lookup |
||||
mapping(uint => uint) m_ownerIndex; |
||||
// the ongoing operations. |
||||
mapping(bytes32 => PendingState) m_pending; |
||||
bytes32[] m_pendingIndex; |
||||
|
||||
// pending transactions we have at present. |
||||
mapping (bytes32 => Transaction) m_txs; |
||||
} |
||||
|
||||
contract Wallet is WalletEvents { |
||||
|
||||
// WALLET CONSTRUCTOR |
||||
// calls the `initWallet` method of the Library in this context |
||||
function Wallet(address[] _owners, uint _required, uint _daylimit) { |
||||
// Signature of the Wallet Library's init function |
||||
bytes4 sig = bytes4(sha3("initWallet(address[],uint256,uint256)")); |
||||
address target = _walletLibrary; |
||||
|
||||
// Compute the size of the call data : arrays has 2 |
||||
// 32bytes for offset and length, plus 32bytes per element ; |
||||
// plus 2 32bytes for each uint |
||||
uint argarraysize = (2 + _owners.length); |
||||
uint argsize = (2 + argarraysize) * 32; |
||||
|
||||
assembly { |
||||
// Add the signature first to memory |
||||
mstore(0x0, sig) |
||||
// Add the call data, which is at the end of the |
||||
// code |
||||
codecopy(0x4, sub(codesize, argsize), argsize) |
||||
// Delegate call to the library |
||||
delegatecall(sub(gas, 10000), target, 0x0, add(argsize, 0x4), 0x0, 0x0) |
||||
} |
||||
} |
||||
|
||||
// METHODS |
||||
|
||||
// gets called when no other function matches |
||||
function() payable { |
||||
// just being sent some cash? |
||||
if (msg.value > 0) |
||||
Deposit(msg.sender, msg.value); |
||||
else if (msg.data.length > 0) |
||||
_walletLibrary.delegatecall(msg.data); |
||||
} |
||||
|
||||
// Gets an owner by 0-indexed position (using numOwners as the count) |
||||
function getOwner(uint ownerIndex) constant returns (address) { |
||||
return address(m_owners[ownerIndex + 1]); |
||||
} |
||||
|
||||
// As return statement unavailable in fallback, explicit the method here |
||||
|
||||
function hasConfirmed(bytes32 _operation, address _owner) external constant returns (bool) { |
||||
return _walletLibrary.delegatecall(msg.data); |
||||
} |
||||
|
||||
function isOwner(address _addr) constant returns (bool) { |
||||
return _walletLibrary.delegatecall(msg.data); |
||||
} |
||||
|
||||
// FIELDS |
||||
address constant _walletLibrary = 0xcafecafecafecafecafecafecafecafecafecafe; |
||||
|
||||
// the number of owners that must confirm the same operation before it is run. |
||||
uint public m_required; |
||||
// pointer used to find a free slot in m_owners |
||||
uint public m_numOwners; |
||||
|
||||
uint public m_dailyLimit; |
||||
uint public m_spentToday; |
||||
uint public m_lastDay; |
||||
|
||||
// list of owners |
||||
uint[256] m_owners; |
||||
} |
@ -0,0 +1,23 @@ |
||||
contract Reentrancy { |
||||
|
||||
mapping(address => uint) public balances; |
||||
|
||||
function donate(address _to) public payable { |
||||
balances[_to] += msg.value; |
||||
} |
||||
|
||||
function balanceOf(address _who) public constant returns (uint balance) { |
||||
return balances[_who]; |
||||
} |
||||
|
||||
function withdraw(uint _amount) public { |
||||
if(balances[msg.sender] >= _amount) { |
||||
if(msg.sender.call.value(_amount)()) { |
||||
_amount; |
||||
} |
||||
balances[msg.sender] -= _amount; |
||||
} |
||||
} |
||||
|
||||
function() payable {} |
||||
} |
@ -0,0 +1,20 @@ |
||||
contract Under { |
||||
|
||||
mapping(address => uint) balances; |
||||
uint public totalSupply; |
||||
|
||||
function Token(uint _initialSupply) { |
||||
balances[msg.sender] = totalSupply = _initialSupply; |
||||
} |
||||
|
||||
function sendeth(address _to, uint _value) public returns (bool) { |
||||
require(balances[msg.sender] - _value >= 0); |
||||
balances[msg.sender] -= _value; |
||||
balances[_to] += _value; |
||||
return true; |
||||
} |
||||
|
||||
function balanceOf(address _owner) public constant returns (uint balance) { |
||||
return balances[_owner]; |
||||
} |
||||
} |
Loading…
Reference in new issue