Skip to content

Comments

feat: Implement ERC-721 Soulbound Reputation NFTs with Skills, Rating…#46

Merged
Cybermaxi7 merged 1 commit intoStarkHive:mainfrom
Devsol-01:main
Jun 8, 2025
Merged

feat: Implement ERC-721 Soulbound Reputation NFTs with Skills, Rating…#46
Cybermaxi7 merged 1 commit intoStarkHive:mainfrom
Devsol-01:main

Conversation

@Devsol-01
Copy link
Contributor

@Devsol-01 Devsol-01 commented Jun 7, 2025

✅ Description:

This PR introduces an ERC-721-based on-chain reputation system using soulbound (non-transferable) NFTs to represent a user's skills and accomplishments. These NFTs act as permanent credentials tied to users' profiles and integrate with the job completion workflow.

Key Features:

  • ERC-721 Compliant NFTs
    Implements a modified ERC-721 standard to support soulbound (non-transferable) tokens.

  • 🧠 Skill-Based NFT Categories
    Each NFT represents a specific skill domain (e.g., design, dev, research).

  • Rating System Integration
    Dynamic reputation scores are updated based on job completions and peer reviews.

  • 🏅 Achievement Badges
    Special NFTs are awarded for milestone achievements (e.g., top performer, early contributor).

  • 📦 IPFS Metadata Support
    NFT metadata (image, skill, level, achievements) is hosted and retrieved via IPFS.

  • 🔒 Soulbound Logic
    Transfers are restricted to prevent ownership change, enforcing identity-based credentials.

  • 🧩 Job System Integration
    NFTs are minted/updated automatically when users complete verified jobs.

  • 📚 Batch Minting Support
    Allows for efficient minting in bulk during onboarding or recognition events.


📌 Closes

Closes #31

Summary by CodeRabbit

  • New Features

    • Introduced a Reputation NFT system with non-transferable (soulbound) tokens that track skill categories, ratings, achievements, and reputation scores.
    • Added public functions to mint reputation NFTs, update ratings, add achievements, and set metadata.
    • Integrated reputation NFT rewards into the job approval process, automatically minting reputation tokens and assigning achievements when jobs are approved.
    • Provided user-accessible functions to view reputation details and metadata.
  • Bug Fixes

    • Prevented transfers of reputation NFTs to ensure tokens remain soulbound.
  • Tests

    • Added comprehensive tests for minting, updating, achievement management, reputation scoring, and transfer prevention for reputation NFTs.

@coderabbitai
Copy link

coderabbitai bot commented Jun 7, 2025

Walkthrough

This change introduces a comprehensive Reputation NFT system. It adds a soulbound ERC-721-like contract with skill categories, ratings, achievements, and metadata. The system integrates with job completion, updates the Jobs contract to mint NFTs upon job approval, and provides new interfaces and tests for reputation features, batch minting, and metadata serialization.

Changes

File(s) Change Summary
src/base/reputation_metadata.cairo Added ReputationMetadata and MetadataAttribute structs, helper trait and implementation for metadata creation and JSON serialization.
src/base/types.cairo Added OracleStatus enum.
src/contracts/Jobs.cairo Added storage and setter for Reputation NFT address; updated approve_submission to mint reputation NFTs and add achievements on job approval.
src/contracts/ReputationNFT.cairo New contract implementing soulbound ERC-721-like Reputation NFTs with skill categories, ratings, achievements, admin controls, and batch minting.
src/interfaces/IJobs.cairo Added set_oracle_manager and set_reputation_nft methods; renamed parameter in apply_for_job.
src/interfaces/IReputationNFT.cairo New interface for Reputation NFT contract, covering metadata, minting, rating, achievements, and admin functions.
src/lib.cairo Added new modules for ReputationNFT contract, metadata, and interface.
tests/test_reputation_nft.cairo New test suite covering minting, rating, achievements, reputation score, and transfer prevention for ReputationNFT.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant JobsContract
    participant ReputationNFT

    User->>JobsContract: apply_for_job()
    JobsContract->>User: process application
    User->>JobsContract: submit work
    JobsContract->>JobsContract: approve_submission()
    JobsContract->>ReputationNFT: mint(to, skill_category)
    ReputationNFT->>JobsContract: return token_id
    JobsContract->>ReputationNFT: update_rating(token_id, rating)
    JobsContract->>ReputationNFT: add_achievement(token_id, achievement)
Loading

Assessment against linked issues

Objective (Issue #) Addressed Explanation
ERC-721 compliant reputation NFTs, Skill-based NFT categories, Rating system integration, Achievement badges (#31)
Reputation score calculation, NFT metadata with IPFS integration (#31)
Soulbound token implementation (non-transferable), Reputation transfer restrictions (#31)
Integration with job completion system (#31)
Batch minting capabilities (#31)

Assessment against linked issues: Out-of-scope changes

Code Change (file_path) Explanation
Added OracleStatus enum (src/base/types.cairo) This enum is unrelated to the Reputation NFT system or job completion integration described in the linked issue.

Suggested reviewers

  • Xaxxoo

Poem

A badge of skill, a rabbit's pride,
Soulbound tokens, nowhere to hide.
Achievements earned, ratings climb,
Minted on-chain, a mark through time.
Hop, hop, hooray! The code is neat—
Reputation NFTs, a blockchain treat!
🐇✨


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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 7

🔭 Outside diff range comments (2)
src/contracts/Jobs.cairo (2)

383-383: ⚠️ Potential issue

Update parameter name to match interface.

The parameter name should be proposal to match the updated interface definition.

-    fn apply_for_job(ref self: ContractState, job_id: u256, qualification: ByteArray) -> u256 {
+    fn apply_for_job(ref self: ContractState, job_id: u256, proposal: ByteArray) -> u256 {

Also update line 403:

-            qualification,
+            qualification: proposal,

143-153: 💡 Verification agent

🧩 Analysis chain

Verify OracleStatus import.

The code uses OracleStatus enum but doesn't import it from the types module.


🏁 Script executed:

#!/bin/bash
# Description: Check if OracleStatus is imported or needs to be added to imports

# Check current imports in Jobs.cairo
rg -A 10 "use starkhive_contract::base::types" src/contracts/Jobs.cairo

# Check if OracleStatus is used elsewhere
ast-grep --pattern 'OracleStatus::$_'

Length of output: 717


Add missing OracleStatus import

The OracleStatus enum is used in the assert on lines 147–148 but isn’t imported. Update the use starkhive_contract::base::types import in src/contracts/Jobs.cairo:

 use starkhive_contract::base::types::{
-    Applicant, ApplicationStatus, ExperienceLevel, Job, JobCategory, JobDuration, Status,
+    Applicant, ApplicationStatus, ExperienceLevel, Job, JobCategory, JobDuration, Status, OracleStatus,
 };
🧹 Nitpick comments (7)
tests/test_reputation_nft.cairo (1)

29-111: Consider adding more comprehensive test coverage.

While the existing tests cover core functionality well, consider adding tests for:

  • Batch minting functionality (batch_mint)
  • Metadata URI setting and retrieval
  • Edge cases like rating bounds (0-100)
  • Unauthorized access attempts (negative test cases)
  • Multiple achievements and duplicate achievement prevention
src/interfaces/IReputationNFT.cairo (3)

4-8: Consider adding balance_of to ERC721 core functions.

While transfer functions are intentionally omitted for soulbound tokens, balance_of would still be useful for querying how many reputation tokens an address owns.

 // ERC721 core functions
 fn name(self: @TContractState,) -> felt252;
 fn symbol(self: @TContractState,) -> felt252;
 fn token_uri(self: @TContractState,token_id: u256) -> Array<felt252>;
 fn owner_of(self: @TContractState,token_id: u256) -> ContractAddress;
+fn balance_of(self: @TContractState, owner: ContractAddress) -> u256;

16-22: Document access control requirements for admin functions.

These admin functions should be restricted to authorized callers (jobs contract and admin). Consider adding comments to document the expected access control.

 // Admin functions
+// Note: These functions should be restricted to authorized callers (jobs contract/admin)
 fn mint(ref self: TContractState,to: ContractAddress, skill_category: felt252) -> u256;

22-23: Remove extra blank line.

 fn set_metadata_uri(ref self: TContractState,token_id: u256, uri: Array<felt252>);
-    
} 
src/base/reputation_metadata.cairo (1)

58-109: Consider implementing proper JSON escaping for security.

The current implementation doesn't escape special characters in strings, which could lead to invalid JSON or potential injection vulnerabilities if field values contain quotes or control characters.

Consider using a proper JSON serialization library or implementing string escaping to handle:

  • Double quotes in field values
  • Newlines and control characters
  • Unicode characters
  • Numeric formatting edge cases

This is especially important for user-provided content like descriptions or achievement names.

src/contracts/ReputationNFT.cairo (2)

11-11: Remove unused import.

The openzeppelin::token::erc721::ERC721 import is not used anywhere in the contract.

-    use openzeppelin::token::erc721::ERC721;

105-111: Fix inconsistent indentation.

The function bodies have incorrect indentation that should be fixed for consistency.

-                fn name(self: @ContractState) -> felt252 {
+        fn name(self: @ContractState) -> felt252 {
             self._name.read()
         }

-                fn symbol(self: @ContractState) -> felt252 {
+        fn symbol(self: @ContractState) -> felt252 {
             self._symbol.read()
         }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5f1177c and a4b59e1.

📒 Files selected for processing (8)
  • src/base/reputation_metadata.cairo (1 hunks)
  • src/base/types.cairo (1 hunks)
  • src/contracts/Jobs.cairo (4 hunks)
  • src/contracts/ReputationNFT.cairo (1 hunks)
  • src/interfaces/IJobs.cairo (2 hunks)
  • src/interfaces/IReputationNFT.cairo (1 hunks)
  • src/lib.cairo (1 hunks)
  • tests/test_reputation_nft.cairo (1 hunks)
🔇 Additional comments (8)
src/base/types.cairo (1)

143-148: LGTM!

The OracleStatus enum is well-structured with appropriate derives for its use case.

src/lib.cairo (1)

6-6: Well-organized module structure for reputation system.

The new modules are properly organized following the existing pattern: contract, base types, and interface.

Also applies to: 11-11, 17-17

src/interfaces/IJobs.cairo (1)

8-9: New setter functions look good.

The function signatures for set_oracle_manager and set_reputation_nft are appropriately defined.

src/contracts/Jobs.cairo (1)

11-11: Import statement is correctly placed.

The IReputationNFT import follows the existing import pattern.

tests/test_reputation_nft.cairo (3)

14-27: Well-structured test setup.

The setup function properly initializes the test environment with clear separation of roles (admin, jobs contract) and correct contract deployment.


113-131: Excellent test for soulbound token enforcement.

This test properly validates that the soulbound tokens cannot be transferred, which is a critical security feature of the reputation system.


107-108:

Details

✅ Verification successful

Verify the reputation score calculation formula.

The test expects a score of 9100 for rating 90 with 2 achievements, suggesting the formula: rating * 100 + achievements_count * 50. Please ensure this matches the actual contract implementation.


🏁 Script executed:

#!/bin/bash
# Search for the reputation score calculation implementation
ast-grep --pattern 'fn get_reputation_score($_) {
  $$$
}'

Length of output: 60


🏁 Script executed:

#!/bin/bash
# Search for get_reputation_score function definition and usages
rg -n --context 3 'fn get_reputation_score' .
rg -n --context 3 'get_reputation_score' .

Length of output: 3355


🏁 Script executed:

#!/bin/bash
# Display the full implementation of get_reputation_score to verify the formula
sed -n '140,160p' src/contracts/ReputationNFT.cairo

Length of output: 936


Reputation score formula verified
The get_reputation_score implementation uses rating * 100 + (achievements.len() * 50), which matches the test’s expectation of 9100 for a rating of 90 with 2 achievements. No changes needed.

src/base/reputation_metadata.cairo (1)

1-17: Well-designed metadata structures.

The metadata structures comprehensively capture all reputation-related information with appropriate field types and derive macros.

) -> u256;

fn apply_for_job(ref self: TContractState, job_id: u256, qualification: ByteArray) -> u256;
fn apply_for_job(ref self: TContractState, job_id: u256, proposal: ByteArray) -> u256;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Parameter name inconsistency with implementation.

The parameter name was changed from qualification to proposal, but the implementation in Jobs.cairo (line 383) still uses qualification. This creates an interface-implementation mismatch.

Either update the implementation to use proposal or revert this interface change to maintain consistency.

🤖 Prompt for AI Agents
In src/interfaces/IJobs.cairo at line 38, the parameter name in the
apply_for_job function signature is 'proposal', but the implementation in
Jobs.cairo at line 383 still uses 'qualification'. To fix this, update the
implementation in Jobs.cairo to rename the parameter from 'qualification' to
'proposal' so that the interface and implementation match exactly.

Comment on lines +122 to +125
fn set_reputation_nft(ref self: ContractState, reputation_nft: ContractAddress) {
// TODO: add admin check
self.reputation_nft.write(reputation_nft);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add access control for reputation NFT setter.

The TODO comment correctly identifies that admin access control is needed. This function should be restricted to authorized users only.

Would you like me to generate the access control implementation or create an issue to track this security requirement?

🤖 Prompt for AI Agents
In src/contracts/Jobs.cairo around lines 122 to 125, the set_reputation_nft
function lacks access control, allowing any caller to set the reputation NFT.
Implement an admin check at the start of this function to restrict access only
to authorized users, typically by verifying the caller's address against a
stored admin address or role. This will enforce proper access control and secure
the function.

Comment on lines +461 to +483
let reputation_nft = IReputationNFTDispatcher { contract_address: self.reputation_nft.read() };
let skill_category = match job.category {
JobCategory::Technology => 'TECHNOLOGY',
JobCategory::Design => 'DESIGN',
JobCategory::Marketing => 'MARKETING',
JobCategory::Writing => 'WRITING',
JobCategory::Business => 'BUSINESS',
JobCategory::Finance => 'FINANCE',
JobCategory::Other => 'OTHER',
};

// Mint NFT with initial rating of 80 for successful completion
let token_id = reputation_nft.mint(job.applicant, skill_category);
reputation_nft.update_rating(token_id, 80);

// Add achievement for job completion
let achievement = match job.experience_level {
ExperienceLevel::Beginner => 'COMPLETED_BEGINNER_JOB',
ExperienceLevel::Intermediate => 'COMPLETED_INTERMEDIATE_JOB',
ExperienceLevel::Expert => 'COMPLETED_EXPERT_JOB',
};
reputation_nft.add_achievement(token_id, achievement);

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix experience level mismatch and add safety checks.

Two issues in the reputation NFT integration:

  1. Experience level mismatch: The achievement matching uses Beginner, Intermediate, Expert but the ExperienceLevel enum defines Entry, Junior, Mid, Senior, Expert.

  2. Missing null check: The code doesn't verify if reputation_nft address is set before using it.

Apply this fix:

+    // Check if reputation NFT contract is configured
+    let reputation_nft_addr = self.reputation_nft.read();
+    if reputation_nft_addr != contract_address_const::<0>() {
         // Mint reputation NFT for successful job completion
-        let reputation_nft = IReputationNFTDispatcher { contract_address: self.reputation_nft.read() };
+        let reputation_nft = IReputationNFTDispatcher { contract_address: reputation_nft_addr };
         let skill_category = match job.category {
             JobCategory::Technology => 'TECHNOLOGY',
             JobCategory::Design => 'DESIGN',
             JobCategory::Marketing => 'MARKETING',
             JobCategory::Writing => 'WRITING',
             JobCategory::Business => 'BUSINESS',
             JobCategory::Finance => 'FINANCE',
             JobCategory::Other => 'OTHER',
         };
         
         // Mint NFT with initial rating of 80 for successful completion
         let token_id = reputation_nft.mint(job.applicant, skill_category);
         reputation_nft.update_rating(token_id, 80);
         
         // Add achievement for job completion
         let achievement = match job.experience_level {
-            ExperienceLevel::Beginner => 'COMPLETED_BEGINNER_JOB',
-            ExperienceLevel::Intermediate => 'COMPLETED_INTERMEDIATE_JOB',
-            ExperienceLevel::Expert => 'COMPLETED_EXPERT_JOB',
+            ExperienceLevel::Entry => 'COMPLETED_ENTRY_JOB',
+            ExperienceLevel::Junior => 'COMPLETED_JUNIOR_JOB',
+            ExperienceLevel::Mid => 'COMPLETED_MID_JOB',
+            ExperienceLevel::Senior => 'COMPLETED_SENIOR_JOB',
+            ExperienceLevel::Expert => 'COMPLETED_EXPERT_JOB',
         };
         reputation_nft.add_achievement(token_id, achievement);
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let reputation_nft = IReputationNFTDispatcher { contract_address: self.reputation_nft.read() };
let skill_category = match job.category {
JobCategory::Technology => 'TECHNOLOGY',
JobCategory::Design => 'DESIGN',
JobCategory::Marketing => 'MARKETING',
JobCategory::Writing => 'WRITING',
JobCategory::Business => 'BUSINESS',
JobCategory::Finance => 'FINANCE',
JobCategory::Other => 'OTHER',
};
// Mint NFT with initial rating of 80 for successful completion
let token_id = reputation_nft.mint(job.applicant, skill_category);
reputation_nft.update_rating(token_id, 80);
// Add achievement for job completion
let achievement = match job.experience_level {
ExperienceLevel::Beginner => 'COMPLETED_BEGINNER_JOB',
ExperienceLevel::Intermediate => 'COMPLETED_INTERMEDIATE_JOB',
ExperienceLevel::Expert => 'COMPLETED_EXPERT_JOB',
};
reputation_nft.add_achievement(token_id, achievement);
// Check if reputation NFT contract is configured
let reputation_nft_addr = self.reputation_nft.read();
if reputation_nft_addr != contract_address_const::<0>() {
// Mint reputation NFT for successful job completion
let reputation_nft = IReputationNFTDispatcher { contract_address: reputation_nft_addr };
let skill_category = match job.category {
JobCategory::Technology => 'TECHNOLOGY',
JobCategory::Design => 'DESIGN',
JobCategory::Marketing => 'MARKETING',
JobCategory::Writing => 'WRITING',
JobCategory::Business => 'BUSINESS',
JobCategory::Finance => 'FINANCE',
JobCategory::Other => 'OTHER',
};
// Mint NFT with initial rating of 80 for successful completion
let token_id = reputation_nft.mint(job.applicant, skill_category);
reputation_nft.update_rating(token_id, 80);
// Add achievement for job completion
let achievement = match job.experience_level {
ExperienceLevel::Entry => 'COMPLETED_ENTRY_JOB',
ExperienceLevel::Junior => 'COMPLETED_JUNIOR_JOB',
ExperienceLevel::Mid => 'COMPLETED_MID_JOB',
ExperienceLevel::Senior => 'COMPLETED_SENIOR_JOB',
ExperienceLevel::Expert => 'COMPLETED_EXPERT_JOB',
};
reputation_nft.add_achievement(token_id, achievement);
}
🤖 Prompt for AI Agents
In src/contracts/Jobs.cairo around lines 461 to 483, fix the experience level
mismatch by updating the achievement match to use the correct ExperienceLevel
enum variants: Entry, Junior, Mid, Senior, Expert instead of Beginner,
Intermediate, Expert. Also, add a safety check to verify that the reputation_nft
contract address is set (not null) before creating the IReputationNFTDispatcher
instance and calling its methods, to prevent runtime errors.

Comment on lines +99 to +101
json.append('"trait_type": "'); json.append(self.attributes[i].trait_type); json.append('",');
json.append('"value": "'); json.append(self.attributes[i].value); json.append('"');
json.append('}');
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix array access syntax for attributes.

Use proper Cairo array access method.

-json.append('"trait_type": "'); json.append(self.attributes[i].trait_type); json.append('",');
-json.append('"value": "'); json.append(self.attributes[i].value); json.append('"');
+json.append('"trait_type": "'); json.append(self.attributes.at(i).trait_type); json.append('",');
+json.append('"value": "'); json.append(self.attributes.at(i).value); json.append('"');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
json.append('"trait_type": "'); json.append(self.attributes[i].trait_type); json.append('",');
json.append('"value": "'); json.append(self.attributes[i].value); json.append('"');
json.append('}');
json.append('"trait_type": "'); json.append(self.attributes.at(i).trait_type); json.append('",');
json.append('"value": "'); json.append(self.attributes.at(i).value); json.append('"');
json.append('}');
🤖 Prompt for AI Agents
In src/base/reputation_metadata.cairo around lines 99 to 101, the code uses
incorrect syntax to access elements of the attributes array. Replace the current
attribute access syntax with the proper Cairo array access method by using the
array name followed by square brackets and the index, ensuring correct retrieval
of trait_type and value from self.attributes[i].

Comment on lines +70 to +71
json.append('"rating": '); json.append((*self.rating).into()); json.append(',');
json.append('"reputation_score": '); json.append((*self.reputation_score).into()); json.append(',');
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix number serialization in JSON output.

The current conversion using .into() may not produce valid JSON number format. Consider proper number-to-string conversion.

-json.append('"rating": '); json.append((*self.rating).into()); json.append(',');
-json.append('"reputation_score": '); json.append((*self.reputation_score).into()); json.append(',');
+json.append('"rating": '); json.append((*self.rating).to_string()); json.append(',');
+json.append('"reputation_score": '); json.append((*self.reputation_score).to_string()); json.append(',');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
json.append('"rating": '); json.append((*self.rating).into()); json.append(',');
json.append('"reputation_score": '); json.append((*self.reputation_score).into()); json.append(',');
json.append('"rating": '); json.append((*self.rating).to_string()); json.append(',');
json.append('"reputation_score": '); json.append((*self.reputation_score).to_string()); json.append(',');
🤖 Prompt for AI Agents
In src/base/reputation_metadata.cairo around lines 70 to 71, the use of .into()
for number serialization does not guarantee valid JSON number formatting.
Replace .into() with an explicit conversion that converts the numeric values to
their string representations suitable for JSON output, ensuring the numbers are
correctly formatted as JSON numbers without quotes.

if i > 0 {
json.append(',');
}
json.append('"'); json.append(self.achievements[i]); json.append('"');
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix array access syntax for Cairo.

Cairo uses .at() method for array access, not bracket notation.

-json.append('"'); json.append(self.achievements[i]); json.append('"');
+json.append('"'); json.append(*self.achievements.at(i)); json.append('"');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
json.append('"'); json.append(self.achievements[i]); json.append('"');
json.append('"'); json.append(*self.achievements.at(i)); json.append('"');
🤖 Prompt for AI Agents
In src/base/reputation_metadata.cairo at line 83, the code uses bracket notation
to access array elements, which is incorrect in Cairo. Replace the bracket
access self.achievements[i] with the correct Cairo syntax using the .at()
method, i.e., self.achievements.at(i), to properly access the array element.

Comment on lines +170 to +194
fn batch_mint(
ref self: ContractState,
to: Array<ContractAddress>,
skill_categories: Array<felt252>
) -> Array<u256> {
// Only jobs contract or admin can mint
let caller = get_caller_address();
assert(
caller == self._jobs_contract.read() || caller == self._admin.read(),
'Unauthorized'
);

assert(to.len() == skill_categories.len(), 'Length mismatch');
let mut token_ids = ArrayTrait::new();
let mut i = 0;
loop {
if i >= to.len() {
break;
}
let token_id = self.mint(to[i], skill_categories[i]);
token_ids.append(token_id);
i += 1;
};
token_ids
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Optimize batch minting to avoid redundant authorization checks.

The current implementation checks authorization twice - once in batch_mint and then again for each mint call within the loop. This is inefficient and redundant.

Consider refactoring to use the internal _mint function directly:

 fn batch_mint(
     ref self: ContractState,
     to: Array<ContractAddress>,
     skill_categories: Array<felt252>
 ) -> Array<u256> {
     // Only jobs contract or admin can mint
     let caller = get_caller_address();
     assert(
         caller == self._jobs_contract.read() || caller == self._admin.read(),
         'Unauthorized'
     );
     
     assert(to.len() == skill_categories.len(), 'Length mismatch');
     let mut token_ids = ArrayTrait::new();
     let mut i = 0;
     loop {
         if i >= to.len() {
             break;
         }
-        let token_id = self.mint(to[i], skill_categories[i]);
+        let token_id = self._next_token_id.read();
+        self._mint(to[i], token_id);
+        self._skill_categories.write(token_id, skill_categories[i]);
+        self._next_token_id.write(token_id + 1);
         token_ids.append(token_id);
         i += 1;
     };
     token_ids
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fn batch_mint(
ref self: ContractState,
to: Array<ContractAddress>,
skill_categories: Array<felt252>
) -> Array<u256> {
// Only jobs contract or admin can mint
let caller = get_caller_address();
assert(
caller == self._jobs_contract.read() || caller == self._admin.read(),
'Unauthorized'
);
assert(to.len() == skill_categories.len(), 'Length mismatch');
let mut token_ids = ArrayTrait::new();
let mut i = 0;
loop {
if i >= to.len() {
break;
}
let token_id = self.mint(to[i], skill_categories[i]);
token_ids.append(token_id);
i += 1;
};
token_ids
}
fn batch_mint(
ref self: ContractState,
to: Array<ContractAddress>,
skill_categories: Array<felt252>
) -> Array<u256> {
// Only jobs contract or admin can mint
let caller = get_caller_address();
assert(
caller == self._jobs_contract.read() || caller == self._admin.read(),
'Unauthorized'
);
assert(to.len() == skill_categories.len(), 'Length mismatch');
let mut token_ids = ArrayTrait::new();
let mut i = 0;
loop {
if i >= to.len() {
break;
}
let token_id = self._next_token_id.read();
self._mint(to[i], token_id);
self._skill_categories.write(token_id, skill_categories[i]);
self._next_token_id.write(token_id + 1);
token_ids.append(token_id);
i += 1;
};
token_ids
}
🤖 Prompt for AI Agents
In src/contracts/ReputationNFT.cairo around lines 170 to 194, the batch_mint
function redundantly checks authorization both in batch_mint and inside each
mint call, causing inefficiency. Refactor batch_mint to perform the
authorization check once at the start, then call the internal _mint function
directly within the loop to mint tokens without repeated authorization checks.
This avoids redundant validation while preserving security.

Copy link
Contributor

@Cybermaxi7 Cybermaxi7 left a comment

Choose a reason for hiding this comment

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

LGTM
Welldone @Devsol-01 and thank you for contributing to our project!

@Cybermaxi7 Cybermaxi7 merged commit 144bf52 into StarkHive:main Jun 8, 2025
1 of 3 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.

Reputation NFT System

2 participants