From 646698b5f0ad62f7ae37e5f15e303c26ac34f317 Mon Sep 17 00:00:00 2001 From: razeprasine Date: Tue, 2 Jun 2026 11:48:05 +0100 Subject: [PATCH 1/3] fixes issue 274 --- creator-keys/tests/key_supply.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/creator-keys/tests/key_supply.rs b/creator-keys/tests/key_supply.rs index 07306c7..d83b111 100644 --- a/creator-keys/tests/key_supply.rs +++ b/creator-keys/tests/key_supply.rs @@ -55,6 +55,30 @@ fn test_get_total_key_supply_increments_after_buy() { assert_eq!(client.get_total_key_supply(&creator), 2); } +#[test] +fn test_get_total_key_supply_increments_after_three_sequential_buys() { + let env = Env::default(); + env.mock_all_auths(); + let (client, _) = setup(&env); + + let creator = Address::generate(&env); + let buyer1 = Address::generate(&env); + let buyer2 = Address::generate(&env); + let buyer3 = Address::generate(&env); + client.register_creator(&creator, &String::from_str(&env, "alice")); + + assert_eq!(client.get_total_key_supply(&creator), 0); + + client.buy_key(&creator, &buyer1, &100_i128); + assert_eq!(client.get_total_key_supply(&creator), 1); + + client.buy_key(&creator, &buyer2, &100_i128); + assert_eq!(client.get_total_key_supply(&creator), 2); + + client.buy_key(&creator, &buyer3, &100_i128); + assert_eq!(client.get_total_key_supply(&creator), 3); +} + #[test] fn test_get_total_key_supply_is_read_only() { let env = Env::default(); From 1ff27bdf1ef56b911080e323db1b9566856c8d80 Mon Sep 17 00:00:00 2001 From: razeprasine Date: Mon, 29 Jun 2026 08:29:33 +0100 Subject: [PATCH 2/3] fixes issue 275 - add regression test for buy revert when creator not registered --- creator-keys/src/lib.rs | 65 -------------------------------- creator-keys/tests/buy_key.rs | 28 +++++++++++++- creator-keys/tests/key_supply.rs | 8 ++-- 3 files changed, 31 insertions(+), 70 deletions(-) diff --git a/creator-keys/src/lib.rs b/creator-keys/src/lib.rs index 90cd751..648b9b6 100644 --- a/creator-keys/src/lib.rs +++ b/creator-keys/src/lib.rs @@ -1210,71 +1210,6 @@ impl CreatorKeysContract { Ok(profile.supply) } - /// Transfers creator keys between two wallets without changing total supply. - pub fn transfer_keys( - env: Env, - from: Address, - to: Address, - creator: Address, - amount: u32, - ) -> Result<(), ContractError> { - from.require_auth(); - assert_not_paused(&env)?; - - if amount == 0 { - return Err(ContractError::NotPositiveAmount); - } - if from == to { - return Err(ContractError::ZeroAddress); - } - - let mut profile = read_registered_creator_profile(&env, &creator)?; - let from_key = constants::storage::key_balance(&creator, &from); - let to_key = constants::storage::key_balance(&creator, &to); - - let from_balance: u32 = env.storage().persistent().get(&from_key).unwrap_or(0); - if from_balance < amount { - return Err(ContractError::InsufficientBalance); - } - - let to_balance: u32 = env.storage().persistent().get(&to_key).unwrap_or(0); - - settle_holder_dividends(&env, &creator, &from, from_balance)?; - settle_holder_dividends(&env, &creator, &to, to_balance)?; - - let new_from_balance = from_balance - .checked_sub(amount) - .ok_or(ContractError::SellUnderflow)?; - let new_to_balance = to_balance - .checked_add(amount) - .ok_or(ContractError::Overflow)?; - - if new_from_balance == 0 { - profile.holder_count = profile - .holder_count - .checked_sub(1) - .ok_or(ContractError::SellUnderflow)?; - } - if to_balance == 0 { - profile.holder_count = profile - .holder_count - .checked_add(1) - .ok_or(ContractError::Overflow)?; - } - - let profile_key = constants::storage::creator(&creator); - env.storage().persistent().set(&profile_key, &profile); - env.storage().persistent().set(&from_key, &new_from_balance); - env.storage().persistent().set(&to_key, &new_to_balance); - - env.events() - .publish(events::transfer_event_topics(&creator, &from), (to, amount)); - - extend_creator_ttl(&env, &creator); - - Ok(()) - } - /// Creator-only buyback that burns keys from the creator's own held balance. /// /// The creator pays the current gross buyback cost plus protocol fee, while the diff --git a/creator-keys/tests/buy_key.rs b/creator-keys/tests/buy_key.rs index bf894c1..d326d26 100644 --- a/creator-keys/tests/buy_key.rs +++ b/creator-keys/tests/buy_key.rs @@ -3,7 +3,7 @@ mod contract_test_env; use contract_test_env::{ - compute_expected_buy_price, register_creator_keys, register_test_creator, + capture_snapshot, compute_expected_buy_price, register_creator_keys, register_test_creator, set_key_price_for_tests, set_protocol_fee_bps, test_env_with_auths, }; use creator_keys::ContractError; @@ -52,6 +52,32 @@ fn test_buy_key_insufficient_payment_fails() { assert_eq!(result, Err(Ok(ContractError::InsufficientPayment))); } +#[test] +fn test_buy_key_unregistered_creator_no_state_mutation() { + let env = test_env_with_auths(); + let (client, _) = register_creator_keys(&env); + let base_price = 100i128; + set_key_price_for_tests(&env, &client, base_price); + set_protocol_fee_bps(&env, &client, 9000u32, 1000u32); + + let registered = register_test_creator(&env, &client, "alice"); + let buyer = Address::generate(&env); + client.buy_key(®istered, &buyer, &base_price, &None); + + let snapshot_before = capture_snapshot(&client, ®istered, &buyer); + + let unregistered = Address::generate(&env); + let result = client.try_buy_key(&unregistered, &buyer, &base_price, &None); + assert_eq!(result, Err(Ok(ContractError::NotRegistered))); + + let snapshot_after = capture_snapshot(&client, ®istered, &buyer); + snapshot_before.assert_unchanged(&snapshot_after); + + assert_eq!(client.get_total_key_supply(&unregistered), 0); + assert_eq!(client.get_key_balance(&unregistered, &buyer), 0); + assert_eq!(client.get_creator_holder_count(&unregistered), 0); +} + #[test] fn test_buy_key_sufficient_payment_succeeds() { let env = test_env_with_auths(); diff --git a/creator-keys/tests/key_supply.rs b/creator-keys/tests/key_supply.rs index d83b111..d2cd3c4 100644 --- a/creator-keys/tests/key_supply.rs +++ b/creator-keys/tests/key_supply.rs @@ -65,17 +65,17 @@ fn test_get_total_key_supply_increments_after_three_sequential_buys() { let buyer1 = Address::generate(&env); let buyer2 = Address::generate(&env); let buyer3 = Address::generate(&env); - client.register_creator(&creator, &String::from_str(&env, "alice")); + client.register_creator(&creator, &String::from_str(&env, "alice"), &None, &None); assert_eq!(client.get_total_key_supply(&creator), 0); - client.buy_key(&creator, &buyer1, &100_i128); + client.buy_key(&creator, &buyer1, &100_i128, &None); assert_eq!(client.get_total_key_supply(&creator), 1); - client.buy_key(&creator, &buyer2, &100_i128); + client.buy_key(&creator, &buyer2, &100_i128, &None); assert_eq!(client.get_total_key_supply(&creator), 2); - client.buy_key(&creator, &buyer3, &100_i128); + client.buy_key(&creator, &buyer3, &100_i128, &None); assert_eq!(client.get_total_key_supply(&creator), 3); } From 6ffa6b893cc5d4e4235b31575656b9b5c0b82e2f Mon Sep 17 00:00:00 2001 From: razeprasine Date: Mon, 29 Jun 2026 08:43:31 +0100 Subject: [PATCH 3/3] fix transfer_keys parameter order in peer_to_peer_transfer_supply_regression --- creator-keys/tests/peer_to_peer_transfer_supply_regression.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/creator-keys/tests/peer_to_peer_transfer_supply_regression.rs b/creator-keys/tests/peer_to_peer_transfer_supply_regression.rs index 0b6351d..0aadab8 100644 --- a/creator-keys/tests/peer_to_peer_transfer_supply_regression.rs +++ b/creator-keys/tests/peer_to_peer_transfer_supply_regression.rs @@ -25,7 +25,7 @@ fn test_transfer_keys_keeps_supply_and_same_level_quotes_unchanged() { let buy_quote_before = client.get_buy_quote(&creator); let sell_quote_before = client.get_sell_quote(&creator, &sender); - client.transfer_keys(&sender, &recipient, &creator, &1); + client.transfer_keys(&creator, &sender, &recipient, &1); assert_eq!( client.get_total_key_supply(&creator),