From e5f64c01370fd855e4804e8c7db4d0393c8dac17 Mon Sep 17 00:00:00 2001 From: edehvictor Date: Fri, 27 Mar 2026 14:58:00 +0100 Subject: [PATCH] feat(creator-keys): implement initial sell-key flow --- creator-keys/src/lib.rs | 34 +++++++++++ creator-keys/tests/sell_key.rs | 100 +++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 creator-keys/tests/sell_key.rs diff --git a/creator-keys/src/lib.rs b/creator-keys/src/lib.rs index a3cecd0..8058a23 100644 --- a/creator-keys/src/lib.rs +++ b/creator-keys/src/lib.rs @@ -284,6 +284,40 @@ impl CreatorKeysContract { Ok(profile.supply) } + pub fn sell_key(env: Env, creator: Address, seller: Address) -> Result { + seller.require_auth(); + + let mut profile: CreatorProfile = + read_creator_profile(&env, &creator).ok_or(ContractError::NotRegistered)?; + + let balance_key = DataKey::KeyBalance(creator.clone(), seller); + let current_balance: u32 = env.storage().persistent().get(&balance_key).unwrap_or(0); + if current_balance == 0 { + return Err(ContractError::InsufficientBalance); + } + + let new_balance = current_balance + .checked_sub(1) + .ok_or(ContractError::Overflow)?; + profile.supply = profile + .supply + .checked_sub(1) + .ok_or(ContractError::Overflow)?; + + if new_balance == 0 { + profile.holder_count = profile + .holder_count + .checked_sub(1) + .ok_or(ContractError::Overflow)?; + } + + let key = DataKey::Creator(creator); + env.storage().persistent().set(&key, &profile); + env.storage().persistent().set(&balance_key, &new_balance); + + Ok(profile.supply) + } + pub fn get_key_balance(env: Env, creator: Address, wallet: Address) -> u32 { let key = DataKey::KeyBalance(creator, wallet); env.storage().persistent().get(&key).unwrap_or(0) diff --git a/creator-keys/tests/sell_key.rs b/creator-keys/tests/sell_key.rs new file mode 100644 index 0000000..8262d51 --- /dev/null +++ b/creator-keys/tests/sell_key.rs @@ -0,0 +1,100 @@ +//! Tests for the initial `sell_key` contract flow. + +use creator_keys::{ContractError, CreatorKeysContract, CreatorKeysContractClient}; +use soroban_sdk::{testutils::Address as _, Address, Env, String}; + +fn setup(env: &Env) -> (CreatorKeysContractClient<'_>, Address, Address) { + let contract_id = env.register(CreatorKeysContract, ()); + let client = CreatorKeysContractClient::new(env, &contract_id); + + let admin = Address::generate(env); + client.set_key_price(&admin, &100_i128); + + let creator = Address::generate(env); + client.register_creator(&creator, &String::from_str(env, "alice")); + + (client, admin, creator) +} + +#[test] +fn test_sell_key_decrements_supply_and_balance() { + let env = Env::default(); + env.mock_all_auths(); + + let (client, _admin, creator) = setup(&env); + let seller = Address::generate(&env); + + client.buy_key(&creator, &seller, &100_i128); + client.buy_key(&creator, &seller, &100_i128); + + let new_supply = client.sell_key(&creator, &seller); + + assert_eq!(new_supply, 1); + assert_eq!(client.get_total_key_supply(&creator), 1); + assert_eq!(client.get_key_balance(&creator, &seller), 1); +} + +#[test] +fn test_sell_key_removes_holder_when_last_key_is_sold() { + let env = Env::default(); + env.mock_all_auths(); + + let (client, _admin, creator) = setup(&env); + let seller = Address::generate(&env); + + client.buy_key(&creator, &seller, &100_i128); + assert_eq!(client.get_creator_holder_count(&creator), 1); + + let new_supply = client.sell_key(&creator, &seller); + + assert_eq!(new_supply, 0); + assert_eq!(client.get_total_key_supply(&creator), 0); + assert_eq!(client.get_key_balance(&creator, &seller), 0); + assert_eq!(client.get_creator_holder_count(&creator), 0); +} + +#[test] +fn test_sell_key_preserves_holder_count_when_seller_still_has_keys() { + let env = Env::default(); + env.mock_all_auths(); + + let (client, _admin, creator) = setup(&env); + let seller = Address::generate(&env); + + client.buy_key(&creator, &seller, &100_i128); + client.buy_key(&creator, &seller, &100_i128); + assert_eq!(client.get_creator_holder_count(&creator), 1); + + let new_supply = client.sell_key(&creator, &seller); + + assert_eq!(new_supply, 1); + assert_eq!(client.get_key_balance(&creator, &seller), 1); + assert_eq!(client.get_creator_holder_count(&creator), 1); +} + +#[test] +fn test_sell_key_fails_for_unregistered_creator() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register(CreatorKeysContract, ()); + let client = CreatorKeysContractClient::new(&env, &contract_id); + + let creator = Address::generate(&env); + let seller = Address::generate(&env); + + let result = client.try_sell_key(&creator, &seller); + assert_eq!(result, Err(Ok(ContractError::NotRegistered))); +} + +#[test] +fn test_sell_key_fails_when_seller_has_no_keys() { + let env = Env::default(); + env.mock_all_auths(); + + let (client, _admin, creator) = setup(&env); + let seller = Address::generate(&env); + + let result = client.try_sell_key(&creator, &seller); + assert_eq!(result, Err(Ok(ContractError::InsufficientBalance))); +}