Skip to content

Commit

Permalink
Merge pull request #217 from blend-capital/misc-todos
Browse files Browse the repository at this point in the history
Misc todos
  • Loading branch information
mootz12 authored Mar 28, 2024
2 parents fe2f7eb + bfd3ae9 commit e5492aa
Show file tree
Hide file tree
Showing 21 changed files with 170 additions and 117 deletions.
1 change: 0 additions & 1 deletion backstop/src/backstop/deposit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ mod tests {
e.as_contract(&backstop_address, || {
execute_deposit(&e, &samwise, &pool_0_id, 100_0000001);

// TODO: Handle token errors gracefully
assert!(false);
});
}
Expand Down
81 changes: 77 additions & 4 deletions backstop/src/backstop/user.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use soroban_sdk::{contracttype, panic_with_error, vec, Env, Vec};

use crate::errors::BackstopError;
use crate::{
constants::{MAX_Q4W_SIZE, Q4W_LOCK_TIME},
errors::BackstopError,
};

/// A deposit that is queued for withdrawal
#[derive(Clone)]
Expand Down Expand Up @@ -51,14 +54,15 @@ impl UserBalance {
if self.shares < to_q {
panic_with_error!(e, BackstopError::BalanceError);
}
if self.q4w.len() >= MAX_Q4W_SIZE {
panic_with_error!(e, BackstopError::TooManyQ4WEntries);
}
self.shares = self.shares - to_q;

// user has enough tokens to withdrawal, add Q4W
// TODO: Consider capping how many active Q4Ws a user can have
let twentyone_days_in_sec = 21 * 24 * 60 * 60;
let new_q4w = Q4W {
amount: to_q,
exp: e.ledger().timestamp() + twentyone_days_in_sec,
exp: e.ledger().timestamp() + Q4W_LOCK_TIME,
};
self.q4w.push_back(new_q4w.clone());
}
Expand Down Expand Up @@ -210,6 +214,75 @@ mod tests {
assert_eq_vec_q4w(&user.q4w, &cur_q4w);
}

#[test]
fn test_q4w_new_to_max_works() {
let e = Env::default();
let exp = 12592000;
let mut cur_q4w = vec![&e];
for i in 0..20 {
cur_q4w.push_back(Q4W {
amount: 200,
exp: exp + i,
});
}
let mut user = UserBalance {
shares: 1000,
q4w: cur_q4w.clone(),
};

e.ledger().set(LedgerInfo {
protocol_version: 20,
sequence_number: 1,
timestamp: 11000000,
network_id: Default::default(),
base_reserve: 10,
min_temp_entry_ttl: 10,
min_persistent_entry_ttl: 10,
max_entry_ttl: 3110400,
});

let to_queue = 500;
user.queue_shares_for_withdrawal(&e, to_queue);
cur_q4w.push_back(Q4W {
amount: to_queue,
exp: 11000000 + 21 * 24 * 60 * 60,
});
assert_eq_vec_q4w(&user.q4w, &cur_q4w);
}

#[test]
#[should_panic(expected = "Error(Contract, #1007)")]
fn test_q4w_new_over_max_panics() {
let e = Env::default();

let exp = 12592000;
let mut cur_q4w = vec![&e];
for i in 0..21 {
cur_q4w.push_back(Q4W {
amount: 200,
exp: exp + i,
});
}
let mut user = UserBalance {
shares: 1000,
q4w: cur_q4w.clone(),
};

e.ledger().set(LedgerInfo {
protocol_version: 20,
sequence_number: 1,
timestamp: 11000000,
network_id: Default::default(),
base_reserve: 10,
min_temp_entry_ttl: 10,
min_persistent_entry_ttl: 10,
max_entry_ttl: 3110400,
});

let to_queue = 500;
user.queue_shares_for_withdrawal(&e, to_queue);
}

#[test]
#[should_panic(expected = "Error(Contract, #10)")]
fn test_q4w_over_shares_panics() {
Expand Down
13 changes: 11 additions & 2 deletions backstop/src/constants.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
/// Fixed-point scalar for 7 decimal numbers
pub const SCALAR_7: i128 = 1_0000000;

// The approximate deployment date of the backstop module TODO: pick one
pub const BACKSTOP_EPOCH: u64 = 1441065600;
/// The approximate deployment time in seconds since epoch of the backstop module. This is NOT the
/// actual deployment time and should not be considered accruate. It is only used to determine reward
/// zone size on ~90 day intervals, starting at 10 on or before April 15th, 2024 00:00:00 UTC.
pub const BACKSTOP_EPOCH: u64 = 1713139200;

/// The maximum amount of active Q4W entries that a user can have against a single backstop.
/// Set such that a user can create a maximum of 1 entry per day over the 21 day lock period.
pub const MAX_Q4W_SIZE: u32 = 21;

/// The time in seconds that a Q4W entry is locked for (21 days).
pub const Q4W_LOCK_TIME: u64 = 21 * 24 * 60 * 60;
62 changes: 57 additions & 5 deletions backstop/src/emissions/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ use super::distributor::update_emission_data_with_config;
/// Add a pool to the reward zone. If the reward zone is full, attempt to swap it with the pool to remove.
pub fn add_to_reward_zone(e: &Env, to_add: Address, to_remove: Address) {
let mut reward_zone = storage::get_reward_zone(e);
let max_rz_len = 10 + (i128(e.ledger().timestamp() - BACKSTOP_EPOCH) >> 23); // bit-shift 23 is ~97 day interval
let max_rz_len = if e.ledger().timestamp() < BACKSTOP_EPOCH {
10
} else {
10 + (i128(e.ledger().timestamp() - BACKSTOP_EPOCH) >> 23) // bit-shift 23 is ~97 day interval
};

// ensure an entity in the reward zone cannot be included twice
if reward_zone.contains(to_add.clone()) {
Expand Down Expand Up @@ -89,8 +93,6 @@ pub fn gulp_emissions(e: &Env) -> i128 {

let mut rz_balance: Vec<PoolBalance> = vec![e];

// TODO: Potential to assume optimization of backstop token balances ~= RZ tokens
// However, linear iteration over the RZ will still occur
// fetch total tokens of BLND in the reward zone
let mut total_non_queued_tokens: i128 = 0;
for rz_pool_index in 0..rz_len {
Expand Down Expand Up @@ -136,12 +138,12 @@ pub fn gulp_pool_emissions(e: &Env, pool_id: &Address) -> i128 {
let blnd_token_client = TokenClient::new(e, &storage::get_blnd_token(e));
let current_allowance = blnd_token_client.allowance(&e.current_contract_address(), pool_id);
let new_tokens = current_allowance + pool_emissions;
let new_seq = e.ledger().sequence() + 17_280 * 30; // ~30 days: TODO: check phase 1 limits
let new_seq = e.ledger().sequence() + storage::LEDGER_BUMP_USER; // ~120 days
blnd_token_client.approve(
&e.current_contract_address(),
pool_id,
&new_tokens,
&new_seq, // ~30 days: TODO: check phase 1 limits
&new_seq,
);
storage::set_pool_emissions(e, pool_id, 0);
pool_emissions
Expand Down Expand Up @@ -574,6 +576,55 @@ mod tests {
});
}

#[test]
fn test_add_to_rz_before_epoch_max_10() {
let e = Env::default();
e.ledger().set(LedgerInfo {
timestamp: BACKSTOP_EPOCH - 100000,
protocol_version: 20,
sequence_number: 0,
network_id: Default::default(),
base_reserve: 10,
min_temp_entry_ttl: 10,
min_persistent_entry_ttl: 10,
max_entry_ttl: 3110400,
});

let backstop_id = create_backstop(&e);
let to_add = Address::generate(&e);
let mut reward_zone: Vec<Address> = vec![
&e,
Address::generate(&e),
Address::generate(&e),
Address::generate(&e),
Address::generate(&e),
Address::generate(&e),
Address::generate(&e),
Address::generate(&e),
Address::generate(&e),
Address::generate(&e),
];

e.as_contract(&backstop_id, || {
storage::set_reward_zone(&e, &reward_zone);
storage::set_pool_balance(
&e,
&to_add,
&PoolBalance {
shares: 90_000_0000000,
tokens: 100_000_0000000,
q4w: 1_000_0000000,
},
);
storage::set_lp_token_val(&e, &(5_0000000, 0_1000000));

add_to_reward_zone(&e, to_add.clone(), Address::generate(&e));
let actual_rz = storage::get_reward_zone(&e);
reward_zone.push_front(to_add);
assert_eq!(actual_rz, reward_zone);
});
}

#[test]
#[should_panic(expected = "Error(Contract, #1002)")]
fn test_add_to_rz_empty_pool_under_backstop_threshold() {
Expand Down Expand Up @@ -660,6 +711,7 @@ mod tests {
assert_eq!(actual_rz, reward_zone);
});
}

#[test]
#[should_panic(expected = "Error(Contract, #1002)")]
fn test_add_to_rz_takes_floor_for_size() {
Expand Down
1 change: 1 addition & 0 deletions backstop/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ pub enum BackstopError {
NotPool = 1004,
InvalidShareMintAmount = 1005,
InvalidTokenWithdrawAmount = 1006,
TooManyQ4WEntries = 1007,
}
4 changes: 1 addition & 3 deletions backstop/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const LEDGER_THRESHOLD_SHARED: u32 = ONE_DAY_LEDGERS * 45; // ~ 45 days
const LEDGER_BUMP_SHARED: u32 = LEDGER_THRESHOLD_SHARED + ONE_DAY_LEDGERS; // ~ 46 days

const LEDGER_THRESHOLD_USER: u32 = ONE_DAY_LEDGERS * 100; // ~ 100 days
const LEDGER_BUMP_USER: u32 = LEDGER_THRESHOLD_USER + 20 * ONE_DAY_LEDGERS; // ~ 120 days
pub(crate) const LEDGER_BUMP_USER: u32 = LEDGER_THRESHOLD_USER + 20 * ONE_DAY_LEDGERS; // ~ 120 days

/********** Storage Types **********/

Expand Down Expand Up @@ -314,8 +314,6 @@ pub fn set_last_distribution_time(e: &Env, timestamp: &u64) {
}

/// Get the current pool addresses that are in the reward zone
///
// @dev - TODO: Once data access costs are available, find the breakeven point for splitting this up
pub fn get_reward_zone(e: &Env) -> Vec<Address> {
get_persistent_default(
e,
Expand Down
1 change: 0 additions & 1 deletion mocks/mock-pool-factory/src/pool_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ impl MockPoolFactoryTrait for MockPoolFactory {
init_args.push_back(max_positions.into_val(&e));
init_args.push_back(pool_init_meta.backstop.to_val());
init_args.push_back(pool_init_meta.blnd_id.to_val());
init_args.push_back(pool_init_meta.usdc_id.to_val());

let pool_address = e.register_contract(None, PoolContract {});
e.invoke_contract::<Val>(&pool_address, &Symbol::new(&e, "initialize"), init_args);
Expand Down
13 changes: 3 additions & 10 deletions mocks/mock-pool-factory/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ pub struct PoolInitMeta {
pub pool_hash: BytesN<32>,
pub backstop: Address,
pub blnd_id: Address,
pub usdc_id: Address,
}

/// Bump the instance rent for the contract
Expand All @@ -35,14 +34,8 @@ pub fn extend_instance(e: &Env) {

/// Fetch the pool initialization metadata
pub fn get_pool_init_meta(e: &Env) -> PoolInitMeta {
// TODO: Change to instance - https://github.com/stellar/rs-soroban-sdk/issues/1040
e.storage().persistent().extend_ttl(
&PoolFactoryDataKey::PoolInitMeta,
LEDGER_THRESHOLD_SHARED,
LEDGER_BUMP_SHARED,
);
e.storage()
.persistent()
.instance()
.get::<PoolFactoryDataKey, PoolInitMeta>(&PoolFactoryDataKey::PoolInitMeta)
.unwrap_optimized()
}
Expand All @@ -53,14 +46,14 @@ pub fn get_pool_init_meta(e: &Env) -> PoolInitMeta {
/// * `pool_init_meta` - The metadata to initialize pools
pub fn set_pool_init_meta(e: &Env, pool_init_meta: &PoolInitMeta) {
e.storage()
.persistent()
.instance()
.set::<PoolFactoryDataKey, PoolInitMeta>(&PoolFactoryDataKey::PoolInitMeta, pool_init_meta)
}

/// Check if the factory has a WASM hash set
pub fn has_pool_init_meta(e: &Env) -> bool {
e.storage()
.persistent()
.instance()
.has(&PoolFactoryDataKey::PoolInitMeta)
}

Expand Down
1 change: 0 additions & 1 deletion pool-factory/src/pool_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ impl PoolFactory for PoolFactoryContract {
init_args.push_back(max_positions.into_val(&e));
init_args.push_back(pool_init_meta.backstop.to_val());
init_args.push_back(pool_init_meta.blnd_id.to_val());
init_args.push_back(pool_init_meta.usdc_id.to_val());
let pool_address = e
.deployer()
.with_current_contract(new_salt)
Expand Down
1 change: 0 additions & 1 deletion pool-factory/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ pub struct PoolInitMeta {
pub pool_hash: BytesN<32>,
pub backstop: Address,
pub blnd_id: Address,
pub usdc_id: Address, //Must have 7 token decimals due to lot decimal restriction in backstop interest auctions
}

/// Bump the instance rent for the contract
Expand Down
15 changes: 0 additions & 15 deletions pool-factory/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,11 @@ fn test_pool_factory() {
let backstop_rate: u32 = 0_1000000;
let max_positions: u32 = 6;
let blnd_id = Address::generate(&e);
let usdc_id = Address::generate(&e);

let pool_init_meta = PoolInitMeta {
backstop: backstop_id.clone(),
pool_hash: wasm_hash.clone(),
blnd_id: blnd_id.clone(),
usdc_id: usdc_id.clone(),
};
pool_factory_client.initialize(&pool_init_meta);

Expand Down Expand Up @@ -116,13 +114,6 @@ fn test_pool_factory() {
.unwrap(),
blnd_id.clone()
);
assert_eq!(
e.storage()
.instance()
.get::<_, Address>(&Symbol::new(&e, "USDCTkn"))
.unwrap(),
usdc_id.clone()
);
});
assert_ne!(deployed_pool_address_1, deployed_pool_address_2);
assert!(pool_factory_client.is_pool(&deployed_pool_address_1));
Expand All @@ -142,13 +133,11 @@ fn test_pool_factory_invalid_pool_init_args_backstop_rate() {

let backstop_id = Address::generate(&e);
let blnd_id = Address::generate(&e);
let usdc_id = Address::generate(&e);

let pool_init_meta = PoolInitMeta {
backstop: backstop_id.clone(),
pool_hash: wasm_hash.clone(),
blnd_id: blnd_id.clone(),
usdc_id: usdc_id.clone(),
};
pool_factory_client.initialize(&pool_init_meta);

Expand Down Expand Up @@ -182,13 +171,11 @@ fn test_pool_factory_invalid_pool_init_args_max_positions() {

let backstop_id = Address::generate(&e);
let blnd_id = Address::generate(&e);
let usdc_id = Address::generate(&e);

let pool_init_meta = PoolInitMeta {
backstop: backstop_id.clone(),
pool_hash: wasm_hash.clone(),
blnd_id: blnd_id.clone(),
usdc_id: usdc_id.clone(),
};
pool_factory_client.initialize(&pool_init_meta);

Expand Down Expand Up @@ -228,13 +215,11 @@ fn test_pool_factory_frontrun_protection() {
let backstop_rate: u32 = 0_1000000;
let max_positions: u32 = 6;
let blnd_id = Address::generate(&e);
let usdc_id = Address::generate(&e);

let pool_init_meta = PoolInitMeta {
backstop: backstop_id.clone(),
pool_hash: wasm_hash.clone(),
blnd_id: blnd_id.clone(),
usdc_id: usdc_id.clone(),
};
pool_factory_client.initialize(&pool_init_meta);

Expand Down
Loading

0 comments on commit e5492aa

Please sign in to comment.