use anyhow::Result;
use ethers::prelude::*;
use std::{str::FromStr, sync::Arc};
use crate::{contract::*, errors::*};
pub struct FlashloanBuilder<M> {
pub borrower: Option<Flashloan<M>>,
pub owner: Option<Address>,
pub lender: Option<Address>,
pub client: Arc<M>,
pub token: Option<Address>,
pub amount: Option<U256>,
pub calls: Vec<Call3>,
pub chain_id: u64,
}
impl<M: Middleware> FlashloanBuilder<M> {
pub fn new(
client: Arc<M>,
chain_id: u64,
owner: Option<Address>,
lender: Option<Address>,
token: Option<Address>,
amount: Option<U256>,
override_contract: Option<Address>,
) -> Self {
Self {
borrower: override_contract.map(|contract| Flashloan::new(contract, client.clone())),
owner,
lender,
client: Arc::clone(&client),
token,
amount,
calls: vec![],
chain_id,
}
}
pub fn with_owner(&mut self, owner: Address) -> &mut Self {
self.owner = Some(owner);
self
}
pub fn with_lender(&mut self, lender: Address) -> &mut Self {
self.lender = Some(lender);
self
}
pub async fn deploy(
&mut self,
lender: Option<Address>,
owner: Option<Address>,
) -> Result<&mut Self> {
let deploy_lender = lender.unwrap_or_else(|| {
self.lender.unwrap_or_else(|| {
Address::from_str("0x1eb4cf3a948e7d72a198fe073ccb8c7a948cd853").unwrap()
})
});
println!("Deploying with lender: {:?}", deploy_lender);
let mut optional_owner = owner;
if optional_owner.is_none() {
optional_owner = self.owner;
}
if optional_owner.is_none() {
let accounts = self
.client
.get_accounts()
.await
.map_err(|e| FlashloanError::ClientFailure(e.to_string()))?;
let first_account = *accounts.get(0).ok_or(FlashloanError::MissingOwner)?;
optional_owner = Some(first_account);
}
let deploy_owner = optional_owner.unwrap();
println!("Deploying with owner: {:?}", deploy_owner);
let contract_deployer =
Flashloan::deploy(Arc::clone(&self.client), (deploy_lender, deploy_owner))
.map_err(|_| FlashloanError::ContractDeployError)?;
self.borrower =
Some(contract_deployer.send().await.map_err(|_| FlashloanError::ContractDeployError)?);
Ok(self)
}
pub fn inner(&self) -> Arc<M> {
Arc::clone(&self.client)
}
pub fn add_call(&mut self, call: Call3) -> &mut Self {
self.calls.push(call);
self
}
pub fn with_token(&mut self, token: Address) -> &mut Self {
self.token = Some(token);
self
}
pub fn with_amount(&mut self, amount: U256) -> &mut Self {
self.amount = Some(amount);
self
}
pub async fn call(&mut self) -> Result<()> {
let token = self.token.ok_or(FlashloanError::MissingToken)?;
let amount = self.amount.ok_or(FlashloanError::MissingAmount)?;
self.inner_call(token, amount, &self.calls.clone()).await
}
pub async fn inner_call(
&mut self,
token: Address,
amount: U256,
calls: &[Call3],
) -> Result<()> {
let contract = self.borrower.as_ref().ok_or(FlashloanError::MissingBorrower)?;
contract
.flash_borrow(token, amount, calls.to_vec())
.call()
.await
.map_err(|ce| FlashloanError::ContractError(ce.to_string()))?;
Ok(())
}
pub async fn execute(&mut self) -> Result<Option<TransactionReceipt>> {
let token = self.token.ok_or(FlashloanError::MissingToken)?;
let amount = self.amount.ok_or(FlashloanError::MissingAmount)?;
self.inner_execute(token, amount, &self.calls.clone()).await
}
pub async fn inner_execute(
&mut self,
token: Address,
amount: U256,
calls: &[Call3],
) -> Result<Option<TransactionReceipt>> {
let contract = self.borrower.as_ref().ok_or(FlashloanError::MissingBorrower)?;
let contract_call = contract.flash_borrow(token, amount, calls.to_vec());
let pending_transaction = contract_call
.send()
.await
.map_err(|ce| FlashloanError::ContractError(ce.to_string()))?;
let optional_receipt = pending_transaction
.await
.map_err(|ce| FlashloanError::ContractError(ce.to_string()))?;
Ok(optional_receipt)
}
}