diff --git a/starknet-core/src/codec.rs b/starknet-core/src/codec.rs index 6d3b8a11..5f1eadda 100644 --- a/starknet-core/src/codec.rs +++ b/starknet-core/src/codec.rs @@ -7,6 +7,11 @@ use crate::types::{Felt, U256}; pub use starknet_core_derive::{Decode, Encode}; +const I128_MIN: Felt = + Felt::from_hex_unchecked("0x0800000000000010ffffffffffffffff80000000000000000000000000000001"); +const I128_MAX: Felt = + Felt::from_hex_unchecked("0x000000000000000000000000000000007fffffffffffffffffffffffffffffff"); + /// Any type where [`Felt`]s can be written into. This would typically be [`Vec`], but can /// also be something like a stateful hasher. /// @@ -175,6 +180,13 @@ impl Encode for U256 { } } +impl Encode for i128 { + fn encode(&self, writer: &mut W) -> Result<(), Error> { + writer.write((*self).into()); + Ok(()) + } +} + impl Encode for Option where T: Encode, @@ -343,6 +355,25 @@ impl<'a> Decode<'a> for U256 { } } +impl<'a> Decode<'a> for i128 { + fn decode_iter(iter: &mut T) -> Result + where + T: Iterator, + { + let input = iter.next().ok_or_else(Error::input_exhausted)?; + + if input <= &I128_MAX { + // Range checked. Safe to unwrap. + Ok(input.to_i128().unwrap()) + } else if input >= &I128_MIN { + // Range checked. Safe to unwrap. + Ok(Self::MIN + (input - I128_MIN).to_i128().unwrap()) + } else { + Err(Error::value_out_of_range(input, "i128")) + } + } +} + impl<'a, T> Decode<'a> for Option where T: Decode<'a>, @@ -553,6 +584,71 @@ mod tests { ); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_encode_i128() { + for (raw, felt) in [ + ( + 0i128, + Felt::from_hex_unchecked( + "0x0000000000000000000000000000000000000000000000000000000000000000", + ), + ), + ( + -1i128, + Felt::from_hex_unchecked( + "0x0800000000000011000000000000000000000000000000000000000000000000", + ), + ), + ( + 1i128, + Felt::from_hex_unchecked( + "0x0000000000000000000000000000000000000000000000000000000000000001", + ), + ), + ( + 10000i128, + Felt::from_hex_unchecked( + "0x0000000000000000000000000000000000000000000000000000000000002710", + ), + ), + ( + -10000i128, + Felt::from_hex_unchecked( + "0x0800000000000010ffffffffffffffffffffffffffffffffffffffffffffd8f1", + ), + ), + ( + i128::MIN, + Felt::from_hex_unchecked( + "0x0800000000000010ffffffffffffffff80000000000000000000000000000001", + ), + ), + ( + i128::MIN + 1, + Felt::from_hex_unchecked( + "0x0800000000000010ffffffffffffffff80000000000000000000000000000002", + ), + ), + ( + i128::MAX, + Felt::from_hex_unchecked( + "0x000000000000000000000000000000007fffffffffffffffffffffffffffffff", + ), + ), + ( + i128::MAX - 1, + Felt::from_hex_unchecked( + "0x000000000000000000000000000000007ffffffffffffffffffffffffffffffe", + ), + ), + ] { + let mut serialized = Vec::::new(); + raw.encode(&mut serialized).unwrap(); + assert_eq!(serialized, vec![felt]); + } + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_encode_u256() { @@ -817,6 +913,69 @@ mod tests { ); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_decode_i128() { + for (raw, felt) in [ + ( + 0i128, + Felt::from_hex_unchecked( + "0x0000000000000000000000000000000000000000000000000000000000000000", + ), + ), + ( + -1i128, + Felt::from_hex_unchecked( + "0x0800000000000011000000000000000000000000000000000000000000000000", + ), + ), + ( + 1i128, + Felt::from_hex_unchecked( + "0x0000000000000000000000000000000000000000000000000000000000000001", + ), + ), + ( + 10000i128, + Felt::from_hex_unchecked( + "0x0000000000000000000000000000000000000000000000000000000000002710", + ), + ), + ( + -10000i128, + Felt::from_hex_unchecked( + "0x0800000000000010ffffffffffffffffffffffffffffffffffffffffffffd8f1", + ), + ), + ( + i128::MIN, + Felt::from_hex_unchecked( + "0x0800000000000010ffffffffffffffff80000000000000000000000000000001", + ), + ), + ( + i128::MIN + 1, + Felt::from_hex_unchecked( + "0x0800000000000010ffffffffffffffff80000000000000000000000000000002", + ), + ), + ( + i128::MAX, + Felt::from_hex_unchecked( + "0x000000000000000000000000000000007fffffffffffffffffffffffffffffff", + ), + ), + ( + i128::MAX - 1, + Felt::from_hex_unchecked( + "0x000000000000000000000000000000007ffffffffffffffffffffffffffffffe", + ), + ), + ] { + assert_eq!(raw, i128::decode(&[felt]).unwrap()); + } + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_decode_u256() {