diff --git a/contracts/identity-registry-contract/src/contract.rs b/contracts/identity-registry-contract/src/contract.rs index 1814245..37f634b 100644 --- a/contracts/identity-registry-contract/src/contract.rs +++ b/contracts/identity-registry-contract/src/contract.rs @@ -1,7 +1,7 @@ use crate::events; use crate::storage; use crate::{error::RegistryError, types::ExpertStatus}; -use soroban_sdk::{Address, Env, String, Vec}; +use soroban_sdk::{Address, BytesN, Env, String, Vec}; /// Initialize the registry with an admin address pub fn initialize_registry(env: &Env, admin: &Address) -> Result<(), RegistryError> { @@ -77,6 +77,14 @@ pub fn remove_moderator(env: &Env, moderator: &Address) -> Result<(), RegistryEr Ok(()) } +/// Upgrade the current contract WASM to a new published version (Admin only) +pub fn upgrade_contract(env: &Env, new_wasm_hash: BytesN<32>) -> Result<(), RegistryError> { + let admin = storage::get_admin(env).ok_or(RegistryError::NotInitialized)?; + admin.require_auth(); + env.deployer().update_current_contract_wasm(new_wasm_hash); + Ok(()) +} + pub fn verify_expert( env: &Env, caller: &Address, diff --git a/contracts/identity-registry-contract/src/lib.rs b/contracts/identity-registry-contract/src/lib.rs index dec5ed4..8b1efb8 100644 --- a/contracts/identity-registry-contract/src/lib.rs +++ b/contracts/identity-registry-contract/src/lib.rs @@ -10,7 +10,7 @@ mod types; use crate::error::RegistryError; use crate::types::ExpertStatus; -use soroban_sdk::{contract, contractimpl, Address, Env, String, Vec}; +use soroban_sdk::{contract, contractimpl, Address, BytesN, Env, String, Vec}; #[contract] pub struct IdentityRegistryContract; @@ -32,6 +32,10 @@ impl IdentityRegistryContract { contract::remove_moderator(&env, &moderator) } + pub fn upgrade_contract(env: Env, new_wasm_hash: BytesN<32>) -> Result<(), RegistryError> { + contract::upgrade_contract(&env, new_wasm_hash) + } + /// Batch Add an expert to the whitelist (Admin only) pub fn batch_add_experts(env: Env, experts: Vec
) -> Result<(), RegistryError> { contract::batch_add_experts(env, experts) diff --git a/contracts/identity-registry-contract/src/test.rs b/contracts/identity-registry-contract/src/test.rs index 5fc4277..f45631f 100644 --- a/contracts/identity-registry-contract/src/test.rs +++ b/contracts/identity-registry-contract/src/test.rs @@ -7,7 +7,7 @@ use crate::{storage, types::ExpertStatus}; use crate::{IdentityRegistryContract, IdentityRegistryContractClient}; use soroban_sdk::testutils::{AuthorizedFunction, AuthorizedInvocation, Events}; use soroban_sdk::{ - testutils::Address as _, vec, Address, Env, IntoVal, String, Symbol, TryIntoVal, + testutils::Address as _, vec, Address, BytesN, Env, IntoVal, String, Symbol, TryIntoVal, }; #[test] @@ -50,6 +50,37 @@ fn test_data_uri_persisted_on_verify() { }); } +#[test] +fn test_upgrade_contract_preserves_expert_directory_state() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register(IdentityRegistryContract, ()); + let client = IdentityRegistryContractClient::new(&env, &contract_id); + + let admin = Address::generate(&env); + let expert = Address::generate(&env); + let uri = String::from_str(&env, "ipfs://preserved"); + + client.init(&admin); + client.add_expert(&admin, &expert, &uri, &0u32); + + assert_eq!(client.get_status(&expert), ExpertStatus::Verified); + assert_eq!(client.get_expert_by_index(&0u64), expert.clone()); + + let new_wasm_hash = BytesN::from_array(&env, &[1u8; 32]); + let res = client.try_upgrade_contract(&new_wasm_hash); + assert!(res.is_ok()); + + assert_eq!(client.get_status(&expert), ExpertStatus::Verified); + assert_eq!(client.get_expert_by_index(&0u64), expert.clone()); + + env.as_contract(&contract_id, || { + let rec = storage::get_expert_record(&env, &expert); + assert_eq!(rec.data_uri, uri); + }); +} + #[test] fn test_update_profile_updates_uri_and_emits_event() { let env = Env::default();