fix(codec)!: ambiguity unit8[] and bytes (#613)

* fix: unit8 encoding

* feat: use ethers::types::Bytes for solidity bytes type

* feat: add const generic from impls

* fix: failing tests

* fix: make compatible with bytes

* update changelog

* make compatible with encoding changes

* chore rm write to file
This commit is contained in:
Matthias Seitz 2021-11-24 21:15:17 +01:00 committed by GitHub
parent 3a768b9c99
commit 2c30468b70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 47 additions and 21 deletions

View File

@ -2,6 +2,8 @@
## ethers-core ## ethers-core
- Change types mapping for solidity `bytes` to rust `ethers::core::Bytes` and solidity `uint8[]` to rust `Vec<u8>`.
[613](https://github.com/gakonst/ethers-rs/pull/613)
- Fix `format_units` to return a `String` of representing a decimal point float - Fix `format_units` to return a `String` of representing a decimal point float
such that the decimal places don't get truncated. such that the decimal places don't get truncated.
[597](https://github.com/gakonst/ethers-rs/pull/597) [597](https://github.com/gakonst/ethers-rs/pull/597)

View File

@ -8,7 +8,7 @@ pub(crate) fn expand(kind: &ParamType) -> Result<TokenStream> {
match kind { match kind {
ParamType::Address => Ok(quote! { #ethers_core::types::Address }), ParamType::Address => Ok(quote! { #ethers_core::types::Address }),
ParamType::Bytes => Ok(quote! { Vec<u8> }), ParamType::Bytes => Ok(quote! { #ethers_core::types::Bytes }),
ParamType::Int(n) => match n / 8 { ParamType::Int(n) => match n / 8 {
1 => Ok(quote! { i8 }), 1 => Ok(quote! { i8 }),
2 => Ok(quote! { i16 }), 2 => Ok(quote! { i16 }),

View File

@ -297,7 +297,7 @@ impl<M: Middleware> Multicall<M> {
.iter() .iter()
.zip(&return_data) .zip(&return_data)
.map(|(call, bytes)| { .map(|(call, bytes)| {
let mut tokens: Vec<Token> = call.function.decode_output(bytes)?; let mut tokens: Vec<Token> = call.function.decode_output(bytes.as_ref())?;
Ok(match tokens.len() { Ok(match tokens.len() {
0 => Token::Tuple(vec![]), 0 => Token::Tuple(vec![]),
@ -343,10 +343,10 @@ impl<M: Middleware> Multicall<M> {
Ok(tx_hash) Ok(tx_hash)
} }
fn as_contract_call(&self) -> ContractCall<M, (U256, Vec<Vec<u8>>)> { fn as_contract_call(&self) -> ContractCall<M, (U256, Vec<Bytes>)> {
// Map the Multicall struct into appropriate types for `aggregate` function // Map the Multicall struct into appropriate types for `aggregate` function
let calls: Vec<(Address, Vec<u8>)> = let calls: Vec<(Address, Bytes)> =
self.calls.iter().map(|call| (call.target, call.data.to_vec())).collect(); self.calls.iter().map(|call| (call.target, call.data.clone())).collect();
// Construct the ContractCall for `aggregate` function to broadcast the transaction // Construct the ContractCall for `aggregate` function to broadcast the transaction
let mut contract_call = self.contract.aggregate(calls); let mut contract_call = self.contract.aggregate(calls);

View File

@ -41,8 +41,8 @@ mod multicallcontract_mod {
#[doc = "Calls the contract's `aggregate` (0x252dba42) function"] #[doc = "Calls the contract's `aggregate` (0x252dba42) function"]
pub fn aggregate( pub fn aggregate(
&self, &self,
calls: Vec<(Address, Vec<u8>)>, calls: Vec<(Address, Bytes)>,
) -> ContractCall<M, (U256, Vec<Vec<u8>>)> { ) -> ContractCall<M, (U256, Vec<Bytes>)> {
self.0 self.0
.method_hash([37, 45, 186, 66], calls) .method_hash([37, 45, 186, 66], calls)
.expect("method not found (this should never happen)") .expect("method not found (this should never happen)")

View File

@ -9,7 +9,7 @@ mod eth_tests {
use super::*; use super::*;
use ethers_contract::{LogMeta, Multicall}; use ethers_contract::{LogMeta, Multicall};
use ethers_core::{ use ethers_core::{
types::{transaction::eip712::Eip712, Address, BlockId, I256, U256}, types::{transaction::eip712::Eip712, Address, BlockId, Bytes, I256, U256},
utils::{keccak256, Ganache}, utils::{keccak256, Ganache},
}; };
use ethers_derive_eip712::*; use ethers_derive_eip712::*;
@ -525,7 +525,7 @@ mod eth_tests {
struct FooBar { struct FooBar {
foo: I256, foo: I256,
bar: U256, bar: U256,
fizz: Vec<u8>, fizz: Bytes,
buzz: [u8; 32], buzz: [u8; 32],
far: String, far: String,
out: Address, out: Address,
@ -563,7 +563,7 @@ mod eth_tests {
let foo_bar = FooBar { let foo_bar = FooBar {
foo: I256::from(10), foo: I256::from(10),
bar: U256::from(20), bar: U256::from(20),
fizz: b"fizz".to_vec(), fizz: b"fizz".into(),
buzz: keccak256("buzz"), buzz: keccak256("buzz"),
far: String::from("space"), far: String::from("space"),
out: Address::from([0; 20]), out: Address::from([0; 20]),

View File

@ -18,6 +18,6 @@ serde_json = "1.0.68"
proc-macro2 = "1.0.29" proc-macro2 = "1.0.29"
[dev-dependencies] [dev-dependencies]
ethers-contract = { version = "^0.6.0", path = "../../ethers-contract"} ethers-contract = { version = "^0.6.0", path = "../../ethers-contract", features = ["abigen"]}
ethers-contract-derive = { version = "^0.6.0", path = "../../ethers-contract/ethers-contract-derive" } ethers-contract-derive = { version = "^0.6.0", path = "../../ethers-contract/ethers-contract-derive" }
ethers-signers = { version = "^0.6.0", path = "../../ethers-signers" } ethers-signers = { version = "^0.6.0", path = "../../ethers-signers" }

View File

@ -18,7 +18,7 @@
//! //!
//! # Example Usage //! # Example Usage
//! //!
//! ```rust //! ```ignore
//! use ethers_contract::EthAbiType; //! use ethers_contract::EthAbiType;
//! use ethers_derive_eip712::*; //! use ethers_derive_eip712::*;
//! use ethers_core::types::{transaction::eip712::Eip712, H160}; //! use ethers_core::types::{transaction::eip712::Eip712, H160};
@ -50,7 +50,7 @@
//! project: "radicle-reward".to_string(), //! project: "radicle-reward".to_string(),
//! }; //! };
//! //!
//! let hash = puzzle.encode_eip712()?; //! let hash = puzzle.encode_eip712().unwrap();
//! ``` //! ```
//! //!
//! # Limitations //! # Limitations

View File

@ -1,6 +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::{types::Selector, utils::id}; use crate::{
types::{Bytes, Selector},
utils::id,
};
pub use ethabi::{Contract as Abi, *}; pub use ethabi::{Contract as Abi, *};
@ -117,7 +120,8 @@ macro_rules! impl_abi_type {
} }
impl_abi_type!( impl_abi_type!(
Vec<u8> => Bytes, Bytes => Bytes,
Vec<u8> => Array(Box::new(ParamType::Uint(8))),
Address => Address, Address => Address,
bool => Bool, bool => Bool,
String => String, String => String,
@ -231,10 +235,17 @@ mod tests {
#[test] #[test]
fn abi_type_works() { fn abi_type_works() {
assert_eq!(ParamType::Bytes, Vec::<u8>::param_type()); assert_eq!(ParamType::Bytes, Bytes::param_type());
assert_eq!(ParamType::Array(Box::new(ParamType::Bytes)), Vec::<Vec<u8>>::param_type()); assert_eq!(ParamType::Array(Box::new(ParamType::Uint(8))), Vec::<u8>::param_type());
assert_eq!(ParamType::Array(Box::new(ParamType::Bytes)), Vec::<Bytes>::param_type());
assert_eq!( assert_eq!(
ParamType::Array(Box::new(ParamType::Array(Box::new(ParamType::Bytes)))), ParamType::Array(Box::new(ParamType::Array(Box::new(ParamType::Uint(8))))),
Vec::<Vec<u8>>::param_type()
);
assert_eq!(
ParamType::Array(Box::new(ParamType::Array(Box::new(ParamType::Array(Box::new(
ParamType::Uint(8)
)))))),
Vec::<Vec<Vec<u8>>>::param_type() Vec::<Vec<Vec<u8>>>::param_type()
); );
@ -242,7 +253,7 @@ mod tests {
assert_eq!( assert_eq!(
ParamType::Tuple(vec![ParamType::Bytes, ParamType::Address]), ParamType::Tuple(vec![ParamType::Bytes, ParamType::Address]),
<(Vec<u8>, Address)>::param_type() <(Bytes, Address)>::param_type()
); );
assert_eq!(ParamType::FixedBytes(32), <[u8; 32]>::param_type()); assert_eq!(ParamType::FixedBytes(32), <[u8; 32]>::param_type());

View File

@ -287,7 +287,7 @@ macro_rules! tokenizable_item {
tokenizable_item! { tokenizable_item! {
Token, String, Address, H256, U256, I256, U128, bool, Vec<u8>, Token, String, Address, H256, U256, I256, U128, bool, Vec<u8>,
i8, i16, i32, i64, i128, u16, u32, u64, u128, i8, i16, i32, i64, i128, u16, u32, u64, u128, Bytes,
} }
macro_rules! impl_tokenizable_item_tuple { macro_rules! impl_tokenizable_item_tuple {
@ -321,12 +321,13 @@ impl Tokenizable for Vec<u8> {
fn from_token(token: Token) -> Result<Self, InvalidOutputType> { fn from_token(token: Token) -> Result<Self, InvalidOutputType> {
match token { match token {
Token::Bytes(data) => Ok(data), Token::Bytes(data) => Ok(data),
Token::Array(data) => data.into_iter().map(u8::from_token).collect(),
Token::FixedBytes(data) => Ok(data), Token::FixedBytes(data) => Ok(data),
other => Err(InvalidOutputType(format!("Expected `bytes`, got {:?}", other))), other => Err(InvalidOutputType(format!("Expected `bytes`, got {:?}", other))),
} }
} }
fn into_token(self) -> Token { fn into_token(self) -> Token {
Token::Bytes(self) Token::Array(self.into_iter().map(Tokenizable::into_token).collect())
} }
} }

View File

@ -34,6 +34,18 @@ impl From<Vec<u8>> for Bytes {
} }
} }
impl<const N: usize> From<[u8; N]> for Bytes {
fn from(src: [u8; N]) -> Self {
src.to_vec().into()
}
}
impl<'a, const N: usize> From<&'a [u8; N]> for Bytes {
fn from(src: &'a [u8; N]) -> Self {
src.to_vec().into()
}
}
pub fn serialize_bytes<S, T>(x: T, s: S) -> Result<S::Ok, S::Error> pub fn serialize_bytes<S, T>(x: T, s: S) -> Result<S::Ok, S::Error>
where where
S: Serializer, S: Serializer,