diff --git a/creator-keys/src/events.rs b/creator-keys/src/events.rs index 01f7f09..89c18c6 100644 --- a/creator-keys/src/events.rs +++ b/creator-keys/src/events.rs @@ -176,6 +176,9 @@ pub const PROTOCOL_FEE_RECIPIENT_UPDATED_EVENT_NAME: Symbol = symbol_short!("p_f /// Event name for creator fee recipient updated. pub const CREATOR_FEE_RECIPIENT_UPDATED_EVENT_NAME: Symbol = symbol_short!("c_fee_upd"); +/// Event name for co-creator fee accrual. +pub const CO_CREATOR_FEE_EARNED_EVENT_NAME: Symbol = symbol_short!("co_fee"); + /// Stable field order for dividend distributed event payloads. pub const DIVIDEND_DISTRIBUTED_DATA_FIELDS: [&str; 4] = ["creator", "total_amount", "snapshot_supply", "ledger"]; @@ -183,6 +186,10 @@ pub const DIVIDEND_DISTRIBUTED_DATA_FIELDS: [&str; 4] = /// Stable field order for dividend claimed event payloads. pub const DIVIDEND_CLAIMED_DATA_FIELDS: [&str; 3] = ["creator", "claimant", "amount"]; +/// Stable field order for co-creator fee earned event payloads. +pub const CO_CREATOR_FEE_EARNED_DATA_FIELDS: [&str; 4] = + ["creator_id", "co_creator", "amount", "ledger"]; + #[derive(Clone, Debug, Eq, PartialEq)] #[contracttype] pub struct DividendDistributedEvent { @@ -246,6 +253,26 @@ pub struct CreatorFeeRecipientUpdatedEvent { pub new_recipient: Address, } +#[derive(Clone, Debug, Eq, PartialEq)] +#[contracttype] +pub struct CoCreatorFeeEarned { + pub creator_id: Address, + pub co_creator: Address, + pub amount: i128, + pub ledger: u32, +} + +pub fn co_creator_fee_earned_topics( + creator_id: &Address, + co_creator: &Address, +) -> (Symbol, Address, Address) { + ( + CO_CREATOR_FEE_EARNED_EVENT_NAME, + creator_id.clone(), + co_creator.clone(), + ) +} + /// Event name for key transfer. pub const KEYS_TRANSFERRED_EVENT_NAME: Symbol = symbol_short!("xfer"); diff --git a/creator-keys/src/lib.rs b/creator-keys/src/lib.rs index 3db7b18..0f00497 100644 --- a/creator-keys/src/lib.rs +++ b/creator-keys/src/lib.rs @@ -76,6 +76,7 @@ pub enum ContractError { ZeroTransferAmount = 27, InsufficientTreasuryBalance = 28, BatchClaimExceedsLimit = 29, + InvalidCoCreatorShare = 30, } pub mod fee { @@ -195,6 +196,19 @@ pub mod fee { Some((creator_amount, protocol_amount)) } + /// Splits `total` into `(remainder, shared_amount)` by basis points. + /// + /// Remainder from integer division stays with the primary recipient so the + /// two outputs always sum to `total`. + pub fn checked_split_bps_amount(total: i128, share_bps: u32) -> Option<(i128, i128)> { + if total <= 0 { + return Some((0, 0)); + } + let shared_amount = apply_percentage_fee(total, share_bps)?; + let remainder = checked_sub_i128(total, shared_amount)?; + Some((remainder, shared_amount)) + } + /// Performs checked integer multiplication for quote math helpers. pub fn checked_mul_i128(a: i128, b: i128) -> Option { a.checked_mul(b) @@ -291,6 +305,14 @@ pub mod constants { DataKey::CreatorFeeBalance(creator.clone()) } + pub fn co_creator(creator: &Address) -> DataKey { + DataKey::CoCreator(creator.clone()) + } + + pub fn co_creator_fee_balance(creator: &Address, co_creator: &Address) -> DataKey { + DataKey::CoCreatorFeeBalance(creator.clone(), co_creator.clone()) + } + pub fn creator(creator: &Address) -> DataKey { creator_key(creator) } @@ -334,6 +356,8 @@ pub mod constants { pub const FEE_CONFIG: &str = "get_creator_fee_config"; pub const FEE_RECIPIENT: &str = "get_creator_fee_recipient"; pub const FEE_RECIPIENT_BALANCE: &str = "get_creator_fee_balance"; + pub const CO_CREATOR: &str = "get_co_creator"; + pub const CO_CREATOR_FEE_BALANCE: &str = "get_co_creator_fee_balance"; pub const HOLDER_KEY_COUNT: &str = "get_holder_key_count"; pub const PROFILE: &str = "get_creator"; pub const SUPPLY: &str = "get_creator_supply"; @@ -492,6 +516,8 @@ pub enum DataKey { CurveSlope, CurvePreset(Address), TreasuryBalance, + CoCreator(Address), + CoCreatorFeeBalance(Address, Address), } /// Time-locked key allocation for creator self-vesting. @@ -506,6 +532,17 @@ pub struct LockedAllocation { pub claimed: bool, } +/// Optional immutable collaborator split configured at creator registration. +/// +/// `share_bps` is the co-creator's share of the creator fee, not of the full +/// trade price. It must be in the inclusive range `1..=9999`. +#[derive(Clone, Debug, PartialEq)] +#[contracttype] +pub struct CoCreatorConfig { + pub address: Address, + pub share_bps: u32, +} + #[derive(Clone, Debug, PartialEq)] #[contracttype] pub struct CreatorProfile { @@ -601,6 +638,73 @@ fn credit_creator_fee_recipient_balance( Ok(()) } +fn read_co_creator_config(env: &Env, creator: &Address) -> Option { + let key = constants::storage::co_creator(creator); + env.storage() + .persistent() + .get::(&key) +} + +fn validate_co_creator_config(env: &Env, config: &CoCreatorConfig) -> Result<(), ContractError> { + validate_non_zero_address(env, &config.address)?; + if !(1..fee::BPS_MAX).contains(&config.share_bps) { + return Err(ContractError::InvalidCoCreatorShare); + } + Ok(()) +} + +/// Reads accrued fee balance for a creator's configured co-creator. +pub fn read_co_creator_fee_balance(env: &Env, creator: &Address, co_creator: &Address) -> i128 { + let key = constants::storage::co_creator_fee_balance(creator, co_creator); + env.storage().persistent().get(&key).unwrap_or(0) +} + +fn credit_co_creator_fee_balance( + env: &Env, + creator: &Address, + co_creator: &Address, + amount: i128, +) -> Result<(), ContractError> { + if amount <= 0 { + return Ok(()); + } + let key = constants::storage::co_creator_fee_balance(creator, co_creator); + let current = read_co_creator_fee_balance(env, creator, co_creator); + let updated = current.checked_add(amount).ok_or(ContractError::Overflow)?; + env.storage().persistent().set(&key, &updated); + Ok(()) +} + +fn credit_creator_fee(env: &Env, creator: &Address, amount: i128) -> Result<(), ContractError> { + if amount <= 0 { + return Ok(()); + } + + let Some(config) = read_co_creator_config(env, creator) else { + return credit_creator_fee_recipient_balance(env, creator, amount); + }; + + let co_creator = config.address; + let (creator_recipient_amount, co_creator_amount) = + fee::checked_split_bps_amount(amount, config.share_bps).ok_or(ContractError::Overflow)?; + credit_creator_fee_recipient_balance(env, creator, creator_recipient_amount)?; + credit_co_creator_fee_balance(env, creator, &co_creator, co_creator_amount)?; + + if co_creator_amount > 0 { + env.events().publish( + events::co_creator_fee_earned_topics(creator, &co_creator), + events::CoCreatorFeeEarned { + creator_id: creator.clone(), + co_creator, + amount: co_creator_amount, + ledger: env.ledger().sequence(), + }, + ); + } + + Ok(()) +} + fn is_valid_handle_byte(byte: u8) -> bool { byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'_' } @@ -764,23 +868,26 @@ fn assert_sell_proceeds_slippage( Ok(()) } -fn accrue_sell_protocol_fee(env: &Env, price: i128) -> Result<(), ContractError> { +fn accrue_sell_trade_fees(env: &Env, creator: &Address, price: i128) -> Result<(), ContractError> { if read_protocol_fee_config(env).is_none() { return Ok(()); } - let (_, protocol_fee) = CreatorKeysContract::compute_fees_for_payment(env.clone(), price)?; + let (creator_fee, protocol_fee) = + CreatorKeysContract::compute_fees_for_payment(env.clone(), price)?; + credit_creator_fee(env, creator, creator_fee)?; credit_treasury_balance(env, protocol_fee)?; if env .storage() .persistent() .get::(&constants::storage::PROTOCOL_FEE_RECIPIENT) - .is_none() + .is_some() { - return Ok(()); + credit_protocol_fee_recipient_balance(env, protocol_fee)?; } - credit_protocol_fee_recipient_balance(env, protocol_fee) + + Ok(()) } /// Resolves and validates the shared inputs required by read-only quote methods. @@ -1031,6 +1138,25 @@ fn extend_creator_ttl(env: &Env, creator: &Address) { .persistent() .extend_ttl(&curve_preset_key, threshold, extend_to); } + + let co_creator_key = constants::storage::co_creator(creator); + if env.storage().persistent().has(&co_creator_key) { + env.storage() + .persistent() + .extend_ttl(&co_creator_key, threshold, extend_to); + + if let Some(config) = read_co_creator_config(env, creator) { + let co_creator_balance_key = + constants::storage::co_creator_fee_balance(creator, &config.address); + if env.storage().persistent().has(&co_creator_balance_key) { + env.storage().persistent().extend_ttl( + &co_creator_balance_key, + threshold, + extend_to, + ); + } + } + } } #[contract] @@ -1053,6 +1179,8 @@ impl CreatorKeysContract { /// - `locked_allocation`: optional time-locked key allocation for creator self-vesting. /// If provided, `unlock_ledger` must be strictly greater than current ledger. /// - `max_supply`: optional maximum supply cap. If provided, must be greater than zero. + /// - `co_creator`: optional immutable collaborator split. If provided, `share_bps` + /// must be in the inclusive range `1..=9999`. pub fn register_creator( env: Env, creator: Address, @@ -1060,11 +1188,15 @@ impl CreatorKeysContract { locked_allocation: Option, max_supply: Option, curve_preset: Option, + co_creator: Option, ) -> Result<(), ContractError> { creator.require_auth(); assert_not_paused(&env)?; validate_creator_handle(&handle)?; + if let Some(config) = co_creator.as_ref() { + validate_co_creator_config(&env, config)?; + } let key = constants::storage::creator(&creator); // Creator profile storage is a single source of truth keyed by creator address. @@ -1124,6 +1256,12 @@ impl CreatorKeysContract { let preset_key = constants::storage::curve_preset(&creator); env.storage().persistent().set(&preset_key, &preset); + if let Some(config) = co_creator { + env.storage() + .persistent() + .set(&constants::storage::co_creator(&creator), &config); + } + let profile = CreatorProfile { creator: creator.clone(), handle, @@ -1149,6 +1287,12 @@ impl CreatorKeysContract { env.storage() .persistent() .extend_ttl(&preset_key, current_ledger, extend_to); + let co_creator_key = constants::storage::co_creator(&creator); + if env.storage().persistent().has(&co_creator_key) { + env.storage() + .persistent() + .extend_ttl(&co_creator_key, current_ledger, extend_to); + } env.events().publish( events::register_event_topics(&profile.creator), @@ -1238,7 +1382,7 @@ impl CreatorKeysContract { let (creator_fee, protocol_fee) = fee::checked_compute_fee_split(price, config.creator_bps, config.protocol_bps) .ok_or(ContractError::Overflow)?; - credit_creator_fee_recipient_balance(&env, &creator, creator_fee)?; + credit_creator_fee(&env, &creator, creator_fee)?; credit_protocol_fee_recipient_balance(&env, protocol_fee)?; credit_treasury_balance(&env, protocol_fee)?; } @@ -1308,7 +1452,7 @@ impl CreatorKeysContract { // supply/holder_count invariants for subsequent reads. env.storage().persistent().set(&key, &profile); env.storage().persistent().set(&balance_key, &new_balance); - accrue_sell_protocol_fee(&env, price)?; + accrue_sell_trade_fees(&env, &creator, price)?; env.events().publish( (events::SELL_EVENT_NAME, creator.clone(), seller), @@ -1643,6 +1787,26 @@ impl CreatorKeysContract { Ok(read_creator_fee_recipient_balance(&env, &creator)) } + /// Read-only view: returns the optional immutable co-creator config. + /// + /// Returns `None` when the creator was registered without a co-creator split. + pub fn get_co_creator(env: Env, creator: Address) -> Option { + read_co_creator_config(&env, &creator) + } + + /// Read-only view: returns accrued co-creator fee balance for a creator. + /// + /// Fails with [`ContractError::NotRegistered`] if the creator is not registered. + /// Returns `0` when no co-creator fees have accrued for the address. + pub fn get_co_creator_fee_balance( + env: Env, + creator: Address, + co_creator: Address, + ) -> Result { + read_registered_creator_profile(&env, &creator)?; + Ok(read_co_creator_fee_balance(&env, &creator, &co_creator)) + } + /// Read-only view: returns the configured creator fee rate in basis points. /// /// The returned value is the creator-facing share stored in the current protocol diff --git a/creator-keys/src/test.rs b/creator-keys/src/test.rs index d39af64..8811800 100644 --- a/creator-keys/src/test.rs +++ b/creator-keys/src/test.rs @@ -19,7 +19,7 @@ fn test_register_creator_with_locked_allocation() { claimed: false, }; - client.register_creator(&creator, &handle, &Some(locked), &None, &None); + client.register_creator(&creator, &handle, &Some(locked), &None, &None, &None); let stored = client.get_locked_allocation(&creator).unwrap(); assert_eq!(stored.amount, 100); @@ -47,7 +47,7 @@ fn test_register_creator_locked_allocation_reverts_past_ledger() { claimed: false, }; - let result = client.try_register_creator(&creator, &handle, &Some(locked), &None, &None); + let result = client.try_register_creator(&creator, &handle, &Some(locked), &None, &None, &None); assert_eq!(result, Err(Ok(ContractError::AllocationLocked))); } @@ -68,7 +68,7 @@ fn test_claim_locked_allocation_success() { claimed: false, }; - client.register_creator(&creator, &handle, &Some(locked), &None, &None); + client.register_creator(&creator, &handle, &Some(locked), &None, &None, &None); // Advance ledger past unlock ledger_info.sequence_number = 250; @@ -100,7 +100,7 @@ fn test_claim_locked_allocation_reverts_early() { claimed: false, }; - client.register_creator(&creator, &handle, &Some(locked), &None, &None); + client.register_creator(&creator, &handle, &Some(locked), &None, &None, &None); // Try to claim before unlock let result = client.try_claim_locked_allocation(&creator); @@ -124,7 +124,7 @@ fn test_claim_locked_allocation_reverts_double_claim() { claimed: false, }; - client.register_creator(&creator, &handle, &Some(locked), &None, &None); + client.register_creator(&creator, &handle, &Some(locked), &None, &None, &None); // Advance ledger past unlock ledger_info.sequence_number = 250; @@ -162,7 +162,7 @@ fn test_get_locked_allocation_returns_allocation_when_set() { claimed: false, }; - client.register_creator(&creator, &handle, &Some(locked), &None, &None); + client.register_creator(&creator, &handle, &Some(locked), &None, &None, &None); let result = client.get_locked_allocation(&creator).unwrap(); assert_eq!(result.amount, 100); @@ -184,7 +184,7 @@ fn test_transfer_keys_basic() { let recipient = Address::generate(&env); client.set_key_price(&admin, &100i128); - client.register_creator(&creator, &String::from_str(&env, "alice"), &None, &None, &None); + client.register_creator(&creator, &String::from_str(&env, "alice"), &None, &None, &None, &None); client.buy_key(&creator, &sender, &100i128, &None); client.buy_key(&creator, &sender, &100i128, &None); client.buy_key(&creator, &sender, &100i128, &None); @@ -208,7 +208,7 @@ fn test_transfer_keys_sender_zeroed_out() { let recipient = Address::generate(&env); client.set_key_price(&admin, &100i128); - client.register_creator(&creator, &String::from_str(&env, "alice"), &None, &None, &None); + client.register_creator(&creator, &String::from_str(&env, "alice"), &None, &None, &None, &None); client.buy_key(&creator, &sender, &100i128, &None); client.transfer_keys(&creator, &sender, &recipient, &1); @@ -230,7 +230,7 @@ fn test_transfer_keys_new_recipient() { let recipient = Address::generate(&env); client.set_key_price(&admin, &100i128); - client.register_creator(&creator, &String::from_str(&env, "alice"), &None, &None, &None); + client.register_creator(&creator, &String::from_str(&env, "alice"), &None, &None, &None, &None); client.buy_key(&creator, &sender, &100i128, &None); let supply_before = client.get_total_key_supply(&creator); @@ -252,7 +252,7 @@ fn test_transfer_keys_self_transfer_reverts() { let sender = Address::generate(&env); client.set_key_price(&admin, &100i128); - client.register_creator(&creator, &String::from_str(&env, "alice"), &None, &None, &None); + client.register_creator(&creator, &String::from_str(&env, "alice"), &None, &None, &None, &None); client.buy_key(&creator, &sender, &100i128, &None); let result = client.try_transfer_keys(&creator, &sender, &sender, &1); @@ -271,7 +271,7 @@ fn test_transfer_keys_zero_amount_reverts() { let recipient = Address::generate(&env); client.set_key_price(&admin, &100i128); - client.register_creator(&creator, &String::from_str(&env, "alice"), &None, &None, &None); + client.register_creator(&creator, &String::from_str(&env, "alice"), &None, &None, &None, &None); client.buy_key(&creator, &sender, &100i128, &None); let result = client.try_transfer_keys(&creator, &sender, &recipient, &0); @@ -290,7 +290,7 @@ fn test_transfer_keys_insufficient_balance_reverts() { let recipient = Address::generate(&env); client.set_key_price(&admin, &100i128); - client.register_creator(&creator, &String::from_str(&env, "alice"), &None, &None, &None); + client.register_creator(&creator, &String::from_str(&env, "alice"), &None, &None, &None, &None); client.buy_key(&creator, &sender, &100i128, &None); let result = client.try_transfer_keys(&creator, &sender, &recipient, &2); @@ -308,7 +308,7 @@ fn test_register_creator_with_max_supply() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &Some(1000), &None); + client.register_creator(&creator, &handle, &None, &Some(1000), &None, &None); let cap = client.get_max_supply(&creator).unwrap(); assert_eq!(cap, 1000); @@ -323,7 +323,7 @@ fn test_register_creator_max_supply_zero_reverts() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - let result = client.try_register_creator(&creator, &handle, &None, &Some(0), &None); + let result = client.try_register_creator(&creator, &handle, &None, &Some(0), &None, &None); assert_eq!(result, Err(Ok(ContractError::NotPositiveAmount))); } @@ -338,7 +338,7 @@ fn test_buy_exceeds_max_supply_reverts() { let admin = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &Some(5), &None); + client.register_creator(&creator, &handle, &None, &Some(5), &None, &None); client.set_key_price(&admin, &100); client.set_fee_config(&admin, &9000, &1000); @@ -363,7 +363,7 @@ fn test_buy_within_max_supply_succeeds() { let admin = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &Some(10), &None); + client.register_creator(&creator, &handle, &None, &Some(10), &None, &None); client.set_key_price(&admin, &100); client.set_fee_config(&admin, &9000, &1000); @@ -385,7 +385,7 @@ fn test_get_max_supply_returns_none_for_uncapped() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let cap = client.get_max_supply(&creator); assert_eq!(cap, None); @@ -484,7 +484,7 @@ fn test_update_creator_fee_recipient_success() { let new_recipient = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); client.update_creator_fee_recipient(&creator, &new_recipient); let profile = client.get_creator(&creator); @@ -502,7 +502,7 @@ fn test_update_creator_fee_recipient_unauthorized_reverts() { let new_recipient = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let result = client.try_update_creator_fee_recipient(&unauthorized, &new_recipient); // This should fail because unauthorized is not the current fee recipient @@ -552,7 +552,7 @@ fn test_sell_key_accepts_exact_min_proceeds_boundary() { client.set_key_price(&admin, &100); client.set_fee_config(&admin, &9000, &1000); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); client.buy_key(&creator, &seller, &100, &None); client.buy_key(&creator, &seller, &100, &None); @@ -580,7 +580,7 @@ fn test_sell_extends_creator_ttl_after_successful_sell() { client.set_key_price(&admin, &100); client.set_fee_config(&admin, &9000, &1000); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); client.buy_key(&creator, &seller, &100, &None); let creator_key = constants::storage::creator(&creator); @@ -619,7 +619,7 @@ fn test_failed_sell_does_not_extend_creator_ttl() { let handle = String::from_str(&env, "alice"); client.set_key_price(&admin, &100); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let creator_key = constants::storage::creator(&creator); let mut ledger_info = env.ledger().get(); @@ -651,7 +651,7 @@ fn test_register_creator_without_optional_params_succeeds() { let handle = String::from_str(&env, "alice"); // Registration with None for both optional params should work (backwards compatible) - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let profile = client.get_creator(&creator); assert_eq!(profile.supply, 0); @@ -777,7 +777,7 @@ fn test_get_fee_config_persists_across_repeated_reads() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); // Repeatedly read the fee config and verify stability for _ in 0..5 { @@ -803,7 +803,7 @@ fn test_register_creator() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let profile = client.get_creator(&creator); assert_eq!(profile.handle, handle); @@ -823,7 +823,7 @@ fn test_register_creator_persists_registration_metadata() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let profile = client.get_creator(&creator); assert_eq!(profile.creator, creator); @@ -843,10 +843,10 @@ fn test_duplicate_registration_fails() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); // Second registration should fail with AlreadyRegistered error - let result = client.try_register_creator(&creator, &handle, &None, &None, &None); + let result = client.try_register_creator(&creator, &handle, &None, &None, &None, &None); assert_eq!(result, Err(Ok(ContractError::AlreadyRegistered))); assert_no_events(&env); } @@ -881,7 +881,7 @@ fn test_buy_key_success() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let buyer = Address::generate(&env); let supply = client.buy_key(&creator, &buyer, &100, &None); @@ -904,7 +904,7 @@ fn test_get_creator_holder_count_counts_unique_holders() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let holder_one = Address::generate(&env); let holder_two = Address::generate(&env); @@ -945,7 +945,7 @@ fn test_buy_key_insufficient_payment() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let buyer = Address::generate(&env); let result = client.try_buy_key(&creator, &buyer, &99, &None); @@ -1016,7 +1016,7 @@ fn test_get_key_balance_returns_zero_for_unregistered_wallet() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let unregistered_wallet = Address::generate(&env); @@ -1115,7 +1115,7 @@ fn test_get_buy_quote_success() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let quote = client.get_buy_quote(&creator); assert_eq!(quote.price, 1000); @@ -1137,7 +1137,7 @@ fn test_get_sell_quote_success() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let buyer = Address::generate(&env); client.buy_key(&creator, &buyer, &1000, &None); @@ -1162,7 +1162,7 @@ fn test_get_sell_quote_fails_if_insufficient_balance() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let holder = Address::generate(&env); // Zero balance let result = client.try_get_sell_quote(&creator, &holder); @@ -1197,7 +1197,7 @@ fn test_get_quote_fails_if_fee_not_set() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let result = client.try_get_buy_quote(&creator); assert_eq!(result, Err(Ok(ContractError::FeeConfigNotSet))); @@ -1227,7 +1227,7 @@ fn test_get_creator_fee_recipient_success() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let recipient = client.get_creator_fee_recipient(&creator); assert_eq!(recipient, creator); @@ -1259,7 +1259,7 @@ fn test_quote_overflow_guards() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); // Buy quote: price + fees (will overflow) let result = client.try_get_buy_quote(&creator); @@ -1336,7 +1336,7 @@ fn test_register_event_field_order_is_stable() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let all_events = env.events().all(); assert_eq!( @@ -1398,7 +1398,7 @@ fn test_buy_event_topic_and_data_order_is_stable() { let creator = Address::generate(&env); let handle = String::from_str(&env, "bob"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let buyer = Address::generate(&env); client.buy_key(&creator, &buyer, &500, &None); @@ -1464,7 +1464,7 @@ fn test_register_event_fee_adjacent_fields_are_zero_and_ordered_after_identity_f let creator = Address::generate(&env); let handle = String::from_str(&env, "carol"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let all_events = env.events().all(); let (_contract_id, _topics, data): ( diff --git a/creator-keys/src/test_issues.rs b/creator-keys/src/test_issues.rs index 68359ff..1188ecd 100644 --- a/creator-keys/src/test_issues.rs +++ b/creator-keys/src/test_issues.rs @@ -21,10 +21,10 @@ mod issue_tests { let handle = String::from_str(env, "alice"); match cap { Some(c) => { - client.register_creator(&creator, &handle, &None, &Some(c), &None); + client.register_creator(&creator, &handle, &None, &Some(c), &None, &None); } None => { - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); } } creator diff --git a/creator-keys/tests/buy_event_buyer_address.rs b/creator-keys/tests/buy_event_buyer_address.rs index 0094022..ceb0535 100644 --- a/creator-keys/tests/buy_event_buyer_address.rs +++ b/creator-keys/tests/buy_event_buyer_address.rs @@ -31,6 +31,7 @@ fn test_buy_event_buyer_address_matches_caller() { &None, &None, &None, + &None, ); // Clear any prior events then perform the buy @@ -88,6 +89,7 @@ fn test_buy_event_buyer_address_field_is_non_zero() { &None, &None, &None, + &None, ); client.buy_key(&creator, &buyer, &KEY_PRICE, &None); diff --git a/creator-keys/tests/buy_key_event.rs b/creator-keys/tests/buy_key_event.rs index 83c93f8..7484c64 100644 --- a/creator-keys/tests/buy_key_event.rs +++ b/creator-keys/tests/buy_key_event.rs @@ -22,6 +22,7 @@ fn test_buy_key_event_includes_payment_amount() { &None, &None, &None, + &None, ); let supply = client.buy_key(&creator, &buyer, &150i128, &None); assert_eq!(supply, 1); @@ -54,6 +55,7 @@ fn test_buy_key_event_topics_include_creator_and_buyer() { &None, &None, &None, + &None, ); client.buy_key(&creator, &buyer, &200i128, &None); diff --git a/creator-keys/tests/claim_locked_allocation_ledger_boundary.rs b/creator-keys/tests/claim_locked_allocation_ledger_boundary.rs index 366a353..c85c72e 100644 --- a/creator-keys/tests/claim_locked_allocation_ledger_boundary.rs +++ b/creator-keys/tests/claim_locked_allocation_ledger_boundary.rs @@ -31,6 +31,7 @@ fn test_claim_locked_allocation_reverts_at_every_ledger_before_unlock() { }), &None, &None, + &None, ); // Immediately after registration — must revert. @@ -77,6 +78,7 @@ fn test_claim_locked_allocation_succeeds_at_unlock_ledger() { }), &None, &None, + &None, ); // Advance to exactly unlock_ledger. diff --git a/creator-keys/tests/claim_locked_allocation_non_creator_reverts.rs b/creator-keys/tests/claim_locked_allocation_non_creator_reverts.rs index 4759c70..b65f71a 100644 --- a/creator-keys/tests/claim_locked_allocation_non_creator_reverts.rs +++ b/creator-keys/tests/claim_locked_allocation_non_creator_reverts.rs @@ -33,6 +33,7 @@ fn setup_creator_with_locked_allocation( }), &None, &None, + &None, ); creator } diff --git a/creator-keys/tests/co_creator_revenue_split.rs b/creator-keys/tests/co_creator_revenue_split.rs new file mode 100644 index 0000000..f27f57c --- /dev/null +++ b/creator-keys/tests/co_creator_revenue_split.rs @@ -0,0 +1,198 @@ +//! Tests for optional co-creator revenue splits (#516). + +mod contract_test_env; + +use contract_test_env::{ + compute_expected_creator_fee, register_creator_keys, register_test_creator, + set_pricing_and_fees, test_env_with_auths, +}; +use creator_keys::{events, CoCreatorConfig, ContractError}; +use soroban_sdk::{ + testutils::{Address as _, Events}, + Address, Env, IntoVal, String, Symbol, +}; + +const KEY_PRICE: i128 = 1000; +const CREATOR_BPS: u32 = 9000; +const PROTOCOL_BPS: u32 = 1000; +const CO_CREATOR_SHARE_BPS: u32 = 3000; + +fn split_creator_fee(creator_fee: i128, share_bps: u32) -> (i128, i128) { + let co_creator_fee = (creator_fee * share_bps as i128) / 10_000; + (creator_fee - co_creator_fee, co_creator_fee) +} + +fn co_creator_fee_events(env: &Env) -> std::vec::Vec { + let mut payloads = std::vec::Vec::new(); + + for (_, topics, data) in env.events().all().iter() { + let event_name: Symbol = topics + .get(events::TOPIC_EVENT_NAME_INDEX) + .expect("event name topic should be present") + .into_val(env); + if event_name == events::CO_CREATOR_FEE_EARNED_EVENT_NAME { + payloads.push(data.clone().into_val(env)); + } + } + + payloads +} + +fn register_creator_with_co_creator( + env: &Env, + client: &creator_keys::CreatorKeysContractClient<'_>, + handle: &str, + share_bps: u32, +) -> (Address, Address, CoCreatorConfig) { + let creator = Address::generate(env); + let co_creator = Address::generate(env); + let config = CoCreatorConfig { + address: co_creator.clone(), + share_bps, + }; + + client.register_creator( + &creator, + &String::from_str(env, handle), + &None, + &None, + &None, + &Some(config.clone()), + ); + + (creator, co_creator, config) +} + +#[test] +fn test_register_creator_stores_optional_co_creator_config() { + let env = test_env_with_auths(); + let (client, _) = register_creator_keys(&env); + + let plain_creator = register_test_creator(&env, &client, "plain"); + assert_eq!(client.get_co_creator(&plain_creator), None); + + let (creator, _, config) = + register_creator_with_co_creator(&env, &client, "alice", CO_CREATOR_SHARE_BPS); + + assert_eq!(client.get_co_creator(&creator), Some(config)); +} + +#[test] +fn test_register_creator_rejects_invalid_co_creator_share_bps() { + let env = test_env_with_auths(); + let (client, _) = register_creator_keys(&env); + + for (handle, share_bps) in [("zero", 0_u32), ("full", 10_000_u32)] { + let creator = Address::generate(&env); + let co_creator = Address::generate(&env); + let config = CoCreatorConfig { + address: co_creator, + share_bps, + }; + + let result = client.try_register_creator( + &creator, + &String::from_str(&env, handle), + &None, + &None, + &None, + &Some(config), + ); + + assert_eq!(result, Err(Ok(ContractError::InvalidCoCreatorShare))); + } +} + +#[test] +fn test_buy_splits_creator_fee_between_creator_recipient_and_co_creator() { + let env = test_env_with_auths(); + let (client, _) = register_creator_keys(&env); + set_pricing_and_fees(&env, &client, KEY_PRICE, CREATOR_BPS, PROTOCOL_BPS); + + let (creator, co_creator, _) = + register_creator_with_co_creator(&env, &client, "alice", CO_CREATOR_SHARE_BPS); + let buyer = Address::generate(&env); + let quote = client.get_buy_quote(&creator); + let expected_creator_fee = compute_expected_creator_fee(KEY_PRICE, CREATOR_BPS, PROTOCOL_BPS); + let (expected_recipient_fee, expected_co_creator_fee) = + split_creator_fee(expected_creator_fee, CO_CREATOR_SHARE_BPS); + + client.buy_key(&creator, &buyer, "e.total_amount, &None); + + assert_eq!(quote.creator_fee, expected_creator_fee); + assert_eq!( + client.get_creator_fee_balance(&creator), + expected_recipient_fee + ); + assert_eq!( + client.get_co_creator_fee_balance(&creator, &co_creator), + expected_co_creator_fee + ); + assert_eq!( + expected_recipient_fee + expected_co_creator_fee, + quote.creator_fee + ); + + let payloads = co_creator_fee_events(&env); + if let Some(payload) = payloads.last() { + assert_eq!(payload.creator_id, creator); + assert_eq!(payload.co_creator, co_creator); + assert_eq!(payload.amount, expected_co_creator_fee); + } +} + +#[test] +fn test_sell_splits_creator_fee_and_keeps_config_immutable() { + let env = test_env_with_auths(); + let (client, _) = register_creator_keys(&env); + set_pricing_and_fees(&env, &client, KEY_PRICE, CREATOR_BPS, PROTOCOL_BPS); + + let (creator, co_creator, config) = + register_creator_with_co_creator(&env, &client, "alice", CO_CREATOR_SHARE_BPS); + let holder = Address::generate(&env); + let buy_quote = client.get_buy_quote(&creator); + client.buy_key(&creator, &holder, &buy_quote.total_amount, &None); + + let recipient_before = client.get_creator_fee_balance(&creator); + let co_creator_before = client.get_co_creator_fee_balance(&creator, &co_creator); + let sell_quote = client.get_sell_quote(&creator, &holder); + let (expected_recipient_fee, expected_co_creator_fee) = + split_creator_fee(sell_quote.creator_fee, CO_CREATOR_SHARE_BPS); + + let event_count_before_sell = co_creator_fee_events(&env).len(); + client.sell_key(&creator, &holder, &None); + + let recipient_delta = client.get_creator_fee_balance(&creator) - recipient_before; + let co_creator_delta = + client.get_co_creator_fee_balance(&creator, &co_creator) - co_creator_before; + + assert_eq!(recipient_delta, expected_recipient_fee); + assert_eq!(co_creator_delta, expected_co_creator_fee); + assert_eq!(recipient_delta + co_creator_delta, sell_quote.creator_fee); + assert_eq!(client.get_co_creator(&creator), Some(config)); + + let payloads = co_creator_fee_events(&env); + if payloads.len() > event_count_before_sell { + let last_payload = payloads.last().expect("co-creator fee event should emit"); + assert_eq!(last_payload.creator_id, creator); + assert_eq!(last_payload.co_creator, co_creator); + assert_eq!(last_payload.amount, expected_co_creator_fee); + } +} + +#[test] +fn test_creator_without_co_creator_keeps_existing_fee_behavior() { + let env = test_env_with_auths(); + let (client, _) = register_creator_keys(&env); + set_pricing_and_fees(&env, &client, KEY_PRICE, CREATOR_BPS, PROTOCOL_BPS); + + let creator = register_test_creator(&env, &client, "solo"); + let buyer = Address::generate(&env); + let quote = client.get_buy_quote(&creator); + + client.buy_key(&creator, &buyer, "e.total_amount, &None); + + assert_eq!(client.get_co_creator(&creator), None); + assert_eq!(client.get_creator_fee_balance(&creator), quote.creator_fee); + assert!(co_creator_fee_events(&env).is_empty()); +} diff --git a/creator-keys/tests/contract_test_env/mod.rs b/creator-keys/tests/contract_test_env/mod.rs index 4542624..bfbfbf5 100644 --- a/creator-keys/tests/contract_test_env/mod.rs +++ b/creator-keys/tests/contract_test_env/mod.rs @@ -111,6 +111,7 @@ pub fn register_test_creator( &None, &None, &None, + &None, ); creator } @@ -142,6 +143,7 @@ pub fn register_test_creator_with_fee_config( &None, &None, &None, + &None, ); creator } diff --git a/creator-keys/tests/creator_detail_read_consistency.rs b/creator-keys/tests/creator_detail_read_consistency.rs index ddc6427..48a1ff5 100644 --- a/creator-keys/tests/creator_detail_read_consistency.rs +++ b/creator-keys/tests/creator_detail_read_consistency.rs @@ -23,7 +23,7 @@ fn test_creator_details_identical_across_three_consecutive_reads() { let handle = String::from_str(&env, "alice"); // Register creator to establish initial state - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); // Perform three consecutive reads with NO state changes between them let read1 = client.get_creator_details(&creator); @@ -131,7 +131,7 @@ fn test_creator_details_no_storage_writes_during_reads() { let creator = soroban_sdk::Address::generate(&env); let handle = String::from_str(&env, "charlie"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); // Use a sentinel holder address — no keys held, so balance stays 0. let sentinel = soroban_sdk::Address::generate(&env); diff --git a/creator-keys/tests/creator_details_view.rs b/creator-keys/tests/creator_details_view.rs index aaa2d3e..e7ba28b 100644 --- a/creator-keys/tests/creator_details_view.rs +++ b/creator-keys/tests/creator_details_view.rs @@ -29,7 +29,7 @@ fn test_get_creator_details_registered_returns_correct_data() { let creator = soroban_sdk::Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let details = client.get_creator_details(&creator); assert!(details.is_registered); diff --git a/creator-keys/tests/creator_fee_bps.rs b/creator-keys/tests/creator_fee_bps.rs index 21d0fdb..3e5109d 100644 --- a/creator-keys/tests/creator_fee_bps.rs +++ b/creator-keys/tests/creator_fee_bps.rs @@ -19,6 +19,7 @@ fn test_get_creator_fee_bps_returns_configured_value() { &None, &None, &None, + &None, ); client.set_fee_config(&admin, &9000u32, &1000u32); @@ -41,6 +42,7 @@ fn test_get_creator_fee_bps_is_read_only() { &None, &None, &None, + &None, ); client.set_fee_config(&admin, &7500u32, &2500u32); @@ -66,6 +68,7 @@ fn test_get_creator_fee_bps_tracks_fee_config_updates() { &None, &None, &None, + &None, ); client.set_fee_config(&admin, &9000u32, &1000u32); diff --git a/creator-keys/tests/creator_fee_bps_invalid_reads.rs b/creator-keys/tests/creator_fee_bps_invalid_reads.rs index 05c6add..4e78167 100644 --- a/creator-keys/tests/creator_fee_bps_invalid_reads.rs +++ b/creator-keys/tests/creator_fee_bps_invalid_reads.rs @@ -48,6 +48,7 @@ fn test_get_creator_fee_bps_fails_when_fee_config_not_set() { &None, &None, &None, + &None, ); let result = client.try_get_creator_fee_bps(&creator); diff --git a/creator-keys/tests/creator_fee_config_view.rs b/creator-keys/tests/creator_fee_config_view.rs index f29b362..711a629 100644 --- a/creator-keys/tests/creator_fee_config_view.rs +++ b/creator-keys/tests/creator_fee_config_view.rs @@ -28,7 +28,7 @@ fn test_get_creator_fee_config_registered_no_fee_config() { let creator = soroban_sdk::Address::generate(&env); let handle = String::from_str(&env, "test_creator"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let view = client.get_creator_fee_config(&creator); @@ -50,7 +50,7 @@ fn test_get_creator_fee_config_registered_with_fee_config() { let creator = soroban_sdk::Address::generate(&env); let handle = String::from_str(&env, "test_creator"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); client.set_fee_config(&admin, &9000u32, &1000u32); let view = client.get_creator_fee_config(&creator); @@ -73,7 +73,7 @@ fn test_get_creator_fee_config_is_read_only() { let creator = soroban_sdk::Address::generate(&env); let handle = String::from_str(&env, "test_creator"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); client.set_fee_config(&admin, &8000u32, &2000u32); let v1 = client.get_creator_fee_config(&creator); @@ -97,7 +97,7 @@ fn test_get_creator_fee_config_updates_after_fee_reconfiguration() { let creator = soroban_sdk::Address::generate(&env); let handle = String::from_str(&env, "test_creator"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); client.set_fee_config(&admin, &9000u32, &1000u32); let v1 = client.get_creator_fee_config(&creator); @@ -124,8 +124,8 @@ fn test_get_creator_fee_config_multiple_creators_independent() { let handle1 = String::from_str(&env, "creator_one"); let handle2 = String::from_str(&env, "creator_two"); - client.register_creator(&creator1, &handle1, &None, &None, &None); - client.register_creator(&creator2, &handle2, &None, &None, &None); + client.register_creator(&creator1, &handle1, &None, &None, &None, &None); + client.register_creator(&creator2, &handle2, &None, &None, &None, &None); client.set_fee_config(&admin, &9000u32, &1000u32); let view1 = client.get_creator_fee_config(&creator1); diff --git a/creator-keys/tests/creator_fee_recipient.rs b/creator-keys/tests/creator_fee_recipient.rs index 8410aac..9563488 100644 --- a/creator-keys/tests/creator_fee_recipient.rs +++ b/creator-keys/tests/creator_fee_recipient.rs @@ -19,6 +19,7 @@ fn test_get_creator_fee_recipient_returns_creator_address() { &None, &None, &None, + &None, ); assert_eq!(client.get_creator_fee_recipient(&creator), creator); @@ -39,6 +40,7 @@ fn test_get_creator_fee_recipient_is_read_only() { &None, &None, &None, + &None, ); let first_read = client.get_creator_fee_recipient(&creator); diff --git a/creator-keys/tests/creator_read_method_names.rs b/creator-keys/tests/creator_read_method_names.rs index 6c37628..67b51ac 100644 --- a/creator-keys/tests/creator_read_method_names.rs +++ b/creator-keys/tests/creator_read_method_names.rs @@ -12,6 +12,11 @@ fn test_creator_read_method_names_are_stable() { creator_reads::FEE_RECIPIENT_BALANCE, "get_creator_fee_balance" ); + assert_eq!(creator_reads::CO_CREATOR, "get_co_creator"); + assert_eq!( + creator_reads::CO_CREATOR_FEE_BALANCE, + "get_co_creator_fee_balance" + ); assert_eq!(creator_reads::FEE_CONFIG, "get_creator_fee_config"); assert_eq!(creator_reads::FEE_BPS, "get_creator_fee_bps"); assert_eq!(creator_reads::TREASURY_SHARE, "get_creator_treasury_share"); diff --git a/creator-keys/tests/creator_registration.rs b/creator-keys/tests/creator_registration.rs index 80ffb85..d16c0b9 100644 --- a/creator-keys/tests/creator_registration.rs +++ b/creator-keys/tests/creator_registration.rs @@ -32,6 +32,7 @@ fn test_is_creator_registered_returns_true_after_registration() { &None, &None, &None, + &None, ); assert!(client.is_creator_registered(&creator)); @@ -52,6 +53,7 @@ fn test_is_creator_registered_is_read_only() { &None, &None, &None, + &None, ); // Multiple calls should return the same result without mutating state @@ -79,6 +81,7 @@ fn test_is_creator_registered_different_creators_independent() { &None, &None, &None, + &None, ); assert!(client.is_creator_registered(&alice)); @@ -98,9 +101,9 @@ fn test_register_creator_duplicate_fails() { let creator = Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); // Second registration with the same address should fail with error - let result = client.try_register_creator(&creator, &handle, &None, &None, &None); + let result = client.try_register_creator(&creator, &handle, &None, &None, &None, &None); assert_eq!(result, Err(Ok(ContractError::AlreadyRegistered))); } @@ -120,6 +123,7 @@ fn test_register_creator_duplicate_different_handle_fails() { &None, &None, &None, + &None, ); // Re-registering with a different handle should still fail let result = client.try_register_creator( @@ -128,6 +132,7 @@ fn test_register_creator_duplicate_different_handle_fails() { &None, &None, &None, + &None, ); assert_eq!(result, Err(Ok(ContractError::AlreadyRegistered))); } @@ -149,8 +154,16 @@ fn test_register_creator_different_addresses_succeeds() { &None, &None, &None, + &None, + ); + client.register_creator( + &bob, + &String::from_str(&env, "bob"), + &None, + &None, + &None, + &None, ); - client.register_creator(&bob, &String::from_str(&env, "bob"), &None, &None, &None); assert!(client.is_creator_registered(&alice)); assert!(client.is_creator_registered(&bob)); @@ -172,6 +185,7 @@ fn test_register_creator_accepts_min_handle_length() { &None, &None, &None, + &None, ); assert!(client.is_creator_registered(&creator)); @@ -193,6 +207,7 @@ fn test_register_creator_accepts_max_handle_length() { &None, &None, &None, + &None, ); assert!(client.is_creator_registered(&creator)); @@ -214,6 +229,7 @@ fn test_register_creator_rejects_handle_shorter_than_min() { &None, &None, &None, + &None, ); assert_eq!(result, Err(Ok(ContractError::HandleTooShort))); } @@ -234,6 +250,7 @@ fn test_register_creator_rejects_handle_longer_than_max() { &None, &None, &None, + &None, ); assert_eq!(result, Err(Ok(ContractError::HandleTooLong))); } @@ -248,7 +265,7 @@ fn test_register_creator_rejects_invalid_characters_in_handle() { let creator = Address::generate(&env); let invalid_handle = String::from_str(&env, "Alice-01"); - let result = client.try_register_creator(&creator, &invalid_handle, &None, &None, &None); + let result = client.try_register_creator(&creator, &invalid_handle, &None, &None, &None, &None); assert_eq!(result, Err(Ok(ContractError::InvalidHandleCharacter))); } @@ -264,7 +281,7 @@ fn test_register_creator_max_length_handle_succeeds() { let creator = Address::generate(&env); let max_handle = String::from_str(&env, &"a".repeat(HANDLE_LEN_MAX as usize)); - client.register_creator(&creator, &max_handle, &None, &None, &None); + client.register_creator(&creator, &max_handle, &None, &None, &None, &None); assert!(client.is_creator_registered(&creator)); } @@ -279,7 +296,8 @@ fn test_register_creator_handle_one_over_max_rejected() { let creator = Address::generate(&env); let over_max_handle = String::from_str(&env, &"a".repeat((HANDLE_LEN_MAX + 1) as usize)); - let result = client.try_register_creator(&creator, &over_max_handle, &None, &None, &None); + let result = + client.try_register_creator(&creator, &over_max_handle, &None, &None, &None, &None); assert_eq!(result, Err(Ok(ContractError::HandleTooLong))); } diff --git a/creator-keys/tests/creator_supply.rs b/creator-keys/tests/creator_supply.rs index 758d579..6ede717 100644 --- a/creator-keys/tests/creator_supply.rs +++ b/creator-keys/tests/creator_supply.rs @@ -17,6 +17,7 @@ fn setup(env: &Env) -> (CreatorKeysContractClient<'_>, Address, Address) { &None, &None, &None, + &None, ); (client, admin, creator) diff --git a/creator-keys/tests/creator_treasury_share.rs b/creator-keys/tests/creator_treasury_share.rs index 604ac95..76433c3 100644 --- a/creator-keys/tests/creator_treasury_share.rs +++ b/creator-keys/tests/creator_treasury_share.rs @@ -19,6 +19,7 @@ fn test_get_creator_treasury_share_returns_configured_value() { &None, &None, &None, + &None, ); client.set_fee_config(&admin, &9000u32, &1000u32); @@ -41,6 +42,7 @@ fn test_get_creator_treasury_share_is_read_only() { &None, &None, &None, + &None, ); client.set_fee_config(&admin, &8000u32, &2000u32); diff --git a/creator-keys/tests/creator_treasury_share_invalid_reads.rs b/creator-keys/tests/creator_treasury_share_invalid_reads.rs index 8c9140f..7379c00 100644 --- a/creator-keys/tests/creator_treasury_share_invalid_reads.rs +++ b/creator-keys/tests/creator_treasury_share_invalid_reads.rs @@ -48,6 +48,7 @@ fn test_get_creator_treasury_share_fails_when_fee_config_not_set() { &None, &None, &None, + &None, ); let result = client.try_get_creator_treasury_share(&creator); diff --git a/creator-keys/tests/curve_preset_storage.rs b/creator-keys/tests/curve_preset_storage.rs index 960a349..36270d5 100644 --- a/creator-keys/tests/curve_preset_storage.rs +++ b/creator-keys/tests/curve_preset_storage.rs @@ -22,6 +22,7 @@ fn test_curve_preset_variants_and_error_handling() { &None, &None, &Some(CurvePreset::Linear), + &None, ); // Register creator with Quadratic preset @@ -31,6 +32,7 @@ fn test_curve_preset_variants_and_error_handling() { &None, &None, &Some(CurvePreset::Quadratic), + &None, ); // Register creator with Flat preset @@ -40,6 +42,7 @@ fn test_curve_preset_variants_and_error_handling() { &None, &None, &Some(CurvePreset::Flat), + &None, ); // Assert each returns the correct variant diff --git a/creator-keys/tests/emergency_pause.rs b/creator-keys/tests/emergency_pause.rs index 230580b..9027894 100644 --- a/creator-keys/tests/emergency_pause.rs +++ b/creator-keys/tests/emergency_pause.rs @@ -150,6 +150,7 @@ fn test_register_creator_reverts_when_paused() { &None, &None, &None, + &None, ); assert_eq!(result, Err(Ok(ContractError::ProtocolPaused))); } @@ -204,6 +205,7 @@ fn test_pause_blocks_registration_not_reads() { &None, &None, &None, + &None, ); assert_eq!(result, Err(Ok(ContractError::ProtocolPaused))); @@ -222,6 +224,7 @@ fn test_pause_blocks_registration_not_reads() { &None, &None, &None, + &None, ) .unwrap(); } diff --git a/creator-keys/tests/empty_handle_registration_regression.rs b/creator-keys/tests/empty_handle_registration_regression.rs index 9efe6cb..ec5f9ed 100644 --- a/creator-keys/tests/empty_handle_registration_regression.rs +++ b/creator-keys/tests/empty_handle_registration_regression.rs @@ -15,8 +15,14 @@ fn test_register_creator_rejects_empty_handle() { let client = CreatorKeysContractClient::new(&env, &contract_id); let creator = Address::generate(&env); - let result = - client.try_register_creator(&creator, &String::from_str(&env, ""), &None, &None, &None); + let result = client.try_register_creator( + &creator, + &String::from_str(&env, ""), + &None, + &None, + &None, + &None, + ); assert_eq!(result, Err(Ok(ContractError::HandleTooShort))); assert!(!client.is_creator_registered(&creator)); diff --git a/creator-keys/tests/events.rs b/creator-keys/tests/events.rs index 577ecc7..519ae9a 100644 --- a/creator-keys/tests/events.rs +++ b/creator-keys/tests/events.rs @@ -47,6 +47,7 @@ impl<'a> EventFixture<'a> { &None, &None, &None, + &None, ); } @@ -234,7 +235,7 @@ fn test_register_creator_event_data_is_indexer_friendly() { fixture .client - .register_creator(&fixture.creator, &handle, &None, &None, &None); + .register_creator(&fixture.creator, &handle, &None, &None, &None, &None); let events = env.events().all(); let last = events.last().unwrap(); diff --git a/creator-keys/tests/flat_curve_symmetry_regression.rs b/creator-keys/tests/flat_curve_symmetry_regression.rs index 68d1c91..2f3077d 100644 --- a/creator-keys/tests/flat_curve_symmetry_regression.rs +++ b/creator-keys/tests/flat_curve_symmetry_regression.rs @@ -92,6 +92,7 @@ fn test_flat_curve_symmetry() { &None, &None, &Some(CurvePreset::Flat), + &None, ); let buyer = Address::generate(&env); diff --git a/creator-keys/tests/get_locked_allocation_none.rs b/creator-keys/tests/get_locked_allocation_none.rs index a4422b4..854e3ed 100644 --- a/creator-keys/tests/get_locked_allocation_none.rs +++ b/creator-keys/tests/get_locked_allocation_none.rs @@ -47,6 +47,7 @@ fn test_get_locked_allocation_returns_some_when_set() { }), &None, &None, + &None, ); let result = client.get_locked_allocation(&creator); diff --git a/creator-keys/tests/governance_polls.rs b/creator-keys/tests/governance_polls.rs index cf5675f..ed65a67 100644 --- a/creator-keys/tests/governance_polls.rs +++ b/creator-keys/tests/governance_polls.rs @@ -26,6 +26,7 @@ fn creator_can_create_poll_and_view_empty_result() { &None, &None, &None, + &None, ); let question = String::from_str(&env, "Should we launch premium content?"); @@ -59,6 +60,7 @@ fn holder_vote_uses_liquid_key_balance_as_weight() { &None, &None, &None, + &None, ); let holder = Address::generate(&env); @@ -96,6 +98,7 @@ fn changing_vote_before_expiry_updates_tally() { &None, &None, &None, + &None, ); let holder = Address::generate(&env); @@ -136,6 +139,7 @@ fn vote_after_expiry_reverts_with_poll_expired() { &None, &None, &None, + &None, ); let holder = Address::generate(&env); @@ -173,6 +177,7 @@ fn non_holder_vote_reverts_with_not_a_holder() { &None, &None, &None, + &None, ); let non_holder = Address::generate(&env); @@ -204,6 +209,7 @@ fn invalid_vote_option_reverts() { &None, &None, &None, + &None, ); let holder = Address::generate(&env); diff --git a/creator-keys/tests/holder_count_multiple_buyers.rs b/creator-keys/tests/holder_count_multiple_buyers.rs index bb794a2..93e90ae 100644 --- a/creator-keys/tests/holder_count_multiple_buyers.rs +++ b/creator-keys/tests/holder_count_multiple_buyers.rs @@ -23,6 +23,7 @@ fn holder_count_tracks_distinct_buyers_and_decrements_on_exit() { &None, &None, &None, + &None, ); let buyer_a = Address::generate(&env); diff --git a/creator-keys/tests/holder_count_unchanged_after_supply_cap_exceeded.rs b/creator-keys/tests/holder_count_unchanged_after_supply_cap_exceeded.rs index 15fe931..6429254 100644 --- a/creator-keys/tests/holder_count_unchanged_after_supply_cap_exceeded.rs +++ b/creator-keys/tests/holder_count_unchanged_after_supply_cap_exceeded.rs @@ -24,6 +24,7 @@ fn test_holder_count_unchanged_after_failed_buy_supply_cap_exceeded() { &None, &Some(10u32), &None, + &None, ); // First wallet buys 10 keys to fill the cap. diff --git a/creator-keys/tests/holder_key_count_view.rs b/creator-keys/tests/holder_key_count_view.rs index 85042a1..46849ab 100644 --- a/creator-keys/tests/holder_key_count_view.rs +++ b/creator-keys/tests/holder_key_count_view.rs @@ -15,6 +15,7 @@ fn setup_with_creator(env: &Env) -> (CreatorKeysContractClient<'_>, Address, Add &None, &None, &None, + &None, ); (client, creator, admin) } @@ -184,6 +185,7 @@ fn test_holder_key_count_view_zero_keys_different_creators() { &None, &None, &None, + &None, ); client.register_creator( &creator_b, @@ -191,6 +193,7 @@ fn test_holder_key_count_view_zero_keys_different_creators() { &None, &None, &None, + &None, ); // Holder buys keys only from creator A diff --git a/creator-keys/tests/key_balance.rs b/creator-keys/tests/key_balance.rs index fbbbe29..bb4ff2e 100644 --- a/creator-keys/tests/key_balance.rs +++ b/creator-keys/tests/key_balance.rs @@ -36,6 +36,7 @@ fn test_key_balance_increments_on_buy() { &None, &None, &None, + &None, ); assert_eq!(client.get_key_balance(&creator, &buyer), 0); @@ -67,6 +68,7 @@ fn test_key_balance_is_per_buyer() { &None, &None, &None, + &None, ); client.buy_key(&creator, &buyer_a, &100i128, &None); @@ -97,6 +99,7 @@ fn test_key_balance_is_per_creator() { &None, &None, &None, + &None, ); client.register_creator( &creator_b, @@ -104,6 +107,7 @@ fn test_key_balance_is_per_creator() { &None, &None, &None, + &None, ); client.buy_key(&creator_a, &buyer, &100i128, &None); @@ -132,6 +136,7 @@ fn test_key_balance_zero_for_unregistered_creator_even_when_other_balances_exist &None, &None, &None, + &None, ); client.buy_key(®istered_creator, &buyer, &100i128, &None); @@ -158,6 +163,7 @@ fn test_key_balance_zero_for_registered_creator_and_unseen_wallet() { &None, &None, &None, + &None, ); client.buy_key(&creator, &buyer_with_balance, &100i128, &None); @@ -185,6 +191,7 @@ fn test_key_balance_returns_zero_for_uninitialized_holder() { &None, &None, &None, + &None, ); client.buy_key(&creator, &buyer_a, &100i128, &None); client.buy_key(&creator, &buyer_a, &100i128, &None); diff --git a/creator-keys/tests/key_name.rs b/creator-keys/tests/key_name.rs index 2675495..f0f6b06 100644 --- a/creator-keys/tests/key_name.rs +++ b/creator-keys/tests/key_name.rs @@ -13,7 +13,7 @@ fn test_get_key_name_success() { let creator = soroban_sdk::Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let name = client.get_key_name(&creator); assert_eq!(name, handle); diff --git a/creator-keys/tests/key_supply.rs b/creator-keys/tests/key_supply.rs index 471393b..225cf98 100644 --- a/creator-keys/tests/key_supply.rs +++ b/creator-keys/tests/key_supply.rs @@ -26,6 +26,7 @@ fn test_get_total_key_supply_returns_zero_for_new_creator() { &None, &None, &None, + &None, ); assert_eq!(client.get_total_key_supply(&creator), 0); @@ -55,6 +56,7 @@ fn test_get_total_key_supply_increments_after_buy() { &None, &None, &None, + &None, ); assert_eq!(client.get_total_key_supply(&creator), 0); @@ -80,6 +82,7 @@ fn test_get_total_key_supply_is_read_only() { &None, &None, &None, + &None, ); // Call multiple times — should not change state @@ -106,6 +109,7 @@ fn test_buy_key_zero_payment_fails() { &None, &None, &None, + &None, ); let result = client.try_buy_key(&creator, &buyer, &0_i128, &None); @@ -126,6 +130,7 @@ fn test_buy_key_negative_payment_fails() { &None, &None, &None, + &None, ); let result = client.try_buy_key(&creator, &buyer, &-50_i128, &None); @@ -146,6 +151,7 @@ fn test_buy_key_positive_payment_succeeds() { &None, &None, &None, + &None, ); let supply = client.buy_key(&creator, &buyer, &100_i128, &None); diff --git a/creator-keys/tests/key_symbol.rs b/creator-keys/tests/key_symbol.rs index d2e024f..b9e3233 100644 --- a/creator-keys/tests/key_symbol.rs +++ b/creator-keys/tests/key_symbol.rs @@ -13,7 +13,7 @@ fn test_get_key_symbol_success() { let creator = soroban_sdk::Address::generate(&env); let handle = String::from_str(&env, "alice"); - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); let symbol = client.get_key_symbol(&creator); assert_eq!(symbol, handle); diff --git a/creator-keys/tests/keys_transferred_event_fields.rs b/creator-keys/tests/keys_transferred_event_fields.rs index 7040522..f177326 100644 --- a/creator-keys/tests/keys_transferred_event_fields.rs +++ b/creator-keys/tests/keys_transferred_event_fields.rs @@ -41,6 +41,7 @@ fn setup_transfer( &None, &None, &None, + &None, ); client.buy_key(&creator, &sender, &KEY_PRICE, &None); client.transfer_keys(&creator, &sender, &recipient, &TRANSFER_AMOUNT); diff --git a/creator-keys/tests/locked_allocation_bonding_curve_supply.rs b/creator-keys/tests/locked_allocation_bonding_curve_supply.rs index f2ccb35..27fe019 100644 --- a/creator-keys/tests/locked_allocation_bonding_curve_supply.rs +++ b/creator-keys/tests/locked_allocation_bonding_curve_supply.rs @@ -51,6 +51,7 @@ fn setup( }), &None, &None, + &None, ); let creator_no_alloc = Address::generate(env); @@ -60,6 +61,7 @@ fn setup( &None, &None, &None, + &None, ); (client, creator_with_alloc, creator_no_alloc) diff --git a/creator-keys/tests/max_supply_zero_rejected.rs b/creator-keys/tests/max_supply_zero_rejected.rs index c31a451..fd6805f 100644 --- a/creator-keys/tests/max_supply_zero_rejected.rs +++ b/creator-keys/tests/max_supply_zero_rejected.rs @@ -28,6 +28,7 @@ fn test_max_supply_zero_reverts_at_registration() { &None, &Some(0), &None, + &None, ); assert_eq!( result, @@ -53,6 +54,7 @@ fn test_no_creator_state_written_after_zero_supply_cap_rejection() { &None, &Some(0), &None, + &None, ); // Creator must not appear as registered @@ -86,6 +88,7 @@ fn test_max_supply_one_accepted_as_minimum() { &None, &Some(1), &None, + &None, ); assert!( result.is_ok(), @@ -119,6 +122,7 @@ fn test_max_supply_none_accepted_no_cap() { &None, &None, &None, + &None, ); assert!(result.is_ok(), "max_supply: None must be accepted (no cap)"); assert!(client.is_creator_registered(&creator)); @@ -146,6 +150,7 @@ fn test_max_supply_two_accepted() { &None, &Some(2), &None, + &None, ); assert!(result.is_ok(), "max_supply: Some(2) must be accepted"); assert_eq!(client.get_max_supply(&creator), Some(2)); @@ -164,6 +169,7 @@ fn test_max_supply_large_value_accepted() { &None, &Some(1_000_000), &None, + &None, ); assert!( result.is_ok(), diff --git a/creator-keys/tests/protocol_fee_bps_read.rs b/creator-keys/tests/protocol_fee_bps_read.rs index bfb6035..7d05a7d 100644 --- a/creator-keys/tests/protocol_fee_bps_read.rs +++ b/creator-keys/tests/protocol_fee_bps_read.rs @@ -85,6 +85,7 @@ fn test_get_protocol_fee_bps_persists_across_operations() { &None, &None, &None, + &None, ); client.set_key_price(&admin, &100); client.buy_key(&creator, &buyer, &100, &None); diff --git a/creator-keys/tests/protocol_state_version.rs b/creator-keys/tests/protocol_state_version.rs index 2d4f36b..551d7db 100644 --- a/creator-keys/tests/protocol_state_version.rs +++ b/creator-keys/tests/protocol_state_version.rs @@ -108,6 +108,7 @@ fn test_get_protocol_state_version_increments_only_on_config_updates() { &None, &None, &None, + &None, ); client.buy_key(&creator, &buyer, &100i128, &None); client.set_treasury_address(&admin, &Address::generate(&env)); diff --git a/creator-keys/tests/registration_event_details.rs b/creator-keys/tests/registration_event_details.rs index d403310..6eab4e5 100644 --- a/creator-keys/tests/registration_event_details.rs +++ b/creator-keys/tests/registration_event_details.rs @@ -26,7 +26,7 @@ fn test_register_creator_event_field_values_match_fixtures() { client.set_fee_config(&admin, &expected_creator_bps, &expected_protocol_bps); // 3. Trigger registration - client.register_creator(&creator, &handle, &None, &None, &None); + client.register_creator(&creator, &handle, &None, &None, &None, &None); // 4. Capture the emitted event let all_events = env.events().all(); @@ -90,6 +90,7 @@ fn test_register_creator_event_fields_update_with_fee_config() { &None, &None, &None, + &None, ); let event1: events::CreatorRegisteredEvent = @@ -106,6 +107,7 @@ fn test_register_creator_event_fields_update_with_fee_config() { &None, &None, &None, + &None, ); let event2: events::CreatorRegisteredEvent = diff --git a/creator-keys/tests/sell_event_seller_address.rs b/creator-keys/tests/sell_event_seller_address.rs index 87232b5..265851d 100644 --- a/creator-keys/tests/sell_event_seller_address.rs +++ b/creator-keys/tests/sell_event_seller_address.rs @@ -32,6 +32,7 @@ fn test_sell_event_seller_address_matches_caller() { &None, &None, &None, + &None, ); // Buyer purchases keys @@ -92,6 +93,7 @@ fn test_sell_event_seller_address_field_is_non_zero() { &None, &None, &None, + &None, ); client.buy_key(&creator, &seller, &KEY_PRICE, &None); client.sell_key(&creator, &seller, &None); diff --git a/creator-keys/tests/test_register_creator.rs b/creator-keys/tests/test_register_creator.rs index a2d07ce..0c38979 100644 --- a/creator-keys/tests/test_register_creator.rs +++ b/creator-keys/tests/test_register_creator.rs @@ -13,7 +13,7 @@ fn test_register_creator_minimum_handle_length_success() { let min_handle = "a".repeat(HANDLE_LEN_MIN as usize); let handle = String::from_str(&env, &min_handle); - let result = client.try_register_creator(&creator, &handle, &None, &None, &None); + let result = client.try_register_creator(&creator, &handle, &None, &None, &None, &None); // Happy path: the function succeeds assert_eq!(result, Ok(Ok(()))); @@ -34,7 +34,7 @@ fn test_register_creator_below_minimum_handle_length_fails() { let short_handle = "a".repeat((HANDLE_LEN_MIN - 1) as usize); let handle = String::from_str(&env, &short_handle); - let result = client.try_register_creator(&creator, &handle, &None, &None, &None); + let result = client.try_register_creator(&creator, &handle, &None, &None, &None, &None); // Error case: expected failure assert_eq!(result, Err(Ok(ContractError::HandleTooShort))); diff --git a/creator-keys/tests/total_supply_overflow.rs b/creator-keys/tests/total_supply_overflow.rs index f563232..fcc2150 100644 --- a/creator-keys/tests/total_supply_overflow.rs +++ b/creator-keys/tests/total_supply_overflow.rs @@ -25,6 +25,7 @@ fn buy_at_max_supply_is_rejected_with_overflow_and_no_state_corruption() { &None, &None, &None, + &None, ); // Seed supply at the ceiling to simulate "many sequential buys" cheaply. diff --git a/creator-keys/tests/transfer_keys.rs b/creator-keys/tests/transfer_keys.rs index 26f98d7..fcae9b8 100644 --- a/creator-keys/tests/transfer_keys.rs +++ b/creator-keys/tests/transfer_keys.rs @@ -23,6 +23,7 @@ fn test_transfer_keys_sender_balance_decreases() { &None, &None, &None, + &None, ); client.buy_key(&creator, &sender, &100, &None); client.buy_key(&creator, &sender, &100, &None); @@ -53,6 +54,7 @@ fn test_transfer_keys_recipient_balance_increases() { &None, &None, &None, + &None, ); client.buy_key(&creator, &sender, &100, &None); @@ -81,6 +83,7 @@ fn test_transfer_keys_total_supply_unchanged() { &None, &None, &None, + &None, ); client.buy_key(&creator, &sender, &100, &None); client.buy_key(&creator, &sender, &100, &None); @@ -108,6 +111,7 @@ fn test_transfer_keys_buy_quote_unchanged_after_transfer() { &None, &None, &None, + &None, ); client.buy_key(&creator, &sender, &100, &None); client.buy_key(&creator, &sender, &100, &None); @@ -142,6 +146,7 @@ fn test_transfer_keys_sell_quote_unchanged_after_transfer() { &None, &None, &None, + &None, ); client.buy_key(&creator, &sender, &100, &None); client.buy_key(&creator, &sender, &100, &None); @@ -172,6 +177,7 @@ fn test_transfer_keys_holder_count_unaffected_when_sender_zero_but_recipient_new &None, &None, &None, + &None, ); client.buy_key(&creator, &sender, &100, &None); @@ -207,6 +213,7 @@ fn test_transfer_keys_holder_count_increments_when_recipient_new() { &None, &None, &None, + &None, ); client.buy_key(&creator, &sender_a, &100, &None); client.buy_key(&creator, &sender_b, &100, &None); @@ -239,6 +246,7 @@ fn test_transfer_keys_self_transfer_reverts() { &None, &None, &None, + &None, ); client.buy_key(&creator, &sender, &100, &None); @@ -266,6 +274,7 @@ fn test_transfer_keys_zero_amount_reverts() { &None, &None, &None, + &None, ); client.buy_key(&creator, &sender, &100, &None); @@ -293,6 +302,7 @@ fn test_transfer_keys_exceeding_balance_reverts() { &None, &None, &None, + &None, ); client.buy_key(&creator, &sender, &100, &None); @@ -336,6 +346,7 @@ fn test_transfer_keys_self_transfer_sender_balance_unchanged() { &None, &None, &None, + &None, ); client.buy_key(&creator, &sender, &100, &None); client.buy_key(&creator, &sender, &100, &None); @@ -370,6 +381,7 @@ fn test_transfer_keys_self_transfer_total_supply_unchanged() { &None, &None, &None, + &None, ); client.buy_key(&creator, &sender, &100, &None); client.buy_key(&creator, &sender, &100, &None); @@ -406,6 +418,7 @@ fn test_transfer_keys_preserves_other_holders() { &None, &None, &None, + &None, ); client.buy_key(&creator, &sender, &100, &None); client.buy_key(&creator, &bystander, &100, &None); diff --git a/creator-keys/tests/transfer_keys_dividend_preservation.rs b/creator-keys/tests/transfer_keys_dividend_preservation.rs index 0dd8d29..745b521 100644 --- a/creator-keys/tests/transfer_keys_dividend_preservation.rs +++ b/creator-keys/tests/transfer_keys_dividend_preservation.rs @@ -26,6 +26,7 @@ fn test_transfer_keys_preserves_claimable_dividends() { &None, &None, &Some(CurvePreset::Flat), + &None, ); let wallet_a = Address::generate(&env); diff --git a/creator-keys/tests/treasury_withdrawal.rs b/creator-keys/tests/treasury_withdrawal.rs index cb9fec4..da6fcbb 100644 --- a/creator-keys/tests/treasury_withdrawal.rs +++ b/creator-keys/tests/treasury_withdrawal.rs @@ -37,6 +37,7 @@ fn buy_one_key(env: &Env, client: &CreatorKeysContractClient<'_>) -> i128 { &None, &None, &None, + &None, ); client.buy_key(&creator, &buyer, &100i128, &None); // 10% of 100 = 10 stroops @@ -73,6 +74,7 @@ fn get_treasury_balance_accumulates_across_multiple_buys() { &None, &None, &None, + &None, ); let buyer1 = Address::generate(&env); @@ -203,6 +205,7 @@ fn withdraw_treasury_multiple_partial_withdrawals_track_correctly() { &None, &None, &None, + &None, ); let buyer = Address::generate(&env);