Vyper is an experimental, contract-oriented programming language which targets the Ethereum Virtual Machine (EVM). Vyper strives to simplify the human readable code and in doing so provide superior auditability. One of the principles and goals of Vyper is to make it near impossible (very difficult) for developers, who use Vyper, to write misleading code. This is done in a number of ways, which we will describe below.
This section is added to be used as reference for those considering moving to development with Vyper Main examples of what Vyper does NOT include, and the reason for those:
-
Modifiers - e.g. in Solidity you can do function foo() mod1 { … }, where mod1 can be defined elsewhere in the code to include a check that is done before execution, a check that is done after execution, some state changes, or possibly other things. Vyper does not have this, because it makes it too easy to write misleading code. mod1 just looks too innocuous for something that could add arbitrary pre-conditions, post-conditions or state changes. Also, it encourages people to write code where the execution jumps around the file, harming auditability. The usual use case for a modifier is something that performs a single check before execution of a program; our recommendation is to simply inline these checks as asserts.
-
Class inheritance - requires people to jump between multiple files to understand what a program is doing, and requires people to understand the rules of precedence in case of conflicts (which class’s function X is the one that’s actually used?). Hence, it makes code too complicated to understand.
-
Inline assembly - adding inline assembly would make it no longer possible to Ctrl+F for a variable name to find all instances where that variable is read or modified.
-
Function overloading - This can cause lots of confusion on which function is called at any given time. Thus it’s easier to write missleading code (foo("hello") logs "hello" but foo("hello", "world") steals you funds). Another problem with function overloading is that it makes the code much harder to search through as you have to keep track on which call refers to which function.
- Variable typecasting
-
Typecasting is a mechanism which allows programmers to convert a variable from one data type to another data type.
- Pre-conditions and post-conditions
-
pre-conditions as well as post-conditions and state changes are handled explicitly, Whilst this does produce redundant code it allows for maximal readability, The process of writing a function should include the following three reflections
-
Condition - What is the current state/condition of the state variables
-
Effects - What effects will the following code have on the state variables once executed
-
Interaction - The actual execution of logic now that the first two steps have been exhaustively dealt with
-
Decorators like @public @constant @payable are declared at the start of each function.
- Public decorator
-
The public decorator makes the function both visible and executable publicly. For example the Ethereum wallet will even display the public functions when viewing the contract.
- Constant decorator
-
Functions which start with the constant decorator are not allowed to change state variables, as part of their execution. If fact the compiler will reject the entire program (with an appropriate warning) if the function tries to change a state variable. If the function is meant to change a state variable then the constant decorator is not used at the start of the function.
- Payable decorator
-
Only functions which declare the @payable decorator at the start will be allowed to transfer value.
Vyper implements the logic of decorators explicitly. For example, the Vyper code compilation process will fail if a function is preceeded with both a payable decorator and a constant decorator. Of course this makes sense because a constant function (one which only reads from the global state) should never need to partake in a transfer of value. Also, each Vyper function must be preceeded with either the @public or the @private decorator to avoid compilation failure. Preceeding a Vyper function with both a @public decorator and a @private decorator will also result in a compilation failure.
Vyper has its own online code editor and compiler at the following URL < https://vyper.online >. This Vyper online compiler allows you to write and then compile your smart contracts into Bytecode, ABI and LLL using only your web browser. The Vyper online compiler has a variety of pre written smart contracts for your convenience. These include a simple open auction, safe remote purchases, ERC20 token and more.
Each Vyper contract is saved in a single file with the .v.py extension. Once installed Vyper can compile and provide bytecode by running the following command
vyper ~/hello_world.v.py
The human readable ABI code (in JSON format) can be obtained by then running the following command
vyper -f json ~/hello_world.v.py
smart contracts can write data to two places, ethereum’s global state trie or Ethereum’s chain data, while this is costly to store, read and modify data. These storage operations are a necessary component of most smart contracts.
- Global state
-
The state variables in a given smart contract are stored in Ethereum’s global state trie, a given smart contract can only store, read and modify data specifically in relation to that contract’s address (i.e. smart contracts can not read or write to other smart contracts).
TODO continue with more information about Global state in relation to Vyper
- Log
-
As previously mentioned, a smart contract can also write to Ethereum’s chain data through log events. While Vyper initially employed the __log__ syntax for declaring these events, an update has been made which brings Vyper’s event declaration more in line with Solidity’s original syntax. For example, Vyper’s declaration of an event called MyLog was originally MyLog: __log__({arg1: indexed(bytes ⇐ 3)}) Vyper’s syntax has now become MyLog: event({arg1: indexed(bytes ⇐ 3)}). It is important to note that the execution of the log event in Vyper was and still is as follows log.MyLog("123").
While smart contracts can write to the Ethereum’s chain data (through log events), smart contracts are unable to read the on-chain log events, which they created. Notwithstanding, one of the advantages of writing to Ethereum’s chain data via log events is that logs can be discovered and read, on the public chain, by light clients. For example, the logsBloom value in a mined block can indicate whether or not a log event was present. Once this has been established the log data can be obtained through the path of logs → data inside a given transaction receipt.
The name, symbol, total supply and decimals variables of ERC20 tokens are publicly available using Vyper.
The code for smart contracts is mainly written in high level languages like Solidity and now potentially Vyper. The compiler is responsible for taking the high level code and creating the lower level interpretation of the code, which is then able to be executed on the Ethereum Virtual Machine (EVM). The lowest representation which the compiler can distille the code to (prior to execution by the EVM) is opcodes. This being the case, each implementation of a high level language (like Vyper) is required to provide an appropriate compilation mechanism (a compiler) to allow (among other things) the high level code to be compiled into the universally predetermined and predefined EVM opcodes. A good example of this is Vyper’s implementation of Ethereum’s sharding opcodes.