Merge branch 'master' of github.com:ConsenSys/mythril

pull/598/head
Bernhard Mueller 6 years ago
commit a2f6a1a017
  1. 9
      Dockerfile
  2. 4
      mythril/analysis/modules/dependence_on_predictable_vars.py
  3. 2
      mythril/analysis/modules/deprecated_ops.py
  4. 4
      mythril/analysis/modules/ether_send.py
  5. 6
      mythril/analysis/modules/multiple_sends.py
  6. 1
      mythril/analysis/symbolic.py
  7. 2
      mythril/analysis/templates/callgraph.html
  8. 8
      mythril/analysis/traceexplore.py
  9. 4
      mythril/ether/ethcontract.py
  10. 115
      mythril/ether/evm.py
  11. 17
      mythril/ethereum/interface/leveldb/accountindexing.py
  12. 61
      mythril/ethereum/interface/leveldb/client.py
  13. 32
      mythril/ethereum/interface/leveldb/state.py
  14. 4
      mythril/interfaces/cli.py
  15. 2
      mythril/laser/ethereum/call.py
  16. 10
      mythril/laser/ethereum/instructions.py
  17. 2
      mythril/laser/ethereum/state.py
  18. 3
      mythril/laser/ethereum/transaction/transaction_models.py
  19. 11
      mythril/mythril.py
  20. 4
      static/Ownable.html
  21. 5
      static/assertions.html
  22. 4
      static/mythril.html
  23. 2
      tests/analysis/test_delegatecall.py
  24. 2
      tests/laser/state/mstack_test.py
  25. 2
      tests/laser/transaction/symbolic_test.py
  26. 3
      tests/taint_runner_test.py
  27. 2
      tests/testdata/outputs_expected/calls.sol.o.graph.html
  28. 2
      tests/testdata/outputs_expected/environments.sol.o.graph.html
  29. 2
      tests/testdata/outputs_expected/ether_send.sol.o.graph.html
  30. 2
      tests/testdata/outputs_expected/exceptions.sol.o.graph.html
  31. 2
      tests/testdata/outputs_expected/kinds_of_calls.sol.o.graph.html
  32. 2
      tests/testdata/outputs_expected/metacoin.sol.o.graph.html
  33. 2
      tests/testdata/outputs_expected/multi_contracts.sol.o.graph.html
  34. 2
      tests/testdata/outputs_expected/nonascii.sol.o.graph.html
  35. 2
      tests/testdata/outputs_expected/origin.sol.o.graph.html
  36. 2
      tests/testdata/outputs_expected/origin.sol.o.json
  37. 2
      tests/testdata/outputs_expected/origin.sol.o.markdown
  38. 2
      tests/testdata/outputs_expected/origin.sol.o.text
  39. 2
      tests/testdata/outputs_expected/overflow.sol.o.graph.html
  40. 2
      tests/testdata/outputs_expected/returnvalue.sol.o.graph.html
  41. 2
      tests/testdata/outputs_expected/suicide.sol.o.graph.html
  42. 2
      tests/testdata/outputs_expected/underflow.sol.o.graph.html

@ -18,15 +18,18 @@ RUN apt-get update \
git \
&& ln -s /usr/bin/python3 /usr/local/bin/python
COPY . /opt/mythril
COPY ./requirements.txt /opt/mythril/requirements.txt
RUN cd /opt/mythril \
&& pip3 install -r requirements.txt \
&& python setup.py install
&& pip3 install -r requirements.txt
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US.en
ENV LC_ALL en_US.UTF-8
COPY . /opt/mythril
RUN cd /opt/mythril \
&& python setup.py install
ENTRYPOINT ["/usr/local/bin/myth"]

@ -120,8 +120,8 @@ def solve(call):
model = solver.get_model(call.node.constraints)
logging.debug("[DEPENDENCE_ON_PREDICTABLE_VARS] MODEL: " + str(model))
for d in model.decls():
logging.debug("[DEPENDENCE_ON_PREDICTABLE_VARS] main model: %s = 0x%x" % (d.name(), model[d].as_long()))
for decl in model.decls():
logging.debug("[DEPENDENCE_ON_PREDICTABLE_VARS] main model: %s = 0x%x" % (decl.name(), model[decl].as_long()))
return True
except UnsatError:

@ -24,7 +24,7 @@ def execute(statespace):
instruction = state.get_current_instruction()
if instruction['opcode'] == "ORIGIN":
description = "Function %s retrieves the transaction origin (tx.origin) using the ORIGIN opcode. " \
description = "The function `{}` retrieves the transaction origin (tx.origin) using the ORIGIN opcode. " \
"Use msg.sender instead.\nSee also: " \
"https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin".format(node.function_name)

@ -111,8 +111,8 @@ def execute(statespace):
try:
model = solver.get_model(node.constraints)
for d in model.decls():
logging.debug("[ETHER_SEND] main model: %s = 0x%x" % (d.name(), model[d].as_long()))
for decl in model.decls():
logging.debug("[ETHER_SEND] main model: %s = 0x%x" % (decl.name(), model[decl].as_long()))
debug = "SOLVER OUTPUT:\n" + solver.pretty_print_model(model)

@ -25,8 +25,8 @@ def execute(statespace):
swc_id=MULTIPLE_SENDS, title="Multiple Calls", _type="Informational")
issue.description = \
"Multiple sends exist in one transaction, try to isolate each external call into its own transaction." \
" As external calls can fail accidentally or deliberately.\nConsecutive calls: \n"
"Multiple sends exist in one transaction. Try to isolate each external call into its own transaction," \
" as external calls can fail accidentally or deliberately.\nConsecutive calls: \n"
for finding in findings:
issue.description += \
@ -38,7 +38,7 @@ def execute(statespace):
def _explore_nodes(call, statespace):
children = _child_nodes(statespace, call.node)
sending_children = list(filter(lambda call: call.node in children, statespace.calls))
sending_children = list(filter(lambda c: c.node in children, statespace.calls))
return sending_children

@ -16,7 +16,6 @@ class SymExecWrapper:
def __init__(self, contract, address, strategy, dynloader=None, max_depth=22,
execution_timeout=None, create_timeout=None, max_transaction_count=3):
s_strategy = None
if strategy == 'dfs':
s_strategy = DepthFirstSearchStrategy
elif strategy == 'bfs':

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title> Laser - Call Graph</title>
<title>Call Graph</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" integrity="sha256-iq5ygGJ7021Pi7H5S+QAUXCPUfaBzfqeplbg/KlEssg=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js" integrity="sha256-JuQeAGbk9rG/EoRMixuy5X8syzICcvB0dj3KindZkY0=" crossorigin="anonymous"></script>

@ -13,8 +13,8 @@ colors = [
{'border': '#4753bf', 'background': '#3b46a1', 'highlight': {'border': '#fff', 'background': '#424db3'}},
]
def get_serializable_statespace(statespace):
nodes = []
edges = []
@ -40,10 +40,10 @@ def get_serializable_statespace(statespace):
color = color_map[node.get_cfg_dict()['contract_name']]
def get_state_accounts(state):
def get_state_accounts(node_state):
state_accounts = []
for key in state.accounts:
account = state.accounts[key].as_dict
for key in node_state.accounts:
account = node_state.accounts[key].as_dict
account.pop('code', None)
account['balance'] = str(account['balance'])

@ -12,8 +12,8 @@ class ETHContract(persistent.Persistent):
# Dynamic contract addresses of the format __[contract-name]_____________ are replaced with a generic address
# Apply this for creation_code & code
creation_code = re.sub(r'(_+.*_+)', 'aa' * 20, creation_code)
code = re.sub(r'(_+.*_+)', 'aa' * 20, code)
creation_code = re.sub(r'(_{2}.{38})', 'aa' * 20, creation_code)
code = re.sub(r'(_{2}.{38})', 'aa' * 20, code)
self.creation_code = creation_code
self.name = name

@ -7,69 +7,52 @@ 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)
res, gas, dat = vm.vm_execute(ext, message, util.safe_decode(code))
stream_handler.flush()
ret = output.getvalue()
lines = ret.split("\n")
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))
trace.append({'pc': pc, 'op': op, 'stack': stack, 'pushvalue': pushvalue})
else:
trace.append({'pc': pc, 'op': op, 'stack': stack})
return trace
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

@ -63,16 +63,15 @@ class AccountIndexer(object):
def get_contract_by_hash(self, contract_hash):
"""
get mapped address by its hash, if not found try indexing
get mapped contract_address by its hash, if not found try indexing
"""
address = self.db.reader._get_address_by_hash(contract_hash)
if address is not None:
return address
contract_address = self.db.reader._get_address_by_hash(contract_hash)
if contract_address is not None:
return contract_address
else:
raise AddressNotFoundError
return self.db.reader._get_address_by_hash(contract_hash)
def _process(self, startblock):
"""
Processesing method
@ -82,9 +81,9 @@ class AccountIndexer(object):
addresses = []
for blockNum in range(startblock, startblock + BATCH_SIZE):
hash = self.db.reader._get_block_hash(blockNum)
if hash is not None:
receipts = self.db.reader._get_block_receipts(hash, blockNum)
block_hash = self.db.reader._get_block_hash(blockNum)
if block_hash is not None:
receipts = self.db.reader._get_block_receipts(block_hash, blockNum)
for receipt in receipts:
if receipt.contractAddress is not None and not all(b == 0 for b in receipt.contractAddress):

@ -79,52 +79,43 @@ class LevelDBReader(object):
gets head block header
"""
if not self.head_block_header:
hash = self.db.get(head_header_key)
num = self._get_block_number(hash)
self.head_block_header = self._get_block_header(hash, num)
block_hash = self.db.get(head_header_key)
num = self._get_block_number(block_hash)
self.head_block_header = self._get_block_header(block_hash, num)
# find header with valid state
while not self.db.get(self.head_block_header.state_root) and self.head_block_header.prevhash is not None:
hash = self.head_block_header.prevhash
num = self._get_block_number(hash)
self.head_block_header = self._get_block_header(hash, num)
block_hash = self.head_block_header.prevhash
num = self._get_block_number(block_hash)
self.head_block_header = self._get_block_header(block_hash, num)
return self.head_block_header
def _get_block_number(self, hash):
"""
gets block number by hash
"""
number_key = block_hash_prefix + hash
def _get_block_number(self, block_hash):
"""Get block number by its hash"""
number_key = block_hash_prefix + block_hash
return self.db.get(number_key)
def _get_block_header(self, hash, num):
"""
get block header by block header hash & number
"""
header_key = header_prefix + num + hash
def _get_block_header(self, block_hash, num):
"""Get block header by block header hash & number"""
header_key = header_prefix + num + block_hash
block_header_data = self.db.get(header_key)
header = rlp.decode(block_header_data, sedes=BlockHeader)
return header
def _get_address_by_hash(self, hash):
"""
get mapped address by its hash
"""
address_key = address_prefix + hash
def _get_address_by_hash(self, block_hash):
"""Get mapped address by its hash"""
address_key = address_prefix + block_hash
return self.db.get(address_key)
def _get_last_indexed_number(self):
"""
latest indexed block number
"""
"""Get latest indexed block number"""
return self.db.get(address_mapping_head_key)
def _get_block_receipts(self, hash, num):
"""
get block transaction receipts by block header hash & number
"""
def _get_block_receipts(self, block_hash, num):
"""Get block transaction receipts by block header hash & number"""
number = _format_block_number(num)
receipts_key = block_receipts_prefix + number + hash
receipts_key = block_receipts_prefix + number + block_hash
receipts_data = self.db.get(receipts_key)
receipts = rlp.decode(receipts_data, sedes=CountableList(ReceiptForStorage))
return receipts
@ -216,12 +207,10 @@ class EthLevelDB(object):
if not cnt % 1000:
logging.info("Searched %d contracts" % cnt)
def contract_hash_to_address(self, hash):
"""
tries to find corresponding account address
"""
def contract_hash_to_address(self, contract_hash):
"""Tries to find corresponding account address"""
address_hash = binascii.a2b_hex(utils.remove_0x_head(hash))
address_hash = binascii.a2b_hex(utils.remove_0x_head(contract_hash))
indexer = AccountIndexer(self)
return _encode_hex(indexer.get_contract_by_hash(address_hash))
@ -230,9 +219,9 @@ class EthLevelDB(object):
"""
gets block header by block number
"""
hash = self.reader._get_block_hash(number)
block_hash = self.reader._get_block_hash(number)
block_number = _format_block_number(number)
return self.reader._get_block_header(hash, block_number)
return self.reader._get_block_header(block_hash, block_number)
def eth_getBlockByNumber(self, number):
"""

@ -43,9 +43,9 @@ class Account(rlp.Serializable):
('code_hash', hash32)
]
def __init__(self, nonce, balance, storage, code_hash, db, address):
def __init__(self, nonce, balance, storage, code_hash, db, addr):
self.db = db
self.address = address
self.address = addr
super(Account, self).__init__(nonce, balance, storage, code_hash)
self.storage_cache = {}
self.storage_trie = SecureTrie(Trie(self.db))
@ -73,12 +73,12 @@ class Account(rlp.Serializable):
return self.storage_cache[key]
@classmethod
def blank_account(cls, db, address, initial_nonce=0):
def blank_account(cls, db, addr, initial_nonce=0):
"""
creates a blank account
"""
db.put(BLANK_HASH, b'')
o = cls(initial_nonce, 0, trie.BLANK_ROOT, BLANK_HASH, db, address)
o = cls(initial_nonce, 0, trie.BLANK_ROOT, BLANK_HASH, db, addr)
o.existent_at_start = False
return o
@ -100,21 +100,21 @@ class State:
self.journal = []
self.cache = {}
def get_and_cache_account(self, address):
"""
gets and caches an account for an addres, creates blank if not found
"""
if address in self.cache:
return self.cache[address]
rlpdata = self.secure_trie.get(address)
if rlpdata == trie.BLANK_NODE and len(address) == 32: # support for hashed addresses
rlpdata = self.trie.get(address)
def get_and_cache_account(self, addr):
"""Gets and caches an account for an addres, creates blank if not found"""
if addr in self.cache:
return self.cache[addr]
rlpdata = self.secure_trie.get(addr)
if rlpdata == trie.BLANK_NODE and len(addr) == 32: # support for hashed addresses
rlpdata = self.trie.get(addr)
if rlpdata != trie.BLANK_NODE:
o = rlp.decode(rlpdata, Account, db=self.db, address=address)
o = rlp.decode(rlpdata, Account, db=self.db, address=addr)
else:
o = Account.blank_account(
self.db, address, 0)
self.cache[address] = o
self.db, addr, 0)
self.cache[addr] = o
o._mutable = True
o._cached_rlp = None
return o

@ -17,8 +17,8 @@ from mythril.mythril import Mythril
from mythril.version import VERSION
def exit_with_error(format, message):
if format == 'text' or format == 'markdown':
def exit_with_error(format_, message):
if format_ == 'text' or format_ == 'markdown':
print(message)
else:
result = {'success': False, 'error': str(message), 'issues': []}

@ -99,7 +99,7 @@ def get_callee_account(global_state, callee_address, dynamic_loader):
try:
code = dynamic_loader.dynld(environment.active_account.address, callee_address)
except Exception as e:
except Exception:
logging.debug("Unable to execute dynamic loader.")
raise ValueError()
if code is None:

@ -497,7 +497,6 @@ class Instruction:
global keccak_function_manager
state = global_state.mstate
environment = global_state.environment
op0, op1 = state.stack.pop(), state.stack.pop()
try:
@ -701,12 +700,9 @@ class Instruction:
try:
# Attempt to concretize value
_bytes = util.concrete_int_to_bytes(value)
state.memory[mstart:mstart+len(_bytes)] = _bytes
except (AttributeError, TypeError):
state.memory[mstart: mstart + len(_bytes)] = _bytes
except:
try:
state.memory[mstart] = value
except TypeError:
@ -948,7 +944,7 @@ class Instruction:
state = global_state.mstate
dpth = int(self.op_code[3:])
state.stack.pop(), state.stack.pop()
[state.stack.pop() for x in range(dpth)]
[state.stack.pop() for _ in range(dpth)]
# Not supported
return [global_state]

@ -278,10 +278,10 @@ class GlobalState:
def new_bitvec(self, name, size=256):
transaction_id = self.current_transaction.id
node_id = self.node.uid
return BitVec("{}_{}".format(transaction_id, name), size)
class WorldState:
"""
The WorldState class represents the world state as described in the yellow paper

@ -129,7 +129,7 @@ class ContractCreationTransaction:
def end(self, global_state, return_data=None, revert=False):
if not all([isinstance(element, int) for element in return_data]):
if not all([isinstance(element, int) for element in return_data]) or len(return_data) == 0:
self.return_data = None
raise TransactionEndSignal(global_state)
@ -137,6 +137,7 @@ class ContractCreationTransaction:
global_state.environment.active_account.code = Disassembly(contract_code)
self.return_data = global_state.environment.active_account.address
assert global_state.environment.active_account.code.instruction_list != []
raise TransactionEndSignal(global_state, revert=revert)

@ -87,7 +87,7 @@ class Mythril(object):
self.sigs = signatures.SignatureDb()
try:
self.sigs.open() # tries mythril_dir/signatures.json by default (provide path= arg to make this configurable)
except FileNotFoundError as fnfe:
except FileNotFoundError:
logging.info(
"No signature database found. Creating database if sigs are loaded in: " + self.sigs.signatures_file + "\n" +
"Consider replacing it with the pre-initialized database at https://raw.githubusercontent.com/ConsenSys/mythril/master/signatures.json")
@ -261,8 +261,7 @@ class Mythril(object):
def search_db(self, search):
def search_callback(contract, address, balance):
def search_callback(_, address, balance):
print("Address: " + address + ", balance: " + str(balance))
try:
@ -290,10 +289,10 @@ class Mythril(object):
code = self.eth.eth_getCode(address)
except FileNotFoundError as e:
raise CriticalError("IPC error: " + str(e))
except ConnectionError as e:
except ConnectionError:
raise CriticalError("Could not connect to RPC server. Make sure that your node is running and that RPC parameters are set correctly.")
except Exception as e:
raise CriticalError("IPC / RPC error: " + str(e))
raise CriticalError("IPC / RPC error: " + str(e))
else:
if code == "0x" or code == "0x0":
raise CriticalError("Received an empty response from eth_getCode. Check the contract address and verify that you are on the correct chain.")
@ -435,7 +434,7 @@ class Mythril(object):
outtxt.append("{}: {}".format(hex(i), self.eth.eth_getStorageAt(address, i)))
except FileNotFoundError as e:
raise CriticalError("IPC error: " + str(e))
except ConnectionError as e:
except ConnectionError:
raise CriticalError("Could not connect to RPC server. Make sure that your node is running and that RPC parameters are set correctly.")
return '\n'.join(outtxt)

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<head>
<title>Call Graph</title>
<style type="text/css">
#mynetwork {
background-color: #232625;

@ -1,7 +1,8 @@
<!DOCTYPE html>
<html>
<head>
<head>
<title>Call Graph</title>
<style type="text/css">
#mynetwork {
background-color: #ffffff;

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<head>
<title>Call Graph</title>
<style type="text/css">
#mynetwork {
background-color: #232625;

@ -189,7 +189,7 @@ def test_delegate_call(sym_mock, concrete_mock, curr_instruction):
statespace.calls = [call]
# act
issues = execute(statespace)
execute(statespace)
# assert
assert concrete_mock.call_count == 1

@ -45,7 +45,7 @@ class MachineStackTest(BaseTestCase):
mstack = MachineStack([0, 1])
with pytest.raises(NotImplementedError):
mstack = mstack + [2]
mstack + [2]
@staticmethod
def test_mstack_no_support_iadd():

@ -49,7 +49,7 @@ def test_execute_contract_creation(mocked_setup: MagicMock):
mocked_setup.side_effect = _is_contract_creation
# Act
new_account = execute_contract_creation(laser_evm, "606000")
execute_contract_creation(laser_evm, "606000")
# Assert
# mocked_setup.assert_called()

@ -6,6 +6,7 @@ from mythril.laser.ethereum.cfg import Node, Edge
from mythril.laser.ethereum.state import MachineState, Account, Environment, GlobalState
from mythril.laser.ethereum.svm import LaserEVM
def test_execute_state(mocker):
record = TaintRecord()
record.stack = [True, False, True]
@ -54,8 +55,6 @@ def test_execute_node(mocker):
assert state_1 in record.states
def test_execute(mocker):
active_account = Account('0x00')
environment = Environment(active_account, None, None, None, None, None)

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Call Graph</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" integrity="sha256-iq5ygGJ7021Pi7H5S+QAUXCPUfaBzfqeplbg/KlEssg=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js" integrity="sha256-JuQeAGbk9rG/EoRMixuy5X8syzICcvB0dj3KindZkY0=" crossorigin="anonymous"></script>

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Call Graph</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" integrity="sha256-iq5ygGJ7021Pi7H5S+QAUXCPUfaBzfqeplbg/KlEssg=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js" integrity="sha256-JuQeAGbk9rG/EoRMixuy5X8syzICcvB0dj3KindZkY0=" crossorigin="anonymous"></script>

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Call Graph</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" integrity="sha256-iq5ygGJ7021Pi7H5S+QAUXCPUfaBzfqeplbg/KlEssg=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js" integrity="sha256-JuQeAGbk9rG/EoRMixuy5X8syzICcvB0dj3KindZkY0=" crossorigin="anonymous"></script>

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Call Graph</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" integrity="sha256-iq5ygGJ7021Pi7H5S+QAUXCPUfaBzfqeplbg/KlEssg=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js" integrity="sha256-JuQeAGbk9rG/EoRMixuy5X8syzICcvB0dj3KindZkY0=" crossorigin="anonymous"></script>

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Call Graph</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" integrity="sha256-iq5ygGJ7021Pi7H5S+QAUXCPUfaBzfqeplbg/KlEssg=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js" integrity="sha256-JuQeAGbk9rG/EoRMixuy5X8syzICcvB0dj3KindZkY0=" crossorigin="anonymous"></script>

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Call Graph</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" integrity="sha256-iq5ygGJ7021Pi7H5S+QAUXCPUfaBzfqeplbg/KlEssg=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js" integrity="sha256-JuQeAGbk9rG/EoRMixuy5X8syzICcvB0dj3KindZkY0=" crossorigin="anonymous"></script>

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Call Graph</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" integrity="sha256-iq5ygGJ7021Pi7H5S+QAUXCPUfaBzfqeplbg/KlEssg=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js" integrity="sha256-JuQeAGbk9rG/EoRMixuy5X8syzICcvB0dj3KindZkY0=" crossorigin="anonymous"></script>

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Call Graph</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" integrity="sha256-iq5ygGJ7021Pi7H5S+QAUXCPUfaBzfqeplbg/KlEssg=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js" integrity="sha256-JuQeAGbk9rG/EoRMixuy5X8syzICcvB0dj3KindZkY0=" crossorigin="anonymous"></script>

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Call Graph</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" integrity="sha256-iq5ygGJ7021Pi7H5S+QAUXCPUfaBzfqeplbg/KlEssg=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js" integrity="sha256-JuQeAGbk9rG/EoRMixuy5X8syzICcvB0dj3KindZkY0=" crossorigin="anonymous"></script>

@ -1 +1 @@
{"error": null, "issues": [{"address": 317, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "Function %s retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin", "function": "transferOwnership(address)", "swc_id": "115", "title": "Use of tx.origin", "type": "Warning"}], "success": true}
{"error": null, "issues": [{"address": 317, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The function `transferOwnership(address)` retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin", "function": "transferOwnership(address)", "swc_id": "115", "title": "Use of tx.origin", "type": "Warning"}], "success": true}

@ -9,5 +9,5 @@
### Description
Function %s retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.
The function `transferOwnership(address)` retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.
See also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin

@ -4,7 +4,7 @@ Type: Warning
Contract: Unknown
Function name: transferOwnership(address)
PC address: 317
Function %s retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.
The function `transferOwnership(address)` retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.
See also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin
--------------------

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Call Graph</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" integrity="sha256-iq5ygGJ7021Pi7H5S+QAUXCPUfaBzfqeplbg/KlEssg=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js" integrity="sha256-JuQeAGbk9rG/EoRMixuy5X8syzICcvB0dj3KindZkY0=" crossorigin="anonymous"></script>

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Call Graph</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" integrity="sha256-iq5ygGJ7021Pi7H5S+QAUXCPUfaBzfqeplbg/KlEssg=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js" integrity="sha256-JuQeAGbk9rG/EoRMixuy5X8syzICcvB0dj3KindZkY0=" crossorigin="anonymous"></script>

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Call Graph</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" integrity="sha256-iq5ygGJ7021Pi7H5S+QAUXCPUfaBzfqeplbg/KlEssg=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js" integrity="sha256-JuQeAGbk9rG/EoRMixuy5X8syzICcvB0dj3KindZkY0=" crossorigin="anonymous"></script>

@ -1,5 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Call Graph</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css" integrity="sha256-iq5ygGJ7021Pi7H5S+QAUXCPUfaBzfqeplbg/KlEssg=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js" integrity="sha256-JuQeAGbk9rG/EoRMixuy5X8syzICcvB0dj3KindZkY0=" crossorigin="anonymous"></script>

Loading…
Cancel
Save