Serialization#

Data serialization#

starknet.py serializes python values to Cairo values and deserializes Cairo values to python values.

Attention

Serializing short strings to felts has been deprecated. Please use starknet_py.cairo.felt.encode_shortstring to create numeric value from string before passing value to serializer.

Serialization from python to Cairo#

Expected Cairo type

Accepted python types

Example python values

Comment

felt

int

0, 1, 1213124124

Provided int must be in range [0;P) - P being the Prime used in cairo-vm.

tuple

any iterable of matching size

(1, 2, (9, 8)), [1, 2, (9, 8)], (v for v in [1, 2, (9, 8)])

Can nest other types apart from pointers

named tuple

dict or NamedTuple or TupleDataclass

{"a": 1, "b": 2, "c" : (3, 4)}, NamedTuple("name", [("a", int), ("b", int), ("c", tuple)])(1, 2, (3, 4))

struct

dict with keys matching struct

{"key_1": 2, "key_2": (1, 2, 3), "key_3": {"other_struct_key": 13}}

Can nest other types apart from pointers

pointer/array (adds parameter_len parameter to abi)

any iterable

[1, 2, 3], [], ({"low": 1, "high": 1}, {"low": 2, "high": 2})

parameter_len is filled automatically from value

uint256

int or dict with "low" and "high" keys and ints as values

0, 340282366920938463463374607431768211583, {"low": 12, "high": 13}

Deserialization from Cairo to python values#

Cairo type

Python type

felt

int

tuple

tuple

named tuple

TupleDataclass

struct

dict with keys matching struct

pointer/array

list

uint256

int

Working with shortstrings#

To make working with short strings easier we provide some utility functions to translate between them and felt values. You can read more about how cairo treats shortstrings in the documentation.

Conversion functions and references:

from starknet_py.cairo.felt import decode_shortstring, encode_shortstring

# Convert a string literal to its felt value
encoded = encode_shortstring("myshortstring")
assert encoded == 0x6D7973686F7274737472696E67

# Decode a felt into a string
decoded = decode_shortstring(encoded)
assert decoded == "myshortstring"

Creating serializers from abi#

For most use cases using high level Contract is enough - it handles serialization and deserialization for you. If you need more flexibility you can use lower level serialization API, see Serializers for more details.

AbiParser transforms ABI into Abi class that can be used for creating serializers. This way you can easily deserialize events or serialize function’s inputs. Remember to use the proper version of AbiParser which depends on parsed ABI version.

Serializing function inputs and outputs#

from starknet_py.abi.v2 import AbiParser

"""
#[external(v0)]
fn test(ref self: ContractState, ref arg: felt252, arg1: felt252, arg2: felt252) -> felt252 {
    let mut x = self.my_storage_var.read();
    x += 1;
    self.my_storage_var.write(x);
    x + internal_func()
}
"""

abi = AbiParser(raw_abi_string).parse()

from starknet_py.serialization.factory import serializer_for_function_v1

# You can create serializer for function inputs/outputs by passing Abi.Function object to serializer_for_function
function_serializer = serializer_for_function_v1(abi.functions["test"])

# You can call function serializer like you would a normal function
assert [111, 222, 333] == function_serializer.serialize(arg=111, arg1=222, arg2=333)
assert [111, 222, 333] == function_serializer.serialize(111, 222, 333)
assert [111, 222, 333] == function_serializer.serialize(111, 222, arg2=333)

# You can use deserialized result from function serializer like a tuple
result = function_serializer.deserialize([1])
(success,) = result
assert success == 1

Serializing events#

Events emitted by contracts can also be serialized, having provided the correct ABI

from starknet_py.serialization import serializer_for_event

"""
#[event]
#[derive(Drop, starknet::Event)]
struct Approval {
    owner: ContractAddress,
    spender: ContractAddress,
    value: u256,
}
"""

# You can create serializer for events by passing Abi.Event object to serializer_for_event
event_serializer = serializer_for_event(
    abi.events["contracts_v2::erc20::ERC20::Approval"]
)

assert [1, 2, 3, 4] == event_serializer.serialize(
    {"owner": 1, "spender": 2, "value": 3 + 4 * 2**128}
)
assert {
    "owner": 1,
    "spender": 2,
    "value": 3 + 4 * 2**128,
} == event_serializer.deserialize([1, 2, 3, 4]).as_dict()