ethabi icon indicating copy to clipboard operation
ethabi copied to clipboard

Signed integer parameters are decoded as unsigned integers

Open marmistrz opened this issue 3 years ago • 6 comments

Consider the following function. In this context data is the data from the smart contract event logs and ethabi::decode is being used to decode this data.

fn decode_log(data: Vec<u8>) -> i128 {
        use ethabi::{ParamType, Token};

        let params = ethabi::decode(&[ParamType::Int(128)], data).unwrap();
        if let [Token::Int(change)] = params.as_slice() {
            change.as_i128()
        } else {
            panic!("Invalid decoded parameters: {:?}", params);
        }
}

This is supposed to parse the data of an event of the following signature:

event EventName(int128 change)

This code fails to compile because, counterintuitively, change is of the type U256, which is an unsigned type. This stems from the following line: https://github.com/rust-ethereum/ethabi/blob/d862110b8c64fdff9bf68cf291ef8481801e859f/ethabi/src/lib.rs#L91 which seems completely wrong.

Is this done on purpose and, if so, how should one decode signed parameters? There seems to be no mention of it in the docs.

marmistrz avatar Oct 21 '21 16:10 marmistrz

@nlordell this seems important for negative value logs right? should we add an I256 type to ethabi (either the one from ethers-core, and we can remove it from ethers, or the one you built in the past?) and use that as pub type Int?

gakonst avatar Jan 12 '22 10:01 gakonst

should we add an I256 type to ethabi

My favourite place to add it would be ethereum-types or primitive-types crate alongside the U256 type. The argument being that signed 256-bit math is part of the EVM so it makes the most sense to me there.

That being said, I think including it here also makes a lot of sense and I just marginally prefer having it in the aforementioned crates over ethabi. Maybe we can start by moving it here and simultaneously asking around in those projects if they would accept including signed integers there?

nlordell avatar Jan 12 '22 10:01 nlordell

Yep, supportive of importing to this package, and then seeing if they'd be willing to upstream.

gakonst avatar Jan 12 '22 11:01 gakonst

Need this fixed !

CRossel87a avatar Apr 13 '23 20:04 CRossel87a

Just solved this kind of problem. In case someone needs it:

fn convert_int256_to_f64(value: U256) -> Option<f64> {
    let half_of_max_u256 = U256::from(u128::MAX);

    let is_negative = value > half_of_max_u256;
    let value = if is_negative {
        let amount = U256::MAX - value;
        str::parse::<f64>(&format!("-{amount}")).unwrap()
    } else {
        str::parse::<f64>(&value.to_string()).unwrap()
    };

    Some(value)
}

0xFar5eer avatar Jul 31 '23 02:07 0xFar5eer