├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── general.md │ └── vip.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .snapcraft └── travis_snapcraft.cfg ├── .travis.yml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── bin ├── vyper ├── vyper-lll └── vyper-serve ├── docs ├── Makefile ├── built-in-functions.rst ├── compiling-a-contract.rst ├── conf.py ├── contributing.rst ├── frequently-asked-questions.rst ├── index.rst ├── installing-vyper.rst ├── logging.rst ├── make.bat ├── structure-of-a-contract.rst ├── testing-deploying-contracts.rst ├── types.rst ├── vyper-by-example.rst └── vyper-logo-transparent.svg ├── examples ├── auctions │ └── simple_open_auction.vy ├── crowdfund.vy ├── market_maker │ └── on_chain_market_maker.vy ├── name_registry │ └── name_registry.vy ├── safe_remote_purchase │ └── safe_remote_purchase.vy ├── stock │ └── company.vy ├── tokens │ ├── ERC20.vy │ ├── ERC20_solidity_compatible │ │ ├── ERC20.vy │ │ └── README.md │ ├── ERC721.vy │ └── vypercoin.vy ├── voting │ └── ballot.vy └── wallet │ ├── sign.js │ └── wallet.vy ├── logo ├── vyper-logo-flat.png ├── vyper-logo-flat.svg ├── vyper-logo-transparent.png ├── vyper-logo-transparent.svg └── vyper-logo.ai ├── requirements-dev.txt ├── requirements-docs.txt ├── scripts ├── fixed_address_creator.py ├── forwarder.py ├── rlp_decoder.py └── rlp_decoder.se.py ├── setup.cfg ├── setup.py ├── snap └── snapcraft.yaml ├── tests ├── __init__.py ├── compiler │ ├── LLL │ │ ├── __init__.py │ │ ├── test_compile_lll.py │ │ ├── test_repeat.py │ │ └── test_with.py │ ├── __init__.py │ ├── test_bytecode_runtime.py │ ├── test_calldatacopy.py │ ├── test_clamps.py │ ├── test_pre_parser.py │ └── test_sha3_32.py ├── conftest.py ├── examples │ ├── auctions │ │ └── test_simple_open_auction.py │ ├── company │ │ └── test_company.py │ ├── market_maker │ │ └── test_on_chain_market_maker.py │ ├── name_registry │ │ └── test_name_registry.py │ ├── safe_remote_purchase │ │ └── test_safe_remote_purchase.py │ ├── tokens │ │ ├── ERC20_solidity_compatible │ │ │ ├── nonvyper │ │ │ │ ├── ERC20_solidity_1.sol │ │ │ │ └── ERC20_solidity_2.sol │ │ │ ├── run_tests.py │ │ │ ├── test │ │ │ │ ├── __init__.py │ │ │ │ ├── erc20_tests_1.py │ │ │ │ └── erc20_tests_2.py │ │ │ └── utils │ │ │ │ ├── __init__.py │ │ │ │ └── pyethereum_test_utils.py │ │ ├── test_erc721.py │ │ └── test_vypercoin.py │ ├── voting │ │ └── test_ballot.py │ └── wallet │ │ └── test_wallet.py └── parser │ ├── exceptions │ ├── __init__.py │ ├── test_constancy_exception.py │ ├── test_function_declaration_exception.py │ ├── test_insufficient_arguments.py │ ├── test_invalid_literal_exception.py │ ├── test_invalid_payable.py │ ├── test_invalid_same_variable_assignment.py │ ├── test_invalid_type_exception.py │ ├── test_parser_exception_pos.py │ ├── test_structure_exception.py │ ├── test_type_mismatch_exception.py │ ├── test_undef_function.py │ └── test_variable_declaration_exception.py │ ├── features │ ├── arithmetic │ │ └── test_modulo.py │ ├── decorators │ │ ├── test_constant.py │ │ ├── test_private.py │ │ └── test_public.py │ ├── external_contracts │ │ ├── test_erc20_abi.py │ │ ├── test_external_contract_calls.py │ │ └── test_modifiable_external_contract_calls.py │ ├── iteration │ │ ├── test_break.py │ │ ├── test_continue.py │ │ ├── test_for_in_list.py │ │ ├── test_range_in.py │ │ └── test_repeater.py │ ├── test_assert.py │ ├── test_assignment.py │ ├── test_bytes_map_keys.py │ ├── test_clampers.py │ ├── test_comments.py │ ├── test_conditionals.py │ ├── test_constructor.py │ ├── test_gas.py │ ├── test_internal_call.py │ ├── test_logging.py │ ├── test_logging_bytes_extended.py │ ├── test_map_delete.py │ └── test_packing.py │ ├── functions │ ├── __init__.py │ ├── rlp │ │ ├── __init__.py │ │ ├── conftest.py │ │ └── test_rlp_list.py │ ├── test_bitwise.py │ ├── test_block.py │ ├── test_block_number.py │ ├── test_ceil.py │ ├── test_concat.py │ ├── test_convert.py │ ├── test_convert_int128.py │ ├── test_convert_uint256.py │ ├── test_default_function.py │ ├── test_default_parameters.py │ ├── test_ec.py │ ├── test_ecrecover.py │ ├── test_extract32.py │ ├── test_floor.py │ ├── test_is_contract.py │ ├── test_length.py │ ├── test_method_id.py │ ├── test_minmax.py │ ├── test_only_init_abi.py │ ├── test_raw_call.py │ ├── test_return_tuple.py │ ├── test_send.py │ ├── test_sha3.py │ └── test_slice.py │ ├── globals │ ├── test_getters.py │ ├── test_globals.py │ └── test_setters.py │ ├── integration │ ├── test_basics.py │ ├── test_crowdfund.py │ └── test_escrow.py │ ├── syntax │ ├── __init__.py │ ├── test_ann_assign.py │ ├── test_as_uint256.py │ ├── test_as_wei_value.py │ ├── test_block.py │ ├── test_blockscope.py │ ├── test_bool.py │ ├── test_byte_string.py │ ├── test_bytes.py │ ├── test_code_size.py │ ├── test_concat.py │ ├── test_constants.py │ ├── test_create_with_code_of.py │ ├── test_custom_units.py │ ├── test_extract32.py │ ├── test_for_range.py │ ├── test_functions_call.py │ ├── test_invalids.py │ ├── test_len.py │ ├── test_list.py │ ├── test_logging.py │ ├── test_maps.py │ ├── test_minmax.py │ ├── test_missing_return.py │ ├── test_nested_list.py │ ├── test_public.py │ ├── test_raw_call.py │ ├── test_return_tuple.py │ ├── test_rlplist.py │ ├── test_selfdestruct.py │ ├── test_send.py │ ├── test_sha3.py │ ├── test_slice.py │ ├── test_timestamp_timedelta.py │ ├── test_tuple_assign.py │ ├── test_unit_exponents.py │ └── utils │ │ ├── test_event_names.py │ │ ├── test_function_names.py │ │ └── test_variable_names.py │ └── types │ ├── numbers │ ├── test_constants.py │ ├── test_custom_units.py │ ├── test_decimals.py │ ├── test_int128.py │ └── test_uint256.py │ ├── test_bytes.py │ ├── test_lists.py │ ├── test_node_types.py │ ├── test_string_literal.py │ ├── test_variable_naming.py │ └── value │ └── test_as_wei_value.py └── vyper ├── __init__.py ├── compile_lll.py ├── compiler.py ├── exceptions.py ├── functions ├── __init__.py ├── functions.py └── signature.py ├── opcodes.py ├── optimizer.py ├── parser ├── __init__.py ├── context.py ├── expr.py ├── global_context.py ├── lll_node.py ├── parser.py ├── parser_utils.py ├── pre_parser.py ├── s_expressions.py ├── self_call.py └── stmt.py ├── premade_contracts.py ├── server.py ├── signatures ├── __init__.py ├── event_signature.py └── function_signature.py ├── types ├── __init__.py ├── convert.py └── types.py └── utils.py /.gitattributes: -------------------------------------------------------------------------------- 1 | *.vy linguist-language=Python 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/general.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: General Feedback 3 | about: Any general feedback or bug reports about the Vyper Compiler. No new features proposals. 4 | --- 5 | 6 | ### Version Information 7 | 8 | * vyper Version: x.x.x 9 | * pyethereum Version: x.x.x 10 | * OS: osx/linux/win 11 | * Python Version (python --version): 12 | * Environment (output of `pip freeze`): 13 | 14 | ### What's your issue about? 15 | 16 | Please include information like: 17 | 18 | * full output of the error you received 19 | * what command you ran 20 | * the code that caused the failure (see [this link](https://help.github.com/articles/basic-writing-and-formatting-syntax/) for help with formatting code) 21 | 22 | 23 | ### How can it be fixed? 24 | 25 | Fill this in if you know how to fix it. 26 | 27 | #### Cute Animal Picture 28 | 29 | > put a cute animal picture here. 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/vip.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Vyper Improvement Proposal (VIP) 3 | about: This is the suggested template for new VIPs. 4 | --- 5 | ## Simple Summary 6 | "If you can't explain it simply, you don't understand it well enough." Provide a simplified and layman-accessible explanation of the VIP. 7 | 8 | ## Abstract 9 | A short description of the technical issue being addressed. 10 | 11 | ## Motivation 12 | The motivation is critical for VIPs that add or change Vyper's functionality. It should clearly explain why the existing Vyper functionality is inadequate to address the problem that the VIP solves as well as how the VIP is in line with Vyper's goals and design philosophy. 13 | 14 | ## Specification 15 | The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow any developer to implement the functionality 16 | 17 | ## Backwards Compatibility 18 | All VIPs that introduce backwards incompatibilities must include a section describing these incompatibilities and their severity. The VIP must explain how the author proposes to deal with these incompatibilities. 19 | 20 | ## Copyright 21 | Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/) 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### - What I did 2 | 3 | ### - How I did it 4 | 5 | ### - How to verify it 6 | 7 | ### - Description for the changelog 8 | 9 | ### - Cute Animal Picture 10 | 11 | > put a cute animal picture here. 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # egg-related 7 | vyper.egg-info/ 8 | build/ 9 | dist/ 10 | .eggs/ 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 | 30 | # sphinx 31 | docs/_build 32 | docs/modules.rst 33 | 34 | # IDEs 35 | .idea/ 36 | -------------------------------------------------------------------------------- /.snapcraft/travis_snapcraft.cfg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/.snapcraft/travis_snapcraft.cfg -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - '3.6' 4 | cache: pip 5 | install: 6 | - pip install --upgrade pip setuptools 7 | - pip install coveralls 8 | - pip install flake8 9 | - pip install . 10 | script: 11 | - python setup.py test 12 | - flake8 vyper/ tests/ 13 | sudo: required 14 | services: 15 | - docker 16 | after_success: 17 | - coveralls 18 | - openssl aes-256-cbc -K $encrypted_6ed035d313c9_key -iv $encrypted_6ed035d313c9_iv 19 | -in .snapcraft/travis_snapcraft.cfg -out .snapcraft/snapcraft.cfg -d 20 | deploy: 21 | skip_cleanup: true 22 | provider: script 23 | script: docker run -v $(pwd):$(pwd) -t snapcore/snapcraft sh -c 24 | "apt update -qq && cd $(pwd) && 25 | snapcraft && snapcraft push *.snap --release edge" 26 | on: 27 | branch: master 28 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6-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/ethereum/vyper" \ 12 | org.label-schema.vendor="Ethereum" \ 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 apt-utils gcc libc6-dev libc-dev libssl-dev libgmp-dev && \ 18 | rm -rf /var/lib/apt/lists/* 19 | 20 | ADD . /code 21 | 22 | WORKDIR /code 23 | 24 | # Pass `--addopts "--version"` because want to execute `python setup.py test` to include test dependencies in built docker-image, but avoid to execute the whole test suite here. 25 | RUN python setup.py install && \ 26 | python setup.py test --addopts "--version" && \ 27 | apt-get purge -y --auto-remove apt-utils gcc libc6-dev libc-dev libssl-dev 28 | 29 | ENTRYPOINT ["/usr/local/bin/vyper"] 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015 Vitalik Buterin 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test lint clean clean-pyc clean-build clean-test docs docker-build 2 | 3 | init: 4 | python setup.py install 5 | 6 | test: 7 | python setup.py test 8 | 9 | lint: 10 | flake8 vyper tests --ignore=E122,E124,E127,E128,E501,E731,W504 11 | 12 | clean: clean-build clean-pyc clean-test 13 | 14 | clean-build: 15 | rm -fr build/ 16 | rm -fr dist/ 17 | rm -fr *.egg-info 18 | 19 | clean-pyc: 20 | find . -name '*.pyc' -exec rm -f {} + 21 | find . -name '*.pyo' -exec rm -f {} + 22 | find . -name '*~' -exec rm -f {} + 23 | find . -name '__pycache__' -exec rmdir {} + 24 | 25 | clean-test: 26 | find . -name 'htmlcov' -exec rm -rf {} + 27 | 28 | docs: 29 | rm -f docs/vyper.rst 30 | rm -f docs/modules.rst 31 | sphinx-apidoc -o docs/ -d 2 vyper/ 32 | $(MAKE) -C docs clean 33 | $(MAKE) -C docs html 34 | open docs/_build/html/index.html 35 | 36 | docker-build: 37 | @docker build -t vyper \ 38 | --build-arg VCS_REF=`git rev-parse --short HEAD` \ 39 | --build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` . 40 | -------------------------------------------------------------------------------- /bin/vyper-lll: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import vyper 5 | 6 | from vyper import ( 7 | optimizer 8 | ) 9 | from vyper.parser.s_expressions import parse_s_exp 10 | from vyper.parser.parser_utils import LLLnode 11 | from vyper import compile_lll 12 | parser = argparse.ArgumentParser(description='Vyper LLL for Ethereum') 13 | parser.add_argument('--version', action='version', version='{0}'.format(vyper.__version__)) 14 | parser.add_argument('input_file', help='Vyper sourcecode to compile') 15 | parser.add_argument('-f', help='Format to print csv list of ir,opt_ir,asm,bytecode', default='bytecode', dest='format') 16 | parser.add_argument('--show-gas-estimates', help='Show gas estimates in ir output mode.', action="store_true") 17 | 18 | args = parser.parse_args() 19 | 20 | if __name__ == "__main__": 21 | 22 | with open(args.input_file) as f: 23 | 24 | if args.show_gas_estimates: 25 | LLLnode.repr_show_gas = True 26 | 27 | format_set = set(dict.fromkeys(args.format.split(','))) 28 | s_expressions = parse_s_exp(f.read()) 29 | lll = LLLnode.from_list(s_expressions[0]) 30 | if 'ir' in format_set: 31 | print(lll) 32 | optimised = optimizer.optimize(lll) 33 | if 'opt_ir' in format_set: 34 | print(optimised) 35 | asm = compile_lll.compile_to_assembly(lll) 36 | if 'asm' in format_set: 37 | print(asm) 38 | bytecode = '0x' + compile_lll.assembly_to_evm(asm).hex() 39 | if 'bytecode' in format_set: 40 | print(bytecode) 41 | -------------------------------------------------------------------------------- /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/compiling-a-contract.rst: -------------------------------------------------------------------------------- 1 | #################### 2 | Compiling a Contract 3 | #################### 4 | To compile a contract, use: 5 | :: 6 | vyper yourFileName.vy 7 | 8 | You can also compile to other formats such as ABI using the below format: 9 | :: 10 | vyper -f ['abi', 'abi_python', 'bytecode', 'bytecode_runtime', 'ir', 'asm'] yourFileName.vy 11 | 12 | It is also possible to use the `-f json` option, which is a legacy alias for `-f abi`. 13 | 14 | .. note:: 15 | Since .vy is not officially a language supported by any syntax highlighters or linters, 16 | it is recommended to name your Vyper file ending with `.vy` in order to have Python syntax highlighting. 17 | 18 | An `online compiler `_ is available as well, which lets you experiment with 19 | the language without having to install Vyper. The online compiler allows you to compile to ``bytecode`` and/or ``LLL``. 20 | 21 | .. note:: 22 | While the vyper version of the online compiler is updated on a regular basis it might 23 | be a bit behind the latest version found in the master branch of the repository. 24 | -------------------------------------------------------------------------------- /docs/contributing.rst: -------------------------------------------------------------------------------- 1 | ############ 2 | Contributing 3 | ############ 4 | 5 | Help is always appreciated! 6 | 7 | To get started, you can try `installing Vyper `_ in order to familiarize 8 | yourself with the components of Vyper and the build process. Also, it may be 9 | useful to become well-versed at writing smart-contracts in Vyper. 10 | 11 | Types of Contributions 12 | ====================== 13 | 14 | In particular, we need help in the following areas: 15 | 16 | * Improving the documentation 17 | * Responding to questions from other users on `StackExchange 18 | `_ and the `Vyper Gitter 19 | `_ 20 | * Suggesting Improvements 21 | * Fixing and responding to `Vyper's GitHub issues `_ 22 | 23 | 24 | 25 | How to Suggest Improvements 26 | =========================== 27 | 28 | To suggest an improvement, please create a Vyper Improvement Proposal (VIP for short) 29 | using the `VIP Template `_. 30 | 31 | How to Report Issues 32 | ==================== 33 | 34 | To report an issue, please use the 35 | `GitHub issues tracker `_. When 36 | reporting issues, please mention the following details: 37 | 38 | * Which version of Vyper you are using 39 | * What was the source code (if applicable) 40 | * Which platform are you running on 41 | * Your operating system name and version 42 | * Detailed steps to reproduce the issue 43 | * What was the result of the issue 44 | * What the expected behaviour is 45 | 46 | Reducing the source code that caused the issue to a bare minimum is always 47 | very helpful and sometimes even clarifies a misunderstanding. 48 | 49 | Fix Bugs 50 | ======== 51 | 52 | Find or report bugs at our `issues page `_. Anything tagged with "bug" is open to whoever wants to implement it. 53 | 54 | Workflow for Pull Requests 55 | ========================== 56 | 57 | In order to contribute, please fork off of the ``master`` branch and make your 58 | changes there. Your commit messages should detail *why* you made your change 59 | in addition to *what* you did (unless it is a tiny change). 60 | 61 | If you need to pull in any changes from ``master`` after making your fork (for 62 | example, to resolve potential merge conflicts), please avoid using ``git merge`` 63 | and instead, ``git rebase`` your branch. 64 | 65 | **Implement Features** 66 | 67 | If you are writing a new feature, please ensure you write appropriate 68 | Boost test cases and place them under ``tests/``. 69 | 70 | If you are making a larger change, please consult first with the Gitter channel. 71 | 72 | Although we do CI testing, please make sure that the tests pass for supported Python version and ensure that it builds locally before submitting a pull request. 73 | 74 | Thank you for your help! ​ 75 | -------------------------------------------------------------------------------- /docs/frequently-asked-questions.rst: -------------------------------------------------------------------------------- 1 | ########################### 2 | Frequently Asked Questions 3 | ########################### 4 | 5 | *************** 6 | Basic Questions 7 | *************** 8 | 9 | ============== 10 | What is Vyper? 11 | ============== 12 | Vyper is a smart contract development language. Vyper aims to be auditable, secure, and human-readable. Being simple to read is more important than being simple to write. 13 | 14 | ================== 15 | Vyper or Solidity? 16 | ================== 17 | For the majority of use-cases, this is personal preference. To support the aims of being secure, auditable, and human-readable, a number of programming constructs included in Solidity are not included in Vyper. If your use-case requires these, use Solidity not Vyper. 18 | 19 | ============================== 20 | What is not included in Vyper? 21 | ============================== 22 | The following constructs are not included because their use can lead to misleading or difficult to understand code: 23 | 24 | * Modifiers 25 | * Class inheritance 26 | * Inline assembly 27 | * Function overloading 28 | * Operator overloading 29 | * Binary fixed point. 30 | 31 | Recursive calling and infinite-length loops are not included because they cannot set an upper bound on gas limits. An upper bound is required to prevent gas limit attacks and ensure the security of smart contracts built in Vyper. 32 | 33 | ====================== 34 | How do for loops work? 35 | ====================== 36 | Like Python for loops but with one significant difference. Vyper does not allow looping over variable lengths. Looping over variables introduces the possibility of infinite-length loops which make gas limit attacks possible. 37 | 38 | ==================== 39 | How do structs work? 40 | ==================== 41 | Structs group variables and are accessed using ``struct.argname``. They are similar to Python dictionaries:: 42 | 43 | # define the struct 44 | struct: { 45 | arg1: int128, arg2: decimal 46 | } 47 | 48 | #access arg1 in struct 49 | struct.arg1 = 1 50 | 51 | 52 | 53 | ****************** 54 | Advanced Questions 55 | ****************** 56 | -------------------------------------------------------------------------------- /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-deploying-contracts.rst: -------------------------------------------------------------------------------- 1 | .. index:: testing;deploying, testing; 2 | 3 | .. _testing_deploying: 4 | 5 | ****************** 6 | Testing a Contract 7 | ****************** 8 | 9 | The following example demonstrates how to compile and deploy your vyper contract. 10 | It requires ``pyethereum>=2.0.0`` for the ``tester`` module 11 | 12 | .. code-block:: python 13 | from vyper import compiler 14 | from ethereum.tools import tester 15 | 16 | # Get a new chain 17 | chain = tester.Chain() 18 | # Set the vyper compiler to run when the vyper language is requested 19 | tester.languages['vyper'] = compiler.Compiler() 20 | 21 | with open('my_contract.vy' 'r') as f: 22 | source_code = f.read() 23 | # Compile and Deploy contract to provisioned testchain 24 | # (e.g. run __init__ method) with given args (e.g. init_args) 25 | # from msg.sender = t.k1 (private key of address 1 in test acconuts) 26 | # and supply 1000 wei to the contract 27 | init_args = ['arg1', 'arg2', 3] 28 | contract = chain.contract(source_code, language="vyper", 29 | init_args, sender=t.k1, value=1000) 30 | 31 | contract.myMethod() # Executes myMethod on the tester "chain" 32 | chain.mine() # Mines the above transaction (and any before it) into a block 33 | 34 | Note: We are working on integration with `ethereum-tester `_, 35 | so this example will change. 36 | 37 | =============================== 38 | Testing Using vyper-run Command 39 | =============================== 40 | 41 | To allow quickly testing contracts, Vyper provides a command line tool for instantly executing a function: 42 | :: 43 | vyper-run yourFileName.vy "yourFunction();" -i some_init_param, another_init_param 44 | 45 | The vyper-run command is composed of 4 parts: 46 | 47 | - vyper-run 48 | 49 | - the name of the contract file you want to execute (for example: coolContract.vy) 50 | 51 | - a string (wrapped in double quotes) with the function you want to trigger, you can trigger multiple functions by adding a semicolon at the end of each function and then call the next function (for example: ``"myFunction1(100,4);myFunction2()"``) + 52 | 53 | - (Optional) the parameters for the ``__init__`` function of the contract (for example: given ``__init__(a: int128, b: int128)`` the syntax would be ``-i 8,27``). 54 | 55 | Putting it all together: 56 | :: 57 | vyper-run myContract.vy "myFunction1();myFunction2()" -i 1,3 58 | 59 | The vyper-run command will print out the returned value of the called functions as well as all the logged events emitted during the function's execution. 60 | 61 | ******************** 62 | Deploying a Contract 63 | ******************** 64 | 65 | You have several options to deploy a Vyper contract to the public testnets. 66 | 67 | One option is to take the bytecode generated by the vyper compiler and manually deploy it through mist or geth: 68 | 69 | .. code-block:: bash 70 | vyper yourFileName.vy 71 | # returns bytecode 72 | 73 | Or deploy it with current browser on `myetherwallet `_ contract menu. 74 | 75 | We are working on integration with `populus `_, 76 | this will be the preferred way of deploying vyper contracts in the future. 77 | -------------------------------------------------------------------------------- /docs/vyper-logo-transparent.svg: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /examples/auctions/simple_open_auction.vy: -------------------------------------------------------------------------------- 1 | # Open Auction 2 | 3 | # Auction params 4 | # Beneficiary receives money from the highest bidder 5 | beneficiary: public(address) 6 | auctionStart: public(timestamp) 7 | auctionEnd: public(timestamp) 8 | 9 | # Current state of auction 10 | highestBidder: public(address) 11 | highestBid: public(wei_value) 12 | 13 | # Set to true at the end, disallows any change 14 | ended: public(bool) 15 | 16 | # Create a simple auction with `_bidding_time` 17 | # seconds bidding time on behalf of the 18 | # beneficiary address `_beneficiary`. 19 | @public 20 | def __init__(_beneficiary: address, _bidding_time: timedelta): 21 | self.beneficiary = _beneficiary 22 | self.auctionStart = block.timestamp 23 | self.auctionEnd = self.auctionStart + _bidding_time 24 | 25 | # Bid on the auction with the value sent 26 | # together with this transaction. 27 | # The value will only be refunded if the 28 | # auction is not won. 29 | @public 30 | @payable 31 | def bid(): 32 | # Check if bidding period is over. 33 | assert block.timestamp < self.auctionEnd 34 | # Check if bid is high enough 35 | assert msg.value > self.highestBid 36 | if not self.highestBid == 0: 37 | # Sends money back to the previous highest bidder 38 | send(self.highestBidder, self.highestBid) 39 | self.highestBidder = msg.sender 40 | self.highestBid = msg.value 41 | 42 | 43 | # End the auction and send the highest bid 44 | # to the beneficiary. 45 | @public 46 | def endAuction(): 47 | # It is a good guideline to structure functions that interact 48 | # with other contracts (i.e. they call functions or send Ether) 49 | # into three phases: 50 | # 1. checking conditions 51 | # 2. performing actions (potentially changing conditions) 52 | # 3. interacting with other contracts 53 | # If these phases are mixed up, the other contract could call 54 | # back into the current contract and modify the state or cause 55 | # effects (Ether payout) to be performed multiple times. 56 | # If functions called internally include interaction with external 57 | # contracts, they also have to be considered interaction with 58 | # external contracts. 59 | 60 | # 1. Conditions 61 | # Check if auction endtime has been reached 62 | assert block.timestamp >= self.auctionEnd 63 | # Check if this function has already been called 64 | assert not self.ended 65 | 66 | # 2. Effects 67 | self.ended = True 68 | 69 | # 3. Interaction 70 | send(self.beneficiary, self.highestBid) 71 | -------------------------------------------------------------------------------- /examples/crowdfund.vy: -------------------------------------------------------------------------------- 1 | # Setup private variables (only callable from within the contract) 2 | funders: {sender: address, value: wei_value}[int128] 3 | nextFunderIndex: int128 4 | beneficiary: address 5 | deadline: timestamp 6 | goal: wei_value 7 | refundIndex: int128 8 | timelimit: timedelta 9 | 10 | 11 | # Setup global variables 12 | @public 13 | def __init__(_beneficiary: address, _goal: wei_value, _timelimit: timedelta): 14 | self.beneficiary = _beneficiary 15 | self.deadline = block.timestamp + _timelimit 16 | self.timelimit = _timelimit 17 | self.goal = _goal 18 | 19 | 20 | # Participate in this crowdfunding campaign 21 | @public 22 | @payable 23 | def participate(): 24 | assert block.timestamp < self.deadline 25 | 26 | nfi: int128 = self.nextFunderIndex 27 | 28 | self.funders[nfi] = {sender: msg.sender, value: msg.value} 29 | self.nextFunderIndex = nfi + 1 30 | 31 | 32 | # Enough money was raised! Send funds to the beneficiary 33 | @public 34 | def finalize(): 35 | assert block.timestamp >= self.deadline and self.balance >= self.goal 36 | 37 | selfdestruct(self.beneficiary) 38 | 39 | 40 | # Not enough money was raised! Refund everyone (max 30 people at a time 41 | # to avoid gas limit issues) 42 | @public 43 | def refund(): 44 | assert block.timestamp >= self.deadline and self.balance < self.goal 45 | 46 | ind: int128 = self.refundIndex 47 | 48 | for i in range(ind, ind + 30): 49 | if i >= self.nextFunderIndex: 50 | self.refundIndex = self.nextFunderIndex 51 | return 52 | 53 | send(self.funders[i].sender, self.funders[i].value) 54 | self.funders[i] = None 55 | 56 | self.refundIndex = ind + 30 57 | -------------------------------------------------------------------------------- /examples/market_maker/on_chain_market_maker.vy: -------------------------------------------------------------------------------- 1 | units: { 2 | currency_value: "a currency" 3 | } 4 | 5 | totalEthQty: public(wei_value) 6 | totalTokenQty: public(uint256(currency_value)) 7 | # Constant set in `initiate` that's used to calculate 8 | # the amount of ether/tokens that are exchanged 9 | invariant: public(uint256(wei * currency_value)) 10 | token_address: address(ERC20) 11 | owner: public(address) 12 | 13 | # Sets the on chain market maker with its owner, intial token quantity, 14 | # and initial ether quantity 15 | @public 16 | @payable 17 | def initiate(token_addr: address, token_quantity: uint256(currency_value)): 18 | assert self.invariant == 0 19 | self.token_address = token_addr 20 | self.token_address.transferFrom(msg.sender, self, as_unitless_number(token_quantity)) 21 | self.owner = msg.sender 22 | self.totalEthQty = msg.value 23 | self.totalTokenQty = token_quantity 24 | self.invariant = msg.value * token_quantity 25 | assert self.invariant > 0 26 | 27 | # Sells ether to the contract in exchange for tokens (minus a fee) 28 | @public 29 | @payable 30 | def ethToTokens(): 31 | fee: wei_value = msg.value / 500 32 | eth_in_purchase: wei_value = msg.value - fee 33 | new_total_eth: wei_value = self.totalEthQty + eth_in_purchase 34 | new_total_tokens: uint256(currency_value) = self.invariant / new_total_eth 35 | self.token_address.transfer(msg.sender, as_unitless_number(self.totalTokenQty - new_total_tokens)) 36 | self.totalEthQty = new_total_eth 37 | self.totalTokenQty = new_total_tokens 38 | 39 | # Sells tokens to the contract in exchange for ether 40 | @public 41 | def tokensToEth(sell_quantity: uint256(currency_value)): 42 | self.token_address.transferFrom(msg.sender, self, as_unitless_number(sell_quantity)) 43 | new_total_tokens: uint256(currency_value) = self.totalTokenQty + sell_quantity 44 | new_total_eth: wei_value = self.invariant / new_total_tokens 45 | eth_to_send: wei_value = self.totalEthQty - new_total_eth 46 | send(msg.sender, eth_to_send) 47 | self.totalEthQty = new_total_eth 48 | self.totalTokenQty = new_total_tokens 49 | 50 | # Owner can withdraw their funds and destroy the market maker 51 | @public 52 | def ownerWithdraw(): 53 | assert self.owner == msg.sender 54 | self.token_address.transfer(self.owner, as_unitless_number(self.totalTokenQty)) 55 | selfdestruct(self.owner) 56 | -------------------------------------------------------------------------------- /examples/name_registry/name_registry.vy: -------------------------------------------------------------------------------- 1 | 2 | registry: address[bytes[100]] 3 | 4 | 5 | @public 6 | def register(name: bytes[100], owner: address): 7 | assert self.registry[name] == ZERO_ADDRESS # check name has not been set yet. 8 | self.registry[name] = owner 9 | 10 | 11 | @public 12 | @constant 13 | def lookup(name: bytes[100]) -> address: 14 | return self.registry[name] 15 | -------------------------------------------------------------------------------- /examples/safe_remote_purchase/safe_remote_purchase.vy: -------------------------------------------------------------------------------- 1 | #Safe Remote Purchase 2 | #Originally from 3 | #https://github.com/ethereum/solidity/blob/develop/docs/solidity-by-example.rst 4 | #ported to vyper and optimized 5 | 6 | #Rundown of the transaction: 7 | #1. Seller posts item for sale and posts safety deposit of double the item value. 8 | # Balance is 2*value. 9 | #(1.1. Seller can reclaim deposit and close the sale as long as nothing was purchased.) 10 | #2. Buyer purchases item (value) plus posts an additional safety deposit (Item value). 11 | # Balance is 4*value. 12 | #3. Seller ships item. 13 | #4. Buyer confirms receiving the item. Buyer's deposit (value) is returned. 14 | #Seller's deposit (2*value) + items value is returned. Balance is 0. 15 | 16 | value: public(wei_value) #Value of the item 17 | seller: public(address) 18 | buyer: public(address) 19 | unlocked: public(bool) 20 | #@constant 21 | #def unlocked() -> bool: #Is a refund possible for the seller? 22 | # return (self.balance == self.value*2) 23 | 24 | @public 25 | @payable 26 | def __init__(): 27 | assert (msg.value % 2) == 0 28 | self.value = msg.value / 2 #The seller initializes the contract by 29 | #posting a safety deposit of 2*value of the item up for sale. 30 | self.seller = msg.sender 31 | self.unlocked = True 32 | 33 | @public 34 | def abort(): 35 | assert self.unlocked #Is the contract still refundable? 36 | assert msg.sender == self.seller #Only the seller can refund 37 | # his deposit before any buyer purchases the item. 38 | selfdestruct(self.seller) #Refunds the seller and deletes the contract. 39 | 40 | @public 41 | @payable 42 | def purchase(): 43 | assert self.unlocked #Is the contract still open (is the item still up for sale)? 44 | assert msg.value == (2 * self.value) #Is the deposit the correct value? 45 | self.buyer = msg.sender 46 | self.unlocked = False 47 | 48 | @public 49 | def received(): 50 | assert not self.unlocked #Is the item already purchased and pending confirmation 51 | # from the buyer? 52 | assert msg.sender == self.buyer 53 | send(self.buyer, self.value) #Return the buyer's deposit (=value) to the buyer. 54 | selfdestruct(self.seller) #Return the seller's deposit (=2*value) 55 | # and the purchase price (=value) to the seller. 56 | -------------------------------------------------------------------------------- /examples/tokens/ERC20.vy: -------------------------------------------------------------------------------- 1 | # Vyper Port of MyToken 2 | # THIS CONTRACT HAS NOT BEEN AUDITED! 3 | # ERC20 details at: 4 | # https://theethereum.wiki/w/index.php/ERC20_Token_Standard 5 | # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md 6 | 7 | 8 | # Events of the token. 9 | Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256}) 10 | Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256}) 11 | 12 | 13 | # Variables of the token. 14 | name: public(bytes32) 15 | symbol: public(bytes32) 16 | totalSupply: public(uint256) 17 | decimals: public(int128) 18 | balances: int128[address] 19 | allowed: int128[address][address] 20 | 21 | 22 | @public 23 | def __init__(_name: bytes32, _symbol: bytes32, _decimals: uint256, _initialSupply: uint256): 24 | self.name = _name 25 | self.symbol = _symbol 26 | self.decimals = _decimals 27 | self.totalSupply =_initialSupply * convert(10, 'uint256') ** _decimals 28 | self.balances[msg.sender] = convert(self.totalSupply, 'int128') 29 | 30 | 31 | # What is the balance of a particular account? 32 | @public 33 | @constant 34 | def balanceOf(_owner: address) -> uint256: 35 | 36 | return convert(self.balances[_owner], 'uint256') 37 | 38 | 39 | # Send `_value` tokens to `_to` from your account 40 | @public 41 | def transfer(_to: address, _amount: int128(uint256)) -> bool: 42 | 43 | if self.balances[msg.sender] >= _amount and \ 44 | self.balances[_to] + _amount >= self.balances[_to]: 45 | 46 | self.balances[msg.sender] -= _amount # Subtract from the sender 47 | self.balances[_to] += _amount # Add the same to the recipient 48 | log.Transfer(msg.sender, _to, convert(_amount, 'uint256')) # log transfer event. 49 | 50 | return True 51 | else: 52 | return False 53 | 54 | 55 | # Transfer allowed tokens from a specific account to another. 56 | @public 57 | def transferFrom(_from: address, _to: address, _value: int128(uint256)) -> bool: 58 | 59 | if _value <= self.allowed[_from][msg.sender] and \ 60 | _value <= self.balances[_from]: 61 | 62 | self.balances[_from] -= _value # decrease balance of from address. 63 | self.allowed[_from][msg.sender] -= _value # decrease allowance. 64 | self.balances[_to] += _value # incease balance of to address. 65 | log.Transfer(_from, _to, convert(_value, 'uint256')) # log transfer event. 66 | 67 | return True 68 | else: 69 | return False 70 | 71 | 72 | # Allow _spender to withdraw from your account, multiple times, up to the _value amount. 73 | # If this function is called again it overwrites the current allowance with _value. 74 | @public 75 | def approve(_spender: address, _amount: int128(uint256)) -> bool: 76 | 77 | self.allowed[msg.sender][_spender] = _amount 78 | log.Approval(msg.sender, _spender, convert(_amount, 'uint256')) 79 | 80 | return True 81 | 82 | 83 | # Get the allowence an address has to spend anothers' token. 84 | @public 85 | def allowance(_owner: address, _spender: address) -> uint256: 86 | 87 | return convert(self.allowed[_owner][_spender], 'uint256') 88 | -------------------------------------------------------------------------------- /examples/tokens/ERC20_solidity_compatible/ERC20.vy: -------------------------------------------------------------------------------- 1 | # Solidity-Compatible EIP20/ERC20 Token 2 | # Implements https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md 3 | # Author: Phil Daian 4 | 5 | # The use of the uint256 datatype as in this token is not 6 | # recommended, as it can pose security risks. 7 | 8 | # This token is intended as a proof of concept towards 9 | # language interoperability and not for production use. 10 | 11 | # Events issued by the contract 12 | Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256(wei)}) 13 | Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256(wei)}) 14 | 15 | balances: uint256(wei)[address] 16 | allowances: (uint256(wei)[address])[address] 17 | num_issued: uint256(wei) 18 | 19 | @public 20 | @payable 21 | def deposit(): 22 | _value: uint256(wei) = msg.value 23 | _sender: address = msg.sender 24 | self.balances[_sender] = self.balances[_sender] + _value 25 | self.num_issued = self.num_issued + _value 26 | # Fire deposit event as transfer from 0x0 27 | log.Transfer(0x0000000000000000000000000000000000000000, _sender, _value) 28 | 29 | @public 30 | def withdraw(_value : uint256(wei)) -> bool: 31 | _sender: address = msg.sender 32 | # Make sure sufficient funds are present, op will not underflow supply 33 | # implicitly through overflow protection 34 | self.balances[_sender] = self.balances[_sender] - _value 35 | self.num_issued = self.num_issued - _value 36 | send(_sender, _value) 37 | # Fire withdraw event as transfer to 0x0 38 | log.Transfer(_sender, 0x0000000000000000000000000000000000000000, _value) 39 | return True 40 | 41 | @public 42 | @constant 43 | def totalSupply() -> uint256(wei): 44 | return self.num_issued 45 | 46 | @public 47 | @constant 48 | def balanceOf(_owner : address) -> uint256(wei): 49 | return self.balances[_owner] 50 | 51 | @public 52 | def transfer(_to : address, _value : uint256(wei)) -> bool: 53 | _sender: address = msg.sender 54 | # Make sure sufficient funds are present implicitly through overflow protection 55 | self.balances[_sender] = self.balances[_sender] - _value 56 | self.balances[_to] = self.balances[_to] + _value 57 | # Fire transfer event 58 | log.Transfer(_sender, _to, _value) 59 | return True 60 | 61 | @public 62 | def transferFrom(_from : address, _to : address, _value : uint256(wei)) -> bool: 63 | _sender: address = msg.sender 64 | allowance: uint256(wei) = self.allowances[_from][_sender] 65 | # Make sure sufficient funds/allowance are present implicitly through overflow protection 66 | self.balances[_from] = self.balances[_from] - _value 67 | self.balances[_to] = self.balances[_to] + _value 68 | self.allowances[_from][_sender] = allowance - _value 69 | # Fire transfer event 70 | log.Transfer(_from, _to, _value) 71 | return True 72 | 73 | @public 74 | def approve(_spender : address, _value : uint256(wei)) -> bool: 75 | _sender: address = msg.sender 76 | self.allowances[_sender][_spender] = _value 77 | # Fire approval event 78 | log.Approval(_sender, _spender, _value) 79 | return True 80 | 81 | @public 82 | @constant 83 | def allowance(_owner : address, _spender : address) -> uint256(wei): 84 | return self.allowances[_owner][_spender] 85 | 86 | -------------------------------------------------------------------------------- /examples/tokens/ERC20_solidity_compatible/README.md: -------------------------------------------------------------------------------- 1 | The Solidity-Compatible ERC20 2 | ----------------------------- 3 | 4 | The code in this example aims at the creation of an 5 | [ERC20](https://github.com/ethereum/EIPs/issues/20) token that is fully Solidity 6 | compatible, and exhibits identical behavior to a Solidity-based ERC20 token. 7 | 8 | ERC20 was chosen due to its popularity in the wider community and its handling of 9 | large quantities of funds. Unfortunately, the ERC20 specification is written with 10 | Solidity in mind, and includes Solidity-specific data types in the function 11 | definitions. 12 | 13 | **To achieve full Solidity compatibility, we use the low-level num256 datatype in 14 | Vyper. This is NOT recommended for contracts where either full Solidity compatibility 15 | is not required, or no other compelling usage for using num256 over num exists**. 16 | Notably, num256 is not overflow protected and may not support all the automatic 17 | security features of *num* as the language evolves. As the code of this token shows, 18 | the use of num256 over num also significantly complicates the contract code. 19 | 20 | **THIS TOKEN HAS NOT BEEN AUDITED AND IS NOT RECOMMENDED FOR PRODUCTION FUNDS**. 21 | While the authors have made every effort to ensure the security of the supplied code, 22 | funds loss is always a possibility, and both Vyper's compiler and language remain 23 | nascent and rapidly evolving. 24 | 25 | Testing 26 | ------- 27 | 28 | This set of ERC20s includes a test suite that achieves: 29 | 30 | - 100% branch and statement coverage (manually verified). 31 | - Independent tests from two test authors. 32 | - Differential testing against two example Solidity tokens, written independently 33 | (available in the ``nonvyper`` tests subfolder and annotated with comments). 34 | 35 | To run the tests, a local installation of pyethereum, Solidity, and Vyper is required. 36 | After installing the dependencies, run ``python run_tests.py`` in the test directory corresponding 37 | to this example. 38 | 39 | Future Plans / TODO 40 | ------------------- 41 | 42 | Interesting potential extensions of this token include: 43 | 44 | - [ERC223](https://github.com/ethereum/EIPs/issues/223) functionality and testing. 45 | - Full formal verification. This is underway using the [KEVM project](https://github.com/kframework/evm-semantics). 46 | - Examples of other common token usage patterns (owner-mintable tokens being one 47 | possible example). 48 | -------------------------------------------------------------------------------- /examples/tokens/vypercoin.vy: -------------------------------------------------------------------------------- 1 | # Vyper Port of MyToken 2 | # THIS CONTRACT HAS NOT BEEN AUDITED! 3 | # ERC20 details at: 4 | # https://theethereum.wiki/w/index.php/ERC20_Token_Standard 5 | # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md 6 | # Events of the token. 7 | Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256}) 8 | Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256}) 9 | 10 | 11 | # Variables of the token. 12 | name: public(bytes32) 13 | symbol: public(bytes32) 14 | totalSupply: public(uint256) 15 | decimals: public(uint256) 16 | balances: uint256[address] 17 | allowed: uint256[address][address] 18 | 19 | @public 20 | def __init__(_name: bytes32, _symbol: bytes32, _decimals: uint256, _initialSupply: uint256): 21 | 22 | assert _initialSupply * 10 ** _decimals >= _initialSupply 23 | self.totalSupply =_initialSupply * 10 ** _decimals 24 | self.balances[msg.sender] = self.totalSupply 25 | self.name = _name 26 | self.symbol = _symbol 27 | self.decimals = _decimals 28 | log.Transfer(ZERO_ADDRESS, msg.sender, self.totalSupply) 29 | 30 | 31 | # What is the balance of a particular account? 32 | @public 33 | @constant 34 | def balanceOf(_owner: address) -> uint256: 35 | 36 | return self.balances[_owner] 37 | 38 | 39 | # Send `_value` tokens to `_to` from your account 40 | @public 41 | def transfer(_to: address, _amount: uint256) -> bool: 42 | 43 | assert self.balances[msg.sender] >= _amount 44 | 45 | self.balances[msg.sender] -= _amount # Subtract from the sender 46 | self.balances[_to] += _amount # Add the same to the recipient 47 | log.Transfer(msg.sender, _to, _amount) # log transfer event. 48 | 49 | return True 50 | 51 | 52 | # Transfer allowed tokens from a specific account to another. 53 | @public 54 | def transferFrom(_from: address, _to: address, _value: uint256) -> bool: 55 | 56 | assert _value <= self.allowed[_from][msg.sender] 57 | assert _value <= self.balances[_from] 58 | 59 | self.balances[_from] -= _value # decrease balance of from address. 60 | self.allowed[_from][msg.sender] -= _value # decrease allowance. 61 | self.balances[_to] += _value # increase balance of to address. 62 | log.Transfer(_from, _to, _value) # log transfer event. 63 | 64 | return True 65 | 66 | 67 | # Allow _spender to withdraw from your account, multiple times, up to the _value amount. 68 | # If this function is called again it overwrites the current allowance with _value. 69 | @public 70 | def approve(_spender: address, _amount: uint256) -> bool: 71 | 72 | self.allowed[msg.sender][_spender] = _amount 73 | log.Approval(msg.sender, _spender, _amount) 74 | 75 | return True 76 | 77 | 78 | # Get the allowance an address has to spend another's token. 79 | @public 80 | def allowance(_owner: address, _spender: address) -> uint256: 81 | 82 | return self.allowed[_owner][_spender] 83 | -------------------------------------------------------------------------------- /examples/wallet/sign.js: -------------------------------------------------------------------------------- 1 | // Expects: 2 | // seq: big integer or number 3 | // to: address, in the form 0x46d241f4.... 4 | // value: big integer or number 5 | // data: hex data 6 | function sign(seq, to, value, data, signingAddr) { 7 | var seqHex = web3.toHex(seq).substr(2); 8 | while (seqHex.length < 64) 9 | seqHex = "0" + seqHex; 10 | var valueHex = web3.toHex(value).substr(2); 11 | while (valueHex.length < 64) 12 | valueHex = "0" + valueHex; 13 | var concatData = "0x" + seqHex + "000000000000000000000000" + to.substr(2) + valueHex + data.substr(2); 14 | var hash = web3.sha3(concatData, {encoding: 'hex'}); 15 | return web3.eth.sign(signingAddr, hash); 16 | } 17 | -------------------------------------------------------------------------------- /examples/wallet/wallet.vy: -------------------------------------------------------------------------------- 1 | # An example of how you can do a wallet in Vyper. 2 | # Warning: NOT AUDITED. Do not use to store substantial quantities of funds. 3 | 4 | # A list of the owners addresses (there are a maximum of 5 owners) 5 | owners: public(address[5]) 6 | # The number of owners required to approve a transaction 7 | threshold: int128 8 | # The number of transactions that have been approved 9 | seq: public(int128) 10 | 11 | 12 | @public 13 | def __init__(_owners: address[5], _threshold: int128): 14 | for i in range(5): 15 | if _owners[i] != ZERO_ADDRESS: 16 | self.owners[i] = _owners[i] 17 | self.threshold = _threshold 18 | 19 | 20 | @public 21 | def testEcrecover(h: bytes32, v:uint256, r:uint256, s:uint256) -> address: 22 | return ecrecover(h, v, r, s) 23 | 24 | 25 | # `@payable` allows functions to receive ether 26 | @public 27 | @payable 28 | def approve(_seq: int128, to: address, value: wei_value, data: bytes[4096], sigdata: uint256[3][5]) -> bytes[4096]: 29 | # Throws if the value sent to the contract is less than the sum of the value to be sent 30 | assert msg.value >= value 31 | # Every time the number of approvals starts at 0 (multiple signatures can be added through the sigdata argument) 32 | approvals: int128 = 0 33 | # Starts by combining: 34 | # 1) The number of transactions approved thus far. 35 | # 2) The address the transaction is going to be sent to (can be a contract or a user). 36 | # 3) The value in wei that will be sent with this transaction. 37 | # 4) The data to be sent with this transaction (usually data is used to deploy contracts or to call functions on contracts, but you can put whatever you want in it). 38 | # Takes the sha3 (keccak256) hash of the combination 39 | h: bytes32 = sha3(concat(convert(_seq, bytes32), convert(to, bytes32), convert(value, bytes32), data)) 40 | # Then we combine the Ethereum Signed message with our previous hash 41 | # Owners will have to sign the below message 42 | h2: bytes32 = sha3(concat("\x19Ethereum Signed Message:\n32", h)) 43 | # Verifies that the caller of approve has entered the correct transaction number 44 | assert self.seq == _seq 45 | # # Iterates through all the owners and verifies that there signatures, 46 | # # given as the sigdata argument are correct 47 | for i in range(5): 48 | if sigdata[i][0] != 0: 49 | # If an invalid signature is given for an owner then the contract throws 50 | assert ecrecover(h2, sigdata[i][0], sigdata[i][1], sigdata[i][2]) == self.owners[i] 51 | # For every valid signature increase the number of approvals by 1 52 | approvals += 1 53 | # Throw if the number of approvals is less then the number of approvals required (the threshold) 54 | assert approvals >= self.threshold 55 | # The transaction has been approved 56 | # Increase the number of approved transactions by 1 57 | self.seq += 1 58 | # Use raw_call to send the transaction 59 | return raw_call(to, data, outsize=4096, gas=3000000, value=value) 60 | 61 | 62 | @public 63 | @payable 64 | def __default__(): 65 | pass 66 | -------------------------------------------------------------------------------- /logo/vyper-logo-flat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/logo/vyper-logo-flat.png -------------------------------------------------------------------------------- /logo/vyper-logo-flat.svg: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /logo/vyper-logo-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/logo/vyper-logo-transparent.png -------------------------------------------------------------------------------- /logo/vyper-logo-transparent.svg: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /logo/vyper-logo.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/logo/vyper-logo.ai -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | bumpversion -------------------------------------------------------------------------------- /requirements-docs.txt: -------------------------------------------------------------------------------- 1 | sphinx==1.6.3 2 | recommonmark==0.4.0 3 | sphinx_rtd_theme==0.2.4 4 | -------------------------------------------------------------------------------- /scripts/fixed_address_creator.py: -------------------------------------------------------------------------------- 1 | from ethereum import transactions, utils 2 | import rlp 3 | from ethereum.slogging import LogRecorder, configure_logging, set_level 4 | config_string = ':info,eth.vm.log:trace,eth.vm.op:trace,eth.vm.stack:trace,eth.vm.exit:trace,eth.pb.msg:trace,eth.pb.tx:debug' 5 | from vyper import optimizer, compile_lll 6 | from rlp_decoder import rlp_decoder_bytes 7 | 8 | def encode_vals(vals): 9 | o = b'' 10 | for v in vals: 11 | if isinstance(v, int): 12 | o += utils.encode_int32(v) 13 | else: 14 | o += v 15 | return o 16 | 17 | # Run some tests first 18 | 19 | from ethereum.tools import tester as t 20 | t.gas_limit = 1000000 21 | chain = t.Chain() 22 | t.s = chain 23 | 24 | rlp_decoder_address = t.s.tx(to=b'', data=rlp_decoder_bytes) 25 | assert t.s.tx(sender=t.k0, to=rlp_decoder_address, data=rlp.encode([b'\x45', b'\x95'])) == encode_vals([96, 129, 162, 1, b"\x45", 1, b"\x95"]) 26 | assert t.s.tx(sender=t.k0, to=rlp_decoder_address, data=rlp.encode([b'cow', b'dog']))== encode_vals([96, 131, 166, 3, b"cow", 3, b"dog"]) 27 | assert t.s.tx(sender=t.k0, to=rlp_decoder_address, data=rlp.encode([]))== encode_vals([32]) 28 | assert t.s.tx(sender=t.k0, to=rlp_decoder_address, data=rlp.encode([b'\x73' * 100, b'dog']))== encode_vals([96, 228, 263, 100, b"\x73" * 100, 3, b"dog"]) 29 | assert t.s.tx(sender=t.k0, to=rlp_decoder_address, data=utils.decode_hex('f6943535353535353535353535353535353535353535a04747474747474747474747474747474747474747474747474747474747474747'))== encode_vals([96, 148, 212, 20, b'\x35' * 20, 32, b'\x47' * 32]) 30 | print("Checks passed!") 31 | 32 | t.s.tx(sender=t.k0, to=rlp_decoder_address, data=rlp.encode([])) 33 | g1 = t.s.head_state.receipts[-1].gas_used - t.s.head_state.receipts[-2].gas_used - t.s.last_tx.intrinsic_gas_used 34 | t.s.tx(sender=t.k0, to=rlp_decoder_address, data=rlp.encode([b'\x03' * 500])) 35 | g2 = t.s.head_state.receipts[-1].gas_used - t.s.head_state.receipts[-2].gas_used - t.s.last_tx.intrinsic_gas_used 36 | t.s.tx(sender=t.k0, to=rlp_decoder_address, data=rlp.encode([b'\x03'] * 25)) 37 | g3 = t.s.head_state.receipts[-1].gas_used - t.s.head_state.receipts[-2].gas_used - t.s.last_tx.intrinsic_gas_used 38 | t.s.tx(sender=t.k0, to=rlp_decoder_address, data=rlp.encode([b'\x03'] * 24 + [b'\x03' * 500])) 39 | g4 = t.s.head_state.receipts[-1].gas_used - t.s.head_state.receipts[-2].gas_used - t.s.last_tx.intrinsic_gas_used 40 | 41 | print("500 bytes increment: %d" % (g2 - g1)) 42 | print("500 bytes increment: %d" % (g4 - g3)) 43 | print("25 items increment: %d" % (g3 - g1)) 44 | print("25 items increment: %d" % (g4 - g2)) 45 | 46 | 47 | # Create transaction 48 | t = transactions.Transaction(0, 30 * 10**9, 2999999, '', 0, rlp_decoder_bytes) 49 | t.startgas = t.intrinsic_gas_used + 50000 + 200 * len(rlp_decoder_bytes) 50 | t.v = 27 51 | t.r = 45 52 | t.s = 79 53 | print("RLP decoder") 54 | print("Instructions for launching:") 55 | print('First send %d wei to %s' % (t.startgas * t.gasprice, 56 | utils.checksum_encode(t.sender))) 57 | print('Publish this tx to create the contract: 0x'+utils.encode_hex(rlp.encode(t))) 58 | print('This is the contract address: '+utils.checksum_encode(utils.mk_contract_address(t.sender, 0))) 59 | -------------------------------------------------------------------------------- /scripts/forwarder.py: -------------------------------------------------------------------------------- 1 | from ethereum import utils 2 | 3 | def mk_forwarder(address): 4 | code = b'\x36\x60\x00\x60\x00\x37' # CALLDATACOPY 0 0 (CALLDATASIZE) 5 | code += b'\x61\x10\x00\x60\x00\x36\x60\x00' # 4096 0 CALLDATASIZE 0 6 | code += b'\x73' + utils.normalize_address(address) + b'\x5a' # address gas 7 | code += b'\xf4' # delegatecall 8 | code += b'\x15\x58\x57' # ISZERO PC JUMPI (fail if inner call fails) 9 | code += b'\x61\x10\x00\x60\x00\xf3' # 4096 0 RETURN 10 | return code 11 | 12 | def mk_wrapper(code): 13 | lencodepush = b'\x60' + utils.encode_int(len(code)) # length of code 14 | returner = lencodepush + b'\x60\x0c\x60\x00' # start from 12 in code, 0 in memory 15 | returner += b'\x39' # CODECOPY 16 | returner += lencodepush + b'\x60\x00' + b'\xf3' # return code 17 | assert len(returner) == 12 18 | return returner + code 19 | 20 | kode = """ 21 | moose: num 22 | def increment_moose(i: num) -> num: 23 | self.moose += i 24 | return self.moose 25 | """ 26 | 27 | def test(): 28 | from ethereum.tools import tester2 29 | c = tester2.Chain() 30 | x = c.contract(kode, language='vyper', sender=tester2.k3) 31 | fwdcode = mk_forwarder(x.address) 32 | initcode = mk_wrapper(fwdcode) 33 | print('Forwarder code:', initcode) 34 | y = c.contract(initcode, language='evm') 35 | assert c.head_state.get_code(y) == fwdcode 36 | z = tester2.ABIContract(c, x.translator, y) 37 | assert z.increment_moose(3) == 3 38 | assert z.increment_moose(5) == 8 39 | print('Tests passed') 40 | 41 | if __name__ == '__main__': 42 | test() 43 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.1.0-beta.4 3 | commit = True 4 | tag = True 5 | 6 | [bumpversion:file:setup.py] 7 | search = version = "{current_version}" 8 | 9 | [aliases] 10 | test = pytest 11 | 12 | [tool:pytest] 13 | addopts = --cov-report term --cov-report html --cov=vyper 14 | python_files = test_*.py 15 | testpaths = tests 16 | 17 | [flake8] 18 | exclude = docs 19 | ignore = 20 | E122 21 | E124 22 | E127 23 | E128 24 | E501 25 | E731 26 | W504 27 | 28 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from setuptools import setup, find_packages 4 | 5 | 6 | setup( 7 | name='vyper', 8 | # *IMPORTANT*: Don't manually change the version here. Use the 'bumpversion' utility. 9 | version='0.1.0-beta.4', 10 | description='Vyper Programming Language for Ethereum', 11 | long_description_markdown_filename='README.md', 12 | author='Vitalik Buterin', 13 | author_email='', 14 | url='https://github.com/ethereum/vyper', 15 | license="MIT", 16 | keywords='ethereum', 17 | include_package_data=True, 18 | packages=find_packages(exclude=('tests', 'docs')), 19 | python_requires='>=3.6', 20 | py_modules=['vyper'], 21 | install_requires=[ 22 | 'pycryptodome>=3.5.1,<4', 23 | ], 24 | setup_requires=[ 25 | 'pytest-runner' 26 | ], 27 | tests_require=[ 28 | 'pytest', 29 | 'pytest-cov', 30 | 'py-evm==0.2.0a32', 31 | 'eth-tester[py-evm]==0.1.0b32', 32 | 'web3==4.4.1', 33 | ], 34 | scripts=[ 35 | 'bin/vyper', 36 | 'bin/vyper-serve', 37 | 'bin/vyper-lll' 38 | ], 39 | classifiers=[ 40 | 'Intended Audience :: Developers', 41 | 'License :: OSI Approved :: MIT License', 42 | 'Programming Language :: Python :: 3.6', 43 | ] 44 | ) 45 | -------------------------------------------------------------------------------- /snap/snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: vyper 2 | version: git 3 | summary: Experimental language for the Ethereum Virtual Machine 4 | description: | 5 | Vyper is an contract-oriented, pythonic programming language that targets the Ethereum Virtual Machine (EVM) 6 | 7 | grade: devel # must be 'stable' to release into candidate/stable channels 8 | confinement: devmode # use 'strict' once you have the right plugs and slots 9 | 10 | apps: 11 | vyper: 12 | command: vyper 13 | 14 | parts: 15 | vyper: 16 | source: . 17 | plugin: python 18 | python-version: python3 19 | after: [python] 20 | stage: 21 | - -usr/bin/python3 22 | python: 23 | source: https://www.python.org/ftp/python/3.6.3/Python-3.6.3.tar.xz 24 | plugin: autotools 25 | configflags: 26 | - --prefix=/usr 27 | build-packages: 28 | - gcc 29 | - libreadline-dev 30 | - libncursesw5-dev 31 | - zlib1g-dev 32 | - libbz2-dev 33 | - liblzma-dev 34 | - libgdbm-dev 35 | - libdb-dev 36 | - libssl-dev 37 | - libexpat1-dev 38 | - libmpdec-dev 39 | - libbluetooth-dev 40 | - libsqlite3-dev 41 | - libffi-dev 42 | stage-packages: 43 | - libc6 44 | stage: 45 | - -usr/lib/python3.6/test 46 | - -usr/bin/pydoc3 47 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/tests/__init__.py -------------------------------------------------------------------------------- /tests/compiler/LLL/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/tests/compiler/LLL/__init__.py -------------------------------------------------------------------------------- /tests/compiler/LLL/test_compile_lll.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from vyper.parser.parser import LLLnode 4 | from vyper.parser.s_expressions import parse_s_exp 5 | 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_lll', fail_list) 20 | def test_lll_compile_fail(bad_lll, get_contract_from_lll, assert_compile_failed): 21 | assert_compile_failed( 22 | lambda: get_contract_from_lll(LLLnode.from_list(bad_lll)), 23 | Exception 24 | ) 25 | 26 | 27 | valid_list = [ 28 | ['pass'], 29 | ['clamplt', ['mload', 0], 300], 30 | ['clampgt', ['mload', 0], -1], 31 | ['uclampgt', 1, ['mload', 0]], 32 | ['uclampge', ['mload', 0], 0], 33 | ] 34 | 35 | 36 | @pytest.mark.parametrize('good_lll', valid_list) 37 | def test_compile_lll_good(good_lll, get_contract_from_lll): 38 | get_contract_from_lll(LLLnode.from_list(good_lll)) 39 | 40 | 41 | def test_lll_from_s_expression(get_contract_from_lll): 42 | code = """ 43 | (seq 44 | (return 45 | 0 46 | (lll ; just return 32 byte of calldata back 47 | (seq 48 | (calldatacopy 0 4 32) 49 | (return 0 32) 50 | stop 51 | ) 52 | 0))) 53 | """ 54 | abi = [{ 55 | "name": "test", 56 | "outputs": [{ 57 | "type": "int128", 58 | "name": "out" 59 | }], 60 | "inputs": [{ 61 | "type": "int128", 62 | "name": "a" 63 | }], 64 | "constant": False, 65 | "payable": False, 66 | "type": "function", 67 | "gas": 394 68 | }] 69 | 70 | s_expressions = parse_s_exp(code) 71 | lll = LLLnode.from_list(s_expressions[0]) 72 | c = get_contract_from_lll(lll, abi=abi) 73 | assert c.test(-123456) == -123456 74 | -------------------------------------------------------------------------------- /tests/compiler/LLL/test_repeat.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def test_repeat(get_contract_from_lll, assert_compile_failed): 4 | good_lll = ['repeat', 0, 0, 1, ['seq']] 5 | bad_lll_1 = ['repeat', 0, 0, 0, ['seq']] 6 | bad_lll_2 = ['repeat', 0, 0, -1, ['seq']] 7 | get_contract_from_lll(good_lll) 8 | assert_compile_failed(lambda: get_contract_from_lll(bad_lll_1), Exception) 9 | assert_compile_failed(lambda: get_contract_from_lll(bad_lll_2), Exception) 10 | -------------------------------------------------------------------------------- /tests/compiler/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/tests/compiler/__init__.py -------------------------------------------------------------------------------- /tests/compiler/test_bytecode_runtime.py: -------------------------------------------------------------------------------- 1 | from vyper import compiler 2 | 3 | 4 | def test_bytecode_runtime(): 5 | code = """ 6 | @public 7 | def a() -> bool: 8 | return True 9 | """ 10 | 11 | bytecode = compiler.compile(code) 12 | bytecode_runtime = compiler.compile(code, bytecode_runtime=True) 13 | 14 | assert len(bytecode) > len(bytecode_runtime) 15 | assert bytecode_runtime in bytecode 16 | -------------------------------------------------------------------------------- /tests/compiler/test_calldatacopy.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def test_calldatacopy(get_contract_from_lll): 4 | lll = ['calldatacopy', 32, 0, ['calldatasize']] 5 | get_contract_from_lll(lll) 6 | -------------------------------------------------------------------------------- /tests/compiler/test_pre_parser.py: -------------------------------------------------------------------------------- 1 | from vyper.exceptions import StructureException 2 | from pytest import raises 3 | 4 | 5 | def test_semicolon_prohibited(get_contract): 6 | code = """@public 7 | def test() -> int128: 8 | a: int128 = 1; b: int128 = 2 9 | return a + b 10 | """ 11 | 12 | with raises(StructureException): 13 | get_contract(code) 14 | 15 | 16 | def test_valid_semicolons(get_contract): 17 | code = """ 18 | @public 19 | def test() -> int128: 20 | a: int128 = 1 21 | b: int128 = 2 22 | s: bytes[300] = "this should not be a problem; because it is in a string" 23 | s = \"\"\"this should not be a problem; because it's in a string\"\"\" 24 | s = 'this should not be a problem;;; because it\\\'s in a string' 25 | s = '''this should not ; \'cause it\'s in a string''' 26 | s = "this should not be \\\"; because it's in a ;\\\"string;\\\";" 27 | return a + b 28 | """ 29 | c = get_contract(code) 30 | assert c.test() == 3 31 | 32 | 33 | def test_external_contract_definition_alias(get_contract): 34 | contract_1 = """ 35 | @public 36 | def bar() -> int128: 37 | return 1 38 | """ 39 | 40 | contract_2 = """ 41 | contract Bar(): 42 | def bar() -> int128: modifying 43 | 44 | bar_contract: Bar 45 | 46 | @public 47 | def foo(contract_address: address) -> int128: 48 | self.bar_contract = contract_address 49 | return self.bar_contract.bar() 50 | """ 51 | 52 | c1 = get_contract(contract_1) 53 | c2 = get_contract(contract_2) 54 | assert c2.foo(c1.address) == 1 55 | 56 | 57 | def test_version_pragma(get_contract): 58 | from vyper import __version__ 59 | code = """ 60 | # @version {} 61 | 62 | @public 63 | def test(): 64 | pass 65 | """.format(__version__) 66 | assert get_contract(code) 67 | 68 | 69 | def test_version_empty_version(assert_compile_failed, get_contract): 70 | code = """ 71 | #@version 72 | 73 | @public 74 | def test(): 75 | pass 76 | """ 77 | assert_compile_failed(lambda: get_contract(code)) 78 | 79 | 80 | def test_version_empty_version_mismatch(assert_compile_failed, get_contract): 81 | code = """ 82 | # @version 9.9.9 83 | 84 | @public 85 | def test(): 86 | pass 87 | """ 88 | assert_compile_failed(lambda: get_contract(code)) 89 | 90 | 91 | def test_version_empty_invalid_version_string(assert_compile_failed, get_contract): 92 | code = """ 93 | # @version hello 94 | 95 | @public 96 | def test(): 97 | pass 98 | """ 99 | assert_compile_failed(lambda: get_contract(code)) 100 | 101 | 102 | def test_unbalanced_parens(assert_compile_failed, get_contract): 103 | code = """ 104 | @public 105 | def foo(): 106 | convert( 107 | """ 108 | 109 | with raises(StructureException): 110 | get_contract(code) 111 | -------------------------------------------------------------------------------- /tests/compiler/test_sha3_32.py: -------------------------------------------------------------------------------- 1 | from vyper.parser.parser_utils import LLLnode 2 | from vyper import compile_lll, optimizer 3 | 4 | 5 | def test_sha3_32(): 6 | lll = ['sha3_32', 0] 7 | evm = ['PUSH1', 0, 'PUSH1', 192, 'MSTORE', 'PUSH1', 32, 'PUSH1', 192, 'SHA3'] 8 | assert compile_lll.compile_to_assembly(LLLnode.from_list(lll)) == evm 9 | assert compile_lll.compile_to_assembly(optimizer.optimize(LLLnode.from_list(lll))) == evm 10 | -------------------------------------------------------------------------------- /tests/examples/name_registry/test_name_registry.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def test_name_registry(w3, get_contract, assert_tx_failed): 4 | a0, a1 = w3.eth.accounts[:2] 5 | with open('examples/name_registry/name_registry.vy') as f: 6 | code = f.read() 7 | c = get_contract(code) 8 | c.register(b'jacques', a0, transact={}) 9 | assert c.lookup(b'jacques') == a0 10 | assert_tx_failed(lambda: c.register(b'jacques', a1)) 11 | -------------------------------------------------------------------------------- /tests/examples/tokens/ERC20_solidity_compatible/run_tests.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from test import erc20_tests_1 3 | from test import erc20_tests_2 4 | 5 | 6 | def prettyprint(message): 7 | print("~" * 80, "\n" + message, "\n" + "~" * 80) 8 | 9 | 10 | success = True 11 | 12 | # Run first test suite (Phil Daian) on each contract 13 | prettyprint("Running Solidity-compatible ERC20 tests, Suite 1") 14 | res = unittest.TextTestRunner(verbosity=2).run(unittest.TestLoader().loadTestsFromModule(erc20_tests_1)) 15 | success &= res.wasSuccessful() 16 | prettyprint("Finished Solidity-compatible ERC20 tests, Suite 1") 17 | 18 | # Run second test suite (Florian Tramer) on each contract 19 | prettyprint("Running Solidity-compatible ERC20 tests, Suite 2") 20 | res = unittest.TextTestRunner(verbosity=2).run(unittest.TestLoader().loadTestsFromModule(erc20_tests_2)) 21 | success &= res.wasSuccessful() 22 | prettyprint("Finished Solidity-compatible ERC20 tests, Suite 2") 23 | 24 | if not success: 25 | print("FAILED : Test failures encounting, exiting with error.") 26 | exit(1) 27 | else: 28 | print("All tests completed successfully.") 29 | -------------------------------------------------------------------------------- /tests/examples/tokens/ERC20_solidity_compatible/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/tests/examples/tokens/ERC20_solidity_compatible/test/__init__.py -------------------------------------------------------------------------------- /tests/examples/tokens/ERC20_solidity_compatible/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/tests/examples/tokens/ERC20_solidity_compatible/utils/__init__.py -------------------------------------------------------------------------------- /tests/examples/tokens/ERC20_solidity_compatible/utils/pyethereum_test_utils.py: -------------------------------------------------------------------------------- 1 | """ Utility class for testing via pyethereum """ 2 | 3 | from ethereum.tools import tester 4 | from ethereum import utils 5 | 6 | import os 7 | import unittest 8 | 9 | 10 | # Extract language from contract extension 11 | def extract_language(sourcefile): 12 | languages = { 13 | '.sol': 'solidity', 14 | '.vy': 'vyper', 15 | '.py': 'vyper' # hack to handle new .vy suggested Vyper extension 16 | } 17 | _, ext = os.path.splitext(sourcefile) 18 | language = languages[ext] 19 | return language 20 | 21 | 22 | def bytes_to_int(bytez): 23 | return int(utils.encode_hex(bytez), 16) 24 | 25 | 26 | def int_to_bytes(i): 27 | return int(i).to_bytes(32, byteorder='big') 28 | 29 | 30 | class PyEthereumTestCase(unittest.TestCase): 31 | 32 | t = None # ethereum.tools.tester module 33 | s = None # Chain object 34 | c = None # Main contract 35 | initial_state = None # Initial state of the chain 36 | 37 | @classmethod 38 | def setUpClass(cls): 39 | super(PyEthereumTestCase, cls).setUpClass() 40 | 41 | # Initialize tester, contract and expose relevant objects 42 | cls.t = tester 43 | cls.s = cls.t.Chain() 44 | 45 | cls.s.head_state.gas_limit = 10**80 46 | cls.s.head_state.set_balance(cls.t.a0, 10**80) 47 | cls.s.head_state.set_balance(cls.t.a1, 10**80) 48 | cls.s.head_state.set_balance(cls.t.a2, 10**80) 49 | cls.s.head_state.set_balance(cls.t.a3, 10**80) 50 | cls.initial_state = None 51 | 52 | def setUp(self): 53 | self.longMessage = True 54 | self.s.revert(self.initial_state) 55 | self.gas_used_before = self.s.head_state.gas_used 56 | self.refunds_before = self.s.head_state.refunds 57 | 58 | from ethereum.slogging import get_logger 59 | get_logger('eth.pb.tx') 60 | get_logger('eth.pb.msg') 61 | 62 | def tearDown(self): 63 | gas_used_after = self.s.head_state.gas_used 64 | print("Test used {} gas".format(gas_used_after - self.gas_used_before)) 65 | 66 | def deploy_contract_from_file(self, contract_file, sender=None, value=0): 67 | with open(contract_file, 'r') as in_file: 68 | code = in_file.read() 69 | 70 | if sender is not None: 71 | return self.s.contract(code, language=extract_language(contract_file), 72 | sender=sender, value=value, startgas=10**20) 73 | else: 74 | return self.s.contract(code, language=extract_language(contract_file), 75 | value=value, startgas=10**20) 76 | 77 | def check_logs(self, topics, data): 78 | found = False 79 | for log_entry in self.s.head_state.receipts[-1].logs: 80 | if topics == log_entry.topics and data == log_entry.data: 81 | found = True 82 | 83 | self.assertTrue(found, self.s.head_state.receipts[-1].logs) 84 | 85 | def assert_tx_failed(self, function_to_test, 86 | exception=tester.TransactionFailed): 87 | """ Ensure that transaction fails, reverting state 88 | (to prevent gas exhaustion) """ 89 | initial_state = self.s.snapshot() 90 | self.assertRaises(exception, function_to_test) 91 | self.s.revert(initial_state) 92 | -------------------------------------------------------------------------------- /tests/parser/exceptions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/tests/parser/exceptions/__init__.py -------------------------------------------------------------------------------- /tests/parser/exceptions/test_constancy_exception.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import ConstancyViolationException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | x: int128 11 | @public 12 | @constant 13 | def foo() -> int128: 14 | self.x = 5 15 | """, 16 | """ 17 | @public 18 | @constant 19 | def foo() -> int128: 20 | send(0x1234567890123456789012345678901234567890, 5) 21 | """, 22 | """ 23 | @public 24 | @constant 25 | def foo() -> int128: 26 | selfdestruct(0x1234567890123456789012345678901234567890) 27 | """, 28 | """ 29 | x: timedelta 30 | y: int128 31 | @public 32 | @constant 33 | def foo() -> int128(sec): 34 | self.y = 9 35 | return 5 36 | """, 37 | """ 38 | @public 39 | @constant 40 | def foo() -> int128: 41 | x = raw_call(0x1234567890123456789012345678901234567890, "cow", outsize=4, gas=595757, value=9) 42 | return 5 43 | """, 44 | """ 45 | @public 46 | @constant 47 | def foo() -> int128: 48 | x = create_with_code_of(0x1234567890123456789012345678901234567890, value=9) 49 | return 5 50 | """, 51 | """ 52 | @public 53 | def foo(x: int128): 54 | x = 5 55 | """, 56 | """ 57 | f:int128 58 | 59 | @public 60 | def a (x:int128)->int128: 61 | self.f = 100 62 | return x+5 63 | 64 | @constant 65 | @public 66 | def b(): 67 | p: int128 = self.a(10) 68 | """, 69 | """ 70 | f:int128 71 | 72 | @public 73 | def a (x:int128): 74 | self.f = 100 75 | 76 | @constant 77 | @public 78 | def b(): 79 | self.a(10) 80 | """ 81 | ] 82 | 83 | 84 | @pytest.mark.parametrize('bad_code', fail_list) 85 | def test_constancy_violation_exception(bad_code): 86 | with raises(ConstancyViolationException): 87 | compiler.compile(bad_code) 88 | -------------------------------------------------------------------------------- /tests/parser/exceptions/test_function_declaration_exception.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import FunctionDeclarationException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def foo(x: int128, x: int128): pass 12 | """, 13 | """ 14 | @public 15 | def foo(int128: int128): 16 | pass 17 | """, 18 | """ 19 | @public 20 | def foo(): 21 | x: int128 22 | @public 23 | def foo(): 24 | y: int128 25 | """, 26 | """ 27 | @public 28 | def foo(): 29 | self.goo() 30 | 31 | @public 32 | def goo(): 33 | self.foo() 34 | """, 35 | """ 36 | foo: int128 37 | 38 | @public 39 | def foo(): 40 | pass 41 | """, 42 | """ 43 | x: int128 44 | 45 | @public 46 | def foo(x: int128): pass 47 | """, 48 | ] 49 | 50 | 51 | @pytest.mark.parametrize('bad_code', fail_list) 52 | def test_function_declaration_exception(bad_code): 53 | with raises(FunctionDeclarationException): 54 | compiler.compile(bad_code) 55 | -------------------------------------------------------------------------------- /tests/parser/exceptions/test_insufficient_arguments.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import StructureException 6 | 7 | fail_list = [ 8 | """ 9 | @public 10 | def foo() -> int128: 11 | return as_wei_value(10) 12 | """ 13 | ] 14 | 15 | 16 | @pytest.mark.parametrize('bad_code', fail_list) 17 | def test_insufficient_arguments(bad_code): 18 | with raises(StructureException) as ex: 19 | compiler.compile(bad_code) 20 | assert "Not enough arguments for function: as_wei_value" in str(ex.value) 21 | -------------------------------------------------------------------------------- /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 InvalidLiteralException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def foo(): 12 | x = 0x12345678901234567890123456789012345678901 13 | """, 14 | """ 15 | @public 16 | def foo(): 17 | x = 0x01234567890123456789012345678901234567890 18 | """, 19 | """ 20 | @public 21 | def foo(): 22 | x = 0x123456789012345678901234567890123456789 23 | """, 24 | """ 25 | @public 26 | def foo(): 27 | x: int128 = -170141183460469231731687303715884105729 # -2**127 - 1 28 | """, 29 | """ 30 | @public 31 | def foo(): 32 | x: decimal = -170141183460469231731687303715884105728. 33 | """, 34 | """ 35 | b: decimal 36 | @public 37 | def foo(): 38 | self.b = 7.5178246872145875217495129745982164981654986129846 39 | """, 40 | """ 41 | @public 42 | def foo(): 43 | x = "these bytes are nо gооd because the o's are from the Russian alphabet" 44 | """, 45 | """ 46 | @public 47 | def foo(): 48 | x = "这个傻老外不懂中文" 49 | """, 50 | """ 51 | @public 52 | def foo(): 53 | x = raw_call(0x123456789012345678901234567890123456789, "cow", outsize=4) 54 | """, 55 | """ 56 | @public 57 | def foo(): 58 | x = create_with_code_of(0x123456789012345678901234567890123456789) 59 | """, 60 | """ 61 | @public 62 | def foo(): 63 | x = as_wei_value(5.1824, "babbage") 64 | """, 65 | """ 66 | @public 67 | def foo(): 68 | x = as_wei_value(0x05, "babbage") 69 | """, 70 | """ 71 | @public 72 | def foo(): 73 | x = as_wei_value(5, "vader") 74 | """, 75 | """ 76 | @public 77 | def foo(): 78 | send(0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae, 5) 79 | """, 80 | """ 81 | @public 82 | def foo(): 83 | x: uint256 = convert(821649876217461872458712528745872158745214187264875632587324658732648753245328764872135671285218762145, uint256) 84 | """, 85 | """ 86 | @public 87 | def foo(): 88 | x = convert(-1, uint256) 89 | """, 90 | """ 91 | @public 92 | def foo(): 93 | x = convert(3.1415, uint256) 94 | """, 95 | """ 96 | # Test decimal limit. 97 | a:decimal 98 | 99 | @public 100 | def foo(): 101 | self.a = 170141183460469231731687303715884105727.888 102 | """, 103 | """ 104 | @public 105 | def foo(): 106 | a: bytes[100] = "ѓtest" 107 | """, 108 | """ 109 | @public 110 | def foo(): 111 | a: bytes32 = sha3("ѓtest") 112 | """, 113 | """ 114 | @public 115 | def overflow() -> uint256: 116 | return 2**256 117 | """, 118 | """ 119 | @public 120 | def overflow2() -> uint256: 121 | a: uint256 = 2**256 122 | return a 123 | """ 124 | ] 125 | 126 | 127 | @pytest.mark.parametrize('bad_code', fail_list) 128 | def test_invalid_literal_exception(bad_code): 129 | with raises(InvalidLiteralException): 130 | compiler.compile(bad_code) 131 | -------------------------------------------------------------------------------- /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 NonPayableViolationException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def foo(): 12 | x = msg.value 13 | """ 14 | ] 15 | 16 | 17 | @pytest.mark.parametrize('bad_code', fail_list) 18 | def test_variable_decleration_exception(bad_code): 19 | with raises(NonPayableViolationException): 20 | compiler.compile(bad_code) 21 | 22 | 23 | valid_list = [ 24 | """ 25 | x: int128 26 | @public 27 | @payable 28 | def foo() -> int128: 29 | self.x = 5 30 | return self.x 31 | """, 32 | """ 33 | @public 34 | @payable 35 | def foo(): 36 | x: wei_value = msg.value 37 | """ 38 | ] 39 | 40 | 41 | @pytest.mark.parametrize('good_code', valid_list) 42 | def test_block_success(good_code): 43 | assert compiler.compile(good_code) is not None 44 | -------------------------------------------------------------------------------- /tests/parser/exceptions/test_invalid_same_variable_assignment.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import VariableDeclarationException 6 | 7 | fail_list = [""" 8 | @public 9 | def test1(b: uint256) -> uint256: 10 | a: uint256 = a + b 11 | return a 12 | """, 13 | """ 14 | @public 15 | def test2(b: uint256, c: uint256) -> uint256: 16 | a: uint256 = a + b + c 17 | """, 18 | """ 19 | @public 20 | def test3(b: uint256, c: uint256) -> uint256: 21 | a: uint256 = - a 22 | return a 23 | """, 24 | """ 25 | @public 26 | def test4(b: bool) -> bool: 27 | a: bool = b or a 28 | return a 29 | """, 30 | """ 31 | @public 32 | def test5(b: bool) -> bool: 33 | a: bool = a != b 34 | return a 35 | """, 36 | """ 37 | @public 38 | def test6(b:bool, c: bool) -> bool: 39 | a: bool = (a and b) and c 40 | return a 41 | """ 42 | ] 43 | 44 | 45 | @pytest.mark.parametrize('bad_code', fail_list) 46 | def test_invalid_type_exception(bad_code): 47 | with raises(VariableDeclarationException): 48 | compiler.compile(bad_code) 49 | -------------------------------------------------------------------------------- /tests/parser/exceptions/test_invalid_type_exception.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import InvalidTypeException 6 | 7 | fail_list = [ 8 | """ 9 | x: bat 10 | """, 11 | """ 12 | x: 5 13 | """, 14 | """ 15 | x: int128[int] 16 | """, 17 | """ 18 | x: int128[-1] 19 | """, 20 | """ 21 | x: int128[3.5] 22 | """, 23 | """ 24 | x: {int128[5]: int128[7]} 25 | """, 26 | """ 27 | x: [bar, baz] 28 | """, 29 | """ 30 | x: [bar(int128), baz(baffle)] 31 | """, 32 | """ 33 | x: {bar: int128, decimal: int128} 34 | """, 35 | """ 36 | x: {bar: int128, 5: int128} 37 | """, 38 | """ 39 | def foo(x): pass 40 | """, 41 | """ 42 | b: {num: int128, address: address} 43 | """, 44 | """ 45 | b: {num: int128, address: address} 46 | """, 47 | """ 48 | b: int128[int128, decimal] 49 | """, 50 | """ 51 | b: int128[int128: address] 52 | """, 53 | """ 54 | x: int128[address[bool]] 55 | @public 56 | def foo() -> int128(wei / sec): 57 | pass 58 | """, 59 | """ 60 | @public 61 | def foo() -> {cow: int128, dog: int128}: 62 | return {cow: 5, dog: 7} 63 | """, 64 | """ 65 | x: wei(wei) 66 | """, 67 | """ 68 | x: int128(address) 69 | """, 70 | """ 71 | x: int128(wei and sec) 72 | """, 73 | """ 74 | x: int128(2 ** 2) 75 | """, 76 | """ 77 | x: int128(wei ** -1) 78 | """, 79 | """ 80 | x: int128(wei >> 3) 81 | """, 82 | """ 83 | x: bytes <= wei 84 | """, 85 | """ 86 | x: string <= 33 87 | """, 88 | """ 89 | x: bytes[1:3] 90 | """, 91 | """ 92 | x: bytes[33.3] 93 | """, 94 | ] 95 | 96 | 97 | @pytest.mark.parametrize('bad_code', fail_list) 98 | def test_invalid_type_exception(bad_code): 99 | with raises(InvalidTypeException): 100 | compiler.compile(bad_code) 101 | -------------------------------------------------------------------------------- /tests/parser/exceptions/test_parser_exception_pos.py: -------------------------------------------------------------------------------- 1 | from pytest import raises 2 | 3 | from vyper.exceptions import ParserException 4 | 5 | 6 | def test_type_exception_pos(): 7 | pos = (1, 2) 8 | 9 | with raises(ParserException) as e: 10 | raise ParserException('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 | -------------------------------------------------------------------------------- /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 TypeMismatchException 6 | 7 | fail_list = [ 8 | """ 9 | @public 10 | def test_func() -> int128: 11 | return (1, 2) 12 | """, 13 | ] 14 | 15 | 16 | @pytest.mark.parametrize('bad_code', fail_list) 17 | def test_type_mismatch_exception(bad_code): 18 | with raises(TypeMismatchException): 19 | compiler.compile(bad_code) 20 | -------------------------------------------------------------------------------- /tests/parser/exceptions/test_undef_function.py: -------------------------------------------------------------------------------- 1 | from pytest import raises 2 | 3 | from vyper import compiler 4 | from vyper.exceptions import StructureException 5 | 6 | 7 | def test_undef_toplevel(): 8 | code = """ 9 | @public 10 | def foo(): 11 | x = bar(55) 12 | """ 13 | with raises(StructureException) as ex: 14 | compiler.compile(code) 15 | assert "Not a top-level function: bar" in str(ex.value) 16 | 17 | 18 | def test_undef_suggestion(): 19 | code = """ 20 | @public 21 | def bar(x: int128) -> int128: 22 | return 3 * x 23 | 24 | @public 25 | def foo() -> int128: 26 | return bar(20) 27 | """ 28 | with raises(StructureException) as ex: 29 | compiler.compile(code) 30 | assert "Not a top-level function: bar" in str(ex.value) 31 | assert "Did you mean self.bar?" in str(ex.value) 32 | -------------------------------------------------------------------------------- /tests/parser/exceptions/test_variable_declaration_exception.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import VariableDeclarationException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | x: int128 11 | x: int128 12 | """, 13 | """ 14 | CALLDATACOPY: int128 15 | """, 16 | """ 17 | int128: bytes[3] 18 | """, 19 | """ 20 | sec: int128 21 | """, 22 | """ 23 | @public 24 | def foo(): 25 | BALANCE = 45 26 | """, 27 | """ 28 | @public 29 | def foo(): 30 | true = 3 31 | """, 32 | """ 33 | x: wei_value 34 | 35 | @public 36 | def foo(): 37 | send(0x1234567890123456789012345678901234567890, x) 38 | """, 39 | """ 40 | @public 41 | def foo(): 42 | x = 5 43 | x: int128 44 | """, 45 | """ 46 | @public 47 | def foo(): 48 | x: int128 49 | x: int128 50 | """, 51 | """ 52 | @public 53 | def foo(): 54 | int128 = 5 55 | """, 56 | """ 57 | @public 58 | def foo(): 59 | bork = zork 60 | """, 61 | """ 62 | b: int128 63 | @public 64 | def foo(): 65 | b = 7 66 | """, 67 | """ 68 | x: int128 69 | @public 70 | def foo(): 71 | x = 5 72 | """, 73 | ] 74 | 75 | 76 | @pytest.mark.parametrize('bad_code', fail_list) 77 | def test_variable_declaration_exception(bad_code): 78 | with raises(VariableDeclarationException): 79 | compiler.compile(bad_code) 80 | -------------------------------------------------------------------------------- /tests/parser/features/arithmetic/test_modulo.py: -------------------------------------------------------------------------------- 1 | from vyper.exceptions import TypeMismatchException 2 | from decimal import Decimal 3 | 4 | 5 | def test_modulo(get_contract_with_gas_estimation): 6 | code = """ 7 | @public 8 | def num_modulo_num() -> int128: 9 | return 1 % 2 10 | 11 | @public 12 | def decimal_modulo_decimal() -> decimal: 13 | return 1.5 % .33 14 | 15 | @public 16 | def decimal_modulo_num() -> decimal: 17 | return .5 % 1.0 18 | 19 | 20 | @public 21 | def num_modulo_decimal() -> decimal: 22 | return 1.5 % 1.0 23 | """ 24 | c = get_contract_with_gas_estimation(code) 25 | assert c.num_modulo_num() == 1 26 | assert c.decimal_modulo_decimal() == Decimal('.18') 27 | assert c.decimal_modulo_num() == Decimal('.5') 28 | assert c.num_modulo_decimal() == Decimal('.5') 29 | 30 | 31 | def test_modulo_with_different_units(assert_compile_failed, get_contract_with_gas_estimation): 32 | code = """ 33 | units: { 34 | currency_value: "a currency amount" 35 | } 36 | @public 37 | def foo(a: int128(currency_value), b: int128): 38 | x: int128 = a % b 39 | """ 40 | assert_compile_failed(lambda: get_contract_with_gas_estimation(code), TypeMismatchException) 41 | 42 | 43 | def test_modulo_with_positional_input(assert_compile_failed, get_contract_with_gas_estimation): 44 | code = """ 45 | @public 46 | def foo(a: int128(sec, positional), b: int128): 47 | x: int128 = a % b 48 | """ 49 | assert_compile_failed(lambda: get_contract_with_gas_estimation(code), TypeMismatchException) 50 | 51 | 52 | def test_modulo_with_input_of_zero(assert_tx_failed, get_contract_with_gas_estimation): 53 | code = """ 54 | @public 55 | def foo(a: decimal, b: decimal) -> decimal: 56 | return a % b 57 | """ 58 | c = get_contract_with_gas_estimation(code) 59 | assert_tx_failed(lambda: c.foo(Decimal('1'), Decimal('0'))) 60 | -------------------------------------------------------------------------------- /tests/parser/features/decorators/test_constant.py: -------------------------------------------------------------------------------- 1 | from vyper.exceptions import StructureException 2 | 3 | 4 | def test_constant_test(get_contract_with_gas_estimation_for_constants): 5 | constant_test = """ 6 | @public 7 | @constant 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(get_contract_with_gas_estimation_for_constants, assert_compile_failed): 19 | code = """ 20 | @public 21 | @payable 22 | @constant 23 | def foo() -> num: 24 | return 5 25 | """ 26 | assert_compile_failed(lambda: get_contract_with_gas_estimation_for_constants(code), StructureException) 27 | -------------------------------------------------------------------------------- /tests/parser/features/decorators/test_public.py: -------------------------------------------------------------------------------- 1 | from vyper.exceptions import StructureException 2 | 3 | 4 | def test_invalid_if_both_public_and_internal(assert_compile_failed, get_contract_with_gas_estimation): 5 | code = """ 6 | @public 7 | @private 8 | def foo(): 9 | x = 1 10 | """ 11 | 12 | assert_compile_failed(lambda: get_contract_with_gas_estimation(code), StructureException) 13 | 14 | 15 | def test_invalid_if_visibility_isnt_declared(assert_compile_failed, get_contract_with_gas_estimation): 16 | code = """ 17 | def foo(): 18 | x = 1 19 | """ 20 | 21 | assert_compile_failed(lambda: get_contract_with_gas_estimation(code), StructureException) 22 | -------------------------------------------------------------------------------- /tests/parser/features/iteration/test_break.py: -------------------------------------------------------------------------------- 1 | from decimal import Decimal 2 | 3 | 4 | def test_break_test(get_contract_with_gas_estimation): 5 | break_test = """ 6 | @public 7 | def log(n: decimal) -> int128: 8 | c: decimal = n * 1.0 9 | output: int128 = 0 10 | for i in range(400): 11 | c = c / 1.2589 12 | if c < 1.0: 13 | output = i 14 | break 15 | return output 16 | """ 17 | 18 | c = get_contract_with_gas_estimation(break_test) 19 | 20 | assert c.log(Decimal('1')) == 0 21 | assert c.log(Decimal('2')) == 3 22 | assert c.log(Decimal('10')) == 10 23 | assert c.log(Decimal('200')) == 23 24 | 25 | print('Passed for-loop break test') 26 | 27 | 28 | def test_break_test_2(get_contract_with_gas_estimation): 29 | break_test_2 = """ 30 | @public 31 | def log(n: decimal) -> int128: 32 | c: decimal = n * 1.0 33 | output: int128 = 0 34 | for i in range(40): 35 | if c < 10.0: 36 | output = i * 10 37 | break 38 | c = c / 10.0 39 | for i in range(10): 40 | c = c / 1.2589 41 | if c < 1.0: 42 | output = output + i 43 | break 44 | return output 45 | """ 46 | 47 | c = get_contract_with_gas_estimation(break_test_2) 48 | assert c.log(Decimal('1')) == 0 49 | assert c.log(Decimal('2')) == 3 50 | assert c.log(Decimal('10')) == 10 51 | assert c.log(Decimal('200')) == 23 52 | assert c.log(Decimal('4000000')) == 66 53 | print('Passed for-loop break test 2') 54 | 55 | 56 | def test_break_test_3(get_contract_with_gas_estimation): 57 | break_test_3 = """ 58 | @public 59 | def log(n: int128) -> int128: 60 | c: decimal = convert(n, decimal) 61 | output: int128 = 0 62 | for i in range(40): 63 | if c < 10.0: 64 | output = i * 10 65 | break 66 | c /= 10.0 67 | for i in range(10): 68 | c /= 1.2589 69 | if c < 1.0: 70 | output = output + i 71 | break 72 | return output 73 | """ 74 | 75 | c = get_contract_with_gas_estimation(break_test_3) 76 | assert c.log(1) == 0 77 | assert c.log(2) == 3 78 | assert c.log(10) == 10 79 | assert c.log(200) == 23 80 | assert c.log(4000000) == 66 81 | print('Passed aug-assignment break composite test') 82 | -------------------------------------------------------------------------------- /tests/parser/features/iteration/test_continue.py: -------------------------------------------------------------------------------- 1 | def test_continue1(get_contract_with_gas_estimation): 2 | code = """ 3 | @public 4 | def foo() -> bool: 5 | for i in range(2): 6 | continue 7 | return False 8 | return True 9 | """ 10 | c = get_contract_with_gas_estimation(code) 11 | assert c.foo() 12 | 13 | 14 | def test_continue2(get_contract_with_gas_estimation): 15 | code = """ 16 | @public 17 | def foo() -> int128: 18 | x: int128 = 0 19 | for i in range(3): 20 | x += 1 21 | continue 22 | x -= 1 23 | return x 24 | """ 25 | c = get_contract_with_gas_estimation(code) 26 | assert c.foo() == 3 27 | 28 | 29 | def test_continue3(get_contract_with_gas_estimation): 30 | code = """ 31 | @public 32 | def foo() -> int128: 33 | x: int128 = 0 34 | for i in range(3): 35 | x += i 36 | continue 37 | return x 38 | """ 39 | c = get_contract_with_gas_estimation(code) 40 | assert c.foo() == 3 41 | 42 | 43 | def test_continue4(get_contract_with_gas_estimation): 44 | code = """ 45 | @public 46 | def foo() -> int128: 47 | x: int128 = 0 48 | for i in range(6): 49 | if i % 2 == 0: 50 | continue 51 | x += 1 52 | return x 53 | """ 54 | c = get_contract_with_gas_estimation(code) 55 | assert c.foo() == 3 56 | -------------------------------------------------------------------------------- /tests/parser/features/iteration/test_repeater.py: -------------------------------------------------------------------------------- 1 | def test_basic_repeater(get_contract_with_gas_estimation): 2 | basic_repeater = """ 3 | @public 4 | def repeat(z: int128) -> int128: 5 | x: int128 = 0 6 | for i in range(6): 7 | x = x + z 8 | return(x) 9 | """ 10 | c = get_contract_with_gas_estimation(basic_repeater) 11 | assert c.repeat(9) == 54 12 | print('Passed basic repeater test') 13 | 14 | 15 | def test_digit_reverser(get_contract_with_gas_estimation): 16 | digit_reverser = """ 17 | @public 18 | def reverse_digits(x: int128) -> int128: 19 | dig: int128[6] 20 | z: int128 = x 21 | for i in range(6): 22 | dig[i] = z % 10 23 | z = z / 10 24 | o: int128 = 0 25 | for i in range(6): 26 | o = o * 10 + dig[i] 27 | return o 28 | 29 | """ 30 | 31 | c = get_contract_with_gas_estimation(digit_reverser) 32 | assert c.reverse_digits(123456) == 654321 33 | print('Passed digit reverser test') 34 | 35 | 36 | def test_more_complex_repeater(get_contract_with_gas_estimation): 37 | more_complex_repeater = """ 38 | @public 39 | def repeat() -> int128: 40 | out: int128 = 0 41 | for i in range(6): 42 | out = out * 10 43 | for j in range(4): 44 | out = out + j 45 | return(out) 46 | """ 47 | 48 | c = get_contract_with_gas_estimation(more_complex_repeater) 49 | assert c.repeat() == 666666 50 | 51 | print('Passed complex repeater test') 52 | 53 | 54 | def test_offset_repeater(get_contract_with_gas_estimation): 55 | offset_repeater = """ 56 | @public 57 | def sum() -> int128: 58 | out: int128 = 0 59 | for i in range(80, 121): 60 | out = out + i 61 | return(out) 62 | """ 63 | 64 | c = get_contract_with_gas_estimation(offset_repeater) 65 | assert c.sum() == 4100 66 | 67 | print('Passed repeater with offset test') 68 | 69 | 70 | def test_offset_repeater_2(get_contract_with_gas_estimation): 71 | offset_repeater_2 = """ 72 | @public 73 | def sum(frm: int128, to: int128) -> int128: 74 | out: int128 = 0 75 | for i in range(frm, frm + 101): 76 | if i == to: 77 | break 78 | out = out + i 79 | return(out) 80 | """ 81 | 82 | c = get_contract_with_gas_estimation(offset_repeater_2) 83 | assert c.sum(100, 99999) == 15150 84 | assert c.sum(70, 131) == 6100 85 | 86 | print('Passed more complex repeater with offset test') 87 | -------------------------------------------------------------------------------- /tests/parser/features/test_assert.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from vyper.exceptions import ( 4 | StructureException 5 | ) 6 | from eth_tester.exceptions import ( 7 | TransactionFailed 8 | ) 9 | 10 | 11 | def test_assert_refund(w3, get_contract_with_gas_estimation, assert_tx_failed): 12 | code = """ 13 | @public 14 | def foo(): 15 | assert 1 == 2 16 | """ 17 | c = get_contract_with_gas_estimation(code) 18 | a0 = w3.eth.accounts[0] 19 | pre_balance = w3.eth.getBalance(a0) 20 | tx_hash = c.foo(transact={'from': a0, 'gas': 10**6, 'gasPrice': 10}) 21 | assert w3.eth.getTransactionReceipt(tx_hash)['status'] == 0 22 | # More info on receipt status: 23 | # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-658.md#specification. 24 | post_balance = w3.eth.getBalance(a0) 25 | # Checks for gas refund from revert 26 | # 10**5 is added to account for gas used before the transactions fails 27 | assert pre_balance > post_balance 28 | 29 | 30 | def test_assert_reason(w3, get_contract_with_gas_estimation, assert_tx_failed): 31 | code = """ 32 | @public 33 | def test(a: int128) -> int128: 34 | assert a > 1, "larger than one please" 35 | return 1 + a 36 | 37 | @public 38 | def test2(a: int128, b: int128) -> int128: 39 | c: int128 = 11 40 | assert a > 1, "a is not large enough" 41 | assert b == 1, "b may only be 1" 42 | return a + b + c 43 | """ 44 | c = get_contract_with_gas_estimation(code) 45 | 46 | assert c.test(2) == 3 47 | with pytest.raises(TransactionFailed) as e_info: 48 | c.test(0) 49 | 50 | assert e_info.value.args[0] == b'larger than one please' 51 | # a = 0, b = 1 52 | with pytest.raises(TransactionFailed) as e_info: 53 | c.test2(0, 1) 54 | assert e_info.value.args[0] == b'a is not large enough' 55 | # a = 1, b = 0 56 | with pytest.raises(TransactionFailed) as e_info: 57 | c.test2(2, 2) 58 | assert e_info.value.args[0] == b'b may only be 1' 59 | # return correct value 60 | assert c.test2(5, 1) == 17 61 | 62 | 63 | def test_assert_reason_empty(get_contract, assert_compile_failed): 64 | code = """ 65 | @public 66 | def test(a: int128) -> int128: 67 | assert a > 1, "" 68 | return 1 + a 69 | """ 70 | assert_compile_failed(lambda: get_contract(code), StructureException) 71 | -------------------------------------------------------------------------------- /tests/parser/features/test_bytes_map_keys.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from vyper.exceptions import TypeMismatchException 3 | 4 | 5 | def test_basic_bytes_keys(w3, get_contract): 6 | code = """ 7 | mapped_bytes: int128[bytes[5]] 8 | 9 | @public 10 | def set(k: bytes[5], v: int128): 11 | self.mapped_bytes[k] = v 12 | 13 | @public 14 | def get(k: bytes[5]) -> int128: 15 | return self.mapped_bytes[k] 16 | """ 17 | 18 | c = get_contract(code) 19 | 20 | c.set(b"test", 54321, transact={}) 21 | 22 | assert c.get(b"test") == 54321 23 | 24 | 25 | def test_basic_bytes_literal_key(get_contract): 26 | code = """ 27 | mapped_bytes: int128[bytes[5]] 28 | 29 | @public 30 | def set(v: int128): 31 | self.mapped_bytes["test"] = v 32 | 33 | @public 34 | def get(k: bytes[5]) -> int128: 35 | return self.mapped_bytes[k] 36 | """ 37 | 38 | c = get_contract(code) 39 | 40 | c.set(54321, transact={}) 41 | 42 | assert c.get(b"test") == 54321 43 | 44 | 45 | def test_basic_long_bytes_as_keys(get_contract): 46 | code = """ 47 | mapped_bytes: int128[bytes[34]] 48 | 49 | @public 50 | def set(k: bytes[34], v: int128): 51 | self.mapped_bytes[k] = v 52 | 53 | @public 54 | def get(k: bytes[34]) -> int128: 55 | return self.mapped_bytes[k] 56 | """ 57 | 58 | c = get_contract(code) 59 | 60 | c.set(b"a" * 34, 6789, transact={'gas': 10**6}) 61 | 62 | assert c.get(b"a" * 34) == 6789 63 | 64 | 65 | def test_mismatched_byte_length(get_contract): 66 | code = """ 67 | mapped_bytes: int128[bytes[34]] 68 | 69 | @public 70 | def set(k: bytes[35], v: int128): 71 | self.mapped_bytes[k] = v 72 | """ 73 | 74 | with pytest.raises(TypeMismatchException): 75 | get_contract(code) 76 | 77 | 78 | def test_extended_bytes_key_from_storage(get_contract): 79 | code = """ 80 | a: int128[bytes[100000]] 81 | 82 | @public 83 | def __init__(): 84 | self.a["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"] = 1069 85 | 86 | @public 87 | def get_it1() -> int128: 88 | key: bytes[100000] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 89 | return self.a[key] 90 | 91 | @public 92 | def get_it2() -> int128: 93 | return self.a["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"] 94 | 95 | @public 96 | def get_it3(key: bytes[100000]) -> int128: 97 | return self.a[key] 98 | """ 99 | 100 | c = get_contract(code) 101 | 102 | assert c.get_it2() == 1069 103 | assert c.get_it2() == 1069 104 | assert c.get_it3(b"a" * 33) == 1069 105 | assert c.get_it3(b"test") == 0 106 | -------------------------------------------------------------------------------- /tests/parser/features/test_clampers.py: -------------------------------------------------------------------------------- 1 | def test_clamper_test_code(assert_tx_failed, get_contract_with_gas_estimation): 2 | clamper_test_code = """ 3 | @public 4 | def foo(s: bytes[3]) -> bytes[3]: 5 | return s 6 | """ 7 | 8 | c = get_contract_with_gas_estimation(clamper_test_code) 9 | assert c.foo(b"ca") == b"ca" 10 | assert c.foo(b"cat") == b"cat" 11 | assert_tx_failed(lambda: c.foo(b"cate")) 12 | 13 | print("Passed bytearray clamping test") 14 | -------------------------------------------------------------------------------- /tests/parser/features/test_comments.py: -------------------------------------------------------------------------------- 1 | def test_comment_test(get_contract_with_gas_estimation): 2 | comment_test = """ 3 | @public 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_conditionals.py: -------------------------------------------------------------------------------- 1 | def test_conditional_return_code(get_contract_with_gas_estimation): 2 | conditional_return_code = """ 3 | @public 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 | -------------------------------------------------------------------------------- /tests/parser/features/test_constructor.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from web3.exceptions import ( 3 | ValidationError 4 | ) 5 | 6 | 7 | def test_init_argument_test(get_contract_with_gas_estimation): 8 | init_argument_test = """ 9 | moose: int128 10 | 11 | @public 12 | def __init__(_moose: int128): 13 | self.moose = _moose 14 | 15 | @public 16 | def returnMoose() -> int128: 17 | return self.moose 18 | """ 19 | 20 | c = get_contract_with_gas_estimation(init_argument_test, *[5]) 21 | assert c.returnMoose() == 5 22 | print('Passed init argument test') 23 | 24 | 25 | def test_constructor_advanced_code(get_contract_with_gas_estimation): 26 | constructor_advanced_code = """ 27 | twox: int128 28 | 29 | @public 30 | def __init__(x: int128): 31 | self.twox = x * 2 32 | 33 | @public 34 | def get_twox() -> int128: 35 | return self.twox 36 | """ 37 | c = get_contract_with_gas_estimation(constructor_advanced_code, *[5]) 38 | assert c.get_twox() == 10 39 | 40 | 41 | def test_constructor_advanced_code2(get_contract_with_gas_estimation): 42 | constructor_advanced_code2 = """ 43 | comb: int128 44 | 45 | @public 46 | def __init__(x: int128[2], y: bytes[3], z: int128): 47 | self.comb = x[0] * 1000 + x[1] * 100 + len(y) * 10 + z 48 | 49 | @public 50 | def get_comb() -> int128: 51 | return self.comb 52 | """ 53 | c = get_contract_with_gas_estimation(constructor_advanced_code2, *[[5, 7], b"dog", 8]) 54 | assert c.get_comb() == 5738 55 | print("Passed advanced init argument tests") 56 | 57 | 58 | def test_large_input_code(get_contract_with_gas_estimation): 59 | large_input_code = """ 60 | @public 61 | def foo(x: int128) -> int128: 62 | return 3 63 | """ 64 | 65 | c = get_contract_with_gas_estimation(large_input_code) 66 | c.foo(1274124) 67 | c.foo(2**120) 68 | 69 | with pytest.raises(ValidationError): 70 | c.foo(2**130) 71 | 72 | 73 | def test_large_input_code_2(w3, get_contract_with_gas_estimation): 74 | large_input_code_2 = """ 75 | @public 76 | def __init__(x: int128): 77 | y: int128 = x 78 | 79 | @public 80 | def foo() -> int128: 81 | return 5 82 | """ 83 | 84 | get_contract_with_gas_estimation(large_input_code_2, *[17]) 85 | 86 | with pytest.raises(TypeError): 87 | get_contract_with_gas_estimation(large_input_code_2, *[2**130]) 88 | 89 | print('Passed invalid input tests') 90 | -------------------------------------------------------------------------------- /tests/parser/features/test_gas.py: -------------------------------------------------------------------------------- 1 | from vyper.parser.parser import parse_to_lll 2 | from vyper.parser import parser_utils 3 | 4 | 5 | def test_gas_call(get_contract_with_gas_estimation): 6 | gas_call = """ 7 | @public 8 | def foo() -> uint256: 9 | return msg.gas 10 | """ 11 | 12 | c = get_contract_with_gas_estimation(gas_call) 13 | 14 | assert c.foo(call={"gas": 50000}) < 50000 15 | assert c.foo(call={"gas": 50000}) > 25000 16 | 17 | print('Passed gas test') 18 | 19 | 20 | def test_gas_estimate_repr(): 21 | code = """ 22 | x: int128 23 | 24 | @public 25 | def __init__(): 26 | self.x = 1 27 | """ 28 | parser_utils.LLLnode.repr_show_gas = True 29 | out = parse_to_lll(code) 30 | assert '35303' in str(out)[:28] 31 | parser_utils.LLLnode.repr_show_gas = False 32 | -------------------------------------------------------------------------------- /tests/parser/features/test_map_delete.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def test_map_delete(get_contract_with_gas_estimation): 4 | code = """ 5 | big_storage: bytes32[bytes32] 6 | 7 | @public 8 | def set(key: bytes32, value: bytes32): 9 | self.big_storage[key] = value 10 | 11 | @public 12 | def get(key: bytes32) -> bytes32: 13 | return self.big_storage[key] 14 | 15 | @public 16 | def delete(key: bytes32): 17 | del self.big_storage[key] 18 | """ 19 | 20 | c = get_contract_with_gas_estimation(code) 21 | 22 | assert c.get(b"test") == b'\x00' * 32 23 | c.set(b"test", b"value", transact={}) 24 | assert c.get(b"test")[:5] == b"value" 25 | c.delete(b"test", transact={}) 26 | assert c.get(b"test") == b'\x00' * 32 27 | 28 | 29 | def test_map_delete_nested(get_contract_with_gas_estimation): 30 | code = """ 31 | big_storage: bytes32[bytes32][bytes32] 32 | 33 | @public 34 | def set(key1: bytes32, key2: bytes32, value: bytes32): 35 | self.big_storage[key1][key2] = value 36 | 37 | @public 38 | def get(key1: bytes32, key2: bytes32) -> bytes32: 39 | return self.big_storage[key1][key2] 40 | 41 | @public 42 | def delete(key1: bytes32, key2: bytes32): 43 | del self.big_storage[key1][key2] 44 | """ 45 | 46 | c = get_contract_with_gas_estimation(code) 47 | 48 | assert c.get(b"test1", b"test2") == b'\x00' * 32 49 | c.set(b"test1", b"test2", b"value", transact={}) 50 | assert c.get(b"test1", b"test2")[:5] == b"value" 51 | c.delete(b"test1", b"test2", transact={}) 52 | assert c.get(b"test1", b"test2") == b'\x00' * 32 53 | 54 | 55 | def test_map_delete_struct(get_contract_with_gas_estimation): 56 | code = """ 57 | structmap: { 58 | a: int128, 59 | b: int128 60 | }[int128] 61 | 62 | 63 | @public 64 | def set(): 65 | self.structmap[123] = { 66 | a: 333, 67 | b: 444 68 | } 69 | 70 | @public 71 | def get() -> (int128, int128): 72 | return self.structmap[123].a, self.structmap[123].b 73 | 74 | @public 75 | def delete(): 76 | self.structmap[123] = None 77 | """ 78 | 79 | c = get_contract_with_gas_estimation(code) 80 | 81 | assert c.get() == [0, 0] 82 | c.set(transact={}) 83 | assert c.get() == [333, 444] 84 | c.delete(transact={}) 85 | assert c.get() == [0, 0] 86 | -------------------------------------------------------------------------------- /tests/parser/features/test_packing.py: -------------------------------------------------------------------------------- 1 | def test_packing_test(get_contract_with_gas_estimation): 2 | packing_test = """ 3 | x: int128 4 | y: int128[5] 5 | z: {foo: int128[3], bar: {a: int128, b: int128}[2]} 6 | a: int128 7 | 8 | @public 9 | def foo() -> int128: 10 | self.x = 1 11 | self.y[0] = 2 12 | self.y[4] = 4 13 | self.z.foo[0] = 8 14 | self.z.foo[2] = 16 15 | self.z.bar[0].a = 32 16 | self.z.bar[0].b = 64 17 | self.z.bar[1].a = 128 18 | self.z.bar[1].b = 256 19 | self.a = 512 20 | return self.x + self.y[0] + self.y[4] + self.z.foo[0] + self.z.foo[2] + \ 21 | self.z.bar[0].a + self.z.bar[0].b + self.z.bar[1].a + self.z.bar[1].b + self.a 22 | 23 | @public 24 | def fop() -> int128: 25 | _x: int128 26 | _y: int128[5] 27 | _z: {foo: int128[3], bar: {a: int128, b: int128}[2]} 28 | _a: int128 29 | _x = 1 30 | _y[0] = 2 31 | _y[4] = 4 32 | _z.foo[0] = 8 33 | _z.foo[2] = 16 34 | _z.bar[0].a = 32 35 | _z.bar[0].b = 64 36 | _z.bar[1].a = 128 37 | _z.bar[1].b = 256 38 | _a = 512 39 | return _x + _y[0] + _y[4] + _z.foo[0] + _z.foo[2] + \ 40 | _z.bar[0].a + _z.bar[0].b + _z.bar[1].a + _z.bar[1].b + _a 41 | """ 42 | 43 | c = get_contract_with_gas_estimation(packing_test) 44 | assert c.foo() == 1023, c.foo() 45 | assert c.fop() == 1023, c.fop() 46 | print('Passed packing test') 47 | -------------------------------------------------------------------------------- /tests/parser/functions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/tests/parser/functions/__init__.py -------------------------------------------------------------------------------- /tests/parser/functions/rlp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/tests/parser/functions/rlp/__init__.py -------------------------------------------------------------------------------- /tests/parser/functions/rlp/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import eth_tester 3 | 4 | from vyper import utils as vyper_utils 5 | 6 | 7 | @pytest.fixture(autouse=True) 8 | def patch_large_gas_limit(monkeypatch): 9 | monkeypatch.setattr(eth_tester.backends.pyevm.main, 'GENESIS_GAS_LIMIT', 10**9) 10 | 11 | 12 | @pytest.fixture 13 | def fake_tx(tester, w3): 14 | def fake_tx(): 15 | tx_hex = "0xf9035b808506fc23ac0083045f788080b903486103305660006109ac5260006109cc527f0100000000000000000000000000000000000000000000000000000000000000600035046109ec526000610a0c5260006109005260c06109ec51101515585760f86109ec51101561006e5760bf6109ec510336141558576001610a0c52610098565b60013560f76109ec51036020035260005160f66109ec510301361415585760f66109ec5103610a0c525b61022060016064818352015b36610a0c511015156100b557610291565b7f0100000000000000000000000000000000000000000000000000000000000000610a0c5135046109ec526109cc5160206109ac51026040015260016109ac51016109ac5260806109ec51101561013b5760016109cc5161044001526001610a0c516109cc5161046001376001610a0c5101610a0c5260216109cc51016109cc52610281565b60b86109ec5110156101d15760806109ec51036109cc51610440015260806109ec51036001610a0c51016109cc51610460013760816109ec5114156101ac5760807f01000000000000000000000000000000000000000000000000000000000000006001610a0c5101350410151558575b607f6109ec5103610a0c5101610a0c5260606109ec51036109cc51016109cc52610280565b60c06109ec51101561027d576001610a0c51013560b76109ec510360200352600051610a2c526038610a2c5110157f01000000000000000000000000000000000000000000000000000000000000006001610a0c5101350402155857610a2c516109cc516104400152610a2c5160b66109ec5103610a0c51016109cc516104600137610a2c5160b66109ec5103610a0c510101610a0c526020610a2c51016109cc51016109cc5261027f565bfe5b5b5b81516001018083528114156100a4575b5050601f6109ac511115155857602060206109ac5102016109005260206109005103610a0c5261022060016064818352015b6000610a0c5112156102d45761030a565b61090051610a0c516040015101610a0c51610900516104400301526020610a0c5103610a0c5281516001018083528114156102c3575b50506109cc516109005101610420526109cc5161090051016109005161044003f35b61000461033003610004600039610004610330036000f31b2d4f" 16 | w3.eth.sendTransaction({'to': '0x39ba083c30fCe59883775Fc729bBE1f9dE4DEe11', 'value': 10**17}) 17 | tx_hash = w3.eth.sendRawTransaction(tx_hex) 18 | receipt = w3.eth.getTransactionReceipt(tx_hash) 19 | contract_address = receipt.contractAddress 20 | assert vyper_utils.RLP_DECODER_ADDRESS == w3.toInt(hexstr=contract_address) 21 | return contract_address 22 | return fake_tx 23 | -------------------------------------------------------------------------------- /tests/parser/functions/test_bitwise.py: -------------------------------------------------------------------------------- 1 | def test_test_bitwise(get_contract_with_gas_estimation): 2 | test_bitwise = """ 3 | @public 4 | def _bitwise_and(x: uint256, y: uint256) -> uint256: 5 | return bitwise_and(x, y) 6 | 7 | @public 8 | def _bitwise_or(x: uint256, y: uint256) -> uint256: 9 | return bitwise_or(x, y) 10 | 11 | @public 12 | def _bitwise_xor(x: uint256, y: uint256) -> uint256: 13 | return bitwise_xor(x, y) 14 | 15 | @public 16 | def _bitwise_not(x: uint256) -> uint256: 17 | return bitwise_not(x) 18 | 19 | @public 20 | def _shift(x: uint256, y: int128) -> uint256: 21 | return shift(x, y) 22 | """ 23 | 24 | c = get_contract_with_gas_estimation(test_bitwise) 25 | x = 126416208461208640982146408124 26 | y = 7128468721412412459 27 | assert c._bitwise_and(x, y) == (x & y) 28 | assert c._bitwise_or(x, y) == (x | y) 29 | assert c._bitwise_xor(x, y) == (x ^ y) 30 | assert c._bitwise_not(x) == 2**256 - 1 - x 31 | assert c._shift(x, 3) == x * 8 32 | assert c._shift(x, 255) == 0 33 | assert c._shift(y, 255) == 2**255 34 | assert c._shift(x, 256) == 0 35 | assert c._shift(x, 0) == x 36 | assert c._shift(x, -1) == x // 2 37 | assert c._shift(x, -3) == x // 8 38 | assert c._shift(x, -256) == 0 39 | 40 | print("Passed bitwise operation tests") 41 | -------------------------------------------------------------------------------- /tests/parser/functions/test_block.py: -------------------------------------------------------------------------------- 1 | def test_block_number(get_contract_with_gas_estimation, w3): 2 | w3.testing.mine(1) 3 | 4 | block_number_code = """ 5 | @public 6 | def block_number() -> uint256: 7 | return block.number 8 | """ 9 | c = get_contract_with_gas_estimation(block_number_code) 10 | assert c.block_number() == 2 11 | 12 | 13 | def test_blockhash(get_contract_with_gas_estimation, w3): 14 | w3.testing.mine(1) 15 | 16 | block_number_code = """ 17 | @public 18 | def prev() -> bytes32: 19 | return block.prevhash 20 | 21 | @public 22 | def previous_blockhash() -> bytes32: 23 | return blockhash(block.number - 1) 24 | """ 25 | c = get_contract_with_gas_estimation(block_number_code) 26 | assert c.prev() == c.previous_blockhash() 27 | 28 | 29 | def test_negative_blockhash(assert_compile_failed, get_contract_with_gas_estimation): 30 | code = """ 31 | @public 32 | def foo() -> bytes32: 33 | return blockhash(-1) 34 | """ 35 | assert_compile_failed(lambda: get_contract_with_gas_estimation(code)) 36 | 37 | 38 | def test_too_old_blockhash(assert_tx_failed, get_contract_with_gas_estimation, w3): 39 | w3.testing.mine(257) 40 | code = """ 41 | @public 42 | def get_50_blockhash() -> bytes32: 43 | return blockhash(block.number - 257) 44 | """ 45 | c = get_contract_with_gas_estimation(code) 46 | assert_tx_failed(lambda: c.get_50_blockhash()) 47 | 48 | 49 | def test_non_existing_blockhash(assert_tx_failed, get_contract_with_gas_estimation): 50 | code = """ 51 | @public 52 | def get_future_blockhash() -> bytes32: 53 | return blockhash(block.number + 1) 54 | """ 55 | c = get_contract_with_gas_estimation(code) 56 | assert_tx_failed(lambda: c.get_future_blockhash()) 57 | -------------------------------------------------------------------------------- /tests/parser/functions/test_block_number.py: -------------------------------------------------------------------------------- 1 | 2 | def test_block_number(get_contract_with_gas_estimation, w3): 3 | block_number_code = """ 4 | @public 5 | def block_number() -> uint256: 6 | return block.number 7 | """ 8 | c = get_contract_with_gas_estimation(block_number_code) 9 | 10 | assert c.block_number() == 1 11 | w3.testing.mine(1) 12 | assert c.block_number() == 2 13 | -------------------------------------------------------------------------------- /tests/parser/functions/test_ceil.py: -------------------------------------------------------------------------------- 1 | from decimal import Decimal 2 | 3 | 4 | def test_ceil(get_contract_with_gas_estimation): 5 | code = """ 6 | x: decimal 7 | 8 | @public 9 | def __init__(): 10 | self.x = 504.0000000001 11 | 12 | @public 13 | def x_ceil() -> int128: 14 | return ceil(self.x) 15 | 16 | @public 17 | def foo() -> int128: 18 | return ceil(.9999999999) 19 | 20 | @public 21 | def fop() -> int128: 22 | return ceil(.0000000001) 23 | 24 | @public 25 | def foq() -> int128: 26 | return ceil(170141183460469231731687303715884105726.0000000002) 27 | 28 | @public 29 | def fos() -> int128: 30 | return ceil(0.0) 31 | 32 | @public 33 | def fou() -> int128: 34 | a: int128 = 305 35 | b: int128 = 100 36 | c: decimal = convert(a, decimal) / convert(b, decimal) 37 | return ceil(c) 38 | """ 39 | 40 | c = get_contract_with_gas_estimation(code) 41 | 42 | assert c.x_ceil() == 505 43 | assert c.foo() == 1 44 | assert c.fop() == 1 45 | assert c.foq() == 170141183460469231731687303715884105727 46 | assert c.fos() == 0 47 | assert c.fou() == 4 48 | 49 | 50 | # ceil(x) should yeild the smallest integer greater than or equal to x 51 | def test_ceil_negative(get_contract_with_gas_estimation): 52 | code = """ 53 | x: decimal 54 | 55 | @public 56 | def __init__(): 57 | self.x = -504.0000000001 58 | 59 | @public 60 | def x_ceil() -> int128: 61 | return ceil(self.x) 62 | 63 | @public 64 | def foo() -> int128: 65 | return ceil(-11.01) 66 | 67 | @public 68 | def fop() -> int128: 69 | return ceil(-5.0) 70 | 71 | @public 72 | def foq() -> int128: 73 | return ceil(-.0000000001) 74 | 75 | @public 76 | def fos() -> int128: 77 | return ceil(-5472.9999999999) 78 | 79 | @public 80 | def fot() -> int128: 81 | return ceil(-170141183460469231731687303715884105727.0000000002) 82 | 83 | @public 84 | def fou() -> int128: 85 | a: decimal = -305.0 86 | b: decimal = 100.0 87 | c: decimal = a / b 88 | return ceil(c) 89 | 90 | @public 91 | def ceil_param(p: decimal) -> int128: 92 | return ceil(p) 93 | """ 94 | 95 | c = get_contract_with_gas_estimation(code) 96 | 97 | assert c.x_ceil() == -504 98 | assert c.foo() == -11 99 | assert c.fop() == -5 100 | assert c.foq() == 0 101 | assert c.fos() == -5472 102 | assert c.fot() == -170141183460469231731687303715884105727 103 | assert c.fou() == -3 104 | assert c.ceil_param(Decimal('-0.5')) == 0 105 | assert c.ceil_param(Decimal('-7777777.7777777')) == -7777777 106 | -------------------------------------------------------------------------------- /tests/parser/functions/test_convert_int128.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def test_convert_bytes32_to_num_overflow(assert_tx_failed, get_contract_with_gas_estimation): 4 | code = """ 5 | @public 6 | def test1(): 7 | y: bytes32 = 0x1000000000000000000000000000000000000000000000000000000000000000 8 | x: int128 = convert(y, int128) 9 | """ 10 | 11 | c = get_contract_with_gas_estimation(code) 12 | assert_tx_failed(lambda: c.test1()) 13 | 14 | 15 | def test_convert_address_to_num(assert_compile_failed, get_contract_with_gas_estimation): 16 | code = """ 17 | @public 18 | def test2(): 19 | x: int128 = convert(msg.sender, int128) 20 | """ 21 | 22 | assert_compile_failed(lambda: get_contract_with_gas_estimation(code), Exception) 23 | 24 | 25 | def test_convert_out_of_range(assert_compile_failed, get_contract_with_gas_estimation): 26 | code = """ 27 | @public 28 | def test2(): 29 | x: int128 30 | x = convert(340282366920938463463374607431768211459, int128) 31 | """ 32 | 33 | assert_compile_failed(lambda: get_contract_with_gas_estimation(code), Exception) 34 | -------------------------------------------------------------------------------- /tests/parser/functions/test_convert_uint256.py: -------------------------------------------------------------------------------- 1 | 2 | def test_convert_to_uint256_with_negative_num(assert_compile_failed, get_contract_with_gas_estimation): 3 | code = """ 4 | @public 5 | def foo() -> uint256: 6 | return convert(1-2, uint256) 7 | """ 8 | assert_compile_failed(lambda: get_contract_with_gas_estimation(code), Exception) 9 | 10 | 11 | def test_convert_to_uint256_with_negative_input(assert_tx_failed, get_contract_with_gas_estimation): 12 | code = """ 13 | @public 14 | def foo(x: int128) -> uint256: 15 | return convert(x, uint256) 16 | """ 17 | c = get_contract_with_gas_estimation(code) 18 | assert_tx_failed(lambda: c.foo(-1)) 19 | 20 | 21 | def test_convert_to_uint256_with_bytes32(get_contract_with_gas_estimation): 22 | code = """ 23 | @public 24 | def foo() -> uint256: 25 | return convert(convert(-1, bytes32), uint256) 26 | """ 27 | 28 | c = get_contract_with_gas_estimation(code) 29 | assert c.foo() == 2 ** 256 - 1 30 | -------------------------------------------------------------------------------- /tests/parser/functions/test_default_function.py: -------------------------------------------------------------------------------- 1 | 2 | def test_throw_on_sending(w3, assert_tx_failed, get_contract_with_gas_estimation): 3 | code = """ 4 | x: public(int128) 5 | 6 | @public 7 | def __init__(): 8 | self.x = 123 9 | """ 10 | c = get_contract_with_gas_estimation(code) 11 | 12 | assert c.x() == 123 13 | assert w3.eth.getBalance(c.address) == 0 14 | assert_tx_failed(lambda: w3.eth.sendTransaction({'to': c.address, 'value': w3.toWei(0.1, 'ether')})) 15 | assert w3.eth.getBalance(c.address) == 0 16 | 17 | 18 | def test_basic_default(w3, get_logs, get_contract_with_gas_estimation): 19 | code = """ 20 | Sent: event({sender: indexed(address)}) 21 | 22 | @public 23 | @payable 24 | def __default__(): 25 | log.Sent(msg.sender) 26 | """ 27 | c = get_contract_with_gas_estimation(code) 28 | 29 | logs = get_logs(w3.eth.sendTransaction({'to': c.address, 'value': 10**17}), c, 'Sent') 30 | assert w3.eth.accounts[0] == logs[0].args.sender 31 | assert w3.eth.getBalance(c.address) == w3.toWei(0.1, 'ether') 32 | 33 | 34 | def test_basic_default_default_param_function(w3, get_logs, get_contract_with_gas_estimation): 35 | code = """ 36 | Sent: event({sender: indexed(address)}) 37 | @public 38 | @payable 39 | def fooBar(a: int128 = 12345) -> int128: 40 | log.Sent(ZERO_ADDRESS) 41 | return a 42 | 43 | @public 44 | @payable 45 | def __default__(): 46 | log.Sent(msg.sender) 47 | """ 48 | c = get_contract_with_gas_estimation(code) 49 | 50 | logs = get_logs(w3.eth.sendTransaction({'to': c.address, 'value': 10**17}), c, 'Sent') 51 | assert w3.eth.accounts[0] == logs[0].args.sender 52 | assert w3.eth.getBalance(c.address) == w3.toWei(0.1, 'ether') 53 | 54 | 55 | def test_basic_default_not_payable(w3, assert_tx_failed, get_contract_with_gas_estimation): 56 | code = """ 57 | Sent: event({sender: indexed(address)}) 58 | 59 | @public 60 | def __default__(): 61 | log.Sent(msg.sender) 62 | """ 63 | c = get_contract_with_gas_estimation(code) 64 | 65 | assert_tx_failed(lambda: w3.eth.sendTransaction({'to': c.address, 'value': 10**17})) 66 | 67 | 68 | def test_multi_arg_default(assert_compile_failed, get_contract_with_gas_estimation): 69 | code = """ 70 | @payable 71 | @public 72 | def __default__(arg1: int128): 73 | pass 74 | """ 75 | assert_compile_failed(lambda: get_contract_with_gas_estimation(code)) 76 | 77 | 78 | def test_always_public(assert_compile_failed, get_contract_with_gas_estimation): 79 | code = """ 80 | @private 81 | def __default__(): 82 | pass 83 | """ 84 | assert_compile_failed(lambda: get_contract_with_gas_estimation(code)) 85 | 86 | 87 | def test_always_public_2(assert_compile_failed, get_contract_with_gas_estimation): 88 | code = """ 89 | Sent: event({sender: indexed(address)}) 90 | 91 | def __default__(): 92 | log.Sent(msg.sender) 93 | """ 94 | assert_compile_failed(lambda: get_contract_with_gas_estimation(code)) 95 | -------------------------------------------------------------------------------- /tests/parser/functions/test_ec.py: -------------------------------------------------------------------------------- 1 | G1 = [1, 2] 2 | 3 | G1_times_two = [ 4 | 1368015179489954701390400359078579693043519447331113978918064868415326638035, 5 | 9918110051302171585080402603319702774565515993150576347155970296011118125764 6 | ] 7 | 8 | G1_times_three = [ 9 | 3353031288059533942658390886683067124040920775575537747144343083137631628272, 10 | 19321533766552368860946552437480515441416830039777911637913418824951667761761 11 | ] 12 | 13 | negative_G1 = [ 14 | 1, 15 | 21888242871839275222246405745257275088696311157297823662689037894645226208581 16 | ] 17 | 18 | curve_order = 21888242871839275222246405745257275088548364400416034343698204186575808495617 19 | 20 | 21 | def test_ecadd(get_contract_with_gas_estimation): 22 | ecadder = """ 23 | x3: uint256[2] 24 | y3: uint256[2] 25 | 26 | @public 27 | def _ecadd(x: uint256[2], y: uint256[2]) -> uint256[2]: 28 | return ecadd(x, y) 29 | 30 | @public 31 | def _ecadd2(x: uint256[2], y: uint256[2]) -> uint256[2]: 32 | x2: uint256[2] = x 33 | y2: uint256[2] = [y[0], y[1]] 34 | return ecadd(x2, y2) 35 | 36 | @public 37 | def _ecadd3(x: uint256[2], y: uint256[2]) -> uint256[2]: 38 | self.x3 = x 39 | self.y3 = [y[0], y[1]] 40 | return ecadd(self.x3, self.y3) 41 | 42 | """ 43 | c = get_contract_with_gas_estimation(ecadder) 44 | 45 | assert c._ecadd(G1, G1) == G1_times_two 46 | assert c._ecadd2(G1, G1_times_two) == G1_times_three 47 | assert c._ecadd3(G1, [0, 0]) == G1 48 | assert c._ecadd3(G1, negative_G1) == [0, 0] 49 | 50 | 51 | def test_ecmul(get_contract_with_gas_estimation): 52 | ecmuller = """ 53 | x3: uint256[2] 54 | y3: uint256 55 | 56 | @public 57 | def _ecmul(x: uint256[2], y: uint256) -> uint256[2]: 58 | return ecmul(x, y) 59 | 60 | @public 61 | def _ecmul2(x: uint256[2], y: uint256) -> uint256[2]: 62 | x2: uint256[2] = x 63 | y2: uint256 = y 64 | return ecmul(x2, y2) 65 | 66 | @public 67 | def _ecmul3(x: uint256[2], y: uint256) -> uint256[2]: 68 | self.x3 = x 69 | self.y3 = y 70 | return ecmul(self.x3, self.y3) 71 | 72 | """ 73 | c = get_contract_with_gas_estimation(ecmuller) 74 | 75 | assert c._ecmul(G1, 0) == [0, 0] 76 | assert c._ecmul(G1, 1) == G1 77 | assert c._ecmul(G1, 3) == G1_times_three 78 | assert c._ecmul(G1, curve_order - 1) == negative_G1 79 | assert c._ecmul(G1, curve_order) == [0, 0] 80 | -------------------------------------------------------------------------------- /tests/parser/functions/test_ecrecover.py: -------------------------------------------------------------------------------- 1 | from eth_account import Account 2 | 3 | 4 | def test_ecrecover_test(get_contract_with_gas_estimation): 5 | ecrecover_test = """ 6 | @public 7 | def test_ecrecover(h: bytes32, v:uint256, r:uint256, s:uint256) -> address: 8 | return ecrecover(h, v, r, s) 9 | 10 | @public 11 | def test_ecrecover2() -> address: 12 | return ecrecover(0x3535353535353535353535353535353535353535353535353535353535353535, 13 | convert(28, uint256), 14 | convert(63198938615202175987747926399054383453528475999185923188997970550032613358815, uint256), 15 | convert(6577251522710269046055727877571505144084475024240851440410274049870970796685, uint256)) 16 | """ 17 | 18 | c = get_contract_with_gas_estimation(ecrecover_test) 19 | 20 | h = b'\x35' * 32 21 | local_account = Account.privateKeyToAccount(b'\x46' * 32) 22 | sig = local_account.signHash(h) 23 | 24 | assert c.test_ecrecover(h, sig.v, sig.r, sig.s) == local_account.address 25 | assert c.test_ecrecover2() == local_account.address 26 | 27 | print("Passed ecrecover test") 28 | -------------------------------------------------------------------------------- /tests/parser/functions/test_extract32.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def test_extract32_extraction(assert_tx_failed, get_contract_with_gas_estimation): 4 | extract32_code = """ 5 | y: bytes[100] 6 | @public 7 | def extrakt32(inp: bytes[100], index: int128) -> bytes32: 8 | return extract32(inp, index) 9 | 10 | @public 11 | def extrakt32_mem(inp: bytes[100], index: int128) -> bytes32: 12 | x: bytes[100] = inp 13 | return extract32(x, index) 14 | 15 | @public 16 | def extrakt32_storage(index: int128, inp: bytes[100]) -> bytes32: 17 | self.y = inp 18 | return extract32(self.y, index) 19 | """ 20 | 21 | c = get_contract_with_gas_estimation(extract32_code) 22 | test_cases = ( 23 | (b"c" * 31, 0), 24 | (b"c" * 32, 0), 25 | (b"c" * 32, -1), 26 | (b"c" * 33, 0), 27 | (b"c" * 33, 1), 28 | (b"c" * 33, 2), 29 | (b"cow" * 30, 0), 30 | (b"cow" * 30, 1), 31 | (b"cow" * 30, 31), 32 | (b"cow" * 30, 32), 33 | (b"cow" * 30, 33), 34 | (b"cow" * 30, 34), 35 | (b"cow" * 30, 58), 36 | (b"cow" * 30, 59), 37 | ) 38 | 39 | for S, i in test_cases: 40 | expected_result = S[i: i + 32] if 0 <= i <= len(S) - 32 else None 41 | if expected_result is None: 42 | assert_tx_failed(lambda: c.extrakt32(S, i)) 43 | else: 44 | assert c.extrakt32(S, i) == expected_result 45 | assert c.extrakt32_mem(S, i) == expected_result 46 | assert c.extrakt32_storage(i, S) == expected_result 47 | 48 | print("Passed bytes32 extraction test") 49 | 50 | 51 | def test_extract32_code(assert_tx_failed, get_contract_with_gas_estimation): 52 | extract32_code = """ 53 | @public 54 | def foo(inp: bytes[32]) -> int128: 55 | return extract32(inp, 0, type=int128) 56 | 57 | @public 58 | def bar(inp: bytes[32]) -> uint256: 59 | return extract32(inp, 0, type=uint256) 60 | 61 | @public 62 | def baz(inp: bytes[32]) -> bytes32: 63 | return extract32(inp, 0, type=bytes32) 64 | 65 | @public 66 | def fop(inp: bytes[32]) -> bytes32: 67 | return extract32(inp, 0) 68 | 69 | @public 70 | def foq(inp: bytes[32]) -> address: 71 | return extract32(inp, 0, type=address) 72 | """ 73 | 74 | c = get_contract_with_gas_estimation(extract32_code) 75 | assert c.foo(b"\x00" * 30 + b"\x01\x01") == 257 76 | assert c.bar(b"\x00" * 30 + b"\x01\x01") == 257 77 | 78 | assert_tx_failed(lambda: c.foo(b"\x80" + b"\x00" * 30)) 79 | 80 | assert c.bar(b"\x80" + b"\x00" * 31) == 2**255 81 | 82 | assert c.baz(b"crow" * 8) == b"crow" * 8 83 | assert c.fop(b"crow" * 8) == b"crow" * 8 84 | assert c.foq(b"\x00" * 12 + b"3" * 20) == "0x" + "3" * 40 85 | 86 | assert_tx_failed(lambda: c.foq(b"crow" * 8)) 87 | 88 | print('Passed extract32 test') 89 | -------------------------------------------------------------------------------- /tests/parser/functions/test_floor.py: -------------------------------------------------------------------------------- 1 | from decimal import Decimal 2 | 3 | 4 | def test_floor(get_contract_with_gas_estimation): 5 | code = """ 6 | x: decimal 7 | 8 | @public 9 | def __init__(): 10 | self.x = 504.0000000001 11 | 12 | @public 13 | def x_floor() -> int128: 14 | return floor(self.x) 15 | 16 | @public 17 | def foo() -> int128: 18 | return floor(1.9999999999) 19 | 20 | @public 21 | def fop() -> int128: 22 | return floor(1.0000000001) 23 | 24 | @public 25 | def foq() -> int128: 26 | return floor(170141183460469231731687303715884105726.0000000002) 27 | 28 | @public 29 | def fos() -> int128: 30 | return floor(0.0) 31 | 32 | @public 33 | def fot() -> int128: 34 | return floor(0.0000000001) 35 | 36 | @public 37 | def fou() -> int128: 38 | a: decimal = 305.0 39 | b: decimal = 100.0 40 | c: decimal = a / b 41 | return floor(c) 42 | """ 43 | c = get_contract_with_gas_estimation(code) 44 | assert c.x_floor() == 504 45 | assert c.foo() == 1 46 | assert c.fop() == 1 47 | assert c.foq() == 170141183460469231731687303715884105726 48 | assert c.fos() == 0 49 | assert c.fot() == 0 50 | assert c.fou() == 3 51 | 52 | 53 | def test_floor_negative(get_contract_with_gas_estimation): 54 | code = """ 55 | x: decimal 56 | 57 | @public 58 | def __init__(): 59 | self.x = -504.0000000001 60 | 61 | @public 62 | def x_floor() -> int128: 63 | return floor(self.x) 64 | 65 | @public 66 | def foo() -> int128: 67 | a: int128 = -65 68 | b: decimal = convert(a, decimal) / 10.0 69 | return floor(b) 70 | 71 | @public 72 | def fop() -> int128: 73 | return floor(-27.0) 74 | 75 | @public 76 | def foq() -> int128: 77 | return floor(-9000.0000000001) 78 | 79 | @public 80 | def fos() -> int128: 81 | return floor(-0.0000000001) 82 | 83 | @public 84 | def fot() -> int128: 85 | return floor(-170141183460469231731687303715884105727.0000000002) 86 | 87 | @public 88 | def fou() -> int128: 89 | a: decimal = -305.0 90 | b: decimal = 100.0 91 | c: decimal = a / b 92 | return floor(c) 93 | 94 | @public 95 | def floor_param(p: decimal) -> int128: 96 | return floor(p) 97 | """ 98 | 99 | c = get_contract_with_gas_estimation(code) 100 | 101 | assert c.x_floor() == -505 102 | assert c.foo() == -7 103 | assert c.fop() == -27 104 | assert c.foq() == -9001 105 | assert c.fos() == -1 106 | assert c.fot() == -170141183460469231731687303715884105728 107 | assert c.fou() == -4 108 | assert c.floor_param(Decimal('-5.6')) == -6 109 | assert c.floor_param(Decimal('-0.0000000001')) == -1 110 | -------------------------------------------------------------------------------- /tests/parser/functions/test_is_contract.py: -------------------------------------------------------------------------------- 1 | def test_is_contract(w3, get_contract_with_gas_estimation): 2 | contract_1 = """ 3 | @public 4 | def foo(arg1: address) -> bool: 5 | result: bool = arg1.is_contract 6 | return result 7 | """ 8 | 9 | contract_2 = """ 10 | @public 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 | def test_test_length(get_contract_with_gas_estimation): 2 | test_length = """ 3 | y: bytes[10] 4 | 5 | @public 6 | def foo(inp: bytes[10]) -> int128: 7 | x: bytes[5] = slice(inp, start=1, len=5) 8 | self.y = slice(inp, start=2, len=4) 9 | return len(inp) * 100 + len(x) * 10 + len(self.y) 10 | """ 11 | 12 | c = get_contract_with_gas_estimation(test_length) 13 | assert c.foo(b"badminton") == 954, c.foo(b"badminton") 14 | print('Passed length test') 15 | -------------------------------------------------------------------------------- /tests/parser/functions/test_method_id.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def test_method_id_test(get_contract_with_gas_estimation): 4 | method_id_test = """ 5 | @public 6 | def double(x: int128) -> int128: 7 | return x * 2 8 | 9 | @public 10 | def returnten() -> int128: 11 | ans: bytes[32] = raw_call(self, concat(method_id("double(int128)", bytes[4]), convert(5, bytes32)), gas=50000, outsize=32) 12 | return convert(convert(ans, bytes32), int128) 13 | """ 14 | c = get_contract_with_gas_estimation(method_id_test) 15 | assert c.returnten() == 10 16 | print("Passed method ID test") 17 | 18 | 19 | def test_method_id_bytes32(get_contract): 20 | code = """ 21 | @public 22 | def sig() -> bytes32: 23 | return method_id('transfer(address,uint256)', bytes32) 24 | """ 25 | c = get_contract(code) 26 | sig = c.sig() 27 | 28 | assert len(sig) == 32 29 | assert sig[-4:] == b"\xa9\x05\x9c\xbb" 30 | 31 | 32 | def test_method_id_bytes4(get_contract): 33 | code = """ 34 | @public 35 | def sig() -> bytes[4]: 36 | return method_id('transfer(address,uint256)', bytes[4]) 37 | """ 38 | c = get_contract(code) 39 | sig = c.sig() 40 | 41 | # assert len(sig) == 4 42 | assert sig == b"\xa9\x05\x9c\xbb" 43 | 44 | 45 | def test_method_id_invalid_space(get_contract, assert_compile_failed): 46 | code = """ 47 | @public 48 | def sig() -> bytes32: 49 | return method_id('transfer(address, uint256)', bytes32) 50 | """ 51 | assert_compile_failed(lambda: get_contract(code)) 52 | 53 | 54 | def test_method_id_invalid_type(get_contract, assert_compile_failed): 55 | code = """ 56 | @public 57 | def sig() -> int128: 58 | return method_id('transfer(address,uint256)', int128) 59 | """ 60 | assert_compile_failed(lambda: get_contract(code)) 61 | -------------------------------------------------------------------------------- /tests/parser/functions/test_only_init_abi.py: -------------------------------------------------------------------------------- 1 | from vyper.compiler import mk_full_signature 2 | 3 | 4 | def test_only_init_function(): 5 | code = """ 6 | x: int128 7 | 8 | @public 9 | def __init__(): 10 | self.x = 1 11 | """ 12 | code_init_empty = """ 13 | x: int128 14 | 15 | @public 16 | def __init__(): 17 | pass 18 | """ 19 | 20 | empty_sig = [{ 21 | 'name': '__init__', 22 | 'outputs': [], 23 | 'inputs': [], 24 | 'constant': False, 25 | 'payable': False, 26 | 'type': 'constructor' 27 | }] 28 | 29 | assert mk_full_signature(code) == empty_sig 30 | assert mk_full_signature(code_init_empty) == empty_sig 31 | -------------------------------------------------------------------------------- /tests/parser/functions/test_send.py: -------------------------------------------------------------------------------- 1 | def test_send(assert_tx_failed, get_contract): 2 | send_test = """ 3 | @public 4 | def foo(): 5 | send(msg.sender, self.balance + 1) 6 | 7 | @public 8 | def fop(): 9 | send(msg.sender, 10) 10 | """ 11 | c = get_contract(send_test, value=10) 12 | assert_tx_failed(lambda: c.foo(transact={})) 13 | c.fop(transact={}) 14 | assert_tx_failed(lambda: c.fop(transact={})) 15 | 16 | 17 | def test_payable_tx_fail(assert_tx_failed, get_contract, w3): 18 | code = """ 19 | @public 20 | def pay_me() -> bool: 21 | return True 22 | """ 23 | c = get_contract(code) 24 | assert_tx_failed(lambda: c.pay_me(transact={'value': w3.toWei(0.1, 'ether')})) 25 | 26 | 27 | def test_default_gas(get_contract, w3): 28 | """ Tests to verify that send to default function will send limited gas (2300), but raw_call can send more.""" 29 | 30 | sender_code = """ 31 | @public 32 | def test_send(receiver: address): 33 | send(receiver, 1) 34 | 35 | @public 36 | def test_call(receiver: address): 37 | raw_call(receiver, "", gas=50000, outsize=0, value=1) 38 | """ 39 | 40 | # default function writes variable, this requires more gas than send can pass 41 | receiver_code = """ 42 | last_sender: public(address) 43 | 44 | @public 45 | @payable 46 | def __default__(): 47 | self.last_sender = msg.sender 48 | """ 49 | 50 | sender = get_contract(sender_code, value=1) 51 | receiver = get_contract(receiver_code) 52 | 53 | sender.test_send(receiver.address, transact={'gas': 100000}) 54 | 55 | # no value transfer hapenned, variable was not changed 56 | assert receiver.last_sender() is None 57 | assert w3.eth.getBalance(sender.address) == 1 58 | assert w3.eth.getBalance(receiver.address) == 0 59 | 60 | sender.test_call(receiver.address, transact={'gas': 100000}) 61 | 62 | # value transfer hapenned, variable was changed 63 | assert receiver.last_sender() == sender.address 64 | assert w3.eth.getBalance(sender.address) == 0 65 | assert w3.eth.getBalance(receiver.address) == 1 66 | -------------------------------------------------------------------------------- /tests/parser/functions/test_sha3.py: -------------------------------------------------------------------------------- 1 | def test_hash_code(get_contract_with_gas_estimation, keccak): 2 | hash_code = """ 3 | @public 4 | def foo(inp: bytes[100]) -> bytes32: 5 | return sha3(inp) 6 | 7 | @public 8 | def bar() -> bytes32: 9 | return sha3("inp") 10 | """ 11 | 12 | c = get_contract_with_gas_estimation(hash_code) 13 | for inp in (b"", b"cow", b"s" * 31, b"\xff" * 32, b"\n" * 33, b"g" * 64, b"h" * 65): 14 | assert '0x' + c.foo(inp).hex() == keccak(inp).hex() 15 | 16 | assert '0x' + c.bar().hex() == keccak(b"inp").hex() 17 | 18 | 19 | def test_hash_code2(get_contract_with_gas_estimation): 20 | hash_code2 = """ 21 | @public 22 | def foo(inp: bytes[100]) -> bool: 23 | return sha3(inp) == sha3("badminton") 24 | """ 25 | c = get_contract_with_gas_estimation(hash_code2) 26 | assert c.foo(b"badminto") is False 27 | assert c.foo(b"badminton") is True 28 | 29 | 30 | def test_hash_code3(get_contract_with_gas_estimation): 31 | hash_code3 = """ 32 | test: bytes[100] 33 | 34 | @public 35 | def set_test(inp: bytes[100]): 36 | self.test = inp 37 | 38 | @public 39 | def tryy(inp: bytes[100]) -> bool: 40 | return sha3(inp) == sha3(self.test) 41 | 42 | @public 43 | def trymem(inp: bytes[100]) -> bool: 44 | x: bytes[100] = self.test 45 | return sha3(inp) == sha3(x) 46 | 47 | @public 48 | def try32(inp: bytes32) -> bool: 49 | return sha3(inp) == sha3(self.test) 50 | """ 51 | c = get_contract_with_gas_estimation(hash_code3) 52 | c.set_test(b"", transact={}) 53 | assert c.tryy(b"") is True 54 | assert c.trymem(b"") is True 55 | assert c.tryy(b"cow") is False 56 | c.set_test(b"cow", transact={}) 57 | assert c.tryy(b"") is False 58 | assert c.tryy(b"cow") is True 59 | c.set_test(b"\x35" * 32, transact={}) 60 | assert c.tryy(b"\x35" * 32) is True 61 | assert c.trymem(b"\x35" * 32) is True 62 | assert c.try32(b"\x35" * 32) is True 63 | assert c.tryy(b"\x35" * 33) is False 64 | c.set_test(b"\x35" * 33, transact={}) 65 | assert c.tryy(b"\x35" * 32) is False 66 | assert c.trymem(b"\x35" * 32) is False 67 | assert c.try32(b"\x35" * 32) is False 68 | assert c.tryy(b"\x35" * 33) is True 69 | 70 | print("Passed SHA3 hash test") 71 | -------------------------------------------------------------------------------- /tests/parser/functions/test_slice.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def test_test_slice(get_contract_with_gas_estimation): 4 | test_slice = """ 5 | 6 | @public 7 | def foo(inp1: bytes[10]) -> bytes[3]: 8 | x: int128 = 5 9 | s: bytes[3] = slice(inp1, start=3, len=3) 10 | y: int128 = 7 11 | return s 12 | 13 | @public 14 | def bar(inp1: bytes[10]) -> int128: 15 | x: int128 = 5 16 | s: bytes[3] = slice(inp1, start=3, len=3) 17 | y: int128 = 7 18 | return x * y 19 | """ 20 | 21 | c = get_contract_with_gas_estimation(test_slice) 22 | x = c.foo(b"badminton") 23 | assert x == b"min", x 24 | 25 | assert c.bar(b"badminton") == 35 26 | 27 | print('Passed slice test') 28 | 29 | 30 | def test_test_slice2(get_contract_with_gas_estimation): 31 | test_slice2 = """ 32 | @public 33 | def slice_tower_test(inp1: bytes[50]) -> bytes[50]: 34 | inp: bytes[50] = inp1 35 | for i in range(1, 11): 36 | inp = slice(inp, start=1, len=30 - i * 2) 37 | return inp 38 | """ 39 | c = get_contract_with_gas_estimation(test_slice2) 40 | x = c.slice_tower_test(b"abcdefghijklmnopqrstuvwxyz1234") 41 | assert x == b"klmnopqrst", x 42 | 43 | print('Passed advanced slice test') 44 | 45 | 46 | def test_test_slice3(get_contract_with_gas_estimation): 47 | test_slice3 = """ 48 | x: int128 49 | s: bytes[50] 50 | y: int128 51 | @public 52 | def foo(inp1: bytes[50]) -> bytes[50]: 53 | self.x = 5 54 | self.s = slice(inp1, start=3, len=3) 55 | self.y = 7 56 | return self.s 57 | 58 | @public 59 | def bar(inp1: bytes[50]) -> int128: 60 | self.x = 5 61 | self.s = slice(inp1, start=3, len=3) 62 | self.y = 7 63 | return self.x * self.y 64 | """ 65 | 66 | c = get_contract_with_gas_estimation(test_slice3) 67 | x = c.foo(b"badminton") 68 | assert x == b"min", x 69 | 70 | assert c.bar(b"badminton") == 35 71 | 72 | print('Passed storage slice test') 73 | 74 | 75 | def test_test_slice4(get_contract_with_gas_estimation, assert_tx_failed): 76 | test_slice4 = """ 77 | @public 78 | def foo(inp: bytes[10], start: int128, _len: int128) -> bytes[10]: 79 | return slice(inp, start=start, len=_len) 80 | """ 81 | 82 | c = get_contract_with_gas_estimation(test_slice4) 83 | assert c.foo(b"badminton", 3, 3) == b"min" 84 | assert c.foo(b"badminton", 0, 9) == b"badminton" 85 | assert c.foo(b"badminton", 1, 8) == b"adminton" 86 | assert c.foo(b"badminton", 1, 7) == b"adminto" 87 | assert c.foo(b"badminton", 1, 0) == b"" 88 | assert c.foo(b"badminton", 9, 0) == b"" 89 | 90 | assert_tx_failed(lambda: c.foo(b"badminton", 0, 10)) 91 | assert_tx_failed(lambda: c.foo(b"badminton", 1, 9)) 92 | assert_tx_failed(lambda: c.foo(b"badminton", 9, 1)) 93 | assert_tx_failed(lambda: c.foo(b"badminton", 10, 0)) 94 | 95 | print('Passed slice edge case test') 96 | 97 | 98 | def test_slice_at_end(get_contract): 99 | code = """ 100 | @public 101 | def ret10_slice() -> bytes[10]: 102 | b: bytes[32] = concat(convert(65, bytes32), '') 103 | c: bytes[10] = slice(b, start=31, len=1) 104 | return c 105 | """ 106 | 107 | c = get_contract(code) 108 | assert c.ret10_slice() == b'A' 109 | -------------------------------------------------------------------------------- /tests/parser/globals/test_getters.py: -------------------------------------------------------------------------------- 1 | def test_state_accessor(get_contract_with_gas_estimation_for_constants): 2 | state_accessor = """ 3 | y: int128[int128] 4 | 5 | @public 6 | def oo(): 7 | self.y[3] = 5 8 | 9 | @public 10 | def foo() -> int128: 11 | return self.y[3] 12 | 13 | """ 14 | 15 | c = get_contract_with_gas_estimation_for_constants(state_accessor) 16 | c.oo(transact={}) 17 | assert c.foo() == 5 18 | print('Passed basic state accessor test') 19 | 20 | 21 | def test_getter_code(get_contract_with_gas_estimation_for_constants): 22 | getter_code = """ 23 | x: public(wei_value) 24 | y: public(int128[5]) 25 | z: public(bytes[100]) 26 | w: public({ 27 | a: wei_value, 28 | b: int128[7], 29 | c: bytes[100], 30 | d: int128[address], 31 | e: int128[3][3], 32 | f: timestamp, 33 | g: wei_value 34 | }[int128]) 35 | 36 | @public 37 | def __init__(): 38 | self.x = as_wei_value(7, "wei") 39 | self.y[1] = 9 40 | self.z = "cow" 41 | self.w[1].a = 11 42 | self.w[1].b[2] = 13 43 | self.w[1].c = "horse" 44 | self.w[1].d[0x1234567890123456789012345678901234567890] = 15 45 | self.w[2].e[1][2] = 17 46 | self.w[3].f = 750 47 | self.w[3].g = 751 48 | """ 49 | 50 | c = get_contract_with_gas_estimation_for_constants(getter_code) 51 | assert c.x() == 7 52 | assert c.y(1) == 9 53 | assert c.z() == b"cow" 54 | assert c.w__a(1) == 11 55 | assert c.w__b(1, 2) == 13 56 | assert c.w__c(1) == b"horse" 57 | assert c.w__d(1, "0x1234567890123456789012345678901234567890") == 15 58 | assert c.w__e(2, 1, 2) == 17 59 | assert c.w__f(3) == 750 60 | assert c.w__g(3) == 751 61 | 62 | print('Passed getter tests') 63 | -------------------------------------------------------------------------------- /tests/parser/globals/test_globals.py: -------------------------------------------------------------------------------- 1 | from pytest import raises 2 | from vyper.exceptions import VariableDeclarationException 3 | 4 | 5 | def test_permanent_variables_test(get_contract_with_gas_estimation): 6 | permanent_variables_test = """ 7 | var: {a: int128, b: int128} 8 | 9 | @public 10 | def __init__(a: int128, b: int128): 11 | self.var.a = a 12 | self.var.b = b 13 | 14 | @public 15 | def returnMoose() -> int128: 16 | return self.var.a * 10 + self.var.b 17 | """ 18 | 19 | c = get_contract_with_gas_estimation(permanent_variables_test, *[5, 7]) 20 | assert c.returnMoose() == 57 21 | print('Passed init argument and variable member test') 22 | 23 | 24 | def test_missing_global(get_contract): 25 | code = """ 26 | @public 27 | def a() -> int128: 28 | return self.b 29 | """ 30 | 31 | with raises(VariableDeclarationException): 32 | get_contract(code) 33 | -------------------------------------------------------------------------------- /tests/parser/integration/test_basics.py: -------------------------------------------------------------------------------- 1 | def test_null_code(get_contract_with_gas_estimation): 2 | null_code = """ 3 | @public 4 | def foo(): 5 | pass 6 | """ 7 | c = get_contract_with_gas_estimation(null_code) 8 | c.foo() 9 | print('Successfully executed a null function') 10 | 11 | 12 | def test_basic_code(get_contract_with_gas_estimation): 13 | basic_code = """ 14 | @public 15 | def foo(x: int128) -> int128: 16 | return x * 2 17 | 18 | """ 19 | c = get_contract_with_gas_estimation(basic_code) 20 | assert c.foo(9) == 18 21 | print('Passed basic code test') 22 | 23 | 24 | def test_selfcall_code_3(get_contract_with_gas_estimation, keccak): 25 | selfcall_code_3 = """ 26 | @public 27 | def _hashy2(x: bytes[100]) -> bytes32: 28 | return sha3(x) 29 | 30 | @public 31 | def return_hash_of_cow_x_30() -> bytes32: 32 | return self._hashy2("cowcowcowcowcowcowcowcowcowcowcowcowcowcowcowcowcowcowcowcowcowcowcowcowcowcowcowcowcowcow") 33 | 34 | @public 35 | def _len(x: bytes[100]) -> int128: 36 | return len(x) 37 | 38 | @public 39 | def returnten() -> int128: 40 | return self._len("badminton!") 41 | """ 42 | 43 | c = get_contract_with_gas_estimation(selfcall_code_3) 44 | assert c.return_hash_of_cow_x_30() == keccak(b'cow' * 30) 45 | assert c.returnten() == 10 46 | 47 | print("Passed single variable-size argument self-call test") 48 | -------------------------------------------------------------------------------- /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 | @public 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 | @public 18 | def finalize(): 19 | assert msg.sender == self.buyer or msg.sender == self.arbitrator 20 | send(self.seller, self.balance) 21 | 22 | @public 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 | @public 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 | @public 52 | def finalize(): 53 | assert msg.sender == self.buyer or msg.sender == self.arbitrator 54 | send(self.seller, self.balance) 55 | 56 | @public 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/syntax/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/tests/parser/syntax/__init__.py -------------------------------------------------------------------------------- /tests/parser/syntax/test_ann_assign.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import ( 6 | VariableDeclarationException, 7 | TypeMismatchException, 8 | StructureException 9 | ) 10 | 11 | 12 | fail_list = [ 13 | """ 14 | @public 15 | def test(): 16 | a = 1 17 | """, 18 | """ 19 | @public 20 | def test(): 21 | a = 33.33 22 | """, 23 | """ 24 | @public 25 | def test(): 26 | a = "test string" 27 | """, 28 | (""" 29 | @public 30 | def test(): 31 | a: int128 = 33.33 32 | """, TypeMismatchException), 33 | (""" 34 | @private 35 | def do_stuff() -> bool: 36 | return True 37 | 38 | @public 39 | def test(): 40 | a: bool = self.do_stuff() or self.do_stuff() 41 | """, StructureException), 42 | (""" 43 | @private 44 | def do_stuff() -> bool: 45 | return True 46 | 47 | @public 48 | def test(): 49 | a: bool = False or self.do_stuff() 50 | """, StructureException), 51 | (""" 52 | @public 53 | def data() -> int128: 54 | s: int128[5] = [1, 2, 3, 4, 5, 6] 55 | """, TypeMismatchException), 56 | (""" 57 | @public 58 | def foo() -> int128: 59 | struct: {a: int128, b: decimal} = {a: 1.2, b: 1} 60 | return struct.a 61 | """, TypeMismatchException), 62 | (""" 63 | @public 64 | def foo() -> int128: 65 | struct: {a: int128, b: decimal} = {b: 1.2, c: 1, d: 33, e: 55} 66 | return struct.a 67 | """, TypeMismatchException) 68 | ] 69 | 70 | 71 | @pytest.mark.parametrize('bad_code', fail_list) 72 | def test_as_wei_fail(bad_code): 73 | if isinstance(bad_code, tuple): 74 | with raises(bad_code[1]): 75 | compiler.compile(bad_code[0]) 76 | else: 77 | with raises(VariableDeclarationException): 78 | compiler.compile(bad_code) 79 | 80 | 81 | valid_list = [ 82 | """ 83 | @public 84 | def test(): 85 | a: int128 = 1 86 | """, 87 | """ 88 | @private 89 | def do_stuff() -> bool: 90 | return True 91 | 92 | @public 93 | def test(): 94 | a: bool = self.do_stuff() 95 | """ 96 | ] 97 | 98 | 99 | @pytest.mark.parametrize('good_code', valid_list) 100 | def test_ann_assign_success(good_code): 101 | assert compiler.compile(good_code) is not None 102 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_as_uint256.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def convert2(inp: uint256) -> address: 12 | return convert(inp, bytes32) 13 | """, 14 | """ 15 | @public 16 | def modtest(x: uint256, y: int128) -> uint256: 17 | return x % y 18 | """ 19 | ] 20 | 21 | 22 | @pytest.mark.parametrize('bad_code', fail_list) 23 | def test_as_wei_fail(bad_code): 24 | 25 | with raises(TypeMismatchException): 26 | compiler.compile(bad_code) 27 | 28 | 29 | valid_list = [ 30 | """ 31 | @public 32 | def convert1(inp: bytes32) -> uint256: 33 | return convert(inp, uint256) 34 | """, 35 | """ 36 | @public 37 | def convert1(inp: bytes32) -> uint256: 38 | return convert(inp, uint256) 39 | """, 40 | """ 41 | @public 42 | def convert2(inp: uint256) -> bytes32: 43 | return convert(inp, bytes32) 44 | """ 45 | ] 46 | 47 | 48 | @pytest.mark.parametrize('good_code', valid_list) 49 | def test_as_wei_success(good_code): 50 | assert compiler.compile(good_code) is not None 51 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_as_wei_value.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def foo(): 12 | x: int128(wei) = as_wei_value(5, szabo) 13 | """, 14 | """ 15 | @public 16 | def foo() -> int128(wei): 17 | x: int128(wei) = 45 18 | return x.balance 19 | """ 20 | ] 21 | 22 | 23 | @pytest.mark.parametrize('bad_code', fail_list) 24 | def test_as_wei_fail(bad_code): 25 | with raises(TypeMismatchException): 26 | compiler.compile(bad_code) 27 | 28 | 29 | valid_list = [ 30 | """ 31 | @public 32 | def foo(): 33 | x: uint256(wei) = as_wei_value(5, "finney") + as_wei_value(2, "babbage") + as_wei_value(8, "shannon") 34 | """, 35 | """ 36 | @public 37 | def foo(): 38 | z: int128 = 2 + 3 39 | x: uint256(wei) = as_wei_value(2 + 3, "finney") 40 | """, 41 | """ 42 | @public 43 | def foo(): 44 | x: uint256(wei) = as_wei_value(5.182, "babbage") 45 | """, 46 | """ 47 | @public 48 | def foo() -> uint256(wei): 49 | x: address = 0x1234567890123456789012345678901234567890 50 | return x.balance 51 | """ 52 | ] 53 | 54 | 55 | @pytest.mark.parametrize('good_code', valid_list) 56 | def test_as_wei_success(good_code): 57 | assert compiler.compile(good_code) is not None 58 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_blockscope.py: -------------------------------------------------------------------------------- 1 | 2 | import pytest 3 | from pytest import raises 4 | 5 | from vyper import compiler 6 | from vyper.exceptions import VariableDeclarationException 7 | 8 | 9 | fail_list = [ 10 | """ 11 | @public 12 | def foo(choice: bool): 13 | if (choice): 14 | a = 1 15 | a += 1 16 | """, 17 | """ 18 | @public 19 | def foo(choice: bool): 20 | if (choice): 21 | a = 0 22 | else: 23 | a = 1 24 | a += 1 25 | """, 26 | """ 27 | @public 28 | def foo(choice: bool): 29 | if (choice): 30 | a = 0 31 | else: 32 | a += 1 33 | """, 34 | """ 35 | @public 36 | def foo(choice: bool): 37 | 38 | for i in range(4): 39 | a = 0 40 | a += 1 41 | """, 42 | """ 43 | @public 44 | def foo(choice: bool): 45 | 46 | for i in range(4): 47 | a = 0 48 | a += 1 49 | """, 50 | """ 51 | a: int128 52 | 53 | @public 54 | def foo(): 55 | a = 5 56 | """, 57 | ] 58 | 59 | 60 | @pytest.mark.parametrize('bad_code', fail_list) 61 | def test_fail_(bad_code): 62 | 63 | with raises(VariableDeclarationException): 64 | compiler.compile(bad_code) 65 | 66 | 67 | valid_list = [ 68 | """ 69 | @public 70 | def foo(choice: bool, choice2: bool): 71 | if (choice): 72 | a: int128 = 11 73 | if choice2 and a > 1: 74 | a -= 1 # should be visible here. 75 | """ 76 | ] 77 | 78 | 79 | @pytest.mark.parametrize('good_code', valid_list) 80 | def test_valid_blockscope(good_code): 81 | assert compiler.compile(good_code) is not None 82 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_bool.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def foo(): 12 | x: bool = True 13 | x = 5 14 | """, 15 | (""" 16 | @public 17 | def foo(): 18 | True = 3 19 | """, SyntaxError), 20 | """ 21 | @public 22 | def foo(): 23 | x: bool = True 24 | x = 129 25 | """, 26 | """ 27 | @public 28 | def foo() -> bool: 29 | return (1 == 2) <= (1 == 1) 30 | """, 31 | """ 32 | @public 33 | def foo() -> bool: 34 | return (1 == 2) or 3 35 | """, 36 | """ 37 | @public 38 | def foo() -> bool: 39 | return 1.0 == 1 40 | """, 41 | """ 42 | @public 43 | def foo() -> bool: 44 | a: address 45 | return a == 1 46 | """, 47 | """ 48 | @public 49 | def foo(a: address) -> bool: 50 | return not a 51 | """, 52 | """ 53 | @public 54 | def foo() -> bool: 55 | b: int128 56 | return not b 57 | """, 58 | """ 59 | @public 60 | def foo() -> bool: 61 | b: uint256 62 | return not b 63 | """, 64 | """ 65 | @public 66 | def foo() -> bool: 67 | b: uint256 68 | return not b 69 | """, 70 | """ 71 | @public 72 | def test(a: address) -> bool: 73 | assert(a) 74 | return True 75 | """ 76 | ] 77 | 78 | 79 | @pytest.mark.parametrize('bad_code', fail_list) 80 | def test_bool_fail(bad_code): 81 | 82 | if isinstance(bad_code, tuple): 83 | with raises(bad_code[1]): 84 | compiler.compile(bad_code[0]) 85 | else: 86 | with raises(TypeMismatchException): 87 | compiler.compile(bad_code) 88 | 89 | 90 | valid_list = [ 91 | """ 92 | @public 93 | def foo(): 94 | x: bool = True 95 | z: bool = x and False 96 | """, 97 | """ 98 | @public 99 | def foo(): 100 | x: bool = True 101 | z: bool = x and False 102 | """, 103 | """ 104 | @public 105 | def foo(): 106 | x: bool = True 107 | x = False 108 | """, 109 | """ 110 | @public 111 | def foo() -> bool: 112 | return 1 == 1 113 | """, 114 | """ 115 | @public 116 | def foo() -> bool: 117 | return 1 != 1 118 | """, 119 | """ 120 | @public 121 | def foo() -> bool: 122 | return 1 > 1 123 | """, 124 | """ 125 | @public 126 | def foo() -> bool: 127 | return 2 >= 1 128 | """, 129 | """ 130 | @public 131 | def foo() -> bool: 132 | return 1 < 1 133 | """, 134 | """ 135 | @public 136 | def foo() -> bool: 137 | return 1 <= 1 138 | """, 139 | """ 140 | @public 141 | def foo2(a: address) -> bool: 142 | return a != ZERO_ADDRESS 143 | """ 144 | ] 145 | 146 | 147 | @pytest.mark.parametrize('good_code', valid_list) 148 | def test_bool_success(good_code): 149 | assert compiler.compile(good_code) is not None 150 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_byte_string.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from vyper import compiler 4 | 5 | 6 | valid_list = [ 7 | """ 8 | @public 9 | def foo() -> bytes[10]: 10 | return "badminton" 11 | """, 12 | """ 13 | @public 14 | def foo(): 15 | x: bytes[11] = "¡très bien!" 16 | """ 17 | ] 18 | 19 | 20 | @pytest.mark.parametrize('good_code', valid_list) 21 | def test_byte_string_success(good_code): 22 | assert compiler.compile(good_code) is not None 23 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_bytes.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import ( 6 | TypeMismatchException, 7 | InvalidLiteralException 8 | ) 9 | 10 | fail_list = [ 11 | """ 12 | @public 13 | def baa(): 14 | x: bytes[50] 15 | y: bytes[50] 16 | z = x + y 17 | """, 18 | """ 19 | @public 20 | def baa(): 21 | x: bytes[50] 22 | y: int128 23 | y = x 24 | """, 25 | """ 26 | @public 27 | def baa(): 28 | x: bytes[50] 29 | y: int128 30 | x = y 31 | """, 32 | """ 33 | @public 34 | def baa(): 35 | x: bytes[50] 36 | y: bytes[60] 37 | x = y 38 | """, 39 | """ 40 | @public 41 | def foo(x: bytes[100]) -> bytes[75]: 42 | return x 43 | """, 44 | """ 45 | @public 46 | def foo(x: bytes[100]) -> int128: 47 | return x 48 | """, 49 | """ 50 | @public 51 | def foo(x: int128) -> bytes[75]: 52 | return x 53 | """, 54 | """ 55 | @public 56 | def foo() -> bytes[10]: 57 | x: bytes[10] = '0x1234567890123456789012345678901234567890' 58 | x = 0x1234567890123456789012345678901234567890 59 | """, 60 | """ 61 | @public 62 | def foo() -> bytes[10]: 63 | return "badmintonzz" 64 | """, 65 | (""" 66 | @public 67 | def test() -> bytes[1]: 68 | a: bytes[1] = 0b0000001 # needs mutliple of 8 bits. 69 | return a 70 | """, InvalidLiteralException) 71 | ] 72 | 73 | 74 | @pytest.mark.parametrize('bad_code', fail_list) 75 | def test_bytes_fail(bad_code): 76 | if isinstance(bad_code, tuple): 77 | with raises(bad_code[1]): 78 | compiler.compile(bad_code[0]) 79 | else: 80 | with raises(TypeMismatchException): 81 | compiler.compile(bad_code) 82 | 83 | 84 | valid_list = [ 85 | """ 86 | @public 87 | def foo(x: bytes[100]) -> bytes[100]: 88 | return x 89 | """, 90 | """ 91 | @public 92 | def foo(x: bytes[100]) -> bytes[150]: 93 | return x 94 | """, 95 | """ 96 | @public 97 | def convert2(inp: uint256) -> bytes32: 98 | return convert(inp, bytes32) 99 | """, 100 | """ 101 | @public 102 | def baa(): 103 | x: bytes[50] 104 | """ 105 | ] 106 | 107 | 108 | @pytest.mark.parametrize('good_code', valid_list) 109 | def test_bytes_success(good_code): 110 | assert compiler.compile(good_code) is not None 111 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_code_size.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def foo() -> int128: 12 | x: int128 = 45 13 | return x.codesize 14 | """, 15 | """ 16 | @public 17 | def foo() -> int128(wei): 18 | x: address = 0x1234567890123456789012345678901234567890 19 | return x.codesize 20 | """ 21 | ] 22 | 23 | 24 | @pytest.mark.parametrize('bad_code', fail_list) 25 | def test_block_fail(bad_code): 26 | 27 | with raises(TypeMismatchException): 28 | compiler.compile(bad_code) 29 | 30 | 31 | valid_list = [ 32 | """ 33 | @public 34 | def foo() -> int128: 35 | x: address = 0x1234567890123456789012345678901234567890 36 | return x.codesize 37 | """ 38 | ] 39 | 40 | 41 | @pytest.mark.parametrize('good_code', valid_list) 42 | def test_block_success(good_code): 43 | assert compiler.compile(good_code) is not None 44 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_concat.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pytest import raises 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def cat(i1: bytes[10], i2: bytes[30]) -> bytes[40]: 12 | return concat(i1, i2, i1, i1) 13 | """, 14 | """ 15 | @public 16 | def cat(i1: bytes[10], i2: bytes[30]) -> bytes[40]: 17 | return concat(i1, 5) 18 | """, 19 | """ 20 | @public 21 | def sandwich(inp: bytes[100], inp2: bytes32) -> bytes[163]: 22 | return concat(inp2, inp, inp2) 23 | """, 24 | """ 25 | y: bytes[10] 26 | 27 | @public 28 | def krazykonkat(z: bytes[10]) -> bytes[24]: 29 | x: bytes[10] = "cow" 30 | self.y = "horse" 31 | return concat(x, " ", self.y, " ", z) 32 | """, 33 | """ 34 | @public 35 | def cat_list(y: int128) -> bytes[40]: 36 | x: int128[1] = [y] 37 | return concat("test", y) 38 | """, 39 | ] 40 | 41 | 42 | @pytest.mark.parametrize('bad_code', fail_list) 43 | def test_block_fail(bad_code): 44 | 45 | with raises(TypeMismatchException): 46 | compiler.compile(bad_code) 47 | 48 | 49 | valid_list = [ 50 | """ 51 | @public 52 | def cat(i1: bytes[10], i2: bytes[30]) -> bytes[40]: 53 | return concat(i1, i2) 54 | """, 55 | """ 56 | @public 57 | def cat(i1: bytes[10], i2: bytes[30]) -> bytes[40]: 58 | return concat(i1, i1, i1, i1) 59 | """, 60 | """ 61 | @public 62 | def cat(i1: bytes[10], i2: bytes[30]) -> bytes[40]: 63 | return concat(i1, i1) 64 | """, 65 | """ 66 | @public 67 | def sandwich(inp: bytes[100], inp2: bytes32) -> bytes[165]: 68 | return concat(inp2, inp, inp2) 69 | """, 70 | """ 71 | y: bytes[10] 72 | 73 | @public 74 | def krazykonkat(z: bytes[10]) -> bytes[25]: 75 | x: bytes[3] = "cow" 76 | self.y = "horse" 77 | return concat(x, " ", self.y, " ", z) 78 | """ 79 | ] 80 | 81 | 82 | @pytest.mark.parametrize('good_code', valid_list) 83 | def test_block_success(good_code): 84 | assert compiler.compile(good_code) is not None 85 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_constants.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import ( 6 | StructureException, 7 | TypeMismatchException, 8 | VariableDeclarationException, 9 | ) 10 | 11 | 12 | fail_list = [ 13 | # no value 14 | """ 15 | VAL: constant(uint256) 16 | """, 17 | # too many args 18 | """ 19 | VAL: constant(uint256, int128) = 12 20 | """, 21 | # invalid type 22 | (""" 23 | VAL: constant(uint256) = "test" 24 | """, TypeMismatchException), 25 | # invalid range 26 | (""" 27 | VAL: constant(uint256) = -1 28 | """, TypeMismatchException), 29 | # reserverd keyword 30 | (""" 31 | wei: constant(uint256) = 1 32 | """, VariableDeclarationException), 33 | # duplicate constant name 34 | (""" 35 | VAL: constant(uint256) = 11 36 | VAL: constant(uint256) = 11 37 | """, VariableDeclarationException), 38 | # bytearray too long. 39 | (""" 40 | VAL: constant(bytes[4]) = "testtest" 41 | """, TypeMismatchException), 42 | # global with same name 43 | (""" 44 | VAL: constant(bytes[4]) = "t" 45 | VAL: uint256 46 | """, VariableDeclarationException) 47 | ] 48 | 49 | 50 | @pytest.mark.parametrize('bad_code', fail_list) 51 | def test_as_wei_fail(bad_code): 52 | if isinstance(bad_code, tuple): 53 | with raises(bad_code[1]): 54 | compiler.compile(bad_code[0]) 55 | else: 56 | with raises(StructureException): 57 | compiler.compile(bad_code) 58 | 59 | 60 | valid_list = [ 61 | """ 62 | VAL: constant(uint256) = 123 63 | """, 64 | """ 65 | VAL: constant(int128) = -123 66 | @public 67 | def test() -> int128: 68 | return 1 * VAL 69 | """ 70 | ] 71 | 72 | 73 | @pytest.mark.parametrize('good_code', valid_list) 74 | def test_as_wei_success(good_code): 75 | assert compiler.compile(good_code) is not None 76 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_create_with_code_of.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | 6 | 7 | fail_list = [ 8 | """ 9 | @public 10 | def foo(): 11 | x: address = create_with_code_of(0x1234567890123456789012345678901234567890, value=4, value=9) 12 | """ 13 | ] 14 | 15 | 16 | @pytest.mark.parametrize('bad_code', fail_list) 17 | def test_type_mismatch_exception(bad_code): 18 | with raises(SyntaxError): 19 | compiler.compile(bad_code) 20 | 21 | 22 | valid_list = [ 23 | """ 24 | @public 25 | def foo(): 26 | x: address = create_with_code_of(0x1234567890123456789012345678901234567890) 27 | """, 28 | """ 29 | @public 30 | def foo(): 31 | x: address = create_with_code_of(0x1234567890123456789012345678901234567890, value=as_wei_value(9, "wei")) 32 | """, 33 | """ 34 | @public 35 | def foo(): 36 | x: address = create_with_code_of(0x1234567890123456789012345678901234567890, value=9) 37 | """ 38 | ] 39 | 40 | 41 | @pytest.mark.parametrize('good_code', valid_list) 42 | def test_rlp_success(good_code): 43 | assert compiler.compile(good_code) is not None 44 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_custom_units.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import ( 6 | VariableDeclarationException, 7 | InvalidTypeException 8 | ) 9 | 10 | 11 | fail_list = [ 12 | """ 13 | units: 1 14 | """, 15 | """ 16 | units: { 17 | "cm": "centimeter" 18 | } 19 | """, 20 | """ 21 | units: { 22 | "cm": 1 23 | } 24 | """, 25 | """ 26 | units: { 27 | cm: "centimeter" 28 | } 29 | units: { 30 | km: "kilometer" 31 | } 32 | """, 33 | """ 34 | units: { 35 | wei: "wei" 36 | } 37 | """, 38 | """ 39 | units: { 40 | cm: 123 41 | } 42 | """, 43 | """ 44 | units: { 45 | cm: "centimeter", 46 | cm: "kilometer" 47 | } 48 | """, 49 | (""" 50 | units: { 51 | cm: "centimeter", 52 | } 53 | @public 54 | def test(): 55 | a: int128(km) 56 | """, InvalidTypeException), 57 | """ 58 | units: { 59 | cm: "centimeter", 60 | } 61 | @public 62 | def test(): 63 | cm: int128 64 | """, 65 | (""" 66 | units: { 67 | cm: "centimeter", 68 | } 69 | a: int128(km) 70 | """, InvalidTypeException), 71 | """ 72 | units: { 73 | cm: "centimeter", 74 | } 75 | cm: bytes[5] 76 | """, 77 | """ 78 | @public 79 | def test(): 80 | units: bytes[4] 81 | """ 82 | ] 83 | 84 | 85 | @pytest.mark.parametrize('bad_code', fail_list) 86 | def test_custom_units_fail(bad_code): 87 | if isinstance(bad_code, tuple): 88 | with raises(bad_code[1]): 89 | compiler.compile(bad_code[0]) 90 | else: 91 | with raises(VariableDeclarationException): 92 | compiler.compile(bad_code) 93 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_extract32.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException 6 | 7 | fail_list = [ 8 | """ 9 | @public 10 | def foo() -> uint256: 11 | return extract32("cowcowcowcowcowccowcowcowcowcowccowcowcowcowcowccowcowcowcowcowc", 0) 12 | """ 13 | ] 14 | 15 | 16 | @pytest.mark.parametrize('bad_code', fail_list) 17 | def test_extract32_fail(bad_code): 18 | 19 | with raises(TypeMismatchException): 20 | compiler.compile(bad_code) 21 | 22 | 23 | valid_list = [ 24 | """ 25 | @public 26 | def foo() -> uint256: 27 | return extract32("cowcowcowcowcowccowcowcowcowcowccowcowcowcowcowccowcowcowcowcowc", 0, type=uint256) 28 | """, 29 | """ 30 | x: bytes[100] 31 | @public 32 | def foo() -> uint256: 33 | self.x = "cowcowcowcowcowccowcowcowcowcowccowcowcowcowcowccowcowcowcowcowc" 34 | return extract32(self.x, 0, type=uint256) 35 | """, 36 | """ 37 | x: bytes[100] 38 | @public 39 | def foo() -> uint256: 40 | self.x = "cowcowcowcowcowccowcowcowcowcowccowcowcowcowcowccowcowcowcowcowc" 41 | return extract32(self.x, 1, type=uint256) 42 | """ 43 | ] 44 | 45 | 46 | @pytest.mark.parametrize('good_code', valid_list) 47 | def test_extract32_success(good_code): 48 | assert compiler.compile(good_code) is not None 49 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_for_range.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from vyper import compiler 4 | 5 | valid_list = [ 6 | """ 7 | @public 8 | def foo(): 9 | for i in range(10): 10 | pass 11 | """, 12 | """ 13 | @public 14 | def foo(): 15 | for i in range(10, 20): 16 | pass 17 | """, 18 | """ 19 | @public 20 | def foo(): 21 | x: int128 = 5 22 | for i in range(x, x + 10): 23 | pass 24 | """ 25 | ] 26 | 27 | 28 | @pytest.mark.parametrize('good_code', valid_list) 29 | def test_range_success(good_code): 30 | assert compiler.compile(good_code) is not None 31 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_functions_call.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import StructureException 6 | 7 | fail_list = [ 8 | """ 9 | @public 10 | def foo() -> uint256: 11 | doesnotexist(2, uint256) 12 | return convert(2, uint256) 13 | """, 14 | """ 15 | @public 16 | def foo() -> uint256: 17 | convert(2, uint256) 18 | return convert(2, uint256) 19 | 20 | """ 21 | ] 22 | 23 | 24 | @pytest.mark.parametrize('bad_code', fail_list) 25 | def test_raw_call_fail(bad_code): 26 | 27 | if isinstance(bad_code, tuple): 28 | with raises(bad_code[1]): 29 | compiler.compile(bad_code[0]) 30 | else: 31 | with raises(StructureException): 32 | compiler.compile(bad_code) 33 | 34 | 35 | valid_list = [ 36 | """ 37 | @public 38 | def foo() -> uint256: 39 | return convert(2, uint256) 40 | """ 41 | ] 42 | 43 | 44 | @pytest.mark.parametrize('good_code', valid_list) 45 | def test_raw_call_success(good_code): 46 | assert compiler.compile(good_code) is not None 47 | -------------------------------------------------------------------------------- /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 TypeMismatchException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def foo(inp: int128) -> int128: 12 | return len(inp) 13 | """, 14 | """ 15 | @public 16 | def foo(inp: int128) -> address: 17 | return len(inp) 18 | """ 19 | ] 20 | 21 | 22 | @pytest.mark.parametrize('bad_code', fail_list) 23 | def test_block_fail(bad_code): 24 | 25 | if isinstance(bad_code, tuple): 26 | with raises(bad_code[1]): 27 | compiler.compile(bad_code[0]) 28 | else: 29 | with raises(TypeMismatchException): 30 | compiler.compile(bad_code) 31 | 32 | 33 | valid_list = [ 34 | """ 35 | @public 36 | def foo(inp: bytes[10]) -> int128: 37 | return len(inp) 38 | """ 39 | ] 40 | 41 | 42 | @pytest.mark.parametrize('good_code', valid_list) 43 | def test_list_success(good_code): 44 | assert compiler.compile(good_code) is not None 45 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_logging.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | Bar: event({_value: int128[4]}) 11 | x: decimal[4] 12 | 13 | @public 14 | def foo(): 15 | log.Bar(self.x) 16 | """, 17 | """ 18 | Bar: event({_value: int128[4]}) 19 | 20 | @public 21 | def foo(): 22 | x: decimal[4] 23 | log.Bar(x) 24 | """ 25 | ] 26 | 27 | 28 | @pytest.mark.parametrize('bad_code', fail_list) 29 | def test_logging_fail(bad_code): 30 | 31 | if isinstance(bad_code, tuple): 32 | with raises(bad_code[1]): 33 | compiler.compile(bad_code[0]) 34 | else: 35 | with raises(TypeMismatchException): 36 | compiler.compile(bad_code) 37 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_minmax.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def foo(): 12 | y = min(7, 0x1234567890123456789012345678901234567890) 13 | """ 14 | ] 15 | 16 | 17 | @pytest.mark.parametrize('bad_code', fail_list) 18 | def test_block_fail(bad_code): 19 | 20 | with raises(TypeMismatchException): 21 | compiler.compile(bad_code) 22 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_missing_return.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import FunctionDeclarationException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def foo() -> int128: 12 | pass 13 | """, 14 | ] 15 | 16 | 17 | @pytest.mark.parametrize('bad_code', fail_list) 18 | def test_missing_return(bad_code): 19 | with raises(FunctionDeclarationException): 20 | compiler.compile(bad_code) 21 | 22 | 23 | valid_list = [ 24 | """ 25 | @public 26 | def foo() -> int128: 27 | return 123 28 | """, 29 | """ 30 | @public 31 | def foo() -> int128: 32 | if False: 33 | return 123 34 | """, # For the time being this is valid code, even though it should not be. 35 | ] 36 | 37 | 38 | @pytest.mark.parametrize('good_code', valid_list) 39 | def test_return_success(good_code): 40 | assert compiler.compile(good_code) is not None 41 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_nested_list.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException, StructureException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | bar: int128[3][3] 11 | @public 12 | def foo(): 13 | self.bar = [[1, 2], [3, 4, 5], [6, 7, 8]] 14 | """, 15 | """ 16 | bar: int128[3][3] 17 | @public 18 | def foo(): 19 | self.bar = [[1, 2, 3], [4, 5, 6], [7.0, 8.0, 9.0]] 20 | """, 21 | """ 22 | @public 23 | def foo() -> int128[2]: 24 | return [[1,2],[3,4]] 25 | """, 26 | """ 27 | @public 28 | def foo() -> int128[2][2]: 29 | return [1,2] 30 | """, 31 | """ 32 | y: address[2][2] 33 | 34 | @public 35 | def foo(x: int128[2][2]) -> int128: 36 | self.y = x 37 | """, 38 | (""" 39 | bar: int128[3][3] 40 | 41 | @public 42 | def foo() -> int128[3]: 43 | self.bar = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 44 | for x in self.bar: 45 | if x == [4, 5, 6]: 46 | return x 47 | """, StructureException) 48 | ] 49 | 50 | 51 | @pytest.mark.parametrize('bad_code', fail_list) 52 | def test_nested_list_fail(bad_code): 53 | 54 | if isinstance(bad_code, tuple): 55 | with raises(bad_code[1]): 56 | compiler.compile(bad_code[0]) 57 | else: 58 | with raises(TypeMismatchException): 59 | compiler.compile(bad_code) 60 | 61 | 62 | valid_list = [ 63 | """ 64 | bar: int128[3][3] 65 | @public 66 | def foo(): 67 | self.bar = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 68 | """, 69 | """ 70 | bar: decimal[3][3] 71 | @public 72 | def foo(): 73 | self.bar = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 74 | """ 75 | ] 76 | 77 | 78 | @pytest.mark.parametrize('good_code', valid_list) 79 | def test_nested_list_sucess(good_code): 80 | assert compiler.compile(good_code) is not None 81 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_public.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from vyper import compiler 4 | 5 | 6 | valid_list = [ 7 | """ 8 | x: public(int128) 9 | """, 10 | """ 11 | x: public(int128(wei / sec)) 12 | y: public(int128(wei / sec ** 2)) 13 | z: public(int128(1 / sec)) 14 | 15 | @public 16 | def foo() -> int128(sec ** 2): 17 | return self.x / self.y / self.z 18 | """ 19 | ] 20 | 21 | 22 | @pytest.mark.parametrize('good_code', valid_list) 23 | def test_public_success(good_code): 24 | assert compiler.compile(good_code) is not None 25 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_raw_call.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException 6 | 7 | 8 | fail_list = [ 9 | (""" 10 | @public 11 | def foo(): 12 | x: bytes[9] = raw_call(0x1234567890123456789012345678901234567890, "cow", outsize=4, outsize=9) 13 | """, SyntaxError), 14 | """ 15 | @public 16 | def foo(): 17 | raw_log(["cow"], "dog") 18 | """, 19 | """ 20 | @public 21 | def foo(): 22 | raw_log([], 0x1234567890123456789012345678901234567890) 23 | """ 24 | ] 25 | 26 | 27 | @pytest.mark.parametrize('bad_code', fail_list) 28 | def test_raw_call_fail(bad_code): 29 | 30 | if isinstance(bad_code, tuple): 31 | with raises(bad_code[1]): 32 | compiler.compile(bad_code[0]) 33 | else: 34 | with raises(TypeMismatchException): 35 | compiler.compile(bad_code) 36 | 37 | 38 | valid_list = [ 39 | """ 40 | @public 41 | def foo(): 42 | x: bytes[9] = raw_call(0x1234567890123456789012345678901234567890, "cow", outsize=4, gas=595757) 43 | """, 44 | """ 45 | @public 46 | def foo(): 47 | x: bytes[9] = raw_call(0x1234567890123456789012345678901234567890, "cow", outsize=4, gas=595757, value=as_wei_value(9, "wei")) 48 | """, 49 | """ 50 | @public 51 | def foo(): 52 | x: bytes[9] = raw_call(0x1234567890123456789012345678901234567890, "cow", outsize=4, gas=595757, value=9) 53 | """ 54 | ] 55 | 56 | 57 | @pytest.mark.parametrize('good_code', valid_list) 58 | def test_raw_call_success(good_code): 59 | assert compiler.compile(good_code) is not None 60 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_return_tuple.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import StructureException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def unmatched_tupl_length() -> (bytes[8], int128, bytes[8]): 12 | return "test", 123 13 | """ 14 | ] 15 | 16 | 17 | @pytest.mark.parametrize('bad_code', fail_list) 18 | def test_tuple_return_fail(bad_code): 19 | 20 | with raises(StructureException): 21 | compiler.compile(bad_code) 22 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_rlplist.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException, StructureException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def foo() -> address: 12 | x = RLPList('\xf6\x9455555555555555555555\xa0GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG', [address, bytes32]) 13 | return x[1] 14 | """, 15 | """ 16 | @public 17 | def foo() -> address: 18 | x = RLPList('\xf6\x9455555555555555555555\xa0GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG', [address, bytes32]) 19 | return x[2] 20 | """, 21 | """ 22 | @public 23 | def foo() -> bytes[500]: 24 | x = RLPList('\xe1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', [bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes]) 25 | return x[1] 26 | """, 27 | (""" 28 | @public 29 | def foo() -> bytes[500]: 30 | x: int128 = 1 31 | return RLPList('\xe0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') 32 | """, StructureException), 33 | """ 34 | @public 35 | def foo() -> bytes[500]: 36 | x: int128[3] = [1, 2, 3] 37 | return RLPList(x, [bytes]) 38 | """, 39 | """ 40 | @public 41 | def foo() -> bytes[500]: 42 | x: bytes[500] = '\xe1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' 43 | a: int128 = 1 44 | return RLPList(x, a) 45 | """, 46 | """ 47 | @public 48 | def foo() -> bytes[500]: 49 | x: bytes[500] = '\xe1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' 50 | return RLPList(x, []) 51 | """, 52 | """ 53 | @public 54 | def foo() -> bytes32: 55 | x = RLPList('\xe1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', [address, int128[2]]) 56 | return x[1] 57 | """, 58 | """ 59 | @public 60 | def foo() -> bytes32: 61 | x = RLPList('\xe1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', [decimal]) 62 | return x[1] 63 | """, 64 | """ 65 | @public 66 | def foo() -> bytes32: 67 | x = RLPList('\xe1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', [int128(wei)]) 68 | return x[1] 69 | """ 70 | ] 71 | 72 | 73 | @pytest.mark.parametrize('bad_code', fail_list) 74 | def test_rlplist_fail(bad_code): 75 | 76 | if isinstance(bad_code, tuple): 77 | with raises(bad_code[1]): 78 | compiler.compile(bad_code[0]) 79 | else: 80 | with raises(TypeMismatchException): 81 | compiler.compile(bad_code) 82 | 83 | 84 | valid_list = [ 85 | """ 86 | @public 87 | def foo() -> bytes[500]: 88 | x = RLPList('\xe0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', [bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes, bytes]) 89 | return x[1] 90 | """, 91 | """ 92 | @public 93 | def foo() -> address: 94 | x = RLPList('\xf6\x9455555555555555555555\xa0GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG', [address, bytes32]) 95 | return x[0] 96 | """, 97 | """ 98 | @public 99 | def foo() -> bytes32: 100 | x = RLPList('\xf6\x9455555555555555555555\xa0GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG', [address, bytes32]) 101 | return x[1] 102 | """ 103 | ] 104 | 105 | 106 | @pytest.mark.parametrize('good_code', valid_list) 107 | def test_rlplist_success(good_code): 108 | assert compiler.compile(good_code) is not None 109 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_selfdestruct.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def foo(): 12 | selfdestruct(7) 13 | """ 14 | ] 15 | 16 | 17 | @pytest.mark.parametrize('bad_code', fail_list) 18 | def test_block_fail(bad_code): 19 | 20 | with raises(TypeMismatchException): 21 | compiler.compile(bad_code) 22 | 23 | 24 | valid_list = [ 25 | """ 26 | @public 27 | def foo(): 28 | selfdestruct(0x1234567890123456789012345678901234567890) 29 | """ 30 | ] 31 | 32 | 33 | @pytest.mark.parametrize('good_code', valid_list) 34 | def test_block_success(good_code): 35 | assert compiler.compile(good_code) is not None 36 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_send.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def foo(): 12 | send(1, 2) 13 | """, 14 | """ 15 | @public 16 | def foo(): 17 | send(1, 2) 18 | """, 19 | """ 20 | @public 21 | def foo(): 22 | send(0x1234567890123456789012345678901234567890, 2.5) 23 | """, 24 | """ 25 | @public 26 | def foo(): 27 | send(0x1234567890123456789012345678901234567890, 0x1234567890123456789012345678901234567890) 28 | """, 29 | """ 30 | x: int128 31 | 32 | @public 33 | def foo(): 34 | send(0x1234567890123456789012345678901234567890, self.x) 35 | """, 36 | """ 37 | x: wei_value 38 | 39 | @public 40 | def foo(): 41 | send(0x1234567890123456789012345678901234567890, self.x + 1.5) 42 | """, 43 | """ 44 | x: decimal 45 | 46 | @public 47 | def foo(): 48 | send(0x1234567890123456789012345678901234567890, self.x) 49 | """ 50 | ] 51 | 52 | 53 | @pytest.mark.parametrize('bad_code', fail_list) 54 | def test_send_fail(bad_code): 55 | with raises(TypeMismatchException): 56 | compiler.compile(bad_code) 57 | 58 | 59 | valid_list = [ 60 | """ 61 | x: wei_value 62 | 63 | @public 64 | def foo(): 65 | send(0x1234567890123456789012345678901234567890, self.x + 1) 66 | """, 67 | """ 68 | x: decimal 69 | 70 | @public 71 | def foo(): 72 | send(0x1234567890123456789012345678901234567890, as_wei_value(floor(self.x), "wei")) 73 | """, 74 | """ 75 | x: wei_value 76 | 77 | @public 78 | def foo(): 79 | send(0x1234567890123456789012345678901234567890, self.x) 80 | """, 81 | """ 82 | @public 83 | def foo(): 84 | send(0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe, 5) 85 | """ 86 | ] 87 | 88 | 89 | @pytest.mark.parametrize('good_code', valid_list) 90 | def test_block_success(good_code): 91 | assert compiler.compile(good_code) is not None 92 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_sha3.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def foo(): 12 | x: bytes32 = sha3(3) 13 | """ 14 | ] 15 | 16 | 17 | @pytest.mark.parametrize('bad_code', fail_list) 18 | def test_block_fail(bad_code): 19 | with raises(TypeMismatchException): 20 | compiler.compile(bad_code) 21 | 22 | 23 | valid_list = [ 24 | """ 25 | @public 26 | def foo(): 27 | x: bytes32 = sha3("moose") 28 | """, 29 | """ 30 | @public 31 | def foo(): 32 | x: bytes32 = sha3(0x1234567890123456789012345678901234567890123456789012345678901234) 33 | """ 34 | ] 35 | 36 | 37 | @pytest.mark.parametrize('good_code', valid_list) 38 | def test_block_success(good_code): 39 | assert compiler.compile(good_code) is not None 40 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_slice.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException 6 | 7 | 8 | fail_list = [ 9 | """ 10 | @public 11 | def foo(inp: bytes[10]) -> bytes[2]: 12 | return slice(inp, start=2, len=3) 13 | """, 14 | """ 15 | @public 16 | def foo(inp: int128) -> bytes[3]: 17 | return slice(inp, start=2, len=3) 18 | """, 19 | """ 20 | @public 21 | def foo(inp: bytes[10]) -> bytes[3]: 22 | return slice(inp, start=4.0, len=3) 23 | """ 24 | ] 25 | 26 | 27 | @pytest.mark.parametrize('bad_code', fail_list) 28 | def test_slice_fail(bad_code): 29 | 30 | with raises(TypeMismatchException): 31 | compiler.compile(bad_code) 32 | 33 | 34 | valid_list = [ 35 | """ 36 | @public 37 | def foo(inp: bytes[10]) -> bytes[3]: 38 | return slice(inp, start=2, len=3) 39 | """, 40 | """ 41 | @public 42 | def foo(inp: bytes[10]) -> bytes[4]: 43 | return slice(inp, start=2, len=3) 44 | """, 45 | """ 46 | @public 47 | def foo() -> bytes[10]: 48 | return slice("badmintonzzz", start=1, len=10) 49 | """ 50 | ] 51 | 52 | 53 | @pytest.mark.parametrize('good_code', valid_list) 54 | def test_slice_success(good_code): 55 | assert compiler.compile(good_code) is not None 56 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_tuple_assign.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import ( 6 | VariableDeclarationException, 7 | TypeMismatchException 8 | ) 9 | 10 | fail_list = [ 11 | (""" 12 | @public 13 | def test(): 14 | a: int128 15 | b: int128 16 | c: int128 17 | a, b, c = 1, 2, 3 18 | """, VariableDeclarationException), 19 | """ 20 | @public 21 | def out_literals() -> (int128, int128, bytes[10]): 22 | return 1, 2, "3333" 23 | 24 | @public 25 | def test() -> (int128, address, bytes[10]): 26 | a: int128 27 | b: int128 28 | a, b, b = self.out_literals() # incorrect bytes type 29 | return a, b, c 30 | """, 31 | """ 32 | @public 33 | def out_literals() -> (int128, int128, bytes[10]): 34 | return 1, 2, "3333" 35 | 36 | @public 37 | def test() -> (int128, address, bytes[10]): 38 | a: int128 39 | b: address 40 | a, b = self.out_literals() # tuple count mismatch 41 | return 42 | """, 43 | """ 44 | @public 45 | def out_literals() -> (int128, int128, int128): 46 | return 1, 2, 3 47 | 48 | @public 49 | def test() -> (int128, int128, bytes[10]): 50 | a: int128 51 | b: int128 52 | c: bytes[10] 53 | a, b, c = self.out_literals() 54 | return a, b, c 55 | """, 56 | """ 57 | @public 58 | def out_literals() -> (int128, int128, bytes[100]): 59 | return 1, 2, "test" 60 | 61 | @public 62 | def test(): 63 | a: int128 64 | b: int128 65 | c: bytes[1] 66 | a, b, c = self.out_literals() 67 | """, 68 | ] 69 | 70 | 71 | @pytest.mark.parametrize('bad_code', fail_list) 72 | def test_tuple_assign_fail(bad_code): 73 | if isinstance(bad_code, tuple): 74 | with raises(bad_code[1]): 75 | compiler.compile(bad_code[0]) 76 | else: 77 | with raises(TypeMismatchException): 78 | compiler.compile(bad_code) 79 | -------------------------------------------------------------------------------- /tests/parser/syntax/test_unit_exponents.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import TypeMismatchException 6 | 7 | fail_list = [ 8 | """ 9 | @public 10 | def baa() -> decimal: 11 | return 2.0 ** 2 12 | """, 13 | """ 14 | @public 15 | def foo(a: int128): 16 | b:int128(sec) 17 | c:int128(sec**2) 18 | c = b ** a 19 | """ 20 | ] 21 | 22 | 23 | @pytest.mark.parametrize('bad_code', fail_list) 24 | def test_exponent_fail(bad_code): 25 | 26 | with raises(TypeMismatchException): 27 | compiler.compile(bad_code) 28 | 29 | 30 | valid_list = [ 31 | """ 32 | @public 33 | def foo(): 34 | a : int128(wei) 35 | b : int128(wei**2) 36 | a = 2 37 | b = a**2 38 | """, 39 | ] 40 | 41 | 42 | @pytest.mark.parametrize('good_code', valid_list) 43 | def test_exponent_success(good_code): 44 | assert compiler.compile(good_code) is not None 45 | -------------------------------------------------------------------------------- /tests/parser/syntax/utils/test_event_names.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import EventDeclarationException 6 | 7 | fail_list = [ 8 | """ 9 | Âssign: event({variable: int128}) 10 | 11 | @public 12 | def foo(i: int128) -> int128: 13 | temp_var : int128 = i 14 | log.Âssign(temp_var) 15 | return temp_var 16 | """, 17 | """ 18 | int128: event({variable: int128}) 19 | 20 | @public 21 | def foo(i: int128) -> int128: 22 | temp_var : int128 = i 23 | log.int128(temp_var) 24 | return temp_var 25 | """, 26 | """ 27 | decimal: event({variable: int128}) 28 | 29 | @public 30 | def foo(i: int128) -> int128: 31 | temp_var : int128 = i 32 | log.decimal(temp_var) 33 | return temp_var 34 | """, 35 | """ 36 | wei: event({variable: int128}) 37 | 38 | @public 39 | def foo(i: int128) -> int128: 40 | temp_var : int128 = i 41 | log.wei(temp_var) 42 | return temp_var 43 | """, 44 | """ 45 | false: event({variable: int128}) 46 | 47 | @public 48 | def foo(i: int128) -> int128: 49 | temp_var : int128 = i 50 | log.false(temp_var) 51 | return temp_var 52 | """, 53 | ] 54 | 55 | 56 | @pytest.mark.parametrize('bad_code', fail_list) 57 | def test_varname_validity_fail(bad_code): 58 | with raises(EventDeclarationException): 59 | compiler.compile(bad_code) 60 | 61 | 62 | valid_list = [ 63 | """ 64 | Assigned: event({variable: int128}) 65 | 66 | @public 67 | def foo(i: int128) -> int128: 68 | variable : int128 = i 69 | log.Assigned(variable) 70 | return variable 71 | """, 72 | """ 73 | _Assign: event({variable: int128}) 74 | 75 | @public 76 | def foo(i: int128) -> int128: 77 | variable : int128 = i 78 | log._Assign(variable) 79 | return variable 80 | """, 81 | """ 82 | Assigned1: event({variable: int128}) 83 | 84 | @public 85 | def foo(i: int128) -> int128: 86 | variable : int128 = i 87 | log.Assigned1(variable) 88 | return variable 89 | """, 90 | ] 91 | 92 | 93 | @pytest.mark.parametrize('good_code', valid_list) 94 | def test_varname_validity_success(good_code): 95 | assert compiler.compile(good_code) is not None 96 | -------------------------------------------------------------------------------- /tests/parser/syntax/utils/test_function_names.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import FunctionDeclarationException 6 | 7 | fail_list = [ 8 | """ 9 | @public 10 | def ő1qwerty(i: int128) -> int128: 11 | temp_var : int128 = i 12 | return temp_var 13 | """, 14 | """ 15 | @public 16 | def int128(i: int128) -> int128: 17 | temp_var : int128 = i 18 | return temp_var 19 | """, 20 | """ 21 | @public 22 | def decimal(i: int128) -> int128: 23 | temp_var : int128 = i 24 | return temp_var 25 | """, 26 | """ 27 | @public 28 | def wei(i: int128) -> int128: 29 | temp_var : int128 = i 30 | return temp_var 31 | """, 32 | """ 33 | @public 34 | def false(i: int128) -> int128: 35 | temp_var : int128 = i 36 | return temp_var 37 | """, 38 | ] 39 | 40 | 41 | @pytest.mark.parametrize('bad_code', fail_list) 42 | def test_varname_validity_fail(bad_code): 43 | with raises(FunctionDeclarationException): 44 | compiler.compile(bad_code) 45 | 46 | 47 | valid_list = [ 48 | """ 49 | @public 50 | def func(i: int128) -> int128: 51 | variable : int128 = i 52 | return variable 53 | """, 54 | """ 55 | @public 56 | def func_to_do_math(i: int128) -> int128: 57 | var_123 : int128 = i 58 | return var_123 59 | """, 60 | """ 61 | @public 62 | def first1(i: int128) -> int128: 63 | _var123 : int128 = i 64 | return _var123 65 | """, 66 | ] 67 | 68 | 69 | @pytest.mark.parametrize('good_code', valid_list) 70 | def test_varname_validity_success(good_code): 71 | assert compiler.compile(good_code) is not None 72 | -------------------------------------------------------------------------------- /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 VariableDeclarationException 6 | 7 | fail_list = [ 8 | """ 9 | @public 10 | def foo(i: int128) -> int128: 11 | varő : int128 = i 12 | return varő 13 | """, 14 | """ 15 | @public 16 | def foo(i: int128) -> int128: 17 | int128 : int128 = i 18 | return int128 19 | """, 20 | """ 21 | @public 22 | def foo(i: int128) -> int128: 23 | decimal : int128 = i 24 | return decimal 25 | """, 26 | """ 27 | @public 28 | def foo(i: int128) -> int128: 29 | wei : int128 = i 30 | return wei 31 | """, 32 | """ 33 | @public 34 | def foo(i: int128) -> int128: 35 | false : int128 = i 36 | return false 37 | """, 38 | ] 39 | 40 | 41 | @pytest.mark.parametrize('bad_code', fail_list) 42 | def test_varname_validity_fail(bad_code): 43 | with raises(VariableDeclarationException): 44 | compiler.compile(bad_code) 45 | 46 | 47 | valid_list = [ 48 | """ 49 | @public 50 | def foo(i: int128) -> int128: 51 | variable : int128 = i 52 | return variable 53 | """, 54 | """ 55 | @public 56 | def foo(i: int128) -> int128: 57 | var_123 : int128 = i 58 | return var_123 59 | """, 60 | """ 61 | @public 62 | def foo(i: int128) -> int128: 63 | _var123 : int128 = i 64 | return _var123 65 | """, 66 | ] 67 | 68 | 69 | @pytest.mark.parametrize('good_code', valid_list) 70 | def test_varname_validity_success(good_code): 71 | assert compiler.compile(good_code) is not None 72 | -------------------------------------------------------------------------------- /tests/parser/types/numbers/test_custom_units.py: -------------------------------------------------------------------------------- 1 | from decimal import Decimal 2 | 3 | 4 | def test_custom_units(get_contract_with_gas_estimation): 5 | code = """ 6 | units: { 7 | cm: "centimeter", 8 | km: "kilometer" 9 | } 10 | 11 | # global storage 12 | a: int128(cm) 13 | 14 | 15 | @public 16 | def test() -> int128(km): 17 | b: int128(km) 18 | b = 100 19 | return b 20 | """ 21 | 22 | c = get_contract_with_gas_estimation(code) 23 | 24 | assert c.test() == 100 25 | 26 | 27 | def test_custom_units_struct(get_contract_with_gas_estimation): 28 | code = """ 29 | units: { 30 | cm: "centimer" 31 | } 32 | 33 | astruct: { 34 | value1: int128(cm) 35 | } 36 | 37 | @public 38 | def test() -> int128(cm): 39 | self.astruct.value1 = 101 40 | return self.astruct.value1 41 | """ 42 | 43 | c = get_contract_with_gas_estimation(code) 44 | 45 | assert c.test() == 101 46 | 47 | 48 | def test_custom_units_public(get_contract_with_gas_estimation): 49 | code = """ 50 | units: { 51 | mm: "millimeter" 52 | } 53 | 54 | a: int128(mm) 55 | b: public(int128(mm)) 56 | 57 | 58 | @public 59 | def test() -> int128(mm): 60 | self.a = 111 61 | return self.a 62 | """ 63 | 64 | c = get_contract_with_gas_estimation(code) 65 | 66 | assert c.test() == 111 67 | 68 | 69 | def test_custom_units_events_and_func(get_contract_with_gas_estimation): 70 | code = """ 71 | units: { 72 | stock: "how much stock there is", 73 | token: "amount of token" 74 | } 75 | 76 | 77 | Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256(stock)}) 78 | 79 | @public 80 | def initiate(token_addr: address, token_quantity: uint256(token)): 81 | pass 82 | """ 83 | 84 | assert get_contract_with_gas_estimation(code) 85 | 86 | 87 | def test_ms(get_contract_with_gas_estimation): 88 | code = """ 89 | units: { 90 | m: "Meter", 91 | s: "Second" 92 | } 93 | 94 | 95 | @public 96 | def velocity(d: decimal(m), t: decimal(s)) -> decimal(m/s): 97 | return d / t 98 | """ 99 | c = get_contract_with_gas_estimation(code) 100 | 101 | assert c.velocity(15, 10) == Decimal('1.5') 102 | assert c.velocity(12, 4) == Decimal('3') 103 | -------------------------------------------------------------------------------- /tests/parser/types/test_node_types.py: -------------------------------------------------------------------------------- 1 | from pytest import raises 2 | 3 | from vyper.types import ( 4 | BaseType, 5 | ByteArrayType, 6 | ListType, 7 | MappingType, 8 | NullType, 9 | StructType, 10 | TupleType, 11 | canonicalize_type, 12 | get_size_of_type, 13 | ) 14 | 15 | 16 | def test_null_type(): 17 | node1 = NullType() 18 | node2 = NullType() 19 | 20 | assert node1 == node2 21 | 22 | 23 | def test_bytearray_node_type(): 24 | 25 | node1 = ByteArrayType(12) 26 | node2 = ByteArrayType(12) 27 | 28 | assert node1 == node2 29 | 30 | node3 = ByteArrayType(13) 31 | node4 = BaseType('int128') 32 | 33 | assert node1 != node3 34 | assert node1 != node4 35 | 36 | 37 | def test_mapping_node_types(): 38 | 39 | with raises(Exception): 40 | MappingType(int, int) 41 | 42 | node1 = MappingType(BaseType('int128'), BaseType('int128')) 43 | node2 = MappingType(BaseType('int128'), BaseType('int128')) 44 | assert node1 == node2 45 | assert str(node1) == "int128[int128]" 46 | 47 | 48 | def test_tuple_node_types(): 49 | node1 = TupleType([BaseType('int128'), BaseType('decimal')]) 50 | node2 = TupleType([BaseType('int128'), BaseType('decimal')]) 51 | 52 | assert node1 == node2 53 | assert str(node1) == "(int128, decimal)" 54 | 55 | 56 | def test_canonicalize_type(): 57 | # Non-basetype not allowed 58 | with raises(Exception): 59 | canonicalize_type(int) 60 | # List of byte arrays not allowed 61 | a = ListType(ByteArrayType(12), 2) 62 | with raises(Exception): 63 | canonicalize_type(a) 64 | # Test ABI format of multiple args. 65 | c = TupleType([BaseType('int128'), BaseType('address')]) 66 | assert canonicalize_type(c) == "(int128,address)" 67 | 68 | 69 | def test_get_size_of_type(): 70 | assert get_size_of_type(BaseType('int128')) == 1 71 | assert get_size_of_type(ByteArrayType(12)) == 3 72 | assert get_size_of_type(ByteArrayType(33)) == 4 73 | assert get_size_of_type(ListType(BaseType('int128'), 10)) == 10 74 | 75 | _tuple = TupleType([BaseType('int128'), BaseType('decimal')]) 76 | assert get_size_of_type(_tuple) == 2 77 | 78 | _struct = StructType({ 79 | 'a': BaseType('int128'), 80 | 'b': BaseType('decimal') 81 | }) 82 | assert get_size_of_type(_struct) == 2 83 | 84 | # Don't allow unknow types. 85 | with raises(Exception): 86 | get_size_of_type(int) 87 | 88 | # Maps are not supported for function arguments or outputs 89 | with raises(Exception): 90 | get_size_of_type(MappingType(BaseType('int128'), BaseType('int128'))) 91 | -------------------------------------------------------------------------------- /tests/parser/types/test_string_literal.py: -------------------------------------------------------------------------------- 1 | def test_string_literal_code(get_contract_with_gas_estimation): 2 | string_literal_code = """ 3 | @public 4 | def foo() -> bytes[5]: 5 | return "horse" 6 | 7 | @public 8 | def bar() -> bytes[10]: 9 | return concat("b", "a", "d", "m", "i", "", "nton") 10 | 11 | @public 12 | def baz() -> bytes[40]: 13 | return concat("0123456789012345678901234567890", "12") 14 | 15 | @public 16 | def baz2() -> bytes[40]: 17 | return concat("01234567890123456789012345678901", "12") 18 | 19 | @public 20 | def baz3() -> bytes[40]: 21 | return concat("0123456789012345678901234567890", "1") 22 | 23 | @public 24 | def baz4() -> bytes[100]: 25 | return concat("01234567890123456789012345678901234567890123456789", 26 | "01234567890123456789012345678901234567890123456789") 27 | """ 28 | 29 | c = get_contract_with_gas_estimation(string_literal_code) 30 | assert c.foo() == b"horse" 31 | assert c.bar() == b"badminton" 32 | assert c.baz() == b"012345678901234567890123456789012" 33 | assert c.baz2() == b"0123456789012345678901234567890112" 34 | assert c.baz3() == b"01234567890123456789012345678901" 35 | assert c.baz4() == b"0123456789" * 10 36 | 37 | print("Passed string literal test") 38 | 39 | 40 | def test_string_literal_splicing_fuzz(get_contract_with_gas_estimation): 41 | for i in range(95, 96, 97): 42 | kode = """ 43 | moo: bytes[100] 44 | 45 | @public 46 | def foo(s: int128, L: int128) -> bytes[100]: 47 | x: int128 = 27 48 | r: bytes[100] = slice("%s", start=s, len=L) 49 | y: int128 = 37 50 | if x * y == 999: 51 | return r 52 | 53 | @public 54 | def bar(s: int128, L: int128) -> bytes[100]: 55 | self.moo = "%s" 56 | x: int128 = 27 57 | r: bytes[100] = slice(self.moo, start=s, len=L) 58 | y: int128 = 37 59 | if x * y == 999: 60 | return r 61 | 62 | @public 63 | def baz(s: int128, L: int128) -> bytes[100]: 64 | x: int128 = 27 65 | self.moo = slice("%s", start=s, len=L) 66 | y: int128 = 37 67 | if x * y == 999: 68 | return self.moo 69 | """ % (("c" * i), ("c" * i), ("c" * i)) 70 | 71 | c = get_contract_with_gas_estimation(kode) 72 | for e in range(63, 64, 65): 73 | for _s in range(31, 32, 33): 74 | o1 = c.foo(_s, e - _s) 75 | o2 = c.bar(_s, e - _s) 76 | o3 = c.baz(_s, e - _s) 77 | assert o1 == o2 == o3 == b"c" * (e - _s), (i, _s, e - _s, o1, o2, o3) 78 | 79 | print("Passed string literal splicing fuzz-test") 80 | -------------------------------------------------------------------------------- /tests/parser/types/test_variable_naming.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from vyper import compiler 5 | from vyper.exceptions import FunctionDeclarationException 6 | 7 | fail_list = [ 8 | """ 9 | @public 10 | def foo(max: int128) -> int128: 11 | return max 12 | """, 13 | """ 14 | @public 15 | def foo(len: int128, sha3: int128) -> int128: 16 | return len+sha3 17 | """ 18 | ] 19 | 20 | 21 | @pytest.mark.parametrize('bad_code', fail_list) 22 | def test_variable_naming_fail(bad_code): 23 | 24 | with raises(FunctionDeclarationException): 25 | compiler.compile(bad_code) 26 | -------------------------------------------------------------------------------- /tests/parser/types/value/test_as_wei_value.py: -------------------------------------------------------------------------------- 1 | def test_test_wei(get_contract_with_gas_estimation): 2 | test_wei = """ 3 | @public 4 | def return_2_finney() -> wei_value: 5 | return as_wei_value(2, "finney") 6 | 7 | @public 8 | def return_3_finney() -> wei_value: 9 | return as_wei_value(2 + 1, "finney") 10 | 11 | @public 12 | def return_2p5_ether() -> wei_value: 13 | return as_wei_value(2.5, "ether") 14 | 15 | @public 16 | def return_3p5_ether() -> wei_value: 17 | return as_wei_value(2.5 + 1.0, "ether") 18 | 19 | @public 20 | def return_2pow64_wei() -> wei_value: 21 | return as_wei_value(18446744.073709551616, "szabo") 22 | """ 23 | 24 | c = get_contract_with_gas_estimation(test_wei) 25 | 26 | assert c.return_2_finney() == 2 * 10**15 27 | assert c.return_3_finney() == 3 * 10**15, c.return_3_finney() 28 | assert c.return_2p5_ether() == 2.5 * 10**18 29 | assert c.return_3p5_ether() == 3.5 * 10**18 30 | assert c.return_2pow64_wei() == 2**64 31 | 32 | print("Passed wei value literals test") 33 | -------------------------------------------------------------------------------- /vyper/__init__.py: -------------------------------------------------------------------------------- 1 | import sys as _sys 2 | import pkg_resources as _pkg_resources 3 | 4 | 5 | if (_sys.version_info.major, _sys.version_info.minor) < (3, 6): 6 | # Can't be tested, as our test harness is using python3.6. 7 | raise Exception("Requires python3.6+") # pragma: no cover 8 | 9 | 10 | try: 11 | __version__ = _pkg_resources.get_distribution('vyper').version 12 | except _pkg_resources.DistributionNotFound: 13 | __version__ = '0.0.0development' 14 | -------------------------------------------------------------------------------- /vyper/compiler.py: -------------------------------------------------------------------------------- 1 | from vyper.parser import parser 2 | from vyper import compile_lll 3 | from vyper import optimizer 4 | 5 | 6 | def compile(code, *args, **kwargs): 7 | lll = optimizer.optimize(parser.parse_tree_to_lll(parser.parse(code), code, runtime_only=kwargs.get('bytecode_runtime', False))) 8 | asm = compile_lll.compile_to_assembly(lll) 9 | 10 | def find_nested_opcode(asm_list, key): 11 | if key in asm_list: 12 | return True 13 | else: 14 | sublists = [sub for sub in asm_list if isinstance(sub, list)] 15 | return any([find_nested_opcode(x, key) for x in sublists]) 16 | 17 | if find_nested_opcode(asm, 'DEBUG'): 18 | print('Please note this code contains DEBUG opcode.') 19 | print('This will only work in a support EVM. This FAIL on any other nodes.') 20 | 21 | c, line_number_map = compile_lll.assembly_to_evm(asm) 22 | return c 23 | 24 | 25 | def gas_estimate(origcode, *args, **kwargs): 26 | o = {} 27 | code = optimizer.optimize(parser.parse_to_lll(origcode)) 28 | 29 | # Extract the stuff inside the LLL bracket 30 | if code.value == 'seq': 31 | if len(code.args) > 0 and code.args[-1].value == 'return': 32 | code = code.args[-1].args[1].args[0] 33 | 34 | assert code.value == 'seq' 35 | for arg in code.args: 36 | if hasattr(arg, 'func_name'): 37 | o[arg.func_name] = arg.total_gas 38 | return o 39 | 40 | 41 | def mk_full_signature(code, *args, **kwargs): 42 | abi = parser.mk_full_signature(parser.parse(code)) 43 | # Add gas estimates for each function to ABI 44 | gas_estimates = gas_estimate(code) 45 | for idx, func in enumerate(abi): 46 | func_name = func['name'].split('(')[0] 47 | # Skip __init__, has no estimate 48 | if func_name in gas_estimates and func_name != '__init__': 49 | abi[idx]['gas'] = gas_estimates[func_name] 50 | return abi 51 | -------------------------------------------------------------------------------- /vyper/exceptions.py: -------------------------------------------------------------------------------- 1 | # Attempts to display the line and column of violating code. 2 | class ParserException(Exception): 3 | def __init__(self, message='Error Message not found.', item=None): 4 | self.message = message 5 | self.lineno = None 6 | self.col_offset = None 7 | 8 | if isinstance(item, tuple): # is a position. 9 | self.lineno, self.col_offset = item 10 | elif item and hasattr(item, 'lineno'): 11 | self.set_err_pos(item.lineno, item.col_offset) 12 | if hasattr(item, 'source_code'): 13 | self.source_code = item.source_code.splitlines() 14 | 15 | def set_err_pos(self, lineno, col_offset): 16 | if not self.lineno: 17 | self.lineno = lineno 18 | 19 | if not self.col_offset: 20 | self.col_offset = col_offset 21 | 22 | def __str__(self): 23 | output = self.message 24 | 25 | if self.lineno and hasattr(self, 'source_code'): 26 | 27 | output = 'line %d: %s\n%s' % ( 28 | self.lineno, 29 | output, 30 | self.source_code[self.lineno - 1] 31 | ) 32 | 33 | if self.col_offset: 34 | col = '-' * self.col_offset + '^' 35 | output += '\n' + col 36 | 37 | elif self.lineno is not None and self.col_offset is not None: 38 | output = 'line %d:%d %s' % ( 39 | self.lineno, 40 | self.col_offset, 41 | output 42 | ) 43 | 44 | return output 45 | 46 | 47 | class VariableDeclarationException(ParserException): 48 | pass 49 | 50 | 51 | class StructureException(ParserException): 52 | pass 53 | 54 | 55 | class ConstancyViolationException(ParserException): 56 | pass 57 | 58 | 59 | class NonPayableViolationException(ParserException): 60 | pass 61 | 62 | 63 | class InvalidLiteralException(ParserException): 64 | pass 65 | 66 | 67 | class InvalidTypeException(ParserException): 68 | pass 69 | 70 | 71 | class TypeMismatchException(ParserException): 72 | pass 73 | 74 | 75 | class FunctionDeclarationException(ParserException): 76 | pass 77 | 78 | 79 | class EventDeclarationException(ParserException): 80 | pass 81 | -------------------------------------------------------------------------------- /vyper/functions/__init__.py: -------------------------------------------------------------------------------- 1 | from .functions import * # noqa: F401,F403 2 | -------------------------------------------------------------------------------- /vyper/parser/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/vyper/parser/__init__.py -------------------------------------------------------------------------------- /vyper/parser/pre_parser.py: -------------------------------------------------------------------------------- 1 | import io 2 | import re 3 | from tokenize import ( 4 | COMMENT, 5 | NAME, 6 | OP, 7 | TokenError, 8 | TokenInfo, 9 | tokenize, 10 | untokenize, 11 | ) 12 | from vyper.exceptions import StructureException 13 | from vyper import __version__ 14 | 15 | 16 | def _parser_version_str(version_str): 17 | version_regex = re.compile(r'^(\d+\.)?(\d+\.)?(\w*)$') 18 | if None in version_regex.match(version_str).groups(): 19 | raise Exception('Could not parse given version: %s' % version_str) 20 | return version_regex.match(version_str).groups() 21 | 22 | 23 | # Do a version check. 24 | def parse_version_pragma(version_str): 25 | version_arr = version_str.split('@version') 26 | 27 | file_version = version_arr[1].strip() 28 | file_major, file_minor, file_patch = _parser_version_str(file_version) 29 | compiler_major, compiler_minor, compiler_patch = _parser_version_str(__version__) 30 | 31 | if (file_major, file_minor) != (compiler_major, compiler_minor): 32 | raise Exception('Given version "{}" is not compatible with the compiler ({}): '.format( 33 | file_version, __version__ 34 | )) 35 | 36 | 37 | # Minor pre-parser checks. 38 | def pre_parse(code): 39 | result = [] 40 | 41 | try: 42 | g = tokenize(io.BytesIO(code.encode('utf-8')).readline) 43 | for token in g: 44 | # Alias contract definition to class definition. 45 | if token.type == COMMENT and "@version" in token.string: 46 | parse_version_pragma(token.string[1:]) 47 | if (token.type, token.string, token.start[1]) == (NAME, "contract", 0): 48 | token = TokenInfo(token.type, "class", token.start, token.end, token.line) 49 | # Prevent semi-colon line statements. 50 | elif (token.type, token.string) == (OP, ";"): 51 | raise StructureException("Semi-colon statements not allowed.", token.start) 52 | 53 | result.append(token) 54 | except TokenError as e: 55 | raise StructureException(e.args[0], e.args[1]) from e 56 | 57 | return untokenize(result).decode('utf-8') 58 | -------------------------------------------------------------------------------- /vyper/parser/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 is '\n': # comment ends at the end of a line 19 | in_comment = False 20 | continue 21 | if char is ';': # start of comment 22 | in_comment = True 23 | continue 24 | if char is '(' and not in_str: 25 | sexp.append([]) 26 | elif char is ')' 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 is '\"': 37 | in_str = not in_str 38 | else: 39 | word += char 40 | return sexp[0] 41 | -------------------------------------------------------------------------------- /vyper/premade_contracts.py: -------------------------------------------------------------------------------- 1 | import ast 2 | 3 | erc20 = """ 4 | class ERC20(): 5 | def name() -> bytes32: constant 6 | def symbol() -> bytes32: constant 7 | def decimals() -> uint256: constant 8 | def balanceOf(_owner: address) -> uint256: constant 9 | def totalSupply() -> uint256: constant 10 | def transfer(_to: address, _amount: uint256) -> bool: modifying 11 | def transferFrom(_from: address, _to: address, _value: uint256) -> bool: modifying 12 | def approve(_spender: address, _amount: uint256) -> bool: modifying 13 | def allowance(_owner: address, _spender: address) -> uint256: modifying 14 | """ 15 | 16 | 17 | def prepare_code(code): 18 | return ast.parse(code).body[0] 19 | 20 | 21 | premade_contracts = { 22 | "ERC20": prepare_code(erc20) 23 | } 24 | -------------------------------------------------------------------------------- /vyper/server.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/vyper/server.py -------------------------------------------------------------------------------- /vyper/signatures/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IDouble/vyper/c756c02f41d8c12ee5fef49c691e25d46ee35550/vyper/signatures/__init__.py -------------------------------------------------------------------------------- /vyper/types/__init__.py: -------------------------------------------------------------------------------- 1 | from .types import * # noqa F401, F403 2 | --------------------------------------------------------------------------------