u<M> where M is either 8, 16, 32, 64, 128 or 256 bits.
enc(X) is the big-endian (i.e. right-aligned) representation of X left-padded with zero-bytes.
In the case of M being 8, 16, 32 or 64, total length must be 8 bytes.
If M is 128, total length must be 16 bytes.
If M is 256, total length must be 32 bytes.
Icon InfoCircle
Note: since all integer values are unsigned, there is no need to preserve the sign when extending/padding; padding with only zeroes is sufficient._
Example:
Encoding 42 yields: 0x000000000000002a, which is the hexadecimal representation of the decimal number 42, right-aligned to 8 bytes.
Encoding u128::MAX - 1 yields: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE, it's right-aligned to 16 bytes
An array of a certain type T, [T; n], where n is the length of the array.
Arrays in Sway have a fixed-length which is known at compile time. This means the ABI encoding for arrays also happens in-place, with no need to account for dynamic sizing.
The encoding for the array contains, in order, the encoding of each element in [T; n], recursively following the encoding for the type T.
For instance, consider the function signature my_func(bool, [u64; 2]) with the values (true, [1, 2]).
The encoding will be:
0x0000000000000001, the true bool encoded in-place.
0x0000000000000001, First element of the parameter [u64; 2], 1, encoded as a u64.
0x0000000000000002, Second element of the parameter [u64; 2], 2, encoded as a u64.
Strings have fixed length and are encoded in-place. str[n], where n is the fixed-size of the string. Rather than padding the string, the encoding of the elements of the string is tightly packed. And unlike the other type encodings, the string encoding is left-aligned.
Note that all strings are encoded in UTF-8.
Example:
Encoding "Hello, World" as a str[12]yields:
0x48656c6c6f2c20576f726c6400000000
Note that we're padding with zeroes in order to keep it right-aligned to 8 bytes (FuelVM's word size).
Encoding ABIs that contain custom types, such as structs, is similar to encoding a set of primitive types. The encoding will proceed in the order that the inner types of a custom type are declared and recursively just like encoding any other type. This way you can encode structs with primitive types or structs with more complex types in them such as other structs, arrays, strings, and enums.
ABI calls containing enums (sum types) are encoded similarly to structs: encode the discriminant first, then recursively encode the type of the enum variant being passed to the function being called.
0x0000000000000001 // The discriminant of the chosen enum, in this case `1`.0000000000000000 // Left padding0000000000000000 // Left padding0000000000000000 // Left padding000000000000002a // `42` encoded as u64
Note that three words of padding are required because the largest variant of MySumType is 4 words wide.
If all the variants of a sum type are of type (), or unit, then only the discriminant needs to be encoded.
ABI calls containing vectors are encoded in the following way:
First, figure out the the length l of the vector. Its length will also be its capacity.
Encode the content of the vector according to the spec of its type, e.g. for a Vec<bool>,
encode each bool element according to the bool specs. This gives out data that is stored
on the heap, and we encode only the pointer to this data
abi MyContract {fnfoo(a:Vec<u32>);} {fnfoo(a:Vec<u32>) {};}
Calling foo with vec![1u32, 2u32, 3u32, 4u32]:
length is 4, capacity is 4
data: [0x0000000000000001, 0x0000000000000002, 0x0000000000000003, 0x0000000000000004], stored at pointer address 0x000000000000beef
Icon InfoCircle
Note: to understand how the u32 are encoded, see the section about encoding integers.
ABI calls containing tuples are encoded as such:
If X is a tuple with the type signature (T_1, T_2, ..., T_n), with T_1,...,T_n being any type except for vector, then enc(X) is encoded as the concatenation of enc(T_1), enc(T_2),enc (T_3), ..., enc(T_n).