Typing โ
Type Inference โ
Just like in Python, most of the time there is no need to specify the type of an object in SmartPy. For a number of reasons (e.g., because SmartPy's target language, Michelson, requires types), each SmartPy expression does however need a type. Therefore SmartPy uses type inference in order to determine each expressions type.
In practice, this means that information about an expression is gathered according to its usage: for example, when somewhere in your contract you write self.data.xย ==ย "abc"
, SmartPy will automatically determine and remember that self.data.x
is a string.
Note that SmartPy types are distinct from Python types: self.data.xย ==ย "abc"
has the Python type sp.Expr
(simply because it is a SmartPy expression), whereas it has the SmartPy type sp.TBool
(see below).
While most of the time the user will not write many types explicitly it is beneficial to at least have a basic understanding of what they are. This also helps understanding error messages better.
Basic Types โ
nat โ
sp.TNat
is the type of non-negative integer values.
See Integers documentation.
Michelson natint โ
sp.TInt
is the type of signed integer values.
See Integers documentation.
Michelson intint or nat โ
sp.TIntOrNat
is the type of integer values when SmartPy doesn't know yet which type is applicable, either sp.TInt
or sp.TNat
.
See Integers documentation.
string โ
The type of string values.
The current version of Michelson restricts strings to be the printable subset of 7-bit ASCII
, namely characters with codes from within [32, 126] range, plus the following escape characters \n
, \\
, \"
. Unescaped line breaks (both \n
and \r
) cannot appear in a string.
"", '', "Hello World", 'Hello World'
See Strings documentation.
Michelson stringbool โ
The type of boolean values.
True, False
See Booleans documentation.
Michelson boolbytes โ
The type of serialized data.
Bytes are used for serializing data, in order to check signatures and compute hashes on them. They can also be used to incorporate data from the wild and untyped outside world.
sp.bytes("0x"), sp.bytes("0x00"), sp.bytes("0x0001"), sp.bytes("0xff"), etc.
See reference Strings and Bytes template.
See Bytes documentation.
Michelson bytesmutez โ
The type of tez amounts in SmartPy is sp.TMutez.
Mutez (micro-Tez) are internally represented by 64-bit signed integers. These are restricted to prevent creating a negative amount of mutez. Instructions are limited to prevent overflow and mixing them with other numerical types by mistake. They are also mandatorily checked for overflows.
sp.mutez(1000000)
# or
sp.tez(1)
See Mutez documentation.
Michelson muteztimestamp โ
A moment in time.
Literal timestamp is written either using RFC3339 notation in a string (readable), or as the number of seconds since Epoch in a natural (optimized).
sp.timestamp(1571761674)
See Timestamps documentation.
Michelson timestampaddress โ
An address of a contract or implicit account.
The address type merely gives the guarantee that the value has the form of a Tezos address, as opposed to contract that guarantees that the value is indeed a valid, existing account.
A valid Tezos address is a string prefixed by either tz1, tz2, tz3 or KT1 and followed by a Base58 encoded hash and terminated by a 4-byte checksum.
The prefix designates the type of address:
tz1
addresses are followed by a ed25519 public key hashtz2
addresses are followed by a Secp256k1 public key hashtz3
addresses are followed by a NIST p256r1 public key hashKT1
addresses are followed by a contract hash
Addresses prefixed by tz1
, tz2
and tz3
designate implicit accounts, whereas those prefixed KT1
designate originated accounts.
Finally, addresses can specify an entrypoint by providing a %<entrypoint_name>
suffix.
sp.address("tz1YtuZ4vhzzn7ssCt93Put8U9UJDdvCXci4")
See Addresses and Contracts documentation.
Michelson addresskey โ
A public cryptographic key.
Supported Curves:
sp.key("edpktx799pgw7M4z8551URER52VcENNCSZwE9f9cst4v6h5vCrQmJE")
See Keys documentation.
Michelson keykey_hash โ
A hash of a public cryptographic key.
sp.key_hash("tz1YtuZ4vhzzn7ssCt93Put8U9UJDdvCXci4")
See Keys documentation.
Michelson key_hashsignature โ
A cryptographic signature.
sp.signature("edsigu3QszDjUpeqYqbvhyRxMpVFamEnvm9FYnt7YiiNt9nmjYfh8ZTbsybZ5WnBkhA7zfHsRVyuTnRsGLR6fNHt1Up1FxgyRtF")
See Signatures documentation.
Michelson signaturechain_id โ
A chain identifier.
An identifier for a chain, used to distinguish the test and the main chains.
The value is derived from the genesis block hash and will thus be different on the main chains of different networks and on the test chains for which the value depends on the first block of the test-chain.
Please note that chain ids are non comparable. Equality can be verified in test scenarios by using verify_equal.
sp.chain_id_cst("0x9caecab9")
See Chain Id documentation.
Michelson chain_idunit โ
The type whose only value is Unit
, to use as a placeholder when some result or parameter is non-necessary. For instance, when the only goal of a contract is to update its storage.
sp.unit
See Unit documentation.
Michelson unitbls12_381_g1 โ
A point on the BLS12-381 curve G1.
Written as raw bytes, using a big-endian point encoding, as specified here.
See reference BLS12 template.
sp.bls12_381_g1("0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1")
See BLS12 381 documentation.
Michelson bls12_381_g1bls12_381_g2 โ
A point on the BLS12-381 curve G2.
Written as raw bytes, using a big-endian point encoding, as specified here.
See reference BLS12 template.
sp.bls12_381_g2("0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801")
See BLS12 381 documentation.
Michelson bls12_381_g2bls12_381_fr โ
An element of the BLS12-381 scalar field Fr.
An element of the scalar field Fr, used for scalar multiplication on the BLS12-381 curves G1 and G2.
Written as raw bytes, using a big-endian point encoding, as specified here.
See reference BLS12 template.
sp.bls12_381_fr("0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221")
See BLS12 381 documentation.
Michelson bls12_381_frchest โ
Represents timelocked arbitrary bytes with the necessary public parameters to open it.
sp.chest("0x01234")
See Timelock documentation.
Michelson chestchest_key โ
Represents the decryption key, alongside with a proof that the key is correct.
sp.chest_key("0x01234")
See Timelock documentation.
Michelson chest_keyContainer Types โ
pair of type1 and type2 โ
A pair or tuple of values.
The type pair type1 type2
is the type of binary pairs composed of a left element of type type1
and a right element of type type2
.
(1, True)
# or
sp.pair(sp.nat(1), True)
list of type โ
A single, immutable, homogeneous linked list, whose elements are of type type
.
[1, 2, 3]
set of type โ
An immutable set of comparable values of type type
.
sp.set([1, 2, 3])
map of kty and vty โ
An immutable map from kty
to vty
.
Immutable maps from keys of type kty
and values of type vty
.
{ 1: "A String" }
# or
sp.map({ 1: "A String" }, tkey = sp.TNat, tvalue = sp.TString)
big_map of kty and vty โ
A lazily deserialized map from kty
to vty
.
Lazily deserialized maps from keys of type kty
of values of type vty
. These maps should be used if you intend to store large amounts of data in a map. Using big_map
can reduce gas costs significantly compared to standard maps, as data is lazily deserialized. Note however that individual operations on big_map
have higher gas costs than those over standard maps. A big_map
also has a lower storage cost than a standard map of the same size, when large keys are used, since only the hash of each key is stored in a big_map
.
The behavior of GET, UPDATE, GET_AND_UPDATE and MEM is the same on big_map
as on normal map
, except that under the hood, elements are loaded and deserialized on demand.
Literal big_map
cannot be pushed directly in contract code. Instead, they must be created using EMPTY_BIG_MAP and manipulated using GET, UPDATE, GET_AND_UPDATE and MEM.
Values of the big_map
type cannot be serialized using PACK.
sp.big_map({ 1 : "A String" }, tkey = sp.TNat, tvalue = sp.TString)
option of type โ
The type of an optional values.
They represent values of type type
or nothing.
Optional values are useful for accommodating missing data, that will only be available after origination.
sp.some(1)
# or
sp.none
contract of type โ
sp.TContract(t)
is the type of contracts whose parameters are of type t
.
A value of type contract type
is guaranteed to be a valid, existing account whose parameter type is type
. This can be opposed to the address
type, that merely gives the guarantee that the value has the form of a Tezos address. Values of the contract type cannot be stored. There are not literal values of type contract. Instead, such values are created using instructions such as CONTRACT or IMPLICIT_ACCOUNT.
sp.contract(sp.TNat, "tz1YtuZ4vhzzn7ssCt93Put8U9UJDdvCXci4", entry_point = "foo").open_some("InvalidInterface")
sapling_state of memo size โ
sp.TSaplingState(memo_sizeย = size)
is the type of sapling states with memo size of size
.
Example
# A type
sp.TSaplingState(memo_size = 8)
# Some value
sp.sapling_empty_state(memo_size = 8)
Please see the Sapling integration page for a more comprehensive description of the Sapling protocol.
Michelson sapling_statesapling_transaction of memo size โ
sp.TSaplingTransaction(memo_sizeย = size)
is the type of sapling transactions with memo size of size
.
## only for tests
sp.sapling_test_transaction(source, target, amount, memo_size)
Please see the Sapling integration page for a more comprehensive description of the Sapling protocol.
Michelson sapling_transactionRecord, Variant and Layout โ
In SmartPy, we can use custom data types called records and variants. Records and variants are translated in Michelson into binary trees of pair and or with annotations corresponding to each field.
The geometry of these binary trees is described by a layout.
Record โ
A record type represents a cartesian product of several types similar to a struct in C
with a layout.
sp.TRecord(**fields)
A record type is introduced by enumerating the field names together with types
sp.TRecord(x = sp.TInt, y = sp.TInt)
It uses the default layout as determined by SmartPy, and can be changed by specifying default_record_layoutflag.
.layout(layout)
A record type, i.e. something of the form sp.TRecord(...)
, can be used to define a record type with a layout by doing:
t = sp.TRecord(owner = sp.TAddress, operator = sp.TAddress, token_id = sp.TString)
t_with_layout = t.layout(("owner", ("operator", "token_id")))
.right_comb()
Like .layout(...) but the geometry used is (f1,ย (f2, ..ย (f_{k-1}, f_k)))))
, the list of fields is determined automatically and sorted alphabetically.
.with_fields(fields)
Adds some fields to the TRecord(...)
where fields
is a Python (string, type)-dictionary of fields.
.without_fields(fields)
Removes some fields from the TRecord(...)
where fields
is a Python list of fields.
Variant โ
A variant type represents a union of several choices, similar to a clean version of a struct with an enum/union pattern in C
.
sp.TVariant(**fields)
A variant type is introduced by enumerating the constructor names together with their inner types.
# Example
sp.TVariant(default_choice = sp.TInt, alternative_choice = sp.TString)
It uses the default layout as determined by SmartPy, and can be changed by specifying default_variant_layoutflag.
.layout(layout)
A variant type, i.e. something of the form sp.TVariant(...)
, can be used to define a variant type with a layout by doing:
t = sp.TVariant(choice_1 = sp.TAddress, choice_2 = sp.TString, choice_3 = sp.TString)
t_with_layout = t.layout(("choice_1", ("choice_2", "choice_3")))
.right_comb()
Like .layout(...) but the geometry used is (f1,ย (f2, ..ย (f_{k-1}, f_k)))))
, the list of fields is determined automatically and sorted alphabetically.
Layouts โ
A layout is a Python expression listing all fields or constructors in a binary tree structure such as ("b",ย ("a",ย "c"))
. There is no equivalent instruction in Michelson.
See reference Data Type Layouts template.
The SmartPy compiler recognizes a special format "[source]
as [target]
" to translate field names between SmartPy and Michelson.
A specific case "[source]
as**"** is also supported to generate annotation-less types.
See FA1.2 template.
Bounded types โ
See Bounded types documentation.
Setting a type constraint โ
This is usually not needed for small contracts or prototypes but gets useful typically when interacting with the outside world, implementing a given interface, etc.
self.init_type(t)
Constrain the contract storage to be of type t
(called in the __init__
constructor).
This is useful because it allows the user to make the storage type explicit or even to define storage-less contracts.
In a test, if not determined in the __init__
method, the storage can be initialized by calling c.init_storage(expression)
.
See reference Init Type Only template.
This is not mandatory but is appreciated by many in practice.
class MyContract(sp.Contract):
def __init__(self):
## Possibly set the storage type
self.init_type(sp.TRecord(a = sp.TInt, b = sp.TString))
## Possibly set the storage
self.init(...)
sp.set_type(expression, t)
Constrain expression
to be of type t
. This can only be used as a command inside a contract.
There is no equivalent instruction in Michelson.
A usual pattern for big contracts is to explicitly setting types in the first lines of entrypoints.
This is usually not needed but is appreciated by many in practice.
@sp.entrypoint
def my_entrypoint(self, x, y, z):
## First set types
sp.set_type(x, sp.TInt)
sp.set_type(y, sp.TString)
sp.set_type(z, sp.TList(sp.TInt))
## Then do the computations
...
sp.set_result_type(t)
Wrap a block of commands and constrain its result type to t
. This can only be used as a command inside a contract.
There is no equivalent instruction in Michelson.
This is useful for making types of failures explicit.
@sp.private_lambda()
def oh_no(params):
with sp.set_result_type(sp.TInt):
sp.if params > 10:
sp.failwith("too big")
sp.else:
sp.result(params)
sp.set_type_expr(expression, t)
Wrap expression
to be of type t
. This can only be used as an expression.
There is no equivalent instruction in Michelson.
A few words of caution about the differences between sp.set_type
and sp.set_type_expr
:
# Inside a contract:
@sp.entrypoint
def my_entrypoint(self, params):
...
## Warning: this is not taken into account (the expression is simply dropped).
sp.set_type_expr(params, sp.TInt)
...
@sp.entrypoint
def my_entrypoint(self, params):
...
## This is taken into account (when we call params afterward).
params = sp.set_type_expr(params, sp.TInt)
... params ...
@sp.entrypoint
def my_entrypoint(self, params):
...
## This is taken into account (sp.set_type is a command).
sp.set_type(params, sp.TInt) ## This is taken into account.
...
# Inside a test scenario:
scenario += ...
## This is illegal (command outside of a contract).
sp.set_type(..., ...)
## This is OK (usually useless nonetheless)
x = sp.set_type_expr(..., ...)
scenario += c.f(x)
Containers have built-in optional constraint arguments.
Define a map of (optional) elements in l
with optional key type tkey
and optional value type tvalue
.
sp.map(l = ..., tkey = ..., tvalue = ...)
Define a big_map of (optional) elements in l
with optional key type tkey
and optional value type tvalue
.
sp.big_map(l = ..., tkey = ..., tvalue = ...)
Defines a set of (optional) elements in list l
with optional element type t
.
sp.set(l = ..., t = ...)`
Defines a list of (optional) elements in list l
with optional element type t
.
sp.list(l = ..., t = ...)