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:
parent
3a768b9c99
commit
2c30468b70
|
@ -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)
|
||||||
|
|
|
@ -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 }),
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)")
|
||||||
|
|
|
@ -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]),
|
||||||
|
|
|
@ -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" }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue