Exemple #1
0
    def get_hash(
        self,
        _from: bytes,
        _to: bytes,
        _ids: List[int],
        _from_values: List[int],
        _to_values: List[int],
        _value_eth_wei: int,
        _nonce: int,
    ) -> bytes:
        """
        Generate a hash mirroring the way we are creating this in the contract.

        :param _from: the from address hashed
        :param _to: the to address hashed
        :param _ids: the token ids
        :param _from_values: the from values
        :param _to_values: the to values
        :param _value_eth_wei: the value of eth (in wei)
        :param _nonce: the trade nonce
        :return: the hash in bytes string representation
        """
        aggregate_hash = keccak256(
            b"".join(
                [
                    _ids[0].to_bytes(32, "big"),
                    _from_values[0].to_bytes(32, "big"),
                    _to_values[0].to_bytes(32, "big"),
                ]
            )
        )
        for i in range(len(_ids)):
            if not i == 0:
                aggregate_hash = keccak256(
                    b"".join(
                        [
                            aggregate_hash,
                            _ids[i].to_bytes(32, "big"),
                            _from_values[i].to_bytes(32, "big"),
                            _to_values[i].to_bytes(32, "big"),
                        ]
                    )
                )

        m_list = []
        m_list.append(_from)
        m_list.append(_to)
        m_list.append(aggregate_hash)
        m_list.append(_value_eth_wei.to_bytes(32, "big"))
        m_list.append(_nonce.to_bytes(32, "big"))
        return keccak256(b"".join(m_list))
Exemple #2
0
    def _assert_reason(self, test_expr, msg):
        if isinstance(msg, vy_ast.Name) and msg.id == "UNREACHABLE":
            return LLLnode.from_list(["assert_unreachable", test_expr],
                                     typ=None,
                                     pos=getpos(msg))

        reason_str_type = ByteArrayType(len(msg.value.strip()))

        sig_placeholder = self.context.new_internal_variable(BaseType(32))
        arg_placeholder = self.context.new_internal_variable(BaseType(32))
        placeholder_bytes = Expr(msg, self.context).lll_node

        method_id = fourbytes_to_int(keccak256(b"Error(string)")[:4])

        revert_seq = [
            "seq",
            ["mstore", sig_placeholder, method_id],
            ["mstore", arg_placeholder, 32],
            placeholder_bytes,
            [
                "revert", sig_placeholder + 28,
                int(4 + get_size_of_type(reason_str_type) * 32)
            ],
        ]
        if test_expr:
            lll_node = ["if", ["iszero", test_expr], revert_seq]
        else:
            lll_node = revert_seq

        return LLLnode.from_list(lll_node, typ=None, pos=getpos(self.stmt))
Exemple #3
0
    def _assert_reason(self, test_expr, msg):
        if isinstance(msg, vy_ast.Name) and msg.id == "UNREACHABLE":
            return LLLnode.from_list(["assert_unreachable", test_expr],
                                     typ=None,
                                     pos=getpos(msg))

        reason_str = msg.s.strip()
        sig_placeholder = self.context.new_placeholder(BaseType(32))
        arg_placeholder = self.context.new_placeholder(BaseType(32))
        reason_str_type = ByteArrayType(len(reason_str))
        placeholder_bytes = Expr(msg, self.context).lll_node
        method_id = fourbytes_to_int(keccak256(b"Error(string)")[:4])
        assert_reason = [
            "seq",
            ["mstore", sig_placeholder, method_id],
            ["mstore", arg_placeholder, 32],
            placeholder_bytes,
            [
                "assert_reason",
                test_expr,
                int(sig_placeholder + 28),
                int(4 + get_size_of_type(reason_str_type) * 32),
            ],
        ]
        return LLLnode.from_list(assert_reason,
                                 typ=None,
                                 pos=getpos(self.stmt))
def keccak256_helper(expr, ir_arg, context):
    sub = ir_arg  # TODO get rid of useless variable
    _check_byteslike(sub.typ, expr)

    # Can hash literals
    # TODO this is dead code.
    if isinstance(sub, bytes):
        return IRnode.from_list(bytes_to_int(keccak256(sub)),
                                typ=BaseType("bytes32"))

    # Can hash bytes32 objects
    if is_base_type(sub.typ, "bytes32"):
        return IRnode.from_list(
            [
                "seq",
                ["mstore", MemoryPositions.FREE_VAR_SPACE, sub],
                ["sha3", MemoryPositions.FREE_VAR_SPACE, 32],
            ],
            typ=BaseType("bytes32"),
            add_gas_estimate=_gas_bound(1),
        )

    sub = ensure_in_memory(sub, context)

    return IRnode.from_list(
        [
            "with",
            "_buf",
            sub,
            ["sha3", ["add", "_buf", 32], ["mload", "_buf"]],
        ],
        typ=BaseType("bytes32"),
        annotation="keccak256",
        add_gas_estimate=_gas_bound(ceil(sub.typ.maxlen / 32)),
    )
Exemple #5
0
 def method_id(self) -> int:
     """
     Four byte selector for this function.
     """
     function_sig = f"{self.name}({','.join(i.canonical_type for i in self.arguments.values())})"
     selector = keccak256(function_sig.encode())[:4].hex()
     return int(selector, 16)
Exemple #6
0
    def _assert_reason(self, test_expr, msg):
        if isinstance(msg, ast.Name) and msg.id == 'UNREACHABLE':
            return self._assert_unreachable(test_expr, msg)

        if not isinstance(msg, ast.Str):
            raise StructureException(
                'Reason parameter of assert needs to be a literal string '
                '(or UNREACHABLE constant).', msg)
        if len(msg.s.strip()) == 0:
            raise StructureException('Empty reason string not allowed.',
                                     self.stmt)
        reason_str = msg.s.strip()
        sig_placeholder = self.context.new_placeholder(BaseType(32))
        arg_placeholder = self.context.new_placeholder(BaseType(32))
        reason_str_type = ByteArrayType(len(reason_str))
        placeholder_bytes = Expr(msg, self.context).lll_node
        method_id = fourbytes_to_int(keccak256(b"Error(string)")[:4])
        assert_reason = [
            'seq',
            ['mstore', sig_placeholder, method_id],
            ['mstore', arg_placeholder, 32],
            placeholder_bytes,
            [
                'assert_reason',
                test_expr,
                int(sig_placeholder + 28),
                int(4 + 32 + get_size_of_type(reason_str_type) * 32),
            ],
        ]
        return LLLnode.from_list(assert_reason,
                                 typ=None,
                                 pos=getpos(self.stmt))
Exemple #7
0
def keccak256_helper(expr, to_hash, context):
    _check_byteslike(to_hash.typ, expr)

    # Can hash literals
    # TODO this is dead code.
    if isinstance(to_hash, bytes):
        return IRnode.from_list(bytes_to_int(keccak256(to_hash)),
                                typ=BaseType("bytes32"))

    # Can hash bytes32 objects
    if is_base_type(to_hash.typ, "bytes32"):
        return IRnode.from_list(
            [
                "seq",
                ["mstore", MemoryPositions.FREE_VAR_SPACE, to_hash],
                ["sha3", MemoryPositions.FREE_VAR_SPACE, 32],
            ],
            typ=BaseType("bytes32"),
            add_gas_estimate=_gas_bound(1),
        )

    to_hash = ensure_in_memory(to_hash, context)

    with to_hash.cache_when_complex("buf") as (b1, to_hash):
        data = bytes_data_ptr(to_hash)
        len_ = get_bytearray_length(to_hash)
        return b1.resolve(
            IRnode.from_list(
                ["sha3", data, len_],
                typ="bytes32",
                annotation="keccak256",
                add_gas_estimate=_gas_bound(ceil(to_hash.typ.maxlen / 32)),
            ))
Exemple #8
0
    def get_single_hash(
        self,
        _from: bytes,
        _to: bytes,
        _id: int,
        _from_value: int,
        _to_value: int,
        _value_eth_wei: int,
        _nonce: int,
    ) -> bytes:
        """
        Generate a hash mirroring the way we are creating this in the contract.

        :param _from: the from address hashed
        :param _to: the to address hashed
        :param _ids: the token ids
        :param _from_value: the from value
        :param _to_value: the to value
        :param _value_eth_wei: the value eth (in wei)
        :param _nonce: the trade nonce
        :return: the hash in bytes string representation
        """
        return keccak256(b"".join([
            _from,
            _to,
            _id.to_bytes(32, "big"),
            _from_value.to_bytes(32, "big"),
            _to_value.to_bytes(32, "big"),
            _value_eth_wei.to_bytes(32, "big"),
            _nonce.to_bytes(32, "big"),
        ]))
Exemple #9
0
 def __init__(self, name: str, arguments: OrderedDict,
              indexed: List) -> None:
     for key in arguments:
         validate_identifier(key)
     self.name = name
     self.arguments = arguments
     self.indexed = indexed
     self.event_id = int(keccak256(self.signature.encode()).hex(), 16)
Exemple #10
0
 def __init__(self, name: str, arguments: OrderedDict, indexed: List) -> None:
     for key in arguments:
         validate_identifier(key)
     self.name = name
     self.arguments = arguments
     self.indexed = indexed
     signature = f"{name}({','.join(v.canonical_type for v in arguments.values())})"
     self.event_id = int(keccak256(signature.encode()).hex(), 16)
Exemple #11
0
    def from_declaration(cls, class_node, global_ctx):
        name = class_node.name
        pos = 0

        check_valid_varname(
            name,
            global_ctx._structs,
            global_ctx._constants,
            pos=class_node,
            error_prefix="Event name invalid. ",
            exc=EventDeclarationException,
        )

        args = []
        indexed_list = []
        if len(class_node.body) != 1 or not isinstance(class_node.body[0],
                                                       vy_ast.Pass):
            for node in class_node.body:
                arg_item = node.target
                arg = node.target.id
                typ = node.annotation

                if isinstance(typ,
                              vy_ast.Call) and typ.get("func.id") == "indexed":
                    indexed_list.append(True)
                    typ = typ.args[0]
                else:
                    indexed_list.append(False)
                check_valid_varname(
                    arg,
                    global_ctx._structs,
                    global_ctx._constants,
                    pos=arg_item,
                    error_prefix="Event argument name invalid or reserved.",
                )
                if arg in (x.name for x in args):
                    raise TypeCheckFailure(
                        f"Duplicate function argument name: {arg}")
                # Can struct be logged?
                parsed_type = global_ctx.parse_type(typ, None)
                args.append(VariableRecord(arg, pos, parsed_type, False))
                if isinstance(parsed_type, ByteArrayType):
                    pos += ceil32(typ.slice.value.n)
                else:
                    pos += get_size_of_type(parsed_type) * 32

        sig = (name + "(" + ",".join([
            canonicalize_type(arg.typ, indexed_list[pos])
            for pos, arg in enumerate(args)
        ]) + ")")  # noqa F812
        event_id = bytes_to_int(keccak256(bytes(sig, "utf-8")))
        return cls(name, args, indexed_list, event_id, sig)
def keccak256_helper(expr, args, kwargs, context):
    sub = args[0]
    # Can hash literals
    if isinstance(sub, bytes):
        return LLLnode.from_list(bytes_to_int(keccak256(sub)),
                                 typ=BaseType("bytes32"),
                                 pos=getpos(expr))
    # Can hash bytes32 objects
    if is_base_type(sub.typ, "bytes32"):
        return LLLnode.from_list(
            [
                "seq",
                ["mstore", MemoryPositions.FREE_VAR_SPACE, sub],
                ["sha3", MemoryPositions.FREE_VAR_SPACE, 32],
            ],
            typ=BaseType("bytes32"),
            pos=getpos(expr),
        )
    # Copy the data to an in-memory array
    if sub.location == "memory":
        # If we are hashing a value in memory, no need to copy it, just hash in-place
        return LLLnode.from_list(
            [
                "with", "_sub", sub,
                ["sha3", ["add", "_sub", 32], ["mload", "_sub"]]
            ],
            typ=BaseType("bytes32"),
            pos=getpos(expr),
        )
    elif sub.location == "storage":
        lengetter = LLLnode.from_list(["sload", ["sha3_32", "_sub"]],
                                      typ=BaseType("int128"))
    else:
        # This should never happen, but just left here for future compiler-writers.
        raise Exception(
            f"Unsupported location: {sub.location}")  # pragma: no test
    placeholder = context.new_internal_variable(sub.typ)
    placeholder_node = LLLnode.from_list(placeholder,
                                         typ=sub.typ,
                                         location="memory")
    copier = make_byte_array_copier(
        placeholder_node,
        LLLnode.from_list("_sub", typ=sub.typ, location=sub.location),
    )
    return LLLnode.from_list(
        [
            "with", "_sub", sub,
            ["seq", copier, ["sha3", ["add", placeholder, 32], lengetter]]
        ],
        typ=BaseType("bytes32"),
        pos=getpos(expr),
    )
Exemple #13
0
def keccak256_helper(expr, args, kwargs, context):
    sub = args[0]
    # Can hash literals
    if isinstance(sub, bytes):
        return LLLnode.from_list(bytes_to_int(keccak256(sub)),
                                 typ=BaseType('bytes32'),
                                 pos=getpos(expr))
    # Can hash bytes32 objects
    if is_base_type(sub.typ, 'bytes32'):
        return LLLnode.from_list(
            [
                'seq', ['mstore', MemoryPositions.FREE_VAR_SPACE, sub],
                ['sha3', MemoryPositions.FREE_VAR_SPACE, 32]
            ],
            typ=BaseType('bytes32'),
            pos=getpos(expr),
        )
    # Copy the data to an in-memory array
    if sub.location == "memory":
        # If we are hashing a value in memory, no need to copy it, just hash in-place
        return LLLnode.from_list(
            [
                'with', '_sub', sub,
                ['sha3', ['add', '_sub', 32], ['mload', '_sub']]
            ],
            typ=BaseType('bytes32'),
            pos=getpos(expr),
        )
    elif sub.location == "storage":
        lengetter = LLLnode.from_list(['sload', ['sha3_32', '_sub']],
                                      typ=BaseType('int128'))
    else:
        # This should never happen, but just left here for future compiler-writers.
        raise Exception("Unsupported location: %s" %
                        sub.location)  # pragma: no test
    placeholder = context.new_placeholder(sub.typ)
    placeholder_node = LLLnode.from_list(placeholder,
                                         typ=sub.typ,
                                         location='memory')
    copier = make_byte_array_copier(
        placeholder_node,
        LLLnode.from_list('_sub', typ=sub.typ, location=sub.location),
    )
    return LLLnode.from_list([
        'with',
        '_sub',
        sub,
        ['seq', copier, ['sha3', ['add', placeholder, 32], lengetter]],
    ],
                             typ=BaseType('bytes32'),
                             pos=getpos(expr))
Exemple #14
0
def pack_logging_topics(event_id, arg_nodes, arg_types, context):
    topics = [event_id]
    for node, typ in zip(arg_nodes, arg_types):
        value = Expr(node, context).lll_node

        if isinstance(typ, ArrayValueAbstractType):
            if isinstance(node, (vy_ast.Str, vy_ast.Bytes)):
                # for literals, generate the topic at compile time
                value = node.value
                if isinstance(value, str):
                    value = value.encode()
                topics.append(bytes_to_int(keccak256(value)))

            elif value.location == "memory":
                topics.append(["sha3", ["add", value, 32], ["mload", value]])

            else:
                # storage or calldata
                placeholder = context.new_internal_variable(value.typ)
                placeholder_node = LLLnode.from_list(placeholder, typ=value.typ, location="memory")
                copier = make_byte_array_copier(
                    placeholder_node,
                    LLLnode.from_list("_sub", typ=value.typ, location=value.location),
                )
                lll_node = [
                    "with",
                    "_sub",
                    value,
                    ["seq", copier, ["sha3", ["add", placeholder, 32], ["mload", placeholder]]],
                ]
                topics.append(lll_node)

        elif isinstance(typ, ArrayDefinition):
            size = typ.size_in_bytes
            if value.location == "memory":
                topics.append(["sha3", value, size])

            else:
                # storage or calldata
                placeholder = context.new_internal_variable(value.typ)
                placeholder_node = LLLnode.from_list(placeholder, typ=value.typ, location="memory")
                setter = make_setter(placeholder_node, value, "memory", value.pos)
                lll_node = ["seq", setter, ["sha3", placeholder, size]]
                topics.append(lll_node)

        else:
            value = unwrap_location(value)
            topics.append(value)

    return topics
Exemple #15
0
def test_get_extcodehash(get_contract, evm_version, no_optimize):
    code = """
a: address

@external
def __init__():
    self.a = self

@external
def foo(x: address) -> bytes32:
    return x.codehash

@external
def foo2(x: address) -> bytes32:
    b: address = x
    return b.codehash

@external
def foo3() -> bytes32:
    return self.codehash

@external
def foo4() -> bytes32:
    return self.a.codehash
    """

    if evm_version in ("byzantium", "atlantis"):
        with pytest.raises(EvmVersionException):
            compile_code(code, evm_version=evm_version)
        return

    compiled = compile_code(code, ["bytecode_runtime"],
                            evm_version=evm_version,
                            no_optimize=no_optimize)
    bytecode = bytes.fromhex(compiled["bytecode_runtime"][2:])
    hash_ = keccak256(bytecode)

    c = get_contract(code, evm_version=evm_version)

    assert c.foo(c.address) == hash_
    assert not int(
        c.foo("0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF").hex(), 16)

    assert c.foo2(c.address) == hash_
    assert not int(
        c.foo2("0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF").hex(), 16)

    assert c.foo3() == hash_
    assert c.foo4() == hash_
Exemple #16
0
def method_id(expr, args, kwargs, context):
    if b' ' in args[0]:
        raise TypeMismatchException('Invalid function signature no spaces allowed.')
    method_id = fourbytes_to_int(keccak256(args[0])[:4])
    if args[1] == 'bytes32':
        return LLLnode(method_id, typ=BaseType('bytes32'), pos=getpos(expr))
    elif args[1] == 'bytes[4]':
        placeholder = LLLnode.from_list(context.new_placeholder(ByteArrayType(4)))
        return LLLnode.from_list(
            ['seq',
                ['mstore', ['add', placeholder, 4], method_id],
                ['mstore', placeholder, 4], placeholder],
            typ=ByteArrayType(4), location='memory', pos=getpos(expr))
    else:
        raise StructureException('Can only produce bytes32 or bytes[4] as outputs')
Exemple #17
0
    def test_handle_response(self):
        """Test the _handle_response method of the http handler to a valid fetch beacon response."""
        # setup
        http_dialogue = self.prepare_skill_dialogue(
            dialogues=self.http_dialogues,
            messages=self.list_of_messages[:1],
        )

        test_response = {
            "result": {
                "block_id": {
                    "hash": "00000000"
                },
                "block": {
                    "header": {
                        "height": "1",
                        "entropy": {
                            "group_signature": "SIGNATURE"
                        },
                    }
                },
            }
        }

        incoming_message = self.build_incoming_message_for_skill_dialogue(
            dialogue=http_dialogue,
            performative=HttpMessage.Performative.RESPONSE,
            version="",
            status_code=200,
            status_text="",
            headers="",
            body=json.dumps(test_response).encode("utf-8"),
        )

        # handle message
        self.http_handler.handle(incoming_message)

        # check that data was correctly entered into shared state
        beacon_data = {
            "entropy": keccak256("SIGNATURE".encode("utf-8")),
            "block_hash": bytes.fromhex("00000000"),
            "block_height": 1,
        }
        assert self.http_handler.context.shared_state[
            "oracle_data"] == beacon_data

        # check that outbox is empty
        self.assert_quantity_in_outbox(0)
Exemple #18
0
def test_create_minimal_proxy_to_create(get_contract):
    code = """
main: address

@external
def test() -> address:
    self.main = create_minimal_proxy_to(self)
    return self.main
    """

    c = get_contract(code)

    address_bits = int(c.address, 16)
    nonce = 1
    rlp_encoded = rlp.encode([address_bits, nonce])
    expected_create_address = keccak256(rlp_encoded)[12:].rjust(20, b"\x00")
    assert c.test() == checksum_encode("0x" + expected_create_address.hex())
Exemple #19
0
    def _handle_response(self, message: HttpMessage) -> None:
        """
        Handle an http response.

        :param msg: the http message to be handled
        :return: None
        """

        msg_body = json.loads(message.body)

        # get entropy and block data
        entropy = (
            msg_body.get("result", {})
            .get("block", {})
            .get("header", {})
            .get("entropy", {})
            .get("group_signature", None)
        )
        block_hash = msg_body.get("result", {}).get("block_id", {}).get("hash", {})
        block_height_str = (
            msg_body.get("result", {})
            .get("block", {})
            .get("header", {})
            .get("height", None)
        )

        if block_height_str:
            block_height = int(block_height_str)  # type: Optional[int]
        else:
            block_height = None

        if entropy is None:
            self.context.logger.info("entropy not present")
        elif block_height is None:  # pragma: nocover
            self.context.logger.info("block height not present")
        else:
            beacon_data = {
                "entropy": keccak256(entropy.encode("utf-8")),
                "block_hash": bytes.fromhex(block_hash),
                "block_height": block_height,
            }
            self.context.logger.info(
                "Beacon info: "
                + str({"block_height": block_height, "entropy": entropy})
            )
            self.context.shared_state["oracle_data"] = beacon_data
Exemple #20
0
def test_contracts_keccak():
    hash_ = keccak256(FOO_CODE.encode()).hex()

    input_json = {
        'sources': {
            'foo.vy': {
                'content': FOO_CODE,
                'keccak256': hash_
            }
        }
    }
    get_input_dict_contracts(input_json)

    input_json['sources']['foo.vy']['keccak256'] = "0x" + hash_
    get_input_dict_contracts(input_json)

    input_json['sources']['foo.vy']['keccak256'] = "0x1234567890"
    with pytest.raises(JSONError):
        get_input_dict_contracts(input_json)
def test_contracts_keccak():
    hash_ = keccak256(FOO_CODE.encode()).hex()

    input_json = {
        "sources": {
            "foo.vy": {
                "content": FOO_CODE,
                "keccak256": hash_
            }
        }
    }
    get_input_dict_contracts(input_json)

    input_json["sources"]["foo.vy"]["keccak256"] = "0x" + hash_
    get_input_dict_contracts(input_json)

    input_json["sources"]["foo.vy"]["keccak256"] = "0x1234567890"
    with pytest.raises(JSONError):
        get_input_dict_contracts(input_json)
Exemple #22
0
def get_input_dict_contracts(input_dict: Dict) -> ContractCodes:
    contract_sources: ContractCodes = {}
    for path, value in input_dict['sources'].items():
        if 'urls' in value:
            raise JSONError(f"{path} - 'urls' is not a supported field, use 'content' instead")
        if 'content' not in value:
            raise JSONError(f"{path} missing required field - 'content'")
        if 'keccak256' in value:
            hash_ = value['keccak256'].lower()
            if hash_.startswith('0x'):
                hash_ = hash_[2:]
            if hash_ != keccak256(value['content'].encode('utf-8')).hex():
                raise JSONError(
                    f"Calculated keccak of '{path}' does not match keccak given in input JSON"
                )
        key = _standardize_path(path)
        if key in contract_sources:
            raise JSONError(f"Contract namespace collision: {key}")
        contract_sources[key] = value['content']
    return contract_sources
Exemple #23
0
def test_raw_call_bytes32_data(w3, tester, get_contract_with_gas_estimation):
    code = """
b: uint256

@external
def foo():
    a: uint256 = 1234
    self.b = 4321
    raw_log([], convert(a, bytes32))
    raw_log([], convert(self.b, bytes32))
    raw_log([], convert(b"testmessage", bytes32))
    raw_log([], keccak256(b""))
    """
    c = get_contract_with_gas_estimation(code)
    tx_hash = c.foo(transact={})
    receipt = tester.get_transaction_receipt(tx_hash.hex())
    logs = receipt["logs"]
    assert logs[0]["data"] == w3.toHex((1234).to_bytes(32, "big"))
    assert logs[1]["data"] == w3.toHex((4321).to_bytes(32, "big"))
    assert logs[2]["data"] == w3.toHex(b"testmessage").ljust(32 * 2 + 2, "0")
    assert logs[3]["data"] == w3.toHex(keccak256(b""))
    def from_definition(
        cls,
        code,
        sigs=None,
        custom_structs=None,
        interface_def=False,
        constant_override=False,
        is_from_json=False,
    ):
        if not custom_structs:
            custom_structs = {}

        name = code.name
        mem_pos = 0

        # Determine the arguments, expects something of the form def foo(arg1:
        # int128, arg2: int128 ...
        args = []
        for arg in code.args.args:
            # Each arg needs a type specified.
            typ = arg.annotation
            parsed_type = parse_type(
                typ,
                None,
                sigs,
                custom_structs=custom_structs,
            )
            args.append(
                VariableRecord(
                    arg.arg,
                    mem_pos,
                    parsed_type,
                    False,
                    defined_at=getpos(arg),
                ))

            if isinstance(parsed_type, ByteArrayLike):
                mem_pos += 32
            else:
                mem_pos += get_size_of_type(parsed_type) * 32

        mutability = "nonpayable"  # Assume nonpayable by default
        nonreentrant_key = ""
        is_internal = False

        # Update function properties from decorators
        # NOTE: Can't import enums here because of circular import
        for dec in code.decorator_list:
            if isinstance(dec, vy_ast.Name) and dec.id in ("payable", "view",
                                                           "pure"):
                mutability = dec.id
            elif isinstance(dec, vy_ast.Name) and dec.id == "internal":
                is_internal = True
            elif isinstance(dec, vy_ast.Name) and dec.id == "external":
                is_internal = False
            elif isinstance(dec,
                            vy_ast.Call) and dec.func.id == "nonreentrant":
                nonreentrant_key = dec.args[0].s

        if constant_override:
            # In case this override is abused, match previous behavior
            if mutability == "payable":
                raise StructureException(
                    f"Function {name} cannot be both constant and payable.")
            mutability = "view"

        # Determine the return type and whether or not it's constant. Expects something
        # of the form:
        # def foo(): ...
        # def foo() -> int128: ...
        # If there is no return type, ie. it's of the form def foo(): ...
        # and NOT def foo() -> type: ..., then it's null
        output_type = None
        if code.returns:
            output_type = parse_type(
                code.returns,
                None,
                sigs,
                custom_structs=custom_structs,
            )
            # Output type must be canonicalizable
            assert isinstance(output_type,
                              TupleType) or canonicalize_type(output_type)
        # Get the canonical function signature
        sig = cls.get_full_sig(name, code.args.args, sigs, custom_structs)

        # Take the first 4 bytes of the hash of the sig to get the method ID
        method_id = fourbytes_to_int(keccak256(bytes(sig, "utf-8"))[:4])
        return cls(
            name,
            args,
            output_type,
            mutability,
            is_internal,
            nonreentrant_key,
            sig,
            method_id,
            code,
            is_from_json,
        )
Exemple #25
0
# ------------------------------------------------------------------------------
"""This module contains the class to connect to an Oracle contract."""

import logging
from typing import Any, Dict

from vyper.utils import keccak256

from aea.common import Address, JSONLike
from aea.configurations.base import PublicId
from aea.contracts.base import Contract
from aea.crypto.base import LedgerApi
from aea.crypto.ethereum import EthereumApi

PUBLIC_ID = PublicId.from_str("fetchai/oracle:0.4.0")
CONTRACT_ROLE = keccak256(b"ORACLE_ROLE")

_default_logger = logging.getLogger(
    "aea.packages.fetchai.contracts.oracle.contract")


class FetchOracleContract(Contract):
    """The Fetch oracle contract."""
    @classmethod
    def get_grant_role_transaction(
        cls,
        ledger_api: LedgerApi,
        contract_address: Address,
        oracle_address: Address,
        gas: int = 0,
    ) -> JSONLike:
Exemple #26
0
def _generate_method_id(name: str,
                        canonical_abi_types: List[str]) -> Dict[str, int]:
    function_sig = f"{name}({','.join(canonical_abi_types)})"
    selector = keccak256(function_sig.encode())[:4].hex()
    return {function_sig: int(selector, 16)}
Exemple #27
0
    def from_definition(
        cls,
        code,
        sigs=None,
        custom_structs=None,
        interface_def=False,
        constants=None,
        constant_override=False,
        is_from_json=False,
    ):
        if not custom_structs:
            custom_structs = {}

        name = code.name
        mem_pos = 0

        valid_name, msg = is_varname_valid(name, custom_structs, constants)
        if not valid_name and (not name.lower() in FUNCTION_WHITELIST):
            raise FunctionDeclarationException("Function name invalid. " + msg, code)

        # Validate default values.
        for default_value in getattr(code.args, "defaults", []):
            validate_default_values(default_value)

        # Determine the arguments, expects something of the form def foo(arg1:
        # int128, arg2: int128 ...
        args = []
        for arg in code.args.args:
            # Each arg needs a type specified.
            typ = arg.annotation
            if not typ:
                raise InvalidType("Argument must have type", arg)
            # Validate arg name.
            check_valid_varname(
                arg.arg,
                custom_structs,
                constants,
                arg,
                "Argument name invalid or reserved. ",
                FunctionDeclarationException,
            )
            # Check for duplicate arg name.
            if arg.arg in (x.name for x in args):
                raise FunctionDeclarationException(
                    "Duplicate function argument name: " + arg.arg, arg,
                )
            parsed_type = parse_type(
                typ, None, sigs, custom_structs=custom_structs, constants=constants,
            )
            args.append(
                VariableRecord(arg.arg, mem_pos, parsed_type, False, defined_at=getpos(arg),)
            )

            if isinstance(parsed_type, ByteArrayLike):
                mem_pos += 32
            else:
                mem_pos += get_size_of_type(parsed_type) * 32

        mutability = "nonpayable"  # Assume nonpayable by default
        internal = False
        external = False
        nonreentrant_key = ""

        # Update function properties from decorators
        # NOTE: Can't import enums here because of circular import
        for dec in code.decorator_list:
            if isinstance(dec, vy_ast.Name) and dec.id in ("payable", "view", "pure"):
                mutability = dec.id
            elif isinstance(dec, vy_ast.Name) and dec.id == "internal":
                internal = True
            elif isinstance(dec, vy_ast.Name) and dec.id == "external":
                external = True
            elif isinstance(dec, vy_ast.Call) and dec.func.id == "nonreentrant":
                if nonreentrant_key:
                    raise StructureException(
                        "Only one @nonreentrant decorator allowed per function", dec
                    )
                if (
                    dec.args
                    and len(dec.args) == 1
                    and isinstance(dec.args[0], vy_ast.Str)
                    and dec.args[0].s
                ):  # noqa: E501
                    nonreentrant_key = dec.args[0].s
                else:
                    raise StructureException(
                        "@nonreentrant decorator requires a non-empty string to use as a key.", dec
                    )
            else:
                raise StructureException("Bad decorator", dec)

        if constant_override:
            # In case this override is abused, match previous behavior
            if mutability == "payable":
                raise StructureException(f"Function {name} cannot be both constant and payable.")
            mutability = "view"

        if external and internal:
            raise StructureException(
                f"Cannot use external and internal decorators on the same function: {name}"
            )
        if mutability == "payable" and internal:
            raise StructureException(f"Function {name} cannot be both internal and payable.")
        if (not external and not internal) and not interface_def:
            raise StructureException(
                "Function visibility must be declared (@external or @internal)", code,
            )
        if mutability in ("view", "pure") and nonreentrant_key:
            raise StructureException(
                f"@nonreentrant makes no sense on a @{mutability} function.", code
            )

        # Determine the return type and whether or not it's constant. Expects something
        # of the form:
        # def foo(): ...
        # def foo() -> int128: ...
        # If there is no return type, ie. it's of the form def foo(): ...
        # and NOT def foo() -> type: ..., then it's null
        if not code.returns:
            output_type = None
        elif isinstance(
            code.returns, (vy_ast.Name, vy_ast.Compare, vy_ast.Subscript, vy_ast.Call, vy_ast.Tuple)
        ):
            output_type = parse_type(
                code.returns, None, sigs, custom_structs=custom_structs, constants=constants,
            )
        else:
            raise InvalidType(
                f"Output type invalid or unsupported: {parse_type(code.returns, None)}",
                code.returns,
            )
        # Output type must be canonicalizable
        if output_type is not None:
            assert isinstance(output_type, TupleType) or canonicalize_type(output_type)
        # Get the canonical function signature
        sig = cls.get_full_sig(name, code.args.args, sigs, custom_structs, constants)

        # Take the first 4 bytes of the hash of the sig to get the method ID
        method_id = fourbytes_to_int(keccak256(bytes(sig, "utf-8"))[:4])
        return cls(
            name,
            args,
            output_type,
            mutability,
            internal,
            nonreentrant_key,
            sig,
            method_id,
            code,
            is_from_json,
        )
Exemple #28
0
    def from_definition(cls,
                        code,
                        sigs=None,
                        custom_units=None,
                        custom_structs=None,
                        contract_def=False,
                        constants=None,
                        constant=False):
        if not custom_structs:
            custom_structs = {}

        name = code.name
        mem_pos = 0

        valid_name, msg = is_varname_valid(name, custom_units, custom_structs,
                                           constants)
        if not valid_name and (not name.lower() in function_whitelist):
            raise FunctionDeclarationException("Function name invalid. " + msg,
                                               code)

        # Validate default values.
        for default_value in getattr(code.args, 'defaults', []):
            allowed_types = (ast.Num, ast.Str, ast.Bytes, ast.List,
                             ast.NameConstant)
            if not isinstance(default_value, allowed_types):
                raise FunctionDeclarationException(
                    "Default parameter values have to be literals.")

        # Determine the arguments, expects something of the form def foo(arg1:
        # int128, arg2: int128 ...
        args = []
        for arg in code.args.args:
            # Each arg needs a type specified.
            typ = arg.annotation
            if not typ:
                raise InvalidTypeException("Argument must have type", arg)
            # Validate arg name.
            check_valid_varname(
                arg.arg,
                custom_units,
                custom_structs,
                constants,
                arg,
                "Argument name invalid or reserved. ",
                FunctionDeclarationException,
            )
            # Check for duplicate arg name.
            if arg.arg in (x.name for x in args):
                raise FunctionDeclarationException(
                    "Duplicate function argument name: " + arg.arg,
                    arg,
                )
            parsed_type = parse_type(
                typ,
                None,
                sigs,
                custom_units=custom_units,
                custom_structs=custom_structs,
                constants=constants,
            )
            args.append(
                VariableRecord(
                    arg.arg,
                    mem_pos,
                    parsed_type,
                    False,
                    defined_at=getpos(arg),
                ))

            if isinstance(parsed_type, ByteArrayLike):
                mem_pos += 32
            else:
                mem_pos += get_size_of_type(parsed_type) * 32

        # Apply decorators
        const, payable, private, public, nonreentrant_key = False, False, False, False, ''
        for dec in code.decorator_list:
            if isinstance(dec, ast.Name) and dec.id == "constant":
                const = True
            elif isinstance(dec, ast.Name) and dec.id == "payable":
                payable = True
            elif isinstance(dec, ast.Name) and dec.id == "private":
                private = True
            elif isinstance(dec, ast.Name) and dec.id == "public":
                public = True
            elif isinstance(dec, ast.Call) and dec.func.id == "nonreentrant":
                if dec.args and len(dec.args) == 1 and isinstance(
                        dec.args[0], ast.Str) and dec.args[0].s:  # noqa: E501
                    nonreentrant_key = dec.args[0].s
                else:
                    raise StructureException(
                        "@nonreentrant decorator requires a non-empty string to use as a key.",
                        dec)
            else:
                raise StructureException("Bad decorator", dec)

        if public and private:
            raise StructureException(
                "Cannot use public and private decorators on the same function: {}"
                .format(name))
        if payable and const:
            raise StructureException(
                "Function {} cannot be both constant and payable.".format(
                    name))
        if payable and private:
            raise StructureException(
                "Function {} cannot be both private and payable.".format(name))
        if (not public and not private) and not contract_def:
            raise StructureException(
                "Function visibility must be declared (@public or @private)",
                code,
            )
        if constant and nonreentrant_key:
            raise StructureException(
                "@nonreentrant makes no sense on a @constant function.", code)
        if constant:
            const = True
        # Determine the return type and whether or not it's constant. Expects something
        # of the form:
        # def foo(): ...
        # def foo() -> int128: ...
        # If there is no return type, ie. it's of the form def foo(): ...
        # and NOT def foo() -> type: ..., then it's null
        if not code.returns:
            output_type = None
        elif isinstance(
                code.returns,
            (ast.Name, ast.Compare, ast.Subscript, ast.Call, ast.Tuple)):
            output_type = parse_type(
                code.returns,
                None,
                sigs,
                custom_units=custom_units,
                custom_structs=custom_structs,
                constants=constants,
            )
        else:
            raise InvalidTypeException(
                "Output type invalid or unsupported: %r" %
                parse_type(code.returns, None),
                code.returns,
            )
        # Output type must be canonicalizable
        if output_type is not None:
            assert isinstance(output_type,
                              TupleType) or canonicalize_type(output_type)
        # Get the canonical function signature
        sig = cls.get_full_sig(name, code.args.args, sigs, custom_units,
                               custom_structs, constants)

        # Take the first 4 bytes of the hash of the sig to get the method ID
        method_id = fourbytes_to_int(keccak256(bytes(sig, 'utf-8'))[:4])
        return cls(name, args, output_type, const, payable, private,
                   nonreentrant_key, sig, method_id, custom_units, code)
Exemple #29
0
    def from_declaration(cls, code, global_ctx):
        name = code.target.id
        pos = 0

        check_valid_varname(name,
                            global_ctx._custom_units,
                            global_ctx._structs,
                            global_ctx._constants,
                            pos=code,
                            error_prefix="Event name invalid. ",
                            exc=EventDeclarationException)

        # Determine the arguments, expects something of the form def foo(arg1: num, arg2: num ...
        args = []
        indexed_list = []
        topics_count = 1
        if code.annotation.args:
            keys = code.annotation.args[0].keys
            values = code.annotation.args[0].values
            for i in range(len(keys)):
                typ = values[i]
                if not isinstance(keys[i], ast.Name):
                    raise EventDeclarationException(
                        'Invalid key type, expected a valid name.',
                        keys[i],
                    )
                if not isinstance(typ, (ast.Name, ast.Call, ast.Subscript)):
                    raise EventDeclarationException(
                        'Invalid event argument type.', typ)
                if isinstance(typ,
                              ast.Call) and not isinstance(typ.func, ast.Name):
                    raise EventDeclarationException(
                        'Invalid event argument type', typ)
                arg = keys[i].id
                arg_item = keys[i]
                is_indexed = False

                # Check to see if argument is a topic
                if isinstance(typ, ast.Call) and typ.func.id == 'indexed':
                    typ = values[i].args[0]
                    indexed_list.append(True)
                    topics_count += 1
                    is_indexed = True
                else:
                    indexed_list.append(False)
                if isinstance(typ, ast.Subscript) and getattr(
                        typ.value, 'id', None
                ) == 'bytes' and typ.slice.value.n > 32 and is_indexed:  # noqa: E501
                    raise EventDeclarationException(
                        "Indexed arguments are limited to 32 bytes")
                if topics_count > 4:
                    raise EventDeclarationException(
                        f"Maximum of 3 topics {topics_count - 1} given",
                        arg,
                    )
                if not isinstance(arg, str):
                    raise VariableDeclarationException("Argument name invalid",
                                                       arg)
                if not typ:
                    raise InvalidTypeException("Argument must have type", arg)
                check_valid_varname(
                    arg,
                    global_ctx._custom_units,
                    global_ctx._structs,
                    global_ctx._constants,
                    pos=arg_item,
                    error_prefix="Event argument name invalid or reserved.",
                )
                if arg in (x.name for x in args):
                    raise VariableDeclarationException(
                        "Duplicate function argument name: " + arg,
                        arg_item,
                    )
                # Can struct be logged?
                parsed_type = global_ctx.parse_type(typ, None)
                args.append(VariableRecord(arg, pos, parsed_type, False))
                if isinstance(parsed_type, ByteArrayType):
                    pos += ceil32(typ.slice.value.n)
                else:
                    pos += get_size_of_type(parsed_type) * 32
        sig = name + '(' + ','.join([
            canonicalize_type(arg.typ, indexed_list[pos])
            for pos, arg in enumerate(args)
        ]) + ')'  # noqa F812
        event_id = bytes_to_int(keccak256(bytes(sig, 'utf-8')))
        return cls(name, args, indexed_list, event_id, sig)
Exemple #30
0
def pack_logging_topics(event_id, args, expected_topics, context, pos):
    topics = [event_id]
    code_pos = pos
    for pos, expected_topic in enumerate(expected_topics):
        expected_type = expected_topic.typ
        arg = args[pos]
        value = Expr(arg, context).lll_node
        arg_type = value.typ

        if isinstance(arg_type, ByteArrayLike) and isinstance(expected_type, ByteArrayLike):
            if arg_type.maxlen > expected_type.maxlen:
                raise TypeMismatch(
                    f"Topic input bytes are too big: {arg_type} {expected_type}", code_pos
                )

            if isinstance(arg, (vy_ast.Str, vy_ast.Bytes)):
                # for literals, generate the topic at compile time
                value = arg.value
                if isinstance(value, str):
                    value = value.encode()
                topics.append(bytes_to_int(keccak256(value)))

            elif value.location == "memory":
                topics.append(["sha3", ["add", value, 32], ["mload", value]])

            else:
                # storage or calldata
                placeholder = context.new_internal_variable(value.typ)
                placeholder_node = LLLnode.from_list(placeholder, typ=value.typ, location="memory")
                copier = make_byte_array_copier(
                    placeholder_node,
                    LLLnode.from_list("_sub", typ=value.typ, location=value.location),
                )
                lll_node = [
                    "with",
                    "_sub",
                    value,
                    ["seq", copier, ["sha3", ["add", placeholder, 32], ["mload", placeholder]]],
                ]
                topics.append(lll_node)

        elif isinstance(arg_type, ListType) and isinstance(expected_type, ListType):
            size = get_size_of_type(value.typ) * 32
            if value.location == "memory":
                topics.append(["sha3", value, size])

            else:
                # storage or calldata
                placeholder = context.new_internal_variable(value.typ)
                placeholder_node = LLLnode.from_list(placeholder, typ=value.typ, location="memory")
                setter = make_setter(placeholder_node, value, "memory", value.pos)
                lll_node = ["seq", setter, ["sha3", placeholder, size]]
                topics.append(lll_node)

        else:
            if arg_type != expected_type:
                raise TypeMismatch(
                    f"Invalid type for logging topic, got {arg_type} expected {expected_type}",
                    value.pos,
                )
            value = unwrap_location(value)
            value = base_type_conversion(value, arg_type, expected_type, pos=code_pos)
            topics.append(value)

    return topics