feat: Implement ERC-721 Soulbound Reputation NFTs with Skills, Rating…#46
feat: Implement ERC-721 Soulbound Reputation NFTs with Skills, Rating…#46Cybermaxi7 merged 1 commit intoStarkHive:mainfrom
Conversation
…s, and IPFS Metadata
WalkthroughThis 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
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)
Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Suggested reviewers
Poem
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 7
🔭 Outside diff range comments (2)
src/contracts/Jobs.cairo (2)
383-383:⚠️ Potential issueUpdate parameter name to match interface.
The parameter name should be
proposalto 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
OracleStatusenum 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
OracleStatusimportThe
OracleStatusenum is used in theasserton lines 147–148 but isn’t imported. Update theuse starkhive_contract::base::typesimport insrc/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_ofwould 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::ERC721import 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
📒 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
OracleStatusenum 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_managerandset_reputation_nftare 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.cairoLength of output: 936
Reputation score formula verified
Theget_reputation_scoreimplementation usesrating * 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; |
There was a problem hiding this comment.
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.
| fn set_reputation_nft(ref self: ContractState, reputation_nft: ContractAddress) { | ||
| // TODO: add admin check | ||
| self.reputation_nft.write(reputation_nft); | ||
| } |
There was a problem hiding this comment.
🛠️ 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.
| 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); | ||
|
|
There was a problem hiding this comment.
Fix experience level mismatch and add safety checks.
Two issues in the reputation NFT integration:
-
Experience level mismatch: The achievement matching uses
Beginner,Intermediate,Expertbut theExperienceLevelenum definesEntry,Junior,Mid,Senior,Expert. -
Missing null check: The code doesn't verify if
reputation_nftaddress 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.
| 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.
| 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('}'); |
There was a problem hiding this comment.
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.
| 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].
| json.append('"rating": '); json.append((*self.rating).into()); json.append(','); | ||
| json.append('"reputation_score": '); json.append((*self.reputation_score).into()); json.append(','); |
There was a problem hiding this comment.
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.
| 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('"'); |
There was a problem hiding this comment.
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.
| 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.
| 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 | ||
| } |
There was a problem hiding this comment.
🛠️ 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.
| 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.
Cybermaxi7
left a comment
There was a problem hiding this comment.
LGTM
Welldone @Devsol-01 and thank you for contributing to our project!
✅ 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
Bug Fixes
Tests