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

Add web3::contract::deploy::execute_no_unlock #252

Merged
merged 10 commits into from
Sep 15, 2019
84 changes: 81 additions & 3 deletions src/contract/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::api::{Eth, Namespace};
use crate::confirm;
use crate::contract::tokens::Tokenize;
use crate::contract::{Contract, Options};
use crate::types::{Address, Bytes, TransactionRequest};
use crate::types::{Address, Bytes, TransactionReceipt, TransactionRequest};
use crate::Transport;

pub use crate::contract::error::deploy::Error;
Expand Down Expand Up @@ -102,13 +102,91 @@ impl<T: Transport> Builder<T> {
waiting,
})
}

/// Execute deployment passing code and contructor parameters.
///
/// Unlike the above `execute`, this method uses
/// `sign_raw_transaction_with_confirmation` instead of
/// `sign_transaction_with_confirmation`, which requires the account from
/// which the transaction is sent to be unlocked.
pub fn sign_and_execute<P, V, Ft>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Ft parameter is unused. This is problematic for calling code because the compiler cannot infer the instantiation of Ft. This leads to the calling code always requiring an explicit type annotation.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just remove it then. I guess I left it by mistake.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try this out.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it solve the issues you were having?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It did. I get other errors now, but as far as this PR goes, it has what we need.
Do you still want me to add a test before we merge?

self,
code: V,
params: P,
from: Address,
password: &str,
web3: crate::Web3<T>,
) -> Result<PendingContract<T, Ft>, ethabi::Error>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
) -> Result<PendingContract<T, Ft>, ethabi::Error>
) -> Result<PendingContract<T, impl Future<...>>, ethabi::Error>

Drop Ft and try this.

where
P: Tokenize,
V: AsRef<str>,
T: Transport,
Ft: Future<Item = TransactionReceipt, Error = crate::error::Error>,
{
let options = self.options;
let eth = self.eth;
let abi = self.abi;

let mut code_hex = code.as_ref().to_string();

for (lib, address) in self.linker {
if lib.len() > 38 {
return Err(
ethabi::ErrorKind::Msg(String::from("The library name should be under 39 characters.")).into(),
);
}
let replace = format!("__{:_<38}", lib); // This makes the required width 38 characters and will pad with `_` to match it.
let address: String = address.as_ref().to_hex();
code_hex = code_hex.replacen(&replace, &address, 1);
}
code_hex = code_hex.replace("\"", "").replace("0x", ""); // This is to fix truffle + serde_json redundant `"` and `0x`
let code = code_hex.from_hex().map_err(ethabi::ErrorKind::Hex)?;

let params = params.into_tokens();
let data = match (abi.constructor(), params.is_empty()) {
(None, false) => {
return Err(ethabi::ErrorKind::Msg("Constructor is not defined in the ABI.".into()).into());
}
(None, true) => code,
(Some(constructor), _) => constructor.encode_input(code, &params)?,
};

let tx = TransactionRequest {
from,
to: None,
gas: options.gas,
gas_price: options.gas_price,
value: options.value,
nonce: options.nonce,
data: Some(Bytes(data)),
condition: options.condition,
};

let waiting = web3.personal().sign_transaction(tx, password).and_then(|signed_tx| {
confirm::send_raw_transaction_with_confirmation(
eth.transport().clone(),
signed_tx.raw,
self.poll_interval,
self.confirmations,
)
});

Ok(PendingContract {
eth: Some(eth),
abi: Some(abi),
waiting,
})
}
}

/// Contract being deployed.
pub struct PendingContract<T: Transport> {
pub struct PendingContract<
T: Transport,
F: Future<Item = TransactionReceipt, Error = crate::error::Error> = confirm::SendTransactionWithConfirmation<T>,
> {
eth: Option<Eth<T>>,
abi: Option<ethabi::Contract>,
waiting: confirm::SendTransactionWithConfirmation<T>,
waiting: F,
}

impl<T: Transport> Future for PendingContract<T> {
Expand Down