Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abiv2 #468

Merged
merged 2 commits into from
Mar 24, 2021
Merged

Abiv2 #468

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ethcontract-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Common types for ethcontract-rs runtime and proc macro.
"""

[dependencies]
ethabi = "13.0"
ethabi-fork-ethcontract = "13.0"
hex = "0.4"
serde = "1.0"
serde_derive = "1.0"
Expand Down
2 changes: 1 addition & 1 deletion ethcontract-common/src/abiext.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! This module implements extensions to the `ethabi` API.

use crate::abi::{Event, Function, ParamType};
use crate::errors::ParseParamTypeError;
use crate::hash::{self, H32};
use ethabi::{Event, Function, ParamType};
use serde_json::json;

/// Extension trait for `ethabi::Function`.
Expand Down
2 changes: 1 addition & 1 deletion ethcontract-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub mod truffle;
pub use crate::abiext::FunctionExt;
pub use crate::bytecode::Bytecode;
pub use crate::truffle::Artifact;
pub use ethabi::{self as abi, Contract as Abi};
pub use ethabi_fork_ethcontract::{self as abi, Contract as Abi};
use serde::Deserialize;
pub use web3::types::Address;
pub use web3::types::H256 as TransactionHash;
Expand Down
3 changes: 2 additions & 1 deletion ethcontract-common/src/truffle.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Module for reading and examining data produced by truffle.

use crate::abi::Contract as Abi;
use crate::errors::ArtifactError;
use crate::{bytecode::Bytecode, DeploymentInformation};
use ethabi::Contract as Abi;
use serde::Deserialize;
use std::collections::HashMap;
use std::fs::File;
Expand Down Expand Up @@ -39,6 +39,7 @@ impl Artifact {
functions: HashMap::new(),
events: HashMap::new(),
fallback: false,
receive: false,
},
bytecode: Default::default(),
networks: HashMap::new(),
Expand Down
2 changes: 2 additions & 0 deletions ethcontract-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ impl Parse for Method {
})
.collect::<ParseResult<Vec<_>>>()?;

#[allow(deprecated)]
nlordell marked this conversation as resolved.
Show resolved Hide resolved
Function {
name,
inputs,
Expand All @@ -350,6 +351,7 @@ impl Parse for Method {
// affect its signature.
outputs: vec![],
constant: false,
state_mutability: Default::default(),
vkgnosis marked this conversation as resolved.
Show resolved Hide resolved
}
};
let signature = function.abi_signature();
Expand Down
38 changes: 10 additions & 28 deletions ethcontract-generate/src/contract/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ fn expand_data_type(event: &Event, event_derives: &[Path]) -> Result<TokenStream
let abi_signature_doc = util::expand_doc(&format!("`{}`", abi_signature));

let params = expand_params(event)?;
let param_names = params.iter().map(|param| &param.0);

let all_anonymous_fields = event.inputs.iter().all(|input| input.name.is_empty());
let (data_type_definition, data_type_construction) = if all_anonymous_fields {
Expand All @@ -68,17 +69,6 @@ fn expand_data_type(event: &Event, event_derives: &[Path]) -> Result<TokenStream
expand_data_struct(&event_name, &params)
};

let params_len = Literal::usize_unsuffixed(params.len());
let read_param_token = params
.iter()
.map(|(name, ty)| {
quote! {
let #name = <#ty as self::ethcontract::web3::contract::tokens::Tokenizable>
::from_token(tokens.next().unwrap())?;
}
})
.collect::<Vec<_>>();

let derives = expand_derives(event_derives);

Ok(quote! {
Expand All @@ -102,25 +92,17 @@ fn expand_data_type(event: &Event, event_derives: &[Path]) -> Result<TokenStream
}
}

impl self::ethcontract::web3::contract::tokens::Detokenize for #event_name {
fn from_tokens(
tokens: Vec<self::ethcontract::common::abi::Token>,
) -> Result<Self, self::ethcontract::web3::contract::Error> {
if tokens.len() != #params_len {
return Err(self::ethcontract::web3::contract::Error::InvalidOutputType(format!(
"Expected {} tokens, got {}: {:?}",
#params_len,
tokens.len(),
tokens
)));
}

#[allow(unused_mut)]
let mut tokens = tokens.into_iter();
#( #read_param_token )*

impl self::ethcontract::tokens::Tokenize for #event_name {
fn from_token(
token: self::ethcontract::common::abi::Token,
) -> Result<Self, self::ethcontract::tokens::Error> {
let (#(#param_names,)*) = self::ethcontract::tokens::Tokenize::from_token(token)?;
Ok(#data_type_construction)
}

fn into_token(self) -> self::ethcontract::common::abi::Token {
unimplemented!("events are only decoded, not encoded")
}
}
})
}
Expand Down
21 changes: 9 additions & 12 deletions ethcontract-generate/src/contract/methods.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::contract::{types, Context};
use crate::util;
use anyhow::{anyhow, Context as _, Result};
use ethcontract_common::abi::{Function, Param};
use ethcontract_common::abi::{Function, Param, StateMutability};
use ethcontract_common::abiext::FunctionExt;
use ethcontract_common::hash::H32;
use inflector::Inflector;
Expand Down Expand Up @@ -104,10 +104,11 @@ fn expand_function(cx: &Context, function: &Function, alias: Option<Ident>) -> R

let input = expand_inputs(&function.inputs)?;
let outputs = expand_fn_outputs(&function.outputs)?;
let (method, result_type_name) = if function.constant {
(quote! { view_method }, quote! { DynViewMethodBuilder })
} else {
(quote! { method }, quote! { DynMethodBuilder })
let (method, result_type_name) = match function.state_mutability {
StateMutability::Pure | StateMutability::View => {
(quote! { view_method }, quote! { DynViewMethodBuilder })
}
_ => (quote! { method }, quote! { DynMethodBuilder }),
};
let result = quote! { self::ethcontract::dyns::#result_type_name<#outputs> };
let arg = expand_inputs_call_arg(&function.inputs);
Expand Down Expand Up @@ -144,7 +145,7 @@ pub(crate) fn expand_inputs_call_arg(inputs: &[Param]) -> TokenStream {

fn expand_fn_outputs(outputs: &[Param]) -> Result<TokenStream> {
match outputs.len() {
0 => Ok(quote! { self::ethcontract::Void }),
0 => Ok(quote! { () }),
vkgnosis marked this conversation as resolved.
Show resolved Hide resolved
1 => types::expand(&outputs[0].kind),
_ => {
let types = outputs
Expand All @@ -169,9 +170,7 @@ fn expand_fallback(cx: &Context) -> TokenStream {
impl Contract {
/// Returns a method builder to setup a call to a smart
/// contract's fallback function.
pub fn fallback<D>(&self, data: D) -> self::ethcontract::dyns::DynMethodBuilder<
self::ethcontract::Void,
>
pub fn fallback<D>(&self, data: D) -> self::ethcontract::dyns::DynMethodBuilder<()>
where
D: Into<Vec<u8>>,
{
Expand Down Expand Up @@ -218,9 +217,7 @@ mod tests {

#[test]
fn expand_fn_outputs_empty() {
assert_quote!(expand_fn_outputs(&[],).unwrap(), {
self::ethcontract::Void
});
assert_quote!(expand_fn_outputs(&[],).unwrap(), { () });
}

#[test]
Expand Down
5 changes: 4 additions & 1 deletion ethcontract-generate/src/contract/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ pub(crate) fn expand(kind: &ParamType) -> Result<TokenStream> {
let size = Literal::usize_unsuffixed(*n);
Ok(quote! { [#inner; #size] })
}
ParamType::Tuple(_) => Err(anyhow!("ABIEncoderV2 is currently not supported")),
ParamType::Tuple(t) => {
let inner = t.iter().map(expand).collect::<Result<Vec<_>>>()?;
vkgnosis marked this conversation as resolved.
Show resolved Hide resolved
Ok(quote! { (#(#inner,)*) })
}
}
}
1 change: 1 addition & 0 deletions ethcontract/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ ws-tokio = ["web3/ws-tokio"]
ws-tls-tokio = ["web3/ws-tls-tokio"]

[dependencies]
arrayvec = "0.5"
nlordell marked this conversation as resolved.
Show resolved Hide resolved
ethcontract-common = { version = "0.11.3", path = "../ethcontract-common" }
ethcontract-derive = { version = "0.11.3", path = "../ethcontract-derive", optional = true}
futures = "0.3"
Expand Down
22 changes: 14 additions & 8 deletions ethcontract/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ mod deploy;
mod event;
mod method;

use crate::errors::{DeployError, LinkError};
use crate::{
errors::{DeployError, LinkError},
tokens::Tokenize,
};
use ethcontract_common::abi::{Error as AbiError, Result as AbiResult};
use ethcontract_common::abiext::FunctionExt;
use ethcontract_common::hash::H32;
use ethcontract_common::{Abi, Artifact, Bytecode, DeploymentInformation};
use std::collections::HashMap;
use std::hash::Hash;
use web3::api::Web3;
use web3::contract::tokens::{Detokenize, Tokenize};
use web3::types::{Address, Bytes, H256};
use web3::Transport;

Expand All @@ -23,7 +25,7 @@ pub use self::event::{
AllEventsBuilder, Event, EventBuilder, EventMetadata, EventStatus, ParseLog, RawLog,
StreamEvent, Topic,
};
pub use self::method::{Detokenizable, MethodBuilder, MethodDefaults, ViewMethodBuilder, Void};
pub use self::method::{MethodBuilder, MethodDefaults, ViewMethodBuilder};

/// Represents a contract instance at an address. Provides methods for
/// contract interaction.
Expand Down Expand Up @@ -164,15 +166,19 @@ impl<T: Transport> Instance<T> {
pub fn method<P, R>(&self, signature: H32, params: P) -> AbiResult<MethodBuilder<T, R>>
where
P: Tokenize,
R: Detokenizable,
R: Tokenize,
{
let signature = signature.as_ref();
let function = self
.methods
.get(signature)
.map(|(name, index)| &self.abi.functions[name][*index])
.ok_or_else(|| AbiError::InvalidName(hex::encode(&signature)))?;
let data = function.encode_input(&params.into_tokens())?;
let tokens = match params.into_token() {
ethcontract_common::abi::Token::Tuple(tokens) => tokens,
_ => unreachable!("function arguments are always tuples"),
};
let data = function.encode_input(&tokens)?;

// take ownership here as it greatly simplifies dealing with futures
// lifetime as it would require the contract Instance to live until
Expand All @@ -192,7 +198,7 @@ impl<T: Transport> Instance<T> {
pub fn view_method<P, R>(&self, signature: H32, params: P) -> AbiResult<ViewMethodBuilder<T, R>>
where
P: Tokenize,
R: Detokenizable,
R: Tokenize,
{
Ok(self.method(signature, params)?.view())
}
Expand All @@ -202,7 +208,7 @@ impl<T: Transport> Instance<T> {
///
/// This method will error if the ABI does not contain an entry for a
/// fallback function.
pub fn fallback<D>(&self, data: D) -> AbiResult<MethodBuilder<T, Void>>
pub fn fallback<D>(&self, data: D) -> AbiResult<MethodBuilder<T, ()>>
where
D: Into<Vec<u8>>,
{
Expand All @@ -221,7 +227,7 @@ impl<T: Transport> Instance<T> {
/// that emits events for the specified Solidity event by name.
pub fn event<E>(&self, signature: H256) -> AbiResult<EventBuilder<T, E>>
where
E: Detokenize,
E: Tokenize,
{
let event = self
.events
Expand Down
7 changes: 5 additions & 2 deletions ethcontract/src/contract/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
//! new contracts.

use crate::errors::{DeployError, ExecutionError};
use crate::tokens::Tokenize;
use crate::transaction::{Account, GasPrice, TransactionBuilder, TransactionResult};
use ethcontract_common::abi::Error as AbiError;
use ethcontract_common::{Abi, Bytecode};
use std::marker::PhantomData;
use web3::api::Web3;
use web3::contract::tokens::Tokenize;
use web3::types::{Address, Bytes, H256, U256};
use web3::Transport;

Expand Down Expand Up @@ -74,7 +74,10 @@ where
}

let code = bytecode.to_bytes()?;
let params = params.into_tokens();
let params = match params.into_token() {
ethcontract_common::abi::Token::Tuple(tokens) => tokens,
_ => unreachable!("function arguments are always tuples"),
};
let data = match (I::abi(&context).constructor(), params.is_empty()) {
(None, false) => return Err(AbiError::InvalidData.into()),
(None, true) => code,
Expand Down
14 changes: 7 additions & 7 deletions ethcontract/src/contract/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod data;
pub use self::data::{Event, EventMetadata, EventStatus, ParseLog, RawLog, StreamEvent};
use crate::errors::{EventError, ExecutionError};
use crate::log::LogFilterBuilder;
use crate::tokens::Tokenize;
pub use ethcontract_common::abi::Topic;
use ethcontract_common::{
abi::{Event as AbiEvent, RawTopicFilter, Token},
Expand All @@ -17,14 +18,13 @@ use std::cmp;
use std::marker::PhantomData;
use std::time::Duration;
use web3::api::Web3;
use web3::contract::tokens::{Detokenize, Tokenizable};
use web3::types::{Address, BlockNumber, H256};
use web3::Transport;

/// A builder for creating a filtered stream of contract events that are
#[derive(Debug)]
#[must_use = "event builders do nothing unless you stream them"]
pub struct EventBuilder<T: Transport, E: Detokenize> {
pub struct EventBuilder<T: Transport, E: Tokenize> {
/// The underlying web3 instance.
web3: Web3<T>,
/// The event ABI data for encoding topic filters and decoding logs.
Expand All @@ -36,7 +36,7 @@ pub struct EventBuilder<T: Transport, E: Detokenize> {
_event: PhantomData<E>,
}

impl<T: Transport, E: Detokenize> EventBuilder<T, E> {
impl<T: Transport, E: Tokenize> EventBuilder<T, E> {
/// Creates a new event builder from a web3 provider and a contract event
/// and address.
pub fn new(web3: Web3<T>, event: AbiEvent, address: Address) -> Self {
Expand Down Expand Up @@ -74,7 +74,7 @@ impl<T: Transport, E: Detokenize> EventBuilder<T, E> {
/// actually `topic[1]`.
pub fn topic0<P>(mut self, topic: Topic<P>) -> Self
where
P: Tokenizable,
P: Tokenize,
{
self.topics.topic0 = tokenize_topic(topic);
self
Expand All @@ -83,7 +83,7 @@ impl<T: Transport, E: Detokenize> EventBuilder<T, E> {
/// Adds a filter for the second indexed topic.
pub fn topic1<P>(mut self, topic: Topic<P>) -> Self
where
P: Tokenizable,
P: Tokenize,
{
self.topics.topic1 = tokenize_topic(topic);
self
Expand All @@ -92,7 +92,7 @@ impl<T: Transport, E: Detokenize> EventBuilder<T, E> {
/// Adds a filter for the third indexed topic.
pub fn topic2<P>(mut self, topic: Topic<P>) -> Self
where
P: Tokenizable,
P: Tokenize,
{
self.topics.topic2 = tokenize_topic(topic);
self
Expand Down Expand Up @@ -161,7 +161,7 @@ impl<T: Transport, E: Detokenize> EventBuilder<T, E> {
/// Converts a tokenizable topic into a raw topic for filtering.
fn tokenize_topic<P>(topic: Topic<P>) -> Topic<Token>
where
P: Tokenizable,
P: Tokenize,
{
topic.map(|parameter| parameter.into_token())
}
Expand Down
10 changes: 4 additions & 6 deletions ethcontract/src/contract/event/data.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//! Module contains code for parsing and manipulating event data.

use crate::errors::ExecutionError;
use ethcontract_common::abi::{Event as AbiEvent, RawLog as AbiRawLog};
use web3::contract::tokens::Detokenize;
use crate::{errors::ExecutionError, tokens::Tokenize};
use ethcontract_common::abi::{Event as AbiEvent, RawLog as AbiRawLog, Token};
use web3::types::{Log, H256};

/// A contract event
Expand Down Expand Up @@ -172,7 +170,7 @@ impl RawLog {
/// Decode raw log data into a tokenizable for a matching event ABI entry.
pub fn decode<D>(self, event: &AbiEvent) -> Result<D, ExecutionError>
where
D: Detokenize,
D: Tokenize,
{
let event_log = event.parse_log(AbiRawLog {
topics: self.topics,
Expand All @@ -184,7 +182,7 @@ impl RawLog {
.into_iter()
.map(|param| param.value)
.collect::<Vec<_>>();
let data = D::from_tokens(tokens)?;
let data = D::from_token(Token::Tuple(tokens))?;

Ok(data)
}
Expand Down
Loading