├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yaml
├── Dockerfile
├── FUNDING.yml
├── LICENSE
├── Makefile
├── README.md
├── SECURITY.md
├── docs
├── Makefile
├── _static
│ ├── css
│ │ ├── dark.css
│ │ └── toggle.css
│ └── js
│ │ └── toggle.js
├── _templates
│ └── versions.html
├── built-in-functions.rst
├── compiler-exceptions.rst
├── compiling-a-contract.rst
├── conf.py
├── constants-and-vars.rst
├── contributing.rst
├── control-structures.rst
├── deploying-contracts.rst
├── event-logging.rst
├── index.rst
├── installing-vyper.rst
├── interfaces.rst
├── make.bat
├── natspec.rst
├── release-notes.rst
├── resources.rst
├── scoping-and-declarations.rst
├── statements.rst
├── structure-of-a-contract.rst
├── style-guide.rst
├── testing-contracts-brownie.rst
├── testing-contracts-ethtester.rst
├── testing-contracts.rst
├── toctree.rst
├── types.rst
├── versioning.rst
├── vyper-by-example.rst
└── vyper-logo-transparent.svg
├── examples
├── auctions
│ ├── blind_auction.vy
│ └── simple_open_auction.vy
├── crowdfund.vy
├── factory
│ ├── Exchange.vy
│ └── Factory.vy
├── market_maker
│ └── on_chain_market_maker.vy
├── name_registry
│ └── name_registry.vy
├── safe_remote_purchase
│ └── safe_remote_purchase.vy
├── stock
│ └── company.vy
├── storage
│ ├── advanced_storage.vy
│ └── storage.vy
├── tokens
│ ├── ERC1155ownable.vy
│ ├── ERC20.vy
│ ├── ERC4626.vy
│ └── ERC721.vy
├── voting
│ └── ballot.vy
└── wallet
│ └── wallet.vy
├── hooks
└── build
├── images
├── curve.png
├── cyfrin.png
├── lido.png
├── unore.png
└── yearn-logo.png
├── logo
├── vyper-logo-flat.png
├── vyper-logo-flat.svg
├── vyper-logo-transparent.png
├── vyper-logo-transparent.svg
└── vyper-logo.ai
├── make.cmd
├── pyproject.toml
├── quicktest.sh
├── requirements-docs.txt
├── setup.cfg
├── setup.py
├── tests
├── __init__.py
├── ast
│ ├── nodes
│ │ ├── test_binary.py
│ │ ├── test_compare_nodes.py
│ │ ├── test_evaluate_binop_decimal.py
│ │ ├── test_evaluate_binop_int.py
│ │ ├── test_evaluate_boolop.py
│ │ ├── test_evaluate_compare.py
│ │ ├── test_evaluate_subscript.py
│ │ ├── test_evaluate_unaryop.py
│ │ ├── test_from_node.py
│ │ ├── test_get_children.py
│ │ ├── test_get_descendants.py
│ │ ├── test_hex.py
│ │ └── test_replace_in_tree.py
│ ├── test_folding.py
│ ├── test_metadata_journal.py
│ ├── test_natspec.py
│ └── test_pre_parser.py
├── base_conftest.py
├── builtins
│ └── folding
│ │ ├── test_abs.py
│ │ ├── test_addmod_mulmod.py
│ │ ├── test_bitwise.py
│ │ ├── test_epsilon.py
│ │ ├── test_floor_ceil.py
│ │ ├── test_fold_as_wei_value.py
│ │ ├── test_keccak_sha.py
│ │ ├── test_len.py
│ │ ├── test_min_max.py
│ │ └── test_powmod.py
├── cli
│ ├── outputs
│ │ ├── test_storage_layout.py
│ │ └── test_storage_layout_overrides.py
│ ├── vyper_compile
│ │ ├── test_compile_files.py
│ │ ├── test_import_paths.py
│ │ └── test_parse_args.py
│ └── vyper_json
│ │ ├── test_compile_from_input_dict.py
│ │ ├── test_compile_json.py
│ │ ├── test_get_contracts.py
│ │ ├── test_get_settings.py
│ │ ├── test_interfaces.py
│ │ ├── test_output_dict.py
│ │ ├── test_output_selection.py
│ │ └── test_parse_args_vyperjson.py
├── compiler
│ ├── __init__.py
│ ├── asm
│ │ └── test_asm_optimizer.py
│ ├── ir
│ │ ├── __init__.py
│ │ ├── test_compile_ir.py
│ │ ├── test_optimize_ir.py
│ │ ├── test_repeat.py
│ │ └── test_with.py
│ ├── test_bytecode_runtime.py
│ ├── test_calldatacopy.py
│ ├── test_compile_code.py
│ ├── test_default_settings.py
│ ├── test_opcodes.py
│ ├── test_pre_parser.py
│ ├── test_sha3_32.py
│ └── test_source_map.py
├── conftest.py
├── examples
│ ├── auctions
│ │ ├── test_blind_auction.py
│ │ └── test_simple_open_auction.py
│ ├── company
│ │ └── test_company.py
│ ├── conftest.py
│ ├── crowdfund
│ │ └── test_crowdfund_example.py
│ ├── factory
│ │ └── test_factory.py
│ ├── market_maker
│ │ └── test_on_chain_market_maker.py
│ ├── name_registry
│ │ └── test_name_registry.py
│ ├── safe_remote_purchase
│ │ └── test_safe_remote_purchase.py
│ ├── storage
│ │ ├── test_advanced_storage.py
│ │ └── test_storage.py
│ ├── tokens
│ │ ├── test_erc1155.py
│ │ ├── test_erc20.py
│ │ ├── test_erc4626.py
│ │ └── test_erc721.py
│ ├── voting
│ │ └── test_ballot.py
│ └── wallet
│ │ └── test_wallet.py
├── fixtures
│ ├── __init__.py
│ └── memorymock.py
├── functional
│ ├── codegen
│ │ ├── test_struct_return.py
│ │ └── test_tuple_return.py
│ ├── semantics
│ │ ├── analysis
│ │ │ ├── test_array_index.py
│ │ │ ├── test_cyclic_function_calls.py
│ │ │ ├── test_for_loop.py
│ │ │ └── test_potential_types.py
│ │ ├── conftest.py
│ │ ├── test_namespace.py
│ │ └── types
│ │ │ ├── test_event.py
│ │ │ ├── test_pure_types.py
│ │ │ ├── test_size_in_bytes.py
│ │ │ ├── test_type_from_abi.py
│ │ │ └── test_type_from_annotation.py
│ └── test_storage_slots.py
├── fuzzing
│ └── test_exponents.py
├── grammar
│ └── test_grammar.py
├── parser
│ ├── ast_utils
│ │ ├── test_ast.py
│ │ └── test_ast_dict.py
│ ├── exceptions
│ │ ├── __init__.py
│ │ ├── test_argument_exception.py
│ │ ├── test_call_violation.py
│ │ ├── test_constancy_exception.py
│ │ ├── test_function_declaration_exception.py
│ │ ├── test_instantiation_exception.py
│ │ ├── test_invalid_literal_exception.py
│ │ ├── test_invalid_payable.py
│ │ ├── test_invalid_reference.py
│ │ ├── test_invalid_type_exception.py
│ │ ├── test_namespace_collision.py
│ │ ├── test_overflow_exception.py
│ │ ├── test_structure_exception.py
│ │ ├── test_syntax_exception.py
│ │ ├── test_type_mismatch_exception.py
│ │ ├── test_undeclared_definition.py
│ │ ├── test_variable_declaration_exception.py
│ │ └── test_vyper_exception_pos.py
│ ├── features
│ │ ├── arithmetic
│ │ │ ├── test_division.py
│ │ │ └── test_modulo.py
│ │ ├── decorators
│ │ │ ├── test_nonreentrant.py
│ │ │ ├── test_payable.py
│ │ │ ├── test_private.py
│ │ │ ├── test_public.py
│ │ │ ├── test_pure.py
│ │ │ └── test_view.py
│ │ ├── external_contracts
│ │ │ ├── test_erc20_abi.py
│ │ │ ├── test_external_contract_calls.py
│ │ │ ├── test_modifiable_external_contract_calls.py
│ │ │ └── test_self_call_struct.py
│ │ ├── iteration
│ │ │ ├── test_break.py
│ │ │ ├── test_continue.py
│ │ │ ├── test_for_in_list.py
│ │ │ ├── test_for_range.py
│ │ │ └── test_range_in.py
│ │ ├── test_address_balance.py
│ │ ├── test_assert.py
│ │ ├── test_assert_unreachable.py
│ │ ├── test_assignment.py
│ │ ├── test_bytes_map_keys.py
│ │ ├── test_clampers.py
│ │ ├── test_comments.py
│ │ ├── test_comparison.py
│ │ ├── test_conditionals.py
│ │ ├── test_constructor.py
│ │ ├── test_gas.py
│ │ ├── test_immutable.py
│ │ ├── test_init.py
│ │ ├── test_internal_call.py
│ │ ├── test_logging.py
│ │ ├── test_logging_bytes_extended.py
│ │ ├── test_logging_from_call.py
│ │ ├── test_memory_dealloc.py
│ │ ├── test_packing.py
│ │ ├── test_reverting.py
│ │ ├── test_short_circuiting.py
│ │ ├── test_string_map_keys.py
│ │ ├── test_ternary.py
│ │ └── test_transient.py
│ ├── functions
│ │ ├── __init__.py
│ │ ├── test_abi.py
│ │ ├── test_abi_decode.py
│ │ ├── test_abi_encode.py
│ │ ├── test_addmod.py
│ │ ├── test_as_wei_value.py
│ │ ├── test_bitwise.py
│ │ ├── test_block.py
│ │ ├── test_block_number.py
│ │ ├── test_ceil.py
│ │ ├── test_concat.py
│ │ ├── test_convert.py
│ │ ├── test_create_functions.py
│ │ ├── test_default_function.py
│ │ ├── test_default_parameters.py
│ │ ├── test_ec.py
│ │ ├── test_ecrecover.py
│ │ ├── test_empty.py
│ │ ├── test_extract32.py
│ │ ├── test_floor.py
│ │ ├── test_interfaces.py
│ │ ├── test_is_contract.py
│ │ ├── test_keccak256.py
│ │ ├── test_length.py
│ │ ├── test_method_id.py
│ │ ├── test_minmax.py
│ │ ├── test_minmax_value.py
│ │ ├── test_mkstr.py
│ │ ├── test_mulmod.py
│ │ ├── test_raw_call.py
│ │ ├── test_return.py
│ │ ├── test_return_struct.py
│ │ ├── test_return_tuple.py
│ │ ├── test_send.py
│ │ ├── test_sha256.py
│ │ ├── test_slice.py
│ │ ├── test_tx.py
│ │ ├── test_unary.py
│ │ └── test_unsafe_math.py
│ ├── globals
│ │ ├── test_getters.py
│ │ ├── test_globals.py
│ │ └── test_setters.py
│ ├── integration
│ │ ├── test_basics.py
│ │ ├── test_crowdfund.py
│ │ └── test_escrow.py
│ ├── parser_utils
│ │ └── test_annotate_and_optimize_ast.py
│ ├── syntax
│ │ ├── __init__.py
│ │ ├── test_abi_encode.py
│ │ ├── test_addmulmod.py
│ │ ├── test_address_code.py
│ │ ├── test_ann_assign.py
│ │ ├── test_as_uint256.py
│ │ ├── test_as_wei_value.py
│ │ ├── test_block.py
│ │ ├── test_blockscope.py
│ │ ├── test_bool.py
│ │ ├── test_bool_ops.py
│ │ ├── test_bytes.py
│ │ ├── test_chainid.py
│ │ ├── test_code_size.py
│ │ ├── test_codehash.py
│ │ ├── test_concat.py
│ │ ├── test_conditionals.py
│ │ ├── test_constants.py
│ │ ├── test_create_with_code_of.py
│ │ ├── test_dynamic_array.py
│ │ ├── test_enum.py
│ │ ├── test_extract32.py
│ │ ├── test_for_range.py
│ │ ├── test_functions_call.py
│ │ ├── test_immutables.py
│ │ ├── test_interfaces.py
│ │ ├── test_invalids.py
│ │ ├── test_keccak256.py
│ │ ├── test_len.py
│ │ ├── test_list.py
│ │ ├── test_logging.py
│ │ ├── test_minmax.py
│ │ ├── test_minmax_value.py
│ │ ├── test_msg_data.py
│ │ ├── test_nested_list.py
│ │ ├── test_no_none.py
│ │ ├── test_print.py
│ │ ├── test_public.py
│ │ ├── test_raw_call.py
│ │ ├── test_return_tuple.py
│ │ ├── test_self_balance.py
│ │ ├── test_selfdestruct.py
│ │ ├── test_send.py
│ │ ├── test_slice.py
│ │ ├── test_string.py
│ │ ├── test_structs.py
│ │ ├── test_ternary.py
│ │ ├── test_tuple_assign.py
│ │ ├── test_unbalanced_return.py
│ │ └── utils
│ │ │ ├── test_event_names.py
│ │ │ ├── test_function_names.py
│ │ │ └── test_variable_names.py
│ ├── test_call_graph_stability.py
│ ├── test_selector_table.py
│ └── types
│ │ ├── numbers
│ │ ├── test_constants.py
│ │ ├── test_decimals.py
│ │ ├── test_isqrt.py
│ │ ├── test_signed_ints.py
│ │ ├── test_sqrt.py
│ │ └── test_unsigned_ints.py
│ │ ├── test_bytes.py
│ │ ├── test_bytes_literal.py
│ │ ├── test_bytes_zero_padding.py
│ │ ├── test_dynamic_array.py
│ │ ├── test_enum.py
│ │ ├── test_identifier_naming.py
│ │ ├── test_lists.py
│ │ ├── test_node_types.py
│ │ ├── test_string.py
│ │ ├── test_string_literal.py
│ │ └── value
│ │ └── test_as_wei_value.py
├── signatures
│ ├── test_invalid_function_decorators.py
│ └── test_method_id_conflicts.py
└── test_utils.py
├── tox.ini
└── vyper
├── __init__.py
├── __main__.py
├── abi_types.py
├── ast
├── README.md
├── __init__.py
├── __init__.pyi
├── annotation.py
├── expansion.py
├── folding.py
├── grammar.lark
├── grammar.py
├── metadata.py
├── natspec.py
├── nodes.py
├── nodes.pyi
├── pre_parser.py
├── utils.py
└── validation.py
├── builtins
├── __init__.py
├── _convert.py
├── _signatures.py
├── _utils.py
├── functions.py
└── interfaces
│ ├── ERC165.py
│ ├── ERC20.py
│ ├── ERC20Detailed.py
│ ├── ERC4626.py
│ ├── ERC721.py
│ └── __init__.py
├── cli
├── __init__.py
├── utils.py
├── vyper_compile.py
├── vyper_ir.py
├── vyper_json.py
└── vyper_serve.py
├── codegen
├── __init__.py
├── abi_encoder.py
├── arithmetic.py
├── context.py
├── core.py
├── events.py
├── expr.py
├── external_call.py
├── function_definitions
│ ├── __init__.py
│ ├── common.py
│ ├── external_function.py
│ ├── internal_function.py
│ └── utils.py
├── global_context.py
├── ir_node.py
├── jumptable_utils.py
├── keccak256_helper.py
├── memory_allocator.py
├── module.py
├── return_.py
├── self_call.py
└── stmt.py
├── compiler
├── README.md
├── __init__.py
├── output.py
├── phases.py
├── settings.py
└── utils.py
├── evm
├── __init__.py
├── address_space.py
└── opcodes.py
├── exceptions.py
├── ir
├── README.md
├── __init__.py
├── compile_ir.py
├── optimizer.py
└── s_expressions.py
├── semantics
├── README.md
├── __init__.py
├── analysis
│ ├── __init__.py
│ ├── annotation.py
│ ├── base.py
│ ├── common.py
│ ├── data_positions.py
│ ├── levenshtein_utils.py
│ ├── local.py
│ ├── module.py
│ └── utils.py
├── data_locations.py
├── environment.py
├── namespace.py
└── types
│ ├── __init__.py
│ ├── base.py
│ ├── bytestrings.py
│ ├── function.py
│ ├── primitives.py
│ ├── shortcuts.py
│ ├── subscriptable.py
│ ├── user.py
│ └── utils.py
├── typing.py
├── utils.py
└── warnings.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # egg-related
7 | build/
8 | .eggs/
9 | dist/
10 | vyper.egg-info/
11 |
12 | .pytest_cache/
13 |
14 | # pyenv
15 | .python-version
16 |
17 | # dotenv
18 | .env
19 |
20 | # virtualenv
21 | .venv/
22 | venv/
23 | ENV/
24 |
25 | # Coverage tests
26 | .coverage*
27 | .cache/
28 | htmlcov/
29 | coverage.xml
30 |
31 | # sphinx
32 | docs/_build/
33 | docs/modules.rst
34 | docs/vyper.rst
35 | docs/vyper.*.rst
36 |
37 | # IDEs
38 | .idea/
39 | .vscode/
40 |
41 | .tox/
42 | .mypy_cache/
43 | .hypothesis/
44 |
45 | # vyper
46 | vyper/version.py
47 | vyper/vyper_git_version.txt
48 | vyper/vyper_git_commithash.txt
49 | *.spec
50 |
51 | # mac
52 | .DS_Store
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/pycqa/isort
3 | rev: 5.9.3
4 | hooks:
5 | - id: isort
6 | name: isort
7 |
8 | - repo: https://github.com/psf/black
9 | rev: 21.9b0
10 | hooks:
11 | - id: black
12 | name: black
13 |
14 | - repo: https://github.com/PyCQA/flake8
15 | rev: 3.9.2
16 | hooks:
17 | - id: flake8
18 |
19 | - repo: https://github.com/pre-commit/mirrors-mypy
20 | rev: v0.910
21 | hooks:
22 | - id: mypy
23 | additional_dependencies:
24 | - "types-setuptools"
25 |
26 | default_language_version:
27 | python: python3.10
28 |
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | # File: .readthedocs.yaml
2 |
3 | version: 2
4 |
5 | # Set the version of Python and other tools you might need
6 | build:
7 | # TODO: update to `latest` once supported
8 | # https://github.com/readthedocs/readthedocs.org/issues/8861
9 | os: ubuntu-22.04
10 | tools:
11 | python: "3.10"
12 |
13 | # Build from the docs/ directory with Sphinx
14 | sphinx:
15 | configuration: docs/conf.py
16 |
17 | formats: all
18 |
19 |
20 | # Optionally declare the Python requirements required to build your docs
21 | python:
22 | install:
23 | - requirements: requirements-docs.txt
24 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.11-slim
2 |
3 | # Specify label-schema specific arguments and labels.
4 | ARG BUILD_DATE
5 | ARG VCS_REF
6 | LABEL org.label-schema.build-date=$BUILD_DATE \
7 | org.label-schema.name="Vyper" \
8 | org.label-schema.description="Vyper is an experimental programming language" \
9 | org.label-schema.url="https://vyper.readthedocs.io/en/latest/" \
10 | org.label-schema.vcs-ref=$VCS_REF \
11 | org.label-schema.vcs-url="https://github.com/vyperlang/vyper" \
12 | org.label-schema.vendor="Vyper Team" \
13 | org.label-schema.schema-version="1.0"
14 |
15 | # coincurve requires libgmp
16 | RUN apt-get update && \
17 | apt-get install -y --no-install-recommends \
18 | apt-utils \
19 | gcc \
20 | git \
21 | libc6-dev \
22 | libc-dev \
23 | libssl-dev \
24 | libgmp-dev \
25 | && rm -rf /var/lib/apt/lists/*
26 |
27 | ADD . /code
28 |
29 | WORKDIR /code
30 |
31 | # force repository to be clean so the version string is right
32 | RUN git reset --hard
33 |
34 | # Using "test" optional to include test dependencies in built docker-image
35 | RUN pip install --no-cache-dir .[test] && \
36 | apt-get purge -y --auto-remove apt-utils gcc libc6-dev libc-dev libssl-dev
37 |
38 | ENTRYPOINT ["/usr/local/bin/vyper"]
39 |
--------------------------------------------------------------------------------
/FUNDING.yml:
--------------------------------------------------------------------------------
1 | custom: https://gitcoin.co/grants/200/vyper-smart-contract-language-2
2 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | SHELL := /bin/bash
2 |
3 | ifeq (, $(shell which pip3))
4 | pip := $(shell which pip3)
5 | else
6 | pip := $(shell which pip)
7 | endif
8 |
9 | .PHONY: test dev-deps lint clean clean-pyc clean-build clean-test docs
10 |
11 | init:
12 | python setup.py install
13 |
14 | dev-init:
15 | ${pip} install .[dev]
16 |
17 | test:
18 | pytest
19 |
20 | mypy:
21 | tox -e mypy
22 |
23 | lint:
24 | tox -e lint
25 |
26 | docs:
27 | rm -f docs/vyper.rst
28 | rm -f docs/modules.rst
29 | sphinx-apidoc -o docs/ -d 2 vyper/
30 | $(MAKE) -C docs clean
31 | $(MAKE) -C docs html
32 | # To display docs, run:
33 | # open docs/_build/html/index.html (macOS)
34 | # start docs/_build/html/index.html (Windows)
35 | # xdg-open docs/_build/html/index.html (Linux)
36 |
37 | release: clean
38 | python setup.py sdist bdist_wheel
39 | twine check dist/*
40 | #twine upload dist/*
41 |
42 | freeze: clean init
43 | echo Generating binary...
44 | export OS="$$(uname -s | tr A-Z a-z)" && \
45 | export VERSION="$$(PYTHONPATH=. python vyper/cli/vyper_compile.py --version)" && \
46 | pyinstaller --target-architecture=universal2 --clean --onefile vyper/cli/vyper_compile.py --name "vyper.$${VERSION}.$${OS}" --add-data vyper:vyper
47 |
48 | clean: clean-build clean-docs clean-pyc clean-test
49 |
50 | clean-build:
51 | @echo Cleaning python build files...
52 | @rm -fr build/
53 | @rm -fr _build/ # docs build dir
54 | @rm -fr dist/
55 | @rm -fr *.egg-info
56 | @rm -f vyper/version.py vyper/vyper_git_version.txt vyper/vyper_git_commithash.txt
57 | @rm -f *.spec
58 |
59 | clean-docs:
60 | @echo Cleaning doc build files...
61 | @rm -rf docs/_build/
62 | @rm -f docs/modules.rst
63 | @rm -f docs/vyper.rst
64 | @rm -f docs/vyper.*.rst
65 |
66 | clean-pyc:
67 | @echo Cleaning python files...
68 | @find . -name '*.pyc' -exec rm -f {} +
69 | @find . -name '*.pyo' -exec rm -f {} +
70 | @find . -name '*~' -exec rm -f {} +
71 | @find . -name '__pycache__' -exec rmdir {} +
72 |
73 | clean-test:
74 | @echo Cleaning test files...
75 | @find . -name 'htmlcov' -exec rm -rf {} +
76 | @rm -fr coverage.xml
77 | @rm -fr .coverage
78 | @rm -fr .eggs/
79 | @rm -fr .hypothesis/
80 | @rm -fr .pytest_cache/
81 | @rm -rf .tox/
82 | @rm -fr .mypy_cache/
83 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = python -msphinx
7 | SPHINXPROJ = Vyper
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
--------------------------------------------------------------------------------
/docs/_static/css/toggle.css:
--------------------------------------------------------------------------------
1 | input[type=checkbox] {
2 | visibility: hidden;
3 | height: 0;
4 | width: 0;
5 | margin: 0;
6 | }
7 |
8 | .rst-versions .rst-current-version {
9 | padding: 10px;
10 | display: flex;
11 | justify-content: space-between;
12 | }
13 |
14 | .rst-versions .rst-current-version .fa-book,
15 | .rst-versions .rst-current-version .fa-v,
16 | .rst-versions .rst-current-version .fa-caret-down {
17 | height: 24px;
18 | line-height: 24px;
19 | vertical-align: middle;
20 | }
21 |
22 | .rst-versions .rst-current-version .fa-element {
23 | width: 80px;
24 | text-align: center;
25 | }
26 |
27 | .rst-versions .rst-current-version .fa-book {
28 | text-align: left;
29 | }
30 |
31 | .rst-versions .rst-current-version .fa-v {
32 | color: #27AE60;
33 | text-align: right;
34 | }
35 |
36 | label {
37 | margin: 0 auto;
38 | display: inline-block;
39 | justify-content: center;
40 | align-items: right;
41 | border-radius: 100px;
42 | position: relative;
43 | cursor: pointer;
44 | text-indent: -9999px;
45 | width: 50px;
46 | height: 21px;
47 | background: #000;
48 | }
49 |
50 | label:after {
51 | border-radius: 50%;
52 | position: absolute;
53 | content: '';
54 | background: #fff;
55 | width: 15px;
56 | height: 15px;
57 | top: 3px;
58 | left: 3px;
59 | transition: ease-in-out 200ms;
60 | }
61 |
62 | input:checked+label {
63 | background: #3a7ca8;
64 | }
65 |
66 | input:checked+label:after {
67 | left: calc(100% - 5px);
68 | transform: translateX(-100%);
69 | }
70 |
71 | html.transition,
72 | html.transition *,
73 | html.transition *:before,
74 | html.transition *:after {
75 | transition: ease-in-out 200ms !important;
76 | transition-delay: 0 !important;
77 | }
--------------------------------------------------------------------------------
/docs/_static/js/toggle.js:
--------------------------------------------------------------------------------
1 | document.addEventListener('DOMContentLoaded', function() {
2 |
3 | var checkbox = document.querySelector('input[name=mode]');
4 |
5 | function toggleCssMode(isDay) {
6 | var mode = (isDay ? "Day" : "Night");
7 | localStorage.setItem("css-mode", mode);
8 |
9 | var darksheet = $('link[href="_static/css/dark.css"]')[0].sheet;
10 | darksheet.disabled = isDay;
11 | }
12 |
13 | if (localStorage.getItem("css-mode") == "Day") {
14 | toggleCssMode(true);
15 | checkbox.setAttribute('checked', true);
16 | }
17 |
18 | checkbox.addEventListener('change', function() {
19 | document.documentElement.classList.add('transition');
20 | window.setTimeout(() => {
21 | document.documentElement.classList.remove('transition');
22 | }, 1000)
23 | toggleCssMode(this.checked);
24 | })
25 |
26 | });
--------------------------------------------------------------------------------
/docs/_templates/versions.html:
--------------------------------------------------------------------------------
1 | {# Add rst-badge after rst-versions for small badge style. #}
2 |
3 |
4 | RTD
5 |
6 |
7 |
8 |
9 |
10 |
11 | v: {{ current_version }}
12 |
13 |
14 |
15 |
16 | - {{ _('Versions') }}
{% for slug, url in versions %}
17 | - {{ slug }}
18 | {% endfor %}
19 |
20 |
21 | - {{ _('Downloads') }}
{% for type, url in downloads %}
22 | - {{ type }}
23 | {% endfor %}
24 |
25 |
26 | {# Translators: The phrase "Read the Docs" is not translated #}
27 | - {{ _('On Read the Docs') }}
28 | -
29 | {{ _('Project Home') }}
30 |
31 | -
32 | {{ _('Builds') }}
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/docs/deploying-contracts.rst:
--------------------------------------------------------------------------------
1 | .. index:: deploying;deploying;
2 |
3 | .. _deploying:
4 |
5 | Deploying a Contract
6 | ********************
7 |
8 | Once you are ready to deploy your contract to a public test net or the main net, you have several options:
9 |
10 | * Take the bytecode generated by the vyper compiler and manually deploy it through mist or geth:
11 |
12 | .. code-block:: bash
13 |
14 | vyper yourFileName.vy
15 | # returns bytecode
16 |
17 | * Take the byte code and ABI and deploy it with your current browser on `myetherwallet's `_ contract menu:
18 |
19 | .. code-block:: bash
20 |
21 | vyper -f abi yourFileName.vy
22 | # returns ABI
23 |
24 | * Use the remote compiler provided by the `Remix IDE `_ to compile and deploy your contract on your net of choice. Remix also provides a JavaScript VM to test deploy your contract.
25 |
26 | .. note::
27 | While the vyper version of the Remix IDE compiler is updated on a regular basis it might be a bit behind the latest version found in the master branch of the repository. Make sure the byte code matches the output from your local compiler.
28 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=python -msphinx
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 | set SPHINXPROJ=Vyper
13 |
14 | if "%1" == "" goto help
15 |
16 | %SPHINXBUILD% >NUL 2>NUL
17 | if errorlevel 9009 (
18 | echo.
19 | echo.The Sphinx module was not found. Make sure you have Sphinx installed,
20 | echo.then set the SPHINXBUILD environment variable to point to the full
21 | echo.path of the 'sphinx-build' executable. Alternatively you may add the
22 | echo.Sphinx directory to PATH.
23 | echo.
24 | echo.If you don't have Sphinx installed, grab it from
25 | echo.http://sphinx-doc.org/
26 | exit /b 1
27 | )
28 |
29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
30 | goto end
31 |
32 | :help
33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
34 |
35 | :end
36 | popd
37 |
--------------------------------------------------------------------------------
/docs/testing-contracts.rst:
--------------------------------------------------------------------------------
1 | .. _testing-contracts:
2 |
3 | Testing a Contract
4 | ##################
5 |
6 | For testing Vyper contracts we recommend the use of `pytest `_ along with one of the following packages:
7 |
8 | * `Brownie `_: A development and testing framework for smart contracts targeting the Ethereum Virtual Machine
9 | * `Ethereum Tester `_: A tool suite for testing ethereum applications
10 |
11 | Example usage for each package is provided in the sections listed below.
12 |
13 | .. toctree::
14 | :maxdepth: 2
15 |
16 | testing-contracts-brownie.rst
17 | testing-contracts-ethtester.rst
18 |
--------------------------------------------------------------------------------
/docs/toctree.rst:
--------------------------------------------------------------------------------
1 | =====
2 | Vyper
3 | =====
4 |
5 | .. toctree::
6 | :maxdepth: 2
7 |
8 | Overview
9 |
10 | .. toctree::
11 | :caption: Getting Started
12 | :maxdepth: 2
13 |
14 | installing-vyper.rst
15 | vyper-by-example.rst
16 |
17 | .. toctree::
18 | :caption: Language Description
19 | :maxdepth: 2
20 |
21 | structure-of-a-contract.rst
22 | types.rst
23 | constants-and-vars.rst
24 | statements.rst
25 | control-structures.rst
26 | scoping-and-declarations.rst
27 | built-in-functions.rst
28 | interfaces.rst
29 | event-logging.rst
30 | natspec.rst
31 |
32 | .. toctree::
33 | :caption: Using the Compiler
34 | :maxdepth: 2
35 |
36 | compiling-a-contract.rst
37 | compiler-exceptions.rst
38 | deploying-contracts.rst
39 | testing-contracts.rst
40 |
41 | .. toctree::
42 | :caption: Additional Resources
43 | :maxdepth: 2
44 |
45 | resources
46 | release-notes.rst
47 | contributing.rst
48 | style-guide.rst
49 | versioning.rst
50 |
--------------------------------------------------------------------------------
/docs/vyper-logo-transparent.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/examples/crowdfund.vy:
--------------------------------------------------------------------------------
1 | # Setup private variables (only callable from within the contract)
2 |
3 | funders: HashMap[address, uint256]
4 | beneficiary: address
5 | deadline: public(uint256)
6 | goal: public(uint256)
7 | timelimit: public(uint256)
8 |
9 | # Setup global variables
10 | @external
11 | def __init__(_beneficiary: address, _goal: uint256, _timelimit: uint256):
12 | self.beneficiary = _beneficiary
13 | self.deadline = block.timestamp + _timelimit
14 | self.timelimit = _timelimit
15 | self.goal = _goal
16 |
17 | # Participate in this crowdfunding campaign
18 | @external
19 | @payable
20 | def participate():
21 | assert block.timestamp < self.deadline, "deadline not met (yet)"
22 |
23 | self.funders[msg.sender] += msg.value
24 |
25 | # Enough money was raised! Send funds to the beneficiary
26 | @external
27 | def finalize():
28 | assert block.timestamp >= self.deadline, "deadline has passed"
29 | assert self.balance >= self.goal, "the goal has not been reached"
30 |
31 | selfdestruct(self.beneficiary)
32 |
33 | # Let participants withdraw their fund
34 | @external
35 | def refund():
36 | assert block.timestamp >= self.deadline and self.balance < self.goal
37 | assert self.funders[msg.sender] > 0
38 |
39 | value: uint256 = self.funders[msg.sender]
40 | self.funders[msg.sender] = 0
41 |
42 | send(msg.sender, value)
43 |
--------------------------------------------------------------------------------
/examples/factory/Exchange.vy:
--------------------------------------------------------------------------------
1 | from vyper.interfaces import ERC20
2 |
3 |
4 | interface Factory:
5 | def register(): nonpayable
6 |
7 |
8 | token: public(ERC20)
9 | factory: Factory
10 |
11 |
12 | @external
13 | def __init__(_token: ERC20, _factory: Factory):
14 | self.token = _token
15 | self.factory = _factory
16 |
17 |
18 | @external
19 | def initialize():
20 | # Anyone can safely call this function because of EXTCODEHASH
21 | self.factory.register()
22 |
23 |
24 | # NOTE: This contract restricts trading to only be done by the factory.
25 | # A practical implementation would probably want counter-pairs
26 | # and liquidity management features for each exchange pool.
27 |
28 |
29 | @external
30 | def receive(_from: address, _amt: uint256):
31 | assert msg.sender == self.factory.address
32 | success: bool = self.token.transferFrom(_from, self, _amt)
33 | assert success
34 |
35 |
36 | @external
37 | def transfer(_to: address, _amt: uint256):
38 | assert msg.sender == self.factory.address
39 | success: bool = self.token.transfer(_to, _amt)
40 | assert success
41 |
--------------------------------------------------------------------------------
/examples/factory/Factory.vy:
--------------------------------------------------------------------------------
1 | from vyper.interfaces import ERC20
2 |
3 | interface Exchange:
4 | def token() -> ERC20: view
5 | def receive(_from: address, _amt: uint256): nonpayable
6 | def transfer(_to: address, _amt: uint256): nonpayable
7 |
8 |
9 | exchange_codehash: public(bytes32)
10 | # Maps token addresses to exchange addresses
11 | exchanges: public(HashMap[ERC20, Exchange])
12 |
13 |
14 | @external
15 | def __init__(_exchange_codehash: bytes32):
16 | # Register the exchange code hash during deployment of the factory
17 | self.exchange_codehash = _exchange_codehash
18 |
19 |
20 | # NOTE: Could implement fancier upgrade logic around self.exchange_codehash
21 | # For example, allowing the deployer of this contract to change this
22 | # value allows them to use a new contract if the old one has an issue.
23 | # This would trigger a cascade effect across all exchanges that would
24 | # need to be handled appropiately.
25 |
26 |
27 | @external
28 | def register():
29 | # Verify code hash is the exchange's code hash
30 | assert msg.sender.codehash == self.exchange_codehash
31 | # Save a lookup for the exchange
32 | # NOTE: Use exchange's token address because it should be globally unique
33 | # NOTE: Should do checks that it hasn't already been set,
34 | # which has to be rectified with any upgrade strategy.
35 | exchange: Exchange = Exchange(msg.sender)
36 | self.exchanges[exchange.token()] = exchange
37 |
38 |
39 | @external
40 | def trade(_token1: ERC20, _token2: ERC20, _amt: uint256):
41 | # Perform a straight exchange of token1 to token 2 (1:1 price)
42 | # NOTE: Any practical implementation would need to solve the price oracle problem
43 | self.exchanges[_token1].receive(msg.sender, _amt)
44 | self.exchanges[_token2].transfer(msg.sender, _amt)
45 |
--------------------------------------------------------------------------------
/examples/market_maker/on_chain_market_maker.vy:
--------------------------------------------------------------------------------
1 | from vyper.interfaces import ERC20
2 |
3 |
4 | totalEthQty: public(uint256)
5 | totalTokenQty: public(uint256)
6 | # Constant set in `initiate` that's used to calculate
7 | # the amount of ether/tokens that are exchanged
8 | invariant: public(uint256)
9 | token_address: ERC20
10 | owner: public(address)
11 |
12 | # Sets the on chain market maker with its owner, intial token quantity,
13 | # and initial ether quantity
14 | @external
15 | @payable
16 | def initiate(token_addr: address, token_quantity: uint256):
17 | assert self.invariant == 0
18 | self.token_address = ERC20(token_addr)
19 | self.token_address.transferFrom(msg.sender, self, token_quantity)
20 | self.owner = msg.sender
21 | self.totalEthQty = msg.value
22 | self.totalTokenQty = token_quantity
23 | self.invariant = msg.value * token_quantity
24 | assert self.invariant > 0
25 |
26 | # Sells ether to the contract in exchange for tokens (minus a fee)
27 | @external
28 | @payable
29 | def ethToTokens():
30 | fee: uint256 = msg.value / 500
31 | eth_in_purchase: uint256 = msg.value - fee
32 | new_total_eth: uint256 = self.totalEthQty + eth_in_purchase
33 | new_total_tokens: uint256 = self.invariant / new_total_eth
34 | self.token_address.transfer(msg.sender, self.totalTokenQty - new_total_tokens)
35 | self.totalEthQty = new_total_eth
36 | self.totalTokenQty = new_total_tokens
37 |
38 | # Sells tokens to the contract in exchange for ether
39 | @external
40 | def tokensToEth(sell_quantity: uint256):
41 | self.token_address.transferFrom(msg.sender, self, sell_quantity)
42 | new_total_tokens: uint256 = self.totalTokenQty + sell_quantity
43 | new_total_eth: uint256 = self.invariant / new_total_tokens
44 | eth_to_send: uint256 = self.totalEthQty - new_total_eth
45 | send(msg.sender, eth_to_send)
46 | self.totalEthQty = new_total_eth
47 | self.totalTokenQty = new_total_tokens
48 |
49 | # Owner can withdraw their funds and destroy the market maker
50 | @external
51 | def ownerWithdraw():
52 | assert self.owner == msg.sender
53 | self.token_address.transfer(self.owner, self.totalTokenQty)
54 | selfdestruct(self.owner)
55 |
--------------------------------------------------------------------------------
/examples/name_registry/name_registry.vy:
--------------------------------------------------------------------------------
1 |
2 | registry: HashMap[Bytes[100], address]
3 |
4 | @external
5 | def register(name: Bytes[100], owner: address):
6 | assert self.registry[name] == empty(address) # check name has not been set yet.
7 | self.registry[name] = owner
8 |
9 |
10 | @view
11 | @external
12 | def lookup(name: Bytes[100]) -> address:
13 | return self.registry[name]
14 |
--------------------------------------------------------------------------------
/examples/storage/advanced_storage.vy:
--------------------------------------------------------------------------------
1 | event DataChange:
2 | setter: indexed(address)
3 | value: int128
4 |
5 | storedData: public(int128)
6 |
7 | @external
8 | def __init__(_x: int128):
9 | self.storedData = _x
10 |
11 | @external
12 | def set(_x: int128):
13 | assert _x >= 0, "No negative values"
14 | assert self.storedData < 100, "Storage is locked when 100 or more is stored"
15 | self.storedData = _x
16 | log DataChange(msg.sender, _x)
17 |
18 | @external
19 | def reset():
20 | self.storedData = 0
21 |
--------------------------------------------------------------------------------
/examples/storage/storage.vy:
--------------------------------------------------------------------------------
1 | storedData: public(int128)
2 |
3 | @external
4 | def __init__(_x: int128):
5 | self.storedData = _x
6 |
7 | @external
8 | def set(_x: int128):
9 | self.storedData = _x
--------------------------------------------------------------------------------
/hooks/build:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # DockerHub automated build override
4 |
5 | # $IMAGE_NAME var is injected into the build so the tag is correct.
6 | docker build \
7 | --build-arg VCS_REF=`git rev-parse --short HEAD` \
8 | --build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \
9 | -t $IMAGE_NAME .
10 |
--------------------------------------------------------------------------------
/images/curve.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/images/curve.png
--------------------------------------------------------------------------------
/images/cyfrin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/images/cyfrin.png
--------------------------------------------------------------------------------
/images/lido.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/images/lido.png
--------------------------------------------------------------------------------
/images/unore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/images/unore.png
--------------------------------------------------------------------------------
/images/yearn-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/images/yearn-logo.png
--------------------------------------------------------------------------------
/logo/vyper-logo-flat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/logo/vyper-logo-flat.png
--------------------------------------------------------------------------------
/logo/vyper-logo-flat.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/logo/vyper-logo-transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/logo/vyper-logo-transparent.png
--------------------------------------------------------------------------------
/logo/vyper-logo-transparent.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/logo/vyper-logo.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/logo/vyper-logo.ai
--------------------------------------------------------------------------------
/make.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 | if "%1"=="init" goto :init
3 | if "%1"=="test" goto :test
4 | if "%1"=="dev-deps" goto :dev-deps
5 | if "%1"=="lint" goto :lint
6 | if "%1"=="docs" goto :docs
7 | if "%1"=="freeze" goto :freeze
8 | if "%1"=="clean" goto :clean
9 | if "%1"=="clean-build" goto :clean-build
10 | if "%1"=="clean-pyc" goto :clean-pyc
11 | if "%1"=="clean-test" goto :clean-test
12 | rem Default
13 | if "%1"=="" goto :init
14 |
15 | :error
16 | echo Unknown parameters: %*
17 | echo Expected: init test lint clean clean-pyc clean-build clean-test docs
18 | rem echo Expect: test lint clean clean-pyc clean-build clean-test docs docker-build
19 | goto :end
20 |
21 | :init
22 | python setup.py install
23 | goto :end
24 |
25 | :test
26 | python setup.py test
27 | goto :end
28 |
29 | :dev-deps
30 | python -m pip install .[test,lint]
31 | goto :end
32 |
33 | :lint
34 | tox -e lint
35 | goto :end
36 |
37 | :docs
38 | CALL docs\make clean
39 | CALL docs\make html
40 | START docs\_build\html\index.html
41 | goto :end
42 |
43 | :freeze
44 | CALL :clean
45 | CALL :init
46 | set PYTHONPATH=.
47 | for /f "delims=" %%a in ('python vyper/cli/vyper_compile.py --version') do @set VERSION=%%a
48 | pyinstaller --clean --onefile vyper/cli/vyper_compile.py --name vyper.%VERSION%.windows --add-data vyper;vyper
49 | goto :end
50 |
51 | :clean
52 | CALL :clean-build
53 | CALL :clean-pyc
54 | CALL :clean-test
55 | goto :end
56 |
57 | :clean-build
58 | if exist build RMDIR /Q /S build
59 | if exist dist RMDIR /Q /S dist
60 | for /d %%x in (*.egg-info) do if exist "%%x" RMDIR /Q /S "%%x"
61 | for /r %%x in (*.spec) do del %%x
62 | goto :end
63 |
64 |
65 | :clean-pyc
66 | for /r %%x in (*.pyc) do del %%x
67 | for /r %%x in (*.pyo) do del %%x
68 | for /r %%x in (*~) do del %%x
69 | for /r /d %%x in (__pycache__) do if exist "%%x" RMDIR "%%x"
70 | goto :end
71 |
72 |
73 | :clean-test
74 | for /r /d %%x in (htmlcov) do if exist "%%x" RMDIR /Q /S "%%x"
75 | goto :end
76 |
77 | :end
78 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | # NOTE: you have to use single-quoted strings in TOML for regular expressions.
2 | # It's the equivalent of r-strings in Python. Multiline strings are treated as
3 | # verbose regular expressions by Black. Use [ ] to denote a significant space
4 | # character.
5 |
6 | [tool.black]
7 | line-length = 100
8 | target-version = ['py310']
9 | include = '\.pyi?$'
10 | exclude = '''
11 | /(
12 | \.eggs
13 | | \.git
14 | | \.hg
15 | | \.mypy_cache
16 | | \.tox
17 | | \.venv
18 | | _build
19 | | buck-out
20 | | build
21 | | dist
22 | | env
23 | | venv
24 | )/
25 | '''
26 |
--------------------------------------------------------------------------------
/quicktest.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # examples:
4 | # ./quicktest.sh
5 | # ./quicktest.sh tests/.../mytest.py
6 |
7 | # run pytest but bail out on first error and suppress coverage.
8 | # useful for dev workflow
9 | pytest -q --no-cov -s --instafail -x --disable-warnings "$@"
10 |
--------------------------------------------------------------------------------
/requirements-docs.txt:
--------------------------------------------------------------------------------
1 | sphinx==4.5.0
2 | recommonmark==0.6.0
3 | sphinx_rtd_theme==0.5.2
4 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | license_files = LICENSE
3 |
4 | [aliases]
5 | test = pytest
6 |
7 | [flake8]
8 | extend-ignore = E203
9 | max-line-length = 100
10 | exclude =
11 | venv*
12 | .tox
13 | docs
14 | build
15 | per-file-ignores =
16 | */__init__.py: F401
17 |
18 | [tool:isort]
19 | force_grid_wrap = 0
20 | include_trailing_comma = True
21 | known_first_party = vyper
22 | multi_line_output = 3
23 | use_parentheses = True
24 | ensure_newline_before_comments = True
25 | line_length = 100
26 |
27 | [tool:pytest]
28 | addopts = -n auto
29 | --cov-branch
30 | --cov-report term
31 | --cov-report html
32 | --cov-report xml
33 | --cov=vyper
34 | python_files = test_*.py
35 | testpaths = tests
36 | markers =
37 | fuzzing: Run Hypothesis fuzz test suite (deselect with '-m "not fuzzing"')
38 |
39 | [tool:mypy]
40 | ignore_missing_imports = True
41 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/tests/__init__.py
--------------------------------------------------------------------------------
/tests/ast/nodes/test_binary.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import ast as vy_ast
4 | from vyper.exceptions import SyntaxException
5 |
6 |
7 | def test_binary_becomes_bytes():
8 | expected = vy_ast.parse_to_ast("foo: Bytes[1] = b'\x01'")
9 | mutated = vy_ast.parse_to_ast("foo: Bytes[1] = 0b00000001")
10 |
11 | assert vy_ast.compare_nodes(expected, mutated)
12 |
13 |
14 | def test_binary_length():
15 | with pytest.raises(SyntaxException):
16 | vy_ast.parse_to_ast("foo: Bytes[1] = 0b01")
17 |
--------------------------------------------------------------------------------
/tests/ast/nodes/test_compare_nodes.py:
--------------------------------------------------------------------------------
1 | from vyper import ast as vy_ast
2 |
3 |
4 | def test_compare_different_node_clases():
5 | vyper_ast = vy_ast.parse_to_ast("foo = 42")
6 | left = vyper_ast.body[0].target
7 | right = vyper_ast.body[0].value
8 |
9 | assert left != right
10 | assert not vy_ast.compare_nodes(left, right)
11 |
12 |
13 | def test_compare_different_nodes_same_class():
14 | vyper_ast = vy_ast.parse_to_ast("[1, 2]")
15 | left, right = vyper_ast.body[0].value.elements
16 |
17 | assert left != right
18 | assert not vy_ast.compare_nodes(left, right)
19 |
20 |
21 | def test_compare_different_nodes_same_value():
22 | vyper_ast = vy_ast.parse_to_ast("[1, 1]")
23 | left, right = vyper_ast.body[0].value.elements
24 |
25 | assert left != right
26 | assert vy_ast.compare_nodes(left, right)
27 |
28 |
29 | def test_compare_complex_nodes_same_value():
30 | vyper_ast = vy_ast.parse_to_ast("[{'foo':'bar', 43:[1,2,3]}, {'foo':'bar', 43:[1,2,3]}]")
31 | left, right = vyper_ast.body[0].value.elements
32 |
33 | assert left != right
34 | assert vy_ast.compare_nodes(left, right)
35 |
36 |
37 | def test_compare_same_node():
38 | vyper_ast = vy_ast.parse_to_ast("42")
39 | node = vyper_ast.body[0].value
40 |
41 | assert node == node
42 | assert vy_ast.compare_nodes(node, node)
43 |
--------------------------------------------------------------------------------
/tests/ast/nodes/test_evaluate_boolop.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from hypothesis import given, settings
3 | from hypothesis import strategies as st
4 |
5 | from vyper import ast as vy_ast
6 |
7 | variables = "abcdefghij"
8 |
9 |
10 | @pytest.mark.fuzzing
11 | @settings(max_examples=50, deadline=1000)
12 | @given(values=st.lists(st.booleans(), min_size=2, max_size=10))
13 | @pytest.mark.parametrize("comparator", ["and", "or"])
14 | def test_boolop_simple(get_contract, values, comparator):
15 | input_value = ",".join(f"{i}: bool" for i in variables[: len(values)])
16 | return_value = f" {comparator} ".join(variables[: len(values)])
17 |
18 | source = f"""
19 | @external
20 | def foo({input_value}) -> bool:
21 | return {return_value}
22 | """
23 | contract = get_contract(source)
24 |
25 | literal_op = f" {comparator} ".join(str(i) for i in values)
26 |
27 | vyper_ast = vy_ast.parse_to_ast(literal_op)
28 | old_node = vyper_ast.body[0].value
29 | new_node = old_node.evaluate()
30 |
31 | assert contract.foo(*values) == new_node.value
32 |
33 |
34 | @pytest.mark.fuzzing
35 | @settings(max_examples=50, deadline=1000)
36 | @given(
37 | values=st.lists(st.booleans(), min_size=2, max_size=10),
38 | comparators=st.lists(st.sampled_from(["and", "or"]), min_size=11, max_size=11),
39 | )
40 | def test_boolop_nested(get_contract, values, comparators):
41 | input_value = ",".join(f"{i}: bool" for i in variables[: len(values)])
42 | return_value = " ".join(f"{a} {b}" for a, b in zip(variables[: len(values)], comparators))
43 | return_value = return_value.rsplit(maxsplit=1)[0]
44 |
45 | source = f"""
46 | @external
47 | def foo({input_value}) -> bool:
48 | return {return_value}
49 | """
50 | contract = get_contract(source)
51 |
52 | literal_op = " ".join(f"{a} {b}" for a, b in zip(values, comparators))
53 | literal_op = literal_op.rsplit(maxsplit=1)[0]
54 |
55 | vyper_ast = vy_ast.parse_to_ast(literal_op)
56 | vy_ast.folding.replace_literal_ops(vyper_ast)
57 | expected = vyper_ast.body[0].value.value
58 |
59 | assert contract.foo(*values) == expected
60 |
--------------------------------------------------------------------------------
/tests/ast/nodes/test_evaluate_subscript.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from hypothesis import given, settings
3 | from hypothesis import strategies as st
4 |
5 | from vyper import ast as vy_ast
6 |
7 |
8 | @pytest.mark.fuzzing
9 | @settings(max_examples=50, deadline=1000)
10 | @given(
11 | idx=st.integers(min_value=0, max_value=9),
12 | array=st.lists(st.integers(), min_size=10, max_size=10),
13 | )
14 | def test_subscript(get_contract, array, idx):
15 | source = """
16 | @external
17 | def foo(array: int128[10], idx: uint256) -> int128:
18 | return array[idx]
19 | """
20 | contract = get_contract(source)
21 |
22 | vyper_ast = vy_ast.parse_to_ast(f"{array}[{idx}]")
23 | old_node = vyper_ast.body[0].value
24 | new_node = old_node.evaluate()
25 |
26 | assert contract.foo(array, idx) == new_node.value
27 |
--------------------------------------------------------------------------------
/tests/ast/nodes/test_evaluate_unaryop.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import ast as vy_ast
4 |
5 |
6 | @pytest.mark.parametrize("bool_cond", [True, False])
7 | def test_unaryop(get_contract, bool_cond):
8 | source = """
9 | @external
10 | def foo(a: bool) -> bool:
11 | return not a
12 | """
13 | contract = get_contract(source)
14 |
15 | vyper_ast = vy_ast.parse_to_ast(f"not {bool_cond}")
16 | old_node = vyper_ast.body[0].value
17 | new_node = old_node.evaluate()
18 |
19 | assert contract.foo(bool_cond) == new_node.value
20 |
21 |
22 | @pytest.mark.parametrize("count", range(2, 11))
23 | @pytest.mark.parametrize("bool_cond", [True, False])
24 | def test_unaryop_nested(get_contract, bool_cond, count):
25 | source = f"""
26 | @external
27 | def foo(a: bool) -> bool:
28 | return {'not ' * count} a
29 | """
30 | contract = get_contract(source)
31 |
32 | literal_op = f"{'not ' * count}{bool_cond}"
33 | vyper_ast = vy_ast.parse_to_ast(literal_op)
34 | vy_ast.folding.replace_literal_ops(vyper_ast)
35 | expected = vyper_ast.body[0].value.value
36 |
37 | assert contract.foo(bool_cond) == expected
38 |
--------------------------------------------------------------------------------
/tests/ast/nodes/test_from_node.py:
--------------------------------------------------------------------------------
1 | from vyper import ast as vy_ast
2 |
3 |
4 | def test_output_class():
5 | old_node = vy_ast.parse_to_ast("foo = 42")
6 | new_node = vy_ast.Int.from_node(old_node, value=666)
7 |
8 | assert isinstance(new_node, vy_ast.Int)
9 |
10 |
11 | def test_source():
12 | old_node = vy_ast.parse_to_ast("foo = 42")
13 | new_node = vy_ast.Int.from_node(old_node, value=666)
14 |
15 | assert old_node.src == new_node.src
16 | assert old_node.node_source_code == new_node.node_source_code
17 |
18 |
19 | def test_kwargs():
20 | old_node = vy_ast.parse_to_ast("42").body[0].value
21 | new_node = vy_ast.Int.from_node(old_node, value=666)
22 |
23 | assert old_node.value == 42
24 | assert new_node.value == 666
25 |
26 |
27 | def test_compare_nodes():
28 | old_node = vy_ast.parse_to_ast("foo = 42")
29 | new_node = vy_ast.Int.from_node(old_node, value=666)
30 |
31 | assert not vy_ast.compare_nodes(old_node, new_node)
32 |
33 |
34 | def test_new_node_has_no_parent():
35 | old_node = vy_ast.parse_to_ast("foo = 42")
36 | new_node = vy_ast.Int.from_node(old_node, value=666)
37 |
38 | assert new_node._parent is None
39 | assert new_node._depth == 0
40 |
--------------------------------------------------------------------------------
/tests/ast/nodes/test_get_children.py:
--------------------------------------------------------------------------------
1 | from vyper import ast as vy_ast
2 |
3 |
4 | def test_order():
5 | node = vy_ast.parse_to_ast("1 + 2").body[0].value
6 | assert node.get_children() == [node.left, node.op, node.right]
7 |
8 |
9 | def test_order_reversed():
10 | node = vy_ast.parse_to_ast("1 + 2").body[0].value
11 | assert node.get_children(reverse=True) == [node.right, node.op, node.left]
12 |
13 |
14 | def test_type_filter():
15 | node = vy_ast.parse_to_ast("[1, 2.0, 'three', 4, 0x05]").body[0].value
16 | assert node.get_children(vy_ast.Int) == [node.elements[0], node.elements[3]]
17 |
18 |
19 | def test_dict_filter():
20 | node = vy_ast.parse_to_ast("[foo, foo(), bar, bar()]").body[0].value
21 | assert node.get_children(filters={"func.id": "foo"}) == [node.elements[1]]
22 |
23 |
24 | def test_only_returns_children():
25 | node = vy_ast.parse_to_ast("[1, 2, (3, 4), 5]").body[0].value
26 | assert node.get_children() == node.elements
27 |
--------------------------------------------------------------------------------
/tests/ast/nodes/test_hex.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import ast as vy_ast
4 | from vyper import semantics
5 | from vyper.exceptions import InvalidLiteral
6 |
7 | code_invalid_checksum = [
8 | """
9 | foo: constant(address) = 0x6b175474e89094c44da98b954eedeac495271d0F
10 | """,
11 | """
12 | foo: constant(address[1]) = [0x6b175474e89094c44da98b954eedeac495271d0F]
13 | """,
14 | """
15 | @external
16 | def foo():
17 | bar: address = 0x6b175474e89094c44da98b954eedeac495271d0F
18 | """,
19 | """
20 | @external
21 | def foo():
22 | bar: address[1] = [0x6b175474e89094c44da98b954eedeac495271d0F]
23 | """,
24 | """
25 | @external
26 | def foo():
27 | for i in [0x6b175474e89094c44da98b954eedeac495271d0F]:
28 | pass
29 | """,
30 | """
31 | foo: constant(bytes20) = 0x6b175474e89094c44da98b954eedeac495271d0F
32 | """,
33 | """
34 | foo: constant(bytes4) = 0x12_34_56
35 | """,
36 | ]
37 |
38 |
39 | @pytest.mark.parametrize("code", code_invalid_checksum)
40 | def test_invalid_checksum(code):
41 | vyper_module = vy_ast.parse_to_ast(code)
42 |
43 | with pytest.raises(InvalidLiteral):
44 | vy_ast.validation.validate_literal_nodes(vyper_module)
45 | semantics.validate_semantics(vyper_module, {})
46 |
--------------------------------------------------------------------------------
/tests/ast/test_metadata_journal.py:
--------------------------------------------------------------------------------
1 | from vyper.ast.metadata import NodeMetadata
2 | from vyper.exceptions import VyperException
3 |
4 |
5 | def test_metadata_journal_basic():
6 | m = NodeMetadata()
7 |
8 | m["x"] = 1
9 | assert m["x"] == 1
10 |
11 |
12 | def test_metadata_journal_commit():
13 | m = NodeMetadata()
14 |
15 | with m.enter_typechecker_speculation():
16 | m["x"] = 1
17 |
18 | assert m["x"] == 1
19 |
20 |
21 | def test_metadata_journal_exception():
22 | m = NodeMetadata()
23 |
24 | m["x"] = 1
25 | try:
26 | with m.enter_typechecker_speculation():
27 | m["x"] = 2
28 | m["x"] = 3
29 |
30 | assert m["x"] == 3
31 | raise VyperException("dummy exception")
32 |
33 | except VyperException:
34 | pass
35 |
36 | # rollback upon exception
37 | assert m["x"] == 1
38 |
39 |
40 | def test_metadata_journal_rollback_inner():
41 | m = NodeMetadata()
42 |
43 | m["x"] = 1
44 | with m.enter_typechecker_speculation():
45 | m["x"] = 2
46 |
47 | try:
48 | with m.enter_typechecker_speculation():
49 | m["x"] = 3
50 | m["x"] = 4 # test multiple writes
51 |
52 | assert m["x"] == 4
53 | raise VyperException("dummy exception")
54 |
55 | except VyperException:
56 | pass
57 |
58 | assert m["x"] == 2
59 |
60 |
61 | def test_metadata_journal_rollback_outer():
62 | m = NodeMetadata()
63 |
64 | m["x"] = 1
65 | try:
66 | with m.enter_typechecker_speculation():
67 | m["x"] = 2
68 |
69 | with m.enter_typechecker_speculation():
70 | m["x"] = 3
71 | m["x"] = 4 # test multiple writes
72 |
73 | assert m["x"] == 4
74 |
75 | m["x"] = 5
76 |
77 | raise VyperException("dummy exception")
78 |
79 | except VyperException:
80 | pass
81 |
82 | assert m["x"] == 1
83 |
--------------------------------------------------------------------------------
/tests/builtins/folding/test_abs.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from hypothesis import example, given, settings
3 | from hypothesis import strategies as st
4 |
5 | from vyper import ast as vy_ast
6 | from vyper.builtins import functions as vy_fn
7 | from vyper.exceptions import OverflowException
8 |
9 |
10 | @pytest.mark.fuzzing
11 | @settings(max_examples=50, deadline=1000)
12 | @given(a=st.integers(min_value=-(2**255) + 1, max_value=2**255 - 1))
13 | @example(a=0)
14 | def test_abs(get_contract, a):
15 | source = """
16 | @external
17 | def foo(a: int256) -> int256:
18 | return abs(a)
19 | """
20 | contract = get_contract(source)
21 |
22 | vyper_ast = vy_ast.parse_to_ast(f"abs({a})")
23 | old_node = vyper_ast.body[0].value
24 | new_node = vy_fn.DISPATCH_TABLE["abs"].evaluate(old_node)
25 |
26 | assert contract.foo(a) == new_node.value == abs(a)
27 |
28 |
29 | @pytest.mark.fuzzing
30 | @settings(max_examples=50, deadline=1000)
31 | @given(a=st.integers(min_value=2**255, max_value=2**256 - 1))
32 | def test_abs_upper_bound_folding(get_contract, a):
33 | source = f"""
34 | @external
35 | def foo(a: int256) -> int256:
36 | return abs({a})
37 | """
38 | with pytest.raises(OverflowException):
39 | get_contract(source)
40 |
41 |
42 | def test_abs_lower_bound(get_contract, assert_tx_failed):
43 | source = """
44 | @external
45 | def foo(a: int256) -> int256:
46 | return abs(a)
47 | """
48 | contract = get_contract(source)
49 |
50 | assert_tx_failed(lambda: contract.foo(-(2**255)))
51 |
52 |
53 | def test_abs_lower_bound_folded(get_contract, assert_tx_failed):
54 | source = """
55 | @external
56 | def foo() -> int256:
57 | return abs(-2**255)
58 | """
59 | with pytest.raises(OverflowException):
60 | get_contract(source)
61 |
--------------------------------------------------------------------------------
/tests/builtins/folding/test_addmod_mulmod.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from hypothesis import assume, given, settings
3 | from hypothesis import strategies as st
4 |
5 | from vyper import ast as vy_ast
6 | from vyper.builtins import functions as vy_fn
7 |
8 | st_uint256 = st.integers(min_value=0, max_value=2**256 - 1)
9 |
10 |
11 | @pytest.mark.fuzzing
12 | @settings(max_examples=50, deadline=1000)
13 | @given(a=st_uint256, b=st_uint256, c=st_uint256)
14 | @pytest.mark.parametrize("fn_name", ["uint256_addmod", "uint256_mulmod"])
15 | def test_modmath(get_contract, a, b, c, fn_name):
16 | assume(c > 0)
17 |
18 | source = f"""
19 | @external
20 | def foo(a: uint256, b: uint256, c: uint256) -> uint256:
21 | return {fn_name}(a, b, c)
22 | """
23 | contract = get_contract(source)
24 |
25 | vyper_ast = vy_ast.parse_to_ast(f"{fn_name}({a}, {b}, {c})")
26 | old_node = vyper_ast.body[0].value
27 | new_node = vy_fn.DISPATCH_TABLE[fn_name].evaluate(old_node)
28 |
29 | assert contract.foo(a, b, c) == new_node.value
30 |
--------------------------------------------------------------------------------
/tests/builtins/folding/test_epsilon.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import ast as vy_ast
4 | from vyper.builtins import functions as vy_fn
5 |
6 |
7 | @pytest.mark.parametrize("typ_name", ["decimal"])
8 | def test_epsilon(get_contract, typ_name):
9 | source = f"""
10 | @external
11 | def foo() -> {typ_name}:
12 | return epsilon({typ_name})
13 | """
14 | contract = get_contract(source)
15 |
16 | vyper_ast = vy_ast.parse_to_ast(f"epsilon({typ_name})")
17 | old_node = vyper_ast.body[0].value
18 | new_node = vy_fn.DISPATCH_TABLE["epsilon"].evaluate(old_node)
19 |
20 | assert contract.foo() == new_node.value
21 |
--------------------------------------------------------------------------------
/tests/builtins/folding/test_floor_ceil.py:
--------------------------------------------------------------------------------
1 | from decimal import Decimal
2 |
3 | import pytest
4 | from hypothesis import example, given, settings
5 | from hypothesis import strategies as st
6 |
7 | from vyper import ast as vy_ast
8 | from vyper.builtins import functions as vy_fn
9 |
10 | st_decimals = st.decimals(
11 | min_value=-(2**32), max_value=2**32, allow_nan=False, allow_infinity=False, places=10
12 | )
13 |
14 |
15 | @pytest.mark.fuzzing
16 | @settings(max_examples=50, deadline=1000)
17 | @given(value=st_decimals)
18 | @example(value=Decimal("0.9999999999"))
19 | @example(value=Decimal("0.0000000001"))
20 | @example(value=Decimal("-0.9999999999"))
21 | @example(value=Decimal("-0.0000000001"))
22 | @pytest.mark.parametrize("fn_name", ["floor", "ceil"])
23 | def test_floor_ceil(get_contract, value, fn_name):
24 | source = f"""
25 | @external
26 | def foo(a: decimal) -> int256:
27 | return {fn_name}(a)
28 | """
29 | contract = get_contract(source)
30 |
31 | vyper_ast = vy_ast.parse_to_ast(f"{fn_name}({value})")
32 | old_node = vyper_ast.body[0].value
33 | new_node = vy_fn.DISPATCH_TABLE[fn_name].evaluate(old_node)
34 |
35 | assert contract.foo(value) == new_node.value
36 |
--------------------------------------------------------------------------------
/tests/builtins/folding/test_fold_as_wei_value.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from hypothesis import given, settings
3 | from hypothesis import strategies as st
4 |
5 | from vyper import ast as vy_ast
6 | from vyper.builtins import functions as vy_fn
7 | from vyper.utils import SizeLimits
8 |
9 | denoms = [x for k in vy_fn.AsWeiValue.wei_denoms.keys() for x in k]
10 |
11 |
12 | st_decimals = st.decimals(
13 | min_value=0,
14 | max_value=SizeLimits.MAX_AST_DECIMAL,
15 | allow_nan=False,
16 | allow_infinity=False,
17 | places=10,
18 | )
19 |
20 |
21 | @pytest.mark.fuzzing
22 | @settings(max_examples=10, deadline=1000)
23 | @given(value=st_decimals)
24 | @pytest.mark.parametrize("denom", denoms)
25 | def test_decimal(get_contract, value, denom):
26 | source = f"""
27 | @external
28 | def foo(a: decimal) -> uint256:
29 | return as_wei_value(a, '{denom}')
30 | """
31 | contract = get_contract(source)
32 |
33 | vyper_ast = vy_ast.parse_to_ast(f"as_wei_value({value:.10f}, '{denom}')")
34 | old_node = vyper_ast.body[0].value
35 | new_node = vy_fn.AsWeiValue().evaluate(old_node)
36 |
37 | assert contract.foo(value) == new_node.value
38 |
39 |
40 | @pytest.mark.fuzzing
41 | @settings(max_examples=10, deadline=1000)
42 | @given(value=st.integers(min_value=0, max_value=2**128))
43 | @pytest.mark.parametrize("denom", denoms)
44 | def test_integer(get_contract, value, denom):
45 | source = f"""
46 | @external
47 | def foo(a: uint256) -> uint256:
48 | return as_wei_value(a, '{denom}')
49 | """
50 | contract = get_contract(source)
51 |
52 | vyper_ast = vy_ast.parse_to_ast(f"as_wei_value({value}, '{denom}')")
53 | old_node = vyper_ast.body[0].value
54 | new_node = vy_fn.AsWeiValue().evaluate(old_node)
55 |
56 | assert contract.foo(value) == new_node.value
57 |
--------------------------------------------------------------------------------
/tests/builtins/folding/test_len.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import ast as vy_ast
4 | from vyper.builtins import functions as vy_fn
5 |
6 |
7 | @pytest.mark.parametrize("length", [0, 1, 32, 33, 64, 65, 1024])
8 | def test_len_string(get_contract, length):
9 | source = """
10 | @external
11 | def foo(a: String[1024]) -> uint256:
12 | return len(a)
13 | """
14 | contract = get_contract(source)
15 |
16 | value = "a" * length
17 |
18 | vyper_ast = vy_ast.parse_to_ast(f"len('{value}')")
19 | old_node = vyper_ast.body[0].value
20 | new_node = vy_fn.Len().evaluate(old_node)
21 |
22 | assert contract.foo(value) == new_node.value
23 |
24 |
25 | @pytest.mark.parametrize("length", [0, 1, 32, 33, 64, 65, 1024])
26 | def test_len_bytes(get_contract, length):
27 | source = """
28 | @external
29 | def foo(a: Bytes[1024]) -> uint256:
30 | return len(a)
31 | """
32 | contract = get_contract(source)
33 |
34 | value = "a" * length
35 |
36 | vyper_ast = vy_ast.parse_to_ast(f"len(b'{value}')")
37 | old_node = vyper_ast.body[0].value
38 | new_node = vy_fn.Len().evaluate(old_node)
39 |
40 | assert contract.foo(value.encode()) == new_node.value
41 |
42 |
43 | @pytest.mark.parametrize("length", [1, 32, 33, 64, 65, 1024])
44 | def test_len_hex(get_contract, length):
45 | source = """
46 | @external
47 | def foo(a: Bytes[1024]) -> uint256:
48 | return len(a)
49 | """
50 | contract = get_contract(source)
51 |
52 | value = f"0x{'00' * length}"
53 |
54 | vyper_ast = vy_ast.parse_to_ast(f"len({value})")
55 | old_node = vyper_ast.body[0].value
56 | new_node = vy_fn.Len().evaluate(old_node)
57 |
58 | assert contract.foo(value) == new_node.value
59 |
--------------------------------------------------------------------------------
/tests/builtins/folding/test_powmod.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from hypothesis import given, settings
3 | from hypothesis import strategies as st
4 |
5 | from vyper import ast as vy_ast
6 | from vyper.builtins import functions as vy_fn
7 |
8 | st_uint256 = st.integers(min_value=0, max_value=2**256)
9 |
10 |
11 | @pytest.mark.fuzzing
12 | @settings(max_examples=100, deadline=1000)
13 | @given(a=st_uint256, b=st_uint256)
14 | def test_powmod_uint256(get_contract, a, b):
15 | source = """
16 | @external
17 | def foo(a: uint256, b: uint256) -> uint256:
18 | return pow_mod256(a, b)
19 | """
20 | contract = get_contract(source)
21 |
22 | vyper_ast = vy_ast.parse_to_ast(f"pow_mod256({a}, {b})")
23 | old_node = vyper_ast.body[0].value
24 | new_node = vy_fn.PowMod256().evaluate(old_node)
25 |
26 | assert contract.foo(a, b) == new_node.value
27 |
--------------------------------------------------------------------------------
/tests/cli/outputs/test_storage_layout.py:
--------------------------------------------------------------------------------
1 | from vyper.compiler import compile_code
2 |
3 |
4 | def test_storage_layout():
5 | code = """
6 | foo: HashMap[address, uint256]
7 |
8 | @external
9 | @nonreentrant("foo")
10 | def public_foo1():
11 | pass
12 |
13 | @external
14 | @nonreentrant("foo")
15 | def public_foo2():
16 | pass
17 |
18 |
19 | @internal
20 | @nonreentrant("bar")
21 | def _bar():
22 | pass
23 |
24 | arr: DynArray[uint256, 3]
25 |
26 | # mix it up a little
27 | baz: Bytes[65]
28 | bar: uint256
29 |
30 | @external
31 | @nonreentrant("bar")
32 | def public_bar():
33 | pass
34 |
35 | @external
36 | @nonreentrant("foo")
37 | def public_foo3():
38 | pass
39 | """
40 |
41 | out = compile_code(code, output_formats=["layout"])
42 |
43 | assert out["layout"]["storage_layout"] == {
44 | "nonreentrant.foo": {"type": "nonreentrant lock", "slot": 0},
45 | "nonreentrant.bar": {"type": "nonreentrant lock", "slot": 1},
46 | "foo": {"type": "HashMap[address, uint256]", "slot": 2},
47 | "arr": {"type": "DynArray[uint256, 3]", "slot": 3},
48 | "baz": {"type": "Bytes[65]", "slot": 7},
49 | "bar": {"type": "uint256", "slot": 11},
50 | }
51 |
52 |
53 | def test_storage_and_immutables_layout():
54 | code = """
55 | name: String[32]
56 | SYMBOL: immutable(String[32])
57 | DECIMALS: immutable(uint8)
58 |
59 | @external
60 | def __init__():
61 | SYMBOL = "VYPR"
62 | DECIMALS = 18
63 | """
64 |
65 | expected_layout = {
66 | "code_layout": {
67 | "DECIMALS": {"length": 32, "offset": 64, "type": "uint8"},
68 | "SYMBOL": {"length": 64, "offset": 0, "type": "String[32]"},
69 | },
70 | "storage_layout": {"name": {"slot": 0, "type": "String[32]"}},
71 | }
72 |
73 | out = compile_code(code, output_formats=["layout"])
74 | assert out["layout"] == expected_layout
75 |
--------------------------------------------------------------------------------
/tests/cli/vyper_compile/test_compile_files.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.cli.vyper_compile import compile_files
4 |
5 |
6 | def test_combined_json_keys(tmp_path):
7 | bar_path = tmp_path.joinpath("bar.vy")
8 | with bar_path.open("w") as fp:
9 | fp.write("")
10 |
11 | combined_keys = {
12 | "bytecode",
13 | "bytecode_runtime",
14 | "blueprint_bytecode",
15 | "abi",
16 | "source_map",
17 | "layout",
18 | "method_identifiers",
19 | "userdoc",
20 | "devdoc",
21 | }
22 | compile_data = compile_files([bar_path], ["combined_json"], root_folder=tmp_path)
23 |
24 | assert set(compile_data.keys()) == {"bar.vy", "version"}
25 | assert set(compile_data["bar.vy"].keys()) == combined_keys
26 |
27 |
28 | def test_invalid_root_path():
29 | with pytest.raises(FileNotFoundError):
30 | compile_files([], [], root_folder="path/that/does/not/exist")
31 |
--------------------------------------------------------------------------------
/tests/cli/vyper_compile/test_parse_args.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import pytest
4 |
5 | from vyper.cli.vyper_compile import _parse_args
6 |
7 |
8 | @pytest.fixture
9 | def chdir_path(tmp_path):
10 | orig_path = os.getcwd()
11 | yield tmp_path
12 | os.chdir(orig_path)
13 |
14 |
15 | def test_paths(chdir_path):
16 | code = """
17 | @external
18 | def foo() -> bool:
19 | return True
20 | """
21 | bar_path = chdir_path.joinpath("bar.vy")
22 | with bar_path.open("w") as fp:
23 | fp.write(code)
24 | _parse_args([str(bar_path)]) # absolute path
25 | os.chdir(chdir_path.parent)
26 | _parse_args([str(bar_path)]) # absolute path, subfolder of cwd
27 | _parse_args([str(bar_path.relative_to(chdir_path.parent))]) # relative path
28 |
--------------------------------------------------------------------------------
/tests/cli/vyper_json/test_compile_json.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import json
4 | from copy import deepcopy
5 |
6 | import pytest
7 |
8 | from vyper.cli.vyper_json import compile_from_input_dict, compile_json
9 | from vyper.exceptions import JSONError
10 |
11 | FOO_CODE = """
12 | import contracts.bar as Bar
13 |
14 | @external
15 | def foo(a: address) -> bool:
16 | return Bar(a).bar(1)
17 | """
18 |
19 | BAR_CODE = """
20 | @external
21 | def bar(a: uint256) -> bool:
22 | return True
23 | """
24 |
25 | BAR_ABI = [
26 | {
27 | "name": "bar",
28 | "outputs": [{"type": "bool", "name": "out"}],
29 | "inputs": [{"type": "uint256", "name": "a"}],
30 | "stateMutability": "nonpayable",
31 | "type": "function",
32 | "gas": 313,
33 | }
34 | ]
35 |
36 | INPUT_JSON = {
37 | "language": "Vyper",
38 | "sources": {
39 | "contracts/foo.vy": {"content": FOO_CODE},
40 | "contracts/bar.vy": {"content": BAR_CODE},
41 | },
42 | "interfaces": {"contracts/bar.json": {"abi": BAR_ABI}},
43 | "settings": {"outputSelection": {"*": ["*"]}},
44 | }
45 |
46 |
47 | def test_input_formats():
48 | assert compile_json(INPUT_JSON) == compile_json(json.dumps(INPUT_JSON))
49 |
50 |
51 | def test_bad_json():
52 | with pytest.raises(JSONError):
53 | compile_json("this probably isn't valid JSON, is it")
54 |
55 |
56 | def test_keyerror_becomes_jsonerror():
57 | input_json = deepcopy(INPUT_JSON)
58 | del input_json["sources"]
59 | with pytest.raises(KeyError):
60 | compile_from_input_dict(input_json)
61 | with pytest.raises(JSONError):
62 | compile_json(input_json)
63 |
--------------------------------------------------------------------------------
/tests/cli/vyper_json/test_get_settings.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import pytest
4 |
5 | from vyper.cli.vyper_json import get_evm_version
6 | from vyper.exceptions import JSONError
7 |
8 |
9 | def test_unknown_evm():
10 | with pytest.raises(JSONError):
11 | get_evm_version({"settings": {"evmVersion": "foo"}})
12 |
13 |
14 | @pytest.mark.parametrize(
15 | "evm_version",
16 | [
17 | "homestead",
18 | "tangerineWhistle",
19 | "spuriousDragon",
20 | "byzantium",
21 | "constantinople",
22 | "petersburg",
23 | ],
24 | )
25 | def test_early_evm(evm_version):
26 | with pytest.raises(JSONError):
27 | get_evm_version({"settings": {"evmVersion": evm_version}})
28 |
29 |
30 | @pytest.mark.parametrize("evm_version", ["istanbul", "berlin", "paris", "shanghai", "cancun"])
31 | def test_valid_evm(evm_version):
32 | assert evm_version == get_evm_version({"settings": {"evmVersion": evm_version}})
33 |
--------------------------------------------------------------------------------
/tests/cli/vyper_json/test_output_dict.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import vyper
4 | from vyper.cli.vyper_json import format_to_output_dict
5 | from vyper.compiler import OUTPUT_FORMATS, compile_codes
6 |
7 | FOO_CODE = """
8 | @external
9 | def foo() -> bool:
10 | return True
11 | """
12 |
13 |
14 | def test_keys():
15 | compiler_data = compile_codes({"foo.vy": FOO_CODE}, output_formats=list(OUTPUT_FORMATS.keys()))
16 | output_json = format_to_output_dict(compiler_data)
17 | assert sorted(output_json.keys()) == ["compiler", "contracts", "sources"]
18 | assert output_json["compiler"] == f"vyper-{vyper.__version__}"
19 | data = compiler_data["foo.vy"]
20 | assert output_json["sources"]["foo.vy"] == {"id": 0, "ast": data["ast_dict"]["ast"]}
21 | assert output_json["contracts"]["foo.vy"]["foo"] == {
22 | "abi": data["abi"],
23 | "devdoc": data["devdoc"],
24 | "interface": data["interface"],
25 | "ir": data["ir_dict"],
26 | "userdoc": data["userdoc"],
27 | "metadata": data["metadata"],
28 | "evm": {
29 | "bytecode": {"object": data["bytecode"], "opcodes": data["opcodes"]},
30 | "deployedBytecode": {
31 | "object": data["bytecode_runtime"],
32 | "opcodes": data["opcodes_runtime"],
33 | "sourceMap": data["source_map"]["pc_pos_map_compressed"],
34 | "sourceMapFull": data["source_map_full"],
35 | },
36 | "methodIdentifiers": data["method_identifiers"],
37 | },
38 | }
39 |
--------------------------------------------------------------------------------
/tests/cli/vyper_json/test_output_selection.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import pytest
4 |
5 | from vyper.cli.vyper_json import TRANSLATE_MAP, get_input_dict_output_formats
6 | from vyper.exceptions import JSONError
7 |
8 |
9 | def test_no_outputs():
10 | with pytest.raises(KeyError):
11 | get_input_dict_output_formats({}, {})
12 |
13 |
14 | def test_invalid_output():
15 | input_json = {"settings": {"outputSelection": {"foo.vy": ["abi", "foobar"]}}}
16 | sources = {"foo.vy": ""}
17 | with pytest.raises(JSONError):
18 | get_input_dict_output_formats(input_json, sources)
19 |
20 |
21 | def test_unknown_contract():
22 | input_json = {"settings": {"outputSelection": {"bar.vy": ["abi"]}}}
23 | sources = {"foo.vy": ""}
24 | with pytest.raises(JSONError):
25 | get_input_dict_output_formats(input_json, sources)
26 |
27 |
28 | @pytest.mark.parametrize("output", TRANSLATE_MAP.items())
29 | def test_translate_map(output):
30 | input_json = {"settings": {"outputSelection": {"foo.vy": [output[0]]}}}
31 | sources = {"foo.vy": ""}
32 | assert get_input_dict_output_formats(input_json, sources) == {"foo.vy": [output[1]]}
33 |
34 |
35 | def test_star():
36 | input_json = {"settings": {"outputSelection": {"*": ["*"]}}}
37 | sources = {"foo.vy": "", "bar.vy": ""}
38 | expected = sorted(set(TRANSLATE_MAP.values()))
39 | result = get_input_dict_output_formats(input_json, sources)
40 | assert result == {"foo.vy": expected, "bar.vy": expected}
41 |
42 |
43 | def test_evm():
44 | input_json = {"settings": {"outputSelection": {"foo.vy": ["abi", "evm"]}}}
45 | sources = {"foo.vy": ""}
46 | expected = ["abi"] + sorted(v for k, v in TRANSLATE_MAP.items() if k.startswith("evm"))
47 | result = get_input_dict_output_formats(input_json, sources)
48 | assert result == {"foo.vy": expected}
49 |
50 |
51 | def test_solc_style():
52 | input_json = {"settings": {"outputSelection": {"foo.vy": {"": ["abi"], "foo.vy": ["ir"]}}}}
53 | sources = {"foo.vy": ""}
54 | assert get_input_dict_output_formats(input_json, sources) == {"foo.vy": ["abi", "ir_dict"]}
55 |
--------------------------------------------------------------------------------
/tests/compiler/__init__.py:
--------------------------------------------------------------------------------
1 | # prevent module name collision between tests/compiler/test_pre_parser.py
2 | # and tests/ast/test_pre_parser.py
3 |
--------------------------------------------------------------------------------
/tests/compiler/ir/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/tests/compiler/ir/__init__.py
--------------------------------------------------------------------------------
/tests/compiler/ir/test_compile_ir.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.codegen.ir_node import IRnode
4 | from vyper.ir import compile_ir
5 | from vyper.ir.s_expressions import parse_s_exp
6 |
7 | fail_list = [
8 | [-(2**255) - 3],
9 | [2**256 + 3],
10 | ["set", "_poz"],
11 | [["set", "var_1", 0, 0]],
12 | ["with", "var_1", 0, ["set", 1, 1]],
13 | ["break"], # invalid break
14 | ["continue"], # invalid continue
15 | ["invalidllelement"],
16 | ]
17 |
18 |
19 | @pytest.mark.parametrize("bad_ir", fail_list)
20 | def test_ir_compile_fail(bad_ir, get_contract_from_ir, assert_compile_failed):
21 | assert_compile_failed(lambda: get_contract_from_ir(IRnode.from_list(bad_ir)), Exception)
22 |
23 |
24 | valid_list = [
25 | ["pass"],
26 | ["assert", ["slt", ["mload", 0], 300]],
27 | ["assert", ["sgt", ["mload", 0], -1]],
28 | ["assert", ["gt", 1, ["mload", 0]]],
29 | ["assert", ["ge", ["mload", 0], 0]],
30 | ]
31 |
32 |
33 | @pytest.mark.parametrize("good_ir", valid_list)
34 | def test_compile_ir_good(good_ir, get_contract_from_ir):
35 | get_contract_from_ir(IRnode.from_list(good_ir))
36 |
37 |
38 | def test_ir_from_s_expression(get_contract_from_ir):
39 | code = """
40 | (seq
41 | (deploy
42 | 0
43 | (seq ; just return 32 byte of calldata back
44 | (calldatacopy 0 4 32)
45 | (return 0 32)
46 | stop
47 | )
48 | 0))
49 | """
50 | abi = [
51 | {
52 | "name": "test",
53 | "outputs": [{"type": "int128", "name": "out"}],
54 | "inputs": [{"type": "int128", "name": "a"}],
55 | "stateMutability": "nonpayable",
56 | "type": "function",
57 | "gas": 394,
58 | }
59 | ]
60 |
61 | s_expressions = parse_s_exp(code)
62 | ir = IRnode.from_list(s_expressions[0])
63 | c = get_contract_from_ir(ir, abi=abi)
64 | assert c.test(-123456) == -123456
65 |
66 |
67 | def test_pc_debugger():
68 | debugger_ir = ["seq", ["mstore", 0, 32], ["pc_debugger"]]
69 | ir_nodes = IRnode.from_list(debugger_ir)
70 | _, line_number_map = compile_ir.assembly_to_evm(compile_ir.compile_to_assembly(ir_nodes))
71 | assert line_number_map["pc_breakpoints"][0] == 4
72 |
--------------------------------------------------------------------------------
/tests/compiler/ir/test_repeat.py:
--------------------------------------------------------------------------------
1 | def test_repeat(get_contract_from_ir, assert_compile_failed):
2 | good_ir = ["repeat", 0, 0, 1, 1, ["seq"]]
3 | bad_ir_1 = ["repeat", 0, 0, 0, 0, ["seq"]]
4 | bad_ir_2 = ["repeat", 0, 0, -1, -1, ["seq"]]
5 | get_contract_from_ir(good_ir)
6 | assert_compile_failed(lambda: get_contract_from_ir(bad_ir_1), Exception)
7 | assert_compile_failed(lambda: get_contract_from_ir(bad_ir_2), Exception)
8 |
--------------------------------------------------------------------------------
/tests/compiler/test_calldatacopy.py:
--------------------------------------------------------------------------------
1 | def test_calldatacopy(get_contract_from_ir):
2 | ir = ["calldatacopy", 32, 0, ["calldatasize"]]
3 | get_contract_from_ir(ir)
4 |
--------------------------------------------------------------------------------
/tests/compiler/test_default_settings.py:
--------------------------------------------------------------------------------
1 | from vyper.codegen import core
2 | from vyper.compiler.phases import CompilerData
3 | from vyper.compiler.settings import OptimizationLevel, _is_debug_mode
4 |
5 |
6 | def test_default_settings():
7 | source_code = ""
8 | compiler_data = CompilerData(source_code)
9 | _ = compiler_data.vyper_module # force settings to be computed
10 |
11 | assert compiler_data.settings.optimize == OptimizationLevel.GAS
12 |
13 |
14 | def test_default_opt_level():
15 | assert OptimizationLevel.default() == OptimizationLevel.GAS
16 |
17 |
18 | def test_codegen_opt_level():
19 | assert core._opt_level == OptimizationLevel.GAS
20 | assert core._opt_gas() is True
21 | assert core._opt_none() is False
22 | assert core._opt_codesize() is False
23 |
24 |
25 | def test_debug_mode(pytestconfig):
26 | debug_mode = pytestconfig.getoption("enable_compiler_debug_mode")
27 | assert _is_debug_mode() == debug_mode
28 |
--------------------------------------------------------------------------------
/tests/compiler/test_opcodes.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | import vyper
4 | from vyper.evm import opcodes
5 | from vyper.exceptions import CompilerPanic
6 |
7 |
8 | @pytest.fixture(params=list(opcodes.EVM_VERSIONS))
9 | def evm_version(request):
10 | default = opcodes.active_evm_version
11 | try:
12 | opcodes.active_evm_version = opcodes.EVM_VERSIONS[request.param]
13 | yield request.param
14 | finally:
15 | opcodes.active_evm_version = default
16 |
17 |
18 | def test_opcodes():
19 | code = """
20 | @external
21 | def a() -> bool:
22 | return True
23 | """
24 |
25 | out = vyper.compile_code(code, ["opcodes_runtime", "opcodes"])
26 |
27 | assert len(out["opcodes"]) > len(out["opcodes_runtime"])
28 | assert out["opcodes_runtime"] in out["opcodes"]
29 |
30 |
31 | def test_version_check_no_begin_or_end():
32 | with pytest.raises(CompilerPanic):
33 | opcodes.version_check()
34 |
35 |
36 | def test_version_check(evm_version):
37 | assert opcodes.version_check(begin=evm_version)
38 | assert opcodes.version_check(end=evm_version)
39 | assert opcodes.version_check(begin=evm_version, end=evm_version)
40 | if evm_version not in ("istanbul"):
41 | assert not opcodes.version_check(end="istanbul")
42 | istanbul_check = opcodes.version_check(begin="istanbul")
43 | assert istanbul_check == (opcodes.EVM_VERSIONS[evm_version] >= opcodes.EVM_VERSIONS["istanbul"])
44 |
45 |
46 | def test_get_opcodes(evm_version):
47 | ops = opcodes.get_opcodes()
48 |
49 | assert "CHAINID" in ops
50 | assert ops["CREATE2"][-1] == 32000
51 |
52 | if evm_version in ("london", "berlin", "paris", "shanghai", "cancun"):
53 | assert ops["SLOAD"][-1] == 2100
54 | else:
55 | assert evm_version == "istanbul"
56 | assert ops["SLOAD"][-1] == 800
57 |
58 | if evm_version in ("shanghai", "cancun"):
59 | assert "PUSH0" in ops
60 |
61 | if evm_version in ("cancun",):
62 | for op in ("TLOAD", "TSTORE", "MCOPY"):
63 | assert op in ops
64 | else:
65 | for op in ("TLOAD", "TSTORE", "MCOPY"):
66 | assert op not in ops
67 |
--------------------------------------------------------------------------------
/tests/compiler/test_sha3_32.py:
--------------------------------------------------------------------------------
1 | from vyper.codegen.ir_node import IRnode
2 | from vyper.evm.opcodes import version_check
3 | from vyper.ir import compile_ir, optimizer
4 |
5 |
6 | def test_sha3_32():
7 | ir = ["sha3_32", 0]
8 | evm = ["PUSH1", 0, "PUSH1", 0, "MSTORE", "PUSH1", 32, "PUSH1", 0, "SHA3"]
9 | if version_check(begin="shanghai"):
10 | evm = ["PUSH0", "PUSH0", "MSTORE", "PUSH1", 32, "PUSH0", "SHA3"]
11 | assert compile_ir.compile_to_assembly(IRnode.from_list(ir)) == evm
12 | assert compile_ir.compile_to_assembly(optimizer.optimize(IRnode.from_list(ir))) == evm
13 |
--------------------------------------------------------------------------------
/tests/examples/conftest.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 |
4 | @pytest.fixture(autouse=True)
5 | def setup(memory_mocker):
6 | pass
7 |
--------------------------------------------------------------------------------
/tests/examples/crowdfund/test_crowdfund_example.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 |
4 | @pytest.fixture
5 | def c(w3, get_contract):
6 | with open("examples/crowdfund.vy") as f:
7 | contract_code = f.read()
8 | contract = get_contract(contract_code, *[w3.eth.accounts[1], 50, 60])
9 | return contract
10 |
11 |
12 | def test_crowdfund_example(c, w3):
13 | a0, a1, a2, a3, a4, a5, a6 = w3.eth.accounts[:7]
14 | c.participate(transact={"value": 5})
15 |
16 | assert c.timelimit() == 60
17 | assert c.deadline() - w3.eth.get_block("latest").timestamp == 59
18 | assert not w3.eth.get_block("latest").timestamp >= c.deadline() # expired
19 | assert not w3.eth.get_balance(c.address) >= c.goal() # not reached
20 | c.participate(transact={"value": 49})
21 | # assert c.reached()
22 | pre_bal = w3.eth.get_balance(a1)
23 | w3.testing.mine(100)
24 | assert not w3.eth.get_block("latest").number >= c.deadline() # expired
25 | c.finalize(transact={})
26 | post_bal = w3.eth.get_balance(a1)
27 | assert post_bal - pre_bal == 54
28 |
29 |
30 | def test_crowdfund_example2(c, w3, assert_tx_failed):
31 | a0, a1, a2, a3, a4, a5, a6 = w3.eth.accounts[:7]
32 | c.participate(transact={"value": 1, "from": a3})
33 | c.participate(transact={"value": 2, "from": a4})
34 | c.participate(transact={"value": 3, "from": a5})
35 | c.participate(transact={"value": 4, "from": a6})
36 |
37 | assert c.timelimit() == 60
38 | w3.testing.mine(100)
39 | # assert c.expired()
40 | # assert not c.reached()
41 | pre_bals = [w3.eth.get_balance(x) for x in [a3, a4, a5, a6]]
42 | assert_tx_failed(lambda: c.refund(transact={"from": a0}))
43 | c.refund(transact={"from": a3})
44 | assert_tx_failed(lambda: c.refund(transact={"from": a3}))
45 | c.refund(transact={"from": a4})
46 | c.refund(transact={"from": a5})
47 | c.refund(transact={"from": a6})
48 | post_bals = [w3.eth.get_balance(x) for x in [a3, a4, a5, a6]]
49 | assert [y - x for x, y in zip(pre_bals, post_bals)] == [1, 2, 3, 4]
50 |
--------------------------------------------------------------------------------
/tests/examples/name_registry/test_name_registry.py:
--------------------------------------------------------------------------------
1 | def test_name_registry(w3, get_contract, assert_tx_failed):
2 | a0, a1 = w3.eth.accounts[:2]
3 | with open("examples/name_registry/name_registry.vy") as f:
4 | code = f.read()
5 | c = get_contract(code)
6 | c.register(b"jacques", a0, transact={})
7 | assert c.lookup(b"jacques") == a0
8 | assert_tx_failed(lambda: c.register(b"jacques", a1))
9 |
--------------------------------------------------------------------------------
/tests/examples/storage/test_storage.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | INITIAL_VALUE = 4
4 |
5 |
6 | @pytest.fixture
7 | def storage_contract(w3, get_contract):
8 | with open("examples/storage/storage.vy") as f:
9 | contract_code = f.read()
10 | # Pass constructor variables directly to the contract
11 | contract = get_contract(contract_code, INITIAL_VALUE)
12 | return contract
13 |
14 |
15 | def test_initial_state(storage_contract):
16 | # Check if the constructor of the contract is set up properly
17 | assert storage_contract.storedData() == INITIAL_VALUE
18 |
19 |
20 | def test_set(w3, storage_contract):
21 | k0 = w3.eth.accounts[0]
22 |
23 | # Let k0 try to set the value to 10
24 | storage_contract.set(10, transact={"from": k0})
25 | assert storage_contract.storedData() == 10 # Directly access storedData
26 |
27 | # Let k0 try to set the value to -5
28 | storage_contract.set(-5, transact={"from": k0})
29 | assert storage_contract.storedData() == -5
30 |
--------------------------------------------------------------------------------
/tests/fixtures/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/tests/fixtures/__init__.py
--------------------------------------------------------------------------------
/tests/fixtures/memorymock.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.codegen.context import Context
4 | from vyper.codegen.core import get_type_for_exact_size
5 |
6 |
7 | class ContextMock(Context):
8 | def __init__(self, *args, **kwargs):
9 | super().__init__(*args, **kwargs)
10 | self._mock_vars = False
11 | self._size = 0
12 |
13 | def internal_memory_scope(self):
14 | if not self._mock_vars:
15 | for i in range(20):
16 | self._new_variable(
17 | f"#mock{i}", get_type_for_exact_size(self._size), self._size, bool(i % 2)
18 | )
19 | self._mock_vars = True
20 | return super().internal_memory_scope()
21 |
22 | @classmethod
23 | def set_mock_var_size(cls, size):
24 | cls._size = size * 32
25 |
26 |
27 | def pytest_addoption(parser):
28 | parser.addoption("--memorymock", action="store_true", help="Run tests with mock allocated vars")
29 |
30 |
31 | def pytest_generate_tests(metafunc):
32 | if "memory_mocker" in metafunc.fixturenames:
33 | params = range(1, 11, 2) if metafunc.config.getoption("memorymock") else [False]
34 | metafunc.parametrize("memory_mocker", params, indirect=True)
35 |
36 |
37 | def pytest_collection_modifyitems(items, config):
38 | if config.getoption("memorymock"):
39 | for item in list(items):
40 | if "memory_mocker" not in item.fixturenames:
41 | items.remove(item)
42 |
43 | # hacky magic to ensure the correct number of tests is shown in collection report
44 | config.pluginmanager.get_plugin("terminalreporter")._numcollected = len(items)
45 |
46 |
47 | @pytest.fixture
48 | def memory_mocker(monkeypatch, request):
49 | if request.param:
50 | monkeypatch.setattr("vyper.codegen.context.Context", ContextMock)
51 | ContextMock.set_mock_var_size(request.param)
52 |
--------------------------------------------------------------------------------
/tests/functional/codegen/test_tuple_return.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 |
4 | @pytest.mark.parametrize("string", ["a", "abc", "abcde", "potato"])
5 | def test_string_inside_tuple(get_contract, string):
6 | code = f"""
7 | @external
8 | def test_return() -> (String[6], uint256):
9 | return "{string}", 42
10 | """
11 | c1 = get_contract(code)
12 |
13 | code = """
14 | interface jsonabi:
15 | def test_return() -> (String[6], uint256): view
16 |
17 | @external
18 | def test_values(a: address) -> (String[6], uint256):
19 | return jsonabi(a).test_return()
20 | """
21 |
22 | c2 = get_contract(code)
23 | assert c2.test_values(c1.address) == [string, 42]
24 |
25 |
26 | @pytest.mark.parametrize("string", ["a", "abc", "abcde", "potato"])
27 | def test_bytes_inside_tuple(get_contract, string):
28 | code = f"""
29 | @external
30 | def test_return() -> (Bytes[6], uint256):
31 | return b"{string}", 42
32 | """
33 | c1 = get_contract(code)
34 |
35 | code = """
36 | interface jsonabi:
37 | def test_return() -> (Bytes[6], uint256): view
38 |
39 | @external
40 | def test_values(a: address) -> (Bytes[6], uint256):
41 | return jsonabi(a).test_return()
42 | """
43 |
44 | c2 = get_contract(code)
45 | assert c2.test_values(c1.address) == [bytes(string, "utf-8"), 42]
46 |
--------------------------------------------------------------------------------
/tests/functional/semantics/analysis/test_cyclic_function_calls.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.ast import parse_to_ast
4 | from vyper.exceptions import CallViolation, StructureException
5 | from vyper.semantics.analysis import validate_semantics
6 | from vyper.semantics.analysis.module import ModuleAnalyzer
7 |
8 |
9 | def test_self_function_call(namespace):
10 | code = """
11 | @internal
12 | def foo():
13 | self.foo()
14 | """
15 | vyper_module = parse_to_ast(code)
16 | with namespace.enter_scope():
17 | with pytest.raises(CallViolation):
18 | ModuleAnalyzer(vyper_module, {}, namespace)
19 |
20 |
21 | def test_cyclic_function_call(namespace):
22 | code = """
23 | @internal
24 | def foo():
25 | self.bar()
26 |
27 | @internal
28 | def bar():
29 | self.foo()
30 | """
31 | vyper_module = parse_to_ast(code)
32 | with namespace.enter_scope():
33 | with pytest.raises(CallViolation):
34 | ModuleAnalyzer(vyper_module, {}, namespace)
35 |
36 |
37 | def test_multi_cyclic_function_call(namespace):
38 | code = """
39 | @internal
40 | def foo():
41 | self.bar()
42 |
43 | @internal
44 | def bar():
45 | self.baz()
46 |
47 | @internal
48 | def baz():
49 | self.potato()
50 |
51 | @internal
52 | def potato():
53 | self.foo()
54 | """
55 | vyper_module = parse_to_ast(code)
56 | with namespace.enter_scope():
57 | with pytest.raises(CallViolation):
58 | ModuleAnalyzer(vyper_module, {}, namespace)
59 |
60 |
61 | def test_global_ann_assign_callable_no_crash():
62 | code = """
63 | balanceOf: public(HashMap[address, uint256])
64 |
65 | @internal
66 | def foo(to : address):
67 | self.balanceOf(to)
68 | """
69 | vyper_module = parse_to_ast(code)
70 | with pytest.raises(StructureException) as excinfo:
71 | validate_semantics(vyper_module, {})
72 | assert excinfo.value.message == "Value is not callable"
73 |
--------------------------------------------------------------------------------
/tests/functional/semantics/conftest.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import ast as vy_ast
4 | from vyper.semantics.namespace import get_namespace
5 |
6 |
7 | @pytest.fixture(scope="session")
8 | def build_node():
9 | """
10 | Yields a helper function for generating a single Vyper AST node.
11 | """
12 |
13 | def _build_node(source):
14 | # docstring ensures string nodes are properly generated, not turned into docstrings
15 | source = f"""'I am a docstring.'\n{source}"""
16 | ast = vy_ast.parse_to_ast(source).body[0]
17 | if isinstance(ast, vy_ast.Expr):
18 | ast = ast.value
19 | return ast
20 |
21 | yield _build_node
22 |
23 |
24 | @pytest.fixture
25 | def namespace():
26 | """
27 | Yields a clean `Namespace` object.
28 | """
29 | obj = get_namespace()
30 | obj.clear()
31 | yield obj
32 | obj.clear()
33 |
--------------------------------------------------------------------------------
/tests/functional/semantics/types/test_size_in_bytes.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.semantics.types.utils import type_from_annotation
4 |
5 | BASE_TYPES = ["int128", "uint256", "bool", "address", "bytes32"]
6 | BYTESTRING_TYPES = ["String", "Bytes"]
7 |
8 |
9 | @pytest.mark.parametrize("type_str", BASE_TYPES)
10 | def test_base_types(build_node, type_str):
11 | node = build_node(type_str)
12 | type_definition = type_from_annotation(node)
13 |
14 | assert type_definition.size_in_bytes == 32
15 |
16 |
17 | @pytest.mark.parametrize("type_str", BYTESTRING_TYPES)
18 | @pytest.mark.parametrize("length,size", [(1, 64), (32, 64), (33, 96), (86, 128)])
19 | def test_array_value_types(build_node, type_str, length, size):
20 | node = build_node(f"{type_str}[{length}]")
21 | type_definition = type_from_annotation(node)
22 |
23 | assert type_definition.size_in_bytes == size
24 |
25 |
26 | @pytest.mark.parametrize("type_str", BASE_TYPES)
27 | @pytest.mark.parametrize("length", range(1, 4))
28 | def test_dynamic_array_lengths(build_node, type_str, length):
29 | node = build_node(f"DynArray[{type_str}, {length}]")
30 | type_definition = type_from_annotation(node)
31 |
32 | assert type_definition.size_in_bytes == 32 + length * 32
33 |
34 |
35 | @pytest.mark.parametrize("type_str", BASE_TYPES)
36 | @pytest.mark.parametrize("length", range(1, 4))
37 | def test_base_types_as_arrays(build_node, type_str, length):
38 | node = build_node(f"{type_str}[{length}]")
39 | type_definition = type_from_annotation(node)
40 |
41 | assert type_definition.size_in_bytes == length * 32
42 |
43 |
44 | @pytest.mark.parametrize("type_str", BASE_TYPES)
45 | @pytest.mark.parametrize("first", range(1, 4))
46 | @pytest.mark.parametrize("second", range(1, 4))
47 | def test_base_types_as_multidimensional_arrays(build_node, type_str, first, second):
48 | node = build_node(f"{type_str}[{first}][{second}]")
49 |
50 | type_definition = type_from_annotation(node)
51 |
52 | assert type_definition.size_in_bytes == first * second * 32
53 |
--------------------------------------------------------------------------------
/tests/functional/semantics/types/test_type_from_abi.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.exceptions import UnknownType
4 | from vyper.semantics.types import PRIMITIVE_TYPES, SArrayT
5 | from vyper.semantics.types.utils import type_from_abi
6 |
7 | BASE_TYPES = ["int128", "uint256", "bool", "address", "bytes32"]
8 |
9 |
10 | @pytest.mark.parametrize("type_str", BASE_TYPES)
11 | def test_base_types(type_str):
12 | base_t = PRIMITIVE_TYPES[type_str]
13 | type_t = type_from_abi({"type": type_str})
14 |
15 | assert base_t == type_t
16 |
17 |
18 | @pytest.mark.parametrize("type_str", BASE_TYPES)
19 | def test_base_types_as_arrays(type_str):
20 | base_t = PRIMITIVE_TYPES[type_str]
21 | type_t = type_from_abi({"type": f"{type_str}[3]"})
22 |
23 | assert type_t == SArrayT(base_t, 3)
24 |
25 |
26 | @pytest.mark.parametrize("type_str", BASE_TYPES)
27 | def test_base_types_as_multidimensional_arrays(type_str):
28 | base_t = PRIMITIVE_TYPES[type_str]
29 |
30 | type_t = type_from_abi({"type": f"{type_str}[3][5]"})
31 |
32 | assert type_t == SArrayT(SArrayT(base_t, 3), 5)
33 |
34 |
35 | @pytest.mark.parametrize("idx", ["0", "-1", "0x00", "'1'", "foo", "[1]", "(1,)"])
36 | def test_invalid_index(idx):
37 | with pytest.raises(UnknownType):
38 | type_from_abi({"type": f"int128[{idx}]"})
39 |
--------------------------------------------------------------------------------
/tests/parser/ast_utils/test_ast.py:
--------------------------------------------------------------------------------
1 | from vyper.ast.utils import parse_to_ast
2 |
3 |
4 | def test_ast_equal():
5 | code = """
6 | @external
7 | def test() -> int128:
8 | a: uint256 = 100
9 | return 123
10 | """
11 |
12 | ast1 = parse_to_ast(code)
13 | ast2 = parse_to_ast("\n \n" + code + "\n\n")
14 |
15 | assert ast1 == ast2
16 |
17 |
18 | def test_ast_unequal():
19 | code1 = """
20 | @external
21 | def test() -> int128:
22 | a: uint256 = 100
23 | return 123
24 | """
25 | code2 = """
26 | @external
27 | def test() -> int128:
28 | a: uint256 = 100
29 | return 121
30 | """
31 |
32 | ast1 = parse_to_ast(code1)
33 | ast2 = parse_to_ast(code2)
34 |
35 | assert ast1 != ast2
36 |
--------------------------------------------------------------------------------
/tests/parser/exceptions/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/tests/parser/exceptions/__init__.py
--------------------------------------------------------------------------------
/tests/parser/exceptions/test_argument_exception.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import ArgumentException
5 |
6 | fail_list = [
7 | """
8 | @external
9 | def foo():
10 | x = as_wei_value(5, "vader")
11 | """,
12 | """
13 | @external
14 | def foo(x: int128, x: int128): pass
15 | """,
16 | """
17 | @external
18 | def foo(x): pass
19 | """,
20 | """
21 | @external
22 | def foo() -> int128:
23 | return as_wei_value(10)
24 | """,
25 | """
26 | @external
27 | def foo():
28 | x: bytes32 = keccak256("moose", 3)
29 | """,
30 | """
31 | @external
32 | def foo():
33 | x: Bytes[4] = raw_call(0x1234567890123456789012345678901234567890, outsize=4)
34 | """,
35 | """
36 | @external
37 | def foo():
38 | x: Bytes[4] = raw_call(
39 | 0x1234567890123456789012345678901234567890, b"cow", gas=111111, outsize=4, moose=9
40 | )
41 | """,
42 | """
43 | @external
44 | def foo():
45 | x: Bytes[4] = create_minimal_proxy_to(0x1234567890123456789012345678901234567890, outsize=4)
46 | """,
47 | """
48 | x: public()
49 | """,
50 | """
51 | @external
52 | def foo():
53 | raw_log([], b"cow", "dog")
54 | """,
55 | """
56 | @external
57 | def foo():
58 | x: Bytes[10] = concat(b"")
59 | """,
60 | """
61 | @external
62 | def foo():
63 | x: Bytes[4] = create_minimal_proxy_to(0x1234567890123456789012345678901234567890, b"cow")
64 | """,
65 | """
66 | @external
67 | def foo():
68 | a: uint256 = min()
69 | """,
70 | """
71 | @external
72 | def foo():
73 | a: uint256 = min(1)
74 | """,
75 | """
76 | @external
77 | def foo():
78 | a: uint256 = min(1, 2, 3)
79 | """,
80 | """
81 | @external
82 | def foo():
83 | for i in range():
84 | pass
85 | """,
86 | """
87 | @external
88 | def foo():
89 | for i in range(1, 2, 3, 4):
90 | pass
91 | """,
92 | ]
93 |
94 |
95 | @pytest.mark.parametrize("bad_code", fail_list)
96 | def test_function_declaration_exception(bad_code):
97 | with pytest.raises(ArgumentException):
98 | compiler.compile_code(bad_code)
99 |
--------------------------------------------------------------------------------
/tests/parser/exceptions/test_call_violation.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from pytest import raises
3 |
4 | from vyper import compiler
5 | from vyper.exceptions import CallViolation
6 |
7 | call_violation_list = [
8 | """
9 | f:int128
10 |
11 | @external
12 | def a (x:int128)->int128:
13 | self.f = 100
14 | return x+5
15 |
16 | @view
17 | @external
18 | def b():
19 | p: int128 = self.a(10)
20 | """,
21 | """
22 | @external
23 | def goo():
24 | pass
25 |
26 | @internal
27 | def foo():
28 | self.goo()
29 | """,
30 | ]
31 |
32 |
33 | @pytest.mark.parametrize("bad_code", call_violation_list)
34 | def test_call_violation_exception(bad_code):
35 | with raises(CallViolation):
36 | compiler.compile_code(bad_code)
37 |
--------------------------------------------------------------------------------
/tests/parser/exceptions/test_function_declaration_exception.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import FunctionDeclarationException
5 |
6 | fail_list = [
7 | """
8 | x: int128
9 | @external
10 | @const
11 | def foo() -> int128:
12 | pass
13 | """,
14 | """
15 | x: int128
16 | @external
17 | @monkeydoodledoo
18 | def foo() -> int128:
19 | pass
20 | """,
21 | """
22 | def foo() -> int128:
23 | q: int128 = 111
24 | return q
25 | """,
26 | """
27 | q: int128
28 | def foo() -> int128:
29 | return self.q
30 | """,
31 | """
32 | @external
33 | def test_func() -> int128:
34 | return (1, 2)
35 | """,
36 | """
37 | @external
38 | def __init__(a: int128 = 12):
39 | pass
40 | """,
41 | """
42 | @external
43 | def __init__() -> uint256:
44 | return 1
45 | """,
46 | """
47 | @external
48 | def __init__() -> bool:
49 | pass
50 | """,
51 | """
52 | a: immutable(uint256)
53 |
54 | @internal
55 | def __init__():
56 | a = 1
57 | """,
58 | """
59 | a: immutable(uint256)
60 |
61 | @external
62 | @pure
63 | def __init__():
64 | a = 1
65 | """,
66 | """
67 | a: immutable(uint256)
68 |
69 | @external
70 | @view
71 | def __init__():
72 | a = 1
73 | """,
74 | ]
75 |
76 |
77 | @pytest.mark.parametrize("bad_code", fail_list)
78 | def test_function_declaration_exception(bad_code):
79 | with pytest.raises(FunctionDeclarationException):
80 | compiler.compile_code(bad_code)
81 |
--------------------------------------------------------------------------------
/tests/parser/exceptions/test_instantiation_exception.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.exceptions import InstantiationException
4 |
5 | invalid_list = [
6 | """
7 | event Foo:
8 | a: uint256
9 |
10 | @external
11 | def foo() -> Foo:
12 | return Foo(2)
13 | """,
14 | """
15 | event Foo:
16 | a: uint256
17 |
18 | @external
19 | def foo() -> (uint256, Foo):
20 | return 1, Foo(2)
21 | """,
22 | """
23 | a: HashMap[uint256, uint256]
24 |
25 | @external
26 | def foo() -> HashMap[uint256, uint256]:
27 | return self.a
28 | """,
29 | """
30 | event Foo:
31 | a: uint256
32 |
33 | @external
34 | def foo(x: Foo):
35 | pass
36 | """,
37 | """
38 | @external
39 | def foo(x: HashMap[uint256, uint256]):
40 | pass
41 | """,
42 | """
43 | event Foo:
44 | a: uint256
45 |
46 | foo: Foo
47 | """,
48 | """
49 | event Foo:
50 | a: uint256
51 |
52 | @external
53 | def foo():
54 | f: Foo = Foo(1)
55 | pass
56 | """,
57 | """
58 | event Foo:
59 | a: uint256
60 |
61 | b: HashMap[uint256, Foo]
62 | """,
63 | """
64 | event Foo:
65 | a: uint256
66 |
67 | b: HashMap[Foo, uint256]
68 | """,
69 | """
70 | b: immutable(HashMap[uint256, uint256])
71 |
72 | @external
73 | def __init__():
74 | b = empty(HashMap[uint256, uint256])
75 | """,
76 | ]
77 |
78 |
79 | @pytest.mark.parametrize("bad_code", invalid_list)
80 | def test_instantiation_exception(bad_code, get_contract, assert_compile_failed):
81 | assert_compile_failed(lambda: get_contract(bad_code), InstantiationException)
82 |
--------------------------------------------------------------------------------
/tests/parser/exceptions/test_invalid_literal_exception.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from pytest import raises
3 |
4 | from vyper import compiler
5 | from vyper.exceptions import InvalidLiteral
6 |
7 | fail_list = [
8 | """
9 | b: decimal
10 | @external
11 | def foo():
12 | self.b = 7.5178246872145875217495129745982164981654986129846
13 | """,
14 | """
15 | @external
16 | def foo():
17 | x: uint256 = convert(-(-(-1)), uint256)
18 | """,
19 | """
20 | @external
21 | def foo(x: int128):
22 | y: int128 = 7
23 | for i in range(x, x + y):
24 | pass
25 | """,
26 | """
27 | @external
28 | def foo():
29 | x: String[100] = "these bytes are nо gооd because the o's are from the Russian alphabet"
30 | """,
31 | """
32 | @external
33 | def foo():
34 | x: String[100] = "这个傻老外不懂中文"
35 | """,
36 | """
37 | @external
38 | def foo():
39 | a: Bytes[100] = "ѓtest"
40 | """,
41 | """
42 | @external
43 | def foo():
44 | a: bytes32 = keccak256("ѓtest")
45 | """,
46 | ]
47 |
48 |
49 | @pytest.mark.parametrize("bad_code", fail_list)
50 | def test_invalid_literal_exception(bad_code):
51 | with raises(InvalidLiteral):
52 | compiler.compile_code(bad_code)
53 |
--------------------------------------------------------------------------------
/tests/parser/exceptions/test_invalid_payable.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from pytest import raises
3 |
4 | from vyper import compiler
5 | from vyper.exceptions import NonPayableViolation
6 |
7 | fail_list = [
8 | """
9 | @external
10 | def foo():
11 | x: uint256 = msg.value
12 | """
13 | ]
14 |
15 |
16 | @pytest.mark.parametrize("bad_code", fail_list)
17 | def test_variable_decleration_exception(bad_code):
18 | with raises(NonPayableViolation):
19 | compiler.compile_code(bad_code)
20 |
21 |
22 | valid_list = [
23 | """
24 | x: int128
25 | @external
26 | @payable
27 | def foo() -> int128:
28 | self.x = 5
29 | return self.x
30 | """,
31 | """
32 | @external
33 | @payable
34 | def foo():
35 | x: uint256 = msg.value
36 | """,
37 | ]
38 |
39 |
40 | @pytest.mark.parametrize("good_code", valid_list)
41 | def test_block_success(good_code):
42 | assert compiler.compile_code(good_code) is not None
43 |
--------------------------------------------------------------------------------
/tests/parser/exceptions/test_invalid_reference.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import InvalidReference
5 |
6 | fail_list = [
7 | """
8 | x: uint256
9 |
10 | @external
11 | def foo():
12 | send(0x1234567890123456789012345678901234567890, x)
13 | """,
14 | """
15 | @external
16 | def bar(x: int128) -> int128:
17 | return 3 * x
18 |
19 | @external
20 | def foo() -> int128:
21 | return bar(20)
22 | """,
23 | """
24 | b: int128
25 | @external
26 | def foo():
27 | b = 7
28 | """,
29 | """
30 | x: int128
31 | @external
32 | def foo():
33 | x = 5
34 | """,
35 | """
36 | @external
37 | def foo():
38 | int128 = 5
39 | """,
40 | """
41 | a: public(constant(uint256)) = 1
42 |
43 | @external
44 | def foo():
45 | b: uint256 = self.a
46 | """,
47 | """
48 | a: public(immutable(uint256))
49 |
50 | @external
51 | def __init__():
52 | a = 123
53 |
54 | @external
55 | def foo():
56 | b: uint256 = self.a
57 | """,
58 | ]
59 |
60 |
61 | @pytest.mark.parametrize("bad_code", fail_list)
62 | def test_invalid_reference_exception(bad_code):
63 | with pytest.raises(InvalidReference):
64 | compiler.compile_code(bad_code)
65 |
--------------------------------------------------------------------------------
/tests/parser/exceptions/test_invalid_type_exception.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.exceptions import InvalidType, UnknownType
4 |
5 | fail_list = [
6 | """
7 | x: bat
8 | """,
9 | """
10 | x: HashMap[int, int128]
11 | """,
12 | """
13 | struct A:
14 | b: B
15 | """,
16 | ]
17 |
18 |
19 | @pytest.mark.parametrize("bad_code", fail_list)
20 | def test_unknown_type_exception(bad_code, get_contract, assert_compile_failed):
21 | assert_compile_failed(lambda: get_contract(bad_code), UnknownType)
22 |
23 |
24 | invalid_list = [
25 | """
26 | @external
27 | def foo():
28 | raw_log(b"cow", b"dog")
29 | """,
30 | """
31 | @external
32 | def foo():
33 | xs: uint256[1] = []
34 | """,
35 | # Must be a literal string.
36 | """
37 | @external
38 | def mint(_to: address, _value: uint256):
39 | assert msg.sender == self,msg.sender
40 | """,
41 | # literal longer than event member
42 | """
43 | event Foo:
44 | message: String[1]
45 | @external
46 | def foo():
47 | log Foo("abcd")
48 | """,
49 | # Raise reason must be string
50 | """
51 | @external
52 | def mint(_to: address, _value: uint256):
53 | raise 1
54 | """,
55 | """
56 | x: int128[3.5]
57 | """,
58 | # Key of mapping must be a base type
59 | """
60 | b: HashMap[(int128, decimal), int128]
61 | """,
62 | # Address literal must be checksummed
63 | """
64 | a: constant(address) = 0x3cd751e6b0078be393132286c442345e5dc49699
65 | """,
66 | """
67 | x: String <= 33
68 | """,
69 | """
70 | x: Bytes <= wei
71 | """,
72 | """
73 | x: 5
74 | """,
75 | ]
76 |
77 |
78 | @pytest.mark.parametrize("bad_code", invalid_list)
79 | def test_invalid_type_exception(bad_code, get_contract, assert_compile_failed):
80 | assert_compile_failed(lambda: get_contract(bad_code), InvalidType)
81 |
--------------------------------------------------------------------------------
/tests/parser/exceptions/test_namespace_collision.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import NamespaceCollision
5 |
6 | fail_list = [
7 | """
8 | @external
9 | def foo(int128: int128):
10 | pass
11 | """,
12 | """
13 | @external
14 | def foo():
15 | x: int128 = 12
16 | @external
17 | def foo():
18 | y: int128 = 12
19 | """,
20 | """
21 | foo: int128
22 |
23 | @external
24 | def foo():
25 | pass
26 | """,
27 | """
28 | x: int128
29 | x: int128
30 | """,
31 | """
32 | @external
33 | def foo():
34 | x: int128 = 0
35 | x: int128 = 0
36 | """,
37 | """
38 | @external
39 | def foo():
40 | msg: bool = True
41 | """,
42 | """
43 | int128: Bytes[3]
44 | """,
45 | ]
46 |
47 |
48 | @pytest.mark.parametrize("bad_code", fail_list)
49 | def test_insufficient_arguments(bad_code):
50 | with pytest.raises(NamespaceCollision):
51 | compiler.compile_code(bad_code)
52 |
53 |
54 | pass_list = [
55 | """
56 | x: int128
57 |
58 | @external
59 | def foo(x: int128): pass
60 | """,
61 | """
62 | x: int128
63 |
64 | @external
65 | def foo():
66 | x: int128 = 1234
67 | """,
68 | ]
69 |
70 |
71 | @pytest.mark.parametrize("code", pass_list)
72 | def test_valid(code):
73 | compiler.compile_code(code)
74 |
--------------------------------------------------------------------------------
/tests/parser/exceptions/test_overflow_exception.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import OverflowException
5 |
6 | fail_list = [
7 | """
8 | @external
9 | def foo():
10 | x: int256 = -57896044618658097711785492504343953926634992332820282019728792003956564819969 # -2**255 - 1 # noqa: E501
11 | """,
12 | """
13 | @external
14 | def foo():
15 | x: decimal = 18707220957835557353007165858768422651595.9365500928
16 | """,
17 | """
18 | @external
19 | def foo():
20 | x: decimal = -18707220957835557353007165858768422651595.9365500929
21 | """,
22 | """
23 | @external
24 | def foo():
25 | x: uint256 = convert(821649876217461872458712528745872158745214187264875632587324658732648753245328764872135671285218762145, uint256) # noqa: E501
26 | """,
27 | """
28 | @external
29 | def overflow2() -> uint256:
30 | a: uint256 = 2**256
31 | return a
32 | """,
33 | ]
34 |
35 |
36 | @pytest.mark.parametrize("bad_code", fail_list)
37 | def test_invalid_literal_exception(bad_code):
38 | with pytest.raises(OverflowException):
39 | compiler.compile_code(bad_code)
40 |
--------------------------------------------------------------------------------
/tests/parser/exceptions/test_syntax_exception.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.exceptions import SyntaxException
4 |
5 | fail_list = [
6 | """
7 | x: Bytes[1:3]
8 | """,
9 | """
10 | b: int128[int128: address]
11 | """,
12 | """
13 | x: int128[5]
14 | @external
15 | def foo():
16 | self.x[2:4] = 3
17 | """,
18 | """
19 | x: int128[5]
20 | @external
21 | def foo():
22 | z = self.x[2:4]
23 | """,
24 | """
25 | @external
26 | def foo():
27 | x: int128[5]
28 | z = x[2:4]
29 | """,
30 | """
31 | Transfer: event({_rom&: indexed(address)})
32 | """,
33 | """
34 | @external
35 | def test() -> uint256:
36 | for i in range(0, 4):
37 | return 0
38 | else:
39 | return 1
40 | return 1
41 | """,
42 | """
43 | @external
44 | def foo():
45 | x = y = 3
46 | """,
47 | """
48 | @external
49 | def foo():
50 | x: address = create_minimal_proxy_to(0x123456789012345678901234567890123456789)
51 | """,
52 | """
53 | @external
54 | def foo():
55 | x: Bytes[4] = raw_call(0x123456789012345678901234567890123456789, "cow", max_outsize=4)
56 | """,
57 | """
58 | @external
59 | def foo():
60 | x: address = 0x12345678901234567890123456789012345678901
61 | """,
62 | """
63 | @external
64 | def foo():
65 | x: address = 0x01234567890123456789012345678901234567890
66 | """,
67 | """
68 | @external
69 | def foo():
70 | x: address = 0x123456789012345678901234567890123456789
71 | """,
72 | """
73 | a: internal(uint256)
74 | """,
75 | """
76 | @external
77 | def foo():
78 | x: uint256 = +1 # test UAdd ast blocked
79 | """,
80 | """
81 | @internal
82 | def f(a:uint256,/): # test posonlyargs blocked
83 | return
84 |
85 | @external
86 | def g():
87 | self.f()
88 | """,
89 | ]
90 |
91 |
92 | @pytest.mark.parametrize("bad_code", fail_list)
93 | def test_syntax_exception(assert_compile_failed, get_contract, bad_code):
94 | assert_compile_failed(lambda: get_contract(bad_code), SyntaxException)
95 |
--------------------------------------------------------------------------------
/tests/parser/exceptions/test_type_mismatch_exception.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from pytest import raises
3 |
4 | from vyper import compiler
5 | from vyper.exceptions import TypeMismatch
6 |
7 | fail_list = [
8 | """
9 | @external
10 | def foo():
11 | a: uint256 = 3
12 | b: int128 = 4
13 | c: uint256 = min(a, b)
14 | """,
15 | """
16 | @external
17 | def broken():
18 | a : uint256 = 3
19 | b : int128 = 4
20 | c : uint256 = unsafe_add(a, b)
21 | """,
22 | """
23 | @external
24 | def foo():
25 | b: Bytes[1] = b"\x05"
26 | x: uint256 = as_wei_value(b, "babbage")
27 | """,
28 | ]
29 |
30 |
31 | @pytest.mark.parametrize("bad_code", fail_list)
32 | def test_type_mismatch_exception(bad_code):
33 | with raises(TypeMismatch):
34 | compiler.compile_code(bad_code)
35 |
--------------------------------------------------------------------------------
/tests/parser/exceptions/test_undeclared_definition.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import UndeclaredDefinition
5 |
6 | fail_list = [
7 | """
8 | @external
9 | def test1(b: uint256) -> uint256:
10 | a: uint256 = a + b
11 | return a
12 | """,
13 | """
14 | @external
15 | def test2(b: uint256, c: uint256) -> uint256:
16 | a: uint256 = a + b + c
17 | return a
18 | """,
19 | """
20 | @external
21 | def test3(b: int128, c: int128) -> int128:
22 | a: int128 = - a
23 | return a
24 | """,
25 | """
26 | @external
27 | def test4(b: bool) -> bool:
28 | a: bool = b or a
29 | return a
30 | """,
31 | """
32 | @external
33 | def test5(b: bool) -> bool:
34 | a: bool = a != b
35 | return a
36 | """,
37 | """
38 | @external
39 | def test6(b:bool, c: bool) -> bool:
40 | a: bool = (a and b) and c
41 | return a
42 | """,
43 | """
44 | @external
45 | def foo():
46 | throe = 2
47 | """,
48 | """
49 | @external
50 | def foo():
51 | x: int128 = bar(55)
52 | """,
53 | """
54 | @external
55 | def foo():
56 | x = 5
57 | x: int128 = 0
58 | """,
59 | """
60 | @external
61 | def foo():
62 | bork = zork
63 | """,
64 | ]
65 |
66 |
67 | @pytest.mark.parametrize("bad_code", fail_list)
68 | def test_undeclared_def_exception(bad_code):
69 | with pytest.raises(UndeclaredDefinition):
70 | compiler.compile_code(bad_code)
71 |
--------------------------------------------------------------------------------
/tests/parser/exceptions/test_variable_declaration_exception.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import VariableDeclarationException
5 |
6 | fail_list = [
7 | """
8 | q: int128 = 12
9 | @external
10 | def foo() -> int128:
11 | return self.q
12 | """,
13 | """
14 | struct S:
15 | x: int128
16 | s: S = S({x: int128}, 1)
17 | """,
18 | """
19 | struct S:
20 | x: int128
21 | s: S = S()
22 | """,
23 | """
24 | foo.a: int128
25 | """,
26 | """
27 | @external
28 | def foo():
29 | bar.x: int128 = 0
30 | """,
31 | ]
32 |
33 |
34 | @pytest.mark.parametrize("bad_code", fail_list)
35 | def test_variable_declaration_exception(bad_code):
36 | with pytest.raises(VariableDeclarationException):
37 | compiler.compile_code(bad_code)
38 |
--------------------------------------------------------------------------------
/tests/parser/exceptions/test_vyper_exception_pos.py:
--------------------------------------------------------------------------------
1 | from pytest import raises
2 |
3 | from vyper.exceptions import VyperException
4 |
5 |
6 | def test_type_exception_pos():
7 | pos = (1, 2)
8 |
9 | with raises(VyperException) as e:
10 | raise VyperException("Fail!", pos)
11 |
12 | assert e.value.lineno == 1
13 | assert e.value.col_offset == 2
14 | assert str(e.value) == "line 1:2 Fail!"
15 |
16 |
17 | # multiple exceptions in file
18 | def test_multiple_exceptions(get_contract, assert_compile_failed):
19 | code = """
20 | struct A:
21 | b: B # unknown type
22 |
23 | foo: immutable(uint256)
24 | bar: immutable(uint256)
25 | @external
26 | def __init__():
27 | self.foo = 1 # SyntaxException
28 | self.bar = 2 # SyntaxException
29 |
30 | """
31 | assert_compile_failed(lambda: get_contract(code), VyperException)
32 |
--------------------------------------------------------------------------------
/tests/parser/features/arithmetic/test_division.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.exceptions import ZeroDivisionException
4 |
5 | BAD_CODE = [
6 | """
7 | @external
8 | def foo() -> uint256:
9 | return 2 / 0
10 | """,
11 | """
12 | @external
13 | def foo() -> int128:
14 | return -2 / 0
15 | """,
16 | """
17 | @external
18 | def foo() -> decimal:
19 | return 2.22 / 0.0
20 | """,
21 | """
22 | @external
23 | def foo(a: uint256) -> uint256:
24 | return a / 0
25 | """,
26 | """
27 | @external
28 | def foo(a: int128) -> int128:
29 | return a / 0
30 | """,
31 | """
32 | @external
33 | def foo(a: decimal) -> decimal:
34 | return a / 0.0
35 | """,
36 | ]
37 |
38 |
39 | @pytest.mark.parametrize("code", BAD_CODE)
40 | def test_divide_by_zero(code, assert_compile_failed, get_contract):
41 | assert_compile_failed(lambda: get_contract(code), ZeroDivisionException)
42 |
--------------------------------------------------------------------------------
/tests/parser/features/decorators/test_public.py:
--------------------------------------------------------------------------------
1 | from vyper.exceptions import FunctionDeclarationException
2 |
3 |
4 | def test_invalid_if_both_public_and_internal(
5 | assert_compile_failed, get_contract_with_gas_estimation
6 | ):
7 | code = """
8 | @external
9 | @internal
10 | def foo():
11 | x: uint256 = 1
12 | """
13 |
14 | assert_compile_failed(
15 | lambda: get_contract_with_gas_estimation(code), FunctionDeclarationException
16 | )
17 |
18 |
19 | def test_invalid_if_visibility_isnt_declared(
20 | assert_compile_failed, get_contract_with_gas_estimation
21 | ):
22 | code = """
23 | def foo():
24 | x: uint256 = 1
25 | """
26 |
27 | assert_compile_failed(
28 | lambda: get_contract_with_gas_estimation(code), FunctionDeclarationException
29 | )
30 |
--------------------------------------------------------------------------------
/tests/parser/features/decorators/test_view.py:
--------------------------------------------------------------------------------
1 | from vyper.exceptions import FunctionDeclarationException
2 |
3 |
4 | def test_constant_test(get_contract_with_gas_estimation_for_constants):
5 | constant_test = """
6 | @external
7 | @view
8 | def foo() -> int128:
9 | return 5
10 | """
11 |
12 | c = get_contract_with_gas_estimation_for_constants(constant_test)
13 | assert c.foo() == 5
14 |
15 | print("Passed constant function test")
16 |
17 |
18 | def test_invalid_constant_and_payable(
19 | get_contract_with_gas_estimation_for_constants, assert_compile_failed
20 | ):
21 | code = """
22 | @external
23 | @payable
24 | @view
25 | def foo() -> num:
26 | return 5
27 | """
28 | assert_compile_failed(
29 | lambda: get_contract_with_gas_estimation_for_constants(code), FunctionDeclarationException
30 | )
31 |
--------------------------------------------------------------------------------
/tests/parser/features/external_contracts/test_self_call_struct.py:
--------------------------------------------------------------------------------
1 | from decimal import Decimal
2 |
3 |
4 | def test_call_to_self_struct(w3, get_contract):
5 | code = """
6 | struct MyStruct:
7 | e1: decimal
8 | e2: uint256
9 |
10 | @internal
11 | @view
12 | def get_my_struct(_e1: decimal, _e2: uint256) -> MyStruct:
13 | return MyStruct({e1: _e1, e2: _e2})
14 |
15 | @external
16 | @view
17 | def wrap_get_my_struct_WORKING(_e1: decimal) -> MyStruct:
18 | testing: MyStruct = self.get_my_struct(_e1, block.timestamp)
19 | return testing
20 |
21 | @external
22 | @view
23 | def wrap_get_my_struct_BROKEN(_e1: decimal) -> MyStruct:
24 | return self.get_my_struct(_e1, block.timestamp)
25 | """
26 | c = get_contract(code)
27 | assert c.wrap_get_my_struct_WORKING(Decimal("0.1")) == (
28 | Decimal("0.1"),
29 | w3.eth.get_block(w3.eth.block_number)["timestamp"],
30 | )
31 | assert c.wrap_get_my_struct_BROKEN(Decimal("0.1")) == (
32 | Decimal("0.1"),
33 | w3.eth.get_block(w3.eth.block_number)["timestamp"],
34 | )
35 |
36 |
37 | def test_call_to_self_struct_2(get_contract):
38 | code = """
39 | struct MyStruct:
40 | e1: decimal
41 |
42 | @internal
43 | @view
44 | def get_my_struct(_e1: decimal) -> MyStruct:
45 | return MyStruct({e1: _e1})
46 |
47 | @external
48 | @view
49 | def wrap_get_my_struct_WORKING(_e1: decimal) -> MyStruct:
50 | testing: MyStruct = self.get_my_struct(_e1)
51 | return testing
52 |
53 | @external
54 | @view
55 | def wrap_get_my_struct_BROKEN(_e1: decimal) -> MyStruct:
56 | return self.get_my_struct(_e1)
57 | """
58 | c = get_contract(code)
59 | assert c.wrap_get_my_struct_WORKING(Decimal("0.1")) == (Decimal("0.1"),)
60 | assert c.wrap_get_my_struct_BROKEN(Decimal("0.1")) == (Decimal("0.1"),)
61 |
--------------------------------------------------------------------------------
/tests/parser/features/test_address_balance.py:
--------------------------------------------------------------------------------
1 | def test_constant_address_balance(w3, get_contract_with_gas_estimation):
2 | code = """
3 | a: constant(address) = 0x776Ba14735FF84789320718cf0aa43e91F7A8Ce1
4 |
5 | @external
6 | def foo() -> uint256:
7 | x: uint256 = a.balance
8 | return x
9 | """
10 | address = "0x776Ba14735FF84789320718cf0aa43e91F7A8Ce1"
11 |
12 | c = get_contract_with_gas_estimation(code)
13 |
14 | assert c.foo() == 0
15 |
16 | w3.eth.send_transaction({"to": address, "value": 1337})
17 |
18 | assert c.foo() == 1337
19 |
--------------------------------------------------------------------------------
/tests/parser/features/test_assert_unreachable.py:
--------------------------------------------------------------------------------
1 | def test_unreachable_refund(w3, get_contract):
2 | code = """
3 | @external
4 | def foo():
5 | assert msg.sender != msg.sender, UNREACHABLE
6 | """
7 |
8 | c = get_contract(code)
9 | a0 = w3.eth.accounts[0]
10 | gas_sent = 10**6
11 | tx_hash = c.foo(transact={"from": a0, "gas": gas_sent, "gasPrice": 10})
12 | tx_receipt = w3.eth.get_transaction_receipt(tx_hash)
13 |
14 | assert tx_receipt["status"] == 0
15 | assert tx_receipt["gasUsed"] == gas_sent # Drains all gains sent
16 |
17 |
18 | def test_basic_unreachable(w3, get_contract, assert_tx_failed):
19 | code = """
20 | @external
21 | def foo(val: int128) -> bool:
22 | assert val > 0, UNREACHABLE
23 | assert val == 2, UNREACHABLE
24 | return True
25 | """
26 |
27 | c = get_contract(code)
28 |
29 | assert c.foo(2) is True
30 |
31 | assert_tx_failed(lambda: c.foo(1), exc_text="Invalid opcode 0xfe")
32 | assert_tx_failed(lambda: c.foo(-1), exc_text="Invalid opcode 0xfe")
33 | assert_tx_failed(lambda: c.foo(-2), exc_text="Invalid opcode 0xfe")
34 |
35 |
36 | def test_basic_call_unreachable(w3, get_contract, assert_tx_failed):
37 | code = """
38 |
39 | @view
40 | @internal
41 | def _test_me(val: int128) -> bool:
42 | return val == 33
43 |
44 | @external
45 | def foo(val: int128) -> int128:
46 | assert self._test_me(val), UNREACHABLE
47 | return -123
48 | """
49 |
50 | c = get_contract(code)
51 |
52 | assert c.foo(33) == -123
53 |
54 | assert_tx_failed(lambda: c.foo(1), exc_text="Invalid opcode 0xfe")
55 | assert_tx_failed(lambda: c.foo(-1), exc_text="Invalid opcode 0xfe")
56 |
57 |
58 | def test_raise_unreachable(w3, get_contract, assert_tx_failed):
59 | code = """
60 | @external
61 | def foo():
62 | raise UNREACHABLE
63 | """
64 |
65 | c = get_contract(code)
66 |
67 | assert_tx_failed(lambda: c.foo(), exc_text="Invalid opcode 0xfe")
68 |
--------------------------------------------------------------------------------
/tests/parser/features/test_comments.py:
--------------------------------------------------------------------------------
1 | def test_comment_test(get_contract_with_gas_estimation):
2 | comment_test = """
3 | @external
4 | def foo() -> int128:
5 | # Returns 3
6 | return 3
7 | """
8 |
9 | c = get_contract_with_gas_estimation(comment_test)
10 | assert c.foo() == 3
11 | print("Passed comment test")
12 |
--------------------------------------------------------------------------------
/tests/parser/features/test_comparison.py:
--------------------------------------------------------------------------------
1 | # test syntactic comparisons
2 | # most tests under tests/ast/nodes/test_evaluate_compare.py
3 | import pytest
4 |
5 |
6 | def test_3034_verbatim(get_contract):
7 | # test GH issue 3034 exactly
8 | code = """
9 | @view
10 | @external
11 | def showError():
12 | adr1: address = 0xFbEEa1C75E4c4465CB2FCCc9c6d6afe984558E20
13 | adr2: address = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
14 | adr3: address = 0xFbEEa1C75E4c4465CB2FCCc9c6d6afe984558E20
15 | assert adr1 in [adr2,adr3], "error in comparison with in statement!"
16 | """
17 | c = get_contract(code)
18 | c.showError()
19 |
20 |
21 | @pytest.mark.parametrize("invert", (True, False))
22 | def test_in_list(get_contract, invert):
23 | # test slightly more complicated variations of #3034
24 | INVERT = "not" if invert else ""
25 | code = f"""
26 | SOME_ADDRESS: constant(address) = 0x22cb70ba2EC32347D9e32740fc14b2f3d038Ce8E
27 | @view
28 | @external
29 | def test_in(addr: address) -> bool:
30 | x: address = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
31 | y: address = 0xFbEEa1C75E4c4465CB2FCCc9c6d6afe984558E20
32 | # in list which
33 | return addr {INVERT} in [x, y, SOME_ADDRESS]
34 | """
35 | c = get_contract(code)
36 | should_in = [
37 | "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
38 | "0xFbEEa1C75E4c4465CB2FCCc9c6d6afe984558E20",
39 | "0x22cb70ba2EC32347D9e32740fc14b2f3d038Ce8E",
40 | ]
41 | should_not_in = [
42 | "0x" + "00" * 20,
43 | "0xfBeeA1C75E4C4465CB2fccC9C6d6AFe984558e21", # y but last bit flipped
44 | ]
45 | for t in should_in:
46 | assert c.test_in(t) is (True if not invert else False)
47 | for t in should_not_in:
48 | assert c.test_in(t) is (True if invert else False)
49 |
--------------------------------------------------------------------------------
/tests/parser/features/test_conditionals.py:
--------------------------------------------------------------------------------
1 | def test_conditional_return_code(get_contract_with_gas_estimation):
2 | conditional_return_code = """
3 | @external
4 | def foo(i: bool) -> int128:
5 | if i:
6 | return 5
7 | else:
8 | assert 2 != 0
9 | return 7
10 | return 11
11 | """
12 |
13 | c = get_contract_with_gas_estimation(conditional_return_code)
14 | assert c.foo(True) == 5
15 | assert c.foo(False) == 7
16 |
17 | print("Passed conditional return tests")
18 |
19 |
20 | def test_single_branch_underflow_public(get_contract_with_gas_estimation):
21 | code = """
22 | @external
23 | def doit():
24 | if False:
25 | raw_call(msg.sender, b"", max_outsize=0, value=0, gas=msg.gas)
26 | """
27 | c = get_contract_with_gas_estimation(code)
28 | c.doit()
29 |
30 |
31 | def test_single_branch_underflow_private(get_contract_with_gas_estimation):
32 | code = """
33 | @internal
34 | def priv() -> uint256:
35 | return 1
36 |
37 | @external
38 | def dont_doit():
39 | if False:
40 | self.priv()
41 | """
42 | c = get_contract_with_gas_estimation(code)
43 | c.dont_doit()
44 |
--------------------------------------------------------------------------------
/tests/parser/features/test_gas.py:
--------------------------------------------------------------------------------
1 | def test_gas_call(get_contract_with_gas_estimation):
2 | gas_call = """
3 | @external
4 | def foo() -> uint256:
5 | return msg.gas
6 | """
7 |
8 | c = get_contract_with_gas_estimation(gas_call)
9 |
10 | assert c.foo(call={"gas": 50000}) < 50000
11 | assert c.foo(call={"gas": 50000}) > 25000
12 |
--------------------------------------------------------------------------------
/tests/parser/features/test_init.py:
--------------------------------------------------------------------------------
1 | import vyper
2 |
3 |
4 | def test_basic_init_function(get_contract):
5 | code = """
6 | val: public(uint256)
7 |
8 | @external
9 | def __init__(a: uint256):
10 | self.val = a
11 | """
12 |
13 | c = get_contract(code, *[123])
14 |
15 | assert c.val() == 123
16 |
17 | # Make sure the init code does not access calldata
18 | assembly = vyper.compile_code(code, ["asm"])["asm"].split(" ")
19 | ir_return_idx_start = assembly.index("{")
20 | ir_return_idx_end = assembly.index("}")
21 |
22 | assert "CALLDATALOAD" in assembly
23 | assert "CALLDATACOPY" not in assembly[:ir_return_idx_start] + assembly[ir_return_idx_end:]
24 | assert "CALLDATALOAD" not in assembly[:ir_return_idx_start] + assembly[ir_return_idx_end:]
25 |
26 |
27 | def test_init_calls_internal(get_contract, assert_compile_failed, assert_tx_failed):
28 | code = """
29 | foo: public(uint8)
30 | @internal
31 | def bar(x: uint256) -> uint8:
32 | return convert(x, uint8) * 7
33 | @external
34 | def __init__(a: uint256):
35 | self.foo = self.bar(a)
36 |
37 | @external
38 | def baz() -> uint8:
39 | return self.bar(convert(self.foo, uint256))
40 | """
41 | n = 5
42 | c = get_contract(code, n)
43 | assert c.foo() == n * 7
44 | assert c.baz() == 245 # 5*7*7
45 |
46 | n = 6
47 | c = get_contract(code, n)
48 | assert c.foo() == n * 7
49 | assert_tx_failed(lambda: c.baz())
50 |
51 | n = 255
52 | assert_compile_failed(lambda: get_contract(code, n))
53 |
54 | n = 256
55 | assert_compile_failed(lambda: get_contract(code, n))
56 |
57 |
58 | # GH issue 3206
59 | def test_nested_internal_call_from_ctor(get_contract):
60 | code = """
61 | x: uint256
62 |
63 | @external
64 | def __init__():
65 | self.a()
66 |
67 | @internal
68 | def a():
69 | self.x += 1
70 | self.b()
71 |
72 | @internal
73 | def b():
74 | self.x += 2
75 |
76 | @external
77 | def test() -> uint256:
78 | return self.x
79 | """
80 | c = get_contract(code)
81 | assert c.test() == 3
82 |
--------------------------------------------------------------------------------
/tests/parser/features/test_memory_dealloc.py:
--------------------------------------------------------------------------------
1 | def test_memory_deallocation(get_contract):
2 | code = """
3 | event Shimmy:
4 | a: indexed(address)
5 | b: uint256
6 |
7 | interface Other:
8 | def sendit(): nonpayable
9 |
10 | @external
11 | def foo(target: address) -> uint256[2]:
12 | log Shimmy(ZERO_ADDRESS, 3)
13 | amount: uint256 = 1
14 | flargen: uint256 = 42
15 | Other(target).sendit()
16 | return [amount, flargen]
17 | """
18 |
19 | code2 = """
20 |
21 | @external
22 | def sendit() -> bool:
23 | return True
24 | """
25 |
26 | c = get_contract(code)
27 | c2 = get_contract(code2)
28 |
29 | assert c.foo(c2.address) == [1, 42]
30 |
--------------------------------------------------------------------------------
/tests/parser/features/test_packing.py:
--------------------------------------------------------------------------------
1 | def test_packing_test(get_contract_with_gas_estimation, memory_mocker):
2 | packing_test = """
3 | struct Bar:
4 | a: int128
5 | b: int128
6 | struct Z:
7 | foo: int128[3]
8 | bar: Bar[2]
9 | x: int128
10 | y: int128[5]
11 | z: Z
12 | a: int128
13 |
14 | @external
15 | def foo() -> int128:
16 | self.x = 1
17 | self.y[0] = 2
18 | self.y[4] = 4
19 | self.z.foo[0] = 8
20 | self.z.foo[2] = 16
21 | self.z.bar[0].a = 32
22 | self.z.bar[0].b = 64
23 | self.z.bar[1].a = 128
24 | self.z.bar[1].b = 256
25 | self.a = 512
26 | return self.x + self.y[0] + self.y[4] + self.z.foo[0] + self.z.foo[2] + \
27 | self.z.bar[0].a + self.z.bar[0].b + self.z.bar[1].a + self.z.bar[1].b + self.a
28 |
29 | @external
30 | def fop() -> int128:
31 | _x: int128 = 0
32 | _y: int128[5] = [0, 0, 0, 0, 0]
33 | _z: Z = Z({foo: [0, 0, 0], bar: [Bar({a: 0, b: 0}), Bar({a: 0, b: 0})]})
34 | _a: int128 = 0
35 | _x = 1
36 | _y[0] = 2
37 | _y[4] = 4
38 | _z.foo[0] = 8
39 | _z.foo[2] = 16
40 | _z.bar[0].a = 32
41 | _z.bar[0].b = 64
42 | _z.bar[1].a = 128
43 | _z.bar[1].b = 256
44 | _a = 512
45 | return _x + _y[0] + _y[4] + _z.foo[0] + _z.foo[2] + \
46 | _z.bar[0].a + _z.bar[0].b + _z.bar[1].a + _z.bar[1].b + _a
47 | """
48 |
49 | c = get_contract_with_gas_estimation(packing_test)
50 | assert c.foo() == 1023, c.foo()
51 | assert c.fop() == 1023, c.fop()
52 | print("Passed packing test")
53 |
--------------------------------------------------------------------------------
/tests/parser/features/test_reverting.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from eth.codecs import abi
3 | from eth_tester.exceptions import TransactionFailed
4 |
5 | from vyper.utils import method_id
6 |
7 | pytestmark = pytest.mark.usefixtures("memory_mocker")
8 |
9 |
10 | def test_revert_reason(w3, assert_tx_failed, get_contract_with_gas_estimation):
11 | reverty_code = """
12 | @external
13 | def foo():
14 | data: Bytes[4] = method_id("NoFives()")
15 | raw_revert(data)
16 | """
17 |
18 | revert_bytes = method_id("NoFives()")
19 |
20 | assert_tx_failed(
21 | lambda: get_contract_with_gas_estimation(reverty_code).foo(transact={}),
22 | TransactionFailed,
23 | exc_text=f"execution reverted: {revert_bytes}",
24 | )
25 |
26 |
27 | def test_revert_reason_typed(w3, assert_tx_failed, get_contract_with_gas_estimation):
28 | reverty_code = """
29 | @external
30 | def foo():
31 | val: uint256 = 5
32 | data: Bytes[100] = _abi_encode(val, method_id=method_id("NoFives(uint256)"))
33 | raw_revert(data)
34 | """
35 |
36 | revert_bytes = method_id("NoFives(uint256)") + abi.encode("(uint256)", (5,))
37 |
38 | assert_tx_failed(
39 | lambda: get_contract_with_gas_estimation(reverty_code).foo(transact={}),
40 | TransactionFailed,
41 | exc_text=f"execution reverted: {revert_bytes}",
42 | )
43 |
44 |
45 | def test_revert_reason_typed_no_variable(w3, assert_tx_failed, get_contract_with_gas_estimation):
46 | reverty_code = """
47 | @external
48 | def foo():
49 | val: uint256 = 5
50 | raw_revert(_abi_encode(val, method_id=method_id("NoFives(uint256)")))
51 | """
52 |
53 | revert_bytes = method_id("NoFives(uint256)") + abi.encode("(uint256)", (5,))
54 |
55 | assert_tx_failed(
56 | lambda: get_contract_with_gas_estimation(reverty_code).foo(transact={}),
57 | TransactionFailed,
58 | exc_text=f"execution reverted: {revert_bytes}",
59 | )
60 |
--------------------------------------------------------------------------------
/tests/parser/features/test_string_map_keys.py:
--------------------------------------------------------------------------------
1 | def test_string_map_keys(get_contract):
2 | code = """
3 | f:HashMap[String[1], bool]
4 | @external
5 | def test() -> bool:
6 | a:String[1] = "a"
7 | b:String[1] = "b"
8 | self.f[a] = True
9 | return self.f[b] # should return False
10 | """
11 | c = get_contract(code)
12 | c.test()
13 | assert c.test() is False
14 |
15 |
16 | def test_string_map_keys_literals(get_contract):
17 | code = """
18 | f:HashMap[String[1], bool]
19 | @external
20 | def test() -> bool:
21 | self.f["a"] = True
22 | return self.f["b"] # should return False
23 | """
24 | c = get_contract(code)
25 | assert c.test() is False
26 |
--------------------------------------------------------------------------------
/tests/parser/functions/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/tests/parser/functions/__init__.py
--------------------------------------------------------------------------------
/tests/parser/functions/test_as_wei_value.py:
--------------------------------------------------------------------------------
1 | def test_ext_call(w3, side_effects_contract, assert_side_effects_invoked, get_contract):
2 | code = """
3 | @external
4 | def foo(a: Foo) -> uint256:
5 | return as_wei_value(a.foo(7), "ether")
6 |
7 | interface Foo:
8 | def foo(x: uint8) -> uint8: nonpayable
9 | """
10 |
11 | c1 = side_effects_contract("uint8")
12 | c2 = get_contract(code)
13 |
14 | assert c2.foo(c1.address) == w3.to_wei(7, "ether")
15 | assert_side_effects_invoked(c1, lambda: c2.foo(c1.address, transact={}))
16 |
17 |
18 | def test_internal_call(w3, get_contract_with_gas_estimation):
19 | code = """
20 | @external
21 | def foo() -> uint256:
22 | return as_wei_value(self.bar(), "ether")
23 |
24 | @internal
25 | def bar() -> uint8:
26 | return 7
27 | """
28 |
29 | c = get_contract_with_gas_estimation(code)
30 |
31 | assert c.foo() == w3.to_wei(7, "ether")
32 |
--------------------------------------------------------------------------------
/tests/parser/functions/test_block.py:
--------------------------------------------------------------------------------
1 | def test_blockhash(get_contract_with_gas_estimation, w3):
2 | w3.testing.mine(1)
3 |
4 | block_number_code = """
5 | @external
6 | def prev() -> bytes32:
7 | return block.prevhash
8 |
9 | @external
10 | def previous_blockhash() -> bytes32:
11 | return blockhash(block.number - 1)
12 | """
13 | c = get_contract_with_gas_estimation(block_number_code)
14 | assert c.prev() == c.previous_blockhash()
15 |
16 |
17 | def test_negative_blockhash(assert_compile_failed, get_contract_with_gas_estimation):
18 | code = """
19 | @external
20 | def foo() -> bytes32:
21 | return blockhash(-1)
22 | """
23 | assert_compile_failed(lambda: get_contract_with_gas_estimation(code))
24 |
25 |
26 | def test_too_old_blockhash(assert_tx_failed, get_contract_with_gas_estimation, w3):
27 | w3.testing.mine(257)
28 | code = """
29 | @external
30 | def get_50_blockhash() -> bytes32:
31 | return blockhash(block.number - 257)
32 | """
33 | c = get_contract_with_gas_estimation(code)
34 | assert_tx_failed(lambda: c.get_50_blockhash())
35 |
36 |
37 | def test_non_existing_blockhash(assert_tx_failed, get_contract_with_gas_estimation):
38 | code = """
39 | @external
40 | def get_future_blockhash() -> bytes32:
41 | return blockhash(block.number + 1)
42 | """
43 | c = get_contract_with_gas_estimation(code)
44 | assert_tx_failed(lambda: c.get_future_blockhash())
45 |
--------------------------------------------------------------------------------
/tests/parser/functions/test_block_number.py:
--------------------------------------------------------------------------------
1 | def test_block_number(get_contract_with_gas_estimation, w3):
2 | block_number_code = """
3 | @external
4 | def block_number() -> uint256:
5 | return block.number
6 | """
7 | c = get_contract_with_gas_estimation(block_number_code)
8 |
9 | assert c.block_number() == 1
10 | w3.testing.mine(1)
11 | assert c.block_number() == 2
12 |
--------------------------------------------------------------------------------
/tests/parser/functions/test_is_contract.py:
--------------------------------------------------------------------------------
1 | def test_is_contract(w3, get_contract_with_gas_estimation):
2 | contract_1 = """
3 | @external
4 | def foo(arg1: address) -> bool:
5 | result: bool = arg1.is_contract
6 | return result
7 | """
8 |
9 | contract_2 = """
10 | @external
11 | def foo(arg1: address) -> bool:
12 | return arg1.is_contract
13 | """
14 | a0, a1 = w3.eth.accounts[:2]
15 | c1 = get_contract_with_gas_estimation(contract_1)
16 | c2 = get_contract_with_gas_estimation(contract_2)
17 |
18 | assert c1.foo(c1.address) is True
19 | assert c1.foo(c2.address) is True
20 | assert c1.foo(a1) is False
21 | assert c1.foo(a0) is False
22 | assert c2.foo(c1.address) is True
23 | assert c2.foo(c2.address) is True
24 | assert c2.foo(a1) is False
25 | assert c2.foo(a0) is False
26 |
--------------------------------------------------------------------------------
/tests/parser/functions/test_length.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 |
4 | def test_test_length(get_contract_with_gas_estimation):
5 | test_length = """
6 | y: Bytes[10]
7 |
8 | @external
9 | def foo(inp: Bytes[10]) -> uint256:
10 | x: Bytes[5] = slice(inp,1, 5)
11 | self.y = slice(inp, 2, 4)
12 | return len(inp) * 100 + len(x) * 10 + len(self.y)
13 | """
14 |
15 | c = get_contract_with_gas_estimation(test_length)
16 | assert c.foo(b"badminton") == 954, c.foo(b"badminton")
17 | print("Passed length test")
18 |
19 |
20 | @pytest.mark.parametrize("typ", ["DynArray[uint256, 50]", "Bytes[50]", "String[50]"])
21 | def test_zero_length(get_contract_with_gas_estimation, typ):
22 | code = f"""
23 | @external
24 | def boo() -> uint256:
25 | e: uint256 = len(empty({typ}))
26 | return e
27 | """
28 |
29 | c = get_contract_with_gas_estimation(code)
30 | assert c.boo() == 0
31 |
--------------------------------------------------------------------------------
/tests/parser/functions/test_method_id.py:
--------------------------------------------------------------------------------
1 | def test_method_id_test(get_contract_with_gas_estimation):
2 | method_id_test = """
3 | @external
4 | def double(x: int128) -> int128:
5 | return x * 2
6 |
7 | @external
8 | def returnten() -> int128:
9 | ans: Bytes[32] = raw_call(self, concat(method_id("double(int128)"), convert(5, bytes32)), gas=50000, max_outsize=32) # noqa: E501
10 | return convert(convert(ans, bytes32), int128)
11 | """
12 | c = get_contract_with_gas_estimation(method_id_test)
13 | assert c.returnten() == 10
14 |
15 |
16 | def test_method_id_bytes4(get_contract):
17 | code = """
18 | @external
19 | def sig() -> bytes4:
20 | return method_id('transfer(address,uint256)', output_type=bytes4)
21 | """
22 | c = get_contract(code)
23 | sig = c.sig()
24 |
25 | assert sig == b"\xa9\x05\x9c\xbb"
26 |
27 |
28 | def test_method_id_Bytes4(get_contract):
29 | code = """
30 | @external
31 | def sig() -> Bytes[4]:
32 | return method_id('transfer(address,uint256)', output_type=Bytes[4])
33 | """
34 | c = get_contract(code)
35 | sig = c.sig()
36 |
37 | # assert len(sig) == 4
38 | assert sig == b"\xa9\x05\x9c\xbb"
39 |
40 |
41 | def test_method_id_bytes4_default(get_contract):
42 | code = """
43 | @external
44 | def sig() -> Bytes[4]:
45 | return method_id('transfer(address,uint256)')
46 | """
47 | c = get_contract(code)
48 | sig = c.sig()
49 |
50 | # assert len(sig) == 4
51 | assert sig == b"\xa9\x05\x9c\xbb"
52 |
53 |
54 | def test_method_id_invalid_space(get_contract, assert_compile_failed):
55 | code = """
56 | @external
57 | def sig() -> bytes4:
58 | return method_id('transfer(address, uint256)', output_type=bytes4)
59 | """
60 | assert_compile_failed(lambda: get_contract(code))
61 |
62 |
63 | def test_method_id_invalid_type(get_contract, assert_compile_failed):
64 | code = """
65 | @external
66 | def sig() -> bytes32:
67 | return method_id('transfer(address,uint256)', output_type=bytes32)
68 | """
69 | assert_compile_failed(lambda: get_contract(code))
70 |
--------------------------------------------------------------------------------
/tests/parser/functions/test_minmax_value.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.exceptions import InvalidType, OverflowException
4 | from vyper.semantics.types import DecimalT, IntegerT
5 | from vyper.semantics.types.shortcuts import INT256_T, UINT256_T
6 |
7 |
8 | @pytest.mark.parametrize("typ", sorted(IntegerT.all() + (DecimalT(),)))
9 | @pytest.mark.parametrize("op", ("min_value", "max_value"))
10 | def test_minmax_value(get_contract, op, typ):
11 | code = f"""
12 | @external
13 | def foo() -> {typ}:
14 | return {op}({typ})
15 | """
16 | c = get_contract(code)
17 |
18 | lo, hi = typ.ast_bounds
19 | if op == "min_value":
20 | assert c.foo() == lo
21 | elif op == "max_value":
22 | assert c.foo() == hi
23 |
24 |
25 | @pytest.mark.parametrize("typ", sorted(IntegerT.all()))
26 | def test_minmax_value_int_oob(get_contract, assert_compile_failed, typ):
27 | upper = f"""
28 | @external
29 | def foo():
30 | a: {typ} = max_value({typ}) + 1
31 | """
32 |
33 | lower = f"""
34 | @external
35 | def foo():
36 | a: {typ} = min_value({typ}) - 1
37 | """
38 |
39 | if typ == UINT256_T:
40 | assert_compile_failed(lambda: get_contract(upper), OverflowException)
41 | else:
42 | assert_compile_failed(lambda: get_contract(upper), InvalidType)
43 |
44 | if typ == INT256_T:
45 | assert_compile_failed(lambda: get_contract(lower), OverflowException)
46 | else:
47 | assert_compile_failed(lambda: get_contract(lower), InvalidType)
48 |
49 |
50 | @pytest.mark.parametrize("typ", [DecimalT()])
51 | def test_minmax_value_decimal_oob(get_contract, assert_compile_failed, typ):
52 | upper = f"""
53 | @external
54 | def foo():
55 | a: {typ} = max_value({typ}) + 1e-10
56 | """
57 |
58 | lower = f"""
59 | @external
60 | def foo():
61 | a: {typ} = min_value({typ}) - 1e-10
62 | """
63 |
64 | assert_compile_failed(lambda: get_contract(upper), OverflowException)
65 | assert_compile_failed(lambda: get_contract(lower), OverflowException)
66 |
--------------------------------------------------------------------------------
/tests/parser/functions/test_mkstr.py:
--------------------------------------------------------------------------------
1 | import math
2 |
3 | import pytest
4 |
5 | VALID_BITS = list(range(8, 257, 8))
6 |
7 |
8 | @pytest.mark.parametrize("bits", VALID_BITS)
9 | def test_mkstr(get_contract_with_gas_estimation, bits):
10 | n_digits = math.ceil(bits * math.log(2) / math.log(10))
11 | code = f"""
12 | @external
13 | def foo(inp: uint{bits}) -> String[{n_digits}]:
14 | return uint2str(inp)
15 | """
16 |
17 | c = get_contract_with_gas_estimation(code)
18 | for i in [1, 2, 2**bits - 1, 0]:
19 | assert c.foo(i) == str(i), (i, c.foo(i))
20 |
21 |
22 | # test for buffer overflow
23 | @pytest.mark.parametrize("bits", VALID_BITS)
24 | def test_mkstr_buffer(get_contract, bits):
25 | n_digits = math.ceil(bits * math.log(2) / math.log(10))
26 | code = f"""
27 | some_string: String[{n_digits}]
28 | @internal
29 | def _foo(x: uint{bits}):
30 | self.some_string = uint2str(x)
31 |
32 | @external
33 | def foo(x: uint{bits}) -> uint256:
34 | y: uint256 = 0
35 | self._foo(x)
36 | return y
37 | """
38 | c = get_contract(code)
39 | assert c.foo(2**bits - 1) == 0, bits
40 |
--------------------------------------------------------------------------------
/tests/parser/functions/test_return.py:
--------------------------------------------------------------------------------
1 | def test_correct_abi_right_padding(tester, w3, get_contract_with_gas_estimation):
2 | selfcall_code_6 = """
3 | @external
4 | def hardtest(arg1: Bytes[64], arg2: Bytes[64]) -> Bytes[128]:
5 | return concat(arg1, arg2)
6 | """
7 |
8 | c = get_contract_with_gas_estimation(selfcall_code_6)
9 |
10 | assert c.hardtest(b"hello" * 5, b"hello" * 10) == b"hello" * 15
11 |
12 | # Make sure underlying structe is correctly right padded
13 | classic_contract = c._classic_contract
14 | func = classic_contract.functions.hardtest(b"hello" * 5, b"hello" * 10)
15 | tx = func.build_transaction({"gasPrice": 0})
16 | del tx["chainId"]
17 | del tx["gasPrice"]
18 |
19 | tx["from"] = w3.eth.accounts[0]
20 | res = w3.to_bytes(hexstr=tester.call(tx))
21 |
22 | static_offset = int.from_bytes(res[:32], "big")
23 | assert static_offset == 32
24 |
25 | dyn_section = res[static_offset:]
26 | assert len(dyn_section) % 32 == 0 # first right pad assert
27 |
28 | len_value = int.from_bytes(dyn_section[:32], "big")
29 |
30 | assert len_value == len(b"hello" * 15)
31 | assert dyn_section[32 : 32 + len_value] == b"hello" * 15
32 | # second right pad assert
33 | assert dyn_section[32 + len_value :] == b"\x00" * (len(dyn_section) - 32 - len_value)
34 |
--------------------------------------------------------------------------------
/tests/parser/functions/test_sha256.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 |
3 | import pytest
4 |
5 | pytestmark = pytest.mark.usefixtures("memory_mocker")
6 |
7 |
8 | def test_sha256_string_literal(get_contract_with_gas_estimation):
9 | code = """
10 | @external
11 | def bar() -> bytes32:
12 | return sha256("test")
13 | """
14 |
15 | c = get_contract_with_gas_estimation(code)
16 |
17 | assert c.bar() == hashlib.sha256(b"test").digest()
18 |
19 |
20 | def test_sha256_literal_bytes(get_contract_with_gas_estimation):
21 | code = """
22 | @external
23 | def bar() -> (bytes32 , bytes32):
24 | x: bytes32 = sha256("test")
25 | y: bytes32 = sha256(b"test")
26 | return x, y
27 | """
28 | c = get_contract_with_gas_estimation(code)
29 | h = hashlib.sha256(b"test").digest()
30 | assert c.bar() == [h, h]
31 |
32 |
33 | def test_sha256_bytes32(get_contract_with_gas_estimation):
34 | code = """
35 | @external
36 | def bar(a: bytes32) -> bytes32:
37 | return sha256(a)
38 | """
39 |
40 | c = get_contract_with_gas_estimation(code)
41 |
42 | test_val = 8 * b"bBaA"
43 | assert c.bar(test_val) == hashlib.sha256(test_val).digest()
44 |
45 |
46 | def test_sha256_bytearraylike(get_contract_with_gas_estimation):
47 | code = """
48 | @external
49 | def bar(a: String[100]) -> bytes32:
50 | return sha256(a)
51 | """
52 |
53 | c = get_contract_with_gas_estimation(code)
54 |
55 | test_val = "test me! test me!"
56 | assert c.bar(test_val) == hashlib.sha256(test_val.encode()).digest()
57 | test_val = "fun"
58 | assert c.bar(test_val) == hashlib.sha256(test_val.encode()).digest()
59 |
60 |
61 | def test_sha256_bytearraylike_storage(get_contract_with_gas_estimation):
62 | code = """
63 | a: public(Bytes[100])
64 |
65 | @external
66 | def set(b: Bytes[100]):
67 | self.a = b
68 |
69 | @external
70 | def bar() -> bytes32:
71 | return sha256(self.a)
72 | """
73 |
74 | c = get_contract_with_gas_estimation(code)
75 |
76 | test_val = b"test me! test me!"
77 | c.set(test_val, transact={})
78 | assert c.a() == test_val
79 | assert c.bar() == hashlib.sha256(test_val).digest()
80 |
--------------------------------------------------------------------------------
/tests/parser/functions/test_tx.py:
--------------------------------------------------------------------------------
1 | def test_tx_gasprice(get_contract):
2 | code = """
3 | @external
4 | def tx_gasprice() -> uint256:
5 | return tx.gasprice
6 | """
7 | c = get_contract(code)
8 | for i in range(10):
9 | assert c.tx_gasprice(call={"gasPrice": 10**i}) == 10**i
10 |
--------------------------------------------------------------------------------
/tests/parser/globals/test_globals.py:
--------------------------------------------------------------------------------
1 | from pytest import raises
2 |
3 | from vyper.exceptions import UndeclaredDefinition
4 |
5 |
6 | def test_permanent_variables_test(get_contract_with_gas_estimation):
7 | permanent_variables_test = """
8 | struct Var:
9 | a: int128
10 | b: int128
11 | var: Var
12 |
13 | @external
14 | def __init__(a: int128, b: int128):
15 | self.var.a = a
16 | self.var.b = b
17 |
18 | @external
19 | def returnMoose() -> int128:
20 | return self.var.a * 10 + self.var.b
21 | """
22 |
23 | c = get_contract_with_gas_estimation(permanent_variables_test, *[5, 7])
24 | assert c.returnMoose() == 57
25 | print("Passed init argument and variable member test")
26 |
27 |
28 | def test_missing_global(get_contract):
29 | code = """
30 | @external
31 | def a() -> int128:
32 | return self.b
33 | """
34 |
35 | with raises(UndeclaredDefinition):
36 | get_contract(code)
37 |
--------------------------------------------------------------------------------
/tests/parser/integration/test_basics.py:
--------------------------------------------------------------------------------
1 | def test_null_code(get_contract_with_gas_estimation):
2 | null_code = """
3 | @external
4 | def foo():
5 | pass
6 | """
7 | c = get_contract_with_gas_estimation(null_code)
8 | c.foo()
9 |
10 |
11 | def test_basic_code(get_contract_with_gas_estimation):
12 | basic_code = """
13 | @external
14 | def foo(x: int128) -> int128:
15 | return x * 2
16 |
17 | """
18 | c = get_contract_with_gas_estimation(basic_code)
19 | assert c.foo(9) == 18
20 |
--------------------------------------------------------------------------------
/tests/parser/integration/test_escrow.py:
--------------------------------------------------------------------------------
1 | # from ethereum.tools import tester
2 |
3 |
4 | def test_arbitration_code(w3, get_contract_with_gas_estimation, assert_tx_failed):
5 | arbitration_code = """
6 | buyer: address
7 | seller: address
8 | arbitrator: address
9 |
10 | @external
11 | def setup(_seller: address, _arbitrator: address):
12 | if self.buyer == ZERO_ADDRESS:
13 | self.buyer = msg.sender
14 | self.seller = _seller
15 | self.arbitrator = _arbitrator
16 |
17 | @external
18 | def finalize():
19 | assert msg.sender == self.buyer or msg.sender == self.arbitrator
20 | send(self.seller, self.balance)
21 |
22 | @external
23 | def refund():
24 | assert msg.sender == self.seller or msg.sender == self.arbitrator
25 | send(self.buyer, self.balance)
26 |
27 | """
28 | a0, a1, a2 = w3.eth.accounts[:3]
29 | c = get_contract_with_gas_estimation(arbitration_code, value=1)
30 | c.setup(a1, a2, transact={})
31 | assert_tx_failed(lambda: c.finalize(transact={"from": a1}))
32 | c.finalize(transact={})
33 |
34 | print("Passed escrow test")
35 |
36 |
37 | def test_arbitration_code_with_init(w3, assert_tx_failed, get_contract_with_gas_estimation):
38 | arbitration_code_with_init = """
39 | buyer: address
40 | seller: address
41 | arbitrator: address
42 |
43 | @external
44 | @payable
45 | def __init__(_seller: address, _arbitrator: address):
46 | if self.buyer == ZERO_ADDRESS:
47 | self.buyer = msg.sender
48 | self.seller = _seller
49 | self.arbitrator = _arbitrator
50 |
51 | @external
52 | def finalize():
53 | assert msg.sender == self.buyer or msg.sender == self.arbitrator
54 | send(self.seller, self.balance)
55 |
56 | @external
57 | def refund():
58 | assert msg.sender == self.seller or msg.sender == self.arbitrator
59 | send(self.buyer, self.balance)
60 | """
61 | a0, a1, a2 = w3.eth.accounts[:3]
62 | c = get_contract_with_gas_estimation(arbitration_code_with_init, *[a1, a2], value=1)
63 | assert_tx_failed(lambda: c.finalize(transact={"from": a1}))
64 | c.finalize(transact={"from": a0})
65 |
66 | print("Passed escrow test with initializer")
67 |
--------------------------------------------------------------------------------
/tests/parser/parser_utils/test_annotate_and_optimize_ast.py:
--------------------------------------------------------------------------------
1 | import ast as python_ast
2 |
3 | from vyper.ast.annotation import annotate_python_ast
4 | from vyper.ast.pre_parser import pre_parse
5 |
6 |
7 | class AssertionVisitor(python_ast.NodeVisitor):
8 | def assert_about_node(self, node):
9 | raise AssertionError()
10 |
11 | def generic_visit(self, node):
12 | self.assert_about_node(node)
13 |
14 | super().generic_visit(node)
15 |
16 |
17 | TEST_CONTRACT_SOURCE_CODE = """
18 | struct S:
19 | a: bool
20 | b: int128
21 |
22 | interface ERC20Contract:
23 | def name() -> String[64]: view
24 |
25 | @external
26 | def foo() -> int128:
27 | return -(-(-1))
28 | """
29 |
30 |
31 | def get_contract_info(source_code):
32 | _, class_types, reformatted_code = pre_parse(source_code)
33 | py_ast = python_ast.parse(reformatted_code)
34 |
35 | annotate_python_ast(py_ast, reformatted_code, class_types)
36 |
37 | return py_ast, reformatted_code
38 |
39 |
40 | def test_it_annotates_ast_with_source_code():
41 | contract_ast, reformatted_code = get_contract_info(TEST_CONTRACT_SOURCE_CODE)
42 |
43 | class AssertSourceCodePresent(AssertionVisitor):
44 | def assert_about_node(self, node):
45 | assert node.full_source_code is reformatted_code
46 |
47 | AssertSourceCodePresent().visit(contract_ast)
48 |
49 |
50 | def test_it_annotates_ast_with_class_types():
51 | contract_ast, _ = get_contract_info(TEST_CONTRACT_SOURCE_CODE)
52 |
53 | struct_def = contract_ast.body[0]
54 | contract_def = contract_ast.body[1]
55 |
56 | assert struct_def.ast_type == "StructDef"
57 | assert contract_def.ast_type == "InterfaceDef"
58 |
59 |
60 | def test_it_rewrites_unary_subtractions():
61 | contract_ast, _ = get_contract_info(TEST_CONTRACT_SOURCE_CODE)
62 |
63 | function_def = contract_ast.body[2]
64 | return_stmt = function_def.body[0]
65 |
66 | assert isinstance(return_stmt.value, python_ast.Num)
67 | assert return_stmt.value.n == -1
68 |
--------------------------------------------------------------------------------
/tests/parser/syntax/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/tests/parser/syntax/__init__.py
--------------------------------------------------------------------------------
/tests/parser/syntax/test_addmulmod.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.exceptions import InvalidType
4 |
5 | fail_list = [
6 | ( # bad AST nodes given as arguments
7 | """
8 | @external
9 | def foo() -> uint256:
10 | return uint256_addmod(1.1, 1.2, 3.0)
11 | """,
12 | InvalidType,
13 | ),
14 | ( # bad AST nodes given as arguments
15 | """
16 | @external
17 | def foo() -> uint256:
18 | return uint256_mulmod(1.1, 1.2, 3.0)
19 | """,
20 | InvalidType,
21 | ),
22 | ]
23 |
24 |
25 | @pytest.mark.parametrize("code,exc", fail_list)
26 | def test_add_mod_fail(assert_compile_failed, get_contract, code, exc):
27 | assert_compile_failed(lambda: get_contract(code), exc)
28 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_as_uint256.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import InvalidType, TypeMismatch
5 |
6 | fail_list = [
7 | (
8 | """
9 | @external
10 | def convert2(inp: uint256) -> uint256:
11 | return convert(inp, bytes32)
12 | """,
13 | TypeMismatch,
14 | ),
15 | (
16 | """
17 | @external
18 | def modtest(x: uint256, y: int128) -> uint256:
19 | return x % y
20 | """,
21 | TypeMismatch,
22 | ),
23 | (
24 | """
25 | @internal
26 | def ret_non():
27 | pass
28 |
29 | @external
30 | def test():
31 | a: uint256 = 100 * self.ret_non()
32 | """,
33 | InvalidType,
34 | ),
35 | ]
36 |
37 |
38 | @pytest.mark.parametrize("bad_code,exc", fail_list)
39 | def test_as_uint256_fail(bad_code, exc):
40 | with pytest.raises(exc):
41 | compiler.compile_code(bad_code)
42 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_as_wei_value.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.exceptions import ArgumentException, InvalidType, StructureException
4 |
5 | fail_list = [
6 | (
7 | """
8 | @external
9 | def foo():
10 | x: int128 = as_wei_value(5, szabo)
11 | """,
12 | ArgumentException,
13 | ),
14 | (
15 | """
16 | @external
17 | def foo() -> int128:
18 | x: int128 = 45
19 | return x.balance
20 | """,
21 | StructureException,
22 | ),
23 | (
24 | """
25 | @external
26 | def foo():
27 | x: int128 = as_wei_value(0xf5, "szabo")
28 | """,
29 | InvalidType,
30 | ),
31 | ]
32 |
33 |
34 | @pytest.mark.parametrize("bad_code,exc", fail_list)
35 | def test_as_wei_fail(get_contract_with_gas_estimation, bad_code, exc, assert_compile_failed):
36 | assert_compile_failed(lambda: get_contract_with_gas_estimation(bad_code), exc)
37 |
38 |
39 | valid_list = [
40 | """
41 | @external
42 | def foo():
43 | x: uint256 = as_wei_value(5, "finney") + as_wei_value(2, "babbage") + as_wei_value(8, "shannon") # noqa: E501
44 | """,
45 | """
46 | @external
47 | def foo():
48 | z: int128 = 2 + 3
49 | x: uint256 = as_wei_value(2 + 3, "finney")
50 | """,
51 | """
52 | @external
53 | def foo():
54 | x: uint256 = as_wei_value(5.182, "babbage")
55 | """,
56 | """
57 | @external
58 | def foo() -> uint256:
59 | x: address = 0x1234567890123456789012345678901234567890
60 | return x.balance
61 | """,
62 | ]
63 |
64 |
65 | @pytest.mark.parametrize("good_code", valid_list)
66 | def test_as_wei_success(good_code, get_contract_with_gas_estimation):
67 | assert get_contract_with_gas_estimation(good_code) is not None
68 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_bool_ops.py:
--------------------------------------------------------------------------------
1 | def test_convert_from_bool(get_contract_with_gas_estimation):
2 | code = """
3 | @external
4 | def foo() -> bool:
5 | val: bool = True and True and False
6 | return val
7 |
8 | @external
9 | def bar() -> bool:
10 | val: bool = True or True or False
11 | return val
12 |
13 | @external
14 | def foobar() -> bool:
15 | val: bool = False and True or False
16 | return val
17 |
18 | @external
19 | def oof() -> bool:
20 | val: bool = False or False or False or False or False or True
21 | return val
22 |
23 | @external
24 | def rab() -> bool:
25 | val: bool = True and True and True and True and True and False
26 | return val
27 |
28 | @external
29 | def oofrab() -> bool:
30 | val: bool = False and True or False and True or False and False or True
31 | return val
32 | """
33 |
34 | c = get_contract_with_gas_estimation(code)
35 | assert c.foo() is False
36 | assert c.bar() is True
37 | assert c.foobar() is False
38 | assert c.oof() is True
39 | assert c.rab() is False
40 | assert c.oofrab() is True
41 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_code_size.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import StructureException
5 |
6 | fail_list = [
7 | """
8 | @external
9 | def foo() -> int128:
10 | x: int128 = 45
11 | return x.codesize
12 | """
13 | ]
14 |
15 |
16 | @pytest.mark.parametrize("bad_code", fail_list)
17 | def test_block_fail(bad_code):
18 | with pytest.raises(StructureException):
19 | compiler.compile_code(bad_code)
20 |
21 |
22 | valid_list = [
23 | """
24 | @external
25 | def foo() -> uint256:
26 | x: address = 0x1234567890123456789012345678901234567890
27 | return x.codesize
28 | """,
29 | """
30 | @external
31 | def foo() -> uint256:
32 | return self.codesize
33 | """,
34 | """
35 | struct Foo:
36 | t: address
37 | foo: Foo
38 |
39 | @external
40 | def bar() -> uint256:
41 | return self.foo.t.codesize
42 | """,
43 | ]
44 |
45 |
46 | @pytest.mark.parametrize("good_code", valid_list)
47 | def test_block_success(good_code):
48 | assert compiler.compile_code(good_code) is not None
49 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_codehash.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.compiler import compile_code
4 | from vyper.compiler.settings import Settings
5 | from vyper.evm.opcodes import EVM_VERSIONS
6 | from vyper.utils import keccak256
7 |
8 |
9 | @pytest.mark.parametrize("evm_version", list(EVM_VERSIONS))
10 | def test_get_extcodehash(get_contract, evm_version, optimize):
11 | code = """
12 | a: address
13 |
14 | @external
15 | def __init__():
16 | self.a = self
17 |
18 | @external
19 | def foo(x: address) -> bytes32:
20 | return x.codehash
21 |
22 | @external
23 | def foo2(x: address) -> bytes32:
24 | b: address = x
25 | return b.codehash
26 |
27 | @external
28 | def foo3() -> bytes32:
29 | return self.codehash
30 |
31 | @external
32 | def foo4() -> bytes32:
33 | return self.a.codehash
34 | """
35 | settings = Settings(evm_version=evm_version, optimize=optimize)
36 | compiled = compile_code(code, ["bytecode_runtime"], settings=settings)
37 | bytecode = bytes.fromhex(compiled["bytecode_runtime"][2:])
38 | hash_ = keccak256(bytecode)
39 |
40 | c = get_contract(code, evm_version=evm_version)
41 |
42 | assert c.foo(c.address) == hash_
43 | assert not int(c.foo("0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF").hex(), 16)
44 |
45 | assert c.foo2(c.address) == hash_
46 | assert not int(c.foo2("0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF").hex(), 16)
47 |
48 | assert c.foo3() == hash_
49 | assert c.foo4() == hash_
50 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_conditionals.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 |
5 | valid_list = [
6 | """
7 | @internal
8 | def mkint() -> int128:
9 | return 1
10 |
11 | @external
12 | def test_zerovalent():
13 | if True:
14 | self.mkint()
15 |
16 | @external
17 | def test_valency_mismatch():
18 | if True:
19 | self.mkint()
20 | else:
21 | pass
22 | """
23 | ]
24 |
25 |
26 | @pytest.mark.parametrize("good_code", valid_list)
27 | def test_conditional_return_code(good_code):
28 | assert compiler.compile_code(good_code) is not None
29 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_create_with_code_of.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from pytest import raises
3 |
4 | from vyper import compiler
5 | from vyper.exceptions import ArgumentException, SyntaxException
6 |
7 | fail_list = [
8 | """
9 | @external
10 | def foo():
11 | x: address = create_minimal_proxy_to(
12 | 0x1234567890123456789012345678901234567890,
13 | value=4,
14 | value=9
15 | )
16 | """,
17 | """
18 | @external
19 | def foo(_salt: bytes32):
20 | x: address = create_minimal_proxy_to(
21 | 0x1234567890123456789012345678901234567890, salt=keccak256(b"Vyper Rocks!"), salt=_salt
22 | )
23 | """,
24 | ]
25 |
26 |
27 | @pytest.mark.parametrize("bad_code", fail_list)
28 | def test_type_mismatch_exception(bad_code):
29 | with raises((SyntaxException, ArgumentException)):
30 | compiler.compile_code(bad_code)
31 |
32 |
33 | valid_list = [
34 | """
35 | @external
36 | def foo():
37 | # test that create_forwarder_to is valid syntax; the name is deprecated
38 | x: address = create_forwarder_to(0x1234567890123456789012345678901234567890)
39 | """,
40 | """
41 | @external
42 | def foo():
43 | x: address = create_minimal_proxy_to(0x1234567890123456789012345678901234567890)
44 | """,
45 | """
46 | @external
47 | def foo():
48 | x: address = create_minimal_proxy_to(
49 | 0x1234567890123456789012345678901234567890,
50 | value=as_wei_value(9, "wei")
51 | )
52 | """,
53 | """
54 | @external
55 | def foo():
56 | x: address = create_minimal_proxy_to(0x1234567890123456789012345678901234567890, value=9)
57 | """,
58 | """
59 | @external
60 | def foo():
61 | x: address = create_minimal_proxy_to(
62 | 0x1234567890123456789012345678901234567890,
63 | salt=keccak256(b"Vyper Rocks!")
64 | )
65 | """,
66 | """
67 | @external
68 | def foo(_salt: bytes32):
69 | x: address = create_minimal_proxy_to(0x1234567890123456789012345678901234567890, salt=_salt)
70 | """,
71 | ]
72 |
73 |
74 | @pytest.mark.parametrize("good_code", valid_list)
75 | def test_rlp_success(good_code):
76 | assert compiler.compile_code(good_code) is not None
77 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_dynamic_array.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import StructureException
5 |
6 | fail_list = [
7 | (
8 | """
9 | foo: DynArray[HashMap[uint8, uint8], 2]
10 | """,
11 | StructureException,
12 | ),
13 | (
14 | """
15 | foo: public(DynArray[HashMap[uint8, uint8], 2])
16 | """,
17 | StructureException,
18 | ),
19 | (
20 | """
21 | @external
22 | def foo():
23 | a: DynArray = [1, 2, 3]
24 | """,
25 | StructureException,
26 | ),
27 | ]
28 |
29 |
30 | @pytest.mark.parametrize("bad_code,exc", fail_list)
31 | def test_block_fail(assert_compile_failed, get_contract, bad_code, exc):
32 | assert_compile_failed(lambda: get_contract(bad_code), exc)
33 |
34 |
35 | valid_list = [
36 | """
37 | enum Foo:
38 | FE
39 | FI
40 |
41 | bar: DynArray[Foo, 10]
42 | """, # dynamic arrays of enums are allowed, but not static arrays
43 | """
44 | bar: DynArray[Bytes[30], 10]
45 | """, # dynamic arrays of bytestrings are allowed, but not static arrays
46 | ]
47 |
48 |
49 | @pytest.mark.parametrize("good_code", valid_list)
50 | def test_dynarray_pass(good_code):
51 | assert compiler.compile_code(good_code) is not None
52 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_for_range.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import StructureException
5 |
6 | fail_list = [
7 | (
8 | """
9 | @external
10 | def foo():
11 | for a[1] in range(10):
12 | pass
13 | """,
14 | StructureException,
15 | ),
16 | (
17 | """
18 | @external
19 | def bar():
20 | for i in range(1,2,bound=2):
21 | pass
22 | """,
23 | StructureException,
24 | ),
25 | (
26 | """
27 | @external
28 | def bar():
29 | x:uint256 = 1
30 | for i in range(x,x+1,bound=2):
31 | pass
32 | """,
33 | StructureException,
34 | ),
35 | ]
36 |
37 |
38 | @pytest.mark.parametrize("bad_code", fail_list)
39 | def test_range_fail(bad_code):
40 | with pytest.raises(bad_code[1]):
41 | compiler.compile_code(bad_code[0])
42 |
43 |
44 | valid_list = [
45 | """
46 | @external
47 | def foo():
48 | for i in range(10):
49 | pass
50 | """,
51 | """
52 | @external
53 | def foo():
54 | for i in range(10, 20):
55 | pass
56 | """,
57 | """
58 | @external
59 | def foo():
60 | x: int128 = 5
61 | for i in range(x, x + 10):
62 | pass
63 | """,
64 | """
65 | interface Foo:
66 | def kick(): nonpayable
67 | foos: Foo[3]
68 | @external
69 | def kick_foos():
70 | for foo in self.foos:
71 | foo.kick()
72 | """,
73 | ]
74 |
75 |
76 | @pytest.mark.parametrize("good_code", valid_list)
77 | def test_range_success(good_code):
78 | assert compiler.compile_code(good_code) is not None
79 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_functions_call.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import StructureException, UndeclaredDefinition, UnknownAttribute
5 |
6 | fail_list = [
7 | (
8 | """
9 | @external
10 | def foo() -> uint256:
11 | doesnotexist(2, uint256)
12 | return convert(2, uint256)
13 | """,
14 | UndeclaredDefinition,
15 | ),
16 | (
17 | """
18 | @external
19 | def foo(x: int256) -> uint256:
20 | convert(x, uint256)
21 | return convert(x, uint256)
22 |
23 | """,
24 | StructureException,
25 | ),
26 | (
27 | """
28 | @internal
29 | def test(a : uint256):
30 | pass
31 |
32 |
33 | @external
34 | def burn(_value: uint256):
35 | self.test(msg.sender._value)
36 | """,
37 | UnknownAttribute,
38 | ),
39 | ]
40 |
41 |
42 | @pytest.mark.parametrize("bad_code,exc", fail_list)
43 | def test_functions_call_fail(bad_code, exc):
44 | with pytest.raises(exc):
45 | compiler.compile_code(bad_code)
46 |
47 |
48 | valid_list = [
49 | """
50 | @external
51 | def foo(x: int128) -> uint256:
52 | return convert(x, uint256)
53 | """,
54 | """
55 | from vyper.interfaces import ERC20
56 |
57 | interface Factory:
58 | def getExchange(token_addr: address) -> address: view
59 |
60 | token: ERC20
61 | factory: Factory
62 |
63 | @external
64 | def setup(token_addr: address):
65 | self.token = ERC20(token_addr)
66 | assert self.factory.getExchange(self.token.address) == self
67 | """,
68 | ]
69 |
70 |
71 | @pytest.mark.parametrize("good_code", valid_list)
72 | def test_functions_call_success(good_code):
73 | assert compiler.compile_code(good_code) is not None
74 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_keccak256.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import InvalidType, UndeclaredDefinition
5 |
6 | type_fail_list = [
7 | """
8 | @external
9 | def foo():
10 | x: bytes32 = keccak256(3)
11 | """
12 | ]
13 |
14 |
15 | @pytest.mark.parametrize("bad_code", type_fail_list)
16 | def test_block_type_fail(bad_code):
17 | with pytest.raises(InvalidType):
18 | compiler.compile_code(bad_code)
19 |
20 |
21 | structure_fail_list = [
22 | """
23 | @external
24 | def foo():
25 | x: bytes32 = sha3("moose")
26 | """,
27 | """
28 | @external
29 | def foo():
30 | x: bytes32 = sha3(0x1234567890123456789012345678901234567890123456789012345678901234)
31 | """,
32 | ]
33 |
34 |
35 | @pytest.mark.parametrize("bad_code", structure_fail_list)
36 | def test_block_structure_fail(bad_code):
37 | with pytest.raises(UndeclaredDefinition):
38 | compiler.compile_code(bad_code)
39 |
40 |
41 | valid_list = [
42 | """
43 | @external
44 | def foo():
45 | x: bytes32 = keccak256("moose")
46 | """,
47 | """
48 | @external
49 | def foo():
50 | x: bytes32 = keccak256(0x1234567890123456789012345678901234567890123456789012345678901234)
51 | """,
52 | ]
53 |
54 |
55 | @pytest.mark.parametrize("good_code", valid_list)
56 | def test_block_success(good_code):
57 | assert compiler.compile_code(good_code) is not None
58 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_len.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from pytest import raises
3 |
4 | from vyper import compiler
5 | from vyper.exceptions import TypeMismatch
6 |
7 | fail_list = [
8 | """
9 | @external
10 | def foo(inp: Bytes[4]) -> int128:
11 | return len(inp)
12 | """,
13 | """
14 | @external
15 | def foo(inp: int128) -> uint256:
16 | return len(inp)
17 | """,
18 | ]
19 |
20 |
21 | @pytest.mark.parametrize("bad_code", fail_list)
22 | def test_block_fail(bad_code):
23 | if isinstance(bad_code, tuple):
24 | with raises(bad_code[1]):
25 | compiler.compile_code(bad_code[0])
26 | else:
27 | with raises(TypeMismatch):
28 | compiler.compile_code(bad_code)
29 |
30 |
31 | valid_list = [
32 | """
33 | @external
34 | def foo(inp: Bytes[10]) -> uint256:
35 | return len(inp)
36 | """,
37 | """
38 | @external
39 | def foo(inp: String[10]) -> uint256:
40 | return len(inp)
41 | """,
42 | ]
43 |
44 |
45 | @pytest.mark.parametrize("good_code", valid_list)
46 | def test_list_success(good_code):
47 | assert compiler.compile_code(good_code) is not None
48 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_logging.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import InvalidType, StructureException, TypeMismatch
5 |
6 | fail_list = [
7 | """
8 | event Bar:
9 | _value: int128[4]
10 |
11 | x: decimal[4]
12 |
13 | @external
14 | def foo():
15 | log Bar(self.x)
16 | """,
17 | """
18 | event Bar:
19 | _value: int128[4]
20 |
21 | @external
22 | def foo():
23 | x: decimal[4] = [0.0, 0.0, 0.0, 0.0]
24 | log Bar(x)
25 | """,
26 | (
27 | """
28 | event Test:
29 | n: uint256
30 |
31 | @external
32 | def test():
33 | log Test(-7)
34 | """,
35 | InvalidType,
36 | ),
37 | ]
38 |
39 |
40 | @pytest.mark.parametrize("bad_code", fail_list)
41 | def test_logging_fail(bad_code):
42 | if isinstance(bad_code, tuple):
43 | with pytest.raises(bad_code[1]):
44 | compiler.compile_code(bad_code[0])
45 | else:
46 | with pytest.raises(TypeMismatch):
47 | compiler.compile_code(bad_code)
48 |
49 |
50 | @pytest.mark.parametrize("mutability", ["@pure", "@view"])
51 | @pytest.mark.parametrize("visibility", ["@internal", "@external"])
52 | def test_logging_from_non_mutable(mutability, visibility):
53 | code = f"""
54 | event Test:
55 | n: uint256
56 |
57 | {visibility}
58 | {mutability}
59 | def test():
60 | log Test(1)
61 | """
62 | with pytest.raises(StructureException):
63 | compiler.compile_code(code)
64 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_minmax.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.exceptions import InvalidType, TypeMismatch
4 |
5 | fail_list = [
6 | (
7 | """
8 | @external
9 | def foo():
10 | y: int128 = min(7, 0x1234567890123456789012345678901234567890)
11 | """,
12 | InvalidType,
13 | ),
14 | (
15 | """
16 | @external
17 | def foo():
18 | a: int16 = min(min_value(int16), max_value(int8))
19 | """,
20 | TypeMismatch,
21 | ),
22 | ]
23 |
24 |
25 | @pytest.mark.parametrize("bad_code,exc", fail_list)
26 | def test_block_fail(assert_compile_failed, get_contract_with_gas_estimation, bad_code, exc):
27 | assert_compile_failed(lambda: get_contract_with_gas_estimation(bad_code), exc)
28 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_minmax_value.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper.exceptions import InvalidType
4 |
5 | fail_list = [
6 | """
7 | @external
8 | def foo():
9 | a: address = min_value(address)
10 | """,
11 | """
12 | @external
13 | def foo():
14 | a: address = max_value(address)
15 | """,
16 | ]
17 |
18 |
19 | @pytest.mark.parametrize("bad_code", fail_list)
20 | def test_block_fail(assert_compile_failed, get_contract_with_gas_estimation, bad_code):
21 | assert_compile_failed(lambda: get_contract_with_gas_estimation(bad_code), InvalidType)
22 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_nested_list.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import InvalidLiteral, InvalidType, TypeMismatch
5 |
6 | fail_list = [
7 | (
8 | """
9 | bar: int128[3][3]
10 | @external
11 | def foo():
12 | self.bar = [[1, 2], [3, 4, 5], [6, 7, 8]]
13 | """,
14 | InvalidType, # casting darray to sarray
15 | ),
16 | (
17 | """
18 | bar: int128[3][3]
19 | @external
20 | def foo():
21 | self.bar = [[1, 2, 3], [4, 5, 6], [7.0, 8.0, 9.0]]
22 | """,
23 | InvalidLiteral,
24 | ),
25 | (
26 | """
27 | @external
28 | def foo() -> int128[2]:
29 | return [[1,2],[3,4]]
30 | """,
31 | InvalidType,
32 | ),
33 | (
34 | """
35 | @external
36 | def foo() -> int128[2][2]:
37 | return [1,2]
38 | """,
39 | InvalidType,
40 | ),
41 | (
42 | """
43 | y: address[2][2]
44 |
45 | @external
46 | def foo(x: int128[2][2]) -> int128:
47 | self.y = x
48 | return 768
49 | """,
50 | TypeMismatch,
51 | ),
52 | ]
53 |
54 |
55 | @pytest.mark.parametrize("bad_code,exc", fail_list)
56 | def test_nested_list_fail(bad_code, exc):
57 | with pytest.raises(exc):
58 | compiler.compile_code(bad_code)
59 |
60 |
61 | valid_list = [
62 | """
63 | bar: int128[3][3]
64 | @external
65 | def foo():
66 | self.bar = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
67 | """,
68 | """
69 | bar: decimal[3][3]
70 | @external
71 | def foo():
72 | self.bar = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]
73 | """,
74 | ]
75 |
76 |
77 | @pytest.mark.parametrize("good_code", valid_list)
78 | def test_nested_list_sucess(good_code):
79 | assert compiler.compile_code(good_code) is not None
80 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_print.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 |
5 | valid_list = [
6 | """
7 | @external
8 | def foo(x: uint256):
9 | print(x)
10 | """,
11 | """
12 | @external
13 | def foo(x: Bytes[1]):
14 | print(x)
15 | """,
16 | """
17 | struct Foo:
18 | x: Bytes[128]
19 | @external
20 | def foo(foo: Foo):
21 | print(foo)
22 | """,
23 | """
24 | struct Foo:
25 | x: uint256
26 | @external
27 | def foo(foo: Foo):
28 | print(foo)
29 | """,
30 | """
31 | BAR: constant(DynArray[uint256, 5]) = [1, 2, 3, 4, 5]
32 |
33 | @external
34 | def foo():
35 | print(BAR)
36 | """,
37 | """
38 | FOO: constant(uint256) = 1
39 | BAR: constant(DynArray[uint256, 5]) = [1, 2, 3, 4, 5]
40 |
41 | @external
42 | def foo():
43 | print(FOO, BAR)
44 | """,
45 | ]
46 |
47 |
48 | @pytest.mark.parametrize("good_code", valid_list)
49 | def test_print_syntax(good_code):
50 | assert compiler.compile_code(good_code) is not None
51 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_public.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 |
5 | valid_list = [
6 | """
7 | x: public(int128)
8 | """,
9 | """
10 | x: public(constant(int128)) = 0
11 | y: public(immutable(int128))
12 |
13 | @external
14 | def __init__():
15 | y = 0
16 | """,
17 | """
18 | x: public(int128)
19 | y: public(int128)
20 | z: public(int128)
21 |
22 | @external
23 | def foo() -> int128:
24 | return self.x / self.y / self.z
25 | """,
26 | # expansion of public user-defined struct
27 | """
28 | struct Foo:
29 | a: uint256
30 |
31 | x: public(HashMap[uint256, Foo])
32 | """,
33 | # expansion of public user-defined enum
34 | """
35 | enum Foo:
36 | BAR
37 |
38 | x: public(HashMap[uint256, Foo])
39 | """,
40 | # expansion of public user-defined interface
41 | """
42 | interface Foo:
43 | def bar(): nonpayable
44 |
45 | x: public(HashMap[uint256, Foo])
46 | """,
47 | ]
48 |
49 |
50 | @pytest.mark.parametrize("good_code", valid_list)
51 | def test_public_success(good_code):
52 | assert compiler.compile_code(good_code) is not None
53 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_self_balance.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.compiler.settings import Settings
5 | from vyper.evm.opcodes import EVM_VERSIONS
6 |
7 |
8 | @pytest.mark.parametrize("evm_version", list(EVM_VERSIONS))
9 | def test_self_balance(w3, get_contract_with_gas_estimation, evm_version):
10 | code = """
11 | @external
12 | @view
13 | def get_balance() -> uint256:
14 | a: uint256 = self.balance
15 | return a
16 |
17 | @external
18 | @payable
19 | def __default__():
20 | pass
21 | """
22 | settings = Settings(evm_version=evm_version)
23 | opcodes = compiler.compile_code(code, ["opcodes"], settings=settings)["opcodes"]
24 | if EVM_VERSIONS[evm_version] >= EVM_VERSIONS["istanbul"]:
25 | assert "SELFBALANCE" in opcodes
26 | else:
27 | assert "SELFBALANCE" not in opcodes
28 |
29 | c = get_contract_with_gas_estimation(code, evm_version=evm_version)
30 | w3.eth.send_transaction({"to": c.address, "value": 1337})
31 |
32 | assert c.get_balance() == 1337
33 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_selfdestruct.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import InvalidType
5 |
6 | fail_list = [
7 | """
8 | @external
9 | def foo():
10 | selfdestruct(7)
11 | """
12 | ]
13 |
14 |
15 | @pytest.mark.parametrize("bad_code", fail_list)
16 | def test_block_fail(bad_code):
17 | with pytest.raises(InvalidType):
18 | compiler.compile_code(bad_code)
19 |
20 |
21 | valid_list = [
22 | """
23 | @external
24 | def foo():
25 | selfdestruct(0x1234567890123456789012345678901234567890)
26 | """
27 | ]
28 |
29 |
30 | @pytest.mark.parametrize("good_code", valid_list)
31 | def test_block_success(good_code):
32 | assert compiler.compile_code(good_code) is not None
33 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_slice.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import InvalidType, TypeMismatch
5 |
6 | fail_list = [
7 | (
8 | """
9 | @external
10 | def foo(inp: Bytes[10]) -> Bytes[2]:
11 | return slice(inp, 2, 3)
12 | """,
13 | TypeMismatch,
14 | ),
15 | (
16 | """
17 | @external
18 | def foo(inp: int128) -> Bytes[3]:
19 | return slice(inp, 2, 3)
20 | """,
21 | TypeMismatch,
22 | ),
23 | (
24 | """
25 | @external
26 | def foo(inp: Bytes[10]) -> Bytes[3]:
27 | return slice(inp, 4.0, 3)
28 | """,
29 | InvalidType,
30 | ),
31 | ]
32 |
33 |
34 | @pytest.mark.parametrize("bad_code,exc", fail_list)
35 | def test_slice_fail(bad_code, exc):
36 | with pytest.raises(exc):
37 | compiler.compile_code(bad_code)
38 |
39 |
40 | valid_list = [
41 | """
42 | @external
43 | def foo(inp: Bytes[10]) -> Bytes[3]:
44 | return slice(inp, 2, 3)
45 | """,
46 | """
47 | @external
48 | def foo(inp: Bytes[10]) -> Bytes[4]:
49 | return slice(inp, 2, 3)
50 | """,
51 | """
52 | @external
53 | def foo() -> Bytes[10]:
54 | return slice(b"badmintonzzz", 1, 10)
55 | """,
56 | ]
57 |
58 |
59 | @pytest.mark.parametrize("good_code", valid_list)
60 | def test_slice_success(good_code):
61 | assert compiler.compile_code(good_code) is not None
62 |
--------------------------------------------------------------------------------
/tests/parser/syntax/test_string.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import StructureException
5 |
6 | valid_list = [
7 | """
8 | @external
9 | def foo() -> String[10]:
10 | return "badminton"
11 | """,
12 | """
13 | @external
14 | def foo():
15 | x: String[11] = "¡très bien!"
16 | """,
17 | """
18 | @external
19 | def foo() -> bool:
20 | x: String[15] = "¡très bien!"
21 | y: String[15] = "test"
22 | return x != y
23 | """,
24 | """
25 | @external
26 | def foo() -> bool:
27 | x: String[15] = "¡très bien!"
28 | y: String[12] = "test"
29 | return x != y
30 | """,
31 | """
32 | @external
33 | def test() -> String[100]:
34 | return "hello world!"
35 | """,
36 | ]
37 |
38 |
39 | @pytest.mark.parametrize("good_code", valid_list)
40 | def test_string_success(good_code):
41 | assert compiler.compile_code(good_code) is not None
42 |
43 |
44 | invalid_list = [
45 | (
46 | """
47 | @external
48 | def foo():
49 | a: String = "abc"
50 | """,
51 | StructureException,
52 | )
53 | ]
54 |
55 |
56 | @pytest.mark.parametrize("bad_code,exc", invalid_list)
57 | def test_string_fail(assert_compile_failed, get_contract_with_gas_estimation, bad_code, exc):
58 | assert_compile_failed(lambda: get_contract_with_gas_estimation(bad_code), exc)
59 |
--------------------------------------------------------------------------------
/tests/parser/syntax/utils/test_variable_names.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from pytest import raises
3 |
4 | from vyper import compiler
5 | from vyper.exceptions import NamespaceCollision, StructureException
6 |
7 | fail_list = [ # noqa: E122
8 | """
9 | @external
10 | def foo(i: int128) -> int128:
11 | varő : int128 = i
12 | return varő
13 | """,
14 | """
15 | @external
16 | def foo(i: int128) -> int128:
17 | wei : int128 = i
18 | return wei
19 | """,
20 | """
21 | @external
22 | def foo(i: int128) -> int128:
23 | false : int128 = i
24 | return false
25 | """,
26 | ]
27 |
28 |
29 | @pytest.mark.parametrize("bad_code", fail_list)
30 | def test_varname_validity_fail(bad_code):
31 | with raises(StructureException):
32 | compiler.compile_code(bad_code)
33 |
34 |
35 | collision_fail_list = [
36 | """
37 | @external
38 | def foo(i: int128) -> int128:
39 | int128 : int128 = i
40 | return int128
41 | """,
42 | """
43 | @external
44 | def foo(i: int128) -> int128:
45 | decimal : int128 = i
46 | return decimal
47 | """,
48 | ]
49 |
50 |
51 | @pytest.mark.parametrize("bad_code", collision_fail_list)
52 | def test_varname_collision_fail(bad_code):
53 | with raises(NamespaceCollision):
54 | compiler.compile_code(bad_code)
55 |
56 |
57 | valid_list = [
58 | """
59 | @external
60 | def foo(i: int128) -> int128:
61 | variable : int128 = i
62 | return variable
63 | """,
64 | """
65 | @external
66 | def foo(i: int128) -> int128:
67 | var_123 : int128 = i
68 | return var_123
69 | """,
70 | """
71 | @external
72 | def foo(i: int128) -> int128:
73 | _var123 : int128 = i
74 | return _var123
75 | """,
76 | ]
77 |
78 |
79 | @pytest.mark.parametrize("good_code", valid_list)
80 | def test_varname_validity_success(good_code):
81 | assert compiler.compile_code(good_code) is not None
82 |
--------------------------------------------------------------------------------
/tests/parser/types/test_bytes_zero_padding.py:
--------------------------------------------------------------------------------
1 | import hypothesis
2 | import pytest
3 |
4 |
5 | @pytest.fixture(scope="module")
6 | def little_endian_contract(get_contract_module):
7 | code = """
8 | @internal
9 | @view
10 | def to_little_endian_64(_value: uint256) -> Bytes[8]:
11 | y: uint256 = 0
12 | x: uint256 = _value
13 | for _ in range(8):
14 | y = (y << 8) | (x & 255)
15 | x >>= 8
16 | return slice(convert(y, bytes32), 24, 8)
17 |
18 | @external
19 | @view
20 | def get_count(counter: uint256) -> Bytes[24]:
21 | return self.to_little_endian_64(counter)
22 | """
23 | c = get_contract_module(code)
24 | return c
25 |
26 |
27 | @pytest.mark.fuzzing
28 | @hypothesis.given(value=hypothesis.strategies.integers(min_value=0, max_value=2**64))
29 | @hypothesis.settings(deadline=400)
30 | def test_zero_pad_range(little_endian_contract, value):
31 | actual_bytes = value.to_bytes(8, byteorder="little")
32 | contract_bytes = little_endian_contract.get_count(value)
33 | assert contract_bytes == actual_bytes
34 |
--------------------------------------------------------------------------------
/tests/parser/types/test_node_types.py:
--------------------------------------------------------------------------------
1 | from pytest import raises
2 |
3 | from vyper.semantics.types import (
4 | AddressT,
5 | BytesT,
6 | DecimalT,
7 | HashMapT,
8 | IntegerT,
9 | SArrayT,
10 | StructT,
11 | TupleT,
12 | )
13 |
14 | # TODO: this module should be merged in with other tests/functional/semantics/types/ tests.
15 |
16 |
17 | def test_bytearray_node_type():
18 | node1 = BytesT(12)
19 | node2 = BytesT(12)
20 |
21 | assert node1 == node2
22 |
23 | node3 = BytesT(13)
24 | node4 = IntegerT(True, 128)
25 |
26 | assert node1 != node3
27 | assert node1 != node4
28 |
29 |
30 | def test_mapping_node_types():
31 | node1 = HashMapT(IntegerT(True, 128), IntegerT(True, 128))
32 | node2 = HashMapT(IntegerT(True, 128), IntegerT(True, 128))
33 | assert node1 == node2
34 | assert str(node1) == "HashMap[int128, int128]"
35 |
36 |
37 | def test_tuple_node_types():
38 | node1 = TupleT([IntegerT(True, 128), DecimalT()])
39 | node2 = TupleT([IntegerT(True, 128), DecimalT()])
40 |
41 | assert node1 == node2
42 | assert str(node1) == "(int128, decimal)"
43 |
44 |
45 | def test_canonicalize_type():
46 | # TODO add more types
47 |
48 | # Test ABI format of multiple args.
49 | c = TupleT([IntegerT(True, 128), AddressT()])
50 | assert c.abi_type.selector_name() == "(int128,address)"
51 |
52 |
53 | def test_type_storage_sizes():
54 | assert IntegerT(True, 128).storage_size_in_words == 1
55 | assert BytesT(12).storage_size_in_words == 2
56 | assert BytesT(33).storage_size_in_words == 3
57 | assert SArrayT(IntegerT(True, 128), 10).storage_size_in_words == 10
58 |
59 | tuple_ = TupleT([IntegerT(True, 128), DecimalT()])
60 | assert tuple_.storage_size_in_words == 2
61 |
62 | struct_ = StructT("Foo", {"a": IntegerT(True, 128), "b": DecimalT()})
63 | assert struct_.storage_size_in_words == 2
64 |
65 | # Don't allow unknown types.
66 | with raises(Exception):
67 | _ = int.storage_size_in_words
68 |
--------------------------------------------------------------------------------
/tests/parser/types/test_string_literal.py:
--------------------------------------------------------------------------------
1 | def test_string_literal_return(get_contract_with_gas_estimation):
2 | code = """
3 | @external
4 | def test() -> String[100]:
5 | return "hello world!"
6 |
7 |
8 | @external
9 | def testb() -> Bytes[100]:
10 | return b"hello world!"
11 | """
12 |
13 | c = get_contract_with_gas_estimation(code)
14 |
15 | assert c.test() == "hello world!"
16 | assert c.testb() == b"hello world!"
17 |
18 |
19 | def test_string_convert(get_contract_with_gas_estimation):
20 | code = """
21 | @external
22 | def testb() -> String[100]:
23 | return convert(b"hello world!", String[100])
24 |
25 | @external
26 | def testbb() -> String[100]:
27 | return convert(convert("hello world!", Bytes[100]), String[100])
28 | """
29 |
30 | c = get_contract_with_gas_estimation(code)
31 |
32 | assert c.testb() == "hello world!"
33 | assert c.testbb() == "hello world!"
34 |
35 |
36 | def test_str_assign(get_contract_with_gas_estimation):
37 | code = """
38 | @external
39 | def test() -> String[100]:
40 | a: String[100] = "baba black sheep"
41 | return a
42 | """
43 |
44 | c = get_contract_with_gas_estimation(code)
45 |
46 | assert c.test() == "baba black sheep"
47 |
--------------------------------------------------------------------------------
/tests/signatures/test_invalid_function_decorators.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import StructureException
5 |
6 | FAILING_CONTRACTS = [
7 | """
8 | @external
9 | @pure
10 | @nonreentrant('lock')
11 | def nonreentrant_foo() -> uint256:
12 | return 1
13 | """
14 | ]
15 |
16 |
17 | @pytest.mark.parametrize("failing_contract_code", FAILING_CONTRACTS)
18 | def test_invalid_function_decorators(failing_contract_code):
19 | with pytest.raises(StructureException):
20 | compiler.compile_code(failing_contract_code)
21 |
--------------------------------------------------------------------------------
/tests/signatures/test_method_id_conflicts.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from vyper import compiler
4 | from vyper.exceptions import StructureException
5 |
6 | FAILING_CONTRACTS = [
7 | """
8 | @external
9 | @view
10 | def gsf():
11 | pass
12 |
13 | @external
14 | @view
15 | def tgeo():
16 | pass
17 | """,
18 | """
19 | @external
20 | @view
21 | def withdraw(a: uint256):
22 | pass
23 |
24 | @external
25 | @view
26 | def OwnerTransferV7b711143(a: uint256):
27 | pass
28 | """,
29 | """
30 | @external
31 | @view
32 | def withdraw(a: uint256):
33 | pass
34 |
35 | @external
36 | @view
37 | def gsf():
38 | pass
39 |
40 | @external
41 | @view
42 | def tgeo():
43 | pass
44 |
45 | @external
46 | @view
47 | def OwnerTransferV7b711143(a: uint256):
48 | pass
49 | """,
50 | """
51 | # check collision with ID = 0x00000000
52 | wycpnbqcyf:public(uint256)
53 |
54 | @external
55 | def randallsRevenge_ilxaotc(): pass
56 | """,
57 | ]
58 |
59 |
60 | @pytest.mark.parametrize("failing_contract_code", FAILING_CONTRACTS)
61 | def test_method_id_conflicts(failing_contract_code):
62 | with pytest.raises(StructureException):
63 | compiler.compile_code(failing_contract_code)
64 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist =
3 | py{310,311}
4 | lint
5 | mypy
6 | docs
7 |
8 | [testenv]
9 | usedevelop = True
10 | commands =
11 | pytest -m "not fuzzing" --showlocals {posargs:tests/}
12 | basepython =
13 | py310: python3.10
14 | py311: python3.11
15 | extras =
16 | test
17 | whitelist_externals = make
18 |
19 | [testenv:docs]
20 | basepython=python3
21 | deps =
22 | sphinx
23 | sphinx_rtd_theme
24 | recommonmark
25 | commands =
26 | sphinx-build {posargs:-E} -b html docs dist/docs -n -q --color
27 |
28 | [testenv:fuzzing]
29 | basepython = python3
30 | commands =
31 | pytest -m fuzzing {posargs:tests/}
32 | extras =
33 | test
34 | whitelist_externals = make
35 |
36 | [testenv:memory]
37 | basepython = python3
38 | commands =
39 | pytest --memorymock {posargs:tests/}
40 | extras =
41 | test
42 | whitelist_externals = make
43 |
44 | [testenv:lint]
45 | basepython = python3
46 | extras = lint
47 | commands =
48 | black -C -t py311 {toxinidir}/vyper {toxinidir}/tests {toxinidir}/setup.py
49 | flake8 {toxinidir}/vyper {toxinidir}/tests
50 | isort {toxinidir}/vyper {toxinidir}/tests {toxinidir}/setup.py
51 |
52 | [testenv:mypy]
53 | basepython = python3
54 | extras = lint
55 | commands =
56 | mypy --install-types --non-interactive --follow-imports=silent --ignore-missing-imports --disallow-incomplete-defs -p vyper
57 |
--------------------------------------------------------------------------------
/vyper/__init__.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path as _Path
2 |
3 | from vyper.compiler import compile_code, compile_codes # noqa: F401
4 |
5 | try:
6 | from importlib.metadata import PackageNotFoundError # type: ignore
7 | from importlib.metadata import version as _version # type: ignore
8 | except ModuleNotFoundError:
9 | from importlib_metadata import PackageNotFoundError # type: ignore
10 | from importlib_metadata import version as _version # type: ignore
11 |
12 | _commit_hash_file = _Path(__file__).parent.joinpath("vyper_git_commithash.txt")
13 |
14 | if _commit_hash_file.exists():
15 | with _commit_hash_file.open() as fp:
16 | __commit__ = fp.read()
17 | else:
18 | __commit__ = "unknown"
19 |
20 | try:
21 | __version__ = _version(__name__)
22 | except PackageNotFoundError:
23 | from vyper.version import version as __version__
24 |
--------------------------------------------------------------------------------
/vyper/__main__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: UTF-8 -*-
3 | import sys
4 |
5 | from vyper.cli import vyper_compile, vyper_ir, vyper_serve
6 |
7 | if __name__ == "__main__":
8 | allowed_subcommands = ("--vyper-compile", "--vyper-ir", "--vyper-serve")
9 |
10 | if len(sys.argv) <= 1 or sys.argv[1] not in allowed_subcommands:
11 | # default (no args, no switch in first arg): run vyper_compile
12 | vyper_compile._parse_cli_args()
13 | else:
14 | # pop switch and forward args to subcommand
15 | subcommand = sys.argv.pop(1)
16 | if subcommand == "--vyper-serve":
17 | vyper_serve._parse_cli_args()
18 | elif subcommand == "--vyper-ir":
19 | vyper_ir._parse_cli_args()
20 | else:
21 | vyper_compile._parse_cli_args()
22 |
--------------------------------------------------------------------------------
/vyper/ast/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | isort:skip_file
3 | """
4 | import sys
5 |
6 | from . import nodes, validation
7 | from .natspec import parse_natspec
8 | from .nodes import compare_nodes
9 | from .utils import ast_to_dict, parse_to_ast, parse_to_ast_with_settings
10 |
11 | # adds vyper.ast.nodes classes into the local namespace
12 | for name, obj in (
13 | (k, v) for k, v in nodes.__dict__.items() if type(v) is type and nodes.VyperNode in v.__mro__
14 | ):
15 | setattr(sys.modules[__name__], name, obj)
16 |
17 |
18 | # required to avoid circular dependency
19 | from . import expansion, folding # noqa: E402
20 |
--------------------------------------------------------------------------------
/vyper/ast/__init__.pyi:
--------------------------------------------------------------------------------
1 | import ast as python_ast
2 | from typing import Any, Optional, Union
3 |
4 | from . import expansion, folding, nodes, validation
5 | from .natspec import parse_natspec as parse_natspec
6 | from .nodes import *
7 | from .utils import ast_to_dict as ast_to_dict
8 | from .utils import parse_to_ast as parse_to_ast
9 |
--------------------------------------------------------------------------------
/vyper/ast/grammar.py:
--------------------------------------------------------------------------------
1 | # EXPERIMENTAL VYPER PARSER
2 | import textwrap
3 |
4 | from lark import Lark
5 | from lark.indenter import Indenter
6 |
7 |
8 | class PythonIndenter(Indenter):
9 | NL_type = "_NEWLINE"
10 | OPEN_PAREN_types = ["LPAR", "LSQB", "LBRACE"]
11 | CLOSE_PAREN_types = ["RPAR", "RSQB", "RBRACE"]
12 | INDENT_type = "_INDENT"
13 | DEDENT_type = "_DEDENT"
14 | tab_len = 4
15 |
16 |
17 | _lark_grammar = None
18 |
19 |
20 | def vyper_grammar():
21 | global _lark_grammar
22 | if _lark_grammar is None:
23 | _lark_grammar = Lark.open_from_package(
24 | "vyper",
25 | "grammar.lark",
26 | ("ast/",),
27 | parser="lalr",
28 | start="module",
29 | postlex=PythonIndenter(),
30 | )
31 | return _lark_grammar
32 |
33 |
34 | def parse_vyper_source(code, dedent=False):
35 | if dedent:
36 | code = textwrap.dedent(code)
37 | return vyper_grammar().parse(code + "\n")
38 |
--------------------------------------------------------------------------------
/vyper/builtins/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/vyper/builtins/__init__.py
--------------------------------------------------------------------------------
/vyper/builtins/_utils.py:
--------------------------------------------------------------------------------
1 | from vyper.ast import parse_to_ast
2 | from vyper.codegen.context import Context
3 | from vyper.codegen.global_context import GlobalContext
4 | from vyper.codegen.stmt import parse_body
5 | from vyper.semantics.analysis.local import FunctionNodeVisitor
6 | from vyper.semantics.namespace import Namespace, override_global_namespace
7 | from vyper.semantics.types.function import ContractFunctionT, FunctionVisibility, StateMutability
8 |
9 |
10 | def _strip_source_pos(ir_node):
11 | ir_node.source_pos = None
12 | for x in ir_node.args:
13 | _strip_source_pos(x)
14 |
15 |
16 | def generate_inline_function(code, variables, variables_2, memory_allocator):
17 | ast_code = parse_to_ast(code, add_fn_node="dummy_fn")
18 | # Annotate the AST with a temporary old (i.e. typecheck) namespace
19 | namespace = Namespace()
20 | namespace.update(variables_2)
21 | with override_global_namespace(namespace):
22 | # Initialise a placeholder `FunctionDef` AST node and corresponding
23 | # `ContractFunctionT` type to rely on the annotation visitors in semantics
24 | # module.
25 | ast_code.body[0]._metadata["type"] = ContractFunctionT(
26 | "sqrt_builtin", [], [], None, FunctionVisibility.INTERNAL, StateMutability.NONPAYABLE
27 | )
28 | # The FunctionNodeVisitor's constructor performs semantic checks
29 | # annotate the AST as side effects.
30 | FunctionNodeVisitor(ast_code, ast_code.body[0], namespace)
31 |
32 | new_context = Context(
33 | vars_=variables, global_ctx=GlobalContext(), memory_allocator=memory_allocator
34 | )
35 | generated_ir = parse_body(ast_code.body[0].body, new_context)
36 | # strip source position info from the generated_ir since
37 | # it doesn't make any sense (e.g. the line numbers will start from 0
38 | # instead of where we are in the code)
39 | # NOTE if we ever use this for inlining user-code, it would make
40 | # sense to fix the offsets of the source positions in the generated
41 | # code instead of stripping them.
42 | _strip_source_pos(generated_ir)
43 | return new_context, generated_ir
44 |
--------------------------------------------------------------------------------
/vyper/builtins/interfaces/ERC165.py:
--------------------------------------------------------------------------------
1 | interface_code = """
2 | @view
3 | @external
4 | def supportsInterface(interface_id: bytes4) -> bool:
5 | pass
6 | """
7 |
--------------------------------------------------------------------------------
/vyper/builtins/interfaces/ERC20.py:
--------------------------------------------------------------------------------
1 | interface_code = """
2 | # Events
3 | event Transfer:
4 | _from: indexed(address)
5 | _to: indexed(address)
6 | _value: uint256
7 |
8 | event Approval:
9 | _owner: indexed(address)
10 | _spender: indexed(address)
11 | _value: uint256
12 |
13 | # Functions
14 | @view
15 | @external
16 | def totalSupply() -> uint256:
17 | pass
18 |
19 | @view
20 | @external
21 | def balanceOf(_owner: address) -> uint256:
22 | pass
23 |
24 | @view
25 | @external
26 | def allowance(_owner: address, _spender: address) -> uint256:
27 | pass
28 |
29 | @external
30 | def transfer(_to: address, _value: uint256) -> bool:
31 | pass
32 |
33 | @external
34 | def transferFrom(_from: address, _to: address, _value: uint256) -> bool:
35 | pass
36 |
37 | @external
38 | def approve(_spender: address, _value: uint256) -> bool:
39 | pass
40 | """
41 |
--------------------------------------------------------------------------------
/vyper/builtins/interfaces/ERC20Detailed.py:
--------------------------------------------------------------------------------
1 | """
2 | NOTE: interface uses `String[1]` where 1 is the lower bound of the string returned by the function.
3 | For end-users this means they can't use `implements: ERC20Detailed` unless their implementation
4 | uses a value n >= 1. Regardless this is fine as one can't do String[0] where n == 0.
5 | """
6 |
7 | interface_code = """
8 | @view
9 | @external
10 | def name() -> String[1]:
11 | pass
12 |
13 | @view
14 | @external
15 | def symbol() -> String[1]:
16 | pass
17 |
18 | @view
19 | @external
20 | def decimals() -> uint8:
21 | pass
22 | """
23 |
--------------------------------------------------------------------------------
/vyper/builtins/interfaces/ERC4626.py:
--------------------------------------------------------------------------------
1 | interface_code = """
2 | # Events
3 | event Deposit:
4 | sender: indexed(address)
5 | owner: indexed(address)
6 | assets: uint256
7 | shares: uint256
8 |
9 | event Withdraw:
10 | sender: indexed(address)
11 | receiver: indexed(address)
12 | owner: indexed(address)
13 | assets: uint256
14 | shares: uint256
15 |
16 | # Functions
17 | @view
18 | @external
19 | def asset() -> address:
20 | pass
21 |
22 | @view
23 | @external
24 | def totalAssets() -> uint256:
25 | pass
26 |
27 | @view
28 | @external
29 | def convertToShares(assetAmount: uint256) -> uint256:
30 | pass
31 |
32 | @view
33 | @external
34 | def convertToAssets(shareAmount: uint256) -> uint256:
35 | pass
36 |
37 | @view
38 | @external
39 | def maxDeposit(owner: address) -> uint256:
40 | pass
41 |
42 | @view
43 | @external
44 | def previewDeposit(assets: uint256) -> uint256:
45 | pass
46 |
47 | @external
48 | def deposit(assets: uint256, receiver: address=msg.sender) -> uint256:
49 | pass
50 |
51 | @view
52 | @external
53 | def maxMint(owner: address) -> uint256:
54 | pass
55 |
56 | @view
57 | @external
58 | def previewMint(shares: uint256) -> uint256:
59 | pass
60 |
61 | @external
62 | def mint(shares: uint256, receiver: address=msg.sender) -> uint256:
63 | pass
64 |
65 | @view
66 | @external
67 | def maxWithdraw(owner: address) -> uint256:
68 | pass
69 |
70 | @view
71 | @external
72 | def previewWithdraw(assets: uint256) -> uint256:
73 | pass
74 |
75 | @external
76 | def withdraw(assets: uint256, receiver: address=msg.sender, owner: address=msg.sender) -> uint256:
77 | pass
78 |
79 | @view
80 | @external
81 | def maxRedeem(owner: address) -> uint256:
82 | pass
83 |
84 | @view
85 | @external
86 | def previewRedeem(shares: uint256) -> uint256:
87 | pass
88 |
89 | @external
90 | def redeem(shares: uint256, receiver: address=msg.sender, owner: address=msg.sender) -> uint256:
91 | pass
92 | """
93 |
--------------------------------------------------------------------------------
/vyper/builtins/interfaces/ERC721.py:
--------------------------------------------------------------------------------
1 | interface_code = """
2 | # Events
3 |
4 | event Transfer:
5 | _from: indexed(address)
6 | _to: indexed(address)
7 | _tokenId: indexed(uint256)
8 |
9 | event Approval:
10 | _owner: indexed(address)
11 | _approved: indexed(address)
12 | _tokenId: indexed(uint256)
13 |
14 | event ApprovalForAll:
15 | _owner: indexed(address)
16 | _operator: indexed(address)
17 | _approved: bool
18 |
19 | # Functions
20 |
21 | @view
22 | @external
23 | def supportsInterface(interface_id: bytes4) -> bool:
24 | pass
25 |
26 | @view
27 | @external
28 | def balanceOf(_owner: address) -> uint256:
29 | pass
30 |
31 | @view
32 | @external
33 | def ownerOf(_tokenId: uint256) -> address:
34 | pass
35 |
36 | @view
37 | @external
38 | def getApproved(_tokenId: uint256) -> address:
39 | pass
40 |
41 | @view
42 | @external
43 | def isApprovedForAll(_owner: address, _operator: address) -> bool:
44 | pass
45 |
46 | @external
47 | @payable
48 | def transferFrom(_from: address, _to: address, _tokenId: uint256):
49 | pass
50 |
51 | @external
52 | @payable
53 | def safeTransferFrom(_from: address, _to: address, _tokenId: uint256):
54 | pass
55 |
56 | @external
57 | @payable
58 | def safeTransferFrom(_from: address, _to: address, _tokenId: uint256, _data: Bytes[1024]):
59 | pass
60 |
61 | @external
62 | @payable
63 | def approve(_approved: address, _tokenId: uint256):
64 | pass
65 |
66 | @external
67 | def setApprovalForAll(_operator: address, _approved: bool):
68 | pass
69 |
70 | """
71 |
--------------------------------------------------------------------------------
/vyper/builtins/interfaces/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/vyper/builtins/interfaces/__init__.py
--------------------------------------------------------------------------------
/vyper/cli/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/vyper/cli/__init__.py
--------------------------------------------------------------------------------
/vyper/cli/vyper_ir.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | import argparse
3 | import sys
4 |
5 | import vyper
6 | from vyper.codegen.ir_node import IRnode
7 | from vyper.ir import compile_ir, optimizer
8 | from vyper.ir.s_expressions import parse_s_exp
9 |
10 |
11 | def _parse_cli_args():
12 | return _parse_args(sys.argv[1:])
13 |
14 |
15 | def _parse_args(argv):
16 | parser = argparse.ArgumentParser(description="Vyper IR IR compiler")
17 | parser.add_argument("input_file", help="Vyper sourcecode to compile")
18 | parser.add_argument(
19 | "--version", action="version", version=f"{vyper.__version__}+commit{vyper.__commit__}"
20 | )
21 | parser.add_argument(
22 | "-f",
23 | help="Format to print csv list of ir,opt_ir,asm,bytecode",
24 | default="bytecode",
25 | dest="format",
26 | )
27 | parser.add_argument(
28 | "--show-gas-estimates", help="Show gas estimates in ir output mode.", action="store_true"
29 | )
30 |
31 | args = parser.parse_args(argv)
32 | output_formats = set(dict.fromkeys(args.format.split(",")))
33 | compiler_data = compile_to_ir(args.input_file, output_formats, args.show_gas_estimates)
34 |
35 | for key in ("ir", "opt_ir", "asm", "bytecode"):
36 | if key in compiler_data:
37 | print(compiler_data[key])
38 |
39 |
40 | def compile_to_ir(input_file, output_formats, show_gas_estimates=False):
41 | with open(input_file) as fh:
42 | s_expressions = parse_s_exp(fh.read())
43 |
44 | if show_gas_estimates:
45 | IRnode.repr_show_gas = True
46 |
47 | compiler_data = {}
48 | ir = IRnode.from_list(s_expressions[0])
49 | ir = optimizer.optimize(ir)
50 | if "ir" in output_formats:
51 | compiler_data["ir"] = ir
52 |
53 | asm = compile_ir.compile_to_assembly(ir)
54 | if "asm" in output_formats:
55 | compiler_data["asm"] = asm
56 |
57 | if "bytecode" in output_formats:
58 | bytecode, _ = compile_ir.assembly_to_evm(asm)
59 | compiler_data["bytecode"] = "0x" + bytecode.hex()
60 |
61 | return compiler_data
62 |
63 |
64 | if __name__ == "__main__":
65 | _parse_cli_args()
66 |
--------------------------------------------------------------------------------
/vyper/codegen/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/vyper/codegen/__init__.py
--------------------------------------------------------------------------------
/vyper/codegen/function_definitions/__init__.py:
--------------------------------------------------------------------------------
1 | from .common import FuncIR, generate_ir_for_function # noqa
2 |
--------------------------------------------------------------------------------
/vyper/codegen/function_definitions/utils.py:
--------------------------------------------------------------------------------
1 | from vyper.evm.opcodes import version_check
2 | from vyper.semantics.types.function import StateMutability
3 |
4 |
5 | def get_nonreentrant_lock(func_type):
6 | if not func_type.nonreentrant:
7 | return ["pass"], ["pass"]
8 |
9 | nkey = func_type.reentrancy_key_position.position
10 |
11 | LOAD, STORE = "sload", "sstore"
12 | if version_check(begin="cancun"):
13 | LOAD, STORE = "tload", "tstore"
14 |
15 | if version_check(begin="berlin"):
16 | # any nonzero values would work here (see pricing as of net gas
17 | # metering); these values are chosen so that downgrading to the
18 | # 0,1 scheme (if it is somehow necessary) is safe.
19 | final_value, temp_value = 3, 2
20 | else:
21 | final_value, temp_value = 0, 1
22 |
23 | check_notset = ["assert", ["ne", temp_value, [LOAD, nkey]]]
24 |
25 | if func_type.mutability == StateMutability.VIEW:
26 | return [check_notset], [["seq"]]
27 |
28 | else:
29 | pre = ["seq", check_notset, [STORE, nkey, temp_value]]
30 | post = [STORE, nkey, final_value]
31 | return [pre], [post]
32 |
--------------------------------------------------------------------------------
/vyper/codegen/global_context.py:
--------------------------------------------------------------------------------
1 | from functools import cached_property
2 | from typing import Optional
3 |
4 | from vyper import ast as vy_ast
5 |
6 |
7 | # Datatype to store all global context information.
8 | # TODO: rename me to ModuleT
9 | class GlobalContext:
10 | def __init__(self, module: Optional[vy_ast.Module] = None):
11 | self._module = module
12 |
13 | @cached_property
14 | def functions(self):
15 | return self._module.get_children(vy_ast.FunctionDef)
16 |
17 | @cached_property
18 | def variables(self):
19 | # variables that this module defines, ex.
20 | # `x: uint256` is a private storage variable named x
21 | if self._module is None: # TODO: make self._module never be None
22 | return None
23 | variable_decls = self._module.get_children(vy_ast.VariableDecl)
24 | return {s.target.id: s.target._metadata["varinfo"] for s in variable_decls}
25 |
26 | @property
27 | def immutables(self):
28 | return [t for t in self.variables.values() if t.is_immutable]
29 |
30 | @cached_property
31 | def immutable_section_bytes(self):
32 | return sum([imm.typ.memory_bytes_required for imm in self.immutables])
33 |
--------------------------------------------------------------------------------
/vyper/codegen/keccak256_helper.py:
--------------------------------------------------------------------------------
1 | from math import ceil
2 |
3 | from vyper.codegen.core import bytes_data_ptr, ensure_in_memory, get_bytearray_length
4 | from vyper.codegen.ir_node import IRnode
5 | from vyper.exceptions import CompilerPanic
6 | from vyper.semantics.types.bytestrings import _BytestringT
7 | from vyper.semantics.types.shortcuts import BYTES32_T
8 | from vyper.utils import SHA3_BASE, SHA3_PER_WORD, MemoryPositions, bytes_to_int, keccak256
9 |
10 |
11 | def _check_byteslike(typ):
12 | if not isinstance(typ, _BytestringT) and typ != BYTES32_T:
13 | # NOTE this may be checked at a higher level, but just be safe
14 | raise CompilerPanic("keccak256 only accepts bytes-like objects")
15 |
16 |
17 | def _gas_bound(num_words):
18 | return SHA3_BASE + num_words * SHA3_PER_WORD
19 |
20 |
21 | def keccak256_helper(to_hash, context):
22 | _check_byteslike(to_hash.typ)
23 |
24 | # Can hash literals
25 | # TODO this is dead code.
26 | if isinstance(to_hash, bytes):
27 | return IRnode.from_list(bytes_to_int(keccak256(to_hash)), typ=BYTES32_T)
28 |
29 | # Can hash bytes32 objects
30 | # TODO: Want to generalize to all bytes_M
31 | if to_hash.typ == BYTES32_T:
32 | return IRnode.from_list(
33 | [
34 | "seq",
35 | ["mstore", MemoryPositions.FREE_VAR_SPACE, to_hash],
36 | ["sha3", MemoryPositions.FREE_VAR_SPACE, 32],
37 | ],
38 | typ=BYTES32_T,
39 | add_gas_estimate=_gas_bound(1),
40 | )
41 |
42 | to_hash = ensure_in_memory(to_hash, context)
43 |
44 | with to_hash.cache_when_complex("buf") as (b1, to_hash):
45 | data = bytes_data_ptr(to_hash)
46 | len_ = get_bytearray_length(to_hash)
47 | return b1.resolve(
48 | IRnode.from_list(
49 | ["sha3", data, len_],
50 | typ=BYTES32_T,
51 | annotation="keccak256",
52 | add_gas_estimate=_gas_bound(ceil(to_hash.typ.maxlen / 32)),
53 | )
54 | )
55 |
--------------------------------------------------------------------------------
/vyper/compiler/settings.py:
--------------------------------------------------------------------------------
1 | import os
2 | from dataclasses import dataclass
3 | from enum import Enum
4 | from typing import Optional
5 |
6 | VYPER_COLOR_OUTPUT = os.environ.get("VYPER_COLOR_OUTPUT", "0") == "1"
7 | VYPER_ERROR_CONTEXT_LINES = int(os.environ.get("VYPER_ERROR_CONTEXT_LINES", "1"))
8 | VYPER_ERROR_LINE_NUMBERS = os.environ.get("VYPER_ERROR_LINE_NUMBERS", "1") == "1"
9 |
10 | VYPER_TRACEBACK_LIMIT: Optional[int]
11 |
12 | _tb_limit_str = os.environ.get("VYPER_TRACEBACK_LIMIT")
13 | if _tb_limit_str is not None:
14 | VYPER_TRACEBACK_LIMIT = int(_tb_limit_str)
15 | else:
16 | VYPER_TRACEBACK_LIMIT = None
17 |
18 |
19 | class OptimizationLevel(Enum):
20 | NONE = 1
21 | GAS = 2
22 | CODESIZE = 3
23 |
24 | @classmethod
25 | def from_string(cls, val):
26 | match val:
27 | case "none":
28 | return cls.NONE
29 | case "gas":
30 | return cls.GAS
31 | case "codesize":
32 | return cls.CODESIZE
33 | raise ValueError(f"unrecognized optimization level: {val}")
34 |
35 | @classmethod
36 | def default(cls):
37 | return cls.GAS
38 |
39 |
40 | @dataclass
41 | class Settings:
42 | compiler_version: Optional[str] = None
43 | optimize: Optional[OptimizationLevel] = None
44 | evm_version: Optional[str] = None
45 |
46 |
47 | _DEBUG = False
48 |
49 |
50 | def _is_debug_mode():
51 | global _DEBUG
52 | return _DEBUG
53 |
54 |
55 | def _set_debug_mode(dbg: bool = False) -> None:
56 | global _DEBUG
57 | _DEBUG = dbg
58 |
--------------------------------------------------------------------------------
/vyper/compiler/utils.py:
--------------------------------------------------------------------------------
1 | from typing import Dict
2 |
3 | from vyper.semantics.types.function import ContractFunctionT
4 |
5 |
6 | def build_gas_estimates(func_ts: Dict[str, ContractFunctionT]) -> dict:
7 | # note: `.gas_estimate` is added to ContractFunctionT._ir_info
8 | # in vyper/semantics/types/function.py
9 | ret = {}
10 | for k, v in func_ts.items():
11 | ret[k] = v._ir_info.gas_estimate
12 | return ret
13 |
14 |
15 | def expand_source_map(compressed_map: str) -> list:
16 | """
17 | Expand a compressed source map string.
18 |
19 | Arguments
20 | ---------
21 | compressed_map : str
22 | `sourceMap` as generated by the compiler, i.e. "1:1:0;;;;3::2;;;4;"
23 |
24 | Returns
25 | -------
26 | List
27 | Expanded source map as `[[start, length, jump, source id], .. ]`
28 | """
29 | source_map: list = [_expand_row(i) if i else None for i in compressed_map.split(";")[:-1]]
30 |
31 | for i, value in enumerate(source_map[1:], 1):
32 | if value is None:
33 | source_map[i] = source_map[i - 1][:3] + [None]
34 | continue
35 | for x in range(3):
36 | if source_map[i][x] is None:
37 | source_map[i][x] = source_map[i - 1][x]
38 |
39 | return source_map
40 |
41 |
42 | def _expand_row(row):
43 | result = [None] * 4
44 | for i, value in enumerate(row.split(":")):
45 | if value:
46 | result[i] = value if i == 3 else int(value)
47 | return result
48 |
--------------------------------------------------------------------------------
/vyper/evm/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/vyper/evm/__init__.py
--------------------------------------------------------------------------------
/vyper/evm/address_space.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 | from typing import Optional
3 |
4 | # TODO consider renaming this module to avoid confusion with the EVM
5 | # concept of addresses (160-bit account IDs).
6 |
7 |
8 | @dataclass(frozen=True)
9 | class AddrSpace:
10 | """
11 | Object representing info about the "address space", analogous to the
12 | LLVM concept. It includes some metadata so that codegen can be
13 | written in a more generic way.
14 |
15 | Attributes:
16 | name: human-readable nickname for the address space
17 | word_scale: a constant which helps calculate offsets in a given
18 | address space. 1 for word-addressable locations (storage),
19 | 32 for byte-addressable locations (memory, calldata, code)
20 | load_op: the opcode for loading a word from this address space
21 | store_op: the opcode for storing a word to this address space
22 | (an address space is read-only if store_op is None)
23 | """
24 |
25 | name: str
26 | word_scale: int
27 | load_op: str
28 | # TODO maybe make positional instead of defaulting to None
29 | store_op: Optional[str] = None
30 |
31 | @property
32 | def word_addressable(self) -> bool:
33 | return self.word_scale == 1
34 |
35 | @property
36 | def byte_addressable(self) -> bool:
37 | return self.word_scale == 32
38 |
39 |
40 | # alternative:
41 | # class Memory(AddrSpace):
42 | # @property
43 | # def word_scale(self):
44 | # return 32
45 | # # implement more properties...
46 | #
47 | # MEMORY = Memory()
48 |
49 | MEMORY = AddrSpace("memory", 32, "mload", "mstore")
50 | STORAGE = AddrSpace("storage", 1, "sload", "sstore")
51 | TRANSIENT = AddrSpace("transient", 1, "tload", "tstore")
52 | CALLDATA = AddrSpace("calldata", 32, "calldataload")
53 | # immutables address space: "immutables" section of memory
54 | # which is read-write in deploy code but then gets turned into
55 | # the "data" section of the runtime code
56 | IMMUTABLES = AddrSpace("immutables", 32, "iload", "istore")
57 | # data addrspace: "data" section of runtime code, read-only.
58 | DATA = AddrSpace("data", 32, "dload")
59 |
--------------------------------------------------------------------------------
/vyper/ir/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cyfrin/2023-09-vyper-compiler/46449fe7bde9a9a9c438f2a6f7edce54e8927413/vyper/ir/__init__.py
--------------------------------------------------------------------------------
/vyper/ir/s_expressions.py:
--------------------------------------------------------------------------------
1 | # Adapted from https://en.wikipedia.org/wiki/S-expression#Parsing
2 |
3 |
4 | def parse_literal(word):
5 | try:
6 | return int(word)
7 | except ValueError:
8 | return word
9 |
10 |
11 | def parse_s_exp(string):
12 | sexp = [[]]
13 | word = ""
14 | in_str = False
15 | in_comment = False
16 | for char in string:
17 | if in_comment:
18 | if char == "\n": # comment ends at the end of a line
19 | in_comment = False
20 | continue
21 | if char == ";": # start of comment
22 | in_comment = True
23 | continue
24 | if char == "(" and not in_str:
25 | sexp.append([])
26 | elif char == ")" and not in_str:
27 | if word:
28 | sexp[-1].append(parse_literal(word))
29 | word = ""
30 | temp = sexp.pop()
31 | sexp[-1].append(temp)
32 | elif char in (" ", "\n", "\t") and not in_str:
33 | if word:
34 | sexp[-1].append(parse_literal(word))
35 | word = ""
36 | elif char == '"':
37 | in_str = not in_str
38 | else:
39 | word += char
40 | return sexp[0]
41 |
--------------------------------------------------------------------------------
/vyper/semantics/__init__.py:
--------------------------------------------------------------------------------
1 | from .analysis import validate_semantics
2 | from .analysis.data_positions import set_data_positions
3 |
--------------------------------------------------------------------------------
/vyper/semantics/analysis/__init__.py:
--------------------------------------------------------------------------------
1 | import vyper.ast as vy_ast
2 |
3 | from .. import types # break a dependency cycle.
4 | from ..namespace import get_namespace
5 | from .local import validate_functions
6 | from .module import add_module_namespace
7 | from .utils import _ExprAnalyser
8 |
9 |
10 | def validate_semantics(vyper_ast, interface_codes):
11 | # validate semantics and annotate AST with type/semantics information
12 | namespace = get_namespace()
13 |
14 | with namespace.enter_scope():
15 | add_module_namespace(vyper_ast, interface_codes)
16 | vy_ast.expansion.expand_annotated_ast(vyper_ast)
17 | validate_functions(vyper_ast)
18 |
--------------------------------------------------------------------------------
/vyper/semantics/analysis/common.py:
--------------------------------------------------------------------------------
1 | from typing import Tuple
2 |
3 | from vyper.exceptions import StructureException
4 |
5 |
6 | class VyperNodeVisitorBase:
7 | ignored_types: Tuple = ()
8 | scope_name = ""
9 |
10 | def visit(self, node, *args):
11 | if isinstance(node, self.ignored_types):
12 | return
13 | node_type = type(node).__name__
14 | visitor_fn = getattr(self, f"visit_{node_type}", None)
15 | if visitor_fn is None:
16 | raise StructureException(
17 | f"Unsupported syntax for {self.scope_name} namespace: {node_type}", node
18 | )
19 | visitor_fn(node, *args)
20 |
--------------------------------------------------------------------------------
/vyper/semantics/data_locations.py:
--------------------------------------------------------------------------------
1 | import enum
2 |
3 |
4 | class DataLocation(enum.Enum):
5 | UNSET = 0
6 | MEMORY = 1
7 | STORAGE = 2
8 | CALLDATA = 3
9 | CODE = 4
10 | # XXX: needed for separate transient storage allocator
11 | # TRANSIENT = 5
12 |
--------------------------------------------------------------------------------
/vyper/semantics/environment.py:
--------------------------------------------------------------------------------
1 | from typing import Dict
2 |
3 | from vyper.semantics.analysis.base import VarInfo
4 | from vyper.semantics.types import AddressT, BytesT, VyperType
5 | from vyper.semantics.types.shortcuts import BYTES32_T, UINT256_T
6 |
7 |
8 | # common properties for environment variables
9 | class _EnvType(VyperType):
10 | def __eq__(self, other):
11 | return self is other
12 |
13 | def __hash__(self):
14 | return hash(id(self))
15 |
16 |
17 | class _Block(_EnvType):
18 | _id = "block"
19 | _type_members = {
20 | "coinbase": AddressT(),
21 | "difficulty": UINT256_T,
22 | "prevrandao": UINT256_T,
23 | "number": UINT256_T,
24 | "gaslimit": UINT256_T,
25 | "basefee": UINT256_T,
26 | "prevhash": BYTES32_T,
27 | "timestamp": UINT256_T,
28 | }
29 |
30 |
31 | class _Chain(_EnvType):
32 | _id = "chain"
33 | _type_members = {"id": UINT256_T}
34 |
35 |
36 | class _Msg(_EnvType):
37 | _id = "msg"
38 | _type_members = {"data": BytesT(), "gas": UINT256_T, "sender": AddressT(), "value": UINT256_T}
39 |
40 |
41 | class _Tx(_EnvType):
42 | _id = "tx"
43 | _type_members = {"origin": AddressT(), "gasprice": UINT256_T}
44 |
45 |
46 | CONSTANT_ENVIRONMENT_VARS = {t._id: t for t in (_Block(), _Chain(), _Tx(), _Msg())}
47 |
48 |
49 | def get_constant_vars() -> Dict:
50 | """
51 | Get a dictionary of constant environment variables.
52 | """
53 | result = {}
54 | for k, v in CONSTANT_ENVIRONMENT_VARS.items():
55 | result[k] = VarInfo(v, is_constant=True)
56 |
57 | return result
58 |
59 |
60 | MUTABLE_ENVIRONMENT_VARS: Dict[str, type] = {"self": AddressT}
61 |
62 |
63 | def get_mutable_vars() -> Dict:
64 | """
65 | Get a dictionary of mutable environment variables (those that are
66 | modified during the course of contract execution, such as `self`).
67 | """
68 | return {name: VarInfo(type_()) for name, type_ in MUTABLE_ENVIRONMENT_VARS.items()}
69 |
--------------------------------------------------------------------------------
/vyper/semantics/types/__init__.py:
--------------------------------------------------------------------------------
1 | from . import primitives, subscriptable, user
2 | from .base import TYPE_T, KwargSettings, VyperType, is_type_t
3 | from .bytestrings import BytesT, StringT, _BytestringT
4 | from .function import MemberFunctionT
5 | from .primitives import AddressT, BoolT, BytesM_T, DecimalT, IntegerT
6 | from .subscriptable import DArrayT, HashMapT, SArrayT, TupleT
7 | from .user import EnumT, EventT, InterfaceT, StructT
8 |
9 |
10 | def _get_primitive_types():
11 | res = [BoolT(), DecimalT()]
12 |
13 | res.extend(IntegerT.all())
14 | res.extend(BytesM_T.all())
15 |
16 | # order of the types matters!
17 | # parsing of literal hex: prefer address over bytes20
18 | res.append(AddressT())
19 |
20 | # note: since bytestrings are parametrizable, the *class* objects
21 | # are in the namespace instead of concrete type objects.
22 | res.extend([BytesT, StringT])
23 |
24 | ret = {t._id: t for t in res}
25 | ret.update(_get_sequence_types())
26 |
27 | return ret
28 |
29 |
30 | def _get_sequence_types():
31 | # since these guys are parametrizable, the *class* objects
32 | # are in the namespace instead of concrete type objects.
33 |
34 | res = [HashMapT, DArrayT]
35 |
36 | ret = {t._id: t for t in res}
37 |
38 | # (static) arrays and tuples are special types which don't show up
39 | # in the type annotation itself.
40 | # since we don't have special handling of annotations in the parser,
41 | # break a dependency cycle by injecting these into the namespace with
42 | # mangled names (that no user can create).
43 | ret["$SArrayT"] = SArrayT
44 | ret["$TupleT"] = TupleT
45 |
46 | return ret
47 |
48 |
49 | # note: it might be good to make this a frozen dict of some sort
50 | PRIMITIVE_TYPES = _get_primitive_types()
51 |
--------------------------------------------------------------------------------
/vyper/semantics/types/shortcuts.py:
--------------------------------------------------------------------------------
1 | from vyper.semantics.types.primitives import SINT, UINT, BytesM_T, IntegerT
2 |
3 | # shortcut type names
4 | UINT256_T = IntegerT(False, 256)
5 | UINT8_T = IntegerT(False, 8)
6 | INT256_T = IntegerT(True, 256)
7 | INT128_T = IntegerT(True, 128)
8 | UINT160_T = IntegerT(False, 160)
9 |
10 | BYTES32_T = BytesM_T(32)
11 | BYTES20_T = BytesM_T(20)
12 | BYTES4_T = BytesM_T(4)
13 |
14 | _ = UINT, SINT # explicitly use: addresses linter F401
15 |
--------------------------------------------------------------------------------
/vyper/typing.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, Optional, Sequence, Tuple, Union
2 |
3 | # Parser
4 | ModificationOffsets = Dict[Tuple[int, int], str]
5 | ParserPosition = Tuple[int, int]
6 |
7 | # Compiler
8 | ContractPath = str
9 | SourceCode = str
10 | ContractCodes = Dict[ContractPath, SourceCode]
11 | OutputFormats = Sequence[str]
12 | OutputDict = Dict[ContractPath, OutputFormats]
13 | StorageLayout = Dict
14 |
15 | # Interfaces
16 | InterfaceAsName = str
17 | InterfaceImportPath = str
18 | InterfaceImports = Dict[InterfaceAsName, InterfaceImportPath]
19 | InterfaceDict = Dict[ContractPath, InterfaceImports]
20 |
21 | # Opcodes
22 | OpcodeGasCost = Union[int, Tuple]
23 | OpcodeValue = Tuple[Optional[int], int, int, OpcodeGasCost]
24 | OpcodeMap = Dict[str, OpcodeValue]
25 | OpcodeRulesetValue = Tuple[Optional[int], int, int, int]
26 | OpcodeRulesetMap = Dict[str, OpcodeRulesetValue]
27 |
--------------------------------------------------------------------------------
/vyper/warnings.py:
--------------------------------------------------------------------------------
1 | # TODO: Create VyperWarning class similarly to what is being done with exceptinos?
2 | class ContractSizeLimitWarning(Warning):
3 | pass
4 |
--------------------------------------------------------------------------------