Skip to content
On this page

Integers and mutez

SmartPy has several types for integers: sp.nat for non-negative integers, sp.int for (all) integers, and sp.mutez for non-negative amounts of micro-Tez, the token of the Tezos blockchain.

sp.int and sp.nat

A literal integer such as 2 is either of type sp.nat or sp.int, depending on how it is used. In order to be explicit about the type, you can simply write sp.nat(2) or sp.int(2).

Basic arithmetic

The operators +, -, * and / perform addition, subtraction, multiplication, and division, respectively. They are homogeneous, meaning that both arguments must be of the same type (either both sp.nat or both sp.int).

The type of the result is the same as the arguments, except for -, which always returns an sp.int.

Examples:

smartpy
assert sp.nat(2) + sp.nat(3) == sp.nat(5)
assert sp.int(2) + sp.int(3) == sp.int(5)
assert sp.nat(2) - sp.nat(3) == sp.int(-1)
assert sp.int(2) - sp.int(3) == sp.int(-1)

The unary negation operator - can take either sp.nat or sp.int and always returns an sp.int. For example, - sp.nat(2) == sp.int(-2).

Mixing different types yields an error: for example sp.nat(2) + sp.int(3) is invalid. For heterogeneous arguments there are sp.add, sp.sub, sp.mul.

Example:

smartpy
a = sp.nat(2)
b = sp.int(3)
assert sp.add(a, b) == sp.int(5)

Division

sp.ediv(a: sp.nat, b: sp.nat) → sp.option[sp.pair[sp.nat, sp.nat]]
sp.ediv(a: sp.int, b: sp.nat) → sp.option[sp.pair[sp.int, sp.nat]]
sp.ediv(a: sp.nat, b: sp.int) → sp.option[sp.pair[sp.int, sp.nat]]
sp.ediv(a: sp.int, b: sp.int) → sp.option[sp.pair[sp.int, sp.nat]]

sp.ediv performs Euclidean division. Note that the result type depends on the types of the given arguments.

The option catches division by zero: sp.ediv(a, 0) == None. If b != 0, then sp.ediv(a, b) = sp.Some(q, r) where q (the quotient) and r (the remainder) are the unique integers such that a == q * b + r and both 0 <= r and r < b.

Example:

smartpy
assert sp.ediv( 14, 3) == sp.Some(( 4, 2))  #  14 ==  4 *  3 + 2
assert sp.ediv(-14, 3) == sp.Some((-5, 1))  # -14 == -5 *  3 + 1
assert sp.ediv( 14,-3) == sp.Some((-4, 2))  #  14 == -4 * -3 + 2
assert sp.ediv(-14,-3) == sp.Some(( 5, 1))  # -14 ==  5 * -3 + 1
(quotient, remainder) = sp.ediv(a, b).unwrap_some(error="Division by 0")

If a and b are of the same type quotient and remainder can be obtained as a / b and sp.mod(a, b), respectively. In both cases a Division_by_zero error is raised if b == 0.

WARNING

For negative denominators the result of division differs between SmartPy and Python. SmartPy follows the Michelson semantics, whereas Python rounds the quotient towards negative infinity (yielding negative remainders!). To avoid confusion between the two, the SmartPy syntax uses / and sp.mod instead of // and %.

Comparison

Two integers of the same type (either sp.nat or sp.int) can be compared with the operators ==, !=, <, <=, >, >=. The result is of type sp.bool. For example, 2 == 3 is False.

From sp.nat to sp.int

sp.to_int(x: sp.nat) → sp.int

To convert from sp.nat to sp.int, there is sp.to_int. For example sp.to_int(sp.nat(2)) == sp.to_int(2), or (thanks to type inference) sp.to_int(2) == 2.

From sp.int to sp.nat

sp.is_nat(a: sp.int) → sp.option[sp.nat]

sp.is_nat takes an sp.int and returns a value of type sp.option[sp.nat]. If a >= 0, then sp.is_nat(a) == sp.Some(b), where b is the unique sp.nat such that sp.to_int(b) == a (i.e. a and b represent the same integer). If a < 0, then sp.is_nat(a) == None. For example:

smartpy
assert sp.is_nat( 2) == sp.Some(2)
assert sp.is_nat(-2) == None
sp.as_nat(x: sp.int) → sp.nat

sp.as_nat performs the same conversion, but instead of returning an option raises an error on negative numbers. Thus sp.as_nat(2) == 2, whereas sp.as_nat(-2) yields an error.

Bitwise arithmetic

Bitwise and, or and xor operations are available as &, | and ^ on sp.nat:

smartpy
assert 42 & 1 == 0
assert 42 | 1 == 43
assert 42 ^ 1 == 43

Furthermore, ~x computes the two's complement of x (of type sp.int):

smartpy
assert ~100 == -101

Shifting

Left and right shifts are also available as << and >> on sp.nat:

smartpy
assert 42 << 1 == 84
assert 42 >> 1 == 21

Token amounts

Micro-Tez amounts are always prefixed by sp.mutez, so e.g. sp.mutez(42) denotes 42 micro-Tez, e.g. 0.000042 Tez. This expression is of type sp.mutez.

sp.tez(a) is equivalent to sp.mutez(a * 1_000_000).

Addition and subtraction on sp.mutez can be performed with + and -. If subtraction were to yield a negative value, an error is raised instead. Thus sp.mutez(5) - sp.mutez(2) == sp.mutez(3), whereas sp.mutez(5) - sp.mutez(10) yields an error.

sp.split_tokens(amount: sp.mutez, quantity: sp.nat, division: sp.nat) → sp.mutez

For combined multiplication and division on sp.mutez values there is sp.split_tokens(a, b, c), which calculates the value "a * b / c".

This enables the computation of mutez percentages, for example:

smartpy
sp.split_tokens(sp.mutez(200), 5, 100) == sp.mutez(10)  # 5% of 200 mutez