Arbitrum Stylus logo

Stylus by Example

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:

1// This should always return true
2pub fn encode_and_decode(
3    &self, 
4    target: Address,
5    value: U256,
6    func: String,
7    data: Bytes,
8    timestamp: U256
9) -> Result<bool, HasherError> {
10    // define sol types tuple
11    type TxIdHashType = (SOLAddress, Uint<256>, SOLString, SOLBytes, Uint<256>);
12    // 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
13    let primative_data = alloy_primitives::Bytes::copy_from_slice(&data);
14    // set the tuple
15    let tx_hash_data = (target, value, func, primative_data, timestamp);
16    // encode the tuple
17    let tx_hash_data_encode = TxIdHashType::abi_encode_sequence(&tx_hash_data);
18
19    let validate = true;
20    
21    // Check the result
22    match TxIdHashType::abi_decode_sequence(&tx_hash_data_encode, validate) {
23        Ok(res) => Ok(res == tx_hash_data),
24        Err(_) => {
25            return Err(HasherError::DecodedFailed(DecodedFailed{}));
26        },
27    }   
28}
1// This should always return true
2pub fn encode_and_decode(
3    &self, 
4    target: Address,
5    value: U256,
6    func: String,
7    data: Bytes,
8    timestamp: U256
9) -> Result<bool, HasherError> {
10    // define sol types tuple
11    type TxIdHashType = (SOLAddress, Uint<256>, SOLString, SOLBytes, Uint<256>);
12    // 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
13    let primative_data = alloy_primitives::Bytes::copy_from_slice(&data);
14    // set the tuple
15    let tx_hash_data = (target, value, func, primative_data, timestamp);
16    // encode the tuple
17    let tx_hash_data_encode = TxIdHashType::abi_encode_sequence(&tx_hash_data);
18
19    let validate = true;
20    
21    // Check the result
22    match TxIdHashType::abi_decode_sequence(&tx_hash_data_encode, validate) {
23        Ok(res) => Ok(res == tx_hash_data),
24        Err(_) => {
25            return Err(HasherError::DecodedFailed(DecodedFailed{}));
26        },
27    }   
28}

Full Example code:

src/lib.rs

1#![cfg_attr(not(any(feature = "export-abi", test)), no_main)]
2extern crate alloc;
3
4
5/// Import items from the SDK. The prelude contains common traits and macros.
6use stylus_sdk::{alloy_primitives::{U256, Address}, prelude::*};
7// Because the naming of `alloy_primitives` and `alloy_sol_types` is the same, we need to rename the types in `alloy_sol_types`.
8use alloy_sol_types::{sol_data::{Address as SOLAddress, *}, SolType, sol};
9
10
11// Define error
12sol! {
13    error DecodedFailed();
14}
15
16// Error types for the MultiSig contract
17#[derive(SolidityError)]
18pub enum DecoderError{
19    DecodedFailed(DecodedFailed)
20}
21
22#[storage]
23#[entrypoint]
24pub struct Decoder;
25
26
27/// Declare that `Decoder` is a contract with the following external methods.
28#[public]
29impl Decoder {
30    // This should always return true
31    pub fn encode_and_decode(
32        &self, 
33        address: Address, 
34        amount: U256
35    ) -> Result<bool, DecoderError> {
36        // define sol types tuple
37        type TxIdHashType = (SOLAddress, Uint<256>);
38        // set the tuple
39        let tx_hash_data = (address, amount);
40        // encode the tuple
41        let tx_hash_data_encode = TxIdHashType::abi_encode_params(&tx_hash_data);
42
43        let validate = true;
44        
45        // Check the result
46        match TxIdHashType::abi_decode_params(&tx_hash_data_encode, validate) {
47            Ok(res) => Ok(res == tx_hash_data),
48            Err(_) => {
49                return Err(DecoderError::DecodedFailed(DecodedFailed{}));
50            },
51        }   
52    }
53
54}
1#![cfg_attr(not(any(feature = "export-abi", test)), no_main)]
2extern crate alloc;
3
4
5/// Import items from the SDK. The prelude contains common traits and macros.
6use stylus_sdk::{alloy_primitives::{U256, Address}, prelude::*};
7// Because the naming of `alloy_primitives` and `alloy_sol_types` is the same, we need to rename the types in `alloy_sol_types`.
8use alloy_sol_types::{sol_data::{Address as SOLAddress, *}, SolType, sol};
9
10
11// Define error
12sol! {
13    error DecodedFailed();
14}
15
16// Error types for the MultiSig contract
17#[derive(SolidityError)]
18pub enum DecoderError{
19    DecodedFailed(DecodedFailed)
20}
21
22#[storage]
23#[entrypoint]
24pub struct Decoder;
25
26
27/// Declare that `Decoder` is a contract with the following external methods.
28#[public]
29impl Decoder {
30    // This should always return true
31    pub fn encode_and_decode(
32        &self, 
33        address: Address, 
34        amount: U256
35    ) -> Result<bool, DecoderError> {
36        // define sol types tuple
37        type TxIdHashType = (SOLAddress, Uint<256>);
38        // set the tuple
39        let tx_hash_data = (address, amount);
40        // encode the tuple
41        let tx_hash_data_encode = TxIdHashType::abi_encode_params(&tx_hash_data);
42
43        let validate = true;
44        
45        // Check the result
46        match TxIdHashType::abi_decode_params(&tx_hash_data_encode, validate) {
47            Ok(res) => Ok(res == tx_hash_data),
48            Err(_) => {
49                return Err(DecoderError::DecodedFailed(DecodedFailed{}));
50            },
51        }   
52    }
53
54}

Cargo.toml

1[package]
2name = "stylus-decode-hashing"
3version = "0.1.0"
4edition = "2021"
5
6[dependencies]
7alloy-primitives = "=0.7.6"
8alloy-sol-types = "=0.7.6"
9mini-alloc = "0.4.2"
10stylus-sdk = "0.5.1"
11
12[features]
13export-abi = ["stylus-sdk/export-abi"]
14debug = ["stylus-sdk/debug"]
15
16[lib]
17crate-type = ["lib", "cdylib"]
18
19[profile.release]
20codegen-units = 1
21strip = true
22lto = true
23panic = "abort"
24opt-level = "s"
1[package]
2name = "stylus-decode-hashing"
3version = "0.1.0"
4edition = "2021"
5
6[dependencies]
7alloy-primitives = "=0.7.6"
8alloy-sol-types = "=0.7.6"
9mini-alloc = "0.4.2"
10stylus-sdk = "0.5.1"
11
12[features]
13export-abi = ["stylus-sdk/export-abi"]
14debug = ["stylus-sdk/debug"]
15
16[lib]
17crate-type = ["lib", "cdylib"]
18
19[profile.release]
20codegen-units = 1
21strip = true
22lto = true
23panic = "abort"
24opt-level = "s"