Example #1
0
def test_struct_abi():
    code = """
struct MyStruct:
    a: address
    b: uint256

@external
@view
def foo(s: MyStruct) -> MyStruct:
    return s
    """

    data = CompilerData(code)
    abi = build_abi_output(data)
    func_abi = abi[0]

    assert func_abi["name"] == "foo"

    expected_output = [
        {
            "type": "tuple",
            "name": "",
            "components": [{"type": "address", "name": "a"}, {"type": "uint256", "name": "b"}],
        }
    ]

    assert func_abi["outputs"] == expected_output

    expected_input = {
        "type": "tuple",
        "name": "s",
        "components": [{"type": "address", "name": "a"}, {"type": "uint256", "name": "b"}],
    }

    assert func_abi["inputs"][0] == expected_input
Example #2
0
def test_struct_abi():
    code = """
struct MyStruct:
    a: address
    b: uint256

@public
@constant
def foo(s: MyStruct) -> MyStruct:
    return s
    """

    data = CompilerData(code)
    abi = build_abi_output(data)
    func_abi = abi[0]

    assert func_abi["name"] == "foo"
    expected = {
        'type':
        'tuple',
        'name':
        '',
        'components': [{
            'type': 'address',
            'name': 'a'
        }, {
            'type': 'uint256',
            'name': 'b'
        }]
    }

    assert func_abi["outputs"][0] == expected

    expected['name'] = "s"
    assert func_abi["inputs"][0] == expected
Example #3
0
def test_only_init_function(source_code):
    empty_sig = [
        {"outputs": [], "inputs": [], "stateMutability": "nonpayable", "type": "constructor"}
    ]

    data = CompilerData(source_code)
    assert build_abi_output(data) == empty_sig
Example #4
0
def test_default_abi():
    default_code = """
@payable
@external
def __default__():
    pass
    """

    data = CompilerData(default_code)
    assert build_abi_output(data) == [{"stateMutability": "payable", "type": "fallback"}]
Example #5
0
def test_only_init_function(source_code):
    empty_sig = [{
        'outputs': [],
        'inputs': [],
        'constant': False,
        'payable': False,
        'type': 'constructor'
    }]

    data = CompilerData(source_code)
    assert build_abi_output(data) == empty_sig
Example #6
0
def test_default_abi():
    default_code = """
@payable
@public
def __default__():
    pass
    """

    data = CompilerData(default_code)
    assert build_abi_output(data) == [{
        'constant': False,
        'payable': True,
        'type': 'fallback'
    }]
Example #7
0
def compile_codes(
    contract_sources: ContractCodes,
    output_formats: Union[OutputDict, OutputFormats, None] = None,
    exc_handler: Union[Callable, None] = None,
    interface_codes: Union[InterfaceDict, InterfaceImports, None] = None,
    initial_id: int = 0,
) -> OrderedDict:
    """
    Generate compiler output(s) from one or more contract source codes.

    Arguments
    ---------
    contract_sources: Dict[str, str]
        Vyper source codes to be compiled. Formatted as `{"contract name": "source code"}`
    output_formats: List, optional
        List of compiler outputs to generate. Possible options are all the keys
        in `OUTPUT_FORMATS`. If not given, the deployment bytecode is generated.
    exc_handler: Callable, optional
        Callable used to handle exceptions if the compilation fails. Should accept
        two arguments - the name of the contract, and the exception that was raised
    initial_id: int, optional
        The lowest source ID value to be used when generating the source map.
    evm_version: str, optional
        The target EVM ruleset to compile for. If not given, defaults to the latest
        implemented ruleset.
    interface_codes: Dict, optional
        Interfaces that may be imported by the contracts during compilation.

        * May be a singular dictionary shared across all sources to be compiled,
          i.e. `{'interface name': "definition"}`
        * or may be organized according to contracts that are being compiled, i.e.
          `{'contract name': {'interface name': "definition"}`

        * Interface definitions are formatted as: `{'type': "json/vyper", 'code': "interface code"}`
        * JSON interfaces are given as lists, vyper interfaces as strings

    Returns
    -------
    Dict
        Compiler output as `{'contract name': {'output key': "output data"}}`
    """

    if output_formats is None:
        output_formats = ("bytecode", )
    if isinstance(output_formats, Sequence):
        output_formats = dict(
            (k, output_formats) for k in contract_sources.keys())

    out: OrderedDict = OrderedDict()
    for source_id, contract_name in enumerate(sorted(contract_sources),
                                              start=initial_id):
        # trailing newline fixes python parsing bug when source ends in a comment
        # https://bugs.python.org/issue35107
        source_code = f"{contract_sources[contract_name]}\n"
        interfaces: Any = interface_codes
        if (isinstance(interfaces, dict) and contract_name in interfaces
                and isinstance(interfaces[contract_name], dict)):
            interfaces = interfaces[contract_name]

        compiler_data = CompilerData(source_code, contract_name, interfaces,
                                     source_id)
        for output_format in output_formats[contract_name]:
            if output_format not in OUTPUT_FORMATS:
                raise ValueError(
                    f"Unsupported format type {repr(output_format)}")
            try:
                out.setdefault(contract_name, {})
                out[contract_name][output_format] = OUTPUT_FORMATS[
                    output_format](compiler_data)
            except Exception as exc:
                if exc_handler is not None:
                    exc_handler(contract_name, exc)
                else:
                    raise exc

    return out
Example #8
0
def parse_natspec(code):
    vyper_ast = CompilerData(code).vyper_module_folded
    return vy_ast.parse_natspec(vyper_ast)
Example #9
0
def compile_codes(
    contract_sources: ContractCodes,
    output_formats: Union[OutputDict, OutputFormats, None] = None,
    exc_handler: Union[Callable, None] = None,
    interface_codes: Union[InterfaceDict, InterfaceImports, None] = None,
    initial_id: int = 0,
    no_optimize: bool = False,
    storage_layouts: Dict[ContractPath, StorageLayout] = None,
    show_gas_estimates: bool = False,
) -> OrderedDict:
    """
    Generate compiler output(s) from one or more contract source codes.

    Arguments
    ---------
    contract_sources: Dict[str, str]
        Vyper source codes to be compiled. Formatted as `{"contract name": "source code"}`
    output_formats: List, optional
        List of compiler outputs to generate. Possible options are all the keys
        in `OUTPUT_FORMATS`. If not given, the deployment bytecode is generated.
    exc_handler: Callable, optional
        Callable used to handle exceptions if the compilation fails. Should accept
        two arguments - the name of the contract, and the exception that was raised
    initial_id: int, optional
        The lowest source ID value to be used when generating the source map.
    evm_version: str, optional
        The target EVM ruleset to compile for. If not given, defaults to the latest
        implemented ruleset.
    no_optimize: bool, optional
        Turn off optimizations. Defaults to False
    show_gas_estimates: bool, optional
        Show gas estimates for abi and ir output modes
    interface_codes: Dict, optional
        Interfaces that may be imported by the contracts during compilation.

        * May be a singular dictionary shared across all sources to be compiled,
          i.e. `{'interface name': "definition"}`
        * or may be organized according to contracts that are being compiled, i.e.
          `{'contract name': {'interface name': "definition"}`

        * Interface definitions are formatted as: `{'type': "json/vyper", 'code': "interface code"}`
        * JSON interfaces are given as lists, vyper interfaces as strings

    Returns
    -------
    Dict
        Compiler output as `{'contract name': {'output key': "output data"}}`
    """

    if output_formats is None:
        output_formats = ("bytecode", )
    if isinstance(output_formats, Sequence):
        output_formats = dict(
            (k, output_formats) for k in contract_sources.keys())

    out: OrderedDict = OrderedDict()
    for source_id, contract_name in enumerate(sorted(contract_sources),
                                              start=initial_id):
        source_code = contract_sources[contract_name]
        interfaces: Any = interface_codes
        storage_layout_override = None
        if storage_layouts and contract_name in storage_layouts:
            storage_layout_override = storage_layouts[contract_name]

        if (isinstance(interfaces, dict) and contract_name in interfaces
                and isinstance(interfaces[contract_name], dict)):
            interfaces = interfaces[contract_name]

        # make IR output the same between runs
        codegen.reset_names()
        compiler_data = CompilerData(
            source_code,
            contract_name,
            interfaces,
            source_id,
            no_optimize,
            storage_layout_override,
            show_gas_estimates,
        )
        for output_format in output_formats[contract_name]:
            if output_format not in OUTPUT_FORMATS:
                raise ValueError(
                    f"Unsupported format type {repr(output_format)}")
            try:
                out.setdefault(contract_name, {})
                out[contract_name][output_format] = OUTPUT_FORMATS[
                    output_format](compiler_data)
            except Exception as exc:
                if exc_handler is not None:
                    exc_handler(contract_name, exc)
                else:
                    raise exc

    return out