Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions contracts/src/rewards/events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//! Event definitions and helpers for the rewards module.
use soroban_sdk::{contracttype, symbol_short, Address, Env, Symbol};

#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PointsAwarded {
pub user: Address,
pub amount: u128,
}

#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BonusAwarded {
pub user: Address,
pub amount: u128,
pub bonus_type: Symbol, // e.g., "streak", "lock", "goal"
}

#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PointsRedeemed {
pub user: Address,
pub amount: u128,
}

#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct StreakUpdated {
pub user: Address,
pub streak: u32,
}

/// Emits a PointsAwarded event.
pub fn emit_points_awarded(env: &Env, user: Address, amount: u128) {
let event = PointsAwarded {
user: user.clone(),
amount,
};
env.events().publish(
(symbol_short!("rewards"), symbol_short!("awarded"), user),
event,
);
}

/// Emits a BonusAwarded event.
pub fn emit_bonus_awarded(env: &Env, user: Address, amount: u128, bonus_type: Symbol) {
let event = BonusAwarded {
user: user.clone(),
amount,
bonus_type,
};
env.events().publish(
(symbol_short!("rewards"), symbol_short!("bonus"), user),
event,
);
}

/// Emits a PointsRedeemed event.
pub fn emit_points_redeemed(env: &Env, user: Address, amount: u128) {
let event = PointsRedeemed {
user: user.clone(),
amount,
};
env.events().publish(
(symbol_short!("rewards"), symbol_short!("redeem"), user),
event,
);
}

/// Emits a StreakUpdated event.
pub fn emit_streak_updated(env: &Env, user: Address, streak: u32) {
let event = StreakUpdated {
user: user.clone(),
streak,
};
env.events().publish(
(symbol_short!("rewards"), symbol_short!("streak"), user),
event,
);
}
11 changes: 2 additions & 9 deletions contracts/src/rewards/mod.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
pub mod config;
pub mod events;
pub mod ranking;
pub mod redemption;
pub mod storage;
pub mod storage_types;

// Re-exporting these makes them accessible as crate::rewards::UserRewards
pub use config::*;
pub use events::*;
pub use storage_types::{RewardsDataKey, UserRewards}; // Optional: re-exports config functions

use soroban_sdk::{contracttype, Address};

#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PointsAwardedEvent {
pub user: Address,
pub amount: u128,
}
6 changes: 3 additions & 3 deletions contracts/src/rewards/redemption.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! Points redemption functionality for protocol benefits.

use crate::errors::SavingsError;
use crate::rewards::events::emit_points_redeemed;
use crate::rewards::storage::{get_user_rewards, save_user_rewards};
use soroban_sdk::{symbol_short, Address, Env, Symbol};
use soroban_sdk::{Address, Env};

/// Redeem points for protocol benefits (fee discounts, boost multiplier, etc.)
///
Expand Down Expand Up @@ -43,8 +44,7 @@ pub fn redeem_points(env: &Env, user: Address, amount: u128) -> Result<(), Savin
save_user_rewards(env, user.clone(), &rewards);

// Emit redemption event
env.events()
.publish((Symbol::new(env, "PointsRedeemed"), user.clone()), amount);
emit_points_redeemed(env, user, amount);

Ok(())
}
43 changes: 8 additions & 35 deletions contracts/src/rewards/storage.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Rewards storage, streak logic, and bonus point calculations.
use super::storage_types::{RewardsDataKey, UserRewards};
use crate::errors::SavingsError;
use crate::rewards::config::get_rewards_config;
use soroban_sdk::{symbol_short, Address, Env, Symbol};
use crate::rewards::events::{emit_bonus_awarded, emit_points_awarded, emit_streak_updated};
use soroban_sdk::{Address, Env, Symbol};

/// Duration threshold for long-lock bonus eligibility (in seconds).
pub const LONG_LOCK_BONUS_THRESHOLD_SECS: u64 = 180 * 24 * 60 * 60;
Expand Down Expand Up @@ -113,7 +113,8 @@ pub fn update_streak(env: &Env, user: Address) -> Result<u32, SavingsError> {
}
};
rewards.last_action_timestamp = now;
save_user_rewards(env, user, &rewards);
save_user_rewards(env, user.clone(), &rewards);
emit_streak_updated(env, user, rewards.current_streak);
Ok(rewards.current_streak)
}

Expand Down Expand Up @@ -213,25 +214,11 @@ pub fn award_deposit_points(env: &Env, user: Address, amount: i128) -> Result<()
// Track user for ranking leaderboard
crate::rewards::ranking::track_user_for_ranking(env, user.clone());

env.events().publish(
(
symbol_short!("rewards"),
symbol_short!("awarded"),
user.clone(),
),
capped_points,
);
emit_points_awarded(env, user.clone(), capped_points);

if streak_bonus_points > 0 && capped_points > base_points {
let actual_bonus = capped_points.saturating_sub(base_points);
env.events().publish(
(
Symbol::new(env, "BonusAwarded"),
user.clone(),
symbol_short!("streak"),
),
actual_bonus,
);
emit_bonus_awarded(env, user, actual_bonus, Symbol::new(env, "streak"));
}

Ok(())
Expand Down Expand Up @@ -270,14 +257,7 @@ pub fn award_long_lock_bonus(
}

add_points(env, user.clone(), bonus_points)?;
env.events().publish(
(
Symbol::new(env, "BonusAwarded"),
user,
symbol_short!("lock"),
),
bonus_points,
);
emit_bonus_awarded(env, user, bonus_points, Symbol::new(env, "lock"));
Ok(bonus_points)
}

Expand All @@ -294,14 +274,7 @@ pub fn award_goal_completion_bonus(env: &Env, user: Address) -> Result<u128, Sav

let bonus_points = config.goal_completion_bonus as u128;
add_points(env, user.clone(), bonus_points)?;
env.events().publish(
(
Symbol::new(env, "BonusAwarded"),
user,
symbol_short!("goal"),
),
bonus_points,
);
emit_bonus_awarded(env, user, bonus_points, Symbol::new(env, "goal"));
Ok(bonus_points)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -725,5 +725,49 @@
]
]
},
"events": []
"events": [
{
"event": {
"ext": "v0",
"contract_id": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"type_": "contract",
"body": {
"v0": {
"topics": [
{
"symbol": "rewards"
},
{
"symbol": "streak"
},
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
],
"data": {
"map": [
{
"key": {
"symbol": "streak"
},
"val": {
"u32": 2
}
},
{
"key": {
"symbol": "user"
},
"val": {
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
}
]
}
}
}
},
"failed_call": false
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -725,5 +725,49 @@
]
]
},
"events": []
"events": [
{
"event": {
"ext": "v0",
"contract_id": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"type_": "contract",
"body": {
"v0": {
"topics": [
{
"symbol": "rewards"
},
{
"symbol": "streak"
},
{
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
],
"data": {
"map": [
{
"key": {
"symbol": "streak"
},
"val": {
"u32": 1
}
},
{
"key": {
"symbol": "user"
},
"val": {
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
}
]
}
}
}
},
"failed_call": false
}
]
}
Loading