Skip to content

Commit 4e53f52

Browse files
authored
Merge pull request #702 from akintewe/feat/wallet-blacklist-issue-700
Add unit tests for admin wallet blacklist rejecting buy/sell/registration
2 parents cf61d95 + cee3442 commit 4e53f52

3 files changed

Lines changed: 374 additions & 0 deletions

File tree

‎creator-keys/src/events.rs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ pub const PAUSE_EVENT_NAME: Symbol = symbol_short!("pause");
3434
/// Event name for protocol unpause.
3535
pub const UNPAUSE_EVENT_NAME: Symbol = symbol_short!("unpause");
3636

37+
/// Event name for a wallet being added to the admin blacklist.
38+
pub const BLACKLIST_ADDED_EVENT_NAME: Symbol = symbol_short!("blk_add");
39+
40+
/// Event name for a wallet being removed from the admin blacklist.
41+
pub const BLACKLIST_REMOVED_EVENT_NAME: Symbol = symbol_short!("blk_rem");
42+
3743
/// Event name for creator registration.
3844
pub const REGISTER_EVENT_NAME: Symbol = symbol_short!("register");
3945

‎creator-keys/src/lib.rs‎

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ pub enum ContractError {
8383
InvalidReferrer = 34,
8484
WalletCapExceeded = 35,
8585
DiscountTierLimitExceeded = 36,
86+
WalletBlacklisted = 37,
8687
}
8788

8889
pub mod fee {
@@ -332,6 +333,10 @@ pub mod constants {
332333
DataKey::Whitelist(creator.clone())
333334
}
334335

336+
pub fn blacklisted(wallet: &Address) -> DataKey {
337+
DataKey::Blacklisted(wallet.clone())
338+
}
339+
335340
pub fn creator(creator: &Address) -> DataKey {
336341
creator_key(creator)
337342
}
@@ -608,6 +613,9 @@ pub enum DataKey {
608613
/// decide whether to emit the TTL-extension event without a TTL read
609614
/// (the Soroban SDK does not expose TTL reads to contract code).
610615
CreatorTtlLiveUntil(Address),
616+
/// Wallet addresses the protocol admin has barred from buying, selling,
617+
/// or registering as a creator.
618+
Blacklisted(Address),
611619
}
612620

613621
/// Time-locked key allocation for creator self-vesting.
@@ -1004,6 +1012,20 @@ fn assert_not_paused(env: &Env) -> Result<(), ContractError> {
10041012
Ok(())
10051013
}
10061014

1015+
fn is_blacklisted(env: &Env, wallet: &Address) -> bool {
1016+
env.storage()
1017+
.persistent()
1018+
.get::<DataKey, bool>(&constants::storage::blacklisted(wallet))
1019+
.unwrap_or(false)
1020+
}
1021+
1022+
fn assert_not_blacklisted(env: &Env, wallet: &Address) -> Result<(), ContractError> {
1023+
if is_blacklisted(env, wallet) {
1024+
return Err(ContractError::WalletBlacklisted);
1025+
}
1026+
Ok(())
1027+
}
1028+
10071029
fn assert_is_admin(env: &Env, caller: &Address) -> Result<(), ContractError> {
10081030
let admin: Address = env
10091031
.storage()
@@ -1521,6 +1543,7 @@ impl CreatorKeysContract {
15211543

15221544
creator.require_auth();
15231545
assert_not_paused(&env)?;
1546+
assert_not_blacklisted(&env, &creator)?;
15241547

15251548
validate_creator_handle(&handle)?;
15261549
if let Some(config) = co_creator.as_ref() {
@@ -1684,6 +1707,7 @@ impl CreatorKeysContract {
16841707
) -> Result<u32, ContractError> {
16851708
buyer.require_auth();
16861709
assert_not_paused(&env)?;
1710+
assert_not_blacklisted(&env, &buyer)?;
16871711

16881712
if payment <= 0 {
16891713
return Err(ContractError::NotPositiveAmount);
@@ -1852,6 +1876,7 @@ impl CreatorKeysContract {
18521876
) -> Result<u32, ContractError> {
18531877
seller.require_auth();
18541878
assert_not_paused(&env)?;
1879+
assert_not_blacklisted(&env, &seller)?;
18551880

18561881
let mut profile: CreatorProfile = read_registered_creator_profile(&env, &creator)?;
18571882

@@ -2231,6 +2256,48 @@ impl CreatorKeysContract {
22312256
is_paused(&env)
22322257
}
22332258

2259+
/// Blocks a wallet from buying, selling, or registering as a creator.
2260+
///
2261+
/// Only the protocol admin may call this. Emits a `blacklist` event.
2262+
pub fn blacklist_wallet(
2263+
env: Env,
2264+
admin: Address,
2265+
wallet: Address,
2266+
) -> Result<(), ContractError> {
2267+
admin.require_auth();
2268+
assert_is_admin(&env, &admin)?;
2269+
env.storage()
2270+
.persistent()
2271+
.set(&constants::storage::blacklisted(&wallet), &true);
2272+
env.events()
2273+
.publish((events::BLACKLIST_ADDED_EVENT_NAME, wallet), ());
2274+
Ok(())
2275+
}
2276+
2277+
/// Restores a previously blacklisted wallet's access to buy, sell, and
2278+
/// register as a creator.
2279+
///
2280+
/// Only the protocol admin may call this. Emits an `unblacklist` event.
2281+
pub fn remove_from_blacklist(
2282+
env: Env,
2283+
admin: Address,
2284+
wallet: Address,
2285+
) -> Result<(), ContractError> {
2286+
admin.require_auth();
2287+
assert_is_admin(&env, &admin)?;
2288+
env.storage()
2289+
.persistent()
2290+
.remove(&constants::storage::blacklisted(&wallet));
2291+
env.events()
2292+
.publish((events::BLACKLIST_REMOVED_EVENT_NAME, wallet), ());
2293+
Ok(())
2294+
}
2295+
2296+
/// Read-only view: returns whether `wallet` is currently blacklisted.
2297+
pub fn is_wallet_blacklisted(env: Env, wallet: Address) -> bool {
2298+
is_blacklisted(&env, &wallet)
2299+
}
2300+
22342301
pub fn get_key_balance(env: Env, creator: Address, wallet: Address) -> u32 {
22352302
let key = constants::storage::holder_balance_key(&creator, &wallet);
22362303
// Read-only callers get `0` for unseen balances to avoid sparse-map lookups failing.

0 commit comments

Comments
 (0)