Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions contracts/reputation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub use profile::BadgeLevel;

mod profile;
mod storage;
pub use profile::{BadgeMetadataEntry, BadgeTier};

use profile::{Profile, RoleMetrics};

Expand Down Expand Up @@ -1024,6 +1025,75 @@ mod test {
assert_eq!(client.get_badge(&addr, &Role::Client), BadgeLevel::Bronze);
}

// ── Issue #406: badge metadata mapping ──

#[test]
fn test_set_and_get_badge_metadata() {
let env = Env::default();
env.mock_all_auths();
let admin = Address::generate(&env);
let addr = Address::generate(&env);
let cid = env.register_contract(None, ReputationContract);
let client = ReputationContractClient::new(&env, &cid);
client.initialize(&admin);

let uri = Bytes::from_slice(&env, b"ipfs://QmBronzeBadge");
client.set_badge_metadata(&admin, &addr, &BadgeTier::Bronze, &uri);

let result = client.get_badge_metadata(&addr, &BadgeTier::Bronze);
assert_eq!(result, Some(uri));
}

#[test]
fn test_badge_metadata_returns_none_when_unset() {
let env = Env::default();
env.mock_all_auths();
let addr = Address::generate(&env);
let cid = env.register_contract(None, ReputationContract);
let client = ReputationContractClient::new(&env, &cid);

let result = client.get_badge_metadata(&addr, &BadgeTier::Gold);
assert_eq!(result, None);
}

#[test]
fn test_badge_metadata_update_overwrites_existing() {
let env = Env::default();
env.mock_all_auths();
let admin = Address::generate(&env);
let addr = Address::generate(&env);
let cid = env.register_contract(None, ReputationContract);
let client = ReputationContractClient::new(&env, &cid);
client.initialize(&admin);

let uri_v1 = Bytes::from_slice(&env, b"ipfs://QmSilverV1");
let uri_v2 = Bytes::from_slice(&env, b"ipfs://QmSilverV2");
client.set_badge_metadata(&admin, &addr, &BadgeTier::Silver, &uri_v1);
client.set_badge_metadata(&admin, &addr, &BadgeTier::Silver, &uri_v2);

assert_eq!(client.get_badge_metadata(&addr, &BadgeTier::Silver), Some(uri_v2));
}

#[test]
fn test_multiple_tiers_stored_independently() {
let env = Env::default();
env.mock_all_auths();
let admin = Address::generate(&env);
let addr = Address::generate(&env);
let cid = env.register_contract(None, ReputationContract);
let client = ReputationContractClient::new(&env, &cid);
client.initialize(&admin);

let bronze_uri = Bytes::from_slice(&env, b"ipfs://Bronze");
let gold_uri = Bytes::from_slice(&env, b"ipfs://Gold");
client.set_badge_metadata(&admin, &addr, &BadgeTier::Bronze, &bronze_uri);
client.set_badge_metadata(&admin, &addr, &BadgeTier::Gold, &gold_uri);

assert_eq!(client.get_badge_metadata(&addr, &BadgeTier::Bronze), Some(bronze_uri));
assert_eq!(client.get_badge_metadata(&addr, &BadgeTier::Gold), Some(gold_uri));
assert_eq!(client.get_badge_metadata(&addr, &BadgeTier::Silver), None);
}

#[test]
#[should_panic(expected = "Error(Contract, #2)")]
fn test_upgrade_requires_admin() {
Expand Down
21 changes: 21 additions & 0 deletions contracts/reputation/src/profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,24 @@ impl BadgeLevel {
}
}

/// Badge tiers keyed in the metadata map.
#[contracttype]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BadgeTier {
Bronze,
Silver,
Gold,
Platinum,
}

#[contracttype]
#[derive(Clone, Debug, PartialEq)]
pub struct BadgeMetadataEntry {
pub tier: BadgeTier,
/// IPFS CID (or any URI) pointing to the badge image / JSON metadata.
pub uri: Bytes,
}

#[contracttype]
#[derive(Clone, Debug, PartialEq)]
pub struct Profile {
Expand All @@ -76,6 +94,8 @@ pub struct Profile {
pub freelancer: RoleMetrics,
pub is_blacklisted: bool,
pub metadata_hash: Option<Bytes>,
/// Per-tier badge metadata URIs set by the admin.
pub badge_metadata: soroban_sdk::Vec<BadgeMetadataEntry>,
}

impl Profile {
Expand All @@ -86,6 +106,7 @@ impl Profile {
freelancer: RoleMetrics::new(),
is_blacklisted: false,
metadata_hash: None,
badge_metadata: soroban_sdk::Vec::new(_env),
}
}
}
Loading