Structure of a Contract

Contracts in Vyper are contained within files, with each file being one smart-contract. Files in Vyper are similar to classes in object-oriented languages. Each file can contain declarations of State Variables, Functions, and structure-structs-types.

State Variables

State variables are values which are permanently stored in contract storage.

storedData: int128

See the Types section for valid state variable types and visibility-and-getters for possible choices for visibility.


Functions are the executable units of code within a contract.

def bid(): // Function
  // ...

Function-calls can happen internally or externally and have different levels of visibility (visibility-and-getters) towards other contracts. Functions must be decorated with either @public or @private.

Default function

A contract can also have a default function, which is executed on a call to the contract if no other functions match the given function identifier (or if none was supplied at all, such as through someone sending it Eth). It is the same construct as fallback functions in Solidity.

This function is always named __default__ and must be annotated with @public. It cannot have arguments and cannot return anything.

If the function is annotated as @payable, this function is executed whenever the contract is sent Ether (without data). This is why the default function cannot accept arguments and return values - it is a design decision of Ethereum to make no differentiation between sending ether to a contract or a user address.


Payment: event({amount: int128, from: indexed(address)})

def __default__():
    log.Payment(msg.value, msg.sender)


Just as in Solidity, Vyper generates a default function if one isn’t found, in the form of a REVERT call. Note that this still generates an exception and thus will not succeed in receiving funds.

Ethereum specifies that the operations will be rolled back if the contract runs out of gas in execution. send calls to the contract come with a free stipend of 2300 gas, which does not leave much room to perform other operations except basic logging. However, if the sender includes a higher gas amount through a call instead of send, then more complex functionality can be run.

It is considered a best practice to ensure your payable default function is compatible with this stipend. The following operations will consume more than 2300 gas:

  • Writing to storage
  • Creating a contract
  • Calling an external function which consumes a large amount of gas
  • Sending Ether

Lastly, although the default function receives no arguments, it can still access the msg global, including:

  • the address of who is interacting with the contract (msg.sender)
  • the amount of ETH sent (msg.value)
  • the gas provided (msg.gas).


Events may be logged in specially indexed data structures that allow clients, including light clients, to efficiently search for them.

Payment: event({amount: int128, arg2: indexed(address)})

total_paid: int128

def pay():
    self.total_paid += msg.value
    log.Payment(msg.value, msg.sender)

Events must be declared before global declarations and function definitions.