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
|
### 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)
|
- 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)
|
- 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)
|
- Add support for Geth `debug_traceTransaction` [#1469](https://github.com/gakonst/ethers-rs/pull/1469)
|
||||||
|
|
|
@ -356,6 +356,7 @@ impl Context {
|
||||||
param: &str,
|
param: &str,
|
||||||
kind: &ParamType,
|
kind: &ParamType,
|
||||||
) -> Result<TokenStream> {
|
) -> Result<TokenStream> {
|
||||||
|
let ethers_core = ethers_core_crate();
|
||||||
match kind {
|
match kind {
|
||||||
ParamType::Array(ty) => {
|
ParamType::Array(ty) => {
|
||||||
let ty = self.expand_input_param_type(fun, param, ty)?;
|
let ty = self.expand_input_param_type(fun, param, ty)?;
|
||||||
|
@ -364,7 +365,18 @@ impl Context {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ParamType::FixedArray(ty, size) => {
|
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;
|
let size = *size;
|
||||||
Ok(quote! {[#ty; #size]})
|
Ok(quote! {[#ty; #size]})
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,17 @@ pub(crate) fn expand(kind: &ParamType) -> Result<TokenStream> {
|
||||||
}
|
}
|
||||||
ParamType::FixedArray(t, n) => {
|
ParamType::FixedArray(t, n) => {
|
||||||
// TODO(nlordell): see above
|
// 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);
|
let size = Literal::usize_unsuffixed(*n);
|
||||||
Ok(quote! { [#inner; #size] })
|
Ok(quote! { [#inner; #size] })
|
||||||
}
|
}
|
||||||
|
|
|
@ -679,3 +679,13 @@ fn can_generate_large_output_struct() {
|
||||||
|
|
||||||
let r = GetByIdReturn(Info::default());
|
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::{
|
abi::{
|
||||||
AbiArrayType, AbiError, AbiType, Detokenize, Token, Tokenizable, TokenizableItem, Tokenize,
|
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
|
/// Trait for ABI encoding
|
||||||
|
@ -65,6 +65,7 @@ impl_abi_codec!(
|
||||||
U128,
|
U128,
|
||||||
U256,
|
U256,
|
||||||
I256,
|
I256,
|
||||||
|
Uint8,
|
||||||
u8,
|
u8,
|
||||||
u16,
|
u16,
|
||||||
u32,
|
u32,
|
||||||
|
@ -279,4 +280,24 @@ mod tests {
|
||||||
let encoded = value.encode();
|
let encoded = value.encode();
|
||||||
assert_eq!(value, String::decode(encoded).unwrap());
|
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
|
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.
|
//! 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)
|
// Adapted from [Gnosis' ethcontract](https://github.com/gnosis/ethcontract-rs/blob/master/common/src/abiext.rs)
|
||||||
use crate::{
|
use crate::{
|
||||||
types::{Bytes, Selector},
|
types::{Bytes, Selector, Uint8, H256, H512, I256, U128, U256, U64},
|
||||||
utils::id,
|
utils::id,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use ethabi::{self, Contract as Abi, *};
|
pub use ethabi::{self, Contract as Abi, *};
|
||||||
|
|
||||||
mod tokens;
|
mod tokens;
|
||||||
|
@ -23,9 +22,6 @@ mod human_readable;
|
||||||
pub use human_readable::{
|
pub use human_readable::{
|
||||||
lexer::HumanReadableParser, parse as parse_abi, parse_str as parse_abi_str, AbiParser,
|
lexer::HumanReadableParser, parse as parse_abi, parse_str as parse_abi_str, AbiParser,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::types::{H256, H512, I256, U128, U256, U64};
|
|
||||||
|
|
||||||
mod sealed {
|
mod sealed {
|
||||||
use ethabi::{Event, Function};
|
use ethabi::{Event, Function};
|
||||||
|
|
||||||
|
@ -166,6 +162,7 @@ impl_abi_type!(
|
||||||
str => String,
|
str => String,
|
||||||
H256 => FixedBytes(32),
|
H256 => FixedBytes(32),
|
||||||
H512 => FixedBytes(64),
|
H512 => FixedBytes(64),
|
||||||
|
Uint8 => Uint(8),
|
||||||
U64 => Uint(64),
|
U64 => Uint(64),
|
||||||
U128 => Uint(128),
|
U128 => Uint(128),
|
||||||
U256 => Uint(256),
|
U256 => Uint(256),
|
||||||
|
|
|
@ -24,6 +24,9 @@ pub use path_or_string::PathOrString;
|
||||||
mod u256;
|
mod u256;
|
||||||
pub use u256::*;
|
pub use u256::*;
|
||||||
|
|
||||||
|
mod uint8;
|
||||||
|
pub use uint8::*;
|
||||||
|
|
||||||
mod i256;
|
mod i256;
|
||||||
pub use i256::{Sign, 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