Skip to main content

ABI Decode

The decode can not be used for encode_packed data because it ignores padding when encode. (For more information you can refer to ABI Encode)

So here we show an example for using decode on data encoded with abi_encode_sequence:

// This should always return true
pub fn encode_and_decode(
&self,
target: Address,
value: U256,
func: String,
data: Bytes,
timestamp: U256
) -> Result<bool, HasherError> {
// define sol types tuple
type TxIdHashType = (SOLAddress, Uint<256>, SOLString, SOLBytes, Uint<256>);
// because the abi_encode_sequence will return alloy_primitives::Bytes rather than stylus_sdk::bytes, so we need to make sure the input and return types are the same
let primative_data = alloy_primitives::Bytes::copy_from_slice(&data);
// set the tuple
let tx_hash_data = (target, value, func, primative_data, timestamp);
// encode the tuple
let tx_hash_data_encode = TxIdHashType::abi_encode_sequence(&tx_hash_data);

let validate = true;

// Check the result
match TxIdHashType::abi_decode_sequence(&tx_hash_data_encode, validate) {
Ok(res) => Ok(res == tx_hash_data),
Err(_) => {
return Err(HasherError::DecodedFailed(DecodedFailed{}));
},
}
}

Full Example code:

src/main.rs

#![no_main]
#![no_std]
extern crate alloc;
/// Use an efficient WASM allocator.
#[global_allocator]
static ALLOC: mini_alloc::MiniAlloc = mini_alloc::MiniAlloc::INIT;

/// Import items from the SDK. The prelude contains common traits and macros.
use stylus_sdk::{alloy_primitives::{U256, Address}, prelude::*};
// Becauce the naming of alloy_primitives and alloy_sol_types is the same, so we need to re-name the types in alloy_sol_types
use alloy_sol_types::{sol_data::{Address as SOLAddress, *}, SolType};
use alloy_sol_types::sol;

// Define error
sol! {
error DecodedFailed();
}

// Error types for the MultiSig contract
#[derive(SolidityError)]
pub enum DecoderError{
DecodedFailed(DecodedFailed)
}

// Define some persistent storage using the Solidity ABI.
// `Decoder` will be the entrypoint.
sol_storage! {
#[entrypoint]
pub struct Decoder {
}
}


/// Declare that `Decoder` is a contract with the following external methods.
#[external]
impl Decoder {
// This should always return true
pub fn encode_and_decode(
&self,
address: Address,
amount: U256
) -> Result<bool, DecoderError> {
// define sol types tuple
type TxIdHashType = (SOLAddress, Uint<256>);
// set the tuple
let tx_hash_data = (address, amount);
// encode the tuple
let tx_hash_data_encode = TxIdHashType::abi_encode_sequence(&tx_hash_data);

let validate = true;

// Check the result
match TxIdHashType::abi_decode_sequence(&tx_hash_data_encode, validate) {
Ok(res) => Ok(res == tx_hash_data),
Err(_) => {
return Err(DecoderError::DecodedFailed(DecodedFailed{}));
},
}
}

}

Cargo.toml

[package]
name = "stylus-encode-hashing"
version = "0.1.0"
edition = "2021"

[dependencies]
alloy-primitives = "0.7.3"
alloy-sol-types = "0.7.3"
mini-alloc = "0.4.2"
stylus-sdk = "0.5.1"

[features]
export-abi = ["stylus-sdk/export-abi"]
debug = ["stylus-sdk/debug"]

[lib]
crate-type = ["lib", "cdylib"]

[profile.release]
codegen-units = 1
strip = true
lto = true
panic = "abort"
opt-level = "s"