Types
SmartPy features a comprehensive type system that provides strong typing and type safety for smart contract development.
Primitive
SmartPy Type | Description | Documentation |
---|---|---|
sp.int | Arbitrary precision integer | Integers and Mutez |
sp.nat | Non-negative integer | Integers and Mutez |
sp.bool | Boolean type with values True or False | Booleans |
sp.string | String of characters | Strings and Bytes |
sp.bytes | Sequence of bytes | Strings and Bytes |
sp.timestamp | Timestamp value | Timestamps |
Tezos specific
SmartPy Type | Description | Documentation |
---|---|---|
sp.mutez | Micro-tez (unit of currency) | Integers and Mutez |
sp.address | Tezos address | Addresses |
sp.key | Public key | Keys and Signatures |
sp.key_hash | Hash of a public key | Keys and Signatures |
sp.signature | Cryptographic signature | Keys and Signatures |
sp.chain_id | Chain identifier | Addresses |
sp.operation | Tezos operation | Operations |
Cryptographic
SmartPy Type | Description | Documentation |
---|---|---|
sp.bls12_381_fr | BLS12-381 scalar field element | BLS12-381 |
sp.bls12_381_g1 | BLS12-381 G1 point | BLS12-381 |
sp.bls12_381_g2 | BLS12-381 G2 point | BLS12-381 |
Compound types
SmartPy Type | Description | Documentation |
---|---|---|
sp.pair[T1, T2] | Pair of values | Tuples |
sp.record(field1=T1, ...) | Named structure with fields | Records |
sp.option[T] | Optional value of type T or None | Options and Variants |
sp.variant(tag1=T1, ...) | Tagged union type | Options and Variants |
sp.list[T] | List of elements of type T | Lists, Sets, and Maps |
sp.set[T] | Collection of unique elements | Lists, Sets, and Maps |
sp.map[K, V] | Associative array mapping keys to values | Lists, Sets, and Maps |
sp.big_map[K, V] | Lazy map to store a lot of values | Lists, Sets, and Maps |
sp.lambda_(t1, t2, **effects) | Function from type A to type B | Lambdas |
sp.ticket[T] | Authenticated quantities issued by contracts or users | Tickets |
sp.contract[T] | Representation of a contract interface accepting values of type T | Contracts |
Type declaration
SmartPy uses Python type annotations for explicit type declarations:
def f(x: sp.int):
pass
A type can be defined using : type =
to be reused later (only at module level).
my_nat: type = sp.nat
def g(x: my_nat):
pass
Type inference
SmartPy infers types for most values:
x = 1 # Inferred as sp.int
y = sp.nat(1) # Explicitly building sp.nat
z = sp.cast(1, sp.nat) # Explicitly set to sp.nat
Type declaration vs conversion
SmartPy provides multiple ways to manipulate types:
Type declaration with constructors
Type constructors in SmartPy are used to explicitly declare a value of a specific type, not to convert between types:
# This DECLARES a nat value - it doesn't convert an int to a nat
# For example: sp.nat(sp.int(5)) isn't allowed
x = sp.nat(5)
# This also DECLARES a value of type list[sp.int]
my_list = [1, 2, 3] # Not a Python list being converted, but a SmartPy sp.list[sp.int]
Type annotation with sp.cast
sp.cast
is used to explicitly annotate the type of an expression, not to convert between types:
# This annotates {} as being a map[sp.address, sp.int]
# It does NOT convert a Python dict to a SmartPy map
x = sp.cast({}, sp.map[sp.address, sp.int])
# Similarly, this annotates 5 as a nat
y = sp.cast(5, sp.nat)
When to use type declaration
SmartPy must know the type of all variables to compile to Michelson. Type declaration is necessary in cases such as:
Empty collections - When initializing empty collections where the type cannot be inferred:
smartpyempty_map = sp.cast({}, sp.map[sp.string, sp.nat])
Explicit contract storage - When defining the expected structure of contract storage:
smartpy@sp.module def main(): t_storage: type = sp.record(counter=sp.nat) class Counter(sp.Contract): def __init__(self, init_value): self.data.counter = init_value # Ensure storage matches the declared type sp.cast(self.data, t_storage)
Layout specifications - To set specific field layouts for records:
pythont_param: type = sp.record( from_=sp.address, txs=sp.list[sp.record(to_=sp.address, amount=sp.nat)] ).layout(("from_", "txs"))
Common misconceptions
Not Type Conversion:
sp.cast
and type constructors do not change a value's type - they declare or annotate it.Not Python Types: SmartPy types are distinct from Python types. For example,
[1, 2, 3]
in SmartPy is asp.list[sp.int]
, not a Python list.
Type system features
Type inference
SmartPy infers the types of most expressions automatically:
x = 1 + 2 # x inferred as sp.int
y = 1 < 2 # y inferred as sp.bool
z = [1, 2, 3] # z inferred as sp.list[sp.int]
Generics
Many SmartPy container types support generic type parameters:
addresses: type = sp.set[sp.address]
balances: type = sp.map[sp.address, sp.mutez]
Type compatibility
SmartPy has a strict type system. Values must match their expected types exactly, with a few exceptions for numerical types:
def f(x: sp.nat):
pass
f(5) # 5 is inferred as sp.nat due to the function signature
# `f(-5)` would fails because -5 cannot be a nat
The SmartPy library provides conversion functions like sp.as_nat()
and sp.to_int()
when explicit type conversion is needed. These are not casts but actual conversion operations that check values and fail if the conversion is not possible.
For more detailed explanation, see casting