Skip to content

Conversation

@nnennaokoye
Copy link

@nnennaokoye nnennaokoye commented Jan 27, 2026

🧠 SkillSphere Pull Request 🌐

Mark with an x all the checkboxes that apply (like [x])


📌 Type of Change

  • 📚 Documentation (updates to README, docs, or comments)
  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ Enhancement (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to change)
  • 🏗️ Refactor (code improvement/cleanup without logical changes)

📝 Changes Description

Added a gas-efficient way to associate off-chain profile metadata with experts by storing only a short data_uri (capped at 64 chars) during verification and allowing verified experts to update it with auth. This keeps on-chain data minimal (one small string per expert), defaults to an empty string in batch adds, and preserves existing URIs on bans.

Impact on storage/gas: minimal increase due to a short string field in ExpertRecord and occasional small event on profile updates; overall design avoids storing large text on-chain to remain cost effective.


📸 Evidence

(A photo, log output, or Soroban CLI output is required as evidence. If this is a smart contract change, please include the test results or invocation logs.)

image

🌌 Comments

(Any extra notes for the reviewer? Are there any specific edge cases they should test?)


Thank you for contributing to SkillSphere! 🌍

We are glad you have chosen to help us democratize access to knowledge on the Stellar network. Your contribution brings us one step closer to a trustless, peer-to-peer consulting economy. Let's build the future together! 🚀

Summary by CodeRabbit

Release Notes

  • New Features

    • Expert profiles now support associated URIs for storing profile data.
    • Verified experts can update their profile URIs independently.
    • Added profile update event for tracking profile changes.
  • Tests

    • Added comprehensive test coverage for profile URI persistence and updates.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 27, 2026

📝 Walkthrough

Walkthrough

This PR implements expert profile metadata storage by adding a data_uri field to track off-chain profile information. It modifies the verification flow to accept and persist URIs, introduces a new update_profile function for experts to self-manage their profile links, adds URI length validation, and includes profile update events and comprehensive test coverage.

Changes

Cohort / File(s) Summary
Data Model
contracts/identity-registry-contract/src/types.rs
Added data_uri: String field to ExpertRecord struct to store off-chain profile references.
Error Handling
contracts/identity-registry-contract/src/error.rs
Added two new error variants: NotVerified (8) and UriTooLong (9) for profile update validation.
Event System
contracts/identity-registry-contract/src/events.rs
Added new ProfileUpdatedEvent struct and emit_profile_updated function to publish profile URI changes; annotated existing emit_status_change with deprecation allowance.
Contract Logic
contracts/identity-registry-contract/src/contract.rs
Modified verify_expert to accept data_uri parameter with length validation; updated batch_add_experts and ban_expert to preserve existing URIs; added new update_profile function allowing verified experts to update their own profile URIs.
Storage Layer
contracts/identity-registry-contract/src/storage.rs
Extended set_expert_record to accept and persist data_uri parameter alongside status.
Public API
contracts/identity-registry-contract/src/lib.rs
Updated add_expert signature to include data_uri parameter; added new update_profile method delegating to contract logic.
Tests
contracts/identity-registry-contract/src/test.rs
Expanded test suite with data_uri persistence validation, profile update scenarios, rejection cases; updated test setup to use contract registration with constructor; modified all expert-related test invocations to include data_uri arguments.

Sequence Diagrams

sequenceDiagram
    participant Expert as Expert (Address)
    participant Contract as Contract
    participant Storage as Storage
    participant Events as Events

    Expert->>Contract: update_profile(new_uri)
    Contract->>Contract: expert.require_auth()
    Contract->>Storage: get_expert_record(expert)
    Storage-->>Contract: ExpertRecord {status, data_uri, ...}
    
    alt status != Verified
        Contract-->>Expert: Error: NotVerified
    else length > limit
        Contract-->>Expert: Error: UriTooLong
    else Valid
        Contract->>Storage: set_expert_record(expert, Verified, new_uri)
        Storage->>Storage: persist updated record
        Contract->>Events: emit_profile_updated(expert, new_uri)
        Events->>Events: publish event
        Contract-->>Expert: Ok()
    end
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly Related PRs

  • PR #13: Modifies the same contract functions (verify_expert and batch_ban_experts) to extend data_uri management and profile handling across status change operations.
  • PR #10: Extends batch_add_experts, verify_expert, and ban_expert with data_uri handling and signature adjustments that directly align with this PR's storage and record management changes.
  • PR #8: Updates batch_add_experts and verify_expert in the same contract file, creating potential merge conflicts and requiring coordinated review of profile metadata integration.

Suggested Reviewers

  • Bosun-Josh121

Poem

🐰 Hop along the profile trail,
URIs stored, the metadata sail,
Experts now can update their name,
Off-chain data in the blockchain game!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Implement "Expert Metadata" (Profile Data)' directly and specifically summarizes the main change in the PR, which adds the ability to store and manage expert profile metadata via a data_uri field.
Description check ✅ Passed The PR description follows the template structure with all required sections completed: issue reference (#18), checkboxes marked, change type selected (Enhancement and Breaking Change), detailed changes description with storage/gas impact, and evidence screenshot attached.
Linked Issues check ✅ Passed All coding requirements from issue #18 are implemented: data_uri field added to ExpertRecord; verify_expert signature accepts data_uri; batch_add_experts defaults empty URIs; update_profile function added with auth/verification checks; ProfileUpdated event created; URI length validation (UriTooLong) and verification status checks (NotVerified) added.
Out of Scope Changes check ✅ Passed All code changes are directly related to the profile metadata feature in issue #18; no unrelated modifications detected beyond the specified scope of adding data_uri support and update_profile functionality.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@contracts/identity-registry-contract/src/events.rs`:
- Line 15: Remove the #[allow(deprecated)] suppression and refactor the events
to use the new #[contractevent] macro: annotate ExpertStatusChangedEvent with
#[contractevent(topics = ["status_change"])] and ProfileUpdatedEvent with
#[contractevent(topics = ["profile_updated"])], keep the same fields (Address,
ExpertStatus, etc.), then replace calls that used env.events().publish(...) with
the new pattern by constructing the event struct and calling .publish(env)
inside the existing emit functions (e.g., emit_status_change and
emit_profile_updated) so they accept &Env and call ExpertStatusChangedEvent {
... }.publish(env) and ProfileUpdatedEvent { ... }.publish(env) respectively.
🧹 Nitpick comments (3)
contracts/identity-registry-contract/src/test.rs (1)

51-77: Consider adding event verification.

The test correctly verifies that the URI is updated in storage. However, the comment on line 76 states that event assertion is skipped to avoid flakiness. If the event emission is an important part of the contract behavior (which it appears to be based on emit_profile_updated being called in update_profile), consider adding event verification similar to test_expert_status_changed_event.

💡 Optional: Add event verification
     // Assert record updated
     env.as_contract(&contract_id, || {
         let rec = storage::get_expert_record(&env, &expert);
         assert_eq!(rec.data_uri, uri2);
     });

-    // Event assertion skipped to avoid flakiness in event buffers
+    // Verify profile_updated event was emitted
+    let events = env.events().all();
+    let event = events.last().unwrap();
+    assert_eq!(event.0, contract_id);
+    let topic: Symbol = event.1.get(0).unwrap().try_into_val(&env).unwrap();
+    assert_eq!(topic, Symbol::new(&env, "profile_updated"));
 }
contracts/identity-registry-contract/src/contract.rs (2)

32-34: Hoist empty URI creation outside the loop.
Minor gas/alloc savings by creating once and cloning per iteration.

♻️ Suggested tweak
-    for expert in experts {
+    let empty_uri = String::from_str(&env, "");
+    for expert in experts {
         let status = storage::get_expert_status(&env, &expert);
         if status == ExpertStatus::Verified {
             return Err(RegistryError::AlreadyVerified);
         }
-        // Default empty URI for batch adds
-        let empty_uri = String::from_str(&env, "");
-        storage::set_expert_record(&env, &expert, ExpertStatus::Verified, empty_uri);
+        // Default empty URI for batch adds
+        storage::set_expert_record(&env, &expert, ExpertStatus::Verified, empty_uri.clone());
         events::emit_status_change(&env, expert, status, ExpertStatus::Verified, admin.clone());
     }

63-79: Centralize URI length limit and clarify that String::len() returns byte count, not character count.

Both verify_expert and update_profile duplicate the 64-byte check. Define a constant at the module level and use it in both functions to keep them in sync. Note: the current comment says "~64 chars" but soroban_sdk::String::len() returns the byte length of the underlying u8 array, so URIs with multi-byte UTF-8 characters may appear shorter in character count than the 64-byte limit.

♻️ Suggested refactor
+const MAX_URI_LEN: u32 = 64;
+
 pub fn verify_expert(env: &Env, expert: &Address, data_uri: String) -> Result<(), RegistryError> {
@@
-    if data_uri.len() > 64 {
+    if data_uri.len() > MAX_URI_LEN {
         return Err(RegistryError::UriTooLong);
     }
@@
 pub fn update_profile(env: &Env, expert: &Address, new_uri: String) -> Result<(), RegistryError> {
@@
-    if new_uri.len() > 64 {
+    if new_uri.len() > MAX_URI_LEN {
         return Err(RegistryError::UriTooLong);
     }

}

// Helper function to emit the status change event
#[allow(deprecated)]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

soroban-sdk events publish deprecated 2025

💡 Result:

In Aug 2025, the Rust Soroban SDK (rs-soroban-sdk) deprecated the old Events::publish(...) API (i.e., env.events().publish(...)). The deprecation landed in PR #1524 (merged Aug 6, 2025) and is called out in the v23.0.0-rc.3 release notes (published Aug 28, 2025) as “Deprecate old events publish method”. [1][2]

Replacement (Protocol 23 / “Whisk” pattern): define events with the #[contractevent] macro and publish by calling publish(&env) on the event value/struct (so the event is included in the contract spec). [1][3]

Example from Stellar docs:

#[contractevent(topics = ["COUNTER", "increment"], data_format = "single-value")]
struct IncrementEvent { count: u32 }

IncrementEvent { count }.publish(&env);

[3]

Why: the #[contractevent] approach is now preferred because it embeds event definitions into the contract spec, enabling downstream tooling/bindings for events. [1]

Sources:
[1] stellar/rs-soroban-sdk#1524
[2] https://github.com/stellar/rs-soroban-sdk/releases/tag/v23.0.0-rc.3
[3] https://developers.stellar.org/docs/build/smart-contracts/example-contracts/events


🏁 Script executed:

fd -e toml -type f | head -20

Repository: LightForgeHub/SkillSphere-Contracts

Length of output: 249


🏁 Script executed:

find . -name "Cargo.toml" -type f

Repository: LightForgeHub/SkillSphere-Contracts

Length of output: 187


🏁 Script executed:

cat -n Cargo.toml 2>/dev/null || cat -n contracts/Cargo.toml 2>/dev/null || find . -name "Cargo.toml" -exec cat -n {} \;

Repository: LightForgeHub/SkillSphere-Contracts

Length of output: 743


🏁 Script executed:

cat -n contracts/identity-registry-contract/src/events.rs

Repository: LightForgeHub/SkillSphere-Contracts

Length of output: 1665


Refactor event emission to use the modern #[contractevent] macro pattern.

The env.events().publish() API was deprecated in soroban-sdk v23.0.0-rc.3 and is replaced by the #[contractevent] macro pattern. Your project uses soroban-sdk 23.1.1, where this deprecation is active. Remove the #[allow(deprecated)] suppression and refactor both ExpertStatusChangedEvent and ProfileUpdatedEvent to use #[contractevent]:

#[contractevent(topics = ["status_change"])]
pub struct ExpertStatusChangedEvent {
    pub expert: Address,
    pub old_status: ExpertStatus,
    pub new_status: ExpertStatus,
    pub admin: Address,
}

pub fn emit_status_change(env: &Env, expert: Address, old_status: ExpertStatus, new_status: ExpertStatus, admin: Address) {
    ExpertStatusChangedEvent { expert, old_status, new_status, admin }.publish(env);
}

This approach embeds event definitions in the contract spec and enables downstream tooling. Apply the same pattern to ProfileUpdatedEvent with topics = ["profile_updated"].

🤖 Prompt for AI Agents
In `@contracts/identity-registry-contract/src/events.rs` at line 15, Remove the
#[allow(deprecated)] suppression and refactor the events to use the new
#[contractevent] macro: annotate ExpertStatusChangedEvent with
#[contractevent(topics = ["status_change"])] and ProfileUpdatedEvent with
#[contractevent(topics = ["profile_updated"])], keep the same fields (Address,
ExpertStatus, etc.), then replace calls that used env.events().publish(...) with
the new pattern by constructing the event struct and calling .publish(env)
inside the existing emit functions (e.g., emit_status_change and
emit_profile_updated) so they accept &Env and call ExpertStatusChangedEvent {
... }.publish(env) and ProfileUpdatedEvent { ... }.publish(env) respectively.

@Bosun-Josh121 Bosun-Josh121 merged commit 2f946f6 into LightForgeHub:main Jan 27, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement "Expert Metadata" (Profile Data)

2 participants