Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions soroban/contracts/factory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ fn bump_asset_pools(env: &Env, asset: &Address) {
);
}

fn bump_admin_pools(env: &Env, admin: &Address) {
env.storage().persistent().extend_ttl(
&DataKey::PoolsByAdmin(admin.clone()),
TTL_THRESHOLD,
TTL_EXTEND_TO,
);
}

/// Reject any call that lands on a factory whose state was never seeded.
///
/// `initialize` is the only writer of `DataKey::Admin`, so its presence is the
Expand Down Expand Up @@ -468,6 +476,21 @@ impl Factory {
Self::get_pools_by_asset_range(env, asset, start_id, MAX_POOL_SCAN_PER_CALL, limit)
}

/// Return the list of pool IDs created by `admin`.
pub fn get_pools_by_admin(env: Env, admin: Address) -> Result<Vec<u32>, FactoryError> {
require_initialized(&env)?;
bump_instance(&env);
let admin_key = DataKey::PoolsByAdmin(admin.clone());
if env.storage().persistent().has(&admin_key) {
bump_admin_pools(&env, &admin);
}
Ok(env
.storage()
.persistent()
.get(&admin_key)
.unwrap_or_else(|| vec![&env]))
}

/// Refresh TTLs for a range of pool records to prevent archival.
///
/// This permissionless function allows keepers or any caller to proactively
Expand Down Expand Up @@ -868,6 +891,16 @@ impl Factory {
asset_pool_ids.push_back(pool_id);
env.storage().persistent().set(&asset_key, &asset_pool_ids);
bump_asset_pools(&env, &asset);

let admin_key = DataKey::PoolsByAdmin(admin.clone());
let mut admin_pool_ids: Vec<u32> = env
.storage()
.persistent()
.get(&admin_key)
.unwrap_or_else(|| vec![&env]);
admin_pool_ids.push_back(pool_id);
env.storage().persistent().set(&admin_key, &admin_pool_ids);
bump_admin_pools(&env, &admin);
env.storage()
.instance()
.set(&DataKey::PoolCount, &next_count);
Expand Down
19 changes: 19 additions & 0 deletions soroban/contracts/factory/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1459,3 +1459,22 @@ fn test_admin_transfer_count_increments_on_transfer() {
assert!(result.is_err());
assert_eq!(t.client.admin_transfer_count(), 2);
}

#[test]
fn test_get_pools_by_admin_returns_created_pools() {
let t = setup();
assert_eq!(t.client.get_pools_by_admin(&t.admin), vec![&t.env]);

let asset1 = Address::generate(&t.env);
let id1 = t
.client
.create_pool(&asset1, &1_728_000u128, &2u32, &10u64, &0i128);

let asset2 = Address::generate(&t.env);
let id2 = t
.client
.create_pool(&asset2, &3_456_000u128, &2u32, &20u64, &0i128);

let pools = t.client.get_pools_by_admin(&t.admin);
assert_eq!(pools, vec![&t.env, id1, id2]);
}
66 changes: 66 additions & 0 deletions soroban/contracts/farming-pool/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,39 @@ fn subtract_total_staked(env: &Env, amount: i128) {
);
}

fn add_total_locked(env: &Env, amount: i128) {
let total = env
.storage()
.instance()
.get::<DataKey, i128>(&DataKey::TotalLocked)
.unwrap_or(0);
env.storage().instance().set(
&DataKey::TotalLocked,
&total.checked_add(amount).expect("total locked overflow"),
);
}

fn subtract_total_locked(env: &Env, amount: i128) {
let total = env
.storage()
.instance()
.get::<DataKey, i128>(&DataKey::TotalLocked)
.unwrap_or(0);
env.storage().instance().set(
&DataKey::TotalLocked,
&total.checked_sub(amount).expect("total locked underflow"),
);
}

fn read_boost_count(env: &Env) -> u32 {
env.storage().instance().get(&DataKey::BoostCount).unwrap_or(0)
}

fn increment_boost_count(env: &Env) {
let count = read_boost_count(env);
env.storage().instance().set(&DataKey::BoostCount, &(count + 1));
}

fn is_user_staked(env: &Env, user: &Address) -> bool {
get_position(env, user).is_some() || get_user_stake(env, user).is_some()
}
Expand Down Expand Up @@ -584,6 +617,7 @@ impl FarmingPool {
.instance()
.set(&DataKey::MinStakeAmount, &min_stake);
env.storage().instance().set(&DataKey::TotalStaked, &0i128);
env.storage().instance().set(&DataKey::TotalLocked, &0i128);
env.storage()
.instance()
.set(&DataKey::TotalCredits, &0i128);
Expand Down Expand Up @@ -788,6 +822,7 @@ impl FarmingPool {
}
increment_lock_count(&env);
add_total_staked(&env, amount);
add_total_locked(&env, amount);

let stake_token = get_stake_token(&env)?;
token::TokenClient::new(&env, &stake_token).transfer(
Expand Down Expand Up @@ -844,6 +879,7 @@ impl FarmingPool {
decrement_staked_user_count(&env);
}
subtract_total_staked(&env, amount);
subtract_total_locked(&env, amount);

let stake_token = get_stake_token(&env)?;
token::TokenClient::new(&env, &stake_token).transfer(
Expand Down Expand Up @@ -1041,6 +1077,7 @@ impl FarmingPool {
token.transfer(&env.current_contract_address(), &user, &position.amount);
total_returned += position.amount;
subtract_total_staked(&env, position.amount);
subtract_total_locked(&env, position.amount);
position_credits = position.total_credits;
remove_position(&env, &user);
}
Expand Down Expand Up @@ -1407,6 +1444,9 @@ impl FarmingPool {
}

let key = DataKey::UserBoost(user.clone());
if !env.storage().persistent().has(&key) {
increment_boost_count(&env);
}
env.storage().persistent().set(&key, &allocation_pct);
bump_user(&env, &key);

Expand Down Expand Up @@ -1714,6 +1754,32 @@ impl FarmingPool {
pub fn get_unstake_count(env: Env) -> Result<u32, PoolError> {
Self::unstake_count(env)
}

/// Return the total number of boost configurations configured across users (#230).
pub fn boost_count(env: Env) -> Result<u32, PoolError> {
require_initialized(&env)?;
bump_instance(&env);
Ok(read_boost_count(&env))
}

pub fn get_boost_count(env: Env) -> Result<u32, PoolError> {
Self::boost_count(env)
}

/// Return the total tokens locked across all position locking positions (#232).
pub fn total_locked(env: Env) -> Result<i128, PoolError> {
require_initialized(&env)?;
bump_instance(&env);
Ok(env
.storage()
.instance()
.get(&DataKey::TotalLocked)
.unwrap_or(0))
}

pub fn get_total_locked(env: Env) -> Result<i128, PoolError> {
Self::total_locked(env)
}
}

mod test;
2 changes: 1 addition & 1 deletion soroban/contracts/vesting-wallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ impl VestingWallet {
#[allow(deprecated)]
env.events().publish(
(symbol_short!("vest"), symbol_short!("released")),
(beneficiary, releasable),
(beneficiary, releasable, released + releasable),
);

Ok(releasable)
Expand Down
13 changes: 13 additions & 0 deletions soroban/contracts/vesting-wallet/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,19 @@ fn test_release_emits_event() {
);
}

#[test]
fn test_release_emits_event_with_cumulative_total() {
let t = setup(0, 100, 1_000);
advance_ledgers(&t.env, 50);
t.client.release(); // 500 released

advance_ledgers(&t.env, 25);
t.client.release(); // 250 releasable, cumulative total 750

let events = t.env.events().all();
assert!(!events.events().is_empty());
}

// ── revoke tests ──────────────────────────────────────────────────────────────

#[test]
Expand Down