Numbers
SmartPy has several types for integers:
sp.nat
for non-negative integers (zero and above), known as natural numbers or natssp.int
for all integerssp.mutez
for 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.ediv
performs Euclidean division, which returns the quotient and the remainder within ansp.option
type. 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 + 2
In any other combination of integers and nats,
sp.ediv
returns 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 + 1
If you try to divide by zero, the option type contains
None
, as in this example:smartpyresult_opt = sp.ediv(sp.nat(14), 0) with sp.match(result_opt): with sp.case.Some as result: (quotient, remainder) = result sp.trace(quotient) sp.trace(remainder) with 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 + r
and both0 <= r
andr < 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_int
converts ansp.nat
to 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_nat
converts ansp.int
to ansp.option[sp.nat]
:- If a variable
a
is greater than or equal to zero,sp.is_nat(a)
returnssp.Some(b)
, wheresp.to_int(b) == a
- If a variable
a
is 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_nat
performs 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 == 43
Furthermore, ~x
computes the two's complement of x
(of type sp.int
):
assert ~100 == -101
Shifting
Left and right shifts are also available as <<
and >>
on sp.nat
:
assert 42 << 1 == 84
assert 42 >> 1 == 21
Token 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_tokens
function helps multiply and divide tokens. It takes threesp.mutez
parameters 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 mutez
This function rounds the result to the closest whole mutez or
sp.mutez(0)
if the result is closer to zero.