pub use crate::{
psp22::*,
traits::flashloan::*,
};
use brush::traits::{
AccountId,
Balance,
Flush,
};
use ink_env::{
CallFlags,
Error as EnvError,
};
use ink_prelude::{
string::String,
vec::Vec,
};
impl<T: PSP22 + PSP22Internal + Flush> FlashLender for T {
default fn max_flashloan(&mut self, token: AccountId) -> Balance {
if token == Self::env().account_id() {
Balance::MAX - self.total_supply()
} else {
0
}
}
default fn flash_fee(&self, token: AccountId, amount: Balance) -> Result<Balance, FlashLenderError> {
if token != Self::env().account_id() {
return Err(FlashLenderError::WrongTokenAddress)
}
Ok(self._get_fee(amount))
}
default fn flashloan(
&mut self,
receiver_account: AccountId,
token: AccountId,
amount: Balance,
data: Vec<u8>,
) -> Result<(), FlashLenderError> {
let fee = self.flash_fee(token, amount)?;
self._mint(receiver_account, amount)?;
self._on_flashloan(receiver_account, token, fee, amount, data)?;
let this = Self::env().account_id();
let current_allowance = self.allowance(receiver_account, this);
if current_allowance < amount + fee {
return Err(FlashLenderError::AllowanceDoesNotAllowRefund)
}
self._approve_from_to(receiver_account, this, current_allowance - amount - fee)?;
self._burn_from(receiver_account, amount + fee)?;
Ok(())
}
}
pub trait PSP22FlashLenderInternal {
fn _get_fee(&self, _amount: Balance) -> Balance;
fn _on_flashloan(
&mut self,
receiver_account: AccountId,
token: AccountId,
fee: Balance,
amount: Balance,
data: Vec<u8>,
) -> Result<(), FlashLenderError>;
}
impl<T: PSP22 + PSP22Internal + Flush> PSP22FlashLenderInternal for T {
default fn _get_fee(&self, _amount: Balance) -> Balance {
0
}
default fn _on_flashloan(
&mut self,
receiver_account: AccountId,
token: AccountId,
fee: Balance,
amount: Balance,
data: Vec<u8>,
) -> Result<(), FlashLenderError> {
self.flush();
let builder =
FlashBorrowerRef::on_flashloan_builder(&receiver_account, Self::env().caller(), token, amount, fee, data)
.call_flags(CallFlags::default().set_allow_reentry(true));
let result = match builder.fire() {
Ok(result) => {
match result {
Ok(_) => Ok(()),
Err(FlashBorrowerError::FlashloanRejected(message)) => {
Err(FlashLenderError::BorrowerRejected(message))
}
}
}
Err(e) => {
match e {
EnvError::NotCallable | EnvError::CalleeTrapped => Ok(()),
_ => {
Err(FlashLenderError::BorrowerRejected(String::from(
"Error while performing the `on_flashloan`",
)))
}
}
}
};
self.load();
result
}
}