Flash Loans
#![no_std]
use soroban_sdk::{contract, contracterror, contractimpl, contracttype, token, Address, Env, log};
#[contracterror]
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum ReceiverError {
InitFailed = 1,
NotInitialized = 2,
}
pub trait FlashLoanReceiver {
fn exec_op(env: Env) -> Result<(), ReceiverError>;
}
#[contracttype]
pub enum DataKey {
Token,
Amount,
PoolAddress,
}
#[contract]
pub struct FlashLoanReceiverContract;
fn compute_fee(amount: &i128) -> i128 {
amount / 1250 // 0.05%, still TBD
}
#[contractimpl]
impl FlashLoanReceiver for FlashLoanReceiverContract {
fn exec_op(e: Env) -> Result<(), ReceiverError> {
let token_client = if let Some(token) = &e
.storage()
.instance()
.get::<DataKey, Address>(&DataKey::Token)
{
token::Client::new(&e, &token)
} else {
return Err(ReceiverError::NotInitialized);
};
let borrowed = e
.storage()
.instance()
.get::<DataKey, i128>(&DataKey::Amount)
.unwrap();
let total_amount = borrowed + compute_fee(&borrowed);
/// @dev should remove logs before deploying smart contracts
log!(&e, "Total amount - {}", total_amount);
let flash_loan = e
.storage()
.instance()
.get::<DataKey, Address>(&DataKey::PoolAddress)
.unwrap();
token_client.approve(
&e.current_contract_address(),
&flash_loan,
&total_amount,
&(e.ledger().sequence() + 1),
);
Ok(())
}
}
#[contractimpl]
impl FlashLoanReceiverContract {
pub fn init(
e: Env,
token_id: Address,
fl_address: Address,
amount: i128,
) -> Result<(), ReceiverError> {
e.storage().instance().set(&DataKey::Token, &token_id);
e.storage()
.instance()
.set(&DataKey::PoolAddress, &fl_address);
e.storage().instance().set(&DataKey::Amount, &amount);
Ok(())
}
}
#[cfg(test)]
mod test;
Explanation
#![no_std]
This attribute prevents linking to the standard library, making the code lighter and more efficient for Soroban contracts. It's big so we save on size.
use soroban_sdk::{contract, contractimpl, Env, log}
Imports stuffs from the Soroban SDK. Env
is basic Soroban type, we need it because we can't use the Rust standard library.
ReceiverError
This defines a custom error type with two variants - one indicating initialization failure, and another indicating the contract requiring initialization before use.
compute_fee
This function calculates a fee based on the borrowed amount.
init
This is used to initialize the contract, the environment, token address, flash pool address, and loan amount are taken as arguments.
exec_op
This function implements the core functionality of the contract. It retrieves the stored token address, it returns an error if not found. It retrieves the borrowed amount. It calculates the total amount with the fee. It logs the total amount. It retrieves the flash loan pool address. It uses the token_client
to approve the flash loan pool to withdraw the total amount plus fees. The approval is valid for the next transaction only (sequence number + 1).
Run in Playground
Loading playground...