Literals and units
Integers
42 (* an integer literal: its type comes from context *)
-42 (* an int *)
1_000_000 (* underscores separate digits *)
0xff (* hexadecimal *)An integer literal takes the type its context expects: a binding's annotation, an assignment's target, a parameter, or a return type. It must fit that type. const x : uint8 := 300; is a compile error:
type Tiny is uint8;
storage is record {
n : uint;
}
external function go() is {
const x : Tiny := 300;
skip
}literal 300 does not fit type `Tiny`With no context, an integer literal is a uint. In arithmetic and comparisons, a literal takes the type of the other side, so level > 3 and level + 1 work for a uint8.
Ether units
wei, gwei, and eth suffixes produce values of type wei:
1wei (* 1 *)
20gwei (* 20 * 10^9 *)
1eth (* 10^18 *)
1eth + 500gweiTime units
seconds, minutes, hours, and days produce durations. A duration adds to a timestamp and is also usable as a uint number of seconds:
import "std/evm";
storage is record {
deadline : timestamp;
period : uint;
}
external function start() is {
storage.deadline := Evm.blockTimestamp() + 1days + 12hours;
storage.period := 30minutes;
}Hex literals
A 0x... literal can be an integer, an address, a bytesN, or bytes, depending on context. A bytesN literal is written at its full width, two digits per byte, and an address literal at 40 digits: as a bytes32, 0x11 is an error. Zero is the one exception, since it has no alignment to get wrong. To make a number a bytesN or address, convert it: bytes32(0x11) is 0x00…0011, and address(0x01) is 0x00…0001. As bytes, a literal is exactly the bytes written, leading zeros included, so its digits must come in pairs: 0x0001 is two bytes, and 0x123 is an error. A bytes literal can be any length; one of more than 64 digits can only be bytes, since no other type holds more than a word.
storage is record {
selector : bytes4;
blob : bytes;
owner : address;
mask : uint;
}
external function set() is {
storage.selector := 0xa9059cbb;
storage.blob := 0x616263;
storage.owner := 0x00000000000000000000000000000000000000ab;
storage.mask := 0xff;
}Strings
String literals are double-quoted and cannot span lines. A backslash starts an escape:
| Escape | Meaning |
|---|---|
\n, \t, \r, \0 | newline, tab, carriage return, zero byte |
\\, \", \' | backslash, double quote, single quote |
\xHH | the byte HH, from 00 to 7f |
\u{H…} | a Unicode code point of 1 to 6 hex digits, stored as UTF-8 |
Any other escape is an error. For bytes above 7f that aren't UTF-8, use a hex literal.
"Hello, world!"
"say \"hi\""
"\x19Ethereum Signed Message:\n32"Booleans and unit
true and false are the two bool values. Unit is the single value of type unit.
Aggregate literals
| Literal | Type |
|---|---|
{ amount = 1; to = who; } | a record, whose type comes from context |
(1, who) | a tuple, (uint, address) |
[1, 2, 3] | a list, list(uint) or list(uint, 3) |
Some(x), None | an option |
type Payment is record {
to : address;
amount : uint;
}
storage is record {
payments : map(uint, Payment);
}
external function pay(const id : uint; const to : address) is {
const p : Payment := { to = to; amount = 5; };
storage.payments[id] := p;
}
external pure function pair() : (uint, bool) is
(1, true)
external pure function sum3() : uint is {
const xs : list(uint, 3) := [1, 2, 3];
} with xs[0] + xs[1] + xs[2]
