diff --git a/src/lib.rs b/src/lib.rs index 975e3c3..495112d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -746,6 +746,14 @@ impl StellarWrapContract { .unwrap_or(0) } + /// Return the global number of wraps minted with `archetype`. + pub fn archetype_count(e: Env, archetype: Symbol) -> u64 { + e.storage() + .persistent() + .get(&DataKey::ArchetypeCount(archetype)) + .unwrap_or(0) + } + /// Return the current admin address, or `None` if the contract is not yet initialized. pub fn get_admin(e: Env) -> Option
{ e.storage().instance().get(&DataKey::Admin) diff --git a/src/test.rs b/src/test.rs index 8cac298..3d5d05f 100644 --- a/src/test.rs +++ b/src/test.rs @@ -2014,3 +2014,81 @@ fn test_has_wrap_is_scoped_to_user() { assert!(client.has_wrap(&user_a, &period)); assert!(!client.has_wrap(&user_b, &period)); } + +// ─── Issue #73: archetype stats tests ──────────────────────────────────────── + +#[test] +fn test_archetype_count_increments_on_mint() { + let env = Env::default(); + let contract_id = env.register_contract(None, StellarWrapContract); + let client = StellarWrapContractClient::new(&env, &contract_id); + + let signing_key = SigningKey::from_bytes(&[90u8; 32]); + let admin_pubkey = BytesN::from_array(&env, &signing_key.verifying_key().to_bytes()); + let admin = Address::generate(&env); + let user = Address::generate(&env); + let archetype = symbol_short!("builder"); + + client.initialize(&admin, &admin_pubkey); + env.mock_all_auths(); + + assert_eq!(client.archetype_count(&archetype), 0); + + let period = 2026u64; + let hash = BytesN::from_array(&env, &[91u8; 32]); + let sig = sign_payload( + &env, + &signing_key, + &contract_id, + &user, + period, + &archetype, + &hash, + ); + client.mint_wrap(&user, &period, &archetype, &hash, &sig); + + assert_eq!(client.archetype_count(&archetype), 1); +} + +#[test] +fn test_archetype_count_tracks_multiple_archetypes_independently() { + let env = Env::default(); + let contract_id = env.register_contract(None, StellarWrapContract); + let client = StellarWrapContractClient::new(&env, &contract_id); + + let signing_key = SigningKey::from_bytes(&[92u8; 32]); + let admin_pubkey = BytesN::from_array(&env, &signing_key.verifying_key().to_bytes()); + let admin = Address::generate(&env); + let user_a = Address::generate(&env); + let user_b = Address::generate(&env); + let arch_a = symbol_short!("builder"); + let arch_b = symbol_short!("defi"); + + client.initialize(&admin, &admin_pubkey); + env.mock_all_auths(); + + let hash = BytesN::from_array(&env, &[93u8; 32]); + let sig_a = sign_payload( + &env, + &signing_key, + &contract_id, + &user_a, + 202601, + &arch_a, + &hash, + ); + let sig_b = sign_payload( + &env, + &signing_key, + &contract_id, + &user_b, + 202601, + &arch_b, + &hash, + ); + client.mint_wrap(&user_a, &202601, &arch_a, &hash, &sig_a); + client.mint_wrap(&user_b, &202601, &arch_b, &hash, &sig_b); + + assert_eq!(client.archetype_count(&arch_a), 1); + assert_eq!(client.archetype_count(&arch_b), 1); +} diff --git a/test_snapshots/test/test_duplicate_period_fails.1.json b/test_snapshots/test/test_duplicate_period_fails.1.json index 147adaf..560d746 100644 --- a/test_snapshots/test/test_duplicate_period_fails.1.json +++ b/test_snapshots/test/test_duplicate_period_fails.1.json @@ -144,6 +144,51 @@ "min_temp_entry_ttl": 16, "max_entry_ttl": 6312000, "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "ArchetypeCount" + }, + { + "symbol": "arch" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "ArchetypeCount" + }, + { + "symbol": "arch" + } + ] + }, + "durability": "persistent", + "val": { + "u64": 1 + } + } + }, + "ext": "v0" + }, + 6307200 + ] + ], [ { "contract_data": { diff --git a/test_snapshots/test/test_mint_emits_event.1.json b/test_snapshots/test/test_mint_emits_event.1.json index bd14fb5..fae9d21 100644 --- a/test_snapshots/test/test_mint_emits_event.1.json +++ b/test_snapshots/test/test_mint_emits_event.1.json @@ -143,6 +143,51 @@ "min_temp_entry_ttl": 16, "max_entry_ttl": 6312000, "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "ArchetypeCount" + }, + { + "symbol": "arch" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "ArchetypeCount" + }, + { + "symbol": "arch" + } + ] + }, + "durability": "persistent", + "val": { + "u64": 1 + } + } + }, + "ext": "v0" + }, + 6307200 + ] + ], [ { "contract_data": { diff --git a/test_snapshots/test/test_minting_flow.1.json b/test_snapshots/test/test_minting_flow.1.json index c9103f4..9279425 100644 --- a/test_snapshots/test/test_minting_flow.1.json +++ b/test_snapshots/test/test_minting_flow.1.json @@ -144,6 +144,51 @@ "min_temp_entry_ttl": 16, "max_entry_ttl": 6312000, "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "ArchetypeCount" + }, + { + "symbol": "arch" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "ArchetypeCount" + }, + { + "symbol": "arch" + } + ] + }, + "durability": "persistent", + "val": { + "u64": 1 + } + } + }, + "ext": "v0" + }, + 6307200 + ] + ], [ { "contract_data": {