Serialization¶
When interacting with the blockchain, a very important aspect to keep in mind is the data format, in particular when dealing with smart-contracts and when the data has a complex representation such as custom structures with nested elements. To make things easy for the user, MxOps will use ABI definitions to:
automatically convert the data provided by the user into the format expected by the blockchain
automatically parse the data received from the blockchain into a human usable format
The rest of this chapter details how the user should provide data and use data when interacting with a smart-contract.
Monotypes¶
Most monotypes can be directly provided as-is, this includes: bool, u<n>, i<n>, BigUint, BigInt, TokenIdentifier, EgldOrEsdtTokenIdentifier and utf-8 string.
Example:
- type: ContractQuery
contract: my_contract
endpoint: my_query_endpoint
arguments:
- true # bool
- 2 # u8
- -623 # i32
- 1329809823980832 # BigUint
- -9248872872987083940 # BigInt
- WEGLD-abcdef # TokenIdentifier
- WEGLD-abcdef # EgldOrEsdtTokenIdentifier
- "my super utf8 string" # utf-8 string
Bytes¶
bytes are trickier as yaml don’t support directly the bytes type. If your intention is to provided vector, list of elements, string or anything that should be converted to bytes, then you can write them in the original format and MxOps will convert them for you.
However, if you really need to pass pure bytes data, then you must use one of the following syntax:
bytes:<b64_encoded_data>, whereb64_encoded_datais your bytes data in the b64 format."<hex_encoded_data>", wherehex_encoded_datais your bytes data in the hex format, provided as a string.
- type: ContractQuery
contract: my_contract
endpoint: my_query_endpoint
arguments:
- [1, 2, 4, 8] # vec that will be converted to bytes
- "bytes:AQIECA==" # same bytes data but in the b64 format
- "0x01020408" # same bytes data but in the hex format, the quotes are mandatory!
Address¶
Addresses are passed in their bech32 form.
- type: ContractQuery
contract: my_contract
endpoint: my_query_endpoint
arguments:
- erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqplllst77y4l # address
List, Tuple, Vec, ManagedVec¶
Lists, Tuples, Vecs, ManagedVecs can be specified as list using yaml syntax or direct list format:
- type: ContractQuery
contract: my_contract
endpoint: my_query_endpoint
arguments:
# List<u8>
- [0, 1, 2, 3]
# Tuple<TokenIdentifier, TokenIdentifier>
- [WEGLD-abcdef, MEX-abcdef]
# Tuple<TokenIdentifier, TokenIdentifier>
- - WEGLD-abcdef
- MEX-abcdef
Structs¶
Structs must be provided simply as a list or a dictionary of their elements. The number of provided elements must exactly match the number of elements of the Struct.
#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, TypeAbi, PartialEq, Eq)]
pub struct MyStruct<M: ManagedTypeApi> {
pub int: u16,
pub seq: ManagedVec<M, u8>,
pub another_byte: u8,
pub uint_32: u32,
pub uint_64: u64,
}
- type: ContractQuery
contract: my_contract
endpoint: my_query_endpoint
arguments:
# MyStruct provided as a list of elements using yaml syntax
- - 8
- [9, 45]
- 0
- 789484
- 485
# MyStruct provided as a list of elements using a list syntax
- [8, [9, 45], 0, 789484, 485]
# MyStruct provided as a dictionnary of elements using the field names
- int: 8
seq: [9, 45]
another_byte: 0
uint_32: 789484
uint_64: 485
Enums¶
Enums are handled as a special kind of Structs. If you have a classical simple Enum, you can just provided the name or the discriminant of the element you want to provide. you can also provide the element as if it was a struct, while providing either of the keys __name__ and __discriminant__.
#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, TypeAbi, PartialEq, Eq)]
pub enum DayOfWeek {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,
}
- type: ContractQuery
contract: my_contract
endpoint: my_query_endpoint
arguments:
# DayOfWeek::Monday using the name
- Monday
# DayOfWeek::Tuesday using the discriminant
- 1
# DayOfWeek::Wednesday using a dictionnary with the name
- __name__: Wednesday
# DayOfWeek::Thursday using a dictionnary with the discriminant
- __disciminant__: 3
In case you are dealing with a complex Enum, you will be forced to use the struct approach while specifying the custom values needed.
#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, TypeAbi, PartialEq, Eq)]
pub enum EnumWithEverything<M: ManagedTypeApi> {
Default,
Today(DayOfWeek),
Write(ManagedVec<M, u8>, u16),
MyStruct {
int: u16,
seq: ManagedVec<M, u8>,
another_byte: u8,
uint_32: u32,
uint_64: u64,
},
}
- type: ContractQuery
contract: my_contract
endpoint: my_query_endpoint
arguments:
# EnumWithEverything::Default
- Default
# EnumWithEverything::Today::Tuesday as a list
- - Today
- Tuesday
# EnumWithEverything::Today::Tuesday as a dictionnary
- __name__: Today
"0": Tuesday
# EnumWithEverything::Write as a list
- - Write
- [1, 2, 4, 8]
- 14
# EnumWithEverything::Write as a dictionnary
- __name__: Write
"0": [1, 2, 4, 8]
"1": 14
# EnumWithEverything::MyStruct as a list
- - MyStruct
- 8
- [9, 45]
- 0
- 789484
- 485
# EnumWithEverything::MyStruct as a dictionnary
- __name__: MyStruct
int: 8
seq: [9, 45]
another_byte: 0
uint_32: 789484
uint_64: 485
MultiValueEncoded¶
When dealing with MultiValueEncoded types, the user must provide the elements as a list.
So if he wants to send three values as multi-encoded, he must provided a list of three values.
#[view]
fn my_query_endpoint(&self, my_isize: isize, biguints: MultiValueEncoded<BigUint>) {}
- type: ContractQuery
contract: my_contract
endpoint: my_query_endpoint
arguments:
- 4 # my_isize
- - 178978798 # -> biguints[0]
- 398835293 # -> biguints[1]
- 105639583 # -> biguints[2]
...
- 434782323 # -> biguints[n]
OptionalValue¶
The sdk from the core team imposes to provide all values, even when they are optional. MxOps is forced to apply this constraint as well: Optional value must be provided. In case you want to specify that you send no value, write null.
#[view]
fn my_query_endpoint(
&self,
my_option_biguint: Option<BigUint>,
my_optional_token_identifier_2: OptionalValue<TokenIdentifier>,
)
- type: ContractQuery
contract: my_contract
endpoint: my_query_endpoint
arguments:
- 123987
- null
Option Value¶
For option values, just write a value of the expected type or null.
#[view]
fn my_query_endpoint(
&self,
my_option_biguint: Option<BigUint>,
)
- type: ContractQuery
contract: my_contract
endpoint: my_query_endpoint
arguments:
- 123987
- type: ContractQuery
contract: my_contract
endpoint: my_query_endpoint
arguments:
- null