use alloy::{
network::Ethereum,
primitives::{Address, U256},
providers::Provider,
rpc::types::TransactionRequest,
sol,
};
use alloy_sol_types::SolCall;
use anyhow::{Context, Result};
use tracing::{debug, info};
use uniswap_sdk_core::{
entities::{BaseCurrency, BaseCurrencyCore, FractionBase},
prelude::{Currency, CurrencyAmount, WETH9},
utils::FromBig,
};
use waterpump_evm_core::weth_ext::Weth9Ext;
sol! {
#[sol(rpc)]
interface IWETH {
function deposit() payable;
function withdraw(uint256 amount) returns (bool);
function balanceOf(address account) returns (uint256);
}
}
#[tracing::instrument(skip(provider, amount), fields(sender_address = ?sender_address, amount = ?amount, currency_is_native = amount.currency.is_native()))]
pub async fn wrap_eth_if_needed<P: Provider<Ethereum>>(
provider: &P,
sender_address: Address,
amount: CurrencyAmount<Currency>,
) -> Result<bool> {
if !amount.currency.is_native() {
debug!("Currency is not native, no wrapping needed");
return Ok(false);
}
info!("Token is native (ETH), wrapping to WETH...");
let chain_id_raw =
provider.get_chain_id().await.context("Failed to get chain ID from provider")?;
let chain_id: u64 = chain_id_raw;
let weth_token = WETH9::on_chain_with_custom(chain_id)?;
let currency: Currency = weth_token.into();
let weth_address = currency.address();
debug!(weth_address = ?weth_address, "WETH address");
let weth = IWETH::new(weth_address, provider);
let current_balance =
weth.balanceOf(sender_address).call().await.context("Failed to check WETH balance")?;
let required_amount = U256::from_big_int(amount.quotient());
debug!(current_balance = ?current_balance, required_amount = ?required_amount, "WETH balance check");
if current_balance >= required_amount {
info!("Sufficient WETH balance, no wrapping needed");
return Ok(false);
}
let eth_to_wrap = required_amount - current_balance;
info!("Insufficient WETH balance, wrapping ETH");
debug!(wrapping_amount = ?eth_to_wrap, "Wrapping amount");
let eth_balance = provider.get_balance(sender_address).await?;
if eth_balance < eth_to_wrap {
return Err(anyhow::anyhow!(
"Insufficient ETH balance. Have: {}, Need: {}",
eth_balance,
eth_to_wrap
));
}
let deposit_calldata = IWETH::depositCall {}.abi_encode();
let tx = TransactionRequest::default()
.from(sender_address)
.to(weth_address)
.input(deposit_calldata.into())
.value(eth_to_wrap);
let pending_tx =
provider.send_transaction(tx).await.context("Failed to send WETH deposit transaction")?;
let tx_hash = pending_tx.watch().await?;
info!(tx_hash = ?tx_hash, "WETH deposit transaction sent");
let receipt = provider
.get_transaction_receipt(tx_hash)
.await
.context("Failed to get WETH deposit transaction receipt")?
.unwrap();
info!(
tx_hash = ?tx_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
"WETH deposit confirmed"
);
Ok(true)
}