示例#1
0
文件: unary.py 项目: zeta1999/slither
    def __str__(self):
        if self == UnaryType.BANG:
            return "!"
        if self == UnaryType.TILD:
            return "~"

        raise SlithIRError("str: Unknown operation type {}".format(self))
示例#2
0
def convert_assignment(left, right, t, return_type):
    if t == AssignmentOperationType.ASSIGN:
        return Assignment(left, right, return_type)
    elif t == AssignmentOperationType.ASSIGN_OR:
        return Binary(left, left, right, BinaryType.OR)
    elif t == AssignmentOperationType.ASSIGN_CARET:
        return Binary(left, left, right, BinaryType.CARET)
    elif t == AssignmentOperationType.ASSIGN_AND:
        return Binary(left, left, right, BinaryType.AND)
    elif t == AssignmentOperationType.ASSIGN_LEFT_SHIFT:
        return Binary(left, left, right, BinaryType.LEFT_SHIFT)
    elif t == AssignmentOperationType.ASSIGN_RIGHT_SHIFT:
        return Binary(left, left, right, BinaryType.RIGHT_SHIFT)
    elif t == AssignmentOperationType.ASSIGN_ADDITION:
        return Binary(left, left, right, BinaryType.ADDITION)
    elif t == AssignmentOperationType.ASSIGN_SUBTRACTION:
        return Binary(left, left, right, BinaryType.SUBTRACTION)
    elif t == AssignmentOperationType.ASSIGN_MULTIPLICATION:
        return Binary(left, left, right, BinaryType.MULTIPLICATION)
    elif t == AssignmentOperationType.ASSIGN_DIVISION:
        return Binary(left, left, right, BinaryType.DIVISION)
    elif t == AssignmentOperationType.ASSIGN_MODULO:
        return Binary(left, left, right, BinaryType.MODULO)

    raise SlithIRError('Missing type during assignment conversion')
示例#3
0
def convert_to_low_level(ir):
    """
        Convert to a transfer/send/or low level call
        The funciton assume to receive a correct IR
        The checks must be done by the caller

        Must be called after can_be_low_level
    """
    if ir.function_name == 'transfer':
        assert len(ir.arguments) == 1
        prev_ir = ir
        ir = Transfer(ir.destination, ir.arguments[0])
        ir.set_expression(prev_ir.expression)
        return ir
    elif ir.function_name == 'send':
        assert len(ir.arguments) == 1
        prev_ir = ir
        ir = Send(ir.destination, ir.arguments[0], ir.lvalue)
        ir.set_expression(prev_ir.expression)
        ir.lvalue.set_type(ElementaryType('bool'))
        return ir
    elif ir.function_name in [
            'call', 'delegatecall', 'callcode', 'staticcall'
    ]:
        new_ir = LowLevelCall(ir.destination, ir.function_name,
                              ir.nbr_arguments, ir.lvalue, ir.type_call)
        new_ir.call_gas = ir.call_gas
        new_ir.call_value = ir.call_value
        new_ir.arguments = ir.arguments
        new_ir.lvalue.set_type(ElementaryType('bool'))
        new_ir.set_expression(ir.expression)
        return new_ir
    raise SlithIRError('Incorrect conversion to low level {}'.format(ir))
示例#4
0
def _convert_type_contract(ir, slither):
    assert isinstance(ir.variable_left.type, TypeInformation)
    contract = ir.variable_left.type.type

    if ir.variable_right == 'creationCode':
        if slither.crytic_compile:
            bytecode = slither.crytic_compile.bytecode_init(contract.name)
        else:
            logger.info(
                'The codebase uses type(x).creationCode, but crytic-compile was not used. As a result, the bytecode cannot be found'
            )
            bytecode = "MISSING_BYTECODE"
        assignment = Assignment(ir.lvalue, Constant(str(bytecode)),
                                ElementaryType('bytes'))
        assignment.lvalue.set_type(ElementaryType('bytes'))
        return assignment
    if ir.variable_right == 'runtimeCode':
        if slither.crytic_compile:
            bytecode = slither.crytic_compile.bytecode_runtime(contract.name)
        else:
            logger.info(
                'The codebase uses type(x).runtimeCode, but crytic-compile was not used. As a result, the bytecode cannot be found'
            )
            bytecode = "MISSING_BYTECODE"
        assignment = Assignment(ir.lvalue, Constant(str(bytecode)),
                                ElementaryType('bytes'))
        assignment.lvalue.set_type(ElementaryType('bytes'))
        return assignment
    if ir.variable_right == 'name':
        assignment = Assignment(ir.lvalue, Constant(contract.name),
                                ElementaryType('string'))
        assignment.lvalue.set_type(ElementaryType('string'))
        return assignment

    raise SlithIRError(f'type({contract.name}).{ir.variable_right} is unknown')
示例#5
0
    def str(operation_type):
        if operation_type == UnaryType.BANG:
            return '!'
        if operation_type == UnaryType.TILD:
            return '~'

        raise SlithIRError('str: Unknown operation type {}'.format(operation_type))
示例#6
0
 def get_type(operation_type, isprefix):
     if isprefix:
         if operation_type == '!':
             return UnaryType.BANG
         if operation_type == '~':
             return UnaryType.TILD
     raise SlithIRError('get_type: Unknown operation type {}'.format(operation_type))
示例#7
0
 def _post_unary_operation(self, expression):
     value = get(expression.expression)
     if expression.type in [
             UnaryOperationType.BANG, UnaryOperationType.TILD
     ]:
         lvalue = TemporaryVariable(self._node)
         operation = Unary(lvalue, value, expression.type)
         operation.set_expression(expression)
         self._result.append(operation)
         set_val(expression, lvalue)
     elif expression.type in [UnaryOperationType.DELETE]:
         operation = Delete(value, value)
         operation.set_expression(expression)
         self._result.append(operation)
         set_val(expression, value)
     elif expression.type in [UnaryOperationType.PLUSPLUS_PRE]:
         operation = Binary(value, value, Constant("1", value.type),
                            BinaryType.ADDITION)
         operation.set_expression(expression)
         self._result.append(operation)
         set_val(expression, value)
     elif expression.type in [UnaryOperationType.MINUSMINUS_PRE]:
         operation = Binary(value, value, Constant("1", value.type),
                            BinaryType.SUBTRACTION)
         operation.set_expression(expression)
         self._result.append(operation)
         set_val(expression, value)
     elif expression.type in [UnaryOperationType.PLUSPLUS_POST]:
         lvalue = TemporaryVariable(self._node)
         operation = Assignment(lvalue, value, value.type)
         operation.set_expression(expression)
         self._result.append(operation)
         operation = Binary(value, value, Constant("1", value.type),
                            BinaryType.ADDITION)
         operation.set_expression(expression)
         self._result.append(operation)
         set_val(expression, lvalue)
     elif expression.type in [UnaryOperationType.MINUSMINUS_POST]:
         lvalue = TemporaryVariable(self._node)
         operation = Assignment(lvalue, value, value.type)
         operation.set_expression(expression)
         self._result.append(operation)
         operation = Binary(value, value, Constant("1", value.type),
                            BinaryType.SUBTRACTION)
         operation.set_expression(expression)
         self._result.append(operation)
         set_val(expression, lvalue)
     elif expression.type in [UnaryOperationType.PLUS_PRE]:
         set_val(expression, value)
     elif expression.type in [UnaryOperationType.MINUS_PRE]:
         lvalue = TemporaryVariable(self._node)
         operation = Binary(lvalue, Constant("0", value.type), value,
                            BinaryType.SUBTRACTION)
         operation.set_expression(expression)
         self._result.append(operation)
         set_val(expression, lvalue)
     else:
         raise SlithIRError(
             'Unary operation to IR not supported {}'.format(expression))
示例#8
0
 def get_type(operation_type, isprefix):
     if isprefix:
         if operation_type == "!":
             return UnaryType.BANG
         if operation_type == "~":
             return UnaryType.TILD
     raise SlithIRError(
         "get_type: Unknown operation type {}".format(operation_type))
示例#9
0
def convert_to_low_level(ir):
    """
        Convert to a transfer/send/or low level call
        The funciton assume to receive a correct IR
        The checks must be done by the caller

        Additionally convert abi... to solidityfunction
    """
    if ir.function_name == 'transfer':
        assert len(ir.arguments) == 1
        ir = Transfer(ir.destination, ir.arguments[0])
        return ir
    elif ir.function_name == 'send':
        assert len(ir.arguments) == 1
        ir = Send(ir.destination, ir.arguments[0], ir.lvalue)
        ir.lvalue.set_type(ElementaryType('bool'))
        return ir
    elif ir.destination.name ==  'abi' and ir.function_name in ['encode',
                                                                'encodePacked',
                                                                'encodeWithSelector',
                                                                'encodeWithSignature',
                                                                'decode']:

        call = SolidityFunction('abi.{}()'.format(ir.function_name))
        new_ir = SolidityCall(call, ir.nbr_arguments, ir.lvalue, ir.type_call)
        new_ir.arguments = ir.arguments
        if isinstance(call.return_type, list) and len(call.return_type) == 1:
            new_ir.lvalue.set_type(call.return_type[0])
        else:
            new_ir.lvalue.set_type(call.return_type)
        return new_ir
    elif ir.function_name in ['call',
                              'delegatecall',
                              'callcode',
                              'staticcall']:
        new_ir = LowLevelCall(ir.destination,
                          ir.function_name,
                          ir.nbr_arguments,
                          ir.lvalue,
                          ir.type_call)
        new_ir.call_gas = ir.call_gas
        new_ir.call_value = ir.call_value
        new_ir.arguments = ir.arguments
        new_ir.lvalue.set_type(ElementaryType('bool'))
        return new_ir
    raise SlithIRError('Incorrect conversion to low level {}'.format(ir))
示例#10
0
    def get_type(operation_type):  # pylint: disable=too-many-branches
        if operation_type == "**":
            return BinaryType.POWER
        if operation_type == "*":
            return BinaryType.MULTIPLICATION
        if operation_type == "/":
            return BinaryType.DIVISION
        if operation_type == "%":
            return BinaryType.MODULO
        if operation_type == "+":
            return BinaryType.ADDITION
        if operation_type == "-":
            return BinaryType.SUBTRACTION
        if operation_type == "<<":
            return BinaryType.LEFT_SHIFT
        if operation_type == ">>":
            return BinaryType.RIGHT_SHIFT
        if operation_type == "&":
            return BinaryType.AND
        if operation_type == "^":
            return BinaryType.CARET
        if operation_type == "|":
            return BinaryType.OR
        if operation_type == "<":
            return BinaryType.LESS
        if operation_type == ">":
            return BinaryType.GREATER
        if operation_type == "<=":
            return BinaryType.LESS_EQUAL
        if operation_type == ">=":
            return BinaryType.GREATER_EQUAL
        if operation_type == "==":
            return BinaryType.EQUAL
        if operation_type == "!=":
            return BinaryType.NOT_EQUAL
        if operation_type == "&&":
            return BinaryType.ANDAND
        if operation_type == "||":
            return BinaryType.OROR

        raise SlithIRError(
            "get_type: Unknown operation type {})".format(operation_type))
示例#11
0
    def get_type(operation_type):
        if operation_type == '**':
            return BinaryType.POWER
        if operation_type == '*':
            return BinaryType.MULTIPLICATION
        if operation_type == '/':
            return BinaryType.DIVISION
        if operation_type == '%':
            return BinaryType.MODULO
        if operation_type == '+':
            return BinaryType.ADDITION
        if operation_type == '-':
            return BinaryType.SUBTRACTION
        if operation_type == '<<':
            return BinaryType.LEFT_SHIFT
        if operation_type == '>>':
            return BinaryType.RIGHT_SHIFT
        if operation_type == '&':
            return BinaryType.AND
        if operation_type == '^':
            return BinaryType.CARET
        if operation_type == '|':
            return BinaryType.OR
        if operation_type == '<':
            return BinaryType.LESS
        if operation_type == '>':
            return BinaryType.GREATER
        if operation_type == '<=':
            return BinaryType.LESS_EQUAL
        if operation_type == '>=':
            return BinaryType.GREATER_EQUAL
        if operation_type == '==':
            return BinaryType.EQUAL
        if operation_type == '!=':
            return BinaryType.NOT_EQUAL
        if operation_type == '&&':
            return BinaryType.ANDAND
        if operation_type == '||':
            return BinaryType.OROR

        raise SlithIRError(
            'get_type: Unknown operation type {})'.format(operation_type))
示例#12
0
 def __str__(self):  # pylint: disable=too-many-branches
     if self == BinaryType.POWER:
         return "**"
     if self == BinaryType.MULTIPLICATION:
         return "*"
     if self == BinaryType.DIVISION:
         return "/"
     if self == BinaryType.MODULO:
         return "%"
     if self == BinaryType.ADDITION:
         return "+"
     if self == BinaryType.SUBTRACTION:
         return "-"
     if self == BinaryType.LEFT_SHIFT:
         return "<<"
     if self == BinaryType.RIGHT_SHIFT:
         return ">>"
     if self == BinaryType.AND:
         return "&"
     if self == BinaryType.CARET:
         return "^"
     if self == BinaryType.OR:
         return "|"
     if self == BinaryType.LESS:
         return "<"
     if self == BinaryType.GREATER:
         return ">"
     if self == BinaryType.LESS_EQUAL:
         return "<="
     if self == BinaryType.GREATER_EQUAL:
         return ">="
     if self == BinaryType.EQUAL:
         return "=="
     if self == BinaryType.NOT_EQUAL:
         return "!="
     if self == BinaryType.ANDAND:
         return "&&"
     if self == BinaryType.OROR:
         return "||"
     raise SlithIRError("str: Unknown operation type {} {})".format(
         self, type(self)))
示例#13
0
 def str(operation_type):
     if operation_type == BinaryType.POWER:
         return '**'
     if operation_type == BinaryType.MULTIPLICATION:
         return '*'
     if operation_type == BinaryType.DIVISION:
         return '/'
     if operation_type == BinaryType.MODULO:
         return '%'
     if operation_type == BinaryType.ADDITION:
         return '+'
     if operation_type == BinaryType.SUBTRACTION:
         return '-'
     if operation_type == BinaryType.LEFT_SHIFT:
         return '<<'
     if operation_type == BinaryType.RIGHT_SHIFT:
         return '>>'
     if operation_type == BinaryType.AND:
         return '&'
     if operation_type == BinaryType.CARET:
         return '^'
     if operation_type == BinaryType.OR:
         return '|'
     if operation_type == BinaryType.LESS:
         return '<'
     if operation_type == BinaryType.GREATER:
         return '>'
     if operation_type == BinaryType.LESS_EQUAL:
         return '<='
     if operation_type == BinaryType.GREATER_EQUAL:
         return '>='
     if operation_type == BinaryType.EQUAL:
         return '=='
     if operation_type == BinaryType.NOT_EQUAL:
         return '!='
     if operation_type == BinaryType.ANDAND:
         return '&&'
     if operation_type == BinaryType.OROR:
         return '||'
     raise SlithIRError(
         'str: Unknown operation type {})'.format(operation_type))
示例#14
0
文件: convert.py 项目: sreev/slither
def propagate_types(ir, node):
    # propagate the type
    using_for = node.function.contract.using_for
    if isinstance(ir, OperationWithLValue):
        # Force assignment in case of missing previous correct type
        if not ir.lvalue.type:
            if isinstance(ir, Assignment):
                ir.lvalue.set_type(ir.rvalue.type)
            elif isinstance(ir, Binary):
                if BinaryType.return_bool(ir.type):
                    ir.lvalue.set_type(ElementaryType('bool'))
                else:
                    ir.lvalue.set_type(ir.variable_left.type)
            elif isinstance(ir, Delete):
                # nothing to propagate
                pass
            elif isinstance(ir, LibraryCall):
                return convert_type_library_call(ir, ir.destination)
            elif isinstance(ir, HighLevelCall):
                t = ir.destination.type

                # Temporary operation (they are removed later)
                if t is None:
                    return

                if isinstance(t, ElementaryType) and t.name == 'address':
                    if can_be_solidity_func(ir):
                        return convert_to_solidity_func(ir)

                # convert library
                if t in using_for or '*' in using_for:
                    new_ir = convert_to_library(ir, node, using_for)
                    if new_ir:
                        return new_ir

                if isinstance(t, UserDefinedType):
                    # UserdefinedType
                    t_type = t.type
                    if isinstance(t_type, Contract):
                        contract = node.slither.get_contract_from_name(t_type.name)
                        return convert_type_of_high_and_internal_level_call(ir, contract)

                # Convert HighLevelCall to LowLevelCall
                if isinstance(t, ElementaryType) and t.name == 'address':
                    if ir.destination.name == 'this':
                        return convert_type_of_high_and_internal_level_call(ir, node.function.contract)
                    if can_be_low_level(ir):
                        return convert_to_low_level(ir)

                # Convert push operations
                # May need to insert a new operation
                # Which leads to return a list of operation
                if isinstance(t, ArrayType) or (isinstance(t, ElementaryType) and t.type == 'bytes'):
                    if ir.function_name == 'push' and len(ir.arguments) == 1:
                        return convert_to_push(ir, node)
                    if ir.function_name == 'pop' and len(ir.arguments) == 0:
                        return convert_to_pop(ir, node)

            elif isinstance(ir, Index):
                if isinstance(ir.variable_left.type, MappingType):
                    ir.lvalue.set_type(ir.variable_left.type.type_to)
                elif isinstance(ir.variable_left.type, ArrayType):
                    ir.lvalue.set_type(ir.variable_left.type.type)

            elif isinstance(ir, InitArray):
                length = len(ir.init_values)
                t = ir.init_values[0].type
                ir.lvalue.set_type(ArrayType(t, length))
            elif isinstance(ir, InternalCall):
                # if its not a tuple, return a singleton
                if ir.function is None:
                    convert_type_of_high_and_internal_level_call(ir, node.function.contract)
                return_type = ir.function.return_type
                if return_type:
                    if len(return_type) == 1:
                        ir.lvalue.set_type(return_type[0])
                    elif len(return_type) > 1:
                        ir.lvalue.set_type(return_type)
                else:
                    ir.lvalue = None
            elif isinstance(ir, InternalDynamicCall):
                # if its not a tuple, return a singleton
                return_type = ir.function_type.return_type
                if return_type:
                    if len(return_type) == 1:
                        ir.lvalue.set_type(return_type[0])
                    else:
                        ir.lvalue.set_type(return_type)
                else:
                    ir.lvalue = None
            elif isinstance(ir, LowLevelCall):
                # Call are not yet converted
                # This should not happen
                assert False
            elif isinstance(ir, Member):
                # TODO we should convert the reference to a temporary if the member is a length or a balance
                if ir.variable_right == 'length' and not isinstance(ir.variable_left, Contract) and isinstance(
                        ir.variable_left.type, (ElementaryType, ArrayType)):
                    length = Length(ir.variable_left, ir.lvalue)
                    length.set_expression(ir.expression)
                    length.lvalue.points_to = ir.variable_left
                    length.set_node(ir.node)
                    return length
                if ir.variable_right == 'balance' and not isinstance(ir.variable_left, Contract) and isinstance(
                        ir.variable_left.type, ElementaryType):
                    b = Balance(ir.variable_left, ir.lvalue)
                    b.set_expression(ir.expression)
                    b.set_node(ir.node)
                    return b
                if ir.variable_right == 'selector' and isinstance(ir.variable_left.type, Function):
                    assignment = Assignment(ir.lvalue,
                                            Constant(str(get_function_id(ir.variable_left.type.full_name))),
                                            ElementaryType('bytes4'))
                    assignment.set_expression(ir.expression)
                    assignment.set_node(ir.node)
                    assignment.lvalue.set_type(ElementaryType('bytes4'))
                    return assignment
                if isinstance(ir.variable_left, TemporaryVariable) and isinstance(ir.variable_left.type,
                                                                                  TypeInformation):
                    return _convert_type_contract(ir, node.function.slither)
                left = ir.variable_left
                t = None
                if isinstance(left, (Variable, SolidityVariable)):
                    t = ir.variable_left.type
                elif isinstance(left, (Contract, Enum, Structure)):
                    t = UserDefinedType(left)
                # can be None due to temporary operation
                if t:
                    if isinstance(t, UserDefinedType):
                        # UserdefinedType
                        type_t = t.type
                        if isinstance(type_t, Enum):
                            ir.lvalue.set_type(t)
                        elif isinstance(type_t, Structure):
                            elems = type_t.elems
                            for elem in elems:
                                if elem == ir.variable_right:
                                    ir.lvalue.set_type(elems[elem].type)
                        else:
                            assert isinstance(type_t, Contract)
                            # Allow type propagtion as a Function
                            # Only for reference variables
                            # This allows to track the selector keyword
                            # We dont need to check for function collision, as solc prevents the use of selector
                            # if there are multiple functions with the same name
                            f = next((f for f in type_t.functions if f.name == ir.variable_right), None)
                            if f:
                                ir.lvalue.set_type(f)
                            else:
                                # Allow propgation for variable access through contract's nale
                                # like Base_contract.my_variable
                                v = next((v for v in type_t.state_variables if v.name == ir.variable_right), None)
                                if v:
                                    ir.lvalue.set_type(v.type)
            elif isinstance(ir, NewArray):
                ir.lvalue.set_type(ir.array_type)
            elif isinstance(ir, NewContract):
                contract = node.slither.get_contract_from_name(ir.contract_name)
                ir.lvalue.set_type(UserDefinedType(contract))
            elif isinstance(ir, NewElementaryType):
                ir.lvalue.set_type(ir.type)
            elif isinstance(ir, NewStructure):
                ir.lvalue.set_type(UserDefinedType(ir.structure))
            elif isinstance(ir, Push):
                # No change required
                pass
            elif isinstance(ir, Send):
                ir.lvalue.set_type(ElementaryType('bool'))
            elif isinstance(ir, SolidityCall):
                if ir.function.name == 'type(address)':
                    ir.function.return_type = [TypeInformation(ir.arguments[0])]
                return_type = ir.function.return_type
                if len(return_type) == 1:
                    ir.lvalue.set_type(return_type[0])
                elif len(return_type) > 1:
                    ir.lvalue.set_type(return_type)
            elif isinstance(ir, TypeConversion):
                ir.lvalue.set_type(ir.type)
            elif isinstance(ir, Unary):
                ir.lvalue.set_type(ir.rvalue.type)
            elif isinstance(ir, Unpack):
                types = ir.tuple.type.type
                idx = ir.index
                t = types[idx]
                ir.lvalue.set_type(t)
            elif isinstance(ir,
                            (Argument, TmpCall, TmpNewArray, TmpNewContract, TmpNewStructure, TmpNewElementaryType)):
                # temporary operation; they will be removed
                pass
            else:
                raise SlithIRError('Not handling {} during type propgation'.format(type(ir)))
示例#15
0
def copy_ir(ir, *instances):
    '''
    Args:
        ir (Operation)
        local_variables_instances(dict(str -> LocalVariable))
        state_variables_instances(dict(str -> StateVariable))
        temporary_variables_instances(dict(int -> Variable))
        reference_variables_instances(dict(int -> Variable))

    Note: temporary and reference can be indexed by int, as they dont need phi functions
    '''
    if isinstance(ir, Assignment):
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        rvalue = get_variable(ir, lambda x: x.rvalue, *instances)
        variable_return_type = ir.variable_return_type
        return Assignment(lvalue, rvalue, variable_return_type)
    elif isinstance(ir, Balance):
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        value = get_variable(ir, lambda x: x.value, *instances)
        return Balance(value, lvalue)
    elif isinstance(ir, Binary):
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        variable_left = get_variable(ir, lambda x: x.variable_left, *instances)
        variable_right = get_variable(ir, lambda x: x.variable_right,
                                      *instances)
        operation_type = ir.type
        return Binary(lvalue, variable_left, variable_right, operation_type)
    elif isinstance(ir, Condition):
        val = get_variable(ir, lambda x: x.value, *instances)
        return Condition(val)
    elif isinstance(ir, Delete):
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        variable = get_variable(ir, lambda x: x.variable, *instances)
        return Delete(lvalue, variable)
    elif isinstance(ir, EventCall):
        name = ir.name
        return EventCall(name)
    elif isinstance(ir, HighLevelCall):  # include LibraryCall
        destination = get_variable(ir, lambda x: x.destination, *instances)
        function_name = ir.function_name
        nbr_arguments = ir.nbr_arguments
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        type_call = ir.type_call
        if isinstance(ir, LibraryCall):
            new_ir = LibraryCall(destination, function_name, nbr_arguments,
                                 lvalue, type_call)
        else:
            new_ir = HighLevelCall(destination, function_name, nbr_arguments,
                                   lvalue, type_call)
        new_ir.call_id = ir.call_id
        new_ir.call_value = get_variable(ir, lambda x: x.call_value,
                                         *instances)
        new_ir.call_gas = get_variable(ir, lambda x: x.call_gas, *instances)
        new_ir.arguments = get_arguments(ir, *instances)
        new_ir.function = ir.function
        return new_ir
    elif isinstance(ir, Index):
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        variable_left = get_variable(ir, lambda x: x.variable_left, *instances)
        variable_right = get_variable(ir, lambda x: x.variable_right,
                                      *instances)
        index_type = ir.index_type
        return Index(lvalue, variable_left, variable_right, index_type)
    elif isinstance(ir, InitArray):
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        init_values = get_rec_values(ir, lambda x: x.init_values, *instances)
        return InitArray(init_values, lvalue)
    elif isinstance(ir, InternalCall):
        function = ir.function
        nbr_arguments = ir.nbr_arguments
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        type_call = ir.type_call
        new_ir = InternalCall(function, function.contract, nbr_arguments,
                              lvalue, type_call)
        new_ir.arguments = get_arguments(ir, *instances)
        return new_ir
    elif isinstance(ir, InternalDynamicCall):
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        function = get_variable(ir, lambda x: x.function, *instances)
        function_type = ir.function_type
        new_ir = InternalDynamicCall(lvalue, function, function_type)
        new_ir.arguments = get_arguments(ir, *instances)
        return new_ir
    elif isinstance(ir, LowLevelCall):
        destination = get_variable(ir, lambda x: x.destination, *instances)
        function_name = ir.function_name
        nbr_arguments = ir.nbr_arguments
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        type_call = ir.type_call
        new_ir = LowLevelCall(destination, function_name, nbr_arguments,
                              lvalue, type_call)
        new_ir.call_id = ir.call_id
        new_ir.call_value = get_variable(ir, lambda x: x.call_value,
                                         *instances)
        new_ir.call_gas = get_variable(ir, lambda x: x.call_gas, *instances)
        new_ir.arguments = get_arguments(ir, *instances)
        return new_ir
    elif isinstance(ir, Member):
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        variable_left = get_variable(ir, lambda x: x.variable_left, *instances)
        variable_right = get_variable(ir, lambda x: x.variable_right,
                                      *instances)
        return Member(variable_left, variable_right, lvalue)
    elif isinstance(ir, NewArray):
        depth = ir.depth
        array_type = ir.array_type
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        new_ir = NewArray(depth, array_type, lvalue)
        new_ir.arguments = get_rec_values(ir, lambda x: x.arguments,
                                          *instances)
        return new_ir
    elif isinstance(ir, NewElementaryType):
        new_type = ir.type
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        new_ir = NewElementaryType(new_type, lvalue)
        new_ir.arguments = get_arguments(ir, *instances)
        return new_ir
    elif isinstance(ir, NewContract):
        contract_name = ir.contract_name
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        new_ir = NewContract(contract_name, lvalue)
        new_ir.arguments = get_arguments(ir, *instances)
        return new_ir
    elif isinstance(ir, NewStructure):
        structure = ir.structure
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        new_ir = NewStructure(structure, lvalue)
        new_ir.arguments = get_arguments(ir, *instances)
        return new_ir
    elif isinstance(ir, Push):
        array = get_variable(ir, lambda x: x.array, *instances)
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        return Push(array, lvalue)
    elif isinstance(ir, Return):
        values = get_rec_values(ir, lambda x: x.values, *instances)
        return Return(values)
    elif isinstance(ir, Send):
        destination = get_variable(ir, lambda x: x.destination, *instances)
        value = get_variable(ir, lambda x: x.call_value, *instances)
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        return Send(destination, value, lvalue)
    elif isinstance(ir, SolidityCall):
        function = ir.function
        nbr_arguments = ir.nbr_arguments
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        type_call = ir.type_call
        new_ir = SolidityCall(function, nbr_arguments, lvalue, type_call)
        new_ir.arguments = get_arguments(ir, *instances)
        return new_ir
    elif isinstance(ir, Transfer):
        destination = get_variable(ir, lambda x: x.destination, *instances)
        value = get_variable(ir, lambda x: x.call_value, *instances)
        return Transfer(destination, value)
    elif isinstance(ir, TypeConversion):
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        variable = get_variable(ir, lambda x: x.variable, *instances)
        variable_type = ir.type
        return TypeConversion(lvalue, variable, variable_type)
    elif isinstance(ir, Unary):
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        rvalue = get_variable(ir, lambda x: x.rvalue, *instances)
        operation_type = ir.type
        return Unary(lvalue, rvalue, operation_type)
    elif isinstance(ir, Unpack):
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        tuple_var = get_variable(ir, lambda x: x.tuple, *instances)
        idx = ir.index
        return Unpack(lvalue, tuple_var, idx)
    elif isinstance(ir, Length):
        lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
        value = get_variable(ir, lambda x: x.value, *instances)
        return Length(value, lvalue)

    raise SlithIRError('Impossible ir copy on {} ({})'.format(ir, type(ir)))