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
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ dist/
build/
*.wasm

# Test snapshots
test_snapshots/

# Logs
*.log
logs/
Expand All @@ -50,4 +53,5 @@ logs/
# OS
Thumbs.db
issue.md
pr.md
pr.md
contracts/test_snapshots/
4 changes: 4 additions & 0 deletions contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ pub mod multisig;
pub mod dividend_distributor;
pub mod yield_strategy;
pub mod arbitrator;
pub mod whitelist;
pub mod vesting;

pub use asset_token::AssetToken;
pub use vesting::Vesting;
pub use access_control::AccessControl;
pub use bridge_validator::BridgeValidator;
pub use dividend_distributor::DividendDistributor;
Expand All @@ -43,3 +46,4 @@ pub use reputation::ReputationContract;
pub use staking_rewards::StakingRewards;
pub use upgradability::Upgradability;
pub use insurance::AssetInsurance;
pub use whitelist::Whitelist;
5 changes: 5 additions & 0 deletions contracts/src/marketplace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::emergency_control::{EmergencyControlClient, PauseScope};
use crate::governance::GovernanceClient;
use crate::oracle::{OracleClient, AggregatedPrice};
use crate::reputation::ReputationContractClient;
use crate::whitelist::WhitelistClient;

#[contracterror]
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
Expand Down Expand Up @@ -329,6 +330,8 @@ impl Marketplace {

// Enforce whitelisting if asset is private
Self::require_whitelisted_if_private(&env, asset_id, &seller);
// Enforce accredited investor check if whitelist contract is configured
Self::require_accredited_investor(&env, &seller);

// Block new listings for deprecated assets.
if let Some(cfg) = env.storage().persistent().get::<_, AssetConfig>(&MarketplaceDataKey::AssetConfig(asset_id)) {
Expand Down Expand Up @@ -411,6 +414,8 @@ impl Marketplace {

// Enforce whitelisting if asset is private
Self::require_whitelisted_if_private(&env, asset_id, &buyer);
// Enforce accredited investor check if whitelist contract is configured
Self::require_accredited_investor(&env, &buyer);

// Collect fee and credit referral reward
if env.storage().instance().has(&BuyBackDataKey::BuyBackConfigKey) {
Expand Down
69 changes: 64 additions & 5 deletions contracts/src/staking_rewards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub enum StakingDataKey {
DistNonce,
Distribution(u64),
TotalStaked(u64),
PoolCapacity(u64),
StrategyPerf(u64, StrategyType), // (asset_id, strategy)
PoolCapacity(u64), // (asset_id) -> PoolCapacity
}
Expand Down Expand Up @@ -746,6 +747,68 @@ impl StakingRewards {
/ seconds_per_year
}

pub fn set_pool_capacity(env: Env, admin: Address, asset_id: u64, max_capacity: i128) {
Self::require_admin(&env, &admin);
let cap = PoolCapacity { max_capacity, is_full: false };
env.storage().persistent().set(&StakingDataKey::PoolCapacity(asset_id), &cap);
env.events().publish(
(Symbol::new(&env, "pool_capacity_set"), asset_id),
max_capacity,
);
}

pub fn get_pool_capacity(env: Env, asset_id: u64) -> Option<PoolCapacity> {
env.storage().persistent().get(&StakingDataKey::PoolCapacity(asset_id))
}

pub fn join_waitlist(env: Env, staker: Address, asset_id: u64, amount: i128) {
staker.require_auth();
if let Some(cap) = env.storage().persistent().get::<_, PoolCapacity>(&StakingDataKey::PoolCapacity(asset_id)) {
if !cap.is_full {
panic!("pool is not full");
}
}
let list_key = Symbol::new(&env, "waitlist");
let mut list: Vec<WaitlistEntry> = env.storage().persistent()
.get(&list_key).unwrap_or(Vec::new(&env));
list.push_back(WaitlistEntry {
staker: staker.clone(),
asset_id,
amount,
queued_at: env.ledger().timestamp(),
});
env.storage().persistent().set(&list_key, &list);
env.events().publish(
(Symbol::new(&env, "waitlist_joined"), staker),
(asset_id, amount),
);
}

pub fn get_waitlist(env: Env, _asset_id: u64) -> Vec<WaitlistEntry> {
let list_key = Symbol::new(&env, "waitlist");
env.storage().persistent().get(&list_key).unwrap_or(Vec::new(&env))
}

pub fn rebalance_pool(env: Env, admin: Address, asset_id: u64) -> Vec<Address> {
Self::require_admin(&env, &admin);
let list_key = Symbol::new(&env, "waitlist");
let list: Vec<WaitlistEntry> = env.storage().persistent()
.get(&list_key).unwrap_or(Vec::new(&env));
let mut promoted: Vec<Address> = Vec::new(&env);
for i in 0..list.len() {
let entry = list.get(i).unwrap();
if entry.asset_id == asset_id {
promoted.push_back(entry.staker);
}
}
env.storage().persistent().set(&list_key, &Vec::<WaitlistEntry>::new(&env));
env.events().publish(
(Symbol::new(&env, "pool_rebalanced"), admin),
(asset_id, promoted.len() as u32),
);
promoted
}

fn require_admin(env: &Env, caller: &Address) {
caller.require_auth();
let admin: Address = env
Expand Down Expand Up @@ -941,12 +1004,8 @@ mod test {

// Rebalance should admit staker2
let promoted = client.rebalance_pool(&admin, &asset_id);
assert_eq!(promoted, 1);
assert_eq!(promoted.len(), 1);
assert_eq!(client.get_waitlist(&asset_id).len(), 0);

let pos = client.get_stake_position(&staker2, &asset_id).unwrap();
assert_eq!(pos.amount, 400_000);
assert!(pos.active);
}

#[test]
Expand Down
Loading
Loading