@@ -4,8 +4,10 @@ use soroban_sdk::{
44 contract, contracterror, contractimpl, contracttype, panic_with_error, Address , Env , Symbol ,
55} ;
66
7+ use soroban_sdk:: token:: Client ;
8+
79/// Minimum number of ledgers between registrations per caller (anti-spam).
8- const RATE_LIMIT_LEDGERS : u32 = 10 ;
10+ const DEFAULT_RATE_LIMIT : u32 = 10 ;
911
1012#[ contracttype]
1113#[ derive( Clone , Debug , Eq , PartialEq ) ]
@@ -14,7 +16,11 @@ pub enum DataKey {
1416 Creator ( Address ) , // maps creator address -> creator_id (u64)
1517 // Canonical storage name: `registration_ledger`.
1618 // Keep the legacy `LastRegLedger` variant to preserve deployed key serialization.
17- LastRegLedger ( Address ) , // last ledger when this caller did a registration
19+ LastRegLedger ( Address ) ,
20+
21+ RateLimit ,
22+ SpamFee ,
23+ FeeToken ,
1824}
1925
2026impl DataKey {
@@ -34,6 +40,8 @@ pub enum Error {
3440 RateLimited = 4 ,
3541 AlreadyRegistered = 5 ,
3642 NotRegistered = 6 ,
43+
44+ InvalidAmount = 7 ,
3745}
3846
3947#[ contract]
@@ -47,6 +55,31 @@ impl CreatorRegistryContract {
4755 panic_with_error ! ( & env, Error :: AlreadyInitialized ) ;
4856 }
4957 env. storage ( ) . instance ( ) . set ( & DataKey :: Admin , & admin) ;
58+
59+ env. storage ( )
60+ . instance ( )
61+ . set ( & DataKey :: RateLimit , & DEFAULT_RATE_LIMIT ) ;
62+ env. storage ( ) . instance ( ) . set ( & DataKey :: SpamFee , & 0i128 ) ;
63+ }
64+ // set the number of ledgers for rate limiting (admin only)
65+ pub fn set_rate_limit ( env : Env , ledgers : u32 ) {
66+ let admin = Self :: get_admin ( & env) ;
67+ admin. require_auth ( ) ;
68+
69+ env. storage ( ) . instance ( ) . set ( & DataKey :: RateLimit , & ledgers) ;
70+ }
71+
72+ // set the fee for spamming registrations (admin only)
73+ pub fn set_spam_fee ( env : Env , token : Address , amount : i128 ) {
74+ let admin = Self :: get_admin ( & env) ;
75+ admin. require_auth ( ) ;
76+
77+ if amount < 0 {
78+ panic_with_error ! ( & env, Error :: InvalidAmount ) ;
79+ }
80+
81+ env. storage ( ) . instance ( ) . set ( & DataKey :: SpamFee , & amount) ;
82+ env. storage ( ) . instance ( ) . set ( & DataKey :: FeeToken , & token) ;
5083 }
5184
5285 /// Register a creator with a specific creator_id
@@ -68,7 +101,7 @@ impl CreatorRegistryContract {
68101 let current = env. ledger ( ) . sequence ( ) ;
69102 let last_key = DataKey :: registration_ledger ( caller. clone ( ) ) ;
70103 if let Some ( last) = env. storage ( ) . persistent ( ) . get :: < DataKey , u32 > ( & last_key) {
71- if current < last. saturating_add ( RATE_LIMIT_LEDGERS ) {
104+ if current < last. saturating_add ( DEFAULT_RATE_LIMIT ) {
72105 panic_with_error ! ( & env, Error :: RateLimited ) ;
73106 }
74107 }
@@ -80,6 +113,21 @@ impl CreatorRegistryContract {
80113
81114 env. storage ( ) . persistent ( ) . set ( & last_key, & current) ;
82115 env. storage ( ) . persistent ( ) . set ( & key, & creator_id) ;
116+
117+ let fee: i128 = env. storage ( ) . instance ( ) . get ( & DataKey :: SpamFee ) . unwrap_or ( 0 ) ;
118+
119+ if fee > 0 {
120+ let token_address: Address = env
121+ . storage ( )
122+ . instance ( )
123+ . get ( & DataKey :: FeeToken )
124+ . unwrap_or_else ( || panic_with_error ! ( & env, Error :: NotInitialized ) ) ;
125+
126+ let token_client = Client :: new ( & env, & token_address) ;
127+
128+ // transfer fee from caller to contract if fee is set
129+ token_client. transfer ( & caller, & env. current_contract_address ( ) , & fee) ;
130+ }
83131 }
84132
85133 /// Unregister a creator (admin only).
@@ -116,6 +164,13 @@ impl CreatorRegistryContract {
116164 pub fn get_creator_id ( env : Env , address : Address ) -> Option < u64 > {
117165 env. storage ( ) . persistent ( ) . get ( & DataKey :: Creator ( address) )
118166 }
167+ // Internal helper to enforce authorization of admin or creator
168+ fn get_admin ( env : & Env ) -> Address {
169+ env. storage ( )
170+ . instance ( )
171+ . get ( & DataKey :: Admin )
172+ . unwrap_or_else ( || panic_with_error ! ( env, Error :: NotInitialized ) )
173+ }
119174}
120175
121176mod test;
0 commit comments