diff --git a/creator-keys/src/lib.rs b/creator-keys/src/lib.rs index 0f00497..a50d994 100644 --- a/creator-keys/src/lib.rs +++ b/creator-keys/src/lib.rs @@ -3101,4 +3101,4 @@ mod tests { } #[cfg(test)] -mod test_issues; +mod test_issues; \ No newline at end of file diff --git a/creator-keys/tests/emergency_pause.rs b/creator-keys/tests/emergency_pause.rs index 9027894..517cfa5 100644 --- a/creator-keys/tests/emergency_pause.rs +++ b/creator-keys/tests/emergency_pause.rs @@ -217,6 +217,7 @@ fn test_pause_blocks_registration_not_reads() { // Unpause — creator_b registration must now succeed client.unpause(&admin); assert!(!client.get_is_paused()); + let _ = client .try_register_creator( &creator_b, diff --git a/creator-keys/tests/flat_curve_lower_than_linear_regression.rs b/creator-keys/tests/flat_curve_lower_than_linear_regression.rs index eece476..5ddbf0f 100644 --- a/creator-keys/tests/flat_curve_lower_than_linear_regression.rs +++ b/creator-keys/tests/flat_curve_lower_than_linear_regression.rs @@ -14,45 +14,45 @@ use contract_test_env::{ register_creator_keys, register_test_creator, set_curve_slope, set_pricing_and_fees, test_env_with_auths, }; -use soroban_sdk::{testutils::Address as _, Address}; +use creator_keys::constants; +use soroban_sdk::Address; const KEY_PRICE: i128 = 1_000; const CREATOR_BPS: u32 = 9_000; const PROTOCOL_BPS: u32 = 1_000; const LINEAR_SLOPE: i128 = 1; -// Covers price + fees at any supply ≤ 10_000 with slope=1 (max price = 11_000) -const SAFE_PAYMENT: i128 = KEY_PRICE * 30; - -fn advance_supply_to( +fn set_registered_supply( + env: &soroban_sdk::Env, + contract_id: &Address, client: &creator_keys::CreatorKeysContractClient<'_>, creator: &Address, - buyer: &Address, target: u32, ) { - let current = client.get_total_key_supply(creator); - for _ in current..target { - client.buy_key(creator, buyer, &SAFE_PAYMENT, &None); - } + let mut profile = client.get_creator(creator); + profile.supply = target; + env.as_contract(contract_id, || { + env.storage() + .persistent() + .set(&constants::storage::creator(creator), &profile); + }); } #[test] fn test_flat_buy_price_lower_than_linear_at_supply_100() { let env = test_env_with_auths(); - let (client, _) = register_creator_keys(&env); + let (client, contract_id) = register_creator_keys(&env); set_pricing_and_fees(&env, &client, KEY_PRICE, CREATOR_BPS, PROTOCOL_BPS); - let buyer = Address::generate(&env); - // Flat curve: slope = 0 → price stays at KEY_PRICE regardless of supply set_curve_slope(&env, &client, 0); let creator_flat = register_test_creator(&env, &client, "flat"); - advance_supply_to(&client, &creator_flat, &buyer, 100); + set_registered_supply(&env, &contract_id, &client, &creator_flat, 100); let flat_quote = client.get_buy_quote(&creator_flat); // Linear curve: slope > 0 → price grows with supply set_curve_slope(&env, &client, LINEAR_SLOPE); let creator_linear = register_test_creator(&env, &client, "linear"); - advance_supply_to(&client, &creator_linear, &buyer, 100); + set_registered_supply(&env, &contract_id, &client, &creator_linear, 100); let linear_quote = client.get_buy_quote(&creator_linear); assert!( @@ -66,19 +66,17 @@ fn test_flat_buy_price_lower_than_linear_at_supply_100() { #[test] fn test_flat_buy_price_lower_than_linear_at_supply_1000() { let env = test_env_with_auths(); - let (client, _) = register_creator_keys(&env); + let (client, contract_id) = register_creator_keys(&env); set_pricing_and_fees(&env, &client, KEY_PRICE, CREATOR_BPS, PROTOCOL_BPS); - let buyer = Address::generate(&env); - set_curve_slope(&env, &client, 0); let creator_flat = register_test_creator(&env, &client, "flat"); - advance_supply_to(&client, &creator_flat, &buyer, 1000); + set_registered_supply(&env, &contract_id, &client, &creator_flat, 1000); let flat_quote = client.get_buy_quote(&creator_flat); set_curve_slope(&env, &client, LINEAR_SLOPE); let creator_linear = register_test_creator(&env, &client, "linear"); - advance_supply_to(&client, &creator_linear, &buyer, 1000); + set_registered_supply(&env, &contract_id, &client, &creator_linear, 1000); let linear_quote = client.get_buy_quote(&creator_linear); assert!( @@ -92,19 +90,17 @@ fn test_flat_buy_price_lower_than_linear_at_supply_1000() { #[test] fn test_flat_buy_price_lower_than_linear_at_supply_10000() { let env = test_env_with_auths(); - let (client, _) = register_creator_keys(&env); + let (client, contract_id) = register_creator_keys(&env); set_pricing_and_fees(&env, &client, KEY_PRICE, CREATOR_BPS, PROTOCOL_BPS); - let buyer = Address::generate(&env); - set_curve_slope(&env, &client, 0); let creator_flat = register_test_creator(&env, &client, "flat"); - advance_supply_to(&client, &creator_flat, &buyer, 10_000); + set_registered_supply(&env, &contract_id, &client, &creator_flat, 10_000); let flat_quote = client.get_buy_quote(&creator_flat); set_curve_slope(&env, &client, LINEAR_SLOPE); let creator_linear = register_test_creator(&env, &client, "linear"); - advance_supply_to(&client, &creator_linear, &buyer, 10_000); + set_registered_supply(&env, &contract_id, &client, &creator_linear, 10_000); let linear_quote = client.get_buy_quote(&creator_linear); assert!( diff --git a/creator-keys/tests/whitelist_window.rs b/creator-keys/tests/whitelist_window.rs new file mode 100644 index 0000000..cd34519 --- /dev/null +++ b/creator-keys/tests/whitelist_window.rs @@ -0,0 +1,152 @@ +mod contract_test_env; + +use contract_test_env::{ + compute_expected_buy_price, register_creator_keys, set_key_price_for_tests, test_env_with_auths, +}; +use creator_keys::{ContractError, WhitelistConfig, MAX_WHITELIST_SIZE}; +use soroban_sdk::{ + testutils::{Address as _, Ledger}, + vec, Address, String, Vec, +}; + +fn register_whitelisted_creator( + env: &soroban_sdk::Env, + client: &creator_keys::CreatorKeysContractClient<'_>, + whitelist: Vec
, + window_ledgers: u32, +) -> Address { + let creator = Address::generate(env); + client.register_creator( + &creator, + &String::from_str(env, "alice"), + &None, + &None, + &None, + &Some(WhitelistConfig { + addresses: whitelist, + window_ledgers, + }), + ); + creator +} + +fn advance_ledgers(env: &soroban_sdk::Env, ledgers: u32) { + let mut ledger = env.ledger().get(); + ledger.sequence_number += ledgers; + env.ledger().set(ledger); +} + +#[test] +fn test_non_whitelisted_wallet_cannot_buy_during_window() { + let env = test_env_with_auths(); + let (client, _) = register_creator_keys(&env); + set_key_price_for_tests(&env, &client, 100); + let approved = Address::generate(&env); + let creator = register_whitelisted_creator(&env, &client, vec![&env, approved], 10); + let buyer = Address::generate(&env); + + let result = client.try_buy_key(&creator, &buyer, &100, &None); + + assert_eq!(result, Err(Ok(ContractError::WhitelistOnly))); + assert_eq!(client.get_total_key_supply(&creator), 0); +} + +#[test] +fn test_whitelisted_wallet_can_buy_during_window() { + let env = test_env_with_auths(); + let (client, _) = register_creator_keys(&env); + set_key_price_for_tests(&env, &client, 100); + let buyer = Address::generate(&env); + let creator = register_whitelisted_creator(&env, &client, vec![&env, buyer.clone()], 10); + + let supply = client.buy_key(&creator, &buyer, &100, &None); + + assert_eq!(supply, 1); + assert_eq!(client.get_key_balance(&creator, &buyer), 1); +} + +#[test] +fn test_anyone_can_buy_after_window_expires() { + let env = test_env_with_auths(); + let (client, _) = register_creator_keys(&env); + set_key_price_for_tests(&env, &client, 100); + let approved = Address::generate(&env); + let creator = register_whitelisted_creator(&env, &client, vec![&env, approved], 5); + advance_ledgers(&env, 5); + let public_buyer = Address::generate(&env); + + let supply = client.buy_key(&creator, &public_buyer, &100, &None); + + assert_eq!(supply, 1); +} + +#[test] +fn test_get_whitelist_status_tracks_active_and_expired_state() { + let env = test_env_with_auths(); + let (client, _) = register_creator_keys(&env); + let buyer = Address::generate(&env); + let registered_at = env.ledger().sequence(); + let creator = register_whitelisted_creator(&env, &client, vec![&env, buyer], 7); + + let active = client.get_whitelist_status(&creator); + assert!(active.active); + assert_eq!(active.expires_at_ledger, registered_at + 7); + assert_eq!(active.remaining_ledgers, 7); + + advance_ledgers(&env, 7); + let expired = client.get_whitelist_status(&creator); + assert!(!expired.active); + assert_eq!(expired.expires_at_ledger, registered_at + 7); + assert_eq!(expired.remaining_ledgers, 0); +} + +#[test] +fn test_whitelist_over_500_addresses_reverts_at_registration() { + let env = test_env_with_auths(); + let (client, _) = register_creator_keys(&env); + let creator = Address::generate(&env); + let mut addresses = Vec::new(&env); + for _ in 0..=MAX_WHITELIST_SIZE { + addresses.push_back(Address::generate(&env)); + } + + let result = client.try_register_creator( + &creator, + &String::from_str(&env, "alice"), + &None, + &None, + &None, + &Some(WhitelistConfig { + addresses, + window_ledgers: 10, + }), + ); + + assert_eq!(result, Err(Ok(ContractError::WhitelistTooLarge))); + assert!(!client.is_creator_registered(&creator)); +} + +#[test] +fn test_none_whitelist_allows_public_buy_immediately() { + let env = test_env_with_auths(); + let (client, _) = register_creator_keys(&env); + set_key_price_for_tests(&env, &client, 100); + let creator = Address::generate(&env); + client.register_creator( + &creator, + &String::from_str(&env, "alice"), + &None, + &None, + &None, + &None, + ); + let buyer = Address::generate(&env); + + let quote = compute_expected_buy_price(0, 100); + let supply = client.buy_key(&creator, &buyer, "e, &None); + let status = client.get_whitelist_status(&creator); + + assert_eq!(supply, 1); + assert!(!status.active); + assert_eq!(status.remaining_ledgers, 0); +}