use std::io::{self, Error, ErrorKind};
use avalanche_types::key;
use ethers::prelude::*;
use ethers_providers::{Middleware, Provider};
impl<T> crate::wallet::Wallet<T>
where
T: key::ReadOnly + key::SignOnly + Clone,
{
pub async fn transfer_c(
&self,
http_rpc: Option<String>,
receiver_h160_addr: H160,
amount_to_transfer: U256,
gas: Option<u64>,
gas_price: Option<u64>,
check_acceptance: bool,
) -> io::Result<()> {
let (http_rpc_ep, c_provider) = if let Some(ep) = &http_rpc {
let c_provider =
Provider::<Http>::try_from(ep.to_string() + "/ext/bc/C/rpc").map_err(|e| {
Error::new(ErrorKind::Other, format!("failed to create c_ '{}'", e))
})?;
(ep.to_string(), c_provider)
} else {
(self.http_rpc.clone(), self.c_provider.clone())
};
let sender_h160_addr = self.keychain.keys[0].get_h160_address();
log::info!(
"transferring {} from {} to {} via {}",
amount_to_transfer,
sender_h160_addr,
receiver_h160_addr,
http_rpc_ep
);
let latest_nonce = c_provider
.get_transaction_count(self.h160_address, Some(BlockNumber::Latest.into()))
.await
.map_err(|e| {
Error::new(
ErrorKind::Other,
format!("failed get_transaction_count '{}'", e),
)
})?;
log::debug!("latest nonce for sender: {}", latest_nonce);
let gas_u256 = if let Some(v) = gas {
U256::from(v)
} else {
U256::from(21000) };
let mut tx_request = TransactionRequest::new()
.from(self.h160_address)
.to(receiver_h160_addr)
.value(amount_to_transfer)
.gas(gas_u256)
.chain_id(self.c_chain_id_u256.as_u64())
.nonce(latest_nonce);
if let Some(gas_price) = gas_price {
tx_request = tx_request.gas_price(U256::from(gas_price))
}
let signer = SignerMiddleware::new(
c_provider.clone(),
self.local_wallet
.clone()
.with_chain_id(self.c_chain_id_u256.as_u64()),
);
let pending_tx = signer
.send_transaction(tx_request, None)
.await
.map_err(|e| {
Error::new(
ErrorKind::Other,
format!("failed to send_transaction '{}'", e),
)
})?;
let tx_receipt = pending_tx.await.map_err(|e| {
Error::new(
ErrorKind::Other,
format!("failed to wait for pending tx '{}'", e),
)
})?;
if tx_receipt.is_none() {
return Err(Error::new(ErrorKind::Other, "tx dropped from mempool"));
}
let receipt = tx_receipt.unwrap();
let tx = signer
.get_transaction(receipt.transaction_hash)
.await
.map_err(|e| Error::new(ErrorKind::Other, format!("failed get_transaction '{}'", e)))?;
if let Some(v) = &tx {
log::info!("{} successfully issued", v.hash());
}
if !check_acceptance {
log::debug!("skipping checking acceptance...");
return Ok(());
}
Ok(())
}
}