Skip to content

Commit a07402d

Browse files
committed
feat(contract): add notification category metadata to events
Off-chain consumers could not selectively subscribe to specific notification categories because every event looked the same beyond its name. This adds a NotificationCategory (Group / Admin / Financial) published as a trailing, indexed topic on every emitted event so listeners and indexers can filter by category without decoding payloads. - Introduce NotificationCategory enum in base::events. - Attach the category as the last topic of every contract event. - Keep the change backward compatible: the event name remains the first topic and all pre-existing topics/data keep their positions; the new category topic is simply appended and ignored by existing listeners. - Add tests covering each category and a subscriber that filters by type.
1 parent 396bda5 commit a07402d

4 files changed

Lines changed: 370 additions & 10 deletions

File tree

contract/contracts/hello-world/src/autoshare_logic.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::base::errors::Error;
22
use crate::base::events::{
33
AdminTransferred, AutoshareCreated, AutoshareUpdated, ContractPaused, ContractUnpaused,
4-
GroupActivated, GroupDeactivated, Withdrawal,
4+
GroupActivated, GroupDeactivated, NotificationCategory, Withdrawal,
55
};
66
use crate::base::types::{AutoShareDetails, GroupMember, PaymentHistory};
77
use soroban_sdk::{contracttype, token, Address, BytesN, Env, String, Vec};
@@ -108,6 +108,7 @@ pub fn create_autoshare(
108108

109109
AutoshareCreated {
110110
creator: creator.clone(),
111+
category: NotificationCategory::Group,
111112
id: id.clone(),
112113
}
113114
.publish(&env);
@@ -275,6 +276,7 @@ pub fn transfer_admin(env: Env, current_admin: Address, new_admin: Address) -> R
275276
env.storage().persistent().set(&DataKey::Admin, &new_admin);
276277
AdminTransferred {
277278
old_admin: current_admin,
279+
category: NotificationCategory::Admin,
278280
new_admin,
279281
}
280282
.publish(&env);
@@ -297,7 +299,10 @@ pub fn pause(env: Env, admin: Address) -> Result<(), Error> {
297299
}
298300

299301
env.storage().persistent().set(&pause_key, &true);
300-
ContractPaused {}.publish(&env);
302+
ContractPaused {
303+
category: NotificationCategory::Admin,
304+
}
305+
.publish(&env);
301306
Ok(())
302307
}
303308

@@ -313,7 +318,10 @@ pub fn unpause(env: Env, admin: Address) -> Result<(), Error> {
313318
}
314319

315320
env.storage().persistent().set(&pause_key, &false);
316-
ContractUnpaused {}.publish(&env);
321+
ContractUnpaused {
322+
category: NotificationCategory::Admin,
323+
}
324+
.publish(&env);
317325
Ok(())
318326
}
319327

@@ -646,8 +654,9 @@ pub fn update_members(
646654
env.storage().persistent().set(&members_key, &new_members);
647655

648656
AutoshareUpdated {
649-
id: id.clone(),
650657
updater: caller,
658+
category: NotificationCategory::Group,
659+
id: id.clone(),
651660
}
652661
.publish(&env);
653662
Ok(())
@@ -680,8 +689,9 @@ pub fn deactivate_group(env: Env, id: BytesN<32>, caller: Address) -> Result<(),
680689
env.storage().persistent().set(&key, &details);
681690

682691
GroupDeactivated {
683-
id: id.clone(),
684692
creator: caller,
693+
category: NotificationCategory::Group,
694+
id: id.clone(),
685695
}
686696
.publish(&env);
687697
Ok(())
@@ -714,8 +724,9 @@ pub fn activate_group(env: Env, id: BytesN<32>, caller: Address) -> Result<(), E
714724
env.storage().persistent().set(&key, &details);
715725

716726
GroupActivated {
717-
id: id.clone(),
718727
creator: caller,
728+
category: NotificationCategory::Group,
729+
id: id.clone(),
719730
}
720731
.publish(&env);
721732
Ok(())
@@ -761,8 +772,9 @@ pub fn withdraw(
761772

762773
Withdrawal {
763774
token,
764-
amount,
765775
recipient,
776+
category: NotificationCategory::Financial,
777+
amount,
766778
}
767779
.publish(&env);
768780
Ok(())

contract/contracts/hello-world/src/base/events.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,65 @@
1-
use soroban_sdk::{contractevent, Address, BytesN};
1+
use soroban_sdk::{contractevent, contracttype, Address, BytesN};
2+
3+
/// High-level notification category attached to every emitted event.
4+
///
5+
/// Off-chain consumers (listeners, indexers, dashboards) often only care about a
6+
/// subset of the events the contract emits. Each event carries its category as a
7+
/// trailing, indexed event topic so consumers can subscribe to — or filter out —
8+
/// whole categories without having to decode the event payload first.
9+
///
10+
/// # Backward compatibility
11+
///
12+
/// The category is published as the *last* topic of every event, after the event
13+
/// name and any pre-existing topics. Existing listeners that read the event name
14+
/// (the first topic) and the previously defined topics/data are unaffected: the
15+
/// extra trailing topic is simply ignored by consumers that don't look for it.
16+
#[contracttype]
17+
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
18+
pub enum NotificationCategory {
19+
/// Lifecycle changes to AutoShare groups: created, updated, activated,
20+
/// deactivated.
21+
Group = 0,
22+
/// Administrative / system actions: pause, unpause, admin transfer.
23+
Admin = 1,
24+
/// Movement of funds: withdrawals.
25+
Financial = 2,
26+
}
227

328
/// Emitted when a new AutoShare group is created.
429
#[contractevent(data_format = "single-value")]
530
#[derive(Clone)]
631
pub struct AutoshareCreated {
732
#[topic]
833
pub creator: Address,
34+
#[topic]
35+
pub category: NotificationCategory,
936
pub id: BytesN<32>,
1037
}
1138

1239
/// Emitted when the contract is paused by the admin.
1340
#[contractevent]
1441
#[derive(Clone)]
15-
pub struct ContractPaused {}
42+
pub struct ContractPaused {
43+
#[topic]
44+
pub category: NotificationCategory,
45+
}
1646

1747
/// Emitted when the contract is unpaused by the admin.
1848
#[contractevent]
1949
#[derive(Clone)]
20-
pub struct ContractUnpaused {}
50+
pub struct ContractUnpaused {
51+
#[topic]
52+
pub category: NotificationCategory,
53+
}
2154

2255
/// Emitted when an AutoShare group's member list is updated.
2356
#[contractevent(data_format = "single-value")]
2457
#[derive(Clone)]
2558
pub struct AutoshareUpdated {
2659
#[topic]
2760
pub updater: Address,
61+
#[topic]
62+
pub category: NotificationCategory,
2863
pub id: BytesN<32>,
2964
}
3065

@@ -34,6 +69,8 @@ pub struct AutoshareUpdated {
3469
pub struct GroupDeactivated {
3570
#[topic]
3671
pub creator: Address,
72+
#[topic]
73+
pub category: NotificationCategory,
3774
pub id: BytesN<32>,
3875
}
3976

@@ -43,6 +80,8 @@ pub struct GroupDeactivated {
4380
pub struct GroupActivated {
4481
#[topic]
4582
pub creator: Address,
83+
#[topic]
84+
pub category: NotificationCategory,
4685
pub id: BytesN<32>,
4786
}
4887

@@ -52,6 +91,8 @@ pub struct GroupActivated {
5291
pub struct AdminTransferred {
5392
#[topic]
5493
pub old_admin: Address,
94+
#[topic]
95+
pub category: NotificationCategory,
5596
pub new_admin: Address,
5697
}
5798

@@ -63,5 +104,7 @@ pub struct Withdrawal {
63104
pub token: Address,
64105
#[topic]
65106
pub recipient: Address,
107+
#[topic]
108+
pub category: NotificationCategory,
66109
pub amount: i128,
67110
}

contract/contracts/hello-world/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,4 +256,7 @@ mod tests {
256256

257257
#[path = "../tests/test_utils_test.rs"]
258258
mod test_utils_test;
259+
260+
#[path = "../tests/notification_test.rs"]
261+
mod notification_test;
259262
}

0 commit comments

Comments
 (0)