use alloy_primitives::{Address, U256};
use alloy_provider::network::Network;
use alloy_provider::{PendingTransactionBuilder, Provider};
use trident_evm_aa::{MulticallBuilder, MulticallError};
use crate::evm::abi::{IERC20, TridentDeposits};
#[derive(Debug, thiserror::Error)]
pub enum EvmDepositError {
#[error("Contract call failed: {0}")]
Contract(#[from] alloy_contract::Error),
#[error("Approval transaction pending error: {0}")]
PendingApproval(#[from] alloy_provider::PendingTransactionError),
#[error(transparent)]
Multicall(#[from] MulticallError),
}
pub async fn deposit<P, N>(
provider: P,
deposit_contract: Address,
signer_address: Address,
token: Address,
amount: U256,
) -> Result<PendingTransactionBuilder<N>, EvmDepositError>
where
P: Provider<N>,
N: Network,
{
ensure_allowance(&provider, token, signer_address, deposit_contract, amount).await?;
let deposits = TridentDeposits::new(deposit_contract, provider);
Ok(deposits.deposit(token, amount).send().await?)
}
pub async fn deposit_multicall<P, N, I>(
provider: P,
deposit_contract: Address,
signer_address: Address,
deposits: I,
) -> Result<PendingTransactionBuilder<N>, EvmDepositError>
where
P: Provider<N>,
N: Network,
I: IntoIterator<Item = (Address, U256)>,
{
let mut builder = MulticallBuilder::new();
for (token, amount) in deposits {
let approve = IERC20::approveCall {
spender: deposit_contract,
value: amount,
};
builder = builder.call(token, &approve);
let deposit = TridentDeposits::depositCall { token, amount };
builder = builder.call(deposit_contract, &deposit);
}
Ok(builder.send(provider, signer_address).await?)
}
async fn ensure_allowance<P, N>(
provider: P,
token: Address,
owner: Address,
spender: Address,
required: U256,
) -> Result<(), EvmDepositError>
where
P: Provider<N>,
N: Network,
{
let erc20 = IERC20::new(token, provider);
let current = erc20.allowance(owner, spender).call().await?;
if current >= required {
return Ok(());
}
let pending = erc20.approve(spender, required).send().await?;
pending.get_receipt().await?;
Ok(())
}