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
13 changes: 13 additions & 0 deletions contract/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ fn load_config(env: &Env) -> Result<Config, InsightArenaError> {
.ok_or(InsightArenaError::NotInitialized)
}

fn validate_protocol_fee(fee_bps: u32) -> Result<(), InsightArenaError> {
if fee_bps > 10_000 {
return Err(InsightArenaError::InvalidFee);
}

Ok(())
}

// ── Entry-point logic (called from contractimpl in lib.rs) ────────────────────

/// One-time contract setup.
Expand All @@ -66,6 +74,8 @@ pub fn initialize(
return Err(InsightArenaError::AlreadyInitialized);
}

validate_protocol_fee(fee_bps)?;

let config = Config {
admin,
protocol_fee_bps: fee_bps,
Expand Down Expand Up @@ -121,6 +131,8 @@ pub fn update_protocol_fee(env: &Env, new_fee_bps: u32) -> Result<(), InsightAre
// Authorisation check — reverts the entire transaction if auth is absent.
config.admin.require_auth();

validate_protocol_fee(new_fee_bps)?;

config.protocol_fee_bps = new_fee_bps;
env.storage().persistent().set(&DataKey::Config, &config);
bump_config(env);
Expand All @@ -133,6 +145,7 @@ pub fn update_protocol_fee_from_governance(
new_fee_bps: u32,
) -> Result<(), InsightArenaError> {
let mut config = load_config(env)?;
validate_protocol_fee(new_fee_bps)?;
config.protocol_fee_bps = new_fee_bps;
env.storage().persistent().set(&DataKey::Config, &config);
bump_config(env);
Expand Down
198 changes: 1 addition & 197 deletions contract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ impl InsightArenaContract {
season::get_active_season(&env)
}

pub fn update_leaderboard(
pub fn update_leaderboard(
env: Env,
admin: Address,
season_id: u32,
Expand Down Expand Up @@ -449,202 +449,6 @@ impl InsightArenaContract {

// ── Tests ─────────────────────────────────────────────────────────────────────

#[cfg(test)]
mod config_tests {
use soroban_sdk::testutils::Address as _;
use soroban_sdk::{Address, Env};
use super::{InsightArenaContract, InsightArenaContractClient, InsightArenaError};

fn deploy(env: &Env) -> InsightArenaContractClient<'_> {
let id = env.register(InsightArenaContract, ());
InsightArenaContractClient::new(env, &id)
}

fn register_token(env: &Env) -> Address {
let token_admin = Address::generate(env);
env.register_stellar_asset_contract_v2(token_admin)
.address()
}

#[test]
fn ensure_not_paused_ok_when_running() {
let env = Env::default();
env.mock_all_auths();
let client = deploy(&env);
let admin = Address::generate(&env);
let oracle = Address::generate(&env);
client.initialize(&admin, &oracle, &200_u32, &register_token(&env));
client.get_config();
}

#[test]
fn ensure_not_paused_err_when_paused() {
let env = Env::default();
env.mock_all_auths();
let client = deploy(&env);
let admin = Address::generate(&env);
let oracle = Address::generate(&env);
client.initialize(&admin, &oracle, &200_u32, &register_token(&env));
client.set_paused(&true);
let result = client.try_get_config();
assert!(matches!(result, Err(Ok(InsightArenaError::Paused))));
}

#[test]
fn ensure_not_paused_not_initialized() {
let env = Env::default();
env.mock_all_auths();
let client = deploy(&env);
let result = client.try_get_config();
assert!(matches!(result, Err(Ok(InsightArenaError::NotInitialized))));
}

#[test]
fn ensure_not_paused_ok_after_unpause() {
let env = Env::default();
env.mock_all_auths();
let client = deploy(&env);
let admin = Address::generate(&env);
let oracle = Address::generate(&env);
client.initialize(&admin, &oracle, &200_u32, &register_token(&env));
client.set_paused(&true);
client.set_paused(&false);
client.get_config();
}
}

#[cfg(test)]
mod leaderboard_tests {
use soroban_sdk::testutils::Address as _;
use soroban_sdk::{vec, Address, Env};
use super::{
InsightArenaContract, InsightArenaContractClient, InsightArenaError, LeaderboardEntry,
};

fn deploy(env: &Env) -> (InsightArenaContractClient<'_>, Address, Address) {
let id = env.register(InsightArenaContract, ());
let client = InsightArenaContractClient::new(env, &id);
let admin = Address::generate(env);
let oracle = Address::generate(env);
let token_admin = Address::generate(env);
let xlm_token = env
.register_stellar_asset_contract_v2(token_admin)
.address();
env.mock_all_auths();
client.initialize(&admin, &oracle, &200_u32, &xlm_token);
(client, admin, xlm_token)
}

#[test]
fn test_update_and_get_historical_leaderboard() {
let env = Env::default();
env.mock_all_auths();
let (client, admin, xlm_token) = deploy(&env);

let reward_pool = 10_000_000;
let token_client = soroban_sdk::token::Client::new(&env, &xlm_token);
soroban_sdk::token::StellarAssetClient::new(&env, &xlm_token).mint(&admin, &reward_pool);
token_client.approve(&admin, &client.address, &reward_pool, &9999);

let season_id = client.create_season(&admin, &100, &200, &reward_pool);
let user1 = Address::generate(&env);
let user2 = Address::generate(&env);
let entries = vec![
&env,
LeaderboardEntry {
rank: 1,
user: user1.clone(),
points: 100,
correct_predictions: 10,
total_predictions: 15,
},
LeaderboardEntry {
rank: 2,
user: user2.clone(),
points: 80,
correct_predictions: 8,
total_predictions: 12,
},
];

client.update_leaderboard(&admin, &season_id, &entries);

let snapshot = client.get_leaderboard(&season_id);
assert_eq!(snapshot.season_id, season_id);
assert_eq!(snapshot.entries.len(), 2);
assert_eq!(snapshot.entries.get(0).unwrap().user, user1);
assert_eq!(snapshot.entries.get(1).unwrap().user, user2);
}

#[test]
fn test_list_snapshot_seasons_deduplication() {
let env = Env::default();
env.mock_all_auths();
let (client, admin, xlm_token) = deploy(&env);

let reward_pool = 20_000_000;
soroban_sdk::token::StellarAssetClient::new(&env, &xlm_token).mint(&admin, &reward_pool);
soroban_sdk::token::Client::new(&env, &xlm_token).approve(
&admin,
&client.address,
&reward_pool,
&9999,
);

let s1 = client.create_season(&admin, &100, &200, &10_000_000);
let s2 = client.create_season(&admin, &201, &300, &10_000_000);

assert_eq!(client.list_snapshot_seasons().len(), 0);

let entries = vec![
&env,
LeaderboardEntry {
rank: 1,
user: Address::generate(&env),
points: 10,
correct_predictions: 1,
total_predictions: 1,
},
];

client.update_leaderboard(&admin, &s1, &entries);
assert_eq!(client.list_snapshot_seasons().len(), 1);
client.update_leaderboard(&admin, &s1, &entries);
assert_eq!(client.list_snapshot_seasons().len(), 1);
client.update_leaderboard(&admin, &s2, &entries);
assert_eq!(client.list_snapshot_seasons().len(), 2);
}

#[test]
fn test_get_leaderboard_not_found() {
let env = Env::default();
env.mock_all_auths();
let (client, _, _) = deploy(&env);
let result = client.try_get_leaderboard(&99);
assert!(matches!(result, Err(Ok(InsightArenaError::SeasonNotFound))));
}

#[test]
fn test_update_leaderboard_unauthorized() {
let env = Env::default();
env.mock_all_auths();
let (client, _, _) = deploy(&env);
let stranger = Address::generate(&env);
let result = client.try_update_leaderboard(&stranger, &1, &vec![&env]);
assert!(matches!(result, Err(Ok(InsightArenaError::Unauthorized))));
}

#[test]
fn test_update_leaderboard_when_paused() {
let env = Env::default();
env.mock_all_auths();
let (client, admin, _) = deploy(&env);
client.set_paused(&true);
let result = client.try_update_leaderboard(&admin, &1, &vec![&env]);
assert!(matches!(result, Err(Ok(InsightArenaError::Paused))));
}
}

#[cfg(test)]
mod season_tests;

Expand Down
Loading
Loading