Numbers
SmartPy has several types for integers:
sp.natfor non-negative integers (zero and above), known as natural numbers or natssp.intfor all integerssp.mutezfor non-negative amounts of micro-tez or mutez, which is one-millionth of a tez, the token of the Tezos blockchain
The types for integers and nats are not compatible with sp.mutez, which means that you can't compare integers and nats with sp.mutez types or use mathematical operations that combine them. However, you can use functions in the standard libraries to convert between nat and mutez.
SmartPy does not support floating-point numbers because Tezos does not.
Integers and natural numbers
A literal integer such as 2 is either of type sp.nat or sp.int, depending on how it is used. To be explicit about the type, you can 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:
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, adding an integer to a nat is invalid, as in sp.nat(2) + sp.int(3).
To manipulate different types, SmartPy provides the functions sp.add, sp.sub, and sp.mul, as in this example:
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.edivperforms Euclidean division, which returns the quotient and the remainder within ansp.optiontype. Note that the quotient type depends on the types of the arguments.If both of the arguments are nats, the function returns an option with a nat for the quotient and a nat for the remainder, as in this example:
smartpyassert sp.ediv(sp.nat(14), sp.nat(3)) == sp.Some( (sp.nat(4), sp.nat(2)) ) # 14 == 4 * 3 + 2In any other combination of integers and nats,
sp.edivreturns an option with an integer for the quotient and a nat for the remainder, as in these examples:smartpyassert sp.ediv(sp.int(-14), sp.nat(3)) == sp.Some( (sp.int(-5), sp.nat(1)) ) # -14 == -5 * 3 + 1 assert sp.ediv(sp.nat(14), sp.int(-3)) == sp.Some( (sp.int(-4), sp.nat(2)) ) # 14 == -4 * -3 + 2 assert sp.ediv(sp.int(-14), sp.int(-3)) == sp.Some( (sp.int(5), sp.nat(1)) ) # -14 == 5 * -3 + 1If you try to divide by zero, the option type contains
None, as in this example:smartpyresult_opt = sp.ediv(sp.nat(14), 0) match result_opt: case Some(result): (quotient, remainder) = result sp.trace(quotient) sp.trace(remainder) case None: sp.trace("Division by zero")If the option type contains
Some, thensp.ediv(a, b) = sp.Some(q, r), whereq(the quotient) andr(the remainder) are the unique integers such thata == q * b + rand both0 <= randr < b.
To get only the quotient or remainder of two integers or two nats, you can use a / b and sp.mod(a, b), respectively. In either case, dividing by zero causes a Division_by_zero.
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
You can compare two integers of the same type (either sp.nat or sp.int) with the operators ==, !=, <, <=, >, >=. The result is of type sp.bool. For example, 2 == 3 is False.
Conversions
- sp.to_int(x: sp.nat) → sp.int
The function
sp.to_intconverts ansp.natto ansp.int. For examplesp.to_int(sp.nat(2)) == sp.to_int(2), or (thanks to type inference)sp.to_int(2) == 2.
- sp.is_nat(a: sp.int) → sp.option[sp.nat]
The function
sp.is_natconverts ansp.intto ansp.option[sp.nat]:- If a variable
ais greater than or equal to zero,sp.is_nat(a)returnssp.Some(b), wheresp.to_int(b) == a - If a variable
ais less than zero,sp.is_nat(a)returnsNone
For example:
smartpyassert sp.is_nat(2) == sp.Some(2) assert sp.is_nat(-2) == None- If a variable
- sp.as_nat(x: sp.int) → sp.nat
The function
sp.as_natperforms the same conversion assp.is_nat, but instead of returning an option, it raises an error on negative numbers. Thussp.as_nat(2) == 2, whereassp.as_nat(-2)yields an error.
Bitwise arithmetic
Bitwise and, or and xor operations are available as &, | and ^ on sp.nat:
assert 42 & 1 == 0
assert 42 | 1 == 43
assert 42 ^ 1 == 43Furthermore, ~x computes the two's complement of x (of type sp.int):
assert ~100 == -101Shifting
Left and right shifts are also available as << and >> on sp.nat:
assert 42 << 1 == 84
assert 42 >> 1 == 21Token amounts
The type sp.mutez represents micro-tez, or one-millionth of one tez, so sp.mutez(42) denotes 42 micro-tez or 0.000042 tez.
As shorthand, you can use sp.tez() to create sp.mutez types. For example, sp.tez(a) is equivalent to sp.mutez(a * 1_000_000).
You can add and subtract mutez values with the + and - operators but you cannot multiply them directly. Negative results raise errors. For example, sp.mutez(5) - sp.mutez(2) == sp.mutez(3), but sp.mutez(5) - sp.mutez(10) raises an error.
- sp.split_tokens(amount: sp.mutez, quantity: sp.nat, division: sp.nat) → sp.mutez
The
sp.split_tokensfunction helps multiply and divide tokens. It takes threesp.mutezparameters and calculates the valuea * b / c. Its result is insp.mutez.This function enables the computation of mutez percentages. This example calculates 5% of 200 mutez:
smartpysp.split_tokens(sp.mutez(200), 5, 100) == sp.mutez(10) # 5% of 200 mutezThis function rounds the result to the closest whole mutez or
sp.mutez(0)if the result is closer to zero.