Skip to content

Commit 179eec6

Browse files
author
Ahmad Abdulkareem
authored
Merge pull request #102 from phertyameen/reputation
Add mentor reputation system (storage, read, increment, decrement)
2 parents 8baa44f + dd328d0 commit 179eec6

File tree

4 files changed

+157
-0
lines changed

4 files changed

+157
-0
lines changed

src/lib.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![no_std]
2+
3+
use soroban_sdk::{contract, contractimpl, Env, Address};
4+
5+
mod storage;
6+
mod reputation;
7+
8+
#[contract]
9+
pub struct SkillSync;
10+
11+
#[contractimpl]
12+
impl SkillSync {
13+
pub fn get_reputation(env: Env, mentor: Address) -> u32 {
14+
reputation::get_reputation(env, mentor)
15+
}
16+
17+
pub fn increment_reputation(env: Env, caller: Address, mentor: Address, amount: u32) {
18+
reputation::increment_reputation(env, caller, mentor, amount)
19+
}
20+
21+
pub fn decrement_reputation(env: Env, caller: Address, mentor: Address, amount: u32) {
22+
reputation::decrement_reputation(env, caller, mentor, amount)
23+
}
24+
}

src/reputation.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use soroban_sdk::{Address, Env, Symbol};
2+
3+
use crate::storage::{get_rep, set_rep};
4+
5+
// 🔐 simple admin check (replace with real ACL if needed)
6+
fn require_admin(e: &Env, caller: &Address) {
7+
let admin: Address = e.storage().instance().get(&Symbol::short("admin")).unwrap();
8+
if &admin != caller {
9+
panic!("Unauthorized");
10+
}
11+
}
12+
13+
// #93 READ
14+
pub fn get_reputation(e: Env, mentor: Address) -> u32 {
15+
get_rep(&e, &mentor)
16+
}
17+
18+
// #91 INCREMENT
19+
pub fn increment_reputation(e: Env, caller: Address, mentor: Address, amount: u32) {
20+
require_admin(&e, &caller);
21+
22+
let current = get_rep(&e, &mentor);
23+
24+
let updated = current
25+
.checked_add(amount)
26+
.expect("Overflow");
27+
28+
set_rep(&e, &mentor, updated);
29+
30+
e.events().publish(
31+
(Symbol::short("rep_inc"), mentor),
32+
updated,
33+
);
34+
}
35+
36+
// #92 DECREMENT
37+
pub fn decrement_reputation(e: Env, caller: Address, mentor: Address, amount: u32) {
38+
require_admin(&e, &caller);
39+
40+
let current = get_rep(&e, &mentor);
41+
42+
let updated = current
43+
.checked_sub(amount)
44+
.unwrap_or(0); // floor at 0
45+
46+
set_rep(&e, &mentor, updated);
47+
48+
e.events().publish(
49+
(Symbol::short("rep_dec"), mentor),
50+
updated,
51+
);
52+
}

src/storage.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use soroban_sdk::{contracttype, Address, Env, Symbol};
2+
3+
#[contracttype]
4+
#[derive(Clone)]
5+
pub struct MentorReputation(pub u32);
6+
7+
fn rep_key() -> Symbol {
8+
Symbol::short("rep")
9+
}
10+
11+
pub fn get_rep(e: &Env, mentor: &Address) -> u32 {
12+
e.storage()
13+
.persistent()
14+
.get(&(rep_key(), mentor))
15+
.unwrap_or(MentorReputation(0))
16+
.0
17+
}
18+
19+
pub fn set_rep(e: &Env, mentor: &Address, value: u32) {
20+
e.storage()
21+
.persistent()
22+
.set(&(rep_key(), mentor), &MentorReputation(value));
23+
}

src/tests/reputation.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use soroban_sdk::{Env, Address};
2+
3+
use crate::SkillSync;
4+
5+
#[test]
6+
fn test_default_reputation() {
7+
let env = Env::default();
8+
let mentor = Address::random(&env);
9+
10+
let rep = SkillSync::get_reputation(env.clone(), mentor);
11+
assert_eq!(rep, 0);
12+
}
13+
14+
#[test]
15+
fn test_increment() {
16+
let env = Env::default();
17+
let admin = Address::random(&env);
18+
let mentor = Address::random(&env);
19+
20+
env.storage().instance().set(&"admin", &admin);
21+
22+
SkillSync::increment_reputation(env.clone(), admin.clone(), mentor.clone(), 10);
23+
24+
let rep = SkillSync::get_reputation(env.clone(), mentor);
25+
assert_eq!(rep, 10);
26+
}
27+
28+
#[test]
29+
fn test_decrement_floor() {
30+
let env = Env::default();
31+
let admin = Address::random(&env);
32+
let mentor = Address::random(&env);
33+
34+
env.storage().instance().set(&"admin", &admin);
35+
36+
SkillSync::increment_reputation(env.clone(), admin.clone(), mentor.clone(), 5);
37+
SkillSync::decrement_reputation(env.clone(), admin.clone(), mentor.clone(), 10);
38+
39+
let rep = SkillSync::get_reputation(env.clone(), mentor);
40+
assert_eq!(rep, 0);
41+
}
42+
43+
#[test]
44+
fn test_overflow_protection() {
45+
let env = Env::default();
46+
let admin = Address::random(&env);
47+
let mentor = Address::random(&env);
48+
49+
env.storage().instance().set(&"admin", &admin);
50+
51+
SkillSync::increment_reputation(env.clone(), admin.clone(), mentor.clone(), u32::MAX);
52+
53+
let result = std::panic::catch_unwind(|| {
54+
SkillSync::increment_reputation(env.clone(), admin.clone(), mentor.clone(), 1);
55+
});
56+
57+
assert!(result.is_err());
58+
}

0 commit comments

Comments
 (0)