diff --git a/mythril/analysis/modules/ether_thief.py b/mythril/analysis/modules/ether_thief.py index 3b5c5697..315c9e64 100644 --- a/mythril/analysis/modules/ether_thief.py +++ b/mythril/analysis/modules/ether_thief.py @@ -75,7 +75,7 @@ class EtherThief(DetectionModule): transaction_sequence = solver.get_transaction_sequence(state, constraints) - debug = "Transaction Sequence: " + str(transaction_sequence) + debug = str(transaction_sequence) issue = Issue( contract=node.contract_name, diff --git a/mythril/analysis/modules/exceptions.py b/mythril/analysis/modules/exceptions.py index 2b17920b..41a6a8e8 100644 --- a/mythril/analysis/modules/exceptions.py +++ b/mythril/analysis/modules/exceptions.py @@ -42,7 +42,7 @@ class ReachableExceptionsModule(DetectionModule): "Use `require()` for regular input checking." ) - debug = "Transaction Sequence: " + str( + debug = str( solver.get_transaction_sequence(state, node.constraints) ) diff --git a/mythril/analysis/modules/integer.py b/mythril/analysis/modules/integer.py index e7d67836..9bd354a7 100644 --- a/mythril/analysis/modules/integer.py +++ b/mythril/analysis/modules/integer.py @@ -108,7 +108,7 @@ class IntegerOverflowUnderflowModule(DetectionModule): operator ) try: - issue.debug = "Transaction Sequence: " + str( + issue.debug = str( solver.get_transaction_sequence(state, node.constraints + [constraint]) ) except UnsatError: @@ -223,7 +223,7 @@ class IntegerOverflowUnderflowModule(DetectionModule): "The subtraction can result in an integer underflow.\n" ) - issue.debug = "Transaction Sequence: " + str( + issue.debug = str( solver.get_transaction_sequence(state, node.constraints) ) issues.append(issue) diff --git a/mythril/analysis/modules/suicide.py b/mythril/analysis/modules/suicide.py index c7b13ead..403da4f5 100644 --- a/mythril/analysis/modules/suicide.py +++ b/mythril/analysis/modules/suicide.py @@ -36,7 +36,7 @@ def _analyze_state(state): "The contract can be killed by anyone. Don't accidentally kill it." ) - debug = "Transaction Sequence: " + str(transaction_sequence) + debug = str(transaction_sequence) issue = Issue( contract=node.contract_name, diff --git a/mythril/ethereum/util.py b/mythril/ethereum/util.py index 6669dadc..9c5a3fce 100644 --- a/mythril/ethereum/util.py +++ b/mythril/ethereum/util.py @@ -73,12 +73,14 @@ def get_indexed_address(index): def solc_exists(version): - solc_binary = os.path.join( - os.environ.get("HOME", str(Path.home())), - ".py-solc/solc-v" + version, - "bin/solc", - ) - if os.path.exists(solc_binary): - return True - else: - return False + solc_binaries = [ + os.path.join( + os.environ.get("HOME", str(Path.home())), + ".py-solc/solc-v" + version, + "bin/solc", + ), # py-solc setup + "/usr/bin/solc", # Ubuntu PPA setup + ] + for solc_path in solc_binaries: + if os.path.exists(solc_path): + return solc_path diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py index 8f52f8b5..90a5975d 100644 --- a/mythril/interfaces/cli.py +++ b/mythril/interfaces/cli.py @@ -200,13 +200,12 @@ def main(): ) rpc = parser.add_argument_group("RPC options") - rpc.add_argument( - "-i", action="store_true", help="Preset: Infura Node service (Mainnet)" - ) + rpc.add_argument( "--rpc", help="custom RPC settings", metavar="HOST:PORT / ganache / infura-[network_name]", + default="infura-mainnet", ) rpc.add_argument( "--rpctls", type=bool, default=False, help="RPC connection over TLS" @@ -290,12 +289,7 @@ def main(): if args.address: # Establish RPC connection if necessary - if args.i: - mythril.set_api_rpc_infura() - elif args.rpc: - mythril.set_api_rpc(rpc=args.rpc, rpctls=args.rpctls) - elif not (args.dynld or not args.no_onchain_storage_access): - mythril.set_api_rpc_localhost() + mythril.set_api_rpc(rpc=args.rpc, rpctls=args.rpctls) elif args.search or args.contract_hash_to_address: # Open LevelDB if necessary mythril.set_api_leveldb( @@ -331,9 +325,11 @@ def main(): if args.code: # Load from bytecode - address, _ = mythril.load_from_bytecode(args.code, args.bin_runtime) + code = args.code[2:] if args.code.startswith("0x") else args.code + address, _ = mythril.load_from_bytecode(code, args.bin_runtime) elif args.codefile: bytecode = "".join([l.strip() for l in args.codefile if len(l.strip()) > 0]) + bytecode = bytecode[2:] if bytecode.startswith("0x") else bytecode address, _ = mythril.load_from_bytecode(bytecode, args.bin_runtime) elif args.address: # Get bytecode from a contract address diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py index 4cbc06c5..7ade087d 100644 --- a/mythril/laser/ethereum/instructions.py +++ b/mythril/laser/ethereum/instructions.py @@ -706,7 +706,7 @@ class Instruction: if size == 0 and isinstance( global_state.current_transaction, ContractCreationTransaction ): - if concrete_code_offset >= len(global_state.environment.code.bytecode) // 2: + if concrete_code_offset >= len(bytecode) // 2: global_state.mstate.mem_extend(concrete_memory_offset, 1) global_state.mstate.memory[ concrete_memory_offset diff --git a/mythril/mythril.py b/mythril/mythril.py index ef74c645..3c7c7b5f 100644 --- a/mythril/mythril.py +++ b/mythril/mythril.py @@ -224,36 +224,33 @@ class Mythril(object): # Figure out solc binary and version # Only proper versions are supported. No nightlies, commits etc (such as available in remix) - if version: - # tried converting input to semver, seemed not necessary so just slicing for now - if version == str(solc.main.get_solc_version())[:6]: - logging.info("Given version matches installed version") - try: - solc_binary = os.environ["SOLC"] - except KeyError: - solc_binary = "solc" - else: - if util.solc_exists(version): - logging.info("Given version is already installed") - else: - try: - solc.install_solc("v" + version) - except SolcError: - raise CriticalError( - "There was an error when trying to install the specified solc version" - ) + if not version: + return os.environ.get("SOLC") or "solc" - solc_binary = os.path.join( - os.environ.get("HOME", str(Path.home())), - ".py-solc/solc-v" + version, - "bin/solc", - ) - logging.info("Setting the compiler to " + str(solc_binary)) + # tried converting input to semver, seemed not necessary so just slicing for now + main_version = solc.main.get_solc_version_string() + main_version_number = re.match(r"\d+.\d+.\d+", main_version) + if main_version is None: + raise CriticalError( + "Could not extract solc version from string {}".format(main_version) + ) + if version == main_version_number: + logging.info("Given version matches installed version") + solc_binary = os.environ.get("SOLC") or "solc" else: - try: - solc_binary = os.environ["SOLC"] - except KeyError: - solc_binary = "solc" + solc_binary = util.solc_exists(version) + if solc_binary: + logging.info("Given version is already installed") + else: + try: + solc.install_solc("v" + version) + except SolcError: + raise CriticalError( + "There was an error when trying to install the specified solc version" + ) + + logging.info("Setting the compiler to %s", solc_binary) + return solc_binary def set_api_leveldb(self, leveldb): diff --git a/solidity_examples/BECToken.sol b/solidity_examples/BECToken.sol index b03a20e5..3a14fd12 100644 --- a/solidity_examples/BECToken.sol +++ b/solidity_examples/BECToken.sol @@ -1,29 +1,29 @@ -pragma solidity ^0.4.16; +pragma solidity 0.5.0; /** * @title SafeMath * @dev Math operations with safety checks that throw on error */ library SafeMath { - function mul(uint256 a, uint256 b) internal constant returns (uint256) { + function mul(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a * b; assert(a == 0 || c / a == b); return c; } - function div(uint256 a, uint256 b) internal constant returns (uint256) { + function div(uint256 a, uint256 b) internal pure returns (uint256) { // assert(b > 0); // Solidity automatically throws when dividing by 0 uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } - function sub(uint256 a, uint256 b) internal constant returns (uint256) { + function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); return a - b; } - function add(uint256 a, uint256 b) internal constant returns (uint256) { + function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; assert(c >= a); return c; @@ -37,7 +37,7 @@ library SafeMath { */ contract ERC20Basic { uint256 public totalSupply; - function balanceOf(address who) public constant returns (uint256); + function balanceOf(address who) public returns (uint256); function transfer(address to, uint256 value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } @@ -63,7 +63,7 @@ contract BasicToken is ERC20Basic { // SafeMath.sub will throw if there is not enough balance. balances[msg.sender] = balances[msg.sender].sub(_value); balances[_to] = balances[_to].add(_value); - Transfer(msg.sender, _to, _value); + emit Transfer(msg.sender, _to, _value); return true; } @@ -72,7 +72,7 @@ contract BasicToken is ERC20Basic { * @param _owner The address to query the the balance of. * @return An uint256 representing the amount owned by the passed address. */ - function balanceOf(address _owner) public constant returns (uint256 balance) { + function balanceOf(address _owner) public returns (uint256 balance) { return balances[_owner]; } } @@ -82,7 +82,7 @@ contract BasicToken is ERC20Basic { * @dev see https://github.com/ethereum/EIPs/issues/20 */ contract ERC20 is ERC20Basic { - function allowance(address owner, address spender) public constant returns (uint256); + function allowance(address owner, address spender) public returns (uint256); function transferFrom(address from, address to, uint256 value) public returns (bool); function approve(address spender, uint256 value) public returns (bool); event Approval(address indexed owner, address indexed spender, uint256 value); @@ -115,7 +115,7 @@ contract StandardToken is ERC20, BasicToken { balances[_from] = balances[_from].sub(_value); balances[_to] = balances[_to].add(_value); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); - Transfer(_from, _to, _value); + emit Transfer(_from, _to, _value); return true; } @@ -131,7 +131,7 @@ contract StandardToken is ERC20, BasicToken { */ function approve(address _spender, uint256 _value) public returns (bool) { allowed[msg.sender][_spender] = _value; - Approval(msg.sender, _spender, _value); + emit Approval(msg.sender, _spender, _value); return true; } @@ -141,7 +141,7 @@ contract StandardToken is ERC20, BasicToken { * @param _spender address The address which will spend the funds. * @return A uint256 specifying the amount of tokens still available for the spender. */ - function allowance(address _owner, address _spender) public constant returns (uint256 remaining) { + function allowance(address _owner, address _spender) public returns (uint256 remaining) { return allowed[_owner][_spender]; } } @@ -162,7 +162,7 @@ contract Ownable { * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ - function Ownable() { + constructor() public { owner = msg.sender; } @@ -182,7 +182,7 @@ contract Ownable { */ function transferOwnership(address newOwner) onlyOwner public { require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); + emit OwnershipTransferred(owner, newOwner); owner = newOwner; } @@ -220,7 +220,7 @@ contract Pausable is Ownable { */ function pause() onlyOwner whenNotPaused public { paused = true; - Pause(); + emit Pause(); } /** @@ -228,7 +228,7 @@ contract Pausable is Ownable { */ function unpause() onlyOwner whenPaused public { paused = false; - Unpause(); + emit Unpause(); } } @@ -251,8 +251,8 @@ contract PausableToken is StandardToken, Pausable { function approve(address _spender, uint256 _value) public whenNotPaused returns (bool) { return super.approve(_spender, _value); } - - function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) { + + function batchTransfer(address[] memory _receivers, uint256 _value) public whenNotPaused returns (bool) { uint cnt = _receivers.length; uint256 amount = uint256(cnt) * _value; require(cnt > 0 && cnt <= 20); @@ -261,7 +261,7 @@ contract PausableToken is StandardToken, Pausable { balances[msg.sender] = balances[msg.sender].sub(amount); for (uint i = 0; i < cnt; i++) { balances[_receivers[i]] = balances[_receivers[i]].add(_value); - Transfer(msg.sender, _receivers[i], _value); + emit Transfer(msg.sender, _receivers[i], _value); } return true; } @@ -287,12 +287,12 @@ contract BecToken is PausableToken { /** * @dev Function to check the amount of tokens that an owner allowed to a spender. */ - function BecToken() { + constructor() public { totalSupply = 7000000000 * (10**(uint256(decimals))); balances[msg.sender] = totalSupply; // Give the creator all initial tokens } - function () { + function () external { //if ether is sent to this address, send it back. revert(); } diff --git a/solidity_examples/WalletLibrary.sol b/solidity_examples/WalletLibrary.sol index 90294219..d972cdd6 100644 --- a/solidity_examples/WalletLibrary.sol +++ b/solidity_examples/WalletLibrary.sol @@ -9,7 +9,7 @@ // 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; +pragma solidity 0.5.0; contract WalletEvents { // EVENTS @@ -50,15 +50,15 @@ contract WalletAbi { function changeRequirement(uint _newRequired) external; - function isOwner(address _addr) constant returns (bool); + function isOwner(address _addr) public returns (bool); - function hasConfirmed(bytes32 _operation, address _owner) external constant returns (bool); + function hasConfirmed(bytes32 _operation, address _owner) external 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); + function execute(address _to, uint _value, bytes calldata _data) external returns (bytes32 o_hash); + function confirm(bytes32 _h) public returns (bool o_success); } contract WalletLibrary is WalletEvents { @@ -96,15 +96,15 @@ contract WalletLibrary is WalletEvents { // METHODS // gets called when no other function matches - function() payable { + function() external payable { // just being sent some cash? if (msg.value > 0) - Deposit(msg.sender, msg.value); + emit 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 { + function initMultiowned(address[] memory _owners, uint _required) public only_uninitialized { m_numOwners = _owners.length + 1; m_owners[1] = uint(msg.sender); m_ownerIndex[uint(msg.sender)] = 1; @@ -122,16 +122,16 @@ contract WalletLibrary is WalletEvents { // make sure they're an owner if (ownerIndex == 0) return; uint ownerIndexBit = 2**ownerIndex; - var pending = m_pending[_operation]; + PendingState memory pending = m_pending[_operation]; if (pending.ownersDone & ownerIndexBit > 0) { pending.yetNeeded++; pending.ownersDone -= ownerIndexBit; - Revoke(msg.sender, _operation); + emit Revoke(msg.sender, _operation); } } // Replaces an owner `_from` with another `_to`. - function changeOwner(address _from, address _to) onlymanyowners(sha3(msg.data)) external { + function changeOwner(address _from, address _to) onlymanyowners(keccak256(msg.data)) external { if (isOwner(_to)) return; uint ownerIndex = m_ownerIndex[uint(_from)]; if (ownerIndex == 0) return; @@ -140,10 +140,10 @@ contract WalletLibrary is WalletEvents { m_owners[ownerIndex] = uint(_to); m_ownerIndex[uint(_from)] = 0; m_ownerIndex[uint(_to)] = ownerIndex; - OwnerChanged(_from, _to); + emit OwnerChanged(_from, _to); } - function addOwner(address _owner) onlymanyowners(sha3(msg.data)) external { + function addOwner(address _owner) onlymanyowners(keccak256(msg.data)) external { if (isOwner(_owner)) return; clearPending(); @@ -154,10 +154,10 @@ contract WalletLibrary is WalletEvents { m_numOwners++; m_owners[m_numOwners] = uint(_owner); m_ownerIndex[uint(_owner)] = m_numOwners; - OwnerAdded(_owner); + emit OwnerAdded(_owner); } - function removeOwner(address _owner) onlymanyowners(sha3(msg.data)) external { + function removeOwner(address _owner) onlymanyowners(keccak256(msg.data)) external { uint ownerIndex = m_ownerIndex[uint(_owner)]; if (ownerIndex == 0) return; if (m_required > m_numOwners - 1) return; @@ -166,27 +166,27 @@ contract WalletLibrary is WalletEvents { 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); + emit OwnerRemoved(_owner); } - function changeRequirement(uint _newRequired) onlymanyowners(sha3(msg.data)) external { + function changeRequirement(uint _newRequired) onlymanyowners(keccak256(msg.data)) external { if (_newRequired > m_numOwners) return; m_required = _newRequired; clearPending(); - RequirementChanged(_newRequired); + emit RequirementChanged(_newRequired); } // Gets an owner by 0-indexed position (using numOwners as the count) - function getOwner(uint ownerIndex) external constant returns (address) { + function getOwner(uint ownerIndex) external view returns (address) { return address(m_owners[ownerIndex + 1]); } - function isOwner(address _addr) constant returns (bool) { + function isOwner(address _addr) public view returns (bool) { return m_ownerIndex[uint(_addr)] > 0; } - function hasConfirmed(bytes32 _operation, address _owner) external constant returns (bool) { - var pending = m_pending[_operation]; + function hasConfirmed(bytes32 _operation, address _owner) external view returns (bool) { + PendingState memory pending = m_pending[_operation]; uint ownerIndex = m_ownerIndex[uint(_owner)]; // make sure they're an owner @@ -198,85 +198,87 @@ contract WalletLibrary is WalletEvents { } // constructor - stores initial daily limit and records the present day's index. - function initDaylimit(uint _limit) only_uninitialized { + function initDaylimit(uint _limit) public 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 { + function setDailyLimit(uint _newLimit) onlymanyowners(keccak256(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 { + function resetSpentToday() onlymanyowners(keccak256(msg.data)) external { m_spentToday = 0; } // throw unless the contract is not yet initialized. - modifier only_uninitialized { if (m_numOwners > 0) throw; _; } + modifier only_uninitialized { require(m_numOwners > 0); _; } // 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 { + function initWallet(address[] memory _owners, uint _required, uint _daylimit) public 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); + function kill(address payable _to) onlymanyowners(keccak256(msg.data)) external { + selfdestruct(_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) { + function execute(address _to, uint _value, bytes calldata _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) { + if (_to == address(0)) { created = create(_value, _data); } else { - if (!_to.call.value(_value)(_data)) - throw; + (bool success, bytes memory data) = _to.call.value(_value)(_data); + require(success); } - SingleTransact(msg.sender, _value, _to, _data, created); + emit SingleTransact(msg.sender, _value, _to, _data, created); } else { // determine our operation hash. - o_hash = sha3(msg.data, block.number); + o_hash = keccak256(abi.encode(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) { + if (m_txs[o_hash].to == address(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); + emit ConfirmationNeeded(o_hash, msg.sender, _value, _to, _data); } } } - function create(uint _value, bytes _code) internal returns (address o_addr) { + function create(uint _value, bytes memory _code) internal returns (address o_addr) { + uint256 o_size; assembly { o_addr := create(_value, add(_code, 0x20), mload(_code)) - jumpi(0xdeadbeef, iszero(extcodesize(o_addr))) + o_size := extcodesize(o_addr) } + require(o_size != 0); } // 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) { + function confirm(bytes32 _h) public onlymanyowners(_h) returns (bool o_success) { + if (m_txs[_h].to != address(0) || m_txs[_h].value != 0 || m_txs[_h].data.length != 0) { address created; - if (m_txs[_h].to == 0) { + if (m_txs[_h].to == address(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; + (bool success, bytes memory data) = m_txs[_h].to.call.value(m_txs[_h].value)(m_txs[_h].data); + require(success); } - MultiTransact(msg.sender, _h, m_txs[_h].value, m_txs[_h].to, m_txs[_h].data, created); + emit MultiTransact(msg.sender, _h, m_txs[_h].value, m_txs[_h].to, m_txs[_h].data, created); delete m_txs[_h]; return true; } @@ -288,9 +290,9 @@ contract WalletLibrary is WalletEvents { // determine what index the present sender is: uint ownerIndex = m_ownerIndex[uint(msg.sender)]; // make sure they're an owner - if (ownerIndex == 0) return; + if (ownerIndex == 0) return false; - var pending = m_pending[_operation]; + PendingState memory 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. @@ -304,7 +306,7 @@ contract WalletLibrary is WalletEvents { 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); + emit Confirmation(msg.sender, _operation); // ok - check if count is enough to go ahead. if (pending.yetNeeded <= 1) { // enough confirmations: reset and run interior. @@ -354,7 +356,7 @@ contract WalletLibrary is WalletEvents { } // determines today's index. - function today() private constant returns (uint) { return now / 1 days; } + function today() private view returns (uint) { return now / 1 days; } function clearPending() internal { uint length = m_pendingIndex.length; @@ -370,7 +372,7 @@ contract WalletLibrary is WalletEvents { } // FIELDS - address constant _walletLibrary = 0xcafecafecafecafecafecafecafecafecafecafe; + address _walletLibrary = 0xCAfEcAfeCAfECaFeCaFecaFecaFECafECafeCaFe; // the number of owners that must confirm the same operation before it is run. uint public m_required; @@ -384,7 +386,7 @@ contract WalletLibrary is WalletEvents { // list of owners uint[256] m_owners; - uint constant c_maxOwners = 250; + uint c_maxOwners = 250; // index on the list of owners to allow reverse lookup mapping(uint => uint) m_ownerIndex; // the ongoing operations. diff --git a/solidity_examples/calls.sol b/solidity_examples/calls.sol index a9069782..513e31fb 100644 --- a/solidity_examples/calls.sol +++ b/solidity_examples/calls.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.17; +pragma solidity 0.5.0; contract Caller { @@ -8,29 +8,29 @@ contract Caller { uint256 statevar; - function Caller(address addr) { + constructor(address addr) public { fixed_address = addr; } function thisisfine() public { - fixed_address.call(); + fixed_address.call(""); } function reentrancy() public { - fixed_address.call(); + fixed_address.call(""); statevar = 0; } - - function calluseraddress(address addr) { - addr.call(); + + function calluseraddress(address addr) public { + addr.call(""); + } + + function callstoredaddress() public { + stored_address.call(""); } - function callstoredaddress() { - stored_address.call(); - } - - function setstoredaddress(address addr) { + function setstoredaddress(address addr) public { stored_address = addr; - } - + } + } \ No newline at end of file diff --git a/solidity_examples/etherstore.sol b/solidity_examples/etherstore.sol index 38a9177c..7cf90388 100644 --- a/solidity_examples/etherstore.sol +++ b/solidity_examples/etherstore.sol @@ -1,3 +1,6 @@ +pragma solidity 0.5.0; + + contract EtherStore { uint256 public withdrawalLimit = 1 ether; @@ -14,7 +17,8 @@ contract EtherStore { require(_weiToWithdraw <= withdrawalLimit); // limit the time allowed to withdraw require(now >= lastWithdrawTime[msg.sender] + 1 weeks); - require(msg.sender.call.value(_weiToWithdraw)()); + (bool success, bytes memory data) = msg.sender.call.value(_weiToWithdraw)(""); + require(success); balances[msg.sender] -= _weiToWithdraw; lastWithdrawTime[msg.sender] = now; } diff --git a/solidity_examples/exceptions.sol b/solidity_examples/exceptions.sol index 95c42da0..aa925603 100644 --- a/solidity_examples/exceptions.sol +++ b/solidity_examples/exceptions.sol @@ -1,40 +1,43 @@ +pragma solidity 0.5.0; + + contract Exceptions { uint256[8] myarray; - function assert1() { + function assert1() public pure { uint256 i = 1; assert(i == 0); } - function assert2() { + function assert2() public pure { uint256 i = 1; assert(i > 0); } - function assert3(uint256 input) { + function assert3(uint256 input) public pure { assert(input != 23); } - function requireisfine(uint256 input) { + function requireisfine(uint256 input) public pure { require(input != 23); } - function divisionby0(uint256 input) { + function divisionby0(uint256 input) public pure { uint256 i = 1/input; } - function thisisfine(uint256 input) { + function thisisfine(uint256 input) public pure { if (input > 0) { uint256 i = 1/input; } - } + } - function arrayaccess(uint256 index) { + function arrayaccess(uint256 index) public view { uint256 i = myarray[index]; } - function thisisalsofind(uint256 index) { + function thisisalsofind(uint256 index) public view { if (index < 8) { uint256 i = myarray[index]; } diff --git a/solidity_examples/hashforether.sol b/solidity_examples/hashforether.sol index a90538ea..f8fe4473 100644 --- a/solidity_examples/hashforether.sol +++ b/solidity_examples/hashforether.sol @@ -1,12 +1,15 @@ +pragma solidity 0.5.0; + + contract HashForEther { - function withdrawWinnings() { - // Winner if the last 8 hex characters of the address are 0. + function withdrawWinnings() public { + // Winner if the last 8 hex characters of the address are 0. require(uint32(msg.sender) == 0); _sendWinnings(); } - function _sendWinnings() { - msg.sender.transfer(this.balance); + function _sendWinnings() public { + msg.sender.transfer(address(this).balance); } } \ No newline at end of file diff --git a/solidity_examples/origin.sol b/solidity_examples/origin.sol index 635c15f4..2ceb10f8 100644 --- a/solidity_examples/origin.sol +++ b/solidity_examples/origin.sol @@ -1,32 +1,33 @@ +pragma solidity 0.5.0; + + contract Origin { address public owner; - /** + /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ - function Origin() { + constructor() public { owner = msg.sender; } /** - * @dev Throws if called by any account other than the owner. + * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { - if (tx.origin != owner) { - throw; - } + require(tx.origin != owner); _; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. + * @param newOwner The address to transfer ownership to. */ - function transferOwnership(address newOwner) onlyOwner { + function transferOwnership(address newOwner) public onlyOwner { if (newOwner != address(0)) { owner = newOwner; } diff --git a/solidity_examples/returnvalue.sol b/solidity_examples/returnvalue.sol index 819580f3..88bd8805 100644 --- a/solidity_examples/returnvalue.sol +++ b/solidity_examples/returnvalue.sol @@ -1,13 +1,17 @@ +pragma solidity 0.5.0; + + contract ReturnValue { - address callee = 0xE0F7e56e62b4267062172495D7506087205A4229; + address public callee = 0xE0f7e56E62b4267062172495D7506087205A4229; - function callnotchecked() { - callee.call(); + function callnotchecked() public { + callee.call(""); } - function callchecked() { - require(callee.call()); + function callchecked() public { + (bool success, bytes memory data) = callee.call(""); + require(success); } } \ No newline at end of file diff --git a/solidity_examples/rubixi.sol b/solidity_examples/rubixi.sol index 301e9196..8e1567c6 100644 --- a/solidity_examples/rubixi.sol +++ b/solidity_examples/rubixi.sol @@ -1,152 +1,152 @@ -contract Rubixi { - - //Declare variables for storage critical to contract - uint private balance = 0; - uint private collectedFees = 0; - uint private feePercent = 10; - uint private pyramidMultiplier = 300; - uint private payoutOrder = 0; - - address private creator; - - //Sets creator - function DynamicPyramid() { - creator = msg.sender; - } - - modifier onlyowner { - if (msg.sender == creator) _; - } - - struct Participant { - address etherAddress; - uint payout; - } - - Participant[] private participants; +pragma solidity 0.5.0; - //Fallback function - function() payable { - init(); - } - - //init function run on fallback - function init() private { - //Ensures only tx with value of 1 ether or greater are processed and added to pyramid - if (msg.value < 1 ether) { - collectedFees += msg.value; - return; - } - - uint _fee = feePercent; - //50% fee rebate on any ether value of 50 or greater - if (msg.value >= 50 ether) _fee /= 2; - - addPayout(_fee); - } - //Function called for valid tx to the contract - function addPayout(uint _fee) private { - //Adds new address to participant array - participants.push(Participant(msg.sender, (msg.value * pyramidMultiplier) / 100)); - - //These statements ensure a quicker payout system to later pyramid entrants, so the pyramid has a longer lifespan - if (participants.length == 10) pyramidMultiplier = 200; - else if (participants.length == 25) pyramidMultiplier = 150; - - // collect fees and update contract balance - balance += (msg.value * (100 - _fee)) / 100; - collectedFees += (msg.value * _fee) / 100; - - //Pays earlier participiants if balance sufficient - while (balance > participants[payoutOrder].payout) { - uint payoutToSend = participants[payoutOrder].payout; - participants[payoutOrder].etherAddress.send(payoutToSend); - - balance -= participants[payoutOrder].payout; - payoutOrder += 1; - } - } +contract Rubixi { + //Declare variables for storage critical to contract + uint private balance = 0; + uint private collectedFees = 0; + uint private feePercent = 10; + uint private pyramidMultiplier = 300; + uint private payoutOrder = 0; + + address payable private creator; + + modifier onlyowner { + if (msg.sender == creator) _; + } + + struct Participant { + address payable etherAddress; + uint payout; + } + + //Fallback function + function() external payable { + init(); + } + + //Sets creator + function dynamicPyramid() public { + creator = msg.sender; + } + + Participant[] private participants; + + //Fee functions for creator + function collectAllFees() public onlyowner { + require(collectedFees == 0); + creator.transfer(collectedFees); + collectedFees = 0; + } + + function collectFeesInEther(uint _amt) public onlyowner { + _amt *= 1 ether; + if (_amt > collectedFees) collectAllFees(); + + require(collectedFees == 0); + + creator.transfer(_amt); + collectedFees -= _amt; + } + + function collectPercentOfFees(uint _pcent) public onlyowner { + require(collectedFees == 0 || _pcent > 100); + + uint feesToCollect = collectedFees / 100 * _pcent; + creator.transfer(feesToCollect); + collectedFees -= feesToCollect; + } + + //Functions for changing variables related to the contract + function changeOwner(address payable _owner) public onlyowner { + creator = _owner; + } + + function changeMultiplier(uint _mult) public onlyowner { + require(_mult > 300 || _mult < 120); + pyramidMultiplier = _mult; + } + + function changeFeePercentage(uint _fee) public onlyowner { + require(_fee > 10); + feePercent = _fee; + } + + //Functions to provide information to end-user using JSON interface or other interfaces + function currentMultiplier() public view returns (uint multiplier, string memory info) { + multiplier = pyramidMultiplier; + info = "This multiplier applies to you as soon as transaction is received, may be lowered to hasten payouts or increased if payouts are fast enough. Due to no float or decimals, multiplier is x100 for a fractional multiplier e.g. 250 is actually a 2.5x multiplier. Capped at 3x max and 1.2x min."; + } + + function currentFeePercentage() public view returns (uint fee, string memory info) { + fee = feePercent; + info = "Shown in % form. Fee is halved(50%) for amounts equal or greater than 50 ethers. (Fee may change, but is capped to a maximum of 10%)"; +} - //Fee functions for creator - function collectAllFees() onlyowner { - if (collectedFees == 0) throw; + function currentPyramidBalanceApproximately() public view returns (uint pyramidBalance, string memory info) { + pyramidBalance = balance / 1 ether; + info = "All balance values are measured in Ethers, note that due to no decimal placing, these values show up as integers only, within the contract itself you will get the exact decimal value you are supposed to"; + } - creator.send(collectedFees); - collectedFees = 0; - } + function nextPayoutWhenPyramidBalanceTotalsApproximately() public view returns (uint balancePayout) { + balancePayout = participants[payoutOrder].payout / 1 ether; + } - function collectFeesInEther(uint _amt) onlyowner { - _amt *= 1 ether; - if (_amt > collectedFees) collectAllFees(); + function feesSeperateFromBalanceApproximately() public view returns (uint fees) { + fees = collectedFees / 1 ether; + } - if (collectedFees == 0) throw; - - creator.send(_amt); - collectedFees -= _amt; - } + function totalParticipants() public view returns (uint count) { + count = participants.length; + } - function collectPercentOfFees(uint _pcent) onlyowner { - if (collectedFees == 0 || _pcent > 100) throw; + function numberOfParticipantsWaitingForPayout() public view returns (uint count) { + count = participants.length - payoutOrder; + } - uint feesToCollect = collectedFees / 100 * _pcent; - creator.send(feesToCollect); - collectedFees -= feesToCollect; + function participantDetails(uint orderInPyramid) public view returns (address addr, uint payout) { + if (orderInPyramid <= participants.length) { + addr = participants[orderInPyramid].etherAddress; + payout = participants[orderInPyramid].payout / 1 ether; } + } - //Functions for changing variables related to the contract - function changeOwner(address _owner) onlyowner { - creator = _owner; + //init function run on fallback + function init() private { + //Ensures only tx with value of 1 ether or greater are processed and added to pyramid + if (msg.value < 1 ether) { + collectedFees += msg.value; + return; } - function changeMultiplier(uint _mult) onlyowner { - if (_mult > 300 || _mult < 120) throw; + uint _fee = feePercent; + // 50% fee rebate on any ether value of 50 or greater + if (msg.value >= 50 ether) _fee /= 2; - pyramidMultiplier = _mult; - } + addPayout(_fee); + } - function changeFeePercentage(uint _fee) onlyowner { - if (_fee > 10) throw; + //Function called for valid tx to the contract + function addPayout(uint _fee) private { + //Adds new address to participant array + participants.push(Participant(msg.sender, (msg.value * pyramidMultiplier) / 100)); - feePercent = _fee; - } + // These statements ensure a quicker payout system to + // later pyramid entrants, so the pyramid has a longer lifespan + if (participants.length == 10) pyramidMultiplier = 200; + else if (participants.length == 25) pyramidMultiplier = 150; - //Functions to provide information to end-user using JSON interface or other interfaces - function currentMultiplier() constant returns(uint multiplier, string info) { - multiplier = pyramidMultiplier; - info = 'This multiplier applies to you as soon as transaction is received, may be lowered to hasten payouts or increased if payouts are fast enough. Due to no float or decimals, multiplier is x100 for a fractional multiplier e.g. 250 is actually a 2.5x multiplier. Capped at 3x max and 1.2x min.'; - } - - function currentFeePercentage() constant returns(uint fee, string info) { - fee = feePercent; - info = 'Shown in % form. Fee is halved(50%) for amounts equal or greater than 50 ethers. (Fee may change, but is capped to a maximum of 10%)'; - } + // collect fees and update contract balance + balance += (msg.value * (100 - _fee)) / 100; + collectedFees += (msg.value * _fee) / 100; - function currentPyramidBalanceApproximately() constant returns(uint pyramidBalance, string info) { - pyramidBalance = balance / 1 ether; - info = 'All balance values are measured in Ethers, note that due to no decimal placing, these values show up as integers only, within the contract itself you will get the exact decimal value you are supposed to'; - } - - function nextPayoutWhenPyramidBalanceTotalsApproximately() constant returns(uint balancePayout) { - balancePayout = participants[payoutOrder].payout / 1 ether; - } - - function feesSeperateFromBalanceApproximately() constant returns(uint fees) { - fees = collectedFees / 1 ether; - } - - function totalParticipants() constant returns(uint count) { - count = participants.length; - } - - function numberOfParticipantsWaitingForPayout() constant returns(uint count) { - count = participants.length - payoutOrder; - } + //Pays earlier participiants if balance sufficient + while (balance > participants[payoutOrder].payout) { + uint payoutToSend = participants[payoutOrder].payout; + participants[payoutOrder].etherAddress.transfer(payoutToSend); - function participantDetails(uint orderInPyramid) constant returns(address Address, uint Payout) { - if (orderInPyramid <= participants.length) { - Address = participants[orderInPyramid].etherAddress; - Payout = participants[orderInPyramid].payout / 1 ether; - } + balance -= participants[payoutOrder].payout; + payoutOrder += 1; } + } } diff --git a/solidity_examples/suicide.sol b/solidity_examples/suicide.sol index 1763365b..9e25678c 100644 --- a/solidity_examples/suicide.sol +++ b/solidity_examples/suicide.sol @@ -1,6 +1,9 @@ +pragma solidity 0.5.0; + + contract Suicide { - function kill(address addr) { + function kill(address payable addr) public { selfdestruct(addr); } diff --git a/solidity_examples/timelock.sol b/solidity_examples/timelock.sol index 33ddb4fe..433a300a 100644 --- a/solidity_examples/timelock.sol +++ b/solidity_examples/timelock.sol @@ -1,3 +1,6 @@ +pragma solidity 0.5.0; + + contract TimeLock { mapping(address => uint) public balances; diff --git a/solidity_examples/token.sol b/solidity_examples/token.sol index 19239427..30eeb963 100644 --- a/solidity_examples/token.sol +++ b/solidity_examples/token.sol @@ -1,11 +1,12 @@ -pragma solidity ^0.4.18; +pragma solidity 0.5.0; + contract Token { mapping(address => uint) balances; uint public totalSupply; - function Token(uint _initialSupply) { + constructor(uint _initialSupply) public { balances[msg.sender] = totalSupply = _initialSupply; } @@ -16,7 +17,7 @@ contract Token { return true; } - function balanceOf(address _owner) public constant returns (uint balance) { + function balanceOf(address _owner) public view returns (uint balance) { return balances[_owner]; } } \ No newline at end of file diff --git a/solidity_examples/weak_random.sol b/solidity_examples/weak_random.sol index 88fc4e12..5acdd7ef 100644 --- a/solidity_examples/weak_random.sol +++ b/solidity_examples/weak_random.sol @@ -1,20 +1,21 @@ -pragma solidity ^0.4.16; +pragma solidity 0.5.0; + contract WeakRandom { struct Contestant { - address addr; + address payable addr; uint gameId; } - uint public constant prize = 2.5 ether; - uint public constant totalTickets = 50; - uint public constant pricePerTicket = prize / totalTickets; + uint public prize = 2.5 ether; + uint public totalTickets = 50; + uint public pricePerTicket = prize / totalTickets; uint public gameId = 1; uint public nextTicket = 0; mapping (uint => Contestant) public contestants; - function () payable public { + function () payable external { uint moneySent = msg.value; while (moneySent >= pricePerTicket && nextTicket < totalTickets) { @@ -37,10 +38,10 @@ contract WeakRandom { address seed1 = contestants[uint(block.coinbase) % totalTickets].addr; address seed2 = contestants[uint(msg.sender) % totalTickets].addr; uint seed3 = block.difficulty; - bytes32 randHash = keccak256(seed1, seed2, seed3); + bytes32 randHash = keccak256(abi.encode(seed1, seed2, seed3)); uint winningNumber = uint(randHash) % totalTickets; - address winningAddress = contestants[winningNumber].addr; + address payable winningAddress = contestants[winningNumber].addr; gameId++; nextTicket = 0; diff --git a/tests/cmd_line_test.py b/tests/cmd_line_test.py index 68640c2a..77d2cd96 100644 --- a/tests/cmd_line_test.py +++ b/tests/cmd_line_test.py @@ -10,18 +10,16 @@ def output_of(command): class CommandLineToolTestCase(BaseTestCase): def test_disassemble_code_correctly(self): - command = "python3 {} MYTH -d --bin-runtime -c 0x5050 --solv 0.4.24".format( - MYTH - ) + command = "python3 {} MYTH -d --bin-runtime -c 0x5050 --solv 0.5.0".format(MYTH) self.assertIn("0 POP\n1 POP\n", output_of(command)) def test_disassemble_solidity_file_correctly(self): solidity_file = str(TESTDATA / "input_contracts" / "metacoin.sol") - command = "python3 {} -d {} --solv 0.4.24".format(MYTH, solidity_file) + command = "python3 {} -d {} --solv 0.5.0".format(MYTH, solidity_file) self.assertIn("2 PUSH1 0x40\n4 MSTORE", output_of(command)) def test_hash_a_function_correctly(self): - command = "python3 {} --solv 0.4.24 --hash 'setOwner(address)'".format(MYTH) + command = "python3 {} --solv 0.5.0 --hash 'setOwner(address)'".format(MYTH) self.assertIn("0x13af4035\n", output_of(command)) diff --git a/tests/laser/transaction/create_transaction_test.py b/tests/laser/transaction/create_transaction_test.py index 643e9efb..9b2351e4 100644 --- a/tests/laser/transaction/create_transaction_test.py +++ b/tests/laser/transaction/create_transaction_test.py @@ -13,7 +13,7 @@ from mythril.analysis.symbolic import SymExecWrapper def test_create(): contract = SolidityContract( str(tests.TESTDATA_INPUTS_CONTRACTS / "calls.sol"), - solc_binary=Mythril._init_solc_binary("0.4.24"), + solc_binary=Mythril._init_solc_binary("0.5.0"), ) laser_evm = svm.LaserEVM({}) @@ -37,7 +37,7 @@ def test_create(): def test_sym_exec(): contract = SolidityContract( str(tests.TESTDATA_INPUTS_CONTRACTS / "calls.sol"), - solc_binary=Mythril._init_solc_binary("0.4.24"), + solc_binary=Mythril._init_solc_binary("0.5.0"), ) sym = SymExecWrapper( diff --git a/tests/native_test.py b/tests/native_test.py index 22e4e3a9..a19e86fd 100644 --- a/tests/native_test.py +++ b/tests/native_test.py @@ -6,48 +6,26 @@ from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum import svm from tests import * +SHA256_TEST = [(0, False) for _ in range(4)] +RIPEMD160_TEST = [(0, False) for _ in range(2)] +ECRECOVER_TEST = [(0, False) for _ in range(2)] +IDENTITY_TEST = [(0, False) for _ in range(2)] -SHA256_TEST = [(0, False) for _ in range(6)] +# These are Random numbers to check whether the 'if condition' is entered or not +# (True means entered) +SHA256_TEST[0] = (hex(5555555555555555), True) +SHA256_TEST[1] = (hex(323232325445454546), True) +SHA256_TEST[2] = (hex(34756834765834658), True) +SHA256_TEST[3] = (hex(8756476956956795876987), True) -RIPEMD160_TEST = [(0, False) for _ in range(6)] +RIPEMD160_TEST[0] = (hex(999999999999999999993), True) +RIPEMD160_TEST[1] = (hex(1111111111112), True) -ECRECOVER_TEST = [(0, False) for _ in range(9)] +ECRECOVER_TEST[0] = (hex(674837568743979857398564869), True) +ECRECOVER_TEST[1] = (hex(3487683476979311), False) -IDENTITY_TEST = [(0, False) for _ in range(4)] - -SHA256_TEST[0] = ( - 5555555555555555, - True, -) # These are Random numbers to check whether the 'if condition' is entered or not(True means entered) -SHA256_TEST[1] = (323232325445454546, True) -SHA256_TEST[2] = (34756834765834658, False) -SHA256_TEST[3] = (8756476956956795876987, True) -SHA256_TEST[4] = (5763467587689578369, True) -SHA256_TEST[5] = (948365957658767467857, False) - -RIPEMD160_TEST[0] = (1242435356364, True) -RIPEMD160_TEST[1] = (6732648654386435, True) -RIPEMD160_TEST[2] = (97457657536546465, False) -RIPEMD160_TEST[3] = (56436346436456546, True) -RIPEMD160_TEST[4] = (999999999999999999993, True) -RIPEMD160_TEST[5] = (1111111111112, False) - - -ECRECOVER_TEST[0] = (786428768768632537676, True) -ECRECOVER_TEST[1] = (4897983476979346779638, False) -ECRECOVER_TEST[2] = (674837568743979857398564869, True) -ECRECOVER_TEST[3] = (3487683476979311, False) -ECRECOVER_TEST[4] = (853729594875984769847369, True) -ECRECOVER_TEST[5] = (83579382475972439587, False) -ECRECOVER_TEST[6] = (8437589437695876985769, True) -ECRECOVER_TEST[7] = (9486794873598347697596, False) -ECRECOVER_TEST[8] = (346934876983476, True) - -IDENTITY_TEST[0] = (87426857369875698, True) -IDENTITY_TEST[1] = (476934798798347, False) - -IDENTITY_TEST[2] = (7346948379483769, True) -IDENTITY_TEST[3] = (83269476937987, False) +IDENTITY_TEST[0] = (hex(87426857369875698), True) +IDENTITY_TEST[1] = (hex(476934798798347), False) def _all_info(laser): @@ -99,10 +77,10 @@ def _all_info(laser): def _test_natives(laser_info, test_list, test_name): success = 0 for i, j in test_list: - if (str(i) in laser_info) == j: + if (str(i) in laser_info or str(int(i, 16)) in laser_info) == j: success += 1 else: - print("Failed: " + str(i) + " " + str(j)) + print("Failed:", str(int(i, 16)), str(j)) assert success == len(test_list) @@ -111,7 +89,7 @@ class NativeTests(BaseTestCase): def runTest(): disassembly = SolidityContract( - "./tests/native_tests.sol", solc_binary=Mythril._init_solc_binary("0.4.24") + "./tests/native_tests.sol", solc_binary=Mythril._init_solc_binary("0.5.0") ).disassembly account = Account("0x0000000000000000000000000000000000000000", disassembly) accounts = {account.address: account} @@ -120,8 +98,8 @@ class NativeTests(BaseTestCase): laser.sym_exec(account.address) laser_info = str(_all_info(laser)) - print("\n") + print(laser_info) _test_natives(laser_info, SHA256_TEST, "SHA256") _test_natives(laser_info, RIPEMD160_TEST, "RIPEMD160") _test_natives(laser_info, ECRECOVER_TEST, "ECRECOVER") diff --git a/tests/native_tests.sol b/tests/native_tests.sol index 762d8443..f321e38c 100644 --- a/tests/native_tests.sol +++ b/tests/native_tests.sol @@ -1,147 +1,90 @@ -pragma solidity ^0.4.17; +pragma solidity 0.5.0; contract Caller { - address public fixed_address; //Just some useless variables - address public stored_address; + //Just some useless variables + address public fixedAddress; + address public storedAddress; - uint256 statevar; //useless( but good for testing as they contribute as decoys) - bytes32 far; + //useless (but good for testing as they contribute as decoys) + uint256 private statevar; + bytes32 private far; - function Caller(address addr) { - fixed_address = addr; + constructor (address addr) public { + fixedAddress = addr; } - function thisisfine() public { //some typical function as a decoy - fixed_address.call(); + //some typical function as a decoy + function thisisfine() public { + (bool success, bytes memory mem) = fixedAddress.call(""); } - function sha256_test1() public { + + function sha256Test1() public returns (uint256) { uint256 i; - if(sha256('ab','c') == 0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad){ //True + if (sha256(abi.encodePacked("ab", "c")) == sha256("abc")) { + // True i = 5555555555555555; - } - - if(sha256('abc') == 0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad){ //True + } else { + // False i = 323232325445454546; } + return i; } - function sha256_test2() public { + + function sha256Test2() public returns (uint256) { uint256 i; - if(sha256('abd') == 0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad) { //False + if (sha256("abd") == sha256(abi.encodePacked("ab", "d"))) { + // True i = 34756834765834658; - } - if(sha256('ab','d') == 0xa52d159f262b2c6ddb724a61840befc36eb30c88877a4030b65cbe86298449c9) { //True + } else { + // False i = 8756476956956795876987; } - } - function sha256_test3() public { - uint256 i; - if(sha256('') == 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855) { //True - i = 5763467587689578369; - } - if(sha256('hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfdhhfdhhhhhh') == 0xe4ebd771f821e3277b77dcc39e94fe7172a5c9c8c12f8885c2d5513385a0a8b8) { //False - i = 948365957658767467857; - } + return i; } - function ripemd_test1() public { - uint256 i; - if(ripemd160('ab','c') == 0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc){ //True - i = 1242435356364; - } - if(ripemd160('abc') == 0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc){ //True - i = 6732648654386435; - } - } - function ripemd_test2() public { - uint256 i; - if(ripemd160('abd') == 0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc) { //False - i = 97457657536546465; - } - if(ripemd160('ab','d') == 0xb0a79cc77e333ea11974e105cd051d33836928b0) { //True - i = 56436346436456546; - } - } - function ripemd_test3() public { - uint256 i; - if(ripemd160('') == 0x9c1185a5c5e9fc54612808977ee8f548b2258d31) { //True - i = 999999999999999999993; - } - if(ripemd160('hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh') == 0x2d1b88a5daa5d138eb7bb14ee320010937f0ebe7) { //False - i = 1111111111112; - } - } + function ripemdTest() public returns (uint256) { + uint256 i; + bytes20 v1 = ripemd160(""); + bytes20 v2 = ripemd160("hhhhh"); - function ecrecover_test1() public { - bytes32 foobar = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8; - bytes memory prefix = "\x19Ethereum Signed Message:\n32"; - bytes32 prefixedHash = keccak256(prefix, foobar); + if (v1 != v2) { + // True + i = 999999999999999999993; + } else { + // False + i = 1111111111112; + } + return i; + } + + function ecrecoverTest() public returns (uint256) { + bytes32 foobar1 = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8; + bytes32 foobar2 = 0x38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e; uint8 v = 28; bytes32 r = 0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608; bytes32 s = 0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada; - if( ecrecover(prefixedHash, v, r, s) == 0x7156526fbd7a3c72969b54f64e42c10fbb768c8a) { //True - uint256 bignum = 786428768768632537676; - } - if( ecrecover(prefixedHash, v, r, s) == 0x7156526fbd7a3c72969b54f64e42c10fbb768c8b) { //False - uint256 small = 4897983476979346779638; - } - foobar = 0x38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e; - if( ecrecover( keccak256(foobar), v, r, s) == 0x0faf91ea0aaaa5377dfdf188b21409007f0b4019) { //True - uint256 dk = 674837568743979857398564869; - } - foobar = 0x38d18acb67d25c7bb9942764b62f18e17054f66a817bd4295423adf9ed98873e; //not same as above, minor change(7bb instead of 8bb) - if( ecrecover( keccak256(foobar), v, r, s) == 0x0faf91ea0aaaa5377dfdf188b21409007f0b4019) { //False - uint256 pk = 3487683476979311; + uint256 i; + address addr1 = ecrecover(keccak256(abi.encodePacked(foobar1)), v, r, s); + address addr2 = ecrecover(keccak256(abi.encodePacked(foobar1, foobar2)), v, r, s); + if (addr1 != addr2) { + // True + i = 674837568743979857398564869; + } else { + // False + i = 3487683476979311; } - + return i; } - function ecrecover_test2() public { - bytes32 foobar = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8; - bytes memory prefix = "\x19Ethereum Signed Message:\n32"; - bytes32 prefixedHash = keccak256(prefix, foobar); - uint8 v = 26; - bytes32 r = 0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608; - bytes32 s = 0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada; - if( ecrecover(prefixedHash, v, r, s) == 0x0000000000000000000000000000000000000000) { //True - uint256 bignum = 853729594875984769847369; - } - if( ecrecover(prefixedHash, v, r, s) == 0x7156526fbd7a3c72969b54f64e42c10fbb768c8b) { //False - uint256 small = 83579382475972439587; - } - } - function ecrecover_test3() public { - bytes32 foobar = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8; - bytes memory prefix = "\x19Ethereum Signed Message:\n32"; - bytes32 prefixedHash = keccak256(prefix, foobar); - uint8 v = 29; - bytes32 r = 0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608; - bytes32 s = 0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada; - if( ecrecover(prefixedHash, v, r, s) == 0x0000000000000000000000000000000000000000) { //True - uint256 bignum = 8437589437695876985769; - } - if( ecrecover(prefixedHash, v, r, s) == 0x7156526fbd7a3c72969b54f64e42c10fbb768c8b) { //False - uint256 small = 9486794873598347697596; - } + //identity is invoked here in compiler and not below + function needIdentityInvoke(uint sea) public returns (uint) { + return sea; } - function ecrecover_test4() public { - bytes32 foobar = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8; - bytes memory prefix = "\x19Ethereum Signed Message:\n32"; - bytes32 prefixedHash = keccak256(prefix, foobar); - uint8 v = 27; - bytes32 r = 0xfffffffffffffffffffffffffffffffffaaedce6af48a03bbfd25e8cd0364141; //greater than the max limit - bytes32 s = 0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada; - if( ecrecover(prefixedHash, v, r, s) == 0x0000000000000000000000000000000000000000) { //True - uint256 bignum = 346934876983476; - } - } - function need_identity_invoke(uint sea) returns (uint) { - return sea; //identity is invoked here in compiler and not below - } - function identity_function(int input) public returns(int out) { - assembly{ + function identityFunction(int input) public returns(int out) { + assembly { let x := mload(0x40) mstore(x, input) @@ -150,17 +93,16 @@ contract Caller { mstore(0x40, x) } } - function identity_test1() public{ - if(identity_function(100)==100) //True - uint256 smallnum = 87426857369875698; - if(identity_function(200)==100) //False - uint256 bignum = 476934798798347; - } - function identity_test2() public{ - if(identity_function(12345678)==12345678) //True - uint256 smallnum = 7346948379483769; - if(identity_function(74648796976)==4685987) //False - uint256 bignum = 83269476937987; - } + function identityTest1() public returns (uint256) { + uint256 i; + if (identityFunction(100) == 100) { + // True + i = 87426857369875698; + } else { + // False + i = 476934798798347; + } + return i; + } } diff --git a/tests/solidity_contract_test.py b/tests/solidity_contract_test.py index 7d72db90..6b55aad1 100644 --- a/tests/solidity_contract_test.py +++ b/tests/solidity_contract_test.py @@ -11,7 +11,7 @@ class SolidityContractTest(BaseTestCase): def test_get_source_info_without_name_gets_latest_contract_info(self): input_file = TEST_FILES / "multi_contracts.sol" contract = SolidityContract( - str(input_file), solc_binary=Mythril._init_solc_binary("0.4.24") + str(input_file), solc_binary=Mythril._init_solc_binary("0.5.0") ) code_info = contract.get_source_info(142) @@ -25,7 +25,7 @@ class SolidityContractTest(BaseTestCase): contract = SolidityContract( str(input_file), name="Transfer1", - solc_binary=Mythril._init_solc_binary("0.4.24"), + solc_binary=Mythril._init_solc_binary("0.5.0"), ) code_info = contract.get_source_info(142) @@ -39,11 +39,11 @@ class SolidityContractTest(BaseTestCase): contract = SolidityContract( str(input_file), name="AssertFail", - solc_binary=Mythril._init_solc_binary("0.4.24"), + solc_binary=Mythril._init_solc_binary("0.5.0"), ) - code_info = contract.get_source_info(62, constructor=True) + code_info = contract.get_source_info(70, constructor=True) self.assertEqual(code_info.filename, str(input_file)) self.assertEqual(code_info.lineno, 6) - self.assertEqual(code_info.code, "assert(var1>0)") + self.assertEqual(code_info.code, "assert(var1 > 0)") diff --git a/tests/svm_test.py b/tests/svm_test.py index e2f31a91..b687e944 100644 --- a/tests/svm_test.py +++ b/tests/svm_test.py @@ -84,7 +84,7 @@ class SVMTestCase(BaseTestCase): ) disassembly = SolidityContract( - str(input_file), solc_binary=Mythril._init_solc_binary("0.4.24") + str(input_file), solc_binary=Mythril._init_solc_binary("0.5.0") ).disassembly account = Account("0x0000000000000000000000000000000000000000", disassembly) accounts = {account.address: account} diff --git a/tests/testdata/input_contracts/calls.sol b/tests/testdata/input_contracts/calls.sol index a9069782..513e31fb 100644 --- a/tests/testdata/input_contracts/calls.sol +++ b/tests/testdata/input_contracts/calls.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.17; +pragma solidity 0.5.0; contract Caller { @@ -8,29 +8,29 @@ contract Caller { uint256 statevar; - function Caller(address addr) { + constructor(address addr) public { fixed_address = addr; } function thisisfine() public { - fixed_address.call(); + fixed_address.call(""); } function reentrancy() public { - fixed_address.call(); + fixed_address.call(""); statevar = 0; } - - function calluseraddress(address addr) { - addr.call(); + + function calluseraddress(address addr) public { + addr.call(""); + } + + function callstoredaddress() public { + stored_address.call(""); } - function callstoredaddress() { - stored_address.call(); - } - - function setstoredaddress(address addr) { + function setstoredaddress(address addr) public { stored_address = addr; - } - + } + } \ No newline at end of file diff --git a/tests/testdata/input_contracts/constructor_assert.sol b/tests/testdata/input_contracts/constructor_assert.sol index aff01b47..fa1e7018 100644 --- a/tests/testdata/input_contracts/constructor_assert.sol +++ b/tests/testdata/input_contracts/constructor_assert.sol @@ -1,8 +1,8 @@ -pragma solidity ^0.4.24; +pragma solidity 0.5.0; -contract AssertFail { - constructor(uint8 var1){ - assert(var1>0); - } +contract AssertFail { + constructor(uint8 var1) public { + assert(var1 > 0); + } } diff --git a/tests/testdata/input_contracts/environments.sol b/tests/testdata/input_contracts/environments.sol index d79b63f3..4a3a66a4 100644 --- a/tests/testdata/input_contracts/environments.sol +++ b/tests/testdata/input_contracts/environments.sol @@ -1,11 +1,11 @@ -pragma solidity ^0.4.16; +pragma solidity 0.5.0; contract IntegerOverflow2 { uint256 public count = 7; mapping(address => uint256) balances; - function batchTransfer(address[] _receivers, uint256 _value) public returns(bool){ + function batchTransfer(address[] memory _receivers, uint256 _value) public returns(bool){ uint cnt = _receivers.length; uint256 amount = uint256(cnt) * _value; diff --git a/tests/testdata/input_contracts/ether_send.sol b/tests/testdata/input_contracts/ether_send.sol index a814332b..59e1e245 100644 --- a/tests/testdata/input_contracts/ether_send.sol +++ b/tests/testdata/input_contracts/ether_send.sol @@ -1,3 +1,6 @@ +pragma solidity 0.5.0; + + contract Crowdfunding { mapping(address => uint) public balances; @@ -10,12 +13,12 @@ contract Crowdfunding { _; } - function crowdfunding() { + function crowdfunding() public { owner = msg.sender; } - function withdrawfunds() onlyOwner { - msg.sender.transfer(this.balance); + function withdrawfunds() public onlyOwner { + msg.sender.transfer(address(this).balance); } function invest() public payable { @@ -24,7 +27,7 @@ contract Crowdfunding { balances[msg.sender] += msg.value; } - function getBalance() public constant returns (uint) { + function getBalance() public view returns (uint) { return balances[msg.sender]; } diff --git a/tests/testdata/input_contracts/exceptions.sol b/tests/testdata/input_contracts/exceptions.sol index 95c42da0..aa925603 100644 --- a/tests/testdata/input_contracts/exceptions.sol +++ b/tests/testdata/input_contracts/exceptions.sol @@ -1,40 +1,43 @@ +pragma solidity 0.5.0; + + contract Exceptions { uint256[8] myarray; - function assert1() { + function assert1() public pure { uint256 i = 1; assert(i == 0); } - function assert2() { + function assert2() public pure { uint256 i = 1; assert(i > 0); } - function assert3(uint256 input) { + function assert3(uint256 input) public pure { assert(input != 23); } - function requireisfine(uint256 input) { + function requireisfine(uint256 input) public pure { require(input != 23); } - function divisionby0(uint256 input) { + function divisionby0(uint256 input) public pure { uint256 i = 1/input; } - function thisisfine(uint256 input) { + function thisisfine(uint256 input) public pure { if (input > 0) { uint256 i = 1/input; } - } + } - function arrayaccess(uint256 index) { + function arrayaccess(uint256 index) public view { uint256 i = myarray[index]; } - function thisisalsofind(uint256 index) { + function thisisalsofind(uint256 index) public view { if (index < 8) { uint256 i = myarray[index]; } diff --git a/tests/testdata/input_contracts/kinds_of_calls.sol b/tests/testdata/input_contracts/kinds_of_calls.sol index 80bedee6..2b1cb8c4 100644 --- a/tests/testdata/input_contracts/kinds_of_calls.sol +++ b/tests/testdata/input_contracts/kinds_of_calls.sol @@ -1,16 +1,19 @@ +pragma solidity 0.5.0; + + contract D { uint public n; address public sender; - function callSetN(address _e, uint _n) { - _e.call(bytes4(sha3("setN(uint256)")), _n); + function callSetN(address _e, uint _n) public { + _e.call(abi.encode(bytes4(keccak256("setN(uint256)")), _n)); } - function callcodeSetN(address _e, uint _n) { - _e.callcode(bytes4(sha3("setN(uint256)")), _n); + function callcodeSetN(address _e, uint _n) public view { + _e.staticcall(abi.encode(bytes4(keccak256("setN(uint256)")), _n)); } - function delegatecallSetN(address _e, uint _n) { - _e.delegatecall(bytes4(sha3("setN(uint256)")), _n); + function delegatecallSetN(address _e, uint _n) public { + _e.delegatecall(abi.encode(bytes4(keccak256("setN(uint256)")), _n)); } } diff --git a/tests/testdata/input_contracts/metacoin.sol b/tests/testdata/input_contracts/metacoin.sol index 8627c1d9..557c0d11 100644 --- a/tests/testdata/input_contracts/metacoin.sol +++ b/tests/testdata/input_contracts/metacoin.sol @@ -1,11 +1,12 @@ -pragma solidity ^0.4.17; +pragma solidity 0.5.0; + contract MetaCoin { mapping (address => uint) public balances; - function MetaCoin() public { + constructor() public { balances[msg.sender] = 10000; } - + function sendToken(address receiver, uint amount) public returns(bool successful){ if (balances[msg.sender] < amount) return false; balances[msg.sender] -= amount; diff --git a/tests/testdata/input_contracts/multi_contracts.sol b/tests/testdata/input_contracts/multi_contracts.sol index e4a4464a..c8c4e76a 100644 --- a/tests/testdata/input_contracts/multi_contracts.sol +++ b/tests/testdata/input_contracts/multi_contracts.sol @@ -1,17 +1,16 @@ -pragma solidity ^0.4.17; +pragma solidity 0.5.0; -contract Transfer1 { - function transfer() { - msg.sender.transfer(1 ether); - } +contract Transfer1 { + function transfer() public { + msg.sender.transfer(1 ether); + } } -contract Transfer2 { - - function transfer() { - msg.sender.transfer(2 ether); - } +contract Transfer2 { + function transfer() public { + msg.sender.transfer(2 ether); + } } diff --git a/tests/testdata/input_contracts/nonascii.sol b/tests/testdata/input_contracts/nonascii.sol index 73ccbe62..d8a28a61 100644 --- a/tests/testdata/input_contracts/nonascii.sol +++ b/tests/testdata/input_contracts/nonascii.sol @@ -1,6 +1,8 @@ -pragma solidity ^0.4.22; +pragma solidity 0.5.0; + + contract nonAscii { - function renderNonAscii () public pure returns (string) { + function renderNonAscii () public pure returns (string memory) { return "Хэллоу Ворлд"; } } \ No newline at end of file diff --git a/tests/testdata/input_contracts/origin.sol b/tests/testdata/input_contracts/origin.sol index 635c15f4..2ceb10f8 100644 --- a/tests/testdata/input_contracts/origin.sol +++ b/tests/testdata/input_contracts/origin.sol @@ -1,32 +1,33 @@ +pragma solidity 0.5.0; + + contract Origin { address public owner; - /** + /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ - function Origin() { + constructor() public { owner = msg.sender; } /** - * @dev Throws if called by any account other than the owner. + * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { - if (tx.origin != owner) { - throw; - } + require(tx.origin != owner); _; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. + * @param newOwner The address to transfer ownership to. */ - function transferOwnership(address newOwner) onlyOwner { + function transferOwnership(address newOwner) public onlyOwner { if (newOwner != address(0)) { owner = newOwner; } diff --git a/tests/testdata/input_contracts/overflow.sol b/tests/testdata/input_contracts/overflow.sol index f61a8b0e..d1d3d875 100644 --- a/tests/testdata/input_contracts/overflow.sol +++ b/tests/testdata/input_contracts/overflow.sol @@ -1,9 +1,12 @@ +pragma solidity 0.5.0; + + contract Over { mapping(address => uint) balances; uint public totalSupply; - function Token(uint _initialSupply) { + constructor(uint _initialSupply) public { balances[msg.sender] = totalSupply = _initialSupply; } @@ -14,7 +17,7 @@ contract Over { return true; } - function balanceOf(address _owner) public constant returns (uint balance) { + function balanceOf(address _owner) public view returns (uint balance) { return balances[_owner]; } } diff --git a/tests/testdata/input_contracts/returnvalue.sol b/tests/testdata/input_contracts/returnvalue.sol index 819580f3..88bd8805 100644 --- a/tests/testdata/input_contracts/returnvalue.sol +++ b/tests/testdata/input_contracts/returnvalue.sol @@ -1,13 +1,17 @@ +pragma solidity 0.5.0; + + contract ReturnValue { - address callee = 0xE0F7e56e62b4267062172495D7506087205A4229; + address public callee = 0xE0f7e56E62b4267062172495D7506087205A4229; - function callnotchecked() { - callee.call(); + function callnotchecked() public { + callee.call(""); } - function callchecked() { - require(callee.call()); + function callchecked() public { + (bool success, bytes memory data) = callee.call(""); + require(success); } } \ No newline at end of file diff --git a/tests/testdata/input_contracts/rubixi.sol b/tests/testdata/input_contracts/rubixi.sol index 91fda1b6..8e1567c6 100644 --- a/tests/testdata/input_contracts/rubixi.sol +++ b/tests/testdata/input_contracts/rubixi.sol @@ -1,152 +1,152 @@ -contract Rubixi { - - //Declare variables for storage critical to contract - uint private balance = 0; - uint private collectedFees = 0; - uint private feePercent = 10; - uint private pyramidMultiplier = 300; - uint private payoutOrder = 0; - - address private creator; - - //Sets creator - function DynamicPyramid() { - creator = msg.sender; - } - - modifier onlyowner { - if (msg.sender == creator) _; - } - - struct Participant { - address etherAddress; - uint payout; - } - - Participant[] private participants; +pragma solidity 0.5.0; - //Fallback function - function() { - init(); - } - - //init function run on fallback - function init() private { - //Ensures only tx with value of 1 ether or greater are processed and added to pyramid - if (msg.value < 1 ether) { - collectedFees += msg.value; - return; - } - - uint _fee = feePercent; - //50% fee rebate on any ether value of 50 or greater - if (msg.value >= 50 ether) _fee /= 2; - - addPayout(_fee); - } - //Function called for valid tx to the contract - function addPayout(uint _fee) private { - //Adds new address to participant array - participants.push(Participant(msg.sender, (msg.value * pyramidMultiplier) / 100)); - - //These statements ensure a quicker payout system to later pyramid entrants, so the pyramid has a longer lifespan - if (participants.length == 10) pyramidMultiplier = 200; - else if (participants.length == 25) pyramidMultiplier = 150; - - // collect fees and update contract balance - balance += (msg.value * (100 - _fee)) / 100; - collectedFees += (msg.value * _fee) / 100; - - //Pays earlier participiants if balance sufficient - while (balance > participants[payoutOrder].payout) { - uint payoutToSend = participants[payoutOrder].payout; - participants[payoutOrder].etherAddress.send(payoutToSend); - - balance -= participants[payoutOrder].payout; - payoutOrder += 1; - } - } +contract Rubixi { + //Declare variables for storage critical to contract + uint private balance = 0; + uint private collectedFees = 0; + uint private feePercent = 10; + uint private pyramidMultiplier = 300; + uint private payoutOrder = 0; + + address payable private creator; + + modifier onlyowner { + if (msg.sender == creator) _; + } + + struct Participant { + address payable etherAddress; + uint payout; + } + + //Fallback function + function() external payable { + init(); + } + + //Sets creator + function dynamicPyramid() public { + creator = msg.sender; + } + + Participant[] private participants; + + //Fee functions for creator + function collectAllFees() public onlyowner { + require(collectedFees == 0); + creator.transfer(collectedFees); + collectedFees = 0; + } + + function collectFeesInEther(uint _amt) public onlyowner { + _amt *= 1 ether; + if (_amt > collectedFees) collectAllFees(); + + require(collectedFees == 0); + + creator.transfer(_amt); + collectedFees -= _amt; + } + + function collectPercentOfFees(uint _pcent) public onlyowner { + require(collectedFees == 0 || _pcent > 100); + + uint feesToCollect = collectedFees / 100 * _pcent; + creator.transfer(feesToCollect); + collectedFees -= feesToCollect; + } + + //Functions for changing variables related to the contract + function changeOwner(address payable _owner) public onlyowner { + creator = _owner; + } + + function changeMultiplier(uint _mult) public onlyowner { + require(_mult > 300 || _mult < 120); + pyramidMultiplier = _mult; + } + + function changeFeePercentage(uint _fee) public onlyowner { + require(_fee > 10); + feePercent = _fee; + } + + //Functions to provide information to end-user using JSON interface or other interfaces + function currentMultiplier() public view returns (uint multiplier, string memory info) { + multiplier = pyramidMultiplier; + info = "This multiplier applies to you as soon as transaction is received, may be lowered to hasten payouts or increased if payouts are fast enough. Due to no float or decimals, multiplier is x100 for a fractional multiplier e.g. 250 is actually a 2.5x multiplier. Capped at 3x max and 1.2x min."; + } + + function currentFeePercentage() public view returns (uint fee, string memory info) { + fee = feePercent; + info = "Shown in % form. Fee is halved(50%) for amounts equal or greater than 50 ethers. (Fee may change, but is capped to a maximum of 10%)"; +} - //Fee functions for creator - function collectAllFees() onlyowner { - if (collectedFees == 0) throw; + function currentPyramidBalanceApproximately() public view returns (uint pyramidBalance, string memory info) { + pyramidBalance = balance / 1 ether; + info = "All balance values are measured in Ethers, note that due to no decimal placing, these values show up as integers only, within the contract itself you will get the exact decimal value you are supposed to"; + } - creator.send(collectedFees); - collectedFees = 0; - } + function nextPayoutWhenPyramidBalanceTotalsApproximately() public view returns (uint balancePayout) { + balancePayout = participants[payoutOrder].payout / 1 ether; + } - function collectFeesInEther(uint _amt) onlyowner { - _amt *= 1 ether; - if (_amt > collectedFees) collectAllFees(); + function feesSeperateFromBalanceApproximately() public view returns (uint fees) { + fees = collectedFees / 1 ether; + } - if (collectedFees == 0) throw; - - creator.send(_amt); - collectedFees -= _amt; - } + function totalParticipants() public view returns (uint count) { + count = participants.length; + } - function collectPercentOfFees(uint _pcent) onlyowner { - if (collectedFees == 0 || _pcent > 100) throw; + function numberOfParticipantsWaitingForPayout() public view returns (uint count) { + count = participants.length - payoutOrder; + } - uint feesToCollect = collectedFees / 100 * _pcent; - creator.send(feesToCollect); - collectedFees -= feesToCollect; + function participantDetails(uint orderInPyramid) public view returns (address addr, uint payout) { + if (orderInPyramid <= participants.length) { + addr = participants[orderInPyramid].etherAddress; + payout = participants[orderInPyramid].payout / 1 ether; } + } - //Functions for changing variables related to the contract - function changeOwner(address _owner) onlyowner { - creator = _owner; + //init function run on fallback + function init() private { + //Ensures only tx with value of 1 ether or greater are processed and added to pyramid + if (msg.value < 1 ether) { + collectedFees += msg.value; + return; } - function changeMultiplier(uint _mult) onlyowner { - if (_mult > 300 || _mult < 120) throw; + uint _fee = feePercent; + // 50% fee rebate on any ether value of 50 or greater + if (msg.value >= 50 ether) _fee /= 2; - pyramidMultiplier = _mult; - } + addPayout(_fee); + } - function changeFeePercentage(uint _fee) onlyowner { - if (_fee > 10) throw; + //Function called for valid tx to the contract + function addPayout(uint _fee) private { + //Adds new address to participant array + participants.push(Participant(msg.sender, (msg.value * pyramidMultiplier) / 100)); - feePercent = _fee; - } + // These statements ensure a quicker payout system to + // later pyramid entrants, so the pyramid has a longer lifespan + if (participants.length == 10) pyramidMultiplier = 200; + else if (participants.length == 25) pyramidMultiplier = 150; - //Functions to provide information to end-user using JSON interface or other interfaces - function currentMultiplier() constant returns(uint multiplier, string info) { - multiplier = pyramidMultiplier; - info = 'This multiplier applies to you as soon as transaction is received, may be lowered to hasten payouts or increased if payouts are fast enough. Due to no float or decimals, multiplier is x100 for a fractional multiplier e.g. 250 is actually a 2.5x multiplier. Capped at 3x max and 1.2x min.'; - } - - function currentFeePercentage() constant returns(uint fee, string info) { - fee = feePercent; - info = 'Shown in % form. Fee is halved(50%) for amounts equal or greater than 50 ethers. (Fee may change, but is capped to a maximum of 10%)'; - } + // collect fees and update contract balance + balance += (msg.value * (100 - _fee)) / 100; + collectedFees += (msg.value * _fee) / 100; - function currentPyramidBalanceApproximately() constant returns(uint pyramidBalance, string info) { - pyramidBalance = balance / 1 ether; - info = 'All balance values are measured in Ethers, note that due to no decimal placing, these values show up as integers only, within the contract itself you will get the exact decimal value you are supposed to'; - } - - function nextPayoutWhenPyramidBalanceTotalsApproximately() constant returns(uint balancePayout) { - balancePayout = participants[payoutOrder].payout / 1 ether; - } - - function feesSeperateFromBalanceApproximately() constant returns(uint fees) { - fees = collectedFees / 1 ether; - } - - function totalParticipants() constant returns(uint count) { - count = participants.length; - } - - function numberOfParticipantsWaitingForPayout() constant returns(uint count) { - count = participants.length - payoutOrder; - } + //Pays earlier participiants if balance sufficient + while (balance > participants[payoutOrder].payout) { + uint payoutToSend = participants[payoutOrder].payout; + participants[payoutOrder].etherAddress.transfer(payoutToSend); - function participantDetails(uint orderInPyramid) constant returns(address Address, uint Payout) { - if (orderInPyramid <= participants.length) { - Address = participants[orderInPyramid].etherAddress; - Payout = participants[orderInPyramid].payout / 1 ether; - } + balance -= participants[payoutOrder].payout; + payoutOrder += 1; } + } } diff --git a/tests/testdata/input_contracts/suicide.sol b/tests/testdata/input_contracts/suicide.sol index 1763365b..9e25678c 100644 --- a/tests/testdata/input_contracts/suicide.sol +++ b/tests/testdata/input_contracts/suicide.sol @@ -1,6 +1,9 @@ +pragma solidity 0.5.0; + + contract Suicide { - function kill(address addr) { + function kill(address payable addr) public { selfdestruct(addr); } diff --git a/tests/testdata/input_contracts/underflow.sol b/tests/testdata/input_contracts/underflow.sol index 6ecef5df..01ed4ef9 100644 --- a/tests/testdata/input_contracts/underflow.sol +++ b/tests/testdata/input_contracts/underflow.sol @@ -1,9 +1,12 @@ +pragma solidity 0.5.0; + + contract Under { mapping(address => uint) balances; uint public totalSupply; - function Token(uint _initialSupply) { + constructor(uint _initialSupply) public { balances[msg.sender] = totalSupply = _initialSupply; } @@ -14,7 +17,7 @@ contract Under { return true; } - function balanceOf(address _owner) public constant returns (uint balance) { + function balanceOf(address _owner) public view returns (uint balance) { return balances[_owner]; } } \ No newline at end of file diff --git a/tests/testdata/input_contracts/weak_random.sol b/tests/testdata/input_contracts/weak_random.sol index 88fc4e12..5acdd7ef 100644 --- a/tests/testdata/input_contracts/weak_random.sol +++ b/tests/testdata/input_contracts/weak_random.sol @@ -1,20 +1,21 @@ -pragma solidity ^0.4.16; +pragma solidity 0.5.0; + contract WeakRandom { struct Contestant { - address addr; + address payable addr; uint gameId; } - uint public constant prize = 2.5 ether; - uint public constant totalTickets = 50; - uint public constant pricePerTicket = prize / totalTickets; + uint public prize = 2.5 ether; + uint public totalTickets = 50; + uint public pricePerTicket = prize / totalTickets; uint public gameId = 1; uint public nextTicket = 0; mapping (uint => Contestant) public contestants; - function () payable public { + function () payable external { uint moneySent = msg.value; while (moneySent >= pricePerTicket && nextTicket < totalTickets) { @@ -37,10 +38,10 @@ contract WeakRandom { address seed1 = contestants[uint(block.coinbase) % totalTickets].addr; address seed2 = contestants[uint(msg.sender) % totalTickets].addr; uint seed3 = block.difficulty; - bytes32 randHash = keccak256(seed1, seed2, seed3); + bytes32 randHash = keccak256(abi.encode(seed1, seed2, seed3)); uint winningNumber = uint(randHash) % totalTickets; - address winningAddress = contestants[winningNumber].addr; + address payable winningAddress = contestants[winningNumber].addr; gameId++; nextTicket = 0;