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
- 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
such that the decimal places don't get truncated.
[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 {
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 {
1 => Ok(quote! { i8 }),
2 => Ok(quote! { i16 }),

View File

@ -297,7 +297,7 @@ impl<M: Middleware> Multicall<M> {
.iter()
.zip(&return_data)
.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() {
0 => Token::Tuple(vec![]),
@ -343,10 +343,10 @@ impl<M: Middleware> Multicall<M> {
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
let calls: Vec<(Address, Vec<u8>)> =
self.calls.iter().map(|call| (call.target, call.data.to_vec())).collect();
let calls: Vec<(Address, Bytes)> =
self.calls.iter().map(|call| (call.target, call.data.clone())).collect();
// Construct the ContractCall for `aggregate` function to broadcast the transaction
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"]
pub fn aggregate(
&self,
calls: Vec<(Address, Vec<u8>)>,
) -> ContractCall<M, (U256, Vec<Vec<u8>>)> {
calls: Vec<(Address, Bytes)>,
) -> ContractCall<M, (U256, Vec<Bytes>)> {
self.0
.method_hash([37, 45, 186, 66], calls)
.expect("method not found (this should never happen)")

View File

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

View File

@ -18,6 +18,6 @@ serde_json = "1.0.68"
proc-macro2 = "1.0.29"
[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-signers = { version = "^0.6.0", path = "../../ethers-signers" }

View File

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

View File

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

View File

@ -287,7 +287,7 @@ macro_rules! tokenizable_item {
tokenizable_item! {
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 {
@ -321,12 +321,13 @@ impl Tokenizable for Vec<u8> {
fn from_token(token: Token) -> Result<Self, InvalidOutputType> {
match token {
Token::Bytes(data) => Ok(data),
Token::Array(data) => data.into_iter().map(u8::from_token).collect(),
Token::FixedBytes(data) => Ok(data),
other => Err(InvalidOutputType(format!("Expected `bytes`, got {:?}", other))),
}
}
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>
where
S: Serializer,