feat: add uint8 type (#1639)
* feat: add uint8 type * update changelog * derive default * fix: failing test
This commit is contained in:
parent
6c017990a1
commit
0b04ffe787
|
@ -4,6 +4,7 @@
|
|||
|
||||
### Unreleased
|
||||
|
||||
- Add `Unit8` helper type [#1639](https://github.com/gakonst/ethers-rs/pull/1639)
|
||||
- Add `evm.deployedBytecode.immutableReferences` output selector [#1523](https://github.com/gakonst/ethers-rs/pull/1523)
|
||||
- Added `get_erc1155_token_transfer_events` function for etherscan client [#1503](https://github.com/gakonst/ethers-rs/pull/1503)
|
||||
- Add support for Geth `debug_traceTransaction` [#1469](https://github.com/gakonst/ethers-rs/pull/1469)
|
||||
|
|
|
@ -356,6 +356,7 @@ impl Context {
|
|||
param: &str,
|
||||
kind: &ParamType,
|
||||
) -> Result<TokenStream> {
|
||||
let ethers_core = ethers_core_crate();
|
||||
match kind {
|
||||
ParamType::Array(ty) => {
|
||||
let ty = self.expand_input_param_type(fun, param, ty)?;
|
||||
|
@ -364,7 +365,18 @@ impl Context {
|
|||
})
|
||||
}
|
||||
ParamType::FixedArray(ty, size) => {
|
||||
let ty = self.expand_input_param_type(fun, param, ty)?;
|
||||
let ty = match **ty {
|
||||
ParamType::Uint(size) => {
|
||||
if size / 8 == 1 {
|
||||
// this prevents type ambiguity with `FixedBytes`
|
||||
quote! { #ethers_core::types::Uint8}
|
||||
} else {
|
||||
self.expand_input_param_type(fun, param, ty)?
|
||||
}
|
||||
}
|
||||
_ => self.expand_input_param_type(fun, param, ty)?,
|
||||
};
|
||||
|
||||
let size = *size;
|
||||
Ok(quote! {[#ty; #size]})
|
||||
}
|
||||
|
|
|
@ -41,7 +41,17 @@ pub(crate) fn expand(kind: &ParamType) -> Result<TokenStream> {
|
|||
}
|
||||
ParamType::FixedArray(t, n) => {
|
||||
// TODO(nlordell): see above
|
||||
let inner = expand(t)?;
|
||||
let inner = match **t {
|
||||
ParamType::Uint(size) => {
|
||||
if size / 8 == 1 {
|
||||
// this prevents type ambiguity with `FixedBytes`
|
||||
quote! { #ethers_core::types::Uint8}
|
||||
} else {
|
||||
expand(t)?
|
||||
}
|
||||
}
|
||||
_ => expand(t)?,
|
||||
};
|
||||
let size = Literal::usize_unsuffixed(*n);
|
||||
Ok(quote! { [#inner; #size] })
|
||||
}
|
||||
|
|
|
@ -679,3 +679,13 @@ fn can_generate_large_output_struct() {
|
|||
|
||||
let r = GetByIdReturn(Info::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gen_complex_function() {
|
||||
abigen!(
|
||||
WyvernExchangeV1,
|
||||
r#"[
|
||||
function atomicMatch_(address[14] addrs, uint[18] uints, uint8[8] feeMethodsSidesKindsHowToCalls, bytes calldataBuy, bytes calldataSell, bytes replacementPatternBuy, bytes replacementPatternSell, bytes staticExtradataBuy, bytes staticExtradataSell, uint8[2] vs, bytes32[5] rssMetadata) public payable
|
||||
]"#,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
abi::{
|
||||
AbiArrayType, AbiError, AbiType, Detokenize, Token, Tokenizable, TokenizableItem, Tokenize,
|
||||
},
|
||||
types::{Address, Bytes, H256, I256, U128, U256},
|
||||
types::{Address, Bytes, Uint8, H256, I256, U128, U256},
|
||||
};
|
||||
|
||||
/// Trait for ABI encoding
|
||||
|
@ -65,6 +65,7 @@ impl_abi_codec!(
|
|||
U128,
|
||||
U256,
|
||||
I256,
|
||||
Uint8,
|
||||
u8,
|
||||
u16,
|
||||
u32,
|
||||
|
@ -279,4 +280,24 @@ mod tests {
|
|||
let encoded = value.encode();
|
||||
assert_eq!(value, String::decode(encoded).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_decode_array_of_fixed_uint8() {
|
||||
// uint8[8]
|
||||
let tokens = vec![Token::FixedArray(vec![
|
||||
Token::Uint(1.into()),
|
||||
Token::Uint(2.into()),
|
||||
Token::Uint(3.into()),
|
||||
Token::Uint(4.into()),
|
||||
Token::Uint(5.into()),
|
||||
Token::Uint(6.into()),
|
||||
Token::Uint(7.into()),
|
||||
Token::Uint(8.into()),
|
||||
])];
|
||||
let data: [Uint8; 8] = Detokenize::from_tokens(tokens).unwrap();
|
||||
assert_eq!(data[0], 1);
|
||||
assert_eq!(data[1], 2);
|
||||
assert_eq!(data[2], 3);
|
||||
assert_eq!(data[7], 8);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1218,4 +1218,11 @@ mod tests {
|
|||
event
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_large_function() {
|
||||
let f = "function atomicMatch_(address[14] addrs, uint[18] uints, uint8[8] feeMethodsSidesKindsHowToCalls, bytes calldataBuy, bytes calldataSell, bytes replacementPatternBuy, bytes replacementPatternSell, bytes staticExtradataBuy, bytes staticExtradataSell, uint8[2] vs, bytes32[5] rssMetadata) public payable";
|
||||
|
||||
let _fun = HumanReadableParser::parse_function(f).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
//! This module implements extensions to the [`ethabi`](https://docs.rs/ethabi) API.
|
||||
// Adapted from [Gnosis' ethcontract](https://github.com/gnosis/ethcontract-rs/blob/master/common/src/abiext.rs)
|
||||
use crate::{
|
||||
types::{Bytes, Selector},
|
||||
types::{Bytes, Selector, Uint8, H256, H512, I256, U128, U256, U64},
|
||||
utils::id,
|
||||
};
|
||||
|
||||
pub use ethabi::{self, Contract as Abi, *};
|
||||
|
||||
mod tokens;
|
||||
|
@ -23,9 +22,6 @@ mod human_readable;
|
|||
pub use human_readable::{
|
||||
lexer::HumanReadableParser, parse as parse_abi, parse_str as parse_abi_str, AbiParser,
|
||||
};
|
||||
|
||||
use crate::types::{H256, H512, I256, U128, U256, U64};
|
||||
|
||||
mod sealed {
|
||||
use ethabi::{Event, Function};
|
||||
|
||||
|
@ -166,6 +162,7 @@ impl_abi_type!(
|
|||
str => String,
|
||||
H256 => FixedBytes(32),
|
||||
H512 => FixedBytes(64),
|
||||
Uint8 => Uint(8),
|
||||
U64 => Uint(64),
|
||||
U128 => Uint(128),
|
||||
U256 => Uint(256),
|
||||
|
|
|
@ -24,6 +24,9 @@ pub use path_or_string::PathOrString;
|
|||
mod u256;
|
||||
pub use u256::*;
|
||||
|
||||
mod uint8;
|
||||
pub use uint8::*;
|
||||
|
||||
mod i256;
|
||||
pub use i256::{Sign, I256};
|
||||
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
//! This module contains a helper type for `uint8`
|
||||
//!
|
||||
//! The reason this exists is to circumvent ambiguity with fixed bytes arrays
|
||||
|
||||
use crate::abi::{InvalidOutputType, Tokenizable, TokenizableItem};
|
||||
use ethabi::{ethereum_types::U256, Token};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::{Add, Sub};
|
||||
|
||||
/// A wrapper for `u8`
|
||||
///
|
||||
/// Note: this type is only necessary in conjunction with `FixedBytes` so that `[Uint8; 8]` is
|
||||
/// recognized as `uint8[8]` and not fixed bytes.
|
||||
///
|
||||
/// See also <https://github.com/gakonst/ethers-rs/issues/1636>
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default, Ord, PartialOrd)]
|
||||
#[repr(transparent)]
|
||||
#[serde(transparent)]
|
||||
pub struct Uint8(u8);
|
||||
|
||||
impl From<u8> for Uint8 {
|
||||
fn from(val: u8) -> Self {
|
||||
Uint8(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Uint8> for u8 {
|
||||
fn from(val: Uint8) -> Self {
|
||||
val.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Uint8> for U256 {
|
||||
fn from(val: Uint8) -> Self {
|
||||
U256::from(val.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<u8> for Uint8 {
|
||||
fn eq(&self, other: &u8) -> bool {
|
||||
self.0 == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Uint8 {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Uint8(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Uint8 {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Uint8(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<u8> for Uint8 {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: u8) -> Self::Output {
|
||||
Uint8(self.0 + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<u8> for Uint8 {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: u8) -> Self::Output {
|
||||
Uint8(self.0 - rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Tokenizable for Uint8 {
|
||||
fn from_token(token: Token) -> Result<Self, InvalidOutputType> {
|
||||
match token {
|
||||
Token::Int(data) | Token::Uint(data) => {
|
||||
if data > U256::from(u8::MAX) {
|
||||
return Err(InvalidOutputType("Integer overflow when casting to u8".to_string()))
|
||||
}
|
||||
Ok(Uint8(data.low_u32() as u8))
|
||||
}
|
||||
other => Err(InvalidOutputType(format!("Expected `uint8`, got {:?}", other))),
|
||||
}
|
||||
}
|
||||
fn into_token(self) -> Token {
|
||||
Token::Uint(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TokenizableItem for Uint8 {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::abi::AbiType;
|
||||
use ethabi::ParamType;
|
||||
|
||||
#[test]
|
||||
fn uint8_array() {
|
||||
assert_eq!(
|
||||
<[Uint8; 8usize]>::param_type(),
|
||||
ParamType::FixedArray(Box::new(ParamType::Uint(8),), 8)
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue