|
|
@ -25,6 +25,7 @@ from mythril.laser.smt import ( |
|
|
|
Bool, |
|
|
|
Bool, |
|
|
|
Not, |
|
|
|
Not, |
|
|
|
LShR, |
|
|
|
LShR, |
|
|
|
|
|
|
|
UGE, |
|
|
|
) |
|
|
|
) |
|
|
|
from mythril.laser.smt import symbol_factory |
|
|
|
from mythril.laser.smt import symbol_factory |
|
|
|
|
|
|
|
|
|
|
@ -56,6 +57,30 @@ TT256 = 2 ** 256 |
|
|
|
TT256M1 = 2 ** 256 - 1 |
|
|
|
TT256M1 = 2 ** 256 - 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def transfer_ether( |
|
|
|
|
|
|
|
global_state: GlobalState, |
|
|
|
|
|
|
|
sender: BitVec, |
|
|
|
|
|
|
|
receiver: BitVec, |
|
|
|
|
|
|
|
value: Union[int, BitVec], |
|
|
|
|
|
|
|
): |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
Perform an Ether transfer between two accounts |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:param global_state: The global state in which the Ether transfer occurs |
|
|
|
|
|
|
|
:param sender: The sender of the Ether |
|
|
|
|
|
|
|
:param receiver: The recipient of the Ether |
|
|
|
|
|
|
|
:param value: The amount of Ether to send |
|
|
|
|
|
|
|
:return: |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
value = value if isinstance(value, BitVec) else symbol_factory.BitVecVal(value, 256) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
global_state.mstate.constraints.append( |
|
|
|
|
|
|
|
UGE(global_state.world_state.balances[sender], value) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
global_state.world_state.balances[receiver] += value |
|
|
|
|
|
|
|
global_state.world_state.balances[sender] -= value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class StateTransition(object): |
|
|
|
class StateTransition(object): |
|
|
|
"""Decorator that handles global state copy and original return. |
|
|
|
"""Decorator that handles global state copy and original return. |
|
|
|
|
|
|
|
|
|
|
@ -842,7 +867,11 @@ class Instruction: |
|
|
|
""" |
|
|
|
""" |
|
|
|
state = global_state.mstate |
|
|
|
state = global_state.mstate |
|
|
|
address = state.stack.pop() |
|
|
|
address = state.stack.pop() |
|
|
|
state.stack.append(global_state.new_bitvec("balance_at_" + str(address), 256)) |
|
|
|
|
|
|
|
|
|
|
|
balance = global_state.world_state.balances[ |
|
|
|
|
|
|
|
global_state.environment.active_account.address |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
state.stack.append(balance) |
|
|
|
return [global_state] |
|
|
|
return [global_state] |
|
|
|
|
|
|
|
|
|
|
|
@StateTransition() |
|
|
|
@StateTransition() |
|
|
@ -1629,7 +1658,7 @@ class Instruction: |
|
|
|
transfer_amount = global_state.environment.active_account.balance() |
|
|
|
transfer_amount = global_state.environment.active_account.balance() |
|
|
|
# Often the target of the suicide instruction will be symbolic |
|
|
|
# Often the target of the suicide instruction will be symbolic |
|
|
|
# If it isn't then we'll transfer the balance to the indicated contract |
|
|
|
# If it isn't then we'll transfer the balance to the indicated contract |
|
|
|
global_state.world_state[target].add_balance(transfer_amount) |
|
|
|
global_state.world_state.balances[target] += transfer_amount |
|
|
|
|
|
|
|
|
|
|
|
global_state.environment.active_account = deepcopy( |
|
|
|
global_state.environment.active_account = deepcopy( |
|
|
|
global_state.environment.active_account |
|
|
|
global_state.environment.active_account |
|
|
@ -1703,6 +1732,10 @@ class Instruction: |
|
|
|
|
|
|
|
|
|
|
|
if callee_account is not None and callee_account.code.bytecode == "": |
|
|
|
if callee_account is not None and callee_account.code.bytecode == "": |
|
|
|
log.debug("The call is related to ether transfer between accounts") |
|
|
|
log.debug("The call is related to ether transfer between accounts") |
|
|
|
|
|
|
|
sender = environment.active_account.address |
|
|
|
|
|
|
|
receiver = callee_account.address |
|
|
|
|
|
|
|
transfer_ether(global_state, sender, receiver, value) |
|
|
|
|
|
|
|
|
|
|
|
global_state.mstate.stack.append( |
|
|
|
global_state.mstate.stack.append( |
|
|
|
global_state.new_bitvec("retval_" + str(instr["address"]), 256) |
|
|
|
global_state.new_bitvec("retval_" + str(instr["address"]), 256) |
|
|
|
) |
|
|
|
) |
|
|
@ -1818,6 +1851,18 @@ class Instruction: |
|
|
|
callee_address, callee_account, call_data, value, gas, _, _ = get_call_parameters( |
|
|
|
callee_address, callee_account, call_data, value, gas, _, _ = get_call_parameters( |
|
|
|
global_state, self.dynamic_loader, True |
|
|
|
global_state, self.dynamic_loader, True |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if callee_account is not None and callee_account.code.bytecode == "": |
|
|
|
|
|
|
|
log.debug("The call is related to ether transfer between accounts") |
|
|
|
|
|
|
|
sender = global_state.environment.active_account.address |
|
|
|
|
|
|
|
receiver = callee_account.address |
|
|
|
|
|
|
|
transfer_ether(global_state, sender, receiver, value) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
global_state.mstate.stack.append( |
|
|
|
|
|
|
|
global_state.new_bitvec("retval_" + str(instr["address"]), 256) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
return [global_state] |
|
|
|
|
|
|
|
|
|
|
|
except ValueError as e: |
|
|
|
except ValueError as e: |
|
|
|
log.debug( |
|
|
|
log.debug( |
|
|
|
"Could not determine required parameters for call, putting fresh symbol on the stack. \n{}".format( |
|
|
|
"Could not determine required parameters for call, putting fresh symbol on the stack. \n{}".format( |
|
|
@ -1921,6 +1966,18 @@ class Instruction: |
|
|
|
callee_address, callee_account, call_data, value, gas, _, _ = get_call_parameters( |
|
|
|
callee_address, callee_account, call_data, value, gas, _, _ = get_call_parameters( |
|
|
|
global_state, self.dynamic_loader |
|
|
|
global_state, self.dynamic_loader |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if callee_account is not None and callee_account.code.bytecode == "": |
|
|
|
|
|
|
|
log.debug("The call is related to ether transfer between accounts") |
|
|
|
|
|
|
|
sender = environment.active_account.address |
|
|
|
|
|
|
|
receiver = callee_account.address |
|
|
|
|
|
|
|
transfer_ether(global_state, sender, receiver, value) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
global_state.mstate.stack.append( |
|
|
|
|
|
|
|
global_state.new_bitvec("retval_" + str(instr["address"]), 256) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
return [global_state] |
|
|
|
|
|
|
|
|
|
|
|
except ValueError as e: |
|
|
|
except ValueError as e: |
|
|
|
log.debug( |
|
|
|
log.debug( |
|
|
|
"Could not determine required parameters for call, putting fresh symbol on the stack. \n{}".format( |
|
|
|
"Could not determine required parameters for call, putting fresh symbol on the stack. \n{}".format( |
|
|
@ -2022,6 +2079,18 @@ class Instruction: |
|
|
|
callee_address, callee_account, call_data, value, gas, memory_out_offset, memory_out_size = get_call_parameters( |
|
|
|
callee_address, callee_account, call_data, value, gas, memory_out_offset, memory_out_size = get_call_parameters( |
|
|
|
global_state, self.dynamic_loader |
|
|
|
global_state, self.dynamic_loader |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if callee_account is not None and callee_account.code.bytecode == "": |
|
|
|
|
|
|
|
log.debug("The call is related to ether transfer between accounts") |
|
|
|
|
|
|
|
sender = global_state.environment.active_account.address |
|
|
|
|
|
|
|
receiver = callee_account.address |
|
|
|
|
|
|
|
transfer_ether(global_state, sender, receiver, value) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
global_state.mstate.stack.append( |
|
|
|
|
|
|
|
global_state.new_bitvec("retval_" + str(instr["address"]), 256) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
return [global_state] |
|
|
|
|
|
|
|
|
|
|
|
except ValueError as e: |
|
|
|
except ValueError as e: |
|
|
|
log.debug( |
|
|
|
log.debug( |
|
|
|
"Could not determine required parameters for call, putting fresh symbol on the stack. \n{}".format( |
|
|
|
"Could not determine required parameters for call, putting fresh symbol on the stack. \n{}".format( |
|
|
|