diff --git a/.freebuff/project-id b/.freebuff/project-id new file mode 100644 index 00000000..15d45306 --- /dev/null +++ b/.freebuff/project-id @@ -0,0 +1 @@ +a16e0d91-aeb4-469c-b8d2-61adab299ccc diff --git a/creator-keys/src/events.rs b/creator-keys/src/events.rs index 305375c1..8f591556 100644 --- a/creator-keys/src/events.rs +++ b/creator-keys/src/events.rs @@ -2167,6 +2167,10 @@ pub struct KeyDeprecatedEvent { pub circulating_supply: u32, /// Total XLM escrowed (`circulating_supply * buyback_price_per_key`). pub total_escrow: i128, + /// Human-readable reason supplied by the creator (#973). + pub reason: String, + /// Optional successor key address (#973). `None` when not designated. + pub successor_key_id: Option
, /// Ledger sequence number at the time of deprecation. pub ledger: u32, } diff --git a/creator-keys/src/lib.rs b/creator-keys/src/lib.rs index 83000dc3..704ca398 100644 --- a/creator-keys/src/lib.rs +++ b/creator-keys/src/lib.rs @@ -838,6 +838,11 @@ pub mod constants { DataKey::DeprecationEscrow(creator.clone()) } + /// Storage key for the rich deprecation metadata record (#973). + pub fn deprecation_info(creator: &Address) -> DataKey { + DataKey::DeprecationInfo(creator.clone()) + } + /// Storage key for the price-oracle approved-caller allowlist. pub const APPROVED_CALLERS: DataKey = DataKey::ApprovedCallers; @@ -1660,6 +1665,9 @@ pub enum DataKey { /// Escrow balance held on behalf of a deprecated key's creator. /// Funds are paid out to redeeming holders and any remainder is returned on full redemption. DeprecationEscrow(Address), + /// Rich deprecation metadata written by `deprecate_key` (#973). + /// Value is a `DeprecationInfo` struct holding reason, optional successor, and timestamp. + DeprecationInfo(Address), /// Configured early exit penalty bps for key. EarlyExitPenaltyBps(Address), /// Maximum buy quantity per transaction for a creator. @@ -2234,6 +2242,40 @@ pub struct AirdropSummary { pub skipped_count: u32, } +// ========================================================================= +// #973 — Key deprecation and successor designation +// ========================================================================= + +/// Persistent storage record written by `deprecate_key` (#973). +/// +/// Stored at `DataKey::DeprecationInfo(creator)` in addition to the existing +/// `DataKey::DeprecatedKey` marker used by the escrow-buyback path (#834). +#[derive(Clone, Debug, Eq, PartialEq)] +#[contracttype] +pub struct DeprecationInfo { + /// Human-readable reason supplied by the creator (max 256 bytes). + pub reason: String, + /// Optional address of the successor key the creator recommends holders + /// migrate to. `None` means no successor has been designated. + pub successor_key_id: Option
, + /// Ledger sequence at which `deprecate_key` was called. + pub deprecated_at_ledger: u32, +} + +/// Return type for `get_deprecation_status` (#973). +#[derive(Clone, Debug, Eq, PartialEq)] +#[contracttype] +pub struct DeprecationStatus { + /// `true` if the key has been deprecated. + pub is_deprecated: bool, + /// Human-readable reason (empty string when `is_deprecated` is `false`). + pub reason: String, + /// Optional successor key address; `None` when not deprecated or not set. + pub successor_key_id: Option
, + /// Ledger sequence of deprecation; `0` when not deprecated. + pub deprecated_at_ledger: u32, +} + fn validate_whitelist_config(config: &WhitelistConfig) -> Result<(), ContractError> { if config.addresses.len() > MAX_WHITELIST_SIZE { return Err(ContractError::WhitelistTooLarge); @@ -6435,6 +6477,7 @@ impl CreatorKeysContract { // ========================================================================= // #834 — Key deprecation and holder buybacks + // #973 — Key deprecation reason and successor designation // ========================================================================= /// Deprecates a creator key, disabling new buys and initiating an orderly @@ -6445,6 +6488,10 @@ impl CreatorKeysContract { /// [`CreatorKeysContract::redeem`] to exchange their keys for the fixed /// buyback price. /// + /// `reason` is a human-readable string (max 256 bytes) explaining why the + /// key is being deprecated. `successor_key_id` is an optional address of a + /// replacement key the creator recommends holders migrate to. + /// /// # Errors /// /// - [`ContractError::Unauthorized`] if `caller != creator`. @@ -6460,6 +6507,8 @@ impl CreatorKeysContract { caller: Address, buyback_price_per_key: i128, escrow_payment: i128, + reason: String, + successor_key_id: Option
, ) -> Result<(), ContractError> { caller.require_auth(); assert_not_paused(&env)?; @@ -6471,6 +6520,11 @@ impl CreatorKeysContract { return Err(ContractError::NotPositiveAmount); } + // Reject reason strings longer than 256 bytes. + if reason.len() > 256 { + return Err(ContractError::BioTooLong); + } + let profile = read_registered_creator_profile(&env, &creator)?; // Reject if already deprecated. @@ -6492,6 +6546,8 @@ impl CreatorKeysContract { return Err(ContractError::InsufficientEscrow); } + let current_ledger = env.ledger().sequence(); + // Persist the deprecation marker (stores the fixed buyback price). let dep_key = constants::storage::deprecated_key(&creator); env.storage() @@ -6507,6 +6563,18 @@ impl CreatorKeysContract { .set(&escrow_key, &required_escrow); extend_key_ttl_to_full_window(&env, &escrow_key); + // Persist the rich deprecation metadata (#973). + let info_key = constants::storage::deprecation_info(&creator); + env.storage().persistent().set( + &info_key, + &DeprecationInfo { + reason: reason.clone(), + successor_key_id: successor_key_id.clone(), + deprecated_at_ledger: current_ledger, + }, + ); + extend_key_ttl_to_full_window(&env, &info_key); + env.events().publish( events::key_deprecated_topics(&creator), events::KeyDeprecatedEvent { @@ -6514,7 +6582,9 @@ impl CreatorKeysContract { buyback_price_per_key, circulating_supply, total_escrow: required_escrow, - ledger: env.ledger().sequence(), + reason, + successor_key_id, + ledger: current_ledger, }, ); @@ -6530,6 +6600,47 @@ impl CreatorKeysContract { Ok(()) } + /// Returns the deprecation status for a creator key (#973). + /// + /// Always succeeds — if the key is not deprecated, returns a + /// `DeprecationStatus` with `is_deprecated = false` and zeroed fields. + pub fn get_deprecation_status(env: Env, creator: Address) -> DeprecationStatus { + let is_deprecated = env + .storage() + .persistent() + .has(&constants::storage::deprecated_key(&creator)); + + if !is_deprecated { + return DeprecationStatus { + is_deprecated: false, + reason: String::from_str(&env, ""), + successor_key_id: None, + deprecated_at_ledger: 0, + }; + } + + let info: Option = env + .storage() + .persistent() + .get(&constants::storage::deprecation_info(&creator)); + + match info { + Some(d) => DeprecationStatus { + is_deprecated: true, + reason: d.reason, + successor_key_id: d.successor_key_id, + deprecated_at_ledger: d.deprecated_at_ledger, + }, + // Fallback: key was deprecated via the old path without DeprecationInfo. + None => DeprecationStatus { + is_deprecated: true, + reason: String::from_str(&env, ""), + successor_key_id: None, + deprecated_at_ledger: 0, + }, + } + } + /// Redeems all keys held by `holder` for a deprecated creator key. /// /// Transfers `holder_balance * buyback_price_per_key` XLM from the escrow diff --git a/creator-keys/tests/key_deprecation.rs b/creator-keys/tests/key_deprecation.rs index 1d9bda64..becc25a8 100644 --- a/creator-keys/tests/key_deprecation.rs +++ b/creator-keys/tests/key_deprecation.rs @@ -73,7 +73,14 @@ fn test_buy_on_deprecated_key_returns_key_deprecated() { buy_one(&client, &creator, &buyer); // escrow = 1 key × 100 = 100 - client.deprecate_key(&creator, &creator, &100_i128, &100_i128); + client.deprecate_key( + &creator, + &creator, + &100_i128, + &100_i128, + &String::from_str(&env, "test"), + &None, + ); let result = client.try_buy_key(&creator, &buyer, &10_000_i128, &None); assert_eq!(result, Err(Ok(ContractError::KeyDeprecated))); @@ -97,7 +104,14 @@ fn test_holder_redeem_receives_correct_payout() { let buyback_price: i128 = 500; let required_escrow: i128 = 3 * buyback_price; // 1500 - client.deprecate_key(&creator, &creator, &buyback_price, &required_escrow); + client.deprecate_key( + &creator, + &creator, + &buyback_price, + &required_escrow, + &String::from_str(&env, "sunsetting"), + &None, + ); let payout = client.redeem(&creator, &holder); assert_eq!(payout, required_escrow); @@ -120,7 +134,14 @@ fn test_deprecate_key_insufficient_escrow_returns_error() { buy_one(&client, &creator, &buyer); buy_one(&client, &creator, &buyer); - let result = client.try_deprecate_key(&creator, &creator, &100_i128, &199_i128); + let result = client.try_deprecate_key( + &creator, + &creator, + &100_i128, + &199_i128, + &String::from_str(&env, "test"), + &None, + ); assert_eq!(result, Err(Ok(ContractError::InsufficientEscrow))); } @@ -134,7 +155,14 @@ fn test_deprecate_key_exact_escrow_succeeds() { buy_one(&client, &creator, &buyer); buy_one(&client, &creator, &buyer); - let result = client.try_deprecate_key(&creator, &creator, &100_i128, &200_i128); + let result = client.try_deprecate_key( + &creator, + &creator, + &100_i128, + &200_i128, + &String::from_str(&env, "test"), + &None, + ); assert_eq!(result, Ok(Ok(()))); } @@ -144,7 +172,14 @@ fn test_deprecate_key_zero_supply_requires_zero_escrow() { let creator = register_creator(&env, &client, "edgar"); // No keys minted; required escrow = 0 so even escrow_payment = 0 is fine. - let result = client.try_deprecate_key(&creator, &creator, &100_i128, &0_i128); + let result = client.try_deprecate_key( + &creator, + &creator, + &100_i128, + &0_i128, + &String::from_str(&env, "test"), + &None, + ); assert_eq!(result, Ok(Ok(()))); } @@ -158,7 +193,14 @@ fn test_non_creator_deprecate_key_returns_unauthorized() { let creator = register_creator(&env, &client, "frank"); let attacker = Address::generate(&env); - let result = client.try_deprecate_key(&creator, &attacker, &100_i128, &0_i128); + let result = client.try_deprecate_key( + &creator, + &attacker, + &100_i128, + &0_i128, + &String::from_str(&env, "test"), + &None, + ); assert_eq!(result, Err(Ok(ContractError::Unauthorized))); } @@ -176,7 +218,14 @@ fn test_deprecate_key_emits_key_deprecated_event() { let buyback_price: i128 = 200; let escrow: i128 = 200; // 1 × 200 - client.deprecate_key(&creator, &creator, &buyback_price, &escrow); + client.deprecate_key( + &creator, + &creator, + &buyback_price, + &escrow, + &String::from_str(&env, "test reason"), + &None, + ); let all_events = env.events().all(); let dep_event = all_events @@ -198,6 +247,8 @@ fn test_deprecate_key_emits_key_deprecated_event() { assert_eq!(data.buyback_price_per_key, buyback_price); assert_eq!(data.circulating_supply, 1); assert_eq!(data.total_escrow, escrow); + assert_eq!(data.reason, String::from_str(&env, "test reason")); + assert_eq!(data.successor_key_id, None); } // --------------------------------------------------------------------------- @@ -214,7 +265,14 @@ fn test_redeem_emits_keys_redeemed_event() { buy_one(&client, &creator, &holder); let buyback_price: i128 = 300; - client.deprecate_key(&creator, &creator, &buyback_price, &(2 * buyback_price)); + client.deprecate_key( + &creator, + &creator, + &buyback_price, + &(2 * buyback_price), + &String::from_str(&env, "retiring"), + &None, + ); client.redeem(&creator, &holder); @@ -253,7 +311,14 @@ fn test_redeem_zero_balance_returns_insufficient_balance() { let no_keys = Address::generate(&env); buy_one(&client, &creator, &other); - client.deprecate_key(&creator, &creator, &100_i128, &100_i128); + client.deprecate_key( + &creator, + &creator, + &100_i128, + &100_i128, + &String::from_str(&env, "test"), + &None, + ); let result = client.try_redeem(&creator, &no_keys); assert_eq!(result, Err(Ok(ContractError::InsufficientBalance))); @@ -264,9 +329,23 @@ fn test_double_deprecation_returns_key_deprecated() { let (env, client, _admin) = setup(); let creator = register_creator(&env, &client, "jake"); - client.deprecate_key(&creator, &creator, &100_i128, &0_i128); + client.deprecate_key( + &creator, + &creator, + &100_i128, + &0_i128, + &String::from_str(&env, "test"), + &None, + ); - let result = client.try_deprecate_key(&creator, &creator, &200_i128, &0_i128); + let result = client.try_deprecate_key( + &creator, + &creator, + &200_i128, + &0_i128, + &String::from_str(&env, "test"), + &None, + ); assert_eq!(result, Err(Ok(ContractError::KeyDeprecated))); } @@ -283,7 +362,14 @@ fn test_multiple_holders_redeem_independently() { buy_one(&client, &creator, &holder_b); let buyback_price: i128 = 150; - client.deprecate_key(&creator, &creator, &buyback_price, &(3 * buyback_price)); + client.deprecate_key( + &creator, + &creator, + &buyback_price, + &(3 * buyback_price), + &String::from_str(&env, "test"), + &None, + ); let payout_a = client.redeem(&creator, &holder_a); assert_eq!(payout_a, 2 * buyback_price); @@ -299,7 +385,14 @@ fn test_deprecate_key_negative_price_returns_not_positive_amount() { let (env, client, _admin) = setup(); let creator = register_creator(&env, &client, "leo"); - let result = client.try_deprecate_key(&creator, &creator, &-1_i128, &0_i128); + let result = client.try_deprecate_key( + &creator, + &creator, + &-1_i128, + &0_i128, + &String::from_str(&env, "test"), + &None, + ); assert_eq!(result, Err(Ok(ContractError::NotPositiveAmount))); } @@ -308,7 +401,14 @@ fn test_deprecate_key_unregistered_creator_returns_not_registered() { let (env, client, _admin) = setup(); let ghost = Address::generate(&env); - let result = client.try_deprecate_key(&ghost, &ghost, &100_i128, &0_i128); + let result = client.try_deprecate_key( + &ghost, + &ghost, + &100_i128, + &0_i128, + &String::from_str(&env, "test"), + &None, + ); assert_eq!(result, Err(Ok(ContractError::NotRegistered))); } @@ -320,7 +420,14 @@ fn test_buy_key_with_referrer_also_blocked_on_deprecated_key() { let referrer = Address::generate(&env); buy_one(&client, &creator, &buyer); - client.deprecate_key(&creator, &creator, &100_i128, &100_i128); + client.deprecate_key( + &creator, + &creator, + &100_i128, + &100_i128, + &String::from_str(&env, "test"), + &None, + ); let result = client.try_buy_key_with_referrer(&creator, &buyer, &10_000_i128, &None, &Some(referrer)); diff --git a/creator-keys/tests/key_deprecation_successor.rs b/creator-keys/tests/key_deprecation_successor.rs new file mode 100644 index 00000000..94ae753d --- /dev/null +++ b/creator-keys/tests/key_deprecation_successor.rs @@ -0,0 +1,280 @@ +//! Integration tests for issue #973 — key deprecation reason and successor designation. +//! +//! Acceptance criteria verified: +//! +//! 1. Deprecation blocked for non-creator callers (Unauthorized). +//! 2. Buy rejected with KeyDeprecated error after deprecation. +//! 3. Sell and transfer still permitted post-deprecation. +//! 4. `get_deprecation_status` returns all fields correctly. +//! 5. `KeyDeprecated` event includes reason and successor_key_id. + +use creator_keys::{ + events, ContractError, CreatorKeysContract, CreatorKeysContractClient, RegisterCreatorParams, +}; +use soroban_sdk::{ + testutils::{Address as _, Events, Ledger as _}, + Address, Env, IntoVal, String, +}; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +fn setup() -> (Env, CreatorKeysContractClient<'static>, Address) { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register(CreatorKeysContract, ()); + let client = CreatorKeysContractClient::new(&env, &contract_id); + + let admin = Address::generate(&env); + client.set_protocol_admin(&admin, &admin); + client.set_key_price(&admin, &100_i128); + client.set_curve_slope(&admin, &0_i128); + client.set_fee_config(&admin, &9_000_u32, &1_000_u32); + client.set_circuit_breaker_threshold(&admin, &10_000_u32); + + (env, client, admin) +} + +fn register_creator(env: &Env, client: &CreatorKeysContractClient, handle: &str) -> Address { + let creator = Address::generate(env); + client.register_creator( + &RegisterCreatorParams { + creator: creator.clone(), + handle: String::from_str(env, handle), + }, + &None, + &None, + &None, + &None, + &None, + &None, + ); + creator +} + +fn buy_one(client: &CreatorKeysContractClient, creator: &Address, buyer: &Address) { + client.buy_key(creator, buyer, &10_000_i128, &None); +} + +// --------------------------------------------------------------------------- +// 1. Deprecation blocked for non-creator callers +// --------------------------------------------------------------------------- + +#[test] +fn test_deprecation_blocked_for_non_creator() { + let (env, client, _admin) = setup(); + let creator = register_creator(&env, &client, "alice973"); + let attacker = Address::generate(&env); + + let result = client.try_deprecate_key( + &creator, + &attacker, + &100_i128, + &0_i128, + &String::from_str(&env, "hostile takeover"), + &None, + ); + assert_eq!(result, Err(Ok(ContractError::Unauthorized))); +} + +// --------------------------------------------------------------------------- +// 2. Buy rejected with KeyDeprecated after deprecation +// --------------------------------------------------------------------------- + +#[test] +fn test_buy_rejected_after_deprecation() { + let (env, client, _admin) = setup(); + let creator = register_creator(&env, &client, "bob973"); + let buyer = Address::generate(&env); + + buy_one(&client, &creator, &buyer); + client.deprecate_key( + &creator, + &creator, + &100_i128, + &100_i128, + &String::from_str(&env, "moving to v2"), + &None, + ); + + let result = client.try_buy_key(&creator, &buyer, &10_000_i128, &None); + assert_eq!(result, Err(Ok(ContractError::KeyDeprecated))); +} + +// --------------------------------------------------------------------------- +// 3. Sell still permitted post-deprecation +// --------------------------------------------------------------------------- + +#[test] +fn test_sell_still_permitted_after_deprecation() { + let (env, client, _admin) = setup(); + let creator = register_creator(&env, &client, "carol973"); + let holder = Address::generate(&env); + + buy_one(&client, &creator, &holder); + assert_eq!(client.get_key_balance(&creator, &holder), 1); + + client.deprecate_key( + &creator, + &creator, + &100_i128, + &100_i128, + &String::from_str(&env, "sunsetting"), + &None, + ); + + // Advance past the flash-loan guard window (a buy and sell in the same + // ledger are otherwise rejected independently of deprecation). + let mut ledger = env.ledger().get(); + ledger.sequence_number += 1; + env.ledger().set(ledger); + + // Sell should succeed even after deprecation. + let result = client.try_sell_key(&creator, &holder, &None); + assert!(result.is_ok(), "sell should succeed on deprecated key"); + assert_eq!(client.get_key_balance(&creator, &holder), 0); +} + +// --------------------------------------------------------------------------- +// 3b. Transfer still permitted post-deprecation +// --------------------------------------------------------------------------- + +#[test] +fn test_transfer_still_permitted_after_deprecation() { + let (env, client, _admin) = setup(); + let creator = register_creator(&env, &client, "carol973b"); + let holder = Address::generate(&env); + let recipient = Address::generate(&env); + + buy_one(&client, &creator, &holder); + assert_eq!(client.get_key_balance(&creator, &holder), 1); + + client.deprecate_key( + &creator, + &creator, + &100_i128, + &100_i128, + &String::from_str(&env, "sunsetting"), + &None, + ); + + // Transfer should succeed even after deprecation. + let result = client.try_transfer_keys(&creator, &holder, &recipient, &1_u32); + assert!(result.is_ok(), "transfer should succeed on deprecated key"); + assert_eq!(client.get_key_balance(&creator, &holder), 0); + assert_eq!(client.get_key_balance(&creator, &recipient), 1); +} + +// --------------------------------------------------------------------------- +// 4. get_deprecation_status returns all fields correctly +// --------------------------------------------------------------------------- + +#[test] +fn test_get_deprecation_status_undeprecated_returns_false() { + let (env, client, _admin) = setup(); + let creator = register_creator(&env, &client, "dave973"); + + let status = client.get_deprecation_status(&creator); + assert!(!status.is_deprecated); + assert_eq!(status.deprecated_at_ledger, 0); + assert_eq!(status.successor_key_id, None); +} + +#[test] +fn test_get_deprecation_status_returns_reason_and_successor() { + let (env, client, _admin) = setup(); + let creator = register_creator(&env, &client, "eve973"); + let successor = register_creator(&env, &client, "successor973"); + + let reason_str = String::from_str(&env, "upgrade to v2"); + + // Pin the ledger sequence so the recorded deprecation timestamp is non-zero. + let mut ledger = env.ledger().get(); + ledger.sequence_number = 42; + env.ledger().set(ledger); + + client.deprecate_key( + &creator, + &creator, + &100_i128, + &0_i128, + &reason_str, + &Some(successor.clone()), + ); + + let status = client.get_deprecation_status(&creator); + assert!(status.is_deprecated); + assert_eq!(status.reason, reason_str); + assert_eq!(status.successor_key_id, Some(successor)); + assert_eq!(status.deprecated_at_ledger, 42); +} + +#[test] +fn test_get_deprecation_status_no_successor_returns_none() { + let (env, client, _admin) = setup(); + let creator = register_creator(&env, &client, "frank973"); + + client.deprecate_key( + &creator, + &creator, + &100_i128, + &0_i128, + &String::from_str(&env, "just retiring"), + &None, + ); + + let status = client.get_deprecation_status(&creator); + assert!(status.is_deprecated); + assert_eq!(status.successor_key_id, None); + assert_eq!(status.reason, String::from_str(&env, "just retiring")); +} + +// --------------------------------------------------------------------------- +// 5. KeyDeprecated event includes reason and successor_key_id +// --------------------------------------------------------------------------- + +#[test] +fn test_key_deprecated_event_includes_reason_and_successor() { + let (env, client, _admin) = setup(); + let creator = register_creator(&env, &client, "grace973"); + let successor = register_creator(&env, &client, "successorkey"); + let buyer = Address::generate(&env); + + buy_one(&client, &creator, &buyer); + + let reason_str = String::from_str(&env, "v2 launch"); + let buyback_price: i128 = 100; + + client.deprecate_key( + &creator, + &creator, + &buyback_price, + &buyback_price, + &reason_str, + &Some(successor.clone()), + ); + + let all_events = env.events().all(); + let dep_event = all_events + .iter() + .rev() + .find(|(_, topics, _)| { + topics + .get(0) + .map(|v| { + let sym: soroban_sdk::Symbol = v.into_val(&env); + sym == events::KEY_DEPRECATED_EVENT_NAME + }) + .unwrap_or(false) + }) + .expect("key_deprecated event not found"); + + let data: events::KeyDeprecatedEvent = dep_event.2.into_val(&env); + assert_eq!(data.creator, creator); + assert_eq!(data.reason, reason_str); + assert_eq!(data.successor_key_id, Some(successor)); + assert_eq!(data.buyback_price_per_key, buyback_price); + assert_eq!(data.circulating_supply, 1); +} diff --git a/creator-keys/tests/redeem_key.rs b/creator-keys/tests/redeem_key.rs index d2965677..a577b030 100644 --- a/creator-keys/tests/redeem_key.rs +++ b/creator-keys/tests/redeem_key.rs @@ -60,9 +60,16 @@ fn buy(client: &CreatorKeysContractClient, creator: &Address, buyer: &Address, n } } -fn deprecate(client: &CreatorKeysContractClient, creator: &Address) { +fn deprecate(env: &Env, client: &CreatorKeysContractClient, creator: &Address) { let supply = client.get_creator_supply(creator) as i128; - client.deprecate_key(creator, creator, &BUYBACK_PRICE, &(supply * BUYBACK_PRICE)); + client.deprecate_key( + creator, + creator, + &BUYBACK_PRICE, + &(supply * BUYBACK_PRICE), + &soroban_sdk::String::from_str(env, "deprecated"), + &None, + ); } // --------------------------------------------------------------------------- @@ -81,7 +88,7 @@ fn redeem_pays_balance_times_buyback_price_and_burns_only_callers_keys() { assert_eq!(client.get_creator_supply(&creator), 5); assert_eq!(client.get_creator_holder_count(&creator), 2); - deprecate(&client, &creator); + deprecate(&env, &client, &creator); let payout = client.redeem(&creator, &holder); @@ -101,7 +108,7 @@ fn second_redeem_by_same_holder_fails_and_cannot_drain_escrow() { buy(&client, &creator, &holder, 1); buy(&client, &creator, &other, 1); - deprecate(&client, &creator); + deprecate(&env, &client, &creator); client.redeem(&creator, &holder); let again = client.try_redeem(&creator, &holder); @@ -168,7 +175,7 @@ fn redeem_emits_keys_redeemed_event_with_wallet_key_quantity_and_payout() { let holder = Address::generate(&env); buy(&client, &creator, &holder, 4); - deprecate(&client, &creator); + deprecate(&env, &client, &creator); client.redeem(&creator, &holder); let (_, topics, data) = env diff --git a/creator-keys/tests/reputation_scoring.rs b/creator-keys/tests/reputation_scoring.rs index ddab874b..62d1b105 100644 --- a/creator-keys/tests/reputation_scoring.rs +++ b/creator-keys/tests/reputation_scoring.rs @@ -249,7 +249,14 @@ fn test_key_deprecation_decrements_reputation() { // Escrow must cover every circulating key at the fixed buyback price. let buyback_price = 100_i128; let required_escrow = buyback_price * client.get_total_key_supply(&creator) as i128; - client.deprecate_key(&creator, &creator, &buyback_price, &required_escrow); + client.deprecate_key( + &creator, + &creator, + &buyback_price, + &required_escrow, + &String::from_str(&env, "sunsetting"), + &None, + ); let view = client.get_reputation(&creator); assert_eq!(view.score, before - REPUTATION_DEPRECATION_PENALTY); @@ -378,7 +385,14 @@ fn test_deprecation_penalty_clamps_to_zero_not_negative() { // A trade only earned 5 points, less than the 50-point deprecation penalty. let before = client.get_reputation(&creator).score; assert!(before < REPUTATION_DEPRECATION_PENALTY); - client.deprecate_key(&creator, &creator, &100, &KEY_PRICE); + client.deprecate_key( + &creator, + &creator, + &100, + &KEY_PRICE, + &String::from_str(&env, "sunsetting"), + &None, + ); assert_eq!(client.get_reputation(&creator).score, 0); }