abi::abiThis module implements ABI encoding/decoding methods for interoperability with EVM message format.
ABI Specification: https://docs.soliditylang.org/en/v0.8.26/abi-spec.html
AbiReader
AbiWriter
new_readernew_writerinto_bytesread_u256read_u8skip_slotread_bytesread_vector_u256read_vector_bytesread_bytes_raw
write_u256write_u8write_byteswrite_vector_u256write_vector_byteswrite_bytes_rawappend_u256append_bytesdecode_bytesuse std::ascii;
use std::bcs;
use std::option;
use std::string;
use std::vector;
use sui::address;
use sui::bcs;
use sui::hex;
AbiReaderUsed to decode abi encoded bytes into variables.
let mut reader = abi::new_reader(data);
let number = reader.read_u256();
let name = reader.read_bytes().to_string();
let addresses = reader.read_vector_u256().map!(|val|
sui::address::from_u256(val));
let info = reader.read_vector_bytes();
public struct AbiReader has copy, drop
bytes: vector<u8>
head: u64
pos: u64
AbiWriterUsed to encode variables into abi encoded bytes.
let mut writer = abi::new_writer(4);
writer
.write_u256(1234)
.write_bytes(b"some_bytes")
.write_vector_u256(vector[12, 34, 56])
.write_vector_bytes(vector[b"some", b"more", b"bytes"]);
let encoded_data = writer.into_bytes();
public struct AbiWriter has copy, drop
bytes: vector<u8>
pos: u64
const U256_BYTES: u64 = 32;
new_readerCreates a new AbiReader from the bytes passed.
public fun new_reader(bytes: vector<u8>): abi::abi::AbiReader
public fun new_reader(bytes: vector<u8>): AbiReader {
AbiReader {
bytes,
head: 0,
pos: 0,
}
}
new_writerCreates a new AbiWriter that can fit up to length bytes before to
overflows.
public fun new_writer(length: u64): abi::abi::AbiWriter
public fun new_writer(length: u64): AbiWriter {
AbiWriter {
bytes: vector::tabulate!(U256_BYTES * length, |_| 0),
pos: 0,
}
}
into_bytesRetrieve the bytes from an AbiWriter.
public fun into_bytes(self: abi::abi::AbiWriter): vector<u8>
public fun into_bytes(self: AbiWriter): vector<u8> {
let AbiWriter { bytes, pos: _ } = self;
bytes
}
read_u256Read a u256 from the next slot of the AbiReader. Should be used to read
other fixed length types as well.
public fun read_u256(self: &mut abi::abi::AbiReader): u256
public fun read_u256(self: &mut AbiReader): u256 {
let mut var = 0u256;
let pos = self.pos;
U256_BYTES.do!(|i| var = (var << 8) | (self.bytes[i + pos] as u256));
self.pos = pos + U256_BYTES;
var
}
read_u8Read a u8 from the next slot of the AbiReader. Aborts if the slot value exceeds u8::MAX
public fun read_u8(self: &mut abi::abi::AbiReader): u8
skip_slotUsed to ignore the next variable in an AbiReader.
public fun skip_slot(self: &mut abi::abi::AbiReader)
public fun skip_slot(self: &mut AbiReader) {
self.pos = self.pos + U256_BYTES;
}
read_bytesReads a variable length bytes from an AbiReader.
This can be used to read other variable length types, such as String.
public fun read_bytes(self: &mut abi::abi::AbiReader): vector<u8>
public fun read_bytes(self: &mut AbiReader): vector<u8> {
let pos = self.pos;
// Move position to the start of the bytes
let offset = self.read_u256() as u64;
self.pos = self.head + offset;
let var = self.decode_bytes();
// Move position to the next slot
self.pos = pos + U256_BYTES;
var
}
read_vector_u256Reads a vector of fixed length variables from an AbiReader as a
vector<u256>. Can also be cast into vectors of other fixed length
types.
public fun read_vector_u256(self: &mut abi::abi::AbiReader): vector<u256>
public fun read_vector_u256(self: &mut AbiReader): vector<u256> {
let pos = self.pos;
// Move position to the start of the dynamic data
let offset = self.read_u256() as u64;
self.pos = self.head + offset;
let length = self.read_u256() as u64;
let var = vector::tabulate!(length, |_| self.read_u256());
self.pos = pos + U256_BYTES;
var
}
read_vector_bytesReads a vector of variable length variables from an AbiReader as a
vector<vector<u8>>. Can also be cast into vectors of other variable length
types.
public fun read_vector_bytes(self: &mut abi::abi::AbiReader): vector<vector<u8>>
public fun read_vector_bytes(self: &mut AbiReader): vector<vector<u8>> {
let pos = self.pos;
let head = self.head;
// Move position to the start of the dynamic data
let offset = self.read_u256() as u64;
self.pos = head + offset;
let length = self.read_u256() as u64;
self.head = self.pos;
let var = vector::tabulate!(length, |_| self.read_bytes());
// Move position to the next slot
self.pos = pos + U256_BYTES;
self.head = head;
var
}
read_bytes_rawReads the raw bytes of a variable length variable. This will return additional bytes at the end of the structure as there is no way to know how to decode the bytes returned. This can be used to decode structs and complex nested vectors that this library does not provide a method for.
For more complex types like structs or nested vectors read_bytes_raw can
be used and decoded manualy. To read a struct that contains a u256 and
a vector<u8> from an AbiReader called reader a user may:
let struct_bytes = reader.read_bytes_raw();
let mut struct_reader = new_reader(struct_bytes);
let number = struct_reader.read_u256();
let data = struct_reader.read_bytes();
As another example, to decode a vector<vector<u256>> into a variable
called table from an AbiReader called reader a user can:
let mut table_bytes = reader.read_bytes_raw();
// Split the data into the length and the actual table contents
let length_bytes = vector::tabulate!(U256_BYTES, |_| table_bytes.remove(0));
let mut length_reader = new_reader(length_bytes);
let length = length_reader.read_u256() as u64;
let mut table_reader = new_reader(table_bytes);
let table = vector::tabulate!(length, |_| table_reader.read_vector_u256());
public fun read_bytes_raw(self: &mut abi::abi::AbiReader): vector<u8>
public fun read_bytes_raw(self: &mut AbiReader): vector<u8> {
// Move position to the start of the bytes
let offset = self.read_u256() as u64;
let length = self.bytes.length() - offset;
let var = vector::tabulate!(length, |i| self.bytes[offset + i]);
var
}
write_u256Write a u256 into the next slot of an AbiWriter. Can be used to write
other fixed length types as well.
public fun write_u256(self: &mut abi::abi::AbiWriter, var: u256): &mut abi::abi::AbiWriter
public fun write_u256(self: &mut AbiWriter, var: u256): &mut AbiWriter {
let pos = self.pos;
U256_BYTES.do!(|i| {
let exp = ((31 - i) * 8 as u8);
let byte = (var >> exp & 255 as u8);
*&mut self.bytes[i + pos] = byte;
});
self.pos = pos + U256_BYTES;
self
}
write_u8Write a u8 into the next slot of an AbiWriter.
public fun write_u8(self: &mut abi::abi::AbiWriter, var: u8): &mut abi::abi::AbiWriter
public fun write_u8(self: &mut AbiWriter, var: u8): &mut AbiWriter {
self.write_u256(var as u256)
}
write_bytesWrite a variable-length bytes into the next slot of an AbiWriter. Can be used to write
other variable length types, such as String.
public fun write_bytes(self: &mut abi::abi::AbiWriter, var: vector<u8>): &mut abi::abi::AbiWriter
public fun write_bytes(self: &mut AbiWriter, var: vector<u8>): &mut AbiWriter {
let offset = self.bytes.length() as u256;
self.write_u256(offset);
// Write dynamic data length and bytes at the tail
self.append_u256(var.length() as u256);
self.append_bytes(var);
self
}
write_vector_u256Write a vector<u256> into the next slot of an AbiWriter. Can be used to
write other vectors of fixed length types as well.
public fun write_vector_u256(self: &mut abi::abi::AbiWriter, var: vector<u256>): &mut abi::abi::AbiWriter
public fun write_vector_u256(self: &mut AbiWriter, var: vector<u256>): &mut AbiWriter {
let offset = self.bytes.length() as u256;
self.write_u256(offset);
let length = var.length();
self.append_u256(length as u256);
var.do!(|val| {
self.append_u256(val)
});
self
}
write_vector_bytesWrite a vector of bytes into the next slot of an AbiWriter. Can be used to
write vectors of other variable length types as well.
public fun write_vector_bytes(self: &mut abi::abi::AbiWriter, var: vector<vector<u8>>): &mut abi::abi::AbiWriter
public fun write_vector_bytes(self: &mut AbiWriter, var: vector<vector<u8>>): &mut AbiWriter {
let offset = self.bytes.length() as u256;
self.write_u256(offset);
let length = var.length();
self.append_u256(length as u256);
let mut writer = new_writer(length);
var.do!(|val| {
writer.write_bytes(val);
});
self.append_bytes(writer.into_bytes());
self
}
write_bytes_rawWrite raw bytes to the next slot of an AbiWriter. This can be used to
write structs or more nested arrays that we support in this module.
For example to encode a struct consisting of u256 called number and a
vector<u8> called data into an AbiWriter named writer a user could
do
let mut struct_writer = new_writer(2);
struct_writer
.write_u256(number)
.write_bytes(data);
writer
.write_bytes_raw(struct_writer.into_bytes());
As another example, to abi encode a vector<vector<u256>> named table
into an AbiWriter named writer a user could do
let length = table.length();
let mut length_writer = new_writer(1);
length_writer.write_u256(length as u256);
let mut bytes = length_writer.into_bytes();
let mut table_writer = new_writer(length);
table.do!(|row| {
table_writer.write_vector_u256(row);
});
bytes.append(table_writer.into_bytes());
writer
.write_bytes_raw(bytes);
public fun write_bytes_raw(self: &mut abi::abi::AbiWriter, var: vector<u8>): &mut abi::abi::AbiWriter
public fun write_bytes_raw(self: &mut AbiWriter, var: vector<u8>): &mut AbiWriter {
let offset = self.bytes.length() as u256;
self.write_u256(offset);
self.append_bytes(var);
self
}
append_u256fun append_u256(self: &mut abi::abi::AbiWriter, var: u256)
fun append_u256(self: &mut AbiWriter, var: u256) {
let mut bytes = bcs::to_bytes(&var);
bytes.reverse();
self.bytes.append(bytes)
}
append_bytesfun append_bytes(self: &mut abi::abi::AbiWriter, var: vector<u8>)
fun append_bytes(self: &mut AbiWriter, var: vector<u8>) {
let length = var.length();
if (length == 0) {
return
};
self.bytes.append(var);
let pad_length = (U256_BYTES) - 1 - (length - 1) % U256_BYTES;
pad_length.do!(|_| self.bytes.push_back(0));
}
decode_bytesfun decode_bytes(self: &mut abi::abi::AbiReader): vector<u8>
fun decode_bytes(self: &mut AbiReader): vector<u8> {
let length = self.read_u256() as u64;
let pos = self.pos;
vector::tabulate!(length, |i| self.bytes[i + pos])
}