Solidity 0.6.12 & Vyper 0.2.3 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?
- Latest
- Solidity 0.5.14 & Vyper Beta 14
- Solidity 0.6.0 & Vyper Beta 16
- Solidity 0.6.10 & Vyper Beta 17
- Solidity 0.6.6 & Vyper Beta 17
- Solidity 0.6.12 & Vyper 0.2.3 (this page)
Cheat sheet
Feature | Solidity | Vyper |
---|---|---|
Version |
$ solc --version Version: 0.6.12 |
$ vyper --version 0.2.3 |
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\'' |
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) |
address.call.value().gas()() |
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 finney 1 szabo 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 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 |