Skip to content

Commit

Permalink
feat: add accrual increase calls to all basic pool functions and fix …
Browse files Browse the repository at this point in the history
…div0 possibility
  • Loading branch information
Teolhyn committed Nov 23, 2024
1 parent 2a7dc68 commit 551d15c
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 15 deletions.
22 changes: 15 additions & 7 deletions contracts/loan_pool/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ impl LoanPoolContract {
user.require_auth();
assert!(amount > 0, "Amount must be positive!");

Self::add_interest_to_accrual(e.clone());

let client = token::Client::new(&e, &pool::read_currency(&e).token_address);
client.transfer(&user, &e.current_contract_address(), &amount);

Expand All @@ -67,6 +69,8 @@ impl LoanPoolContract {
pub fn withdraw(e: Env, user: Address, amount: i128) -> (i128, i128) {
user.require_auth();

Self::add_interest_to_accrual(e.clone());

// Get users receivables
let Positions { receivables, .. } = positions::read_positions(&e, &user);

Expand Down Expand Up @@ -107,6 +111,8 @@ impl LoanPoolContract {
loan_manager_addr.require_auth();
user.require_auth();

Self::add_interest_to_accrual(e.clone());

let balance = pool::read_available_balance(&e);
assert!(
amount < balance,
Expand Down Expand Up @@ -134,6 +140,8 @@ impl LoanPoolContract {
user.require_auth();
assert!(amount > 0, "Amount must be positive!");

Self::add_interest_to_accrual(e.clone());

let token_address = &pool::read_currency(&e).token_address;
let client = token::Client::new(&e, token_address);
client.transfer(&user, &e.current_contract_address(), &amount);
Expand All @@ -150,6 +158,8 @@ impl LoanPoolContract {

pub fn withdraw_collateral(e: Env, user: Address, amount: i128) -> i128 {
user.require_auth();
Self::add_interest_to_accrual(e.clone());

let loan_manager_addr = pool::read_loan_manager_addr(&e);
loan_manager_addr.require_auth();
assert!(amount > 0, "Amount must be positive!");
Expand All @@ -171,17 +181,11 @@ impl LoanPoolContract {
pub fn add_interest_to_accrual(e: Env) {
const DECIMAL: i128 = 10000000;
const SECONDS_IN_YEAR: u64 = 31_556_926;
/*
We calculate interest for ledgers_between from a given APY approximation simply by dividing the rate r with ledgers in a year
and multiplying it with ledgers_between. This would result in slightly different total yearly interest, e.g. 12% -> 12.7% total.
Perfect calculations are impossible in real world time as we must use ledgers as our time and ledger times vary between 5-6s.
*/
// TODO: we must store the init ledger for loans as loans started on different times would pay the same amount of interest on the given time.

let current_timestamp = e.ledger().timestamp();
let accrual = pool::read_accrual(&e);
let accrual_last_update = pool::read_accrual_last_updated(&e);
let ledgers_since_update = current_timestamp - accrual_last_update; // Currently unused but is a placeholder for interest calculations. Now time is handled.
let ledgers_since_update = current_timestamp - accrual_last_update;
let ledger_ratio: i128 =
(i128::from(ledgers_since_update) * DECIMAL) / (i128::from(SECONDS_IN_YEAR));

Expand Down Expand Up @@ -226,6 +230,8 @@ impl LoanPoolContract {
let loan_manager_addr = pool::read_loan_manager_addr(&e);
loan_manager_addr.require_auth();

Self::add_interest_to_accrual(e.clone());

let amount_to_admin = if amount < unpaid_interest {
amount / 10
} else {
Expand Down Expand Up @@ -253,6 +259,8 @@ impl LoanPoolContract {
let loan_manager_addr = pool::read_loan_manager_addr(&e);
loan_manager_addr.require_auth();

Self::add_interest_to_accrual(e.clone());

let amount_to_admin = if amount < unpaid_interest {
amount / 10
} else {
Expand Down
20 changes: 12 additions & 8 deletions contracts/loan_pool/src/interest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,20 @@ pub fn get_interest(e: Env) -> i128 {
let available = pool::read_available_balance(&e);
let total = pool::read_total_balance(&e);

let slope_before_panic =
(INTEREST_RATE_AT_PANIC - BASE_INTEREST_RATE) * 10_000_000 / PANIC_RATES_THRESHOLD;
let slope_after_panic = (MAX_INTEREST_RATE - INTEREST_RATE_AT_PANIC) * 10_000_000
/ (100_000_000 - PANIC_RATES_THRESHOLD);
if total > 0 {
let slope_before_panic =
(INTEREST_RATE_AT_PANIC - BASE_INTEREST_RATE) * 10_000_000 / PANIC_RATES_THRESHOLD;
let slope_after_panic = (MAX_INTEREST_RATE - INTEREST_RATE_AT_PANIC) * 10_000_000
/ (100_000_000 - PANIC_RATES_THRESHOLD);

let ratio_of_balances = ((total - available) * 100_000_000) / total; // correct
let ratio_of_balances = ((total - available) * 100_000_000) / total; // correct

if ratio_of_balances < PANIC_RATES_THRESHOLD {
(slope_before_panic * ratio_of_balances) / 10_000_000 + BASE_INTEREST_RATE
if ratio_of_balances < PANIC_RATES_THRESHOLD {
(slope_before_panic * ratio_of_balances) / 10_000_000 + BASE_INTEREST_RATE
} else {
(slope_after_panic * ratio_of_balances) / 10_000_000 + PANIC_BASE_RATE
}
} else {
(slope_after_panic * ratio_of_balances) / 10_000_000 + PANIC_BASE_RATE
BASE_INTEREST_RATE
}
}

0 comments on commit 551d15c

Please sign in to comment.