Solidity & Vyper Cheat Sheet

This is a feature by feature reference guide to the two most popular programming languages on Ethereum.


Something missing? Check out the official Solidity reference or Vyper reference.

The content of our latest cheat sheets is open source and you are welcome to suggest changes at our GitHub repository.


Looking for a different version?



Cheat sheet


Feature Solidity Vyper
Version
$ solc --version
Version: 0.7.0
$ vyper --version
0.2.4
General notes on syntax

Solidity loosely borrows its syntax from Javascript and C

Vyper syntax is valid Python 3 syntax (but the opposite is not true)

Block delimiters
{ }
:  # Vyper uses Python's off-side rule
Statement separator
;
'\n' and :
End of line comment
// comment
# comment
Multiple line comment
/* multiple line
comment */
# Multiple line
# comment
Constant
uint constant TOTAL_SUPPLY = 10000000;
TOTAL_SUPPLY: constant(uint256) = 10000000
Assignment
v = 1;
v = 1
Parallel assignment
(x, y) = (0, 1);

Tuple to tuple assignment not supported

Swap
(x, y) = (y, x);

Compound assignment
-=, *=, /=, %=, |=, &=, ^=
-=, *=, /=, %=, |=, &=, ^=
Increment and decrement
i++, ++i, i--, --i
i += 1, i -= 1
Null

null doesn't exist in Solidity but any unitialized variables take a default value represented by 0 in memory

null doesn't exist in Vyper but any unitialized variables take a default value represented by 0 in memory

Set variable to default value
delete v // doesn't work with mappings
v = empty(uint256)
Null test
v == 0
v == 0
Conditional expression
x > 0 ? x : -x

Conditional expression not supported

Contract lifecycle
Feature Solidity Vyper
Contract creation
Contract c = new Contract(args);

Contract creation with funding
Contract c = new Contract{value: amount}(args);

Salted contract creation (CREATE2)
Contract c = new Contract{salt: salt}(args);

Create forwarder contract

contract: address = create_forwarder_to(other_contract, value)
Selfdestruct (Avoid)
selfdestruct(refundAddr)
selfdestruct(refund_addr)
Interfaces
Feature Solidity Vyper
Interfaces
interface HelloWorld {
    function hello() external pure;
    function world(int) external pure;
}
interface HelloWorld:
    def hello(): nonpayable
    def world(uint256): nonpayable
Interface type
interface HelloWorldWithEvent {
    event Event();
    function hello() external pure;
    function world(int) external pure;
}

contract Test {
    bytes4 public hello_world_with_event = type(HelloWorldWithEvent).interfaceId;
}

Operators
Feature Solidity Vyper
True and false
true false
True False
Falsehoods
false
False
Logical operators
&& || !
and or not
Relational operators
== != < > <= =>
== != < > <= =>
Min and max

max(x, y)
Arithmetic operators
+ - * / % ** unary-
+ - * / % ** unary-
Integer division
/
/
Bit operators
<< >> & | ^ ~
<< >> & | ^ ~
Binary & hex literals
uint x = 0x52
string memory s = hex"52"
a: address= 0x14d465376c051Cbcd80Aa2d35Fd5df9910f80543
b: Bytes[32]= b'\x01\x02\x03\x04\x05\x06... (32 bytes)
d: Bytes[1] = 0b00010001
Data structures
Feature Solidity Vyper
String type
string
String[N]  # N is a fixed number
Bytes type
bytes  // dynamic
bytes1, bytes2, ..., bytes32  // packed
bytes[N]  // N is a fixed number, unpacked
Bytes[N]  # N is a fixed number
String literal
"don't \"no\""
'don"t \'no\''
"don't \"no\""
'don"t \'no\''
Unicode literal
unicode"🍠"

String length
bytes(s).length
len(s)
String literal escapes
\<newline> (escapes an actual newline)
\\ (backslash)
\' (single quote)
\" (double quote)
\b (backspace)
\f (form feed)
\n (newline)
\r (carriage return)
\t (tab)
\v (vertical tab)
\xNN (hex escape)
\uNNNN (unicode escape)
\<newline> (escapes an actual newline)
\\ (backslash)
\' (single quote)
\" (double quote)
\a (bell)
\b (backspace)
\f (form feed)
\n (newline)
\r (carriage return)
\t (tab)
\v (vertical tab)
\ooo (octal escape)
\xNN (hex escape)
\uNNNN (unicode escape)
\uNNNNNNNN (unicode escape)
Are strings mutable?

Yes

Yes

Slice
abi.decode(_payload[:4], (bytes4))
// array slices only implemented for calldata arrays
slice(x, _start, _len)
String comparison
keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2))
keccak256(s1) == keccak256(s2)
String concatenation
abi.encodePacked(s1, s2)
concat(s1, s2)
Array literal
[1, 2, 3]
[1, 2, 3]
Length
a.length
len(a)
Empty test
a.length == 0

Lookup
a[0]
a[0]
Update
a[0] = 1;
a[0] = 1
Out of bounds access

Failing assertion

Failing assertion

Add new element
a.push(3);  # Dynamic arrays

Remove element
a.pop();  # Dynamic arrays

Struct
struct Pair {
    uint x;
    uint y;
}  // Creating a struct

Pair memory pair = Pair(2, 3);  // Instantiating a struct variable
require(pair.y > pair.x);  // Accessing elements
struct Pair:
    x: uint256
    y: uint256  # Creating a struct

pair: Pair = Pair({x: 2, y: 3})  # Instantiating a struct variable
assert pair.y > pair.x  # Accessing elements
Mapping size

Impossible to know

Impossible to know

Lookup
m[2]
m[2]
Update
m[2] = 1;
m[2] = 1
Missing key behaviour

A mapping has no concept of set keys, a mapping always refers to a hashed value that is the same for a given mapping and key

A mapping has no concept of set keys, a mapping always refers to a hashed value that is the same for a given mapping and key

Delete key
m[2] = 0;
m[2] = empty(uint256)
Immutable variables
uint immutable x; // have to be assigned in the constructor

Functions
Feature Solidity Vyper
Define function
function add2(uint x, uint y) public pure returns (uint) {
    return x + y;
}
@external
def add2(x: uint256, y: uint256) -> uint256:
    return x + y
Function argument storage location
function first(uint[] calldata x) public pure returns (uint) {
    // this function doesn't copy x to memory
    return x[0];
}

function first(uint[] memory x) public pure returns (uint) {
    // this function first copies x to memory
    return x[0];
}

Invoke function
add2(x, y)
add2(x, y)
External function calls
c.f{gas: 1000, value: 4 ether}()
c.f()
raw_call(address, data, outsize, gas, value, is_delegate_call)
Control flow
Feature Solidity Vyper
If statement
if (a > 2) {
    ...
else if (a == 0) {
    ...
} else {
    ...
}
if a > 2:
    ...
elif a == 0:
    ...
else:
    ...
For loop
for (uint i = 0; i < 3; i++) {
    ...
}
for i in range(3):
    ...
While loop
while (a > 0) {
    ...
}

Do-While loop
do {
    ...
} while (a > 0);

Return value
return x + y;
return x + y
Break
break;
break
Continue
continue;
continue
Assert
assert(x > y);
assert x > y
Require
require(x > y);

Revert
require(false, "revert reason")
raise "revert reason"
Exception handling
interface DataFeed { function getData(address token) external returns (uint value); }

contract FeedConsumer {
    DataFeed feed;
    uint errorCount;
    function rate(address token) public returns (uint value, bool success) {
        // Permanently disable the mechanism if there are
        // more than 10 errors.
        require(errorCount < 10);
        try feed.getData(token) returns (uint v) {
            return (v, true);
        } catch Error(string memory /*reason*/) {
            // This is executed in case
            // revert was called inside getData
            // and a reason string was provided.
            errorCount++;
            return (0, false);
        } catch (bytes memory /*lowLevelData*/) {
            // This is executed in case revert() was used
            // or there was a failing assertion, division
            // by zero, etc. inside getData.
            errorCount++;
            return (0, false);
        }
    }
}

Misc
Feature Solidity Vyper
Comments
NatSpec conventions for functions:

/// @author Mary A. Botanist
/// @notice Calculate tree age in years, rounded up, for live trees
/// @dev The Alexandr N. Tetearing algorithm could increase precision
/// @param rings The number of rings from dendrochronological sample
/// @return age in years, rounded up for partial years

Events:

/// The address `participant` just registered for the gathering.
event Registered(address participant);

Special inheritance syntax for contracts:

/// @inheritdoc OtherContract
def foo():
    """
    @author Mary A. Botanist
    @notice Calculate tree age in years, rounded up, for live trees
    @dev The Alexandr N. Tetearing algorithm could increase precision
    @param rings The number of rings from dendrochronological sample
    @return age in years, rounded up for partial years
    """
    ...
Payment with error on failure (Avoid for Solidity)
address.transfer()
send(address, value)
Payment with false on failure (Avoid for Solidity)
address.send()

Payment with gas forwarding (WARNING)

raw_call(address, data, outsize, gas, value, is_delegate_call)
Event logging
event Deposit(
    address indexed _from,
    bytes32 indexed _id,
    uint _value
);

emit Deposit(msg.sender, _id, msg.value);
event Deposit:
    _from: indexed(address)
    _id: indexed(bytes32)
    _value: uint256

log Deposit(msg.sender, _id, msg.value)
Units, global constants and type ranges
1 ether
1 wei
1 gwei
1 seconds
1 minutes
1 hours
1 days
1 weeks
1 years  // deprecated
type(uint).min
type(uint).max
type(int8).min
type(int8).max
...
ZERO_ADDRESS
as_wei_value(1, "finney")
as_wei_value(1, "szabo")
as_wei_value(1, "wei")
as_wei_value(1, "babbage")
as_wei_value(1, "shannon")
EMPTY_BYTES32
MAX_INT128
MIN_INT128
MAX_DECIMAL
MIN_DECIMAL
MAX_UINT256
ZERO_WEI
Block and transaction properties
blockhash(blockNumber)
block.coinbase
block.difficulty
block.gaslimit
block.number

block.timestamp
now  // alias for block.timestamp, deprecated
gasleft()
msg.data
msg.gas
msg.sender
msg.sig
msg.value
tx.gasprice
tx.origin
blockhash(blockNumber)
block.coinbase
block.difficulty

block.number
block.prevhash  # Same as blockhash(block.number - 1)
block.timestamp



msg.gas
msg.sender

msg.value

tx.origin