Merge pull request #767 from ConsenSys/develop

Merge for v0.19.8
pull/818/head
Bernhard Mueller 6 years ago committed by GitHub
commit 6128931242
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .circleci/config.yml
  2. 3
      .gitattributes
  3. 2
      .gitignore
  4. 4
      Dockerfile
  5. 2
      MANIFEST.in
  6. 47
      mythril/analysis/analysis_utils.py
  7. 43
      mythril/analysis/modules/delegatecall.py
  8. 141
      mythril/analysis/modules/ether_thief.py
  9. 2
      mythril/analysis/modules/exceptions.py
  10. 305
      mythril/analysis/modules/external_calls.py
  11. 24
      mythril/analysis/modules/integer.py
  12. 134
      mythril/analysis/modules/suicide.py
  13. 32
      mythril/analysis/security.py
  14. 2
      mythril/analysis/solver.py
  15. 7
      mythril/analysis/symbolic.py
  16. 19
      mythril/disassembler/disassembly.py
  17. 3
      mythril/ether/__init__.py
  18. 65
      mythril/ether/evm.py
  19. 2
      mythril/ethereum/evmcontract.py
  20. 4
      mythril/ethereum/interface/leveldb/accountindexing.py
  21. 4
      mythril/ethereum/interface/leveldb/client.py
  22. 19
      mythril/ethereum/util.py
  23. 17
      mythril/interfaces/cli.py
  24. 10
      mythril/laser/ethereum/call.py
  25. 12
      mythril/laser/ethereum/instructions.py
  26. 4
      mythril/laser/ethereum/natives.py
  27. 4
      mythril/laser/ethereum/state/account.py
  28. 179
      mythril/laser/ethereum/state/calldata.py
  29. 4
      mythril/laser/ethereum/state/environment.py
  30. 3
      mythril/laser/ethereum/state/global_state.py
  31. 4
      mythril/laser/ethereum/transaction/concolic.py
  32. 18
      mythril/laser/ethereum/transaction/symbolic.py
  33. 10
      mythril/laser/ethereum/transaction/transaction_models.py
  34. 100
      mythril/mythril.py
  35. 0
      mythril/solidity/__init__.py
  36. 6
      mythril/solidity/soliditycontract.py
  37. 375
      mythril/support/signatures.py
  38. 0
      mythril/support/support_utils.py
  39. 12
      mythril/support/truffle.py
  40. BIN
      signatures.db
  41. 396809
      signatures.json
  42. 40
      solidity_examples/BECToken.sol
  43. 104
      solidity_examples/WalletLibrary.sol
  44. 18
      solidity_examples/calls.sol
  45. 6
      solidity_examples/etherstore.sol
  46. 19
      solidity_examples/exceptions.sol
  47. 9
      solidity_examples/hashforether.sol
  48. 11
      solidity_examples/origin.sol
  49. 14
      solidity_examples/returnvalue.sol
  50. 264
      solidity_examples/rubixi.sol
  51. 5
      solidity_examples/suicide.sol
  52. 3
      solidity_examples/timelock.sol
  53. 7
      solidity_examples/token.sol
  54. 17
      solidity_examples/weak_random.sol
  55. 8
      tests/__init__.py
  56. 268
      tests/analysis/test_delegatecall.py
  57. 14
      tests/cmd_line_test.py
  58. 6
      tests/disassembler/disassembly.py
  59. 2
      tests/disassembler_test.py
  60. 23
      tests/evmcontract_test.py
  61. 14
      tests/graph_test.py
  62. 1
      tests/laser/evm_testsuite/evm_test.py
  63. 80
      tests/laser/state/calldata_test.py
  64. 15
      tests/laser/transaction/create_transaction_test.py
  65. 4
      tests/mythril_dir/config.ini
  66. BIN
      tests/mythril_dir/signatures.db.example
  67. 396809
      tests/mythril_dir/signatures.json.example
  68. 70
      tests/native_test.py
  69. 196
      tests/native_tests.sol
  70. 10
      tests/report_test.py
  71. 3
      tests/rpc_test.py
  72. 23
      tests/solidity_contract_test.py
  73. 19
      tests/svm_test.py
  74. 2
      tests/testdata/compile.py
  75. 21
      tests/testdata/input_contracts/calls.sol
  76. 10
      tests/testdata/input_contracts/constructor_assert.sol
  77. 4
      tests/testdata/input_contracts/environments.sol
  78. 11
      tests/testdata/input_contracts/ether_send.sol
  79. 19
      tests/testdata/input_contracts/exceptions.sol
  80. 15
      tests/testdata/input_contracts/kinds_of_calls.sol
  81. 5
      tests/testdata/input_contracts/metacoin.sol
  82. 19
      tests/testdata/input_contracts/multi_contracts.sol
  83. 6
      tests/testdata/input_contracts/nonascii.sol
  84. 11
      tests/testdata/input_contracts/origin.sol
  85. 9
      tests/testdata/input_contracts/overflow.sol
  86. 14
      tests/testdata/input_contracts/returnvalue.sol
  87. 264
      tests/testdata/input_contracts/rubixi.sol
  88. 5
      tests/testdata/input_contracts/suicide.sol
  89. 7
      tests/testdata/input_contracts/underflow.sol
  90. 17
      tests/testdata/input_contracts/weak_random.sol
  91. 127
      tests/testdata/outputs_expected/calls.sol.o.json
  92. 46
      tests/testdata/outputs_expected/calls.sol.o.markdown
  93. 42
      tests/testdata/outputs_expected/calls.sol.o.text
  94. 68
      tests/testdata/outputs_expected/environments.sol.o.json
  95. 27
      tests/testdata/outputs_expected/ether_send.sol.o.json
  96. 26
      tests/testdata/outputs_expected/ether_send.sol.o.markdown
  97. 22
      tests/testdata/outputs_expected/ether_send.sol.o.text
  98. 16
      tests/testdata/outputs_expected/exceptions.sol.o.json
  99. 55
      tests/testdata/outputs_expected/kinds_of_calls.sol.o.json
  100. 4
      tests/testdata/outputs_expected/kinds_of_calls.sol.o.markdown
  101. Some files were not shown because too many files have changed in this diff Show More

@ -51,6 +51,7 @@ jobs:
environment: environment:
LC_ALL: en_US.ASCII LC_ALL: en_US.ASCII
LANG: en_US.ASCII LANG: en_US.ASCII
MYTHRIL_DIR: '/home/mythril'
- store_test_results: - store_test_results:
path: /home/mythril/.tox/output path: /home/mythril/.tox/output

3
.gitattributes vendored

@ -1,2 +1,5 @@
tests/testdata/* linguist-detectable=false tests/testdata/* linguist-detectable=false
static/* linguist-documentation static/* linguist-documentation
# Solidity
*.sol linguist-language=Solidity

2
.gitignore vendored

@ -176,7 +176,7 @@ lol*
coverage_html_report/ coverage_html_report/
tests/testdata/outputs_current/ tests/testdata/outputs_current/
tests/testdata/outputs_current_laser_result/ tests/testdata/outputs_current_laser_result/
tests/mythril_dir/signatures.json tests/mythril_dir/signatures.db
# VSCode # VSCode
.vscode .vscode

@ -1,6 +1,9 @@
FROM ubuntu:bionic FROM ubuntu:bionic
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y \
libsqlite3-0 \
libsqlite3-dev \
&& apt-get install -y \ && apt-get install -y \
build-essential \ build-essential \
locales \ locales \
@ -16,6 +19,7 @@ RUN apt-get update \
python3-dev \ python3-dev \
pandoc \ pandoc \
git \ git \
wget \
&& ln -s /usr/bin/python3 /usr/local/bin/python && ln -s /usr/bin/python3 /usr/local/bin/python
COPY ./requirements.txt /opt/mythril/requirements.txt COPY ./requirements.txt /opt/mythril/requirements.txt

@ -1,2 +1,2 @@
include mythril/disassembler/signatures.json include mythril/disassembler/signatures.db
include mythril/analysis/templates/* include mythril/analysis/templates/*

@ -1,47 +0,0 @@
import re
from typing import List
from z3 import *
from mythril.laser.ethereum.transaction import ContractCreationTransaction
from mythril.laser.ethereum.state.global_state import GlobalState
def get_non_creator_constraints(state: GlobalState) -> (List, bool):
"""
Get constraints which say that the caller isn't the creator of the contract
:param state: The state
:return: tuple of (constraints, bool) where the bool says whether the caller is constrained or not
"""
not_creator_constraints = []
creator = None
if isinstance(
state.world_state.transaction_sequence[0], ContractCreationTransaction
):
creator = state.world_state.transaction_sequence[0].caller
if creator is not None:
for transaction in state.world_state.transaction_sequence[1:]:
not_creator_constraints.append(
Not(Extract(159, 0, transaction.caller) == Extract(159, 0, creator))
)
not_creator_constraints.append(
Not(Extract(159, 0, transaction.caller) == 0)
)
else:
for transaction in state.world_state.transaction_sequence:
not_creator_constraints.append(
Not(Extract(159, 0, transaction.caller) == 0)
)
if not has_caller_check_constraint(state.mstate.constraints):
return [], True
return not_creator_constraints, False
def has_caller_check_constraint(constraints: List) -> bool:
"""
Checks whether the caller is constrained to a value or not
"""
for constraint in constraints:
if re.search(r"caller", str(constraint)) and re.search(
r"[0-9]{20}", str(constraint)
):
return False
return True

@ -37,9 +37,6 @@ class DelegateCallModule(DetectionModule):
if meminstart.type == VarType.CONCRETE: if meminstart.type == VarType.CONCRETE:
issues += self._concrete_call(call, state, address, meminstart) issues += self._concrete_call(call, state, address, meminstart)
if call.to.type == VarType.SYMBOLIC:
issues += self._symbolic_call(call, state, address, statespace)
return issues return issues
def _concrete_call(self, call, state, address, meminstart): def _concrete_call(self, call, state, address, meminstart):
@ -68,45 +65,5 @@ class DelegateCallModule(DetectionModule):
return [issue] return [issue]
def _symbolic_call(self, call, state, address, statespace):
issue = Issue(
contract=call.node.contract_name,
function_name=call.node.function_name,
address=address,
swc_id=DELEGATECALL_TO_UNTRUSTED_CONTRACT,
bytecode=state.environment.code.bytecode,
title=call.type + " to a user-supplied address",
gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
)
if "calldata" in str(call.to):
issue.description = "This contract delegates execution to a contract address obtained from calldata."
else:
m = re.search(r"storage_([a-z0-9_&^]+)", str(call.to))
if m:
idx = m.group(1)
func = statespace.find_storage_write(
state.environment.active_account.address, idx
)
if func:
issue.description = (
"This contract delegates execution to a contract address in storage slot "
+ str(idx)
+ ". This storage slot can be written to by calling the function `"
+ func
+ "`."
)
else:
logging.debug(
"[DELEGATECALL] No storage writes to index " + str(idx)
)
issue.description += " Be aware that the called contract gets unrestricted access to this contract's state."
return [issue]
detector = DelegateCallModule() detector = DelegateCallModule()

@ -1,13 +1,13 @@
from mythril.analysis.ops import * from mythril.analysis.ops import *
from mythril.analysis import solver from mythril.analysis import solver
from mythril.analysis.analysis_utils import get_non_creator_constraints
from mythril.analysis.report import Issue from mythril.analysis.report import Issue
from mythril.analysis.swc_data import UNPROTECTED_ETHER_WITHDRAWAL from mythril.analysis.swc_data import UNPROTECTED_ETHER_WITHDRAWAL
from mythril.analysis.modules.base import DetectionModule from mythril.analysis.modules.base import DetectionModule
from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.exceptions import UnsatError from mythril.exceptions import UnsatError
from z3 import BitVecVal, UGT from z3 import BitVecVal, UGT, Sum
import logging import logging
from copy import copy
DESCRIPTION = """ DESCRIPTION = """
@ -22,7 +22,56 @@ An issue is reported if:
""" """
ARBITRARY_SENDER_ADDRESS = 0xAAAAAAAABBBBBBBBBCCCCCCCDDDDDDDDEEEEEEEE
def _analyze_state(state):
instruction = state.get_current_instruction()
node = state.node
if instruction["opcode"] != "CALL":
return []
call_value = state.mstate.stack[-3]
target = state.mstate.stack[-2]
eth_sent_total = BitVecVal(0, 256)
constraints = copy(node.constraints)
for tx in state.world_state.transaction_sequence:
if tx.caller == 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF:
# There's sometimes no overflow check on balances added.
# But we don't care about attacks that require more 2^^256 ETH to be sent.
constraints += [BVAddNoOverflow(eth_sent_total, tx.call_value, False)]
eth_sent_total = Sum(eth_sent_total, tx.call_value)
constraints += [UGT(call_value, eth_sent_total), target == state.environment.sender]
try:
transaction_sequence = solver.get_transaction_sequence(state, constraints)
debug = str(transaction_sequence)
issue = Issue(
contract=node.contract_name,
function_name=node.function_name,
address=instruction["address"],
swc_id=UNPROTECTED_ETHER_WITHDRAWAL,
title="Ether thief",
_type="Warning",
bytecode=state.environment.code.bytecode,
description="Arbitrary senders other than the contract creator can withdraw ETH from the contract"
+ " account without previously having sent an equivalent amount of ETH to it. This is likely to be"
+ " a vulnerability.",
debug=debug,
gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
)
except UnsatError:
logging.debug("[ETHER_THIEF] no model found")
return []
return [issue]
class EtherThief(DetectionModule): class EtherThief(DetectionModule):
@ -32,83 +81,17 @@ class EtherThief(DetectionModule):
swc_id=UNPROTECTED_ETHER_WITHDRAWAL, swc_id=UNPROTECTED_ETHER_WITHDRAWAL,
hooks=["CALL"], hooks=["CALL"],
description=DESCRIPTION, description=DESCRIPTION,
entrypoint="callback",
) )
self._issues = []
def execute(self, state: GlobalState):
self._issues.extend(_analyze_state(state))
return self.issues
def execute(self, state_space): @property
logging.debug("Executing module: %s", self.name) def issues(self):
issues = [] return self._issues
for k in state_space.nodes:
node = state_space.nodes[k]
for state in node.states:
issues += self._analyze_state(state, node)
return issues
@staticmethod
def _analyze_state(state, node):
issues = []
instruction = state.get_current_instruction()
if instruction["opcode"] != "CALL":
return []
call_value = state.mstate.stack[-3]
target = state.mstate.stack[-2]
not_creator_constraints, constrained = get_non_creator_constraints(state)
if constrained:
return []
eth_sent_total = BitVecVal(0, 256)
for tx in state.world_state.transaction_sequence[1:]:
eth_sent_total += tx.call_value
try:
model = solver.get_model(
node.constraints
+ not_creator_constraints
+ [
UGT(call_value, eth_sent_total),
state.environment.sender == ARBITRARY_SENDER_ADDRESS,
target == state.environment.sender,
]
)
transaction_sequence = solver.get_transaction_sequence(
state,
node.constraints
+ not_creator_constraints
+ [
call_value > eth_sent_total,
state.environment.sender == ARBITRARY_SENDER_ADDRESS,
target == state.environment.sender,
],
)
debug = "Transaction Sequence: " + str(transaction_sequence)
issue = Issue(
contract=node.contract_name,
function_name=node.function_name,
address=instruction["address"],
swc_id=UNPROTECTED_ETHER_WITHDRAWAL,
title="Ether thief",
_type="Warning",
bytecode=state.environment.code.bytecode,
description="Arbitrary senders other than the contract creator can withdraw ETH from the contract"
+ " account without previously having sent an equivalent amount of ETH to it. This is likely to be"
+ " a vulnerability.",
debug=debug,
gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
)
issues.append(issue)
except UnsatError:
logging.debug("[ETHER_THIEF] no model found")
return issues
detector = EtherThief() detector = EtherThief()

@ -42,7 +42,7 @@ class ReachableExceptionsModule(DetectionModule):
"Use `require()` for regular input checking." "Use `require()` for regular input checking."
) )
debug = "Transaction Sequence: " + str( debug = str(
solver.get_transaction_sequence(state, node.constraints) solver.get_transaction_sequence(state, node.constraints)
) )

@ -1,218 +1,111 @@
from z3 import * from z3 import *
from mythril.analysis.ops import *
from mythril.analysis.report import Issue from mythril.analysis.report import Issue
from mythril.analysis import solver from mythril.analysis import solver
from mythril.analysis.swc_data import REENTRANCY from mythril.analysis.swc_data import REENTRANCY
from mythril.analysis.modules.base import DetectionModule from mythril.analysis.modules.base import DetectionModule
import re from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.exceptions import UnsatError
import logging import logging
from mythril.laser.ethereum.cfg import JumpType
DESCRIPTION = """
class ExternalCallModule(DetectionModule): Search for low level calls (e.g. call.value()) that forward all gas to the callee.
def __init__(self, max_search_depth=64): Report a warning if the callee address can be set by the sender, otherwise create
an informational issue.
"""
def _analyze_state(state):
node = state.node
gas = state.mstate.stack[-1]
to = state.mstate.stack[-2]
address = state.get_current_instruction()["address"]
try:
constraints = node.constraints
transaction_sequence = solver.get_transaction_sequence(
state, constraints + [UGT(gas, 2300)]
)
# Check whether we can also set the callee address
try:
constraints += [to == 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF]
transaction_sequence = solver.get_transaction_sequence(state, constraints)
debug = str(transaction_sequence)
description = (
"The contract executes a function call with high gas to a user-supplied address. "
"Note that the callee can contain arbitrary code and may re-enter any function in this contract. "
"Review the business logic carefully to prevent unanticipated effects on the contract state."
)
issue = Issue(
contract=node.contract_name,
function_name=node.function_name,
address=address,
swc_id=REENTRANCY,
title="External call to user-supplied address",
_type="Warning",
bytecode=state.environment.code.bytecode,
description=description,
debug=debug,
gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
)
except UnsatError:
logging.debug(
"[EXTERNAL_CALLS] Callee address cannot be modified. Reporting informational issue."
)
debug = str(transaction_sequence)
description = (
"The contract executes a function call to an external address. "
"Verify that the code at this address is trusted and immutable."
)
issue = Issue(
contract=node.contract_name,
function_name=state.node.function_name,
address=address,
swc_id=REENTRANCY,
title="External call",
_type="Informational",
bytecode=state.environment.code.bytecode,
description=description,
debug=debug,
gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
)
except UnsatError:
logging.debug("[EXTERNAL_CALLS] No model found.")
return []
return [issue]
class ExternalCalls(DetectionModule):
def __init__(self):
super().__init__( super().__init__(
name="External Calls", name="External calls",
swc_id=REENTRANCY, swc_id=REENTRANCY,
hooks=["CALL"], hooks=["CALL"],
description="Check for call.value()() to external addresses", description=(DESCRIPTION),
entrypoint="callback",
) )
self.max_search_depth = max_search_depth self._issues = []
self.calls_visited = []
def execute(self, state: GlobalState):
def search_children( self._issues.extend(_analyze_state(state))
self, statespace, node, transaction_id, start_index=0, depth=0, results=None return self.issues
):
if results is None: @property
results = [] def issues(self):
logging.debug("SEARCHING NODE %d", node.uid) return self._issues
if depth < self.max_search_depth:
detector = ExternalCalls()
n_states = len(node.states)
if n_states > start_index:
for j in range(start_index, n_states):
if (
node.states[j].get_current_instruction()["opcode"] == "SSTORE"
and node.states[j].current_transaction.id == transaction_id
):
results.append(
node.states[j].get_current_instruction()["address"]
)
children = []
for edge in statespace.edges:
if edge.node_from == node.uid and edge.type != JumpType.Transaction:
children.append(statespace.nodes[edge.node_to])
if len(children):
for node in children:
results += self.search_children(
statespace,
node,
transaction_id,
depth=depth + 1,
results=results,
)
return results
def execute(self, statespace):
issues = []
for call in statespace.calls:
state = call.state
address = state.get_current_instruction()["address"]
if call.type == "CALL":
logging.debug(
"[EXTERNAL_CALLS] Call to: %s, value = %s, gas = %s"
% (str(call.to), str(call.value), str(call.gas))
)
if (
call.to.type == VarType.SYMBOLIC
and (call.gas.type == VarType.CONCRETE and call.gas.val > 2300)
or (
call.gas.type == VarType.SYMBOLIC
and "2300" not in str(call.gas)
)
):
description = "This contract executes a message call to "
target = str(call.to)
user_supplied = False
if "calldata" in target or "caller" in target:
if "calldata" in target:
description += (
"an address provided as a function argument. "
)
else:
description += "the address of the transaction sender. "
user_supplied = True
else:
m = re.search(r"storage_([a-z0-9_&^]+)", str(call.to))
if m:
idx = m.group(1)
func = statespace.find_storage_write(
state.environment.active_account.address, idx
)
if func:
description += (
"an address found at storage slot "
+ str(idx)
+ ". "
+ "This storage slot can be written to by calling the function `"
+ func
+ "`. "
)
user_supplied = True
if user_supplied:
description += (
"Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. "
"Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state."
)
issue = Issue(
contract=call.node.contract_name,
function_name=call.node.function_name,
address=address,
title="Message call to external contract",
_type="Warning",
description=description,
bytecode=state.environment.code.bytecode,
swc_id=REENTRANCY,
gas_used=(
state.mstate.min_gas_used,
state.mstate.max_gas_used,
),
)
else:
description += "to another contract. Make sure that the called contract is trusted and does not execute user-supplied code."
issue = Issue(
contract=call.node.contract_name,
function_name=call.node.function_name,
address=address,
title="Message call to external contract",
_type="Informational",
description=description,
bytecode=state.environment.code.bytecode,
swc_id=REENTRANCY,
gas_used=(
state.mstate.min_gas_used,
state.mstate.max_gas_used,
),
)
issues.append(issue)
if address not in self.calls_visited:
self.calls_visited.append(address)
logging.debug(
"[EXTERNAL_CALLS] Checking for state changes starting from "
+ call.node.function_name
)
# Check for SSTORE in remaining instructions in current node & nodes down the CFG
state_change_addresses = self.search_children(
statespace,
call.node,
call.state.current_transaction.id,
call.state_index + 1,
depth=0,
results=[],
)
logging.debug(
"[EXTERNAL_CALLS] Detected state changes at addresses: "
+ str(state_change_addresses)
)
if len(state_change_addresses):
for address in state_change_addresses:
description = (
"The contract account state is changed after an external call. "
"Consider that the called contract could re-enter the function before this "
"state change takes place. This can lead to business logic vulnerabilities."
)
issue = Issue(
contract=call.node.contract_name,
function_name=call.node.function_name,
address=address,
title="State change after external call",
_type="Warning",
description=description,
bytecode=state.environment.code.bytecode,
swc_id=REENTRANCY,
gas_used=(
state.mstate.min_gas_used,
state.mstate.max_gas_used,
),
)
issues.append(issue)
return issues
detector = ExternalCallModule()

@ -108,8 +108,8 @@ class IntegerOverflowUnderflowModule(DetectionModule):
operator operator
) )
try: try:
issue.debug = "Transaction Sequence: " + str( issue.debug = str(
solver.get_transaction_sequence(state, node.constraints) solver.get_transaction_sequence(state, node.constraints + [constraint])
) )
except UnsatError: except UnsatError:
return issues return issues
@ -167,33 +167,19 @@ class IntegerOverflowUnderflowModule(DetectionModule):
constraints = copy.deepcopy(node.constraints) constraints = copy.deepcopy(node.constraints)
# Filter for patterns that indicate benign underflows
# Pattern 1: (96 + calldatasize_MAIN) - (96), where (96 + calldatasize_MAIN) would underflow if calldatasize is very large.
# Pattern 2: (256*If(1 & storage_0 == 0, 1, 0)) - 1, this would underlow if storage_0 = 0
if type(op0) == int and type(op1) == int: if type(op0) == int and type(op1) == int:
return [] return []
if re.search(r"calldatasize_", str(op0)):
return []
if re.search(r"256\*.*If\(1", str(op0), re.DOTALL) or re.search(
r"256\*.*If\(1", str(op1), re.DOTALL
):
return []
if re.search(r"32 \+.*calldata", str(op0), re.DOTALL) or re.search(
r"32 \+.*calldata", str(op1), re.DOTALL
):
return []
logging.debug( logging.debug(
"[INTEGER_UNDERFLOW] Checking SUB {0}, {1} at address {2}".format( "[INTEGER_UNDERFLOW] Checking SUB {0}, {1} at address {2}".format(
str(op0), str(op1), str(instruction["address"]) str(op0), str(op1), str(instruction["address"])
) )
) )
allowed_types = [int, BitVecRef, BitVecNumRef] allowed_types = [int, BitVecRef, BitVecNumRef]
if type(op0) in allowed_types and type(op1) in allowed_types: if type(op0) in allowed_types and type(op1) in allowed_types:
constraints.append(UGT(op1, op0)) constraints.append(Not(BVSubNoUnderflow(op0, op1, signed=False)))
try: try:
model = solver.get_model(constraints) model = solver.get_model(constraints)
@ -223,7 +209,7 @@ class IntegerOverflowUnderflowModule(DetectionModule):
"The subtraction can result in an integer underflow.\n" "The subtraction can result in an integer underflow.\n"
) )
issue.debug = "Transaction Sequence: " + str( issue.debug = str(
solver.get_transaction_sequence(state, node.constraints) solver.get_transaction_sequence(state, node.constraints)
) )
issues.append(issue) issues.append(issue)

@ -1,20 +1,60 @@
from mythril.analysis import solver from mythril.analysis import solver
from mythril.analysis.analysis_utils import get_non_creator_constraints
from mythril.analysis.ops import * from mythril.analysis.ops import *
from mythril.analysis.report import Issue from mythril.analysis.report import Issue
from mythril.analysis.swc_data import UNPROTECTED_SELFDESTRUCT from mythril.analysis.swc_data import UNPROTECTED_SELFDESTRUCT
from mythril.exceptions import UnsatError from mythril.exceptions import UnsatError
from mythril.analysis.modules.base import DetectionModule from mythril.analysis.modules.base import DetectionModule
from mythril.laser.ethereum.transaction import ContractCreationTransaction from mythril.laser.ethereum.state.global_state import GlobalState
import re
import logging import logging
DESCRIPTION = """
Check if the contact can be 'accidentally' killed by anyone.
For kill-able contracts, also check whether it is possible to direct the contract balance to the attacker.
""" """
MODULE DESCRIPTION:
""" def _analyze_state(state):
logging.info("Suicide module: Analyzing suicide instruction")
node = state.node
instruction = state.get_current_instruction()
to = state.mstate.stack[-1]
logging.debug("[SUICIDE] SUICIDE in function " + node.function_name)
try:
try:
transaction_sequence = solver.get_transaction_sequence(
state,
node.constraints + [to == 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF],
)
description = "Anyone can kill this contract and withdraw its balance to their own account."
except UnsatError:
transaction_sequence = solver.get_transaction_sequence(
state, node.constraints
)
description = (
"The contract can be killed by anyone. Don't accidentally kill it."
)
debug = str(transaction_sequence)
issue = Issue(
contract=node.contract_name,
function_name=node.function_name,
address=instruction["address"],
swc_id=UNPROTECTED_SELFDESTRUCT,
bytecode=state.environment.code.bytecode,
title="Unchecked SUICIDE",
_type="Warning",
description=description,
debug=debug,
gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
)
return [issue]
except UnsatError:
logging.info("[UNCHECKED_SUICIDE] no model found")
return []
class SuicideModule(DetectionModule): class SuicideModule(DetectionModule):
@ -23,82 +63,18 @@ class SuicideModule(DetectionModule):
name="Unprotected Suicide", name="Unprotected Suicide",
swc_id=UNPROTECTED_SELFDESTRUCT, swc_id=UNPROTECTED_SELFDESTRUCT,
hooks=["SUICIDE"], hooks=["SUICIDE"],
description=( description=(DESCRIPTION),
"Check for SUICIDE instructions that either can be reached by anyone, " entrypoint="callback",
"or where msg.sender is checked against a tainted storage index (i.e. "
"there's a write to that index is unconstrained by msg.sender)."
),
) )
self._issues = []
def execute(self, state_space): def execute(self, state: GlobalState):
self._issues.extend(_analyze_state(state))
logging.debug("Executing module: UNCHECKED_SUICIDE") return self.issues
issues = []
for k in state_space.nodes:
node = state_space.nodes[k]
for state in node.states:
issues += self._analyze_state(state, node)
return issues
def _analyze_state(self, state, node):
issues = []
instruction = state.get_current_instruction()
if instruction["opcode"] != "SUICIDE":
return []
to = state.mstate.stack[-1]
logging.debug("[UNCHECKED_SUICIDE] suicide in function " + node.function_name)
description = "A reachable SUICIDE instruction was detected. "
if "caller" in str(to):
description += "The remaining Ether is sent to the caller's address.\n"
elif "storage" in str(to):
description += "The remaining Ether is sent to a stored address.\n"
elif "calldata" in str(to):
description += "The remaining Ether is sent to an address provided as a function argument.\n"
elif type(to) == BitVecNumRef:
description += "The remaining Ether is sent to: " + hex(to.as_long()) + "\n"
else:
description += "The remaining Ether is sent to: " + str(to) + "\n"
not_creator_constraints, constrained = get_non_creator_constraints(state)
if constrained:
return []
try:
model = solver.get_model(node.constraints + not_creator_constraints)
debug = "Transaction Sequence: " + str(
solver.get_transaction_sequence(
state, node.constraints + not_creator_constraints
)
)
issue = Issue(
contract=node.contract_name,
function_name=node.function_name,
address=instruction["address"],
swc_id=UNPROTECTED_SELFDESTRUCT,
bytecode=state.environment.code.bytecode,
title="Unchecked SUICIDE",
_type="Warning",
description=description,
debug=debug,
gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
)
issues.append(issue)
except UnsatError:
logging.debug("[UNCHECKED_SUICIDE] no model found")
return issues @property
def issues(self):
return self._issues
detector = SuicideModule() detector = SuicideModule()

@ -9,6 +9,12 @@ import logging
OPCODE_LIST = [c[0] for _, c in opcodes.items()] OPCODE_LIST = [c[0] for _, c in opcodes.items()]
def reset_callback_modules():
modules = get_detection_modules("callback")
for module in modules:
module.detector._issues = []
def get_detection_module_hooks(): def get_detection_module_hooks():
hook_dict = defaultdict(list) hook_dict = defaultdict(list)
_modules = get_detection_modules(entrypoint="callback") _modules = get_detection_modules(entrypoint="callback")
@ -35,17 +41,18 @@ def get_detection_modules(entrypoint, include_modules=()):
_modules = [] _modules = []
if not include_modules: if not include_modules:
for loader, module_name, _ in pkgutil.walk_packages(modules.__path__):
for loader, name, _ in pkgutil.walk_packages(modules.__path__): if module_name != "base":
module = loader.find_module(name).load_module(name) module = importlib.import_module(
if module.__name__ != "base" and module.detector.entrypoint == entrypoint: "mythril.analysis.modules." + module_name
_modules.append(module) )
if module.detector.entrypoint == entrypoint:
_modules.append(module)
else: else:
for module_name in include_modules: for module_name in include_modules:
module = importlib.import_module(module_name, modules) module = importlib.import_module("mythril.analysis.modules." + module_name)
if module.__name__ != "base" and module.detector.entrypoint == entrypoint:
_modules.append(module) _modules.append(module)
logging.info("Found %s detection modules", len(_modules)) logging.info("Found %s detection modules", len(_modules))
return _modules return _modules
@ -61,4 +68,11 @@ def fire_lasers(statespace, module_names=()):
logging.info("Executing " + module.detector.name) logging.info("Executing " + module.detector.name)
issues += module.detector.execute(statespace) issues += module.detector.execute(statespace)
for module in get_detection_modules(
entrypoint="callback", include_modules=module_names
):
logging.debug("Retrieving results for " + module.detector.name)
issues += module.detector.issues
reset_callback_modules()
return issues return issues

@ -103,7 +103,7 @@ def get_transaction_sequence(global_state, constraints):
concrete_transactions[tx_id]["calldata"] = "0x" + "".join( concrete_transactions[tx_id]["calldata"] = "0x" + "".join(
[ [
hex(b)[2:] if len(hex(b)) % 2 == 0 else "0" + hex(b)[2:] hex(b)[2:] if len(hex(b)) % 2 == 0 else "0" + hex(b)[2:]
for b in transaction.call_data.concretized(model) for b in transaction.call_data.concrete(model)
] ]
) )

@ -1,9 +1,8 @@
from mythril.analysis.security import get_detection_module_hooks from mythril.analysis.security import get_detection_module_hooks
from mythril.laser.ethereum import svm from mythril.laser.ethereum import svm
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.ether.soliditycontract import SolidityContract, ETHContract from mythril.solidity.soliditycontract import SolidityContract, EVMContract
import copy import copy
import logging
from .ops import get_variable, SStore, Call, VarType from .ops import get_variable, SStore, Call, VarType
from mythril.laser.ethereum.strategy.basic import ( from mythril.laser.ethereum.strategy.basic import (
DepthFirstSearchStrategy, DepthFirstSearchStrategy,
@ -61,14 +60,14 @@ class SymExecWrapper:
transaction_count=transaction_count, transaction_count=transaction_count,
) )
self.laser.register_hooks( self.laser.register_hooks(
hook_type="post", hook_dict=get_detection_module_hooks() hook_type="pre", hook_dict=get_detection_module_hooks()
) )
if isinstance(contract, SolidityContract): if isinstance(contract, SolidityContract):
self.laser.sym_exec( self.laser.sym_exec(
creation_code=contract.creation_code, contract_name=contract.name creation_code=contract.creation_code, contract_name=contract.name
) )
elif isinstance(contract, ETHContract) and contract.creation_code: elif isinstance(contract, EVMContract) and contract.creation_code:
self.laser.sym_exec( self.laser.sym_exec(
creation_code=contract.creation_code, contract_name=contract.name creation_code=contract.creation_code, contract_name=contract.name
) )

@ -1,6 +1,6 @@
from mythril.ether import util from mythril.ethereum import util
from mythril.disassembler import asm from mythril.disassembler import asm
from mythril.support.signatures import SignatureDb from mythril.support.signatures import SignatureDB
import logging import logging
@ -23,16 +23,9 @@ class Disassembly(object):
self.function_name_to_address = {} self.function_name_to_address = {}
self.address_to_function_name = {} self.address_to_function_name = {}
signatures = {} # open from default locations
try: # control if you want to have online signature hash lookups
# open from default locations signatures = SignatureDB(enable_online_lookup=enable_online_lookup)
signatures = SignatureDb(
enable_online_lookup=enable_online_lookup
) # control if you want to have online signature hash lookups
except FileNotFoundError:
logging.info(
"Missing function signature file. Resolving of function names from signature file disabled."
)
# Need to take from PUSH1 to PUSH4 because solc seems to remove excess 0s at the beginning for optimizing # Need to take from PUSH1 to PUSH4 because solc seems to remove excess 0s at the beginning for optimizing
jump_table_indices = asm.find_op_code_sequence( jump_table_indices = asm.find_op_code_sequence(
@ -54,7 +47,7 @@ class Disassembly(object):
def get_function_info( def get_function_info(
index: int, instruction_list: list, signature_database: SignatureDb index: int, instruction_list: list, signature_database: SignatureDB
) -> (str, int, str): ) -> (str, int, str):
""" """
Finds the function information for a call table entry Finds the function information for a call table entry

@ -1,3 +0,0 @@
import time
start_time = time.time()

@ -1,65 +0,0 @@
from ethereum import vm, messages, transactions
from ethereum.state import State
from ethereum.slogging import get_logger
from mythril.ether import util
from logging import StreamHandler
from io import StringIO
import re
def trace(code, calldata=""):
log_handlers = [
"eth.vm.op",
"eth.vm.op.stack",
"eth.vm.op.memory",
"eth.vm.op.storage",
]
output = StringIO()
stream_handler = StreamHandler(output)
for handler in log_handlers:
log_vm_op = get_logger(handler)
log_vm_op.setLevel("TRACE")
log_vm_op.addHandler(stream_handler)
addr = bytes.fromhex("0123456789ABCDEF0123456789ABCDEF01234567")
state = State()
ext = messages.VMExt(state, transactions.Transaction(0, 0, 21000, addr, 0, addr))
message = vm.Message(addr, addr, 0, 21000, calldata)
vm.vm_execute(ext, message, util.safe_decode(code))
stream_handler.flush()
ret = output.getvalue()
lines = ret.split("\n")
state_trace = []
for line in lines:
m = re.search(r"pc=b\'(\d+)\'.*op=([A-Z0-9]+)", line)
if m:
pc = m.group(1)
op = m.group(2)
m = re.match(r".*stack=(\[.*?\])", line)
if m:
stackitems = re.findall(r"b\'(\d+)\'", m.group(1))
stack = "["
if len(stackitems):
for i in range(0, len(stackitems) - 1):
stack += hex(int(stackitems[i])) + ", "
stack += hex(int(stackitems[-1]))
stack += "]"
else:
stack = "[]"
if re.match(r"^PUSH.*", op):
val = re.search(r"pushvalue=(\d+)", line).group(1)
pushvalue = hex(int(val))
state_trace.append(
{"pc": pc, "op": op, "stack": stack, "pushvalue": pushvalue}
)
else:
state_trace.append({"pc": pc, "op": op, "stack": stack})
return state_trace

@ -4,7 +4,7 @@ import persistent
import re import re
class ETHContract(persistent.Persistent): class EVMContract(persistent.Persistent):
def __init__( def __init__(
self, code="", creation_code="", name="Unknown", enable_online_lookup=False self, code="", creation_code="", name="Unknown", enable_online_lookup=False
): ):

@ -1,5 +1,5 @@
import logging import logging
from mythril import ether from mythril import ethereum
import time import time
from ethereum.messages import Log from ethereum.messages import Log
import rlp import rlp
@ -156,7 +156,7 @@ class AccountIndexer(object):
processed += BATCH_SIZE processed += BATCH_SIZE
blockNum = min(blockNum + BATCH_SIZE, self.lastBlock + 1) blockNum = min(blockNum + BATCH_SIZE, self.lastBlock + 1)
cost_time = time.time() - ether.start_time cost_time = time.time() - ethereum.start_time
print( print(
"%d blocks processed (in %d seconds), %d unique addresses found, next block: %d" "%d blocks processed (in %d seconds), %d unique addresses found, next block: %d"
% (processed, cost_time, count, min(self.lastBlock, blockNum)) % (processed, cost_time, count, min(self.lastBlock, blockNum))

@ -10,7 +10,7 @@ from ethereum import utils
from ethereum.block import BlockHeader, Block from ethereum.block import BlockHeader, Block
from mythril.ethereum.interface.leveldb.state import State from mythril.ethereum.interface.leveldb.state import State
from mythril.ethereum.interface.leveldb.eth_db import ETH_DB from mythril.ethereum.interface.leveldb.eth_db import ETH_DB
from mythril.ether.ethcontract import ETHContract from mythril.ethereum.evmcontract import EVMContract
from mythril.exceptions import AddressNotFoundError from mythril.exceptions import AddressNotFoundError
# Per https://github.com/ethereum/go-ethereum/blob/master/core/rawdb/schema.go # Per https://github.com/ethereum/go-ethereum/blob/master/core/rawdb/schema.go
@ -182,7 +182,7 @@ class EthLevelDB(object):
for account in self.reader._get_head_state().get_all_accounts(): for account in self.reader._get_head_state().get_all_accounts():
if account.code is not None: if account.code is not None:
code = _encode_hex(account.code) code = _encode_hex(account.code)
contract = ETHContract(code, enable_online_lookup=False) contract = EVMContract(code, enable_online_lookup=False)
yield contract, account.address, account.balance yield contract, account.address, account.balance

@ -6,6 +6,7 @@ from subprocess import Popen, PIPE
import binascii import binascii
import os import os
import json import json
from pathlib import Path
def safe_decode(hex_encoded_string): def safe_decode(hex_encoded_string):
@ -72,10 +73,14 @@ def get_indexed_address(index):
def solc_exists(version): def solc_exists(version):
solc_binary = os.path.join( solc_binaries = [
os.environ["HOME"], ".py-solc/solc-v" + version, "bin/solc" os.path.join(
) os.environ.get("HOME", str(Path.home())),
if os.path.exists(solc_binary): ".py-solc/solc-v" + version,
return True "bin/solc",
else: ), # py-solc setup
return False "/usr/bin/solc", # Ubuntu PPA setup
]
for solc_path in solc_binaries:
if os.path.exists(solc_path):
return solc_path

@ -200,13 +200,12 @@ def main():
) )
rpc = parser.add_argument_group("RPC options") rpc = parser.add_argument_group("RPC options")
rpc.add_argument(
"-i", action="store_true", help="Preset: Infura Node service (Mainnet)"
)
rpc.add_argument( rpc.add_argument(
"--rpc", "--rpc",
help="custom RPC settings", help="custom RPC settings",
metavar="HOST:PORT / ganache / infura-[network_name]", metavar="HOST:PORT / ganache / infura-[network_name]",
default="infura-mainnet",
) )
rpc.add_argument( rpc.add_argument(
"--rpctls", type=bool, default=False, help="RPC connection over TLS" "--rpctls", type=bool, default=False, help="RPC connection over TLS"
@ -290,12 +289,7 @@ def main():
if args.address: if args.address:
# Establish RPC connection if necessary # Establish RPC connection if necessary
if args.i: mythril.set_api_rpc(rpc=args.rpc, rpctls=args.rpctls)
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()
elif args.search or args.contract_hash_to_address: elif args.search or args.contract_hash_to_address:
# Open LevelDB if necessary # Open LevelDB if necessary
mythril.set_api_leveldb( mythril.set_api_leveldb(
@ -331,9 +325,11 @@ def main():
if args.code: if args.code:
# Load from bytecode # 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: elif args.codefile:
bytecode = "".join([l.strip() for l in args.codefile if len(l.strip()) > 0]) 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) address, _ = mythril.load_from_bytecode(bytecode, args.bin_runtime)
elif args.address: elif args.address:
# Get bytecode from a contract address # Get bytecode from a contract address
@ -389,7 +385,6 @@ def main():
max_depth=args.max_depth, max_depth=args.max_depth,
execution_timeout=args.execution_timeout, execution_timeout=args.execution_timeout,
create_timeout=args.create_timeout, create_timeout=args.create_timeout,
transaction_count=1,
) )
try: try:

@ -3,7 +3,11 @@ from typing import Union
from z3 import simplify, ExprRef, Extract from z3 import simplify, ExprRef, Extract
import mythril.laser.ethereum.util as util import mythril.laser.ethereum.util as util
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.calldata import CalldataType, Calldata from mythril.laser.ethereum.state.calldata import (
CalldataType,
SymbolicCalldata,
ConcreteCalldata,
)
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.support.loader import DynLoader from mythril.support.loader import DynLoader
import re import re
@ -174,12 +178,12 @@ def get_call_data(
starting_calldata.append(Extract(j + 7, j, elem)) starting_calldata.append(Extract(j + 7, j, elem))
i += 1 i += 1
call_data = Calldata(transaction_id, starting_calldata) call_data = ConcreteCalldata(transaction_id, starting_calldata)
call_data_type = CalldataType.CONCRETE call_data_type = CalldataType.CONCRETE
logging.debug("Calldata: " + str(call_data)) logging.debug("Calldata: " + str(call_data))
except TypeError: except TypeError:
logging.debug("Unsupported symbolic calldata offset") logging.debug("Unsupported symbolic calldata offset")
call_data_type = CalldataType.SYMBOLIC call_data_type = CalldataType.SYMBOLIC
call_data = Calldata("{}_internalcall".format(transaction_id)) call_data = SymbolicCalldata("{}_internalcall".format(transaction_id))
return call_data, call_data_type return call_data, call_data_type

@ -42,7 +42,7 @@ from mythril.laser.ethereum.evm_exceptions import (
) )
from mythril.laser.ethereum.gas import OPCODE_GAS from mythril.laser.ethereum.gas import OPCODE_GAS
from mythril.laser.ethereum.keccak import KeccakFunctionManager from mythril.laser.ethereum.keccak import KeccakFunctionManager
from mythril.laser.ethereum.state.calldata import CalldataType, Calldata from mythril.laser.ethereum.state.calldata import CalldataType
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.ethereum.transaction import ( from mythril.laser.ethereum.transaction import (
MessageCallTransaction, MessageCallTransaction,
@ -131,7 +131,7 @@ class Instruction:
def evaluate(self, global_state: GlobalState, post=False) -> List[GlobalState]: def evaluate(self, global_state: GlobalState, post=False) -> List[GlobalState]:
""" Performs the mutation for this instruction """ """ Performs the mutation for this instruction """
# Generalize some ops # Generalize some ops
logging.debug("Evaluating {}".format(self.op_code)) # logging.debug("Evaluating {}".format(self.op_code))
op = self.op_code.lower() op = self.op_code.lower()
if self.op_code.startswith("PUSH"): if self.op_code.startswith("PUSH"):
op = "push" op = "push"
@ -458,10 +458,9 @@ class Instruction:
environment = global_state.environment environment = global_state.environment
op0 = state.stack.pop() op0 = state.stack.pop()
value, constraints = environment.calldata.get_word_at(op0) value = environment.calldata.get_word_at(op0)
state.stack.append(value) state.stack.append(value)
state.constraints.extend(constraints)
return [global_state] return [global_state]
@ -541,9 +540,8 @@ class Instruction:
i_data = dstart i_data = dstart
new_memory = [] new_memory = []
for i in range(size): for i in range(size):
value, constraints = environment.calldata[i_data] value = environment.calldata[i_data]
new_memory.append(value) new_memory.append(value)
state.constraints.extend(constraints)
i_data = ( i_data = (
i_data + 1 if isinstance(i_data, int) else simplify(i_data + 1) i_data + 1 if isinstance(i_data, int) else simplify(i_data + 1)
@ -706,7 +704,7 @@ class Instruction:
if size == 0 and isinstance( if size == 0 and isinstance(
global_state.current_transaction, ContractCreationTransaction 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.mem_extend(concrete_memory_offset, 1)
global_state.mstate.memory[ global_state.mstate.memory[
concrete_memory_offset concrete_memory_offset

@ -8,7 +8,7 @@ from ethereum.utils import ecrecover_to_pub
from py_ecc.secp256k1 import N as secp256k1n from py_ecc.secp256k1 import N as secp256k1n
from rlp.utils import ALL_BYTES from rlp.utils import ALL_BYTES
from mythril.laser.ethereum.state.calldata import Calldata from mythril.laser.ethereum.state.calldata import BaseCalldata
from mythril.laser.ethereum.util import bytearray_to_int, sha3, get_concrete_int from mythril.laser.ethereum.util import bytearray_to_int, sha3, get_concrete_int
from z3 import Concat, simplify from z3 import Concat, simplify
@ -88,7 +88,7 @@ def identity(data: Union[bytes, str, List[int]]) -> bytes:
return result return result
def native_contracts(address: int, data: Calldata): def native_contracts(address: int, data: BaseCalldata):
""" """
takes integer address 1, 2, 3, 4 takes integer address 1, 2, 3, 4
""" """

@ -1,6 +1,6 @@
from typing import Dict, Union, Any, KeysView from typing import Dict, Union, Any, KeysView
from z3 import BitVec, ExprRef from z3 import BitVec, BitVecVal, ExprRef
from mythril.disassembler.disassembly import Disassembly from mythril.disassembler.disassembly import Disassembly
@ -41,7 +41,7 @@ class Storage:
pass pass
if self.concrete: if self.concrete:
return 0 return 0
self._storage[item] = BitVec("storage_" + str(item), 256) self._storage[item] = BitVecVal(0, 256)
return self._storage[item] return self._storage[item]
def __setitem__(self, key: str, value: ExprRef) -> None: def __setitem__(self, key: str, value: ExprRef) -> None:

@ -1,17 +1,7 @@
from enum import Enum from enum import Enum
from typing import Union, Any from typing import Union, Any
from z3 import ( from z3 import BitVecVal, BitVecRef, BitVec, simplify, Concat, If, ExprRef
BitVecVal, from z3.z3types import Z3Exception, Model
BitVecRef,
BitVecSort,
BitVec,
Implies,
simplify,
Concat,
UGT,
Array,
)
from z3.z3types import Z3Exception
from mythril.laser.ethereum.util import get_concrete_int from mythril.laser.ethereum.util import get_concrete_int
@ -21,84 +11,133 @@ class CalldataType(Enum):
SYMBOLIC = 2 SYMBOLIC = 2
class Calldata: class BaseCalldata:
""" """
Calldata class representing the calldata of a transaction Base calldata class
This represents the calldata provided when sending a transaction to a contract
""" """
def __init__(self, tx_id, starting_calldata=None): def __init__(self, tx_id):
"""
Constructor for Calldata
:param tx_id: unique value representing the transaction the calldata is for
:param starting_calldata: byte array representing the concrete calldata of a transaction
"""
self.tx_id = tx_id self.tx_id = tx_id
if starting_calldata is not None:
self._calldata = []
self.calldatasize = BitVecVal(len(starting_calldata), 256)
self.concrete = True
else:
self._calldata = Array(
"{}_calldata".format(self.tx_id), BitVecSort(256), BitVecSort(8)
)
self.calldatasize = BitVec("{}_calldatasize".format(self.tx_id), 256)
self.concrete = False
if self.concrete:
for calldata_byte in starting_calldata:
if type(calldata_byte) == int:
self._calldata.append(BitVecVal(calldata_byte, 8))
else:
self._calldata.append(calldata_byte)
def concretized(self, model):
result = []
for i in range(
get_concrete_int(model.eval(self.calldatasize, model_completion=True))
):
result.append(
get_concrete_int(model.eval(self._calldata[i], model_completion=True))
)
@property
def calldatasize(self) -> ExprRef:
"""
:return: Calldata size for this calldata object
"""
result = self.size
if isinstance(result, int):
return BitVecVal(result, 256)
return result return result
def get_word_at(self, index: int): def get_word_at(self, offset: int) -> ExprRef:
return self[index : index + 32] """ Gets word at offset"""
return self[offset : offset + 32]
def __getitem__(self, item: Union[int, slice]) -> Any: def __getitem__(self, item: Union[int, slice]) -> Any:
if isinstance(item, int) or isinstance(item, ExprRef):
return self._load(item)
if isinstance(item, slice): if isinstance(item, slice):
start, step, stop = item.start, item.step, item.stop start = 0 if item.start is None else item.start
step = 1 if item.step is None else item.step
stop = self.size if item.stop is None else item.stop
try: try:
if start is None:
start = 0
if step is None:
step = 1
if stop is None:
stop = self.calldatasize
current_index = ( current_index = (
start if isinstance(start, BitVecRef) else BitVecVal(start, 256) start if isinstance(start, BitVecRef) else BitVecVal(start, 256)
) )
dataparts = [] parts = []
while simplify(current_index != stop): while simplify(current_index != stop):
dataparts.append(self[current_index]) parts.append(self._load(current_index))
current_index = simplify(current_index + step) current_index = simplify(current_index + step)
except Z3Exception: except Z3Exception:
raise IndexError("Invalid Calldata Slice") raise IndexError("Invalid Calldata Slice")
values, constraints = zip(*dataparts) return simplify(Concat(parts))
result_constraints = []
for c in constraints: raise ValueError
result_constraints.extend(c)
return simplify(Concat(values)), result_constraints def _load(self, item: Union[int, ExprRef]) -> Any:
raise NotImplementedError()
@property
def size(self) -> Union[ExprRef, int]:
""" Returns the exact size of this calldata, this is not normalized"""
raise NotImplementedError()
def concrete(self, model: Model) -> list:
""" Returns a concrete version of the calldata using the provided model"""
raise NotImplementedError
class ConcreteCalldata(BaseCalldata):
def __init__(self, tx_id: int, calldata: list):
"""
Initializes the ConcreteCalldata object
:param tx_id: Id of the transaction that the calldata is for.
:param calldata: The concrete calldata content
"""
self._calldata = calldata
super().__init__(tx_id)
if self.concrete: def _load(self, item: Union[int, ExprRef]) -> Any:
if isinstance(item, int):
try: try:
return self._calldata[get_concrete_int(item)], () return self._calldata[item]
except IndexError: except IndexError:
return BitVecVal(0, 8), () return 0
else:
constraints = [ value = BitVecVal(0x0, 8)
Implies(self._calldata[item] != 0, UGT(self.calldatasize, item)) for i in range(self.size):
] value = If(item == i, self._calldata[i], value)
return value
def concrete(self, model: Model) -> list:
return self._calldata
@property
def size(self) -> int:
return len(self._calldata)
class SymbolicCalldata(BaseCalldata):
def __init__(self, tx_id: int):
"""
Initializes the SymbolicCalldata object
:param tx_id: Id of the transaction that the calldata is for.
"""
self._reads = []
self._size = BitVec("calldatasize", 256)
super().__init__(tx_id)
def _load(self, item: Union[int, ExprRef], clean=False) -> Any:
x = BitVecVal(item, 256) if isinstance(item, int) else item
symbolic_base_value = If(
x > self._size,
BitVecVal(0, 8),
BitVec("{}_calldata_{}".format(self.tx_id, str(item)), 8),
)
return_value = symbolic_base_value
for r_index, r_value in self._reads:
return_value = If(r_index == item, r_value, return_value)
if not clean:
self._reads.append((item, symbolic_base_value))
return simplify(return_value)
def concrete(self, model: Model) -> list:
concrete_length = get_concrete_int(model.eval(self.size, model_completion=True))
result = []
for i in range(concrete_length):
value = self._load(i, clean=True)
c_value = get_concrete_int(model.eval(value, model_completion=True))
result.append(c_value)
return result
return self._calldata[item], constraints @property
def size(self) -> ExprRef:
return self._size

@ -3,7 +3,7 @@ from typing import Dict
from z3 import ExprRef, BitVecVal from z3 import ExprRef, BitVecVal
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.calldata import Calldata, CalldataType from mythril.laser.ethereum.state.calldata import CalldataType, BaseCalldata
class Environment: class Environment:
@ -15,7 +15,7 @@ class Environment:
self, self,
active_account: Account, active_account: Account,
sender: ExprRef, sender: ExprRef,
calldata: Calldata, calldata: BaseCalldata,
gasprice: ExprRef, gasprice: ExprRef,
callvalue: ExprRef, callvalue: ExprRef,
origin: ExprRef, origin: ExprRef,

@ -21,6 +21,7 @@ class GlobalState:
machine_state=None, machine_state=None,
transaction_stack=None, transaction_stack=None,
last_return_data=None, last_return_data=None,
annotations=None,
): ):
""" Constructor for GlobalState""" """ Constructor for GlobalState"""
self.node = node self.node = node
@ -32,6 +33,7 @@ class GlobalState:
self.transaction_stack = transaction_stack if transaction_stack else [] self.transaction_stack = transaction_stack if transaction_stack else []
self.op_code = "" self.op_code = ""
self.last_return_data = last_return_data self.last_return_data = last_return_data
self.annotations = annotations or []
def __copy__(self) -> "GlobalState": def __copy__(self) -> "GlobalState":
world_state = copy(self.world_state) world_state = copy(self.world_state)
@ -45,6 +47,7 @@ class GlobalState:
mstate, mstate,
transaction_stack=transaction_stack, transaction_stack=transaction_stack,
last_return_data=self.last_return_data, last_return_data=self.last_return_data,
annotations=self.annotations,
) )
@property @property

@ -6,7 +6,7 @@ from mythril.laser.ethereum.transaction.transaction_models import (
) )
from z3 import BitVec from z3 import BitVec
from mythril.laser.ethereum.state.environment import Environment from mythril.laser.ethereum.state.environment import Environment
from mythril.laser.ethereum.state.calldata import Calldata, CalldataType from mythril.laser.ethereum.state.calldata import CalldataType, ConcreteCalldata
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.world_state import WorldState from mythril.laser.ethereum.state.world_state import WorldState
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
@ -42,7 +42,7 @@ def execute_message_call(
code=Disassembly(code), code=Disassembly(code),
caller=caller_address, caller=caller_address,
callee_account=open_world_state[callee_address], callee_account=open_world_state[callee_address],
call_data=Calldata(next_transaction_id, data), call_data=ConcreteCalldata(next_transaction_id, data),
call_data_type=CalldataType.SYMBOLIC, call_data_type=CalldataType.SYMBOLIC,
call_value=value, call_value=value,
) )

@ -1,9 +1,13 @@
from z3 import BitVec, Extract, Not from z3 import BitVec, BitVecVal
from logging import debug from logging import debug
from mythril.disassembler.disassembly import Disassembly from mythril.disassembler.disassembly import Disassembly
from mythril.laser.ethereum.cfg import Node, Edge, JumpType from mythril.laser.ethereum.cfg import Node, Edge, JumpType
from mythril.laser.ethereum.state.calldata import CalldataType, Calldata from mythril.laser.ethereum.state.calldata import (
CalldataType,
BaseCalldata,
SymbolicCalldata,
)
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.transaction.transaction_models import ( from mythril.laser.ethereum.transaction.transaction_models import (
MessageCallTransaction, MessageCallTransaction,
@ -12,6 +16,10 @@ from mythril.laser.ethereum.transaction.transaction_models import (
) )
CREATOR_ADDRESS = 0xAFFEAFFEAFFEAFFEAFFEAFFEAFFEAFFEAFFEAFFE
ATTACKER_ADDRESS = 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
def execute_message_call(laser_evm, callee_address: str) -> None: def execute_message_call(laser_evm, callee_address: str) -> None:
""" Executes a message call transaction from all open states """ """ Executes a message call transaction from all open states """
# TODO: Resolve circular import between .transaction and ..svm to import LaserEVM here # TODO: Resolve circular import between .transaction and ..svm to import LaserEVM here
@ -30,9 +38,9 @@ def execute_message_call(laser_evm, callee_address: str) -> None:
gas_price=BitVec("gas_price{}".format(next_transaction_id), 256), gas_price=BitVec("gas_price{}".format(next_transaction_id), 256),
gas_limit=8000000, # block gas limit gas_limit=8000000, # block gas limit
origin=BitVec("origin{}".format(next_transaction_id), 256), origin=BitVec("origin{}".format(next_transaction_id), 256),
caller=BitVec("caller{}".format(next_transaction_id), 256), caller=BitVecVal(ATTACKER_ADDRESS, 256),
callee_account=open_world_state[callee_address], callee_account=open_world_state[callee_address],
call_data=Calldata(next_transaction_id), call_data=SymbolicCalldata(next_transaction_id),
call_data_type=CalldataType.SYMBOLIC, call_data_type=CalldataType.SYMBOLIC,
call_value=BitVec("call_value{}".format(next_transaction_id), 256), call_value=BitVec("call_value{}".format(next_transaction_id), 256),
) )
@ -64,7 +72,7 @@ def execute_contract_creation(
gas_limit=8000000, # block gas limit gas_limit=8000000, # block gas limit
origin=BitVec("origin{}".format(next_transaction_id), 256), origin=BitVec("origin{}".format(next_transaction_id), 256),
code=Disassembly(contract_initialization_code), code=Disassembly(contract_initialization_code),
caller=BitVec("creator{}".format(next_transaction_id), 256), caller=BitVecVal(CREATOR_ADDRESS, 256),
callee_account=new_account, callee_account=new_account,
call_data=[], call_data=[],
call_data_type=CalldataType.SYMBOLIC, call_data_type=CalldataType.SYMBOLIC,

@ -2,7 +2,11 @@ import logging
from typing import Union from typing import Union
from mythril.disassembler.disassembly import Disassembly from mythril.disassembler.disassembly import Disassembly
from mythril.laser.ethereum.state.environment import Environment from mythril.laser.ethereum.state.environment import Environment
from mythril.laser.ethereum.state.calldata import Calldata from mythril.laser.ethereum.state.calldata import (
BaseCalldata,
ConcreteCalldata,
SymbolicCalldata,
)
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.world_state import WorldState from mythril.laser.ethereum.state.world_state import WorldState
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
@ -75,9 +79,9 @@ class BaseTransaction:
self.caller = caller self.caller = caller
self.callee_account = callee_account self.callee_account = callee_account
if call_data is None and init_call_data: if call_data is None and init_call_data:
self.call_data = Calldata(self.id, call_data) self.call_data = ConcreteCalldata(self.id, call_data)
else: else:
self.call_data = call_data if isinstance(call_data, Calldata) else None self.call_data = call_data if isinstance(call_data, BaseCalldata) else None
self.call_data_type = ( self.call_data_type = (
call_data_type call_data_type
if call_data_type is not None if call_data_type is not None

@ -9,6 +9,7 @@ import logging
import json import json
import os import os
import re import re
from pathlib import Path
from ethereum import utils from ethereum import utils
import codecs import codecs
@ -17,9 +18,9 @@ import solc
from configparser import ConfigParser from configparser import ConfigParser
import platform import platform
from mythril.ether import util from mythril.ethereum import util
from mythril.ether.ethcontract import ETHContract from mythril.ethereum.evmcontract import EVMContract
from mythril.ether.soliditycontract import SolidityContract, get_contracts_from_file from mythril.solidity.soliditycontract import SolidityContract, get_contracts_from_file
from mythril.ethereum.interface.rpc.client import EthJsonRpc from mythril.ethereum.interface.rpc.client import EthJsonRpc
from mythril.ethereum.interface.rpc.exceptions import ConnectionError from mythril.ethereum.interface.rpc.exceptions import ConnectionError
from mythril.support import signatures from mythril.support import signatures
@ -94,27 +95,10 @@ class Mythril(object):
self.mythril_dir = self._init_mythril_dir() self.mythril_dir = self._init_mythril_dir()
self.sigs = {} # tries mythril_dir/signatures.db by default (provide path= arg to make this configurable)
try: self.sigs = signatures.SignatureDB(
# tries mythril_dir/signatures.json by default (provide path= arg to make this configurable) enable_online_lookup=self.enable_online_lookup
self.sigs = signatures.SignatureDb( )
enable_online_lookup=self.enable_online_lookup
)
except FileNotFoundError as e:
logging.info(str(e))
# Create empty db file if none exists
f = open(os.path.join(self.mythril_dir, "signatures.json"), "w")
f.write("{}")
f.close()
self.sigs = signatures.SignatureDb(
enable_online_lookup=self.enable_online_lookup
)
except json.JSONDecodeError as e:
raise CriticalError(str(e))
self.solc_binary = self._init_solc_binary(solv) self.solc_binary = self._init_solc_binary(solv)
self.config_path = os.path.join(self.mythril_dir, "config.ini") self.config_path = os.path.join(self.mythril_dir, "config.ini")
@ -223,34 +207,33 @@ class Mythril(object):
# Figure out solc binary and version # Figure out solc binary and version
# Only proper versions are supported. No nightlies, commits etc (such as available in remix) # Only proper versions are supported. No nightlies, commits etc (such as available in remix)
if version: if not version:
# tried converting input to semver, seemed not necessary so just slicing for now return os.environ.get("SOLC") or "solc"
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"
)
solc_binary = os.path.join( # tried converting input to semver, seemed not necessary so just slicing for now
os.environ["HOME"], ".py-solc/solc-v" + version, "bin/solc" main_version = solc.main.get_solc_version_string()
) main_version_number = re.match(r"\d+.\d+.\d+", main_version)
logging.info("Setting the compiler to " + str(solc_binary)) 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: else:
try: solc_binary = util.solc_exists(version)
solc_binary = os.environ["SOLC"] if solc_binary:
except KeyError: logging.info("Given version is already installed")
solc_binary = "solc" 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 return solc_binary
def set_api_leveldb(self, leveldb): def set_api_leveldb(self, leveldb):
@ -319,11 +302,13 @@ class Mythril(object):
print(self.eth_db.contract_hash_to_address(hash)) print(self.eth_db.contract_hash_to_address(hash))
def load_from_bytecode(self, code, bin_runtime=False): def load_from_bytecode(self, code, bin_runtime=False, address=None):
address = util.get_indexed_address(0)
if address is None:
address = util.get_indexed_address(0)
if bin_runtime: if bin_runtime:
self.contracts.append( self.contracts.append(
ETHContract( EVMContract(
code=code, code=code,
name="MAIN", name="MAIN",
enable_online_lookup=self.enable_online_lookup, enable_online_lookup=self.enable_online_lookup,
@ -331,7 +316,7 @@ class Mythril(object):
) )
else: else:
self.contracts.append( self.contracts.append(
ETHContract( EVMContract(
creation_code=code, creation_code=code,
name="MAIN", name="MAIN",
enable_online_lookup=self.enable_online_lookup, enable_online_lookup=self.enable_online_lookup,
@ -360,7 +345,7 @@ class Mythril(object):
) )
else: else:
self.contracts.append( self.contracts.append(
ETHContract( EVMContract(
code, code,
name=address, name=address,
enable_online_lookup=self.enable_online_lookup, enable_online_lookup=self.enable_online_lookup,
@ -386,12 +371,9 @@ class Mythril(object):
try: try:
# import signatures from solidity source # import signatures from solidity source
self.sigs.import_from_solidity_source( self.sigs.import_solidity_file(
file, solc_binary=self.solc_binary, solc_args=self.solc_args file, solc_binary=self.solc_binary, solc_args=self.solc_args
) )
# Save updated function signatures
self.sigs.write() # dump signatures to disk (previously opened file or default location)
if contract_name is not None: if contract_name is not None:
contract = SolidityContract( contract = SolidityContract(
input_file=file, input_file=file,

@ -1,6 +1,6 @@
import mythril.laser.ethereum.util as helper import mythril.laser.ethereum.util as helper
from mythril.ether.ethcontract import ETHContract from mythril.ethereum.evmcontract import EVMContract
from mythril.ether.util import get_solc_json from mythril.ethereum.util import get_solc_json
from mythril.exceptions import NoContractFoundError from mythril.exceptions import NoContractFoundError
@ -42,7 +42,7 @@ def get_contracts_from_file(input_file, solc_args=None, solc_binary="solc"):
raise NoContractFoundError raise NoContractFoundError
class SolidityContract(ETHContract): class SolidityContract(EVMContract):
def __init__(self, input_file, name=None, solc_args=None, solc_binary="solc"): def __init__(self, input_file, name=None, solc_args=None, solc_binary="solc"):
data = get_solc_json(input_file, solc_args=solc_args, solc_binary=solc_binary) data = get_solc_json(input_file, solc_args=solc_args, solc_binary=solc_binary)

@ -3,11 +3,11 @@
"""mythril.py: Function Signature Database """mythril.py: Function Signature Database
""" """
import os import os
import json
import time import time
import logging import logging
import sqlite3
from typing import List
from collections import defaultdict
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
from mythril.exceptions import CompilerError from mythril.exceptions import CompilerError
@ -22,280 +22,199 @@ except ImportError:
FourByteDirectoryOnlineLookupError = Exception FourByteDirectoryOnlineLookupError = Exception
try: class SQLiteDB(object):
# Posix based file locking (Linux, Ubuntu, MacOS, etc.) """
import fcntl Simple CM for sqlite3 databases. Commits everything at exit.
"""
def lock_file(f, exclusive=False):
if f.mode == "r" and exclusive:
raise Exception("Please use non exclusive mode for reading")
flag = fcntl.LOCK_EX if exclusive else fcntl.LOCK_SH
fcntl.lockf(f, flag)
def unlock_file(f):
return
except ImportError:
# Windows file locking
# TODO: confirm the existence or non existence of shared locks in windows msvcrt and make changes based on that
import msvcrt
def file_size(f): def __init__(self, path):
return os.path.getsize(os.path.realpath(f.name)) self.path = path
self.conn = None
self.cursor = None
def lock_file(f, exclusive=False): def __enter__(self):
if f.mode == "r" and exclusive: self.conn = sqlite3.connect(self.path)
raise Exception("Please use non exclusive mode for reading") self.cursor = self.conn.cursor()
msvcrt.locking(f.fileno(), msvcrt.LK_RLCK, file_size(f)) return self.cursor
def unlock_file(f): def __exit__(self, exc_class, exc, traceback):
msvcrt.locking(f.fileno(), msvcrt.LK_UNLCK, file_size(f)) self.conn.commit()
self.conn.close()
def __repr__(self):
return "<SQLiteDB path={}>".format(self.path)
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs): class SignatureDB(object):
if cls not in cls._instances: def __init__(self, enable_online_lookup: bool = False, path: str = None) -> None:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) self.enable_online_lookup = enable_online_lookup
return cls._instances[cls] self.online_lookup_miss = set()
self.online_lookup_timeout = 0
if path is None:
self.path = os.environ.get("MYTHRIL_DIR") or os.path.join(
os.path.expanduser("~"), ".mythril"
)
self.path = os.path.join(self.path, "signatures.db")
logging.info("Using signature database at %s", self.path)
# NOTE: Creates a new DB file if it doesn't exist already
with SQLiteDB(self.path) as cur:
cur.execute(
(
"CREATE TABLE IF NOT EXISTS signatures"
"(byte_sig VARCHAR(10), text_sig VARCHAR(255),"
"PRIMARY KEY (byte_sig, text_sig))"
)
)
class SignatureDb(object, metaclass=Singleton): def __getitem__(self, item: str) -> List[str]:
def __init__(self, enable_online_lookup=False):
""" """
Constr Provide dict interface db[sighash]
:param enable_online_lookup: enable onlien signature hash lookup :param item: 4-byte signature string
:return: list of matching text signature strings
""" """
self.signatures = defaultdict(list) # signatures in-mem cache return self.get(byte_sig=item)
self.signatures_file = None
self.enable_online_lookup = (
enable_online_lookup
) # enable online funcsig resolving
# temporarily track misses from onlinedb to avoid requesting the same non-existent sighash multiple times
self.online_lookup_miss = set()
# flag the online directory as unavailable for some time
self.online_directory_unavailable_until = 0
self.open()
def open(self, path=None): @staticmethod
def _normalize_byte_sig(byte_sig: str) -> str:
""" """
Open a function signature db from json file Adds a leading 0x to the byte signature if it's not already there.
:param byte_sig: 4-byte signature string
:param path: specific path to signatures.json; default mythril location if not specified :return: normalized byte signature string
:return: self
""" """
if not path: if not byte_sig.startswith("0x"):
# try default locations byte_sig = "0x" + byte_sig
try: if not len(byte_sig) == 10:
mythril_dir = os.environ["MYTHRIL_DIR"] raise ValueError(
except KeyError: "Invalid byte signature %s, must have 10 characters", byte_sig
mythril_dir = os.path.join(os.path.expanduser("~"), ".mythril")
path = os.path.join(mythril_dir, "signatures.json")
# store early to allow error handling to access the place we tried to load the file
self.signatures_file = path
if not os.path.exists(path):
logging.debug("Signatures: file not found: %s" % path)
raise FileNotFoundError(
(
"Could not find signature file in {}. Function name resolution disabled.\n"
"Consider replacing it with the pre-initialized database at "
"https://raw.githubusercontent.com/ConsenSys/mythril/master/signatures.json"
).format(path)
) )
return byte_sig
with open(path, "r") as f: def add(self, byte_sig: str, text_sig: str) -> None:
lock_file(f)
try:
sigs = json.load(f)
except json.JSONDecodeError as e:
# reraise with path
raise json.JSONDecodeError(
"Invalid JSON in the signatures file {}: {}".format(path, str(e))
)
finally:
unlock_file(f)
# assert signature file format
for sighash, funcsig in sigs.items():
if (
not sighash.startswith("0x")
or len(sighash) != 10
or not isinstance(funcsig, list)
):
raise ValueError(
"Malformed signature file at {}. {}: {} is not a valid entry".format(
path, sighash, funcsig
)
)
self.signatures = defaultdict(list, sigs)
return self
def update_signatures(self, new_signatures):
for sighash, funcsigs in new_signatures.items():
# eliminate duplicates
updated_funcsigs = set(funcsigs + self.signatures[sighash])
self.signatures[sighash] = list(updated_funcsigs)
def write(self, path=None, sync=True):
""" """
Write signatures database as json to file Adds a new byte - text signature pair to the database.
:param byte_sig: 4-byte signature string
:param path: specify path otherwise update the file that was loaded with open() :param text_sig: resolved text signature
:param sync: lock signature file, load contents and merge it into memcached sighash db, then save it :return:
:return: self
""" """
path = path or self.signatures_file byte_sig = self._normalize_byte_sig(byte_sig)
directory = os.path.split(path)[0] with SQLiteDB(self.path) as cur:
# ignore new row if it's already in the DB (and would cause a unique constraint error)
if sync and os.path.exists(path): cur.execute(
# reload and save if file exists "INSERT OR IGNORE INTO signatures (byte_sig, text_sig) VALUES (?,?)",
with open(path, "r") as f: (byte_sig, text_sig),
lock_file(f) )
try:
sigs = json.load(f)
finally:
unlock_file(f)
self.update_signatures(sigs)
if directory and not os.path.exists(directory):
os.makedirs(directory) # create folder structure if not existS
if not os.path.exists(path): # creates signatures.json file if it doesn't exist
open(path, "w").close()
with open(path, "r+") as f: # placing 'w+' here will result in race conditions
lock_file(f, exclusive=True)
try:
json.dump(self.signatures, f, indent=4, sort_keys=True)
finally:
unlock_file(f)
return self
def get(self, sighash, timeout=2): def get(self, byte_sig: str, online_timeout: int = 2) -> List[str]:
""" """
get a function signature for a sighash Get a function text signature for a byte signature
1) try local cache 1) try local cache
2) try online lookup (if enabled; if not flagged as unavailable) 2) try online lookup (if enabled; if not flagged as unavailable)
:param sighash: function signature hash as hexstr :param byte_sig: function signature hash as hexstr
:param timeout: online lookup timeout :param online_timeout: online lookup timeout
:return: list of matching function signatures :return: list of matching function text signatures
""" """
if not sighash.startswith("0x"):
sighash = "0x%s" % sighash # normalize sighash format byte_sig = self._normalize_byte_sig(byte_sig)
# try lookup in the local DB
with SQLiteDB(self.path) as cur:
cur.execute("SELECT text_sig FROM signatures WHERE byte_sig=?", (byte_sig,))
text_sigs = cur.fetchall()
if text_sigs:
return [t[0] for t in text_sigs]
# abort if we're not allowed to check 4byte or we already missed
# the signature, or we're on a timeout
if ( if (
self.enable_online_lookup not self.enable_online_lookup
and not self.signatures.get(sighash) or byte_sig in self.online_lookup_miss
and sighash not in self.online_lookup_miss or time.time() < self.online_lookup_timeout
and time.time() > self.online_directory_unavailable_until
): ):
# online lookup enabled, and signature not in cache, sighash was not a miss earlier, and online directory not down
logging.debug(
"Signatures: performing online lookup for sighash %r" % sighash
)
try:
funcsigs = SignatureDb.lookup_online(
sighash, timeout=timeout
) # might return multiple sigs
if funcsigs:
# only store if we get at least one result
self.update_signatures({sighash: funcsigs})
else:
# miss
self.online_lookup_miss.add(sighash)
except FourByteDirectoryOnlineLookupError as fbdole:
self.online_directory_unavailable_until = (
time.time() + 2 * 60
) # wait at least 2 mins to try again
logging.warning(
"online function signature lookup not available. will not try to lookup hash for the next 2 minutes. exception: %r"
% fbdole
)
if sighash not in self.signatures:
return [] return []
if type(self.signatures[sighash]) != list:
return [self.signatures[sighash]]
return self.signatures[sighash]
def __getitem__(self, item): try:
""" text_sigs = self.lookup_online(byte_sig=byte_sig, timeout=online_timeout)
Provide dict interface Signatures()[sighash] if not text_sigs:
:param item: sighash self.online_lookup_miss.add(byte_sig)
:return: list of matching signatures return []
""" else:
return self.get(sighash=item) for resolved in text_sigs:
self.add(byte_sig, resolved)
return text_sigs
except FourByteDirectoryOnlineLookupError as fbdole:
# wait at least 2 mins to try again
self.online_lookup_timeout = time.time() + 2 * 60
logging.warning("Online lookup failed, not retrying for 2min: %s", fbdole)
return []
def import_from_solidity_source( def import_solidity_file(
self, file_path, solc_binary="solc", solc_args=None self, file_path: str, solc_binary: str = "solc", solc_args: str = None
): ):
""" """
Import Function Signatures from solidity source files Import Function Signatures from solidity source files
:param file_path: solidity source code file path :param file_path: solidity source code file path
:return: self :return:
""" """
self.update_signatures( sigs = {}
self.get_sigs_from_file( cmd = [solc_binary, "--hashes", file_path]
file_path, solc_binary=solc_binary, solc_args=solc_args if solc_args:
cmd.extend(solc_args.split())
try:
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
stdout, stderr = p.communicate()
ret = p.returncode
if ret != 0:
raise CompilerError(
"Solc has experienced a fatal error (code {}).\n\n{}".format(
ret, stderr.decode("utf-8")
)
)
except FileNotFoundError:
raise CompilerError(
(
"Compiler not found. Make sure that solc is installed and in PATH, "
"or the SOLC environment variable is set."
)
) )
)
return self stdout = stdout.decode("unicode_escape").split("\n")
for line in stdout:
# the ':' need not be checked but just to be sure
if all(map(lambda x: x in line, ["(", ")", ":"])):
sigs["0x" + line.split(":")[0]] = [line.split(":")[1].strip()]
logging.debug("Signatures: found %d signatures after parsing" % len(sigs))
# update DB with what we've found
for byte_sig, text_sigs in sigs.items():
for text_sig in text_sigs:
self.add(byte_sig, text_sig)
@staticmethod @staticmethod
def lookup_online(sighash, timeout=None, proxies=None): def lookup_online(byte_sig: str, timeout: int, proxies=None) -> List[str]:
""" """
Lookup function signatures from 4byte.directory. Lookup function signatures from 4byte.directory.
//tintinweb: the smart-contract-sanctuary project dumps contracts from etherscan.io and feeds them into //tintinweb: the smart-contract-sanctuary project dumps contracts from etherscan.io and feeds them into
4bytes.directory. 4bytes.directory.
https://github.com/tintinweb/smart-contract-sanctuary https://github.com/tintinweb/smart-contract-sanctuary
:param sighash: function signature hash as hexstr :param byte_sig: function signature hash as hexstr
:param timeout: optional timeout for online lookup :param timeout: optional timeout for online lookup
:param proxies: optional proxy servers for online lookup :param proxies: optional proxy servers for online lookup
:return: a list of matching function signatures for this hash :return: a list of matching function signatures for this hash
""" """
if not ethereum_input_decoder: if not ethereum_input_decoder:
return None return []
return list( return list(
ethereum_input_decoder.decoder.FourByteDirectory.lookup_signatures( ethereum_input_decoder.decoder.FourByteDirectory.lookup_signatures(
sighash, timeout=timeout, proxies=proxies byte_sig, timeout=timeout, proxies=proxies
) )
) )
@staticmethod def __repr__(self):
def get_sigs_from_file(file_name, solc_binary="solc", solc_args=None): return "<SignatureDB path='{}' enable_online_lookup={}>".format(
""" self.path, self.enable_online_lookup
:param file_name: accepts a filename )
:return: their signature mappings
"""
sigs = {}
cmd = [solc_binary, "--hashes", file_name]
if solc_args:
cmd.extend(solc_args.split())
try:
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
stdout, stderr = p.communicate()
ret = p.returncode
if ret != 0:
raise CompilerError(
"Solc experienced a fatal error (code %d).\n\n%s"
% (ret, stderr.decode("UTF-8"))
)
except FileNotFoundError:
raise CompilerError(
"Compiler not found. Make sure that solc is installed and in PATH, or set the SOLC environment variable."
)
stdout = stdout.decode("unicode_escape").split("\n")
for line in stdout:
if (
"(" in line and ")" in line and ":" in line
): # the ':' need not be checked but just to be sure
sigs["0x" + line.split(":")[0]] = [line.split(":")[1].strip()]
logging.debug("Signatures: found %d signatures after parsing" % len(sigs))
return sigs

@ -5,14 +5,13 @@ import sys
import json import json
import logging import logging
from ethereum.utils import sha3 from ethereum.utils import sha3
from mythril.ether.ethcontract import ETHContract from mythril.ethereum.evmcontract import EVMContract
from mythril.ether.soliditycontract import SourceMapping from mythril.solidity.soliditycontract import SourceMapping
from mythril.exceptions import CriticalError
from mythril.analysis.security import fire_lasers from mythril.analysis.security import fire_lasers
from mythril.analysis.symbolic import SymExecWrapper from mythril.analysis.symbolic import SymExecWrapper
from mythril.analysis.report import Report from mythril.analysis.report import Report
from mythril.ether import util from mythril.ethereum import util
from mythril.laser.ethereum.util import get_instruction_index from mythril.laser.ethereum.util import get_instruction_index
@ -44,7 +43,7 @@ def analyze_truffle_project(sigs, args):
continue continue
get_sigs_from_truffle(sigs, contractdata) get_sigs_from_truffle(sigs, contractdata)
ethcontract = ETHContract(bytecode, name=name) ethcontract = EVMContract(bytecode, name=name)
address = util.get_indexed_address(0) address = util.get_indexed_address(0)
sym = SymExecWrapper( sym = SymExecWrapper(
@ -139,8 +138,7 @@ def get_sigs_from_truffle(sigs, contract_data):
function_name = abi["name"] function_name = abi["name"]
list_of_args = ",".join([input["type"] for input in abi["inputs"]]) list_of_args = ",".join([input["type"] for input in abi["inputs"]])
signature = function_name + "(" + list_of_args + ")" signature = function_name + "(" + list_of_args + ")"
sigs.signatures["0x" + sha3(signature)[:4].hex()] = [signature] sigs.add("0x" + sha3(signature)[:4].hex(), signature)
sigs.write()
def get_mappings(source, deployed_source_map): def get_mappings(source, deployed_source_map):

Binary file not shown.

File diff suppressed because it is too large Load Diff

@ -1,29 +1,29 @@
pragma solidity ^0.4.16; pragma solidity 0.5.0;
/** /**
* @title SafeMath * @title SafeMath
* @dev Math operations with safety checks that throw on error * @dev Math operations with safety checks that throw on error
*/ */
library SafeMath { 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; uint256 c = a * b;
assert(a == 0 || c / a == b); assert(a == 0 || c / a == b);
return c; 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 // assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b; uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold // assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c; 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); assert(b <= a);
return a - b; 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; uint256 c = a + b;
assert(c >= a); assert(c >= a);
return c; return c;
@ -37,7 +37,7 @@ library SafeMath {
*/ */
contract ERC20Basic { contract ERC20Basic {
uint256 public totalSupply; 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); function transfer(address to, uint256 value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value); 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. // SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender].sub(_value); balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value); balances[_to] = balances[_to].add(_value);
Transfer(msg.sender, _to, _value); emit Transfer(msg.sender, _to, _value);
return true; return true;
} }
@ -72,7 +72,7 @@ contract BasicToken is ERC20Basic {
* @param _owner The address to query the the balance of. * @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address. * @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]; return balances[_owner];
} }
} }
@ -82,7 +82,7 @@ contract BasicToken is ERC20Basic {
* @dev see https://github.com/ethereum/EIPs/issues/20 * @dev see https://github.com/ethereum/EIPs/issues/20
*/ */
contract ERC20 is ERC20Basic { 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 transferFrom(address from, address to, uint256 value) public returns (bool);
function approve(address spender, uint256 value) public returns (bool); function approve(address spender, uint256 value) public returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value); 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[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value); balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
Transfer(_from, _to, _value); emit Transfer(_from, _to, _value);
return true; return true;
} }
@ -131,7 +131,7 @@ contract StandardToken is ERC20, BasicToken {
*/ */
function approve(address _spender, uint256 _value) public returns (bool) { function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value; allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value); emit Approval(msg.sender, _spender, _value);
return true; return true;
} }
@ -141,7 +141,7 @@ contract StandardToken is ERC20, BasicToken {
* @param _spender address The address which will spend the funds. * @param _spender address The address which will spend the funds.
* @return A uint256 specifying the amount of tokens still available for the spender. * @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]; return allowed[_owner][_spender];
} }
} }
@ -162,7 +162,7 @@ contract Ownable {
* @dev The Ownable constructor sets the original `owner` of the contract to the sender * @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account. * account.
*/ */
function Ownable() { constructor() public {
owner = msg.sender; owner = msg.sender;
} }
@ -182,7 +182,7 @@ contract Ownable {
*/ */
function transferOwnership(address newOwner) onlyOwner public { function transferOwnership(address newOwner) onlyOwner public {
require(newOwner != address(0)); require(newOwner != address(0));
OwnershipTransferred(owner, newOwner); emit OwnershipTransferred(owner, newOwner);
owner = newOwner; owner = newOwner;
} }
@ -220,7 +220,7 @@ contract Pausable is Ownable {
*/ */
function pause() onlyOwner whenNotPaused public { function pause() onlyOwner whenNotPaused public {
paused = true; paused = true;
Pause(); emit Pause();
} }
/** /**
@ -228,7 +228,7 @@ contract Pausable is Ownable {
*/ */
function unpause() onlyOwner whenPaused public { function unpause() onlyOwner whenPaused public {
paused = false; paused = false;
Unpause(); emit Unpause();
} }
} }
@ -252,7 +252,7 @@ contract PausableToken is StandardToken, Pausable {
return super.approve(_spender, _value); 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; uint cnt = _receivers.length;
uint256 amount = uint256(cnt) * _value; uint256 amount = uint256(cnt) * _value;
require(cnt > 0 && cnt <= 20); require(cnt > 0 && cnt <= 20);
@ -261,7 +261,7 @@ contract PausableToken is StandardToken, Pausable {
balances[msg.sender] = balances[msg.sender].sub(amount); balances[msg.sender] = balances[msg.sender].sub(amount);
for (uint i = 0; i < cnt; i++) { for (uint i = 0; i < cnt; i++) {
balances[_receivers[i]] = balances[_receivers[i]].add(_value); balances[_receivers[i]] = balances[_receivers[i]].add(_value);
Transfer(msg.sender, _receivers[i], _value); emit Transfer(msg.sender, _receivers[i], _value);
} }
return true; 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. * @dev Function to check the amount of tokens that an owner allowed to a spender.
*/ */
function BecToken() { constructor() public {
totalSupply = 7000000000 * (10**(uint256(decimals))); totalSupply = 7000000000 * (10**(uint256(decimals)));
balances[msg.sender] = totalSupply; // Give the creator all initial tokens balances[msg.sender] = totalSupply; // Give the creator all initial tokens
} }
function () { function () external {
//if ether is sent to this address, send it back. //if ether is sent to this address, send it back.
revert(); revert();
} }

@ -9,7 +9,7 @@
// some number (specified in constructor) of the set of owners (specified in the constructor, modifiable) before the // some number (specified in constructor) of the set of owners (specified in the constructor, modifiable) before the
// interior is executed. // interior is executed.
pragma solidity ^0.4.9; pragma solidity 0.5.0;
contract WalletEvents { contract WalletEvents {
// EVENTS // EVENTS
@ -50,15 +50,15 @@ contract WalletAbi {
function changeRequirement(uint _newRequired) external; 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. // (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 setDailyLimit(uint _newLimit) external;
function execute(address _to, uint _value, bytes _data) external returns (bytes32 o_hash); function execute(address _to, uint _value, bytes calldata _data) external returns (bytes32 o_hash);
function confirm(bytes32 _h) returns (bool o_success); function confirm(bytes32 _h) public returns (bool o_success);
} }
contract WalletLibrary is WalletEvents { contract WalletLibrary is WalletEvents {
@ -96,15 +96,15 @@ contract WalletLibrary is WalletEvents {
// METHODS // METHODS
// gets called when no other function matches // gets called when no other function matches
function() payable { function() external payable {
// just being sent some cash? // just being sent some cash?
if (msg.value > 0) 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 // constructor is given number of sigs required to do protected "onlymanyowners" transactions
// as well as the selection of addresses capable of confirming them. // 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_numOwners = _owners.length + 1;
m_owners[1] = uint(msg.sender); m_owners[1] = uint(msg.sender);
m_ownerIndex[uint(msg.sender)] = 1; m_ownerIndex[uint(msg.sender)] = 1;
@ -122,16 +122,16 @@ contract WalletLibrary is WalletEvents {
// make sure they're an owner // make sure they're an owner
if (ownerIndex == 0) return; if (ownerIndex == 0) return;
uint ownerIndexBit = 2**ownerIndex; uint ownerIndexBit = 2**ownerIndex;
var pending = m_pending[_operation]; PendingState memory pending = m_pending[_operation];
if (pending.ownersDone & ownerIndexBit > 0) { if (pending.ownersDone & ownerIndexBit > 0) {
pending.yetNeeded++; pending.yetNeeded++;
pending.ownersDone -= ownerIndexBit; pending.ownersDone -= ownerIndexBit;
Revoke(msg.sender, _operation); emit Revoke(msg.sender, _operation);
} }
} }
// Replaces an owner `_from` with another `_to`. // 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; if (isOwner(_to)) return;
uint ownerIndex = m_ownerIndex[uint(_from)]; uint ownerIndex = m_ownerIndex[uint(_from)];
if (ownerIndex == 0) return; if (ownerIndex == 0) return;
@ -140,10 +140,10 @@ contract WalletLibrary is WalletEvents {
m_owners[ownerIndex] = uint(_to); m_owners[ownerIndex] = uint(_to);
m_ownerIndex[uint(_from)] = 0; m_ownerIndex[uint(_from)] = 0;
m_ownerIndex[uint(_to)] = ownerIndex; 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; if (isOwner(_owner)) return;
clearPending(); clearPending();
@ -154,10 +154,10 @@ contract WalletLibrary is WalletEvents {
m_numOwners++; m_numOwners++;
m_owners[m_numOwners] = uint(_owner); m_owners[m_numOwners] = uint(_owner);
m_ownerIndex[uint(_owner)] = m_numOwners; 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)]; uint ownerIndex = m_ownerIndex[uint(_owner)];
if (ownerIndex == 0) return; if (ownerIndex == 0) return;
if (m_required > m_numOwners - 1) return; if (m_required > m_numOwners - 1) return;
@ -166,27 +166,27 @@ contract WalletLibrary is WalletEvents {
m_ownerIndex[uint(_owner)] = 0; m_ownerIndex[uint(_owner)] = 0;
clearPending(); clearPending();
reorganizeOwners(); //make sure m_numOwner is equal to the number of owners and always points to the optimal free slot 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; if (_newRequired > m_numOwners) return;
m_required = _newRequired; m_required = _newRequired;
clearPending(); clearPending();
RequirementChanged(_newRequired); emit RequirementChanged(_newRequired);
} }
// Gets an owner by 0-indexed position (using numOwners as the count) // 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]); 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; return m_ownerIndex[uint(_addr)] > 0;
} }
function hasConfirmed(bytes32 _operation, address _owner) external constant returns (bool) { function hasConfirmed(bytes32 _operation, address _owner) external view returns (bool) {
var pending = m_pending[_operation]; PendingState memory pending = m_pending[_operation];
uint ownerIndex = m_ownerIndex[uint(_owner)]; uint ownerIndex = m_ownerIndex[uint(_owner)];
// make sure they're an 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. // 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_dailyLimit = _limit;
m_lastDay = today(); m_lastDay = today();
} }
// (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent 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; m_dailyLimit = _newLimit;
} }
// resets the amount already spent today. needs many of the owners to confirm. // 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; m_spentToday = 0;
} }
// throw unless the contract is not yet initialized. // 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 // constructor - just pass on the owner array to the multiowned and
// the limit to daylimit // 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); initDaylimit(_daylimit);
initMultiowned(_owners, _required); initMultiowned(_owners, _required);
} }
// kills the contract sending everything to `_to`. // kills the contract sending everything to `_to`.
function kill(address _to) onlymanyowners(sha3(msg.data)) external { function kill(address payable _to) onlymanyowners(keccak256(msg.data)) external {
suicide(_to); selfdestruct(_to);
} }
// Outside-visible transact entry point. Executes transaction immediately if below daily spend limit. // 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 // 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 // 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. // 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. // first, take the opportunity to check that we're under the daily limit.
if ((_data.length == 0 && underLimit(_value)) || m_required == 1) { if ((_data.length == 0 && underLimit(_value)) || m_required == 1) {
// yes - just execute the call. // yes - just execute the call.
address created; address created;
if (_to == 0) { if (_to == address(0)) {
created = create(_value, _data); created = create(_value, _data);
} else { } else {
if (!_to.call.value(_value)(_data)) (bool success, bytes memory data) = _to.call.value(_value)(_data);
throw; require(success);
} }
SingleTransact(msg.sender, _value, _to, _data, created); emit SingleTransact(msg.sender, _value, _to, _data, created);
} else { } else {
// determine our operation hash. // 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 // 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].to = _to;
m_txs[o_hash].value = _value; m_txs[o_hash].value = _value;
m_txs[o_hash].data = _data; m_txs[o_hash].data = _data;
} }
if (!confirm(o_hash)) { 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 { assembly {
o_addr := create(_value, add(_code, 0x20), mload(_code)) 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 // 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. // to determine the body of the transaction from the hash provided.
function confirm(bytes32 _h) onlymanyowners(_h) returns (bool o_success) { function confirm(bytes32 _h) public onlymanyowners(_h) returns (bool o_success) {
if (m_txs[_h].to != 0 || m_txs[_h].value != 0 || m_txs[_h].data.length != 0) { if (m_txs[_h].to != address(0) || m_txs[_h].value != 0 || m_txs[_h].data.length != 0) {
address created; 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); created = create(m_txs[_h].value, m_txs[_h].data);
} else { } else {
if (!m_txs[_h].to.call.value(m_txs[_h].value)(m_txs[_h].data)) (bool success, bytes memory data) = m_txs[_h].to.call.value(m_txs[_h].value)(m_txs[_h].data);
throw; 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]; delete m_txs[_h];
return true; return true;
} }
@ -288,9 +290,9 @@ contract WalletLibrary is WalletEvents {
// determine what index the present sender is: // determine what index the present sender is:
uint ownerIndex = m_ownerIndex[uint(msg.sender)]; uint ownerIndex = m_ownerIndex[uint(msg.sender)];
// make sure they're an owner // 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 we're not yet working on this operation, switch over and reset the confirmation status.
if (pending.yetNeeded == 0) { if (pending.yetNeeded == 0) {
// reset count of confirmations needed. // reset count of confirmations needed.
@ -304,7 +306,7 @@ contract WalletLibrary is WalletEvents {
uint ownerIndexBit = 2**ownerIndex; uint ownerIndexBit = 2**ownerIndex;
// make sure we (the message sender) haven't confirmed this operation previously. // make sure we (the message sender) haven't confirmed this operation previously.
if (pending.ownersDone & ownerIndexBit == 0) { if (pending.ownersDone & ownerIndexBit == 0) {
Confirmation(msg.sender, _operation); emit Confirmation(msg.sender, _operation);
// ok - check if count is enough to go ahead. // ok - check if count is enough to go ahead.
if (pending.yetNeeded <= 1) { if (pending.yetNeeded <= 1) {
// enough confirmations: reset and run interior. // enough confirmations: reset and run interior.
@ -354,7 +356,7 @@ contract WalletLibrary is WalletEvents {
} }
// determines today's index. // 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 { function clearPending() internal {
uint length = m_pendingIndex.length; uint length = m_pendingIndex.length;
@ -370,7 +372,7 @@ contract WalletLibrary is WalletEvents {
} }
// FIELDS // FIELDS
address constant _walletLibrary = 0xcafecafecafecafecafecafecafecafecafecafe; address _walletLibrary = 0xCAfEcAfeCAfECaFeCaFecaFecaFECafECafeCaFe;
// the number of owners that must confirm the same operation before it is run. // the number of owners that must confirm the same operation before it is run.
uint public m_required; uint public m_required;
@ -384,7 +386,7 @@ contract WalletLibrary is WalletEvents {
// list of owners // list of owners
uint[256] m_owners; uint[256] m_owners;
uint constant c_maxOwners = 250; uint c_maxOwners = 250;
// index on the list of owners to allow reverse lookup // index on the list of owners to allow reverse lookup
mapping(uint => uint) m_ownerIndex; mapping(uint => uint) m_ownerIndex;
// the ongoing operations. // the ongoing operations.

@ -1,4 +1,4 @@
pragma solidity ^0.4.17; pragma solidity 0.5.0;
contract Caller { contract Caller {
@ -8,28 +8,28 @@ contract Caller {
uint256 statevar; uint256 statevar;
function Caller(address addr) { constructor(address addr) public {
fixed_address = addr; fixed_address = addr;
} }
function thisisfine() public { function thisisfine() public {
fixed_address.call(); fixed_address.call("");
} }
function reentrancy() public { function reentrancy() public {
fixed_address.call(); fixed_address.call("");
statevar = 0; statevar = 0;
} }
function calluseraddress(address addr) { function calluseraddress(address addr) public {
addr.call(); addr.call("");
} }
function callstoredaddress() { function callstoredaddress() public {
stored_address.call(); stored_address.call("");
} }
function setstoredaddress(address addr) { function setstoredaddress(address addr) public {
stored_address = addr; stored_address = addr;
} }

@ -1,3 +1,6 @@
pragma solidity 0.5.0;
contract EtherStore { contract EtherStore {
uint256 public withdrawalLimit = 1 ether; uint256 public withdrawalLimit = 1 ether;
@ -14,7 +17,8 @@ contract EtherStore {
require(_weiToWithdraw <= withdrawalLimit); require(_weiToWithdraw <= withdrawalLimit);
// limit the time allowed to withdraw // limit the time allowed to withdraw
require(now >= lastWithdrawTime[msg.sender] + 1 weeks); 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; balances[msg.sender] -= _weiToWithdraw;
lastWithdrawTime[msg.sender] = now; lastWithdrawTime[msg.sender] = now;
} }

@ -1,40 +1,43 @@
pragma solidity 0.5.0;
contract Exceptions { contract Exceptions {
uint256[8] myarray; uint256[8] myarray;
function assert1() { function assert1() public pure {
uint256 i = 1; uint256 i = 1;
assert(i == 0); assert(i == 0);
} }
function assert2() { function assert2() public pure {
uint256 i = 1; uint256 i = 1;
assert(i > 0); assert(i > 0);
} }
function assert3(uint256 input) { function assert3(uint256 input) public pure {
assert(input != 23); assert(input != 23);
} }
function requireisfine(uint256 input) { function requireisfine(uint256 input) public pure {
require(input != 23); require(input != 23);
} }
function divisionby0(uint256 input) { function divisionby0(uint256 input) public pure {
uint256 i = 1/input; uint256 i = 1/input;
} }
function thisisfine(uint256 input) { function thisisfine(uint256 input) public pure {
if (input > 0) { if (input > 0) {
uint256 i = 1/input; uint256 i = 1/input;
} }
} }
function arrayaccess(uint256 index) { function arrayaccess(uint256 index) public view {
uint256 i = myarray[index]; uint256 i = myarray[index];
} }
function thisisalsofind(uint256 index) { function thisisalsofind(uint256 index) public view {
if (index < 8) { if (index < 8) {
uint256 i = myarray[index]; uint256 i = myarray[index];
} }

@ -1,12 +1,15 @@
pragma solidity 0.5.0;
contract HashForEther { contract HashForEther {
function withdrawWinnings() { function withdrawWinnings() public {
// Winner if the last 8 hex characters of the address are 0. // Winner if the last 8 hex characters of the address are 0.
require(uint32(msg.sender) == 0); require(uint32(msg.sender) == 0);
_sendWinnings(); _sendWinnings();
} }
function _sendWinnings() { function _sendWinnings() public {
msg.sender.transfer(this.balance); msg.sender.transfer(address(this).balance);
} }
} }

@ -1,3 +1,6 @@
pragma solidity 0.5.0;
contract Origin { contract Origin {
address public owner; address public owner;
@ -6,7 +9,7 @@ contract Origin {
* @dev The Ownable constructor sets the original `owner` of the contract to the sender * @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account. * account.
*/ */
function Origin() { constructor() public {
owner = msg.sender; owner = msg.sender;
} }
@ -15,9 +18,7 @@ contract Origin {
* @dev Throws if called by any account other than the owner. * @dev Throws if called by any account other than the owner.
*/ */
modifier onlyOwner() { modifier onlyOwner() {
if (tx.origin != owner) { require(tx.origin != owner);
throw;
}
_; _;
} }
@ -26,7 +27,7 @@ contract Origin {
* @dev Allows the current owner to transfer control of the contract to a newOwner. * @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)) { if (newOwner != address(0)) {
owner = newOwner; owner = newOwner;
} }

@ -1,13 +1,17 @@
pragma solidity 0.5.0;
contract ReturnValue { contract ReturnValue {
address callee = 0xE0F7e56e62b4267062172495D7506087205A4229; address public callee = 0xE0f7e56E62b4267062172495D7506087205A4229;
function callnotchecked() { function callnotchecked() public {
callee.call(); callee.call("");
} }
function callchecked() { function callchecked() public {
require(callee.call()); (bool success, bytes memory data) = callee.call("");
require(success);
} }
} }

@ -1,152 +1,152 @@
contract Rubixi { pragma solidity 0.5.0;
//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;
//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 contract Rubixi {
function addPayout(uint _fee) private { //Declare variables for storage critical to contract
//Adds new address to participant array uint private balance = 0;
participants.push(Participant(msg.sender, (msg.value * pyramidMultiplier) / 100)); uint private collectedFees = 0;
uint private feePercent = 10;
//These statements ensure a quicker payout system to later pyramid entrants, so the pyramid has a longer lifespan uint private pyramidMultiplier = 300;
if (participants.length == 10) pyramidMultiplier = 200; uint private payoutOrder = 0;
else if (participants.length == 25) pyramidMultiplier = 150;
address payable private creator;
// collect fees and update contract balance
balance += (msg.value * (100 - _fee)) / 100; modifier onlyowner {
collectedFees += (msg.value * _fee) / 100; if (msg.sender == creator) _;
}
//Pays earlier participiants if balance sufficient
while (balance > participants[payoutOrder].payout) { struct Participant {
uint payoutToSend = participants[payoutOrder].payout; address payable etherAddress;
participants[payoutOrder].etherAddress.send(payoutToSend); uint payout;
}
balance -= participants[payoutOrder].payout;
payoutOrder += 1; //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 currentPyramidBalanceApproximately() public view returns (uint pyramidBalance, string memory info) {
function collectAllFees() onlyowner { pyramidBalance = balance / 1 ether;
if (collectedFees == 0) throw; 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); function nextPayoutWhenPyramidBalanceTotalsApproximately() public view returns (uint balancePayout) {
collectedFees = 0; balancePayout = participants[payoutOrder].payout / 1 ether;
} }
function collectFeesInEther(uint _amt) onlyowner { function feesSeperateFromBalanceApproximately() public view returns (uint fees) {
_amt *= 1 ether; fees = collectedFees / 1 ether;
if (_amt > collectedFees) collectAllFees(); }
if (collectedFees == 0) throw; function totalParticipants() public view returns (uint count) {
count = participants.length;
creator.send(_amt); }
collectedFees -= _amt;
}
function collectPercentOfFees(uint _pcent) onlyowner { function numberOfParticipantsWaitingForPayout() public view returns (uint count) {
if (collectedFees == 0 || _pcent > 100) throw; count = participants.length - payoutOrder;
}
uint feesToCollect = collectedFees / 100 * _pcent; function participantDetails(uint orderInPyramid) public view returns (address addr, uint payout) {
creator.send(feesToCollect); if (orderInPyramid <= participants.length) {
collectedFees -= feesToCollect; addr = participants[orderInPyramid].etherAddress;
payout = participants[orderInPyramid].payout / 1 ether;
} }
}
//Functions for changing variables related to the contract //init function run on fallback
function changeOwner(address _owner) onlyowner { function init() private {
creator = _owner; //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 { uint _fee = feePercent;
if (_mult > 300 || _mult < 120) throw; // 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 { //Function called for valid tx to the contract
if (_fee > 10) throw; 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 // collect fees and update contract balance
function currentMultiplier() constant returns(uint multiplier, string info) { balance += (msg.value * (100 - _fee)) / 100;
multiplier = pyramidMultiplier; collectedFees += (msg.value * _fee) / 100;
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%)';
}
function currentPyramidBalanceApproximately() constant returns(uint pyramidBalance, string info) { //Pays earlier participiants if balance sufficient
pyramidBalance = balance / 1 ether; while (balance > participants[payoutOrder].payout) {
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'; uint payoutToSend = participants[payoutOrder].payout;
} participants[payoutOrder].etherAddress.transfer(payoutToSend);
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;
}
function participantDetails(uint orderInPyramid) constant returns(address Address, uint Payout) { balance -= participants[payoutOrder].payout;
if (orderInPyramid <= participants.length) { payoutOrder += 1;
Address = participants[orderInPyramid].etherAddress;
Payout = participants[orderInPyramid].payout / 1 ether;
}
} }
}
} }

@ -1,6 +1,9 @@
pragma solidity 0.5.0;
contract Suicide { contract Suicide {
function kill(address addr) { function kill(address payable addr) public {
selfdestruct(addr); selfdestruct(addr);
} }

@ -1,3 +1,6 @@
pragma solidity 0.5.0;
contract TimeLock { contract TimeLock {
mapping(address => uint) public balances; mapping(address => uint) public balances;

@ -1,11 +1,12 @@
pragma solidity ^0.4.18; pragma solidity 0.5.0;
contract Token { contract Token {
mapping(address => uint) balances; mapping(address => uint) balances;
uint public totalSupply; uint public totalSupply;
function Token(uint _initialSupply) { constructor(uint _initialSupply) public {
balances[msg.sender] = totalSupply = _initialSupply; balances[msg.sender] = totalSupply = _initialSupply;
} }
@ -16,7 +17,7 @@ contract Token {
return true; return true;
} }
function balanceOf(address _owner) public constant returns (uint balance) { function balanceOf(address _owner) public view returns (uint balance) {
return balances[_owner]; return balances[_owner];
} }
} }

@ -1,20 +1,21 @@
pragma solidity ^0.4.16; pragma solidity 0.5.0;
contract WeakRandom { contract WeakRandom {
struct Contestant { struct Contestant {
address addr; address payable addr;
uint gameId; uint gameId;
} }
uint public constant prize = 2.5 ether; uint public prize = 2.5 ether;
uint public constant totalTickets = 50; uint public totalTickets = 50;
uint public constant pricePerTicket = prize / totalTickets; uint public pricePerTicket = prize / totalTickets;
uint public gameId = 1; uint public gameId = 1;
uint public nextTicket = 0; uint public nextTicket = 0;
mapping (uint => Contestant) public contestants; mapping (uint => Contestant) public contestants;
function () payable public { function () payable external {
uint moneySent = msg.value; uint moneySent = msg.value;
while (moneySent >= pricePerTicket && nextTicket < totalTickets) { while (moneySent >= pricePerTicket && nextTicket < totalTickets) {
@ -37,10 +38,10 @@ contract WeakRandom {
address seed1 = contestants[uint(block.coinbase) % totalTickets].addr; address seed1 = contestants[uint(block.coinbase) % totalTickets].addr;
address seed2 = contestants[uint(msg.sender) % totalTickets].addr; address seed2 = contestants[uint(msg.sender) % totalTickets].addr;
uint seed3 = block.difficulty; uint seed3 = block.difficulty;
bytes32 randHash = keccak256(seed1, seed2, seed3); bytes32 randHash = keccak256(abi.encode(seed1, seed2, seed3));
uint winningNumber = uint(randHash) % totalTickets; uint winningNumber = uint(randHash) % totalTickets;
address winningAddress = contestants[winningNumber].addr; address payable winningAddress = contestants[winningNumber].addr;
gameId++; gameId++;
nextTicket = 0; nextTicket = 0;

@ -18,16 +18,16 @@ MYTHRIL_DIR = TESTS_DIR / "mythril_dir"
class BaseTestCase(TestCase): class BaseTestCase(TestCase):
def setUp(self): def setUp(self):
self.changed_files = [] self.changed_files = []
self.ori_mythril_dir = getattr(os.environ, "MYTHRIL_DIR", "") self.ori_mythril_dir = os.environ.get("MYTHRIL_DIR", "")
os.environ["MYTHRIL_DIR"] = str(MYTHRIL_DIR) os.environ["MYTHRIL_DIR"] = str(MYTHRIL_DIR)
shutil.copyfile( shutil.copyfile(
str(MYTHRIL_DIR / "signatures.json.example"), str(MYTHRIL_DIR / "signatures.db.example"),
str(MYTHRIL_DIR / "signatures.json"), str(MYTHRIL_DIR / "signatures.db"),
) )
def tearDown(self): def tearDown(self):
os.environ["MYTHRIL_DIR"] = self.ori_mythril_dir os.environ["MYTHRIL_DIR"] = self.ori_mythril_dir
os.remove(str(MYTHRIL_DIR / "signatures.json")) os.remove(str(MYTHRIL_DIR / "signatures.db"))
def compare_files_error_message(self): def compare_files_error_message(self):
message = "Following output files are changed, compare them manually to see differences: \n" message = "Following output files are changed, compare them manually to see differences: \n"

@ -1,268 +0,0 @@
from mythril.analysis.modules.delegatecall import detector
from mythril.analysis.ops import Call, Variable, VarType
from mythril.analysis.symbolic import SymExecWrapper
from mythril.laser.ethereum.cfg import Node
from mythril.laser.ethereum.state.environment import Environment
from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.global_state import GlobalState
import pytest
from unittest.mock import MagicMock, patch
import pytest_mock
from mythril.disassembler.disassembly import Disassembly
def test_concrete_call():
# arrange
address = "0x10"
active_account = Account(address)
active_account.code = Disassembly("00")
environment = Environment(active_account, None, None, None, None, None)
state = GlobalState(None, environment, None)
state.mstate.memory = ["placeholder", "calldata_bling_0"]
node = Node("example")
node.contract_name = "the contract name"
node.function_name = "the function name"
to = Variable(1, VarType.CONCRETE)
meminstart = Variable(1, VarType.CONCRETE)
call = Call(node, state, None, None, to, None)
# act
issues = detector._concrete_call(call, state, address, meminstart)
# assert
issue = issues[0]
assert issue.address == address
assert issue.contract == node.contract_name
assert issue.function == node.function_name
assert issue.title == "Call data forwarded with delegatecall()"
assert issue.type == "Informational"
assert (
issue.description
== "This contract forwards its call data via DELEGATECALL in its fallback function."
" This means that any function in the called contract can be executed."
" Note that the callee contract will have access to the storage of the "
"calling contract.\nDELEGATECALL target: 0x1"
)
def test_concrete_call_symbolic_to():
# arrange
address = "0x10"
active_account = Account(address)
active_account.code = Disassembly("00")
environment = Environment(active_account, None, None, None, None, None)
state = GlobalState(None, environment, None)
state.mstate.memory = ["placeholder", "calldata_bling_0"]
node = Node("example")
node.contract_name = "the contract name"
node.function_name = "the function name"
to = Variable("calldata_3", VarType.SYMBOLIC)
meminstart = Variable(1, VarType.CONCRETE)
call = Call(node, state, None, None, to, None)
# act
issues = detector._concrete_call(call, state, address, meminstart)
# assert
issue = issues[0]
assert issue.address == address
assert issue.contract == node.contract_name
assert issue.function == node.function_name
assert issue.title == "Call data forwarded with delegatecall()"
assert issue.type == "Informational"
assert issue.description == (
"This contract forwards its call data via DELEGATECALL in its fallback function."
" This means that any function in the called contract can be executed."
" Note that the callee contract will have access to the storage of the "
"calling contract.\nDELEGATECALL target: calldata_3"
)
def test_concrete_call_not_calldata():
# arrange
state = GlobalState(None, None, None)
state.mstate.memory = ["placeholder", "not_calldata"]
meminstart = Variable(1, VarType.CONCRETE)
# act
issues = detector._concrete_call(None, state, None, meminstart)
# assert
assert issues == []
def test_symbolic_call_storage_to(mocker):
# arrange
address = "0x10"
active_account = Account(address)
active_account.code = Disassembly("00")
environment = Environment(active_account, None, None, None, None, None)
state = GlobalState(None, environment, None)
state.mstate.memory = ["placeholder", "calldata_bling_0"]
node = Node("example")
node.contract_name = "the contract name"
node.function_name = "the function name"
to = Variable("storage_1", VarType.SYMBOLIC)
call = Call(node, state, None, "Type: ", to, None)
mocker.patch.object(SymExecWrapper, "__init__", lambda x, y: None)
statespace = SymExecWrapper(1)
mocker.patch.object(statespace, "find_storage_write")
statespace.find_storage_write.return_value = "Function name"
# act
issues = detector._symbolic_call(call, state, address, statespace)
# assert
issue = issues[0]
assert issue.address == address
assert issue.contract == node.contract_name
assert issue.function == node.function_name
assert issue.title == "Type: to a user-supplied address"
assert issue.type == "Informational"
assert issue.description == (
"This contract delegates execution to a contract address in storage slot 1."
" This storage slot can be written to by calling the function `Function name`."
" Be aware that the called contract gets unrestricted access to this contract's state."
)
def test_symbolic_call_calldata_to(mocker):
# arrange
address = "0x10"
active_account = Account(address)
active_account.code = Disassembly("00")
environment = Environment(active_account, None, None, None, None, None)
state = GlobalState(None, environment, None)
state.mstate.memory = ["placeholder", "calldata_bling_0"]
node = Node("example")
node.contract_name = "the contract name"
node.function_name = "the function name"
to = Variable("calldata", VarType.SYMBOLIC)
call = Call(node, state, None, "Type: ", to, None)
mocker.patch.object(SymExecWrapper, "__init__", lambda x, y: None)
statespace = SymExecWrapper(1)
mocker.patch.object(statespace, "find_storage_write")
statespace.find_storage_write.return_value = "Function name"
# act
issues = detector._symbolic_call(call, state, address, statespace)
# assert
issue = issues[0]
assert issue.address == address
assert issue.contract == node.contract_name
assert issue.function == node.function_name
assert issue.title == "Type: to a user-supplied address"
assert issue.type == "Informational"
assert issue.description == (
"This contract delegates execution to a contract address obtained from calldata."
" Be aware that the called contract gets unrestricted access to this contract's state."
)
@patch("mythril.laser.ethereum.state.global_state.GlobalState.get_current_instruction")
@patch("mythril.analysis.modules.delegatecall.detector._concrete_call")
@patch("mythril.analysis.modules.delegatecall.detector._symbolic_call")
def test_delegate_call(sym_mock, concrete_mock, curr_instruction):
# arrange
# sym_mock = mocker.patch.object(delegatecall, "_symbolic_call")
# concrete_mock = mocker.patch.object(delegatecall, "_concrete_call")
sym_mock.return_value = []
concrete_mock.return_value = []
curr_instruction.return_value = {"address": "0x10"}
active_account = Account("0x10")
active_account.code = Disassembly("00")
environment = Environment(active_account, None, None, None, None, None)
state = GlobalState(None, environment, Node)
state.mstate.memory = ["placeholder", "calldata_bling_0"]
state.mstate.stack = [1, 2, 3]
assert state.get_current_instruction() == {"address": "0x10"}
node = Node("example")
node.contract_name = "the contract name"
node.function_name = "fallback"
to = Variable("storage_1", VarType.SYMBOLIC)
call = Call(node, state, None, "DELEGATECALL", to, None)
statespace = MagicMock()
statespace.calls = [call]
# act
detector.execute(statespace)
# assert
assert concrete_mock.call_count == 1
assert sym_mock.call_count == 1
@patch("mythril.analysis.modules.delegatecall.detector._concrete_call")
@patch("mythril.analysis.modules.delegatecall.detector._symbolic_call")
def test_delegate_call_not_delegate(sym_mock, concrete_mock):
# arrange
# sym_mock = mocker.patch.object(delegatecall, "_symbolic_call")
# concrete_mock = mocker.patch.object(delegatecall, "_concrete_call")
sym_mock.return_value = []
concrete_mock.return_value = []
node = Node("example")
node.function_name = "fallback"
to = Variable("storage_1", VarType.SYMBOLIC)
call = Call(node, None, None, "NOT_DELEGATECALL", to, None)
statespace = MagicMock()
statespace.calls = [call]
# act
issues = detector.execute(statespace)
# assert
assert issues == []
assert concrete_mock.call_count == 0
assert sym_mock.call_count == 0
@patch("mythril.analysis.modules.delegatecall.detector._concrete_call")
@patch("mythril.analysis.modules.delegatecall.detector._symbolic_call")
def test_delegate_call_not_fallback(sym_mock, concrete_mock):
# arrange
# sym_mock = mocker.patch.object(delegatecall, "_symbolic_call")
# concrete_mock = mocker.patch.object(delegatecall, "_concrete_call")
sym_mock.return_value = []
concrete_mock.return_value = []
node = Node("example")
node.function_name = "not_fallback"
to = Variable("storage_1", VarType.SYMBOLIC)
call = Call(node, None, None, "DELEGATECALL", to, None)
statespace = MagicMock()
statespace.calls = [call]
# act
issues = detector.execute(statespace)
# assert
assert issues == []
assert concrete_mock.call_count == 0
assert sym_mock.call_count == 0

@ -1,5 +1,5 @@
from subprocess import check_output from subprocess import check_output
from tests import * from tests import BaseTestCase, TESTDATA, PROJECT_DIR, TESTS_DIR
MYTH = str(PROJECT_DIR / "myth") MYTH = str(PROJECT_DIR / "myth")
@ -10,23 +10,23 @@ def output_of(command):
class CommandLineToolTestCase(BaseTestCase): class CommandLineToolTestCase(BaseTestCase):
def test_disassemble_code_correctly(self): def test_disassemble_code_correctly(self):
command = "python3 {} MYTH -d --bin-runtime -c 0x5050".format(MYTH) command = "python3 {} MYTH -d --bin-runtime -c 0x5050 --solv 0.5.0".format(MYTH)
self.assertEqual("0 POP\n1 POP\n", output_of(command)) self.assertIn("0 POP\n1 POP\n", output_of(command))
def test_disassemble_solidity_file_correctly(self): def test_disassemble_solidity_file_correctly(self):
solidity_file = str(TESTDATA / "input_contracts" / "metacoin.sol") solidity_file = str(TESTDATA / "input_contracts" / "metacoin.sol")
command = "python3 {} -d {}".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)) self.assertIn("2 PUSH1 0x40\n4 MSTORE", output_of(command))
def test_hash_a_function_correctly(self): def test_hash_a_function_correctly(self):
command = "python3 {} --hash 'setOwner(address)'".format(MYTH) command = "python3 {} --solv 0.5.0 --hash 'setOwner(address)'".format(MYTH)
self.assertEqual("0x13af4035\n", output_of(command)) self.assertIn("0x13af4035\n", output_of(command))
class TruffleTestCase(BaseTestCase): class TruffleTestCase(BaseTestCase):
def test_analysis_truffle_project(self): def test_analysis_truffle_project(self):
truffle_project_root = str(TESTS_DIR / "truffle_project") truffle_project_root = str(TESTS_DIR / "truffle_project")
command = "cd {}; truffle compile; python3 {} --truffle -t 1".format( command = "cd {}; truffle compile; python3 {} --truffle -t 2".format(
truffle_project_root, MYTH truffle_project_root, MYTH
) )
self.assertIn("=== Ether thief ====", output_of(command)) self.assertIn("=== Ether thief ====", output_of(command))

@ -12,7 +12,7 @@ def test_get_function_info(mocker):
# Arrange # Arrange
global instruction_list global instruction_list
signature_database_mock = SignatureDb() signature_database_mock = SignatureDB()
mocker.patch.object(signature_database_mock, "get") mocker.patch.object(signature_database_mock, "get")
signature_database_mock.get.return_value = ["function_name"] signature_database_mock.get.return_value = ["function_name"]
@ -31,7 +31,7 @@ def test_get_function_info_multiple_names(mocker):
# Arrange # Arrange
global instruction_list global instruction_list
signature_database_mock = SignatureDb() signature_database_mock = SignatureDB()
mocker.patch.object(signature_database_mock, "get") mocker.patch.object(signature_database_mock, "get")
signature_database_mock.get.return_value = ["function_name", "another_name"] signature_database_mock.get.return_value = ["function_name", "another_name"]
@ -48,7 +48,7 @@ def test_get_function_info_no_names(mocker):
# Arrange # Arrange
global instruction_list global instruction_list
signature_database_mock = SignatureDb() signature_database_mock = SignatureDB()
mocker.patch.object(signature_database_mock, "get") mocker.patch.object(signature_database_mock, "get")
signature_database_mock.get.return_value = [] signature_database_mock.get.return_value = []

@ -1,5 +1,5 @@
from mythril.disassembler.disassembly import Disassembly from mythril.disassembler.disassembly import Disassembly
from mythril.ether import util from mythril.ethereum import util
from tests import * from tests import *

@ -1,41 +1,42 @@
import unittest from mythril.ethereum.evmcontract import EVMContract
from mythril.ether.ethcontract import ETHContract from tests import BaseTestCase
class ETHContractTestCase(unittest.TestCase): class EVMContractTestCase(BaseTestCase):
def setUp(self): def setUp(self):
super().setUp()
self.code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029" self.code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029"
self.creation_code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029" self.creation_code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029"
class Getinstruction_listTestCase(ETHContractTestCase): class Getinstruction_listTestCase(EVMContractTestCase):
def runTest(self): def runTest(self):
contract = ETHContract(self.code, self.creation_code) contract = EVMContract(self.code, self.creation_code)
disassembly = contract.disassembly disassembly = contract.disassembly
self.assertEqual( self.assertEqual(
len(disassembly.instruction_list), len(disassembly.instruction_list),
53, 53,
"Error disassembling code using ETHContract.get_instruction_list()", "Error disassembling code using EVMContract.get_instruction_list()",
) )
class GetEASMTestCase(ETHContractTestCase): class GetEASMTestCase(EVMContractTestCase):
def runTest(self): def runTest(self):
contract = ETHContract(self.code) contract = EVMContract(self.code)
instruction_list = contract.get_easm() instruction_list = contract.get_easm()
self.assertTrue( self.assertTrue(
"PUSH1 0x60" in instruction_list, "PUSH1 0x60" in instruction_list,
"Error obtaining EASM code through ETHContract.get_easm()", "Error obtaining EASM code through EVMContract.get_easm()",
) )
class MatchesExpressionTestCase(ETHContractTestCase): class MatchesExpressionTestCase(EVMContractTestCase):
def runTest(self): def runTest(self):
contract = ETHContract(self.code) contract = EVMContract(self.code)
self.assertTrue( self.assertTrue(
contract.matches_expression("code#PUSH1# or code#PUSH1#"), contract.matches_expression("code#PUSH1# or code#PUSH1#"),

@ -1,14 +1,18 @@
from mythril.analysis.callgraph import generate_graph from mythril.analysis.callgraph import generate_graph
from mythril.analysis.symbolic import SymExecWrapper from mythril.analysis.symbolic import SymExecWrapper
from mythril.ether import util from mythril.ethereum import util
from mythril.ether.soliditycontract import ETHContract from mythril.solidity.soliditycontract import EVMContract
from tests import * from tests import (
BaseTestCase,
TESTDATA_INPUTS,
TESTDATA_OUTPUTS_EXPECTED,
TESTDATA_OUTPUTS_CURRENT,
)
import re import re
class GraphTest(BaseTestCase): class GraphTest(BaseTestCase):
def test_generate_graph(self): def test_generate_graph(self):
for input_file in TESTDATA_INPUTS.iterdir(): for input_file in TESTDATA_INPUTS.iterdir():
output_expected = TESTDATA_OUTPUTS_EXPECTED / ( output_expected = TESTDATA_OUTPUTS_EXPECTED / (
input_file.name + ".graph.html" input_file.name + ".graph.html"
@ -17,7 +21,7 @@ class GraphTest(BaseTestCase):
input_file.name + ".graph.html" input_file.name + ".graph.html"
) )
contract = ETHContract(input_file.read_text()) contract = EVMContract(input_file.read_text())
sym = SymExecWrapper( sym = SymExecWrapper(
contract, contract,

@ -7,6 +7,7 @@ from datetime import datetime
import binascii import binascii
import json import json
import os
from pathlib import Path from pathlib import Path
import pytest import pytest
from z3 import ExprRef, simplify from z3 import ExprRef, simplify

@ -1,6 +1,6 @@
import pytest import pytest
from mythril.laser.ethereum.state.calldata import Calldata from mythril.laser.ethereum.state.calldata import ConcreteCalldata, SymbolicCalldata
from z3 import Solver, simplify from z3 import Solver, simplify, BitVec, sat, unsat
from z3.z3types import Z3Exception from z3.z3types import Z3Exception
from mock import MagicMock from mock import MagicMock
@ -13,21 +13,11 @@ uninitialized_test_data = [
@pytest.mark.parametrize("starting_calldata", uninitialized_test_data) @pytest.mark.parametrize("starting_calldata", uninitialized_test_data)
def test_concrete_calldata_uninitialized_index(starting_calldata): def test_concrete_calldata_uninitialized_index(starting_calldata):
# Arrange # Arrange
calldata = Calldata(0, starting_calldata) calldata = ConcreteCalldata(0, starting_calldata)
solver = Solver()
# Act # Act
value, constraint1 = calldata[100] value = calldata[100]
value2, constraint2 = calldata.get_word_at(200) value2 = calldata.get_word_at(200)
solver.add(constraint1)
solver.add(constraint2)
solver.check()
model = solver.model()
value = model.eval(value)
value2 = model.eval(value2)
# Assert # Assert
assert value == 0 assert value == 0
@ -36,73 +26,65 @@ def test_concrete_calldata_uninitialized_index(starting_calldata):
def test_concrete_calldata_calldatasize(): def test_concrete_calldata_calldatasize():
# Arrange # Arrange
calldata = Calldata(0, [1, 4, 7, 3, 7, 2, 9]) calldata = ConcreteCalldata(0, [1, 4, 7, 3, 7, 2, 9])
solver = Solver() solver = Solver()
# Act # Act
solver.check() solver.check()
model = solver.model() model = solver.model()
result = model.eval(calldata.calldatasize) result = model.eval(calldata.calldatasize)
# Assert # Assert
assert result == 7 assert result == 7
def test_symbolic_calldata_constrain_index(): def test_concrete_calldata_constrain_index():
# Arrange # Arrange
calldata = Calldata(0) calldata = ConcreteCalldata(0, [1, 4, 7, 3, 7, 2, 9])
solver = Solver() solver = Solver()
# Act # Act
value, calldata_constraints = calldata[100] value = calldata[2]
constraint = value == 50 constraint = value == 3
solver.add([constraint] + calldata_constraints)
solver.check()
model = solver.model()
value = model.eval(value) solver.add([constraint])
calldatasize = model.eval(calldata.calldatasize) result = solver.check()
# Assert # Assert
assert value == 50 assert str(result) == "unsat"
assert simplify(calldatasize >= 100)
def test_concrete_calldata_constrain_index(): def test_symbolic_calldata_constrain_index():
# Arrange # Arrange
calldata = Calldata(0, [1, 4, 7, 3, 7, 2, 9]) calldata = SymbolicCalldata(0)
solver = Solver() solver = Solver()
# Act # Act
value, calldata_constraints = calldata[2] value = calldata[51]
constraint = value == 3
constraints = [value == 1, calldata.calldatasize == 50]
solver.add(constraints)
solver.add([constraint] + calldata_constraints)
result = solver.check() result = solver.check()
# Assert # Assert
assert str(result) == "unsat" assert str(result) == "unsat"
def test_concrete_calldata_constrain_index(): def test_symbolic_calldata_equal_indices():
# Arrange calldata = SymbolicCalldata(0)
calldata = Calldata(0)
mstate = MagicMock()
mstate.constraints = []
solver = Solver()
# Act index_a = BitVec("index_a", 256)
constraints = [] index_b = BitVec("index_b", 256)
value, calldata_constraints = calldata[51]
constraints.append(value == 1)
constraints.append(calldata.calldatasize == 50)
solver.add(constraints + calldata_constraints) # Act
a = calldata[index_a]
b = calldata[index_b]
result = solver.check() s = Solver()
s.append(index_a == index_b)
s.append(a != b)
# Assert # Assert
assert str(result) == "unsat" assert unsat == s.check()

@ -1,16 +1,20 @@
from mythril.mythril import Mythril
from mythril.laser.ethereum.transaction import execute_contract_creation from mythril.laser.ethereum.transaction import execute_contract_creation
from mythril.ether import util from mythril.ethereum import util
import mythril.laser.ethereum.svm as svm import mythril.laser.ethereum.svm as svm
from mythril.disassembler.disassembly import Disassembly from mythril.disassembler.disassembly import Disassembly
from datetime import datetime from datetime import datetime
from mythril.ether.soliditycontract import SolidityContract from mythril.solidity.soliditycontract import SolidityContract
import tests import tests
from mythril.analysis.security import fire_lasers from mythril.analysis.security import fire_lasers
from mythril.analysis.symbolic import SymExecWrapper from mythril.analysis.symbolic import SymExecWrapper
def test_create(): def test_create():
contract = SolidityContract(str(tests.TESTDATA_INPUTS_CONTRACTS / "calls.sol")) contract = SolidityContract(
str(tests.TESTDATA_INPUTS_CONTRACTS / "calls.sol"),
solc_binary=Mythril._init_solc_binary("0.5.0"),
)
laser_evm = svm.LaserEVM({}) laser_evm = svm.LaserEVM({})
@ -31,7 +35,10 @@ def test_create():
def test_sym_exec(): def test_sym_exec():
contract = SolidityContract(str(tests.TESTDATA_INPUTS_CONTRACTS / "calls.sol")) contract = SolidityContract(
str(tests.TESTDATA_INPUTS_CONTRACTS / "calls.sol"),
solc_binary=Mythril._init_solc_binary("0.5.0"),
)
sym = SymExecWrapper( sym = SymExecWrapper(
contract, address=(util.get_indexed_address(0)), strategy="dfs" contract, address=(util.get_indexed_address(0)), strategy="dfs"

@ -0,0 +1,4 @@
[defaults]
leveldb_dir = /Users/bernhardmueller/Library/Ethereum/geth/chaindata
dynamic_loading = infura

File diff suppressed because it is too large Load Diff

@ -1,52 +1,31 @@
from mythril.ether.soliditycontract import SolidityContract from mythril.solidity.soliditycontract import SolidityContract
from mythril.mythril import Mythril
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.machine_state import MachineState from mythril.laser.ethereum.state.machine_state import MachineState
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.ethereum import svm from mythril.laser.ethereum import svm
from tests import * from tests import BaseTestCase
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)] IDENTITY_TEST[0] = (hex(87426857369875698), True)
IDENTITY_TEST[1] = (hex(476934798798347), False)
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)
def _all_info(laser): def _all_info(laser):
@ -98,17 +77,20 @@ def _all_info(laser):
def _test_natives(laser_info, test_list, test_name): def _test_natives(laser_info, test_list, test_name):
success = 0 success = 0
for i, j in test_list: 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 success += 1
else: else:
print("Failed: " + str(i) + " " + str(j)) print("Failed:", str(int(i, 16)), str(j))
assert success == len(test_list) assert success == len(test_list)
class NativeTests(BaseTestCase): class NativeTests(BaseTestCase):
@staticmethod @staticmethod
def runTest(): def runTest():
disassembly = SolidityContract("./tests/native_tests.sol").disassembly
disassembly = SolidityContract(
"./tests/native_tests.sol", solc_binary=Mythril._init_solc_binary("0.5.0")
).disassembly
account = Account("0x0000000000000000000000000000000000000000", disassembly) account = Account("0x0000000000000000000000000000000000000000", disassembly)
accounts = {account.address: account} accounts = {account.address: account}
@ -116,8 +98,8 @@ class NativeTests(BaseTestCase):
laser.sym_exec(account.address) laser.sym_exec(account.address)
laser_info = str(_all_info(laser)) laser_info = str(_all_info(laser))
print("\n")
print(laser_info)
_test_natives(laser_info, SHA256_TEST, "SHA256") _test_natives(laser_info, SHA256_TEST, "SHA256")
_test_natives(laser_info, RIPEMD160_TEST, "RIPEMD160") _test_natives(laser_info, RIPEMD160_TEST, "RIPEMD160")
_test_natives(laser_info, ECRECOVER_TEST, "ECRECOVER") _test_natives(laser_info, ECRECOVER_TEST, "ECRECOVER")

@ -1,147 +1,90 @@
pragma solidity ^0.4.17; pragma solidity 0.5.0;
contract Caller { contract Caller {
address public fixed_address; //Just some useless variables //Just some useless variables
address public stored_address; address public fixedAddress;
address public storedAddress;
uint256 statevar; //useless( but good for testing as they contribute as decoys) //useless (but good for testing as they contribute as decoys)
bytes32 far; uint256 private statevar;
bytes32 private far;
function Caller(address addr) { constructor (address addr) public {
fixed_address = addr; fixedAddress = addr;
} }
function thisisfine() public { //some typical function as a decoy //some typical function as a decoy
fixed_address.call(); function thisisfine() public {
(bool success, bytes memory mem) = fixedAddress.call("");
} }
function sha256_test1() public {
function sha256Test1() public returns (uint256) {
uint256 i; uint256 i;
if(sha256('ab','c') == 0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad){ //True if (sha256(abi.encodePacked("ab", "c")) == sha256("abc")) {
// True
i = 5555555555555555; i = 5555555555555555;
} } else {
// False
if(sha256('abc') == 0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad){ //True
i = 323232325445454546; i = 323232325445454546;
} }
return i;
} }
function sha256_test2() public {
function sha256Test2() public returns (uint256) {
uint256 i; uint256 i;
if(sha256('abd') == 0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad) { //False if (sha256("abd") == sha256(abi.encodePacked("ab", "d"))) {
// True
i = 34756834765834658; i = 34756834765834658;
} } else {
if(sha256('ab','d') == 0xa52d159f262b2c6ddb724a61840befc36eb30c88877a4030b65cbe86298449c9) { //True // False
i = 8756476956956795876987; i = 8756476956956795876987;
} }
} return i;
function sha256_test3() public {
uint256 i;
if(sha256('') == 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855) { //True
i = 5763467587689578369;
}
if(sha256('hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfdhhfdhhhhhh') == 0xe4ebd771f821e3277b77dcc39e94fe7172a5c9c8c12f8885c2d5513385a0a8b8) { //False
i = 948365957658767467857;
}
} }
function ripemd_test1() public { function ripemdTest() public returns (uint256) {
uint256 i; uint256 i;
if(ripemd160('ab','c') == 0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc){ //True bytes20 v1 = ripemd160("");
i = 1242435356364; bytes20 v2 = ripemd160("hhhhh");
}
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 ecrecover_test1() public { if (v1 != v2) {
bytes32 foobar = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8; // True
bytes memory prefix = "\x19Ethereum Signed Message:\n32"; i = 999999999999999999993;
bytes32 prefixedHash = keccak256(prefix, foobar); } else {
// False
i = 1111111111112;
}
return i;
}
function ecrecoverTest() public returns (uint256) {
bytes32 foobar1 = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8;
bytes32 foobar2 = 0x38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e;
uint8 v = 28; uint8 v = 28;
bytes32 r = 0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608; bytes32 r = 0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608;
bytes32 s = 0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada; bytes32 s = 0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada;
if( ecrecover(prefixedHash, v, r, s) == 0x7156526fbd7a3c72969b54f64e42c10fbb768c8a) { //True uint256 i;
uint256 bignum = 786428768768632537676; address addr1 = ecrecover(keccak256(abi.encodePacked(foobar1)), v, r, s);
} address addr2 = ecrecover(keccak256(abi.encodePacked(foobar1, foobar2)), v, r, s);
if( ecrecover(prefixedHash, v, r, s) == 0x7156526fbd7a3c72969b54f64e42c10fbb768c8b) { //False if (addr1 != addr2) {
uint256 small = 4897983476979346779638; // True
} i = 674837568743979857398564869;
foobar = 0x38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e; } else {
if( ecrecover( keccak256(foobar), v, r, s) == 0x0faf91ea0aaaa5377dfdf188b21409007f0b4019) { //True // False
uint256 dk = 674837568743979857398564869; i = 3487683476979311;
}
foobar = 0x38d18acb67d25c7bb9942764b62f18e17054f66a817bd4295423adf9ed98873e; //not same as above, minor change(7bb instead of 8bb)
if( ecrecover( keccak256(foobar), v, r, s) == 0x0faf91ea0aaaa5377dfdf188b21409007f0b4019) { //False
uint256 pk = 3487683476979311;
} }
return i;
} }
function ecrecover_test2() public { //identity is invoked here in compiler and not below
bytes32 foobar = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8; function needIdentityInvoke(uint sea) public returns (uint) {
bytes memory prefix = "\x19Ethereum Signed Message:\n32"; return sea;
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;
}
} }
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 function identityFunction(int input) public returns(int out) {
uint256 bignum = 346934876983476; assembly {
}
}
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{
let x := mload(0x40) let x := mload(0x40)
mstore(x, input) mstore(x, input)
@ -150,17 +93,16 @@ contract Caller {
mstore(0x40, x) 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;
}
} }

@ -1,10 +1,9 @@
from mythril.analysis.report import Report from mythril.analysis.report import Report
from mythril.analysis.security import fire_lasers from mythril.analysis.security import fire_lasers, reset_callback_modules
from mythril.analysis.symbolic import SymExecWrapper from mythril.analysis.symbolic import SymExecWrapper
from mythril.ether import util from mythril.ethereum import util
from mythril.ether.soliditycontract import ETHContract from mythril.solidity.soliditycontract import EVMContract
from multiprocessing import Pool, cpu_count from multiprocessing import Pool, cpu_count
import datetime
import pytest import pytest
import json import json
from tests import * from tests import *
@ -23,7 +22,7 @@ def _fix_debug_data(json_str):
def _generate_report(input_file): def _generate_report(input_file):
contract = ETHContract(input_file.read_text(), enable_online_lookup=False) contract = EVMContract(input_file.read_text(), enable_online_lookup=False)
sym = SymExecWrapper( sym = SymExecWrapper(
contract, contract,
address=(util.get_indexed_address(0)), address=(util.get_indexed_address(0)),
@ -43,6 +42,7 @@ def _generate_report(input_file):
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def reports(): def reports():
""" Fixture that analyses all reports""" """ Fixture that analyses all reports"""
reset_callback_modules()
pool = Pool(cpu_count()) pool = Pool(cpu_count())
input_files = sorted( input_files = sorted(
[f for f in TESTDATA_INPUTS.iterdir() if f.name != "environments.sol.o"] [f for f in TESTDATA_INPUTS.iterdir() if f.name != "environments.sol.o"]

@ -1,9 +1,10 @@
from unittest import TestCase from unittest import TestCase
from tests import BaseTestCase
from mythril.ethereum.interface.rpc.client import EthJsonRpc from mythril.ethereum.interface.rpc.client import EthJsonRpc
class RpcTest(TestCase): class RpcTest(BaseTestCase):
client = None client = None
def setUp(self): def setUp(self):

@ -1,6 +1,7 @@
from pathlib import Path from pathlib import Path
from mythril.ether.soliditycontract import SolidityContract from mythril.mythril import Mythril
from mythril.solidity.soliditycontract import SolidityContract
from tests import BaseTestCase from tests import BaseTestCase
TEST_FILES = Path(__file__).parent / "testdata/input_contracts" TEST_FILES = Path(__file__).parent / "testdata/input_contracts"
@ -9,7 +10,9 @@ TEST_FILES = Path(__file__).parent / "testdata/input_contracts"
class SolidityContractTest(BaseTestCase): class SolidityContractTest(BaseTestCase):
def test_get_source_info_without_name_gets_latest_contract_info(self): def test_get_source_info_without_name_gets_latest_contract_info(self):
input_file = TEST_FILES / "multi_contracts.sol" input_file = TEST_FILES / "multi_contracts.sol"
contract = SolidityContract(str(input_file)) contract = SolidityContract(
str(input_file), solc_binary=Mythril._init_solc_binary("0.5.0")
)
code_info = contract.get_source_info(142) code_info = contract.get_source_info(142)
@ -19,7 +22,11 @@ class SolidityContractTest(BaseTestCase):
def test_get_source_info_with_contract_name_specified(self): def test_get_source_info_with_contract_name_specified(self):
input_file = TEST_FILES / "multi_contracts.sol" input_file = TEST_FILES / "multi_contracts.sol"
contract = SolidityContract(str(input_file), name="Transfer1") contract = SolidityContract(
str(input_file),
name="Transfer1",
solc_binary=Mythril._init_solc_binary("0.5.0"),
)
code_info = contract.get_source_info(142) code_info = contract.get_source_info(142)
@ -29,10 +36,14 @@ class SolidityContractTest(BaseTestCase):
def test_get_source_info_with_contract_name_specified_constructor(self): def test_get_source_info_with_contract_name_specified_constructor(self):
input_file = TEST_FILES / "constructor_assert.sol" input_file = TEST_FILES / "constructor_assert.sol"
contract = SolidityContract(str(input_file), name="AssertFail") contract = SolidityContract(
str(input_file),
name="AssertFail",
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.filename, str(input_file))
self.assertEqual(code_info.lineno, 6) self.assertEqual(code_info.lineno, 6)
self.assertEqual(code_info.code, "assert(var1>0)") self.assertEqual(code_info.code, "assert(var1 > 0)")

@ -2,14 +2,21 @@ import json
from mythril.analysis.security import get_detection_module_hooks from mythril.analysis.security import get_detection_module_hooks
from mythril.analysis.symbolic import SymExecWrapper from mythril.analysis.symbolic import SymExecWrapper
from mythril.analysis.callgraph import generate_graph from mythril.analysis.callgraph import generate_graph
from mythril.ether.ethcontract import ETHContract from mythril.ethereum.evmcontract import EVMContract
from mythril.ether.soliditycontract import SolidityContract from mythril.solidity.soliditycontract import SolidityContract
from mythril.mythril import Mythril
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.machine_state import MachineState from mythril.laser.ethereum.state.machine_state import MachineState
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.ethereum import svm from mythril.laser.ethereum import svm
from tests import * from tests import (
BaseTestCase,
TESTDATA_INPUTS_CONTRACTS,
TESTDATA_OUTPUTS_EXPECTED_LASER_RESULT,
TESTDATA_OUTPUTS_CURRENT_LASER_RESULT,
)
class LaserEncoder(json.JSONEncoder): class LaserEncoder(json.JSONEncoder):
@ -81,7 +88,9 @@ class SVMTestCase(BaseTestCase):
input_file.name + ".json" input_file.name + ".json"
) )
disassembly = SolidityContract(str(input_file)).disassembly disassembly = SolidityContract(
str(input_file), solc_binary=Mythril._init_solc_binary("0.5.0")
).disassembly
account = Account("0x0000000000000000000000000000000000000000", disassembly) account = Account("0x0000000000000000000000000000000000000000", disassembly)
accounts = {account.address: account} accounts = {account.address: account}
@ -105,7 +114,7 @@ class SVMTestCase(BaseTestCase):
code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029" code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029"
contract = ETHContract(code) contract = EVMContract(code)
sym = SymExecWrapper(contract, "0xd0a6E6C543bC68Db5db3A191B171A77407Ff7ccf") sym = SymExecWrapper(contract, "0xd0a6E6C543bC68Db5db3A191B171A77407Ff7ccf")
html = generate_graph(sym) html = generate_graph(sym)

@ -1,6 +1,6 @@
# compile test contracts # compile test contracts
from pathlib import Path from pathlib import Path
from mythril.ether.soliditycontract import SolidityContract from mythril.solidity.soliditycontract import SolidityContract
# Recompiles all the to be tested contracts # Recompiles all the to be tested contracts
root = Path(__file__).parent root = Path(__file__).parent

@ -1,4 +1,4 @@
pragma solidity ^0.4.17; pragma solidity 0.5.0;
contract Caller { contract Caller {
@ -8,28 +8,29 @@ contract Caller {
uint256 statevar; uint256 statevar;
function Caller(address addr) { constructor(address addr) public {
fixed_address = addr; fixed_address = address(0x552254CbAaF32613C6c0450CF19524594eF84044);
} }
function thisisfine() public { function thisisfine() public {
fixed_address.call(); fixed_address.call("");
} }
function reentrancy() public { function reentrancy() public {
fixed_address.call(); fixed_address.call("");
statevar = 0; statevar = 0;
} }
function calluseraddress(address addr) { function calluseraddress(address addr) public {
addr.call(); addr.call("");
} }
function callstoredaddress() { function callstoredaddress() public {
stored_address.call(); stored_address.call("");
statevar = 0;
} }
function setstoredaddress(address addr) { function setstoredaddress(address addr) public {
stored_address = addr; stored_address = addr;
} }

@ -1,8 +1,8 @@
pragma solidity ^0.4.24; pragma solidity 0.5.0;
contract AssertFail {
constructor(uint8 var1){ contract AssertFail {
assert(var1>0); constructor(uint8 var1) public {
} assert(var1 > 0);
}
} }

@ -1,11 +1,11 @@
pragma solidity ^0.4.16; pragma solidity 0.5.0;
contract IntegerOverflow2 { contract IntegerOverflow2 {
uint256 public count = 7; uint256 public count = 7;
mapping(address => uint256) balances; 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; uint cnt = _receivers.length;
uint256 amount = uint256(cnt) * _value; uint256 amount = uint256(cnt) * _value;

@ -1,3 +1,6 @@
pragma solidity 0.5.0;
contract Crowdfunding { contract Crowdfunding {
mapping(address => uint) public balances; mapping(address => uint) public balances;
@ -10,12 +13,12 @@ contract Crowdfunding {
_; _;
} }
function crowdfunding() { function crowdfunding() public {
owner = msg.sender; owner = msg.sender;
} }
function withdrawfunds() onlyOwner { function withdrawfunds() public onlyOwner {
msg.sender.transfer(this.balance); msg.sender.transfer(address(this).balance);
} }
function invest() public payable { function invest() public payable {
@ -24,7 +27,7 @@ contract Crowdfunding {
balances[msg.sender] += msg.value; balances[msg.sender] += msg.value;
} }
function getBalance() public constant returns (uint) { function getBalance() public view returns (uint) {
return balances[msg.sender]; return balances[msg.sender];
} }

@ -1,40 +1,43 @@
pragma solidity 0.5.0;
contract Exceptions { contract Exceptions {
uint256[8] myarray; uint256[8] myarray;
function assert1() { function assert1() public pure {
uint256 i = 1; uint256 i = 1;
assert(i == 0); assert(i == 0);
} }
function assert2() { function assert2() public pure {
uint256 i = 1; uint256 i = 1;
assert(i > 0); assert(i > 0);
} }
function assert3(uint256 input) { function assert3(uint256 input) public pure {
assert(input != 23); assert(input != 23);
} }
function requireisfine(uint256 input) { function requireisfine(uint256 input) public pure {
require(input != 23); require(input != 23);
} }
function divisionby0(uint256 input) { function divisionby0(uint256 input) public pure {
uint256 i = 1/input; uint256 i = 1/input;
} }
function thisisfine(uint256 input) { function thisisfine(uint256 input) public pure {
if (input > 0) { if (input > 0) {
uint256 i = 1/input; uint256 i = 1/input;
} }
} }
function arrayaccess(uint256 index) { function arrayaccess(uint256 index) public view {
uint256 i = myarray[index]; uint256 i = myarray[index];
} }
function thisisalsofind(uint256 index) { function thisisalsofind(uint256 index) public view {
if (index < 8) { if (index < 8) {
uint256 i = myarray[index]; uint256 i = myarray[index];
} }

@ -1,16 +1,19 @@
pragma solidity 0.5.0;
contract D { contract D {
uint public n; uint public n;
address public sender; address public sender;
function callSetN(address _e, uint _n) { function callSetN(address _e, uint _n) public {
_e.call(bytes4(sha3("setN(uint256)")), _n); _e.call(abi.encode(bytes4(keccak256("setN(uint256)")), _n));
} }
function callcodeSetN(address _e, uint _n) { function callcodeSetN(address _e, uint _n) public view {
_e.callcode(bytes4(sha3("setN(uint256)")), _n); _e.staticcall(abi.encode(bytes4(keccak256("setN(uint256)")), _n));
} }
function delegatecallSetN(address _e, uint _n) { function delegatecallSetN(address _e, uint _n) public {
_e.delegatecall(bytes4(sha3("setN(uint256)")), _n); _e.delegatecall(abi.encode(bytes4(keccak256("setN(uint256)")), _n));
} }
} }

@ -1,8 +1,9 @@
pragma solidity ^0.4.17; pragma solidity 0.5.0;
contract MetaCoin { contract MetaCoin {
mapping (address => uint) public balances; mapping (address => uint) public balances;
function MetaCoin() public { constructor() public {
balances[msg.sender] = 10000; balances[msg.sender] = 10000;
} }

@ -1,17 +1,16 @@
pragma solidity ^0.4.17; pragma solidity 0.5.0;
contract Transfer1 {
function transfer() { contract Transfer1 {
msg.sender.transfer(1 ether); 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);
}
} }

@ -1,6 +1,8 @@
pragma solidity ^0.4.22; pragma solidity 0.5.0;
contract nonAscii { contract nonAscii {
function renderNonAscii () public pure returns (string) { function renderNonAscii () public pure returns (string memory) {
return "Хэллоу Ворлд"; return "Хэллоу Ворлд";
} }
} }

@ -1,3 +1,6 @@
pragma solidity 0.5.0;
contract Origin { contract Origin {
address public owner; address public owner;
@ -6,7 +9,7 @@ contract Origin {
* @dev The Ownable constructor sets the original `owner` of the contract to the sender * @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account. * account.
*/ */
function Origin() { constructor() public {
owner = msg.sender; owner = msg.sender;
} }
@ -15,9 +18,7 @@ contract Origin {
* @dev Throws if called by any account other than the owner. * @dev Throws if called by any account other than the owner.
*/ */
modifier onlyOwner() { modifier onlyOwner() {
if (tx.origin != owner) { require(tx.origin != owner);
throw;
}
_; _;
} }
@ -26,7 +27,7 @@ contract Origin {
* @dev Allows the current owner to transfer control of the contract to a newOwner. * @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)) { if (newOwner != address(0)) {
owner = newOwner; owner = newOwner;
} }

@ -1,20 +1,23 @@
pragma solidity 0.5.0;
contract Over { contract Over {
mapping(address => uint) balances; mapping(address => uint) balances;
uint public totalSupply; uint public totalSupply;
function Token(uint _initialSupply) { constructor(uint _initialSupply) public {
balances[msg.sender] = totalSupply = _initialSupply; balances[msg.sender] = totalSupply = _initialSupply;
} }
function sendeth(address _to, uint _value) public returns (bool) { function sendeth(address _to, uint _value) public returns (bool) {
require(balances[msg.sender] - _value >= 0); // require(balances[msg.sender] - _value >= 0);
balances[msg.sender] -= _value; balances[msg.sender] -= _value;
balances[_to] += _value; balances[_to] += _value;
return true; return true;
} }
function balanceOf(address _owner) public constant returns (uint balance) { function balanceOf(address _owner) public view returns (uint balance) {
return balances[_owner]; return balances[_owner];
} }
} }

@ -1,13 +1,17 @@
pragma solidity 0.5.0;
contract ReturnValue { contract ReturnValue {
address callee = 0xE0F7e56e62b4267062172495D7506087205A4229; address public callee = 0xE0f7e56E62b4267062172495D7506087205A4229;
function callnotchecked() { function callnotchecked() public {
callee.call(); callee.call("");
} }
function callchecked() { function callchecked() public {
require(callee.call()); (bool success, bytes memory data) = callee.call("");
require(success);
} }
} }

@ -1,152 +1,152 @@
contract Rubixi { pragma solidity 0.5.0;
//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;
//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 contract Rubixi {
function addPayout(uint _fee) private { //Declare variables for storage critical to contract
//Adds new address to participant array uint private balance = 0;
participants.push(Participant(msg.sender, (msg.value * pyramidMultiplier) / 100)); uint private collectedFees = 0;
uint private feePercent = 10;
//These statements ensure a quicker payout system to later pyramid entrants, so the pyramid has a longer lifespan uint private pyramidMultiplier = 300;
if (participants.length == 10) pyramidMultiplier = 200; uint private payoutOrder = 0;
else if (participants.length == 25) pyramidMultiplier = 150;
address payable private creator;
// collect fees and update contract balance
balance += (msg.value * (100 - _fee)) / 100; modifier onlyowner {
collectedFees += (msg.value * _fee) / 100; if (msg.sender == creator) _;
}
//Pays earlier participiants if balance sufficient
while (balance > participants[payoutOrder].payout) { struct Participant {
uint payoutToSend = participants[payoutOrder].payout; address payable etherAddress;
participants[payoutOrder].etherAddress.send(payoutToSend); uint payout;
}
balance -= participants[payoutOrder].payout;
payoutOrder += 1; //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 currentPyramidBalanceApproximately() public view returns (uint pyramidBalance, string memory info) {
function collectAllFees() onlyowner { pyramidBalance = balance / 1 ether;
if (collectedFees == 0) throw; 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); function nextPayoutWhenPyramidBalanceTotalsApproximately() public view returns (uint balancePayout) {
collectedFees = 0; balancePayout = participants[payoutOrder].payout / 1 ether;
} }
function collectFeesInEther(uint _amt) onlyowner { function feesSeperateFromBalanceApproximately() public view returns (uint fees) {
_amt *= 1 ether; fees = collectedFees / 1 ether;
if (_amt > collectedFees) collectAllFees(); }
if (collectedFees == 0) throw; function totalParticipants() public view returns (uint count) {
count = participants.length;
creator.send(_amt); }
collectedFees -= _amt;
}
function collectPercentOfFees(uint _pcent) onlyowner { function numberOfParticipantsWaitingForPayout() public view returns (uint count) {
if (collectedFees == 0 || _pcent > 100) throw; count = participants.length - payoutOrder;
}
uint feesToCollect = collectedFees / 100 * _pcent; function participantDetails(uint orderInPyramid) public view returns (address addr, uint payout) {
creator.send(feesToCollect); if (orderInPyramid <= participants.length) {
collectedFees -= feesToCollect; addr = participants[orderInPyramid].etherAddress;
payout = participants[orderInPyramid].payout / 1 ether;
} }
}
//Functions for changing variables related to the contract //init function run on fallback
function changeOwner(address _owner) onlyowner { function init() private {
creator = _owner; //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 { uint _fee = feePercent;
if (_mult > 300 || _mult < 120) throw; // 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 { //Function called for valid tx to the contract
if (_fee > 10) throw; 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 // collect fees and update contract balance
function currentMultiplier() constant returns(uint multiplier, string info) { balance += (msg.value * (100 - _fee)) / 100;
multiplier = pyramidMultiplier; collectedFees += (msg.value * _fee) / 100;
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%)';
}
function currentPyramidBalanceApproximately() constant returns(uint pyramidBalance, string info) { //Pays earlier participiants if balance sufficient
pyramidBalance = balance / 1 ether; while (balance > participants[payoutOrder].payout) {
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'; uint payoutToSend = participants[payoutOrder].payout;
} participants[payoutOrder].etherAddress.transfer(payoutToSend);
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;
}
function participantDetails(uint orderInPyramid) constant returns(address Address, uint Payout) { balance -= participants[payoutOrder].payout;
if (orderInPyramid <= participants.length) { payoutOrder += 1;
Address = participants[orderInPyramid].etherAddress;
Payout = participants[orderInPyramid].payout / 1 ether;
}
} }
}
} }

@ -1,6 +1,9 @@
pragma solidity 0.5.0;
contract Suicide { contract Suicide {
function kill(address addr) { function kill(address payable addr) public {
selfdestruct(addr); selfdestruct(addr);
} }

@ -1,9 +1,12 @@
pragma solidity 0.5.0;
contract Under { contract Under {
mapping(address => uint) balances; mapping(address => uint) balances;
uint public totalSupply; uint public totalSupply;
function Token(uint _initialSupply) { constructor(uint _initialSupply) public {
balances[msg.sender] = totalSupply = _initialSupply; balances[msg.sender] = totalSupply = _initialSupply;
} }
@ -14,7 +17,7 @@ contract Under {
return true; return true;
} }
function balanceOf(address _owner) public constant returns (uint balance) { function balanceOf(address _owner) public view returns (uint balance) {
return balances[_owner]; return balances[_owner];
} }
} }

@ -1,20 +1,21 @@
pragma solidity ^0.4.16; pragma solidity 0.5.0;
contract WeakRandom { contract WeakRandom {
struct Contestant { struct Contestant {
address addr; address payable addr;
uint gameId; uint gameId;
} }
uint public constant prize = 2.5 ether; uint public prize = 2.5 ether;
uint public constant totalTickets = 50; uint public totalTickets = 50;
uint public constant pricePerTicket = prize / totalTickets; uint public pricePerTicket = prize / totalTickets;
uint public gameId = 1; uint public gameId = 1;
uint public nextTicket = 0; uint public nextTicket = 0;
mapping (uint => Contestant) public contestants; mapping (uint => Contestant) public contestants;
function () payable public { function () payable external {
uint moneySent = msg.value; uint moneySent = msg.value;
while (moneySent >= pricePerTicket && nextTicket < totalTickets) { while (moneySent >= pricePerTicket && nextTicket < totalTickets) {
@ -37,10 +38,10 @@ contract WeakRandom {
address seed1 = contestants[uint(block.coinbase) % totalTickets].addr; address seed1 = contestants[uint(block.coinbase) % totalTickets].addr;
address seed2 = contestants[uint(msg.sender) % totalTickets].addr; address seed2 = contestants[uint(msg.sender) % totalTickets].addr;
uint seed3 = block.difficulty; uint seed3 = block.difficulty;
bytes32 randHash = keccak256(seed1, seed2, seed3); bytes32 randHash = keccak256(abi.encode(seed1, seed2, seed3));
uint winningNumber = uint(randHash) % totalTickets; uint winningNumber = uint(randHash) % totalTickets;
address winningAddress = contestants[winningNumber].addr; address payable winningAddress = contestants[winningNumber].addr;
gameId++; gameId++;
nextTicket = 0; nextTicket = 0;

@ -1,126 +1 @@
{ {"error": null, "issues": [{"address": 661, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", "function": "thisisfine()", "max_gas_used": 1254, "min_gas_used": 643, "swc-id": "107", "title": "External call", "type": "Informational"}, {"address": 666, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "thisisfine()", "max_gas_used": 35963, "min_gas_used": 1352, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 779, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", "function": "callstoredaddress()", "max_gas_used": 1298, "min_gas_used": 687, "swc-id": "107", "title": "External call", "type": "Informational"}, {"address": 784, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "callstoredaddress()", "max_gas_used": 36007, "min_gas_used": 1396, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 858, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", "function": "reentrancy()", "max_gas_used": 1320, "min_gas_used": 709, "swc-id": "107", "title": "External call", "type": "Informational"}, {"address": 871, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "reentrancy()", "max_gas_used": 61043, "min_gas_used": 6432, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 912, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call with high gas to a user-supplied address. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent unanticipated effects on the contract state.", "function": "calluseraddress(address)", "max_gas_used": 616, "min_gas_used": 335, "swc-id": "107", "title": "External call to user-supplied address", "type": "Warning"}, {"address": 918, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "calluseraddress(address)", "max_gas_used": 35327, "min_gas_used": 1046, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true}
"error": null,
"issues": [
{
"address": 661,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.",
"function": "thisisfine()",
"swc-id": "107",
"min_gas_used": 643,
"max_gas_used": 1254,
"title": "Message call to external contract",
"type": "Informational"
},
{
"address": 666,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "thisisfine()",
"swc-id": "104",
"min_gas_used": 1352,
"max_gas_used": 35963,
"title": "Unchecked CALL return value",
"type": "Informational"
},
{
"address": 779,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "This contract executes a message call to an address found at storage slot 1. This storage slot can be written to by calling the function `setstoredaddress(address)`. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.",
"function": "callstoredaddress()",
"swc-id": "107",
"min_gas_used": 687,
"max_gas_used": 1298,
"title": "Message call to external contract",
"type": "Warning"
},
{
"address": 779,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "Possible transaction order dependence vulnerability: The value or direction of the call statement is determined from a tainted storage location.",
"function": "callstoredaddress()",
"swc-id": "114",
"min_gas_used": 687,
"max_gas_used": 1298,
"title": "Transaction order dependence",
"type": "Warning"
},
{
"address": 784,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "callstoredaddress()",
"swc-id": "104",
"min_gas_used": 1396,
"max_gas_used": 36007,
"title": "Unchecked CALL return value",
"type": "Informational"
},
{
"address": 858,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.",
"function": "_function_0xe11f493e",
"swc-id": "107",
"min_gas_used": 709,
"max_gas_used": 1320,
"title": "Message call to external contract",
"type": "Informational"
},
{
"address": 869,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.",
"function": "_function_0xe11f493e",
"swc-id": "107",
"min_gas_used": 709,
"max_gas_used": 1320,
"title": "State change after external call",
"type": "Warning"
},
{
"address": 871,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "_function_0xe11f493e",
"swc-id": "104",
"min_gas_used": 6432,
"max_gas_used": 61043,
"title": "Unchecked CALL return value",
"type": "Informational"
},
{
"address": 912,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.",
"function": "calluseraddress(address)",
"swc-id": "107",
"min_gas_used": 335,
"max_gas_used": 616,
"title": "Message call to external contract",
"type": "Warning"
},
{
"address": 918,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "calluseraddress(address)",
"swc-id": "104",
"min_gas_used": 1046,
"max_gas_used": 35327,
"title": "Unchecked CALL return value",
"type": "Informational"
}
],
"success": true
}

@ -1,6 +1,6 @@
# Analysis results for test-filename.sol # Analysis results for test-filename.sol
## Message call to external contract ## External call
- SWC ID: 107 - SWC ID: 107
- Type: Informational - Type: Informational
- Contract: Unknown - Contract: Unknown
@ -10,7 +10,7 @@
### Description ### Description
This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code. The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.
## Unchecked CALL return value ## Unchecked CALL return value
- SWC ID: 104 - SWC ID: 104
@ -24,21 +24,9 @@ This contract executes a message call to to another contract. Make sure that the
The return value of an external call is not checked. Note that execution continue even if the called contract throws. The return value of an external call is not checked. Note that execution continue even if the called contract throws.
## Message call to external contract ## External call
- SWC ID: 107 - SWC ID: 107
- Type: Warning - Type: Informational
- Contract: Unknown
- Function name: `callstoredaddress()`
- PC address: 779
- Estimated Gas Usage: 687 - 1298
### Description
This contract executes a message call to an address found at storage slot 1. This storage slot can be written to by calling the function `setstoredaddress(address)`. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.
## Transaction order dependence
- SWC ID: 114
- Type: Warning
- Contract: Unknown - Contract: Unknown
- Function name: `callstoredaddress()` - Function name: `callstoredaddress()`
- PC address: 779 - PC address: 779
@ -46,7 +34,7 @@ This contract executes a message call to an address found at storage slot 1. Thi
### Description ### Description
Possible transaction order dependence vulnerability: The value or direction of the call statement is determined from a tainted storage location. The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.
## Unchecked CALL return value ## Unchecked CALL return value
- SWC ID: 104 - SWC ID: 104
@ -60,35 +48,23 @@ Possible transaction order dependence vulnerability: The value or direction of t
The return value of an external call is not checked. Note that execution continue even if the called contract throws. The return value of an external call is not checked. Note that execution continue even if the called contract throws.
## Message call to external contract ## External call
- SWC ID: 107 - SWC ID: 107
- Type: Informational - Type: Informational
- Contract: Unknown - Contract: Unknown
- Function name: `_function_0xe11f493e` - Function name: `reentrancy()`
- PC address: 858 - PC address: 858
- Estimated Gas Usage: 709 - 1320 - Estimated Gas Usage: 709 - 1320
### Description ### Description
This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code. The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.
## State change after external call
- SWC ID: 107
- Type: Warning
- Contract: Unknown
- Function name: `_function_0xe11f493e`
- PC address: 869
- Estimated Gas Usage: 709 - 1320
### Description
The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.
## Unchecked CALL return value ## Unchecked CALL return value
- SWC ID: 104 - SWC ID: 104
- Type: Informational - Type: Informational
- Contract: Unknown - Contract: Unknown
- Function name: `_function_0xe11f493e` - Function name: `reentrancy()`
- PC address: 871 - PC address: 871
- Estimated Gas Usage: 6432 - 61043 - Estimated Gas Usage: 6432 - 61043
@ -96,7 +72,7 @@ The contract account state is changed after an external call. Consider that the
The return value of an external call is not checked. Note that execution continue even if the called contract throws. The return value of an external call is not checked. Note that execution continue even if the called contract throws.
## Message call to external contract ## External call to user-supplied address
- SWC ID: 107 - SWC ID: 107
- Type: Warning - Type: Warning
- Contract: Unknown - Contract: Unknown
@ -106,7 +82,7 @@ The return value of an external call is not checked. Note that execution continu
### Description ### Description
This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state. The contract executes a function call with high gas to a user-supplied address. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent unanticipated effects on the contract state.
## Unchecked CALL return value ## Unchecked CALL return value
- SWC ID: 104 - SWC ID: 104

@ -1,11 +1,11 @@
==== Message call to external contract ==== ==== External call ====
SWC ID: 107 SWC ID: 107
Type: Informational Type: Informational
Contract: Unknown Contract: Unknown
Function name: thisisfine() Function name: thisisfine()
PC address: 661 PC address: 661
Estimated Gas Usage: 643 - 1254 Estimated Gas Usage: 643 - 1254
This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code. The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.
-------------------- --------------------
==== Unchecked CALL return value ==== ==== Unchecked CALL return value ====
@ -18,24 +18,14 @@ Estimated Gas Usage: 1352 - 35963
The return value of an external call is not checked. Note that execution continue even if the called contract throws. The return value of an external call is not checked. Note that execution continue even if the called contract throws.
-------------------- --------------------
==== Message call to external contract ==== ==== External call ====
SWC ID: 107 SWC ID: 107
Type: Warning Type: Informational
Contract: Unknown
Function name: callstoredaddress()
PC address: 779
Estimated Gas Usage: 687 - 1298
This contract executes a message call to an address found at storage slot 1. This storage slot can be written to by calling the function `setstoredaddress(address)`. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.
--------------------
==== Transaction order dependence ====
SWC ID: 114
Type: Warning
Contract: Unknown Contract: Unknown
Function name: callstoredaddress() Function name: callstoredaddress()
PC address: 779 PC address: 779
Estimated Gas Usage: 687 - 1298 Estimated Gas Usage: 687 - 1298
Possible transaction order dependence vulnerability: The value or direction of the call statement is determined from a tainted storage location. The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.
-------------------- --------------------
==== Unchecked CALL return value ==== ==== Unchecked CALL return value ====
@ -48,44 +38,34 @@ Estimated Gas Usage: 1396 - 36007
The return value of an external call is not checked. Note that execution continue even if the called contract throws. The return value of an external call is not checked. Note that execution continue even if the called contract throws.
-------------------- --------------------
==== Message call to external contract ==== ==== External call ====
SWC ID: 107 SWC ID: 107
Type: Informational Type: Informational
Contract: Unknown Contract: Unknown
Function name: _function_0xe11f493e Function name: reentrancy()
PC address: 858 PC address: 858
Estimated Gas Usage: 709 - 1320 Estimated Gas Usage: 709 - 1320
This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code. The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.
--------------------
==== State change after external call ====
SWC ID: 107
Type: Warning
Contract: Unknown
Function name: _function_0xe11f493e
PC address: 869
Estimated Gas Usage: 709 - 1320
The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.
-------------------- --------------------
==== Unchecked CALL return value ==== ==== Unchecked CALL return value ====
SWC ID: 104 SWC ID: 104
Type: Informational Type: Informational
Contract: Unknown Contract: Unknown
Function name: _function_0xe11f493e Function name: reentrancy()
PC address: 871 PC address: 871
Estimated Gas Usage: 6432 - 61043 Estimated Gas Usage: 6432 - 61043
The return value of an external call is not checked. Note that execution continue even if the called contract throws. The return value of an external call is not checked. Note that execution continue even if the called contract throws.
-------------------- --------------------
==== Message call to external contract ==== ==== External call to user-supplied address ====
SWC ID: 107 SWC ID: 107
Type: Warning Type: Warning
Contract: Unknown Contract: Unknown
Function name: calluseraddress(address) Function name: calluseraddress(address)
PC address: 912 PC address: 912
Estimated Gas Usage: 335 - 616 Estimated Gas Usage: 335 - 616
This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state. The contract executes a function call with high gas to a user-supplied address. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent unanticipated effects on the contract state.
-------------------- --------------------
==== Unchecked CALL return value ==== ==== Unchecked CALL return value ====

@ -1,36 +1,36 @@
{ {
"error": null, "error": null,
"issues": [ "issues": [
{ {
"address": 158, "address": 158,
"contract": "Unknown", "contract": "Unknown",
"debug": "<DEBUG-DATA>", "debug": "<DEBUG-DATA>",
"description": "The arithmetic operation can result in integer overflow.\n", "description": "The arithmetic operation can result in integer overflow.\n",
"function": "_function_0x83f12fec", "function": "_function_0x83f12fec",
"swc-id": "101", "swc-id": "101",
"title": "Integer Overflow", "title": "Integer Overflow",
"type": "Warning" "type": "Warning",
}, },
{ {
"address": 278, "address": 278,
"contract": "Unknown", "contract": "Unknown",
"debug": "<DEBUG-DATA>", "debug": "<DEBUG-DATA>",
"description": "The arithmetic operation can result in integer overflow.\n", "description": "The arithmetic operation can result in integer overflow.\n",
"function": "_function_0x83f12fec", "function": "_function_0x83f12fec",
"swc-id": "101", "swc-id": "101",
"title": "Integer Overflow", "title": "Integer Overflow",
"type": "Warning" "type": "Warning",
}, },
{ {
"address": 378, "address": 378,
"contract": "Unknown", "contract": "Unknown",
"debug": "<DEBUG-DATA>", "debug": "<DEBUG-DATA>",
"description": "The substraction can result in an integer underflow.\n", "description": "The substraction can result in an integer underflow.\n",
"function": "_function_0x83f12fec", "function": "_function_0x83f12fec",
"swc-id": "101", "swc-id": "101",
"title": "Integer Underflow", "title": "Integer Underflow",
"type": "Warning" "type": "Warning",
} },
], ],
"success": true "success": true,
} }

@ -1,30 +1,5 @@
{ {
"error": null, "error": null,
"issues": [ "issues": [],
{
"address": 722,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "Arbitrary senders other than the contract creator can withdraw ETH from the contract account without previously having sent an equivalent amount of ETH to it. This is likely to be a vulnerability.",
"function": "withdrawfunds()",
"max_gas_used": 1749,
"min_gas_used": 1138,
"swc-id": "105",
"title": "Ether thief",
"type": "Warning"
},
{
"address": 883,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "This binary add operation can result in integer overflow.\n",
"function": "invest()",
"max_gas_used": 1856,
"min_gas_used": 1571,
"swc-id": "101",
"title": "Integer Overflow",
"type": "Warning"
}
],
"success": true "success": true
} }

@ -1,25 +1,3 @@
# Analysis results for test-filename.sol # Analysis results for None
## Ether thief The analysis was completed successfully. No issues were detected.
- SWC ID: 105
- Type: Warning
- Contract: Unknown
- Function name: `withdrawfunds()`
- PC address: 722
- Estimated Gas Usage: 1138 - 1749
### Description
Arbitrary senders other than the contract creator can withdraw ETH from the contract account without previously having sent an equivalent amount of ETH to it. This is likely to be a vulnerability.
## Integer Overflow
- SWC ID: 101
- Type: Warning
- Contract: Unknown
- Function name: `invest()`
- PC address: 883
- Estimated Gas Usage: 1571 - 1856
### Description
This binary add operation can result in integer overflow.

@ -1,21 +1 @@
==== Ether thief ==== The analysis was completed successfully. No issues were detected.
SWC ID: 105
Type: Warning
Contract: Unknown
Function name: withdrawfunds()
PC address: 722
Estimated Gas Usage: 1138 - 1749
Arbitrary senders other than the contract creator can withdraw ETH from the contract account without previously having sent an equivalent amount of ETH to it. This is likely to be a vulnerability.
--------------------
==== Integer Overflow ====
SWC ID: 101
Type: Warning
Contract: Unknown
Function name: invest()
PC address: 883
Estimated Gas Usage: 1571 - 1856
This binary add operation can result in integer overflow.
--------------------

@ -7,9 +7,9 @@
"debug": "<DEBUG-DATA>", "debug": "<DEBUG-DATA>",
"description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking.", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking.",
"function": "assert3(uint256)", "function": "assert3(uint256)",
"swc-id": "110",
"min_gas_used": 206,
"max_gas_used": 301, "max_gas_used": 301,
"min_gas_used": 206,
"swc-id": "110",
"title": "Exception state", "title": "Exception state",
"type": "Informational" "type": "Informational"
}, },
@ -19,9 +19,9 @@
"debug": "<DEBUG-DATA>", "debug": "<DEBUG-DATA>",
"description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking.", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking.",
"function": "arrayaccess(uint256)", "function": "arrayaccess(uint256)",
"swc-id": "110",
"min_gas_used": 256,
"max_gas_used": 351, "max_gas_used": 351,
"min_gas_used": 256,
"swc-id": "110",
"title": "Exception state", "title": "Exception state",
"type": "Informational" "type": "Informational"
}, },
@ -31,9 +31,9 @@
"debug": "<DEBUG-DATA>", "debug": "<DEBUG-DATA>",
"description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking.", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking.",
"function": "divisionby0(uint256)", "function": "divisionby0(uint256)",
"swc-id": "110",
"min_gas_used": 272,
"max_gas_used": 367, "max_gas_used": 367,
"min_gas_used": 272,
"swc-id": "110",
"title": "Exception state", "title": "Exception state",
"type": "Informational" "type": "Informational"
}, },
@ -43,9 +43,9 @@
"debug": "<DEBUG-DATA>", "debug": "<DEBUG-DATA>",
"description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking.", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking.",
"function": "assert1()", "function": "assert1()",
"swc-id": "110",
"min_gas_used": 268,
"max_gas_used": 363, "max_gas_used": 363,
"min_gas_used": 268,
"swc-id": "110",
"title": "Exception state", "title": "Exception state",
"type": "Informational" "type": "Informational"
} }

@ -1,54 +1 @@
{ {"error": null, "issues": [{"address": 626, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x141f32ff", "max_gas_used": 35856, "min_gas_used": 1104, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 857, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x9b58bc26", "max_gas_used": 35919, "min_gas_used": 1167, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 1038, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call with high gas to a user-supplied address. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent unanticipated effects on the contract state.", "function": "_function_0xeea4c864", "max_gas_used": 1229, "min_gas_used": 477, "swc-id": "107", "title": "External call to user-supplied address", "type": "Warning"}, {"address": 1046, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xeea4c864", "max_gas_used": 35944, "min_gas_used": 1192, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true}
"error": null,
"issues": [
{
"address": 626,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "_function_0x141f32ff",
"swc-id": "104",
"min_gas_used": 1104,
"max_gas_used": 35856,
"title": "Unchecked CALL return value",
"type": "Informational"
},
{
"address": 857,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "_function_0x9b58bc26",
"swc-id": "104",
"min_gas_used": 1167,
"max_gas_used": 35919,
"title": "Unchecked CALL return value",
"type": "Informational"
},
{
"address": 1038,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.",
"function": "_function_0xeea4c864",
"swc-id": "107",
"min_gas_used": 477,
"max_gas_used": 1229,
"title": "Message call to external contract",
"type": "Warning"
},
{
"address": 1046,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "_function_0xeea4c864",
"swc-id": "104",
"min_gas_used": 1192,
"max_gas_used": 35944,
"title": "Unchecked CALL return value",
"type": "Informational"
}
],
"success": true
}

@ -24,7 +24,7 @@ The return value of an external call is not checked. Note that execution continu
The return value of an external call is not checked. Note that execution continue even if the called contract throws. The return value of an external call is not checked. Note that execution continue even if the called contract throws.
## Message call to external contract ## External call to user-supplied address
- SWC ID: 107 - SWC ID: 107
- Type: Warning - Type: Warning
- Contract: Unknown - Contract: Unknown
@ -34,7 +34,7 @@ The return value of an external call is not checked. Note that execution continu
### Description ### Description
This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state. The contract executes a function call with high gas to a user-supplied address. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent unanticipated effects on the contract state.
## Unchecked CALL return value ## Unchecked CALL return value
- SWC ID: 104 - SWC ID: 104

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save