Skip to content

Commit 2115580

Browse files
committed
feat: add operator role for withdrawal processing separate from admin ownership (#118)
1 parent 715a0ab commit 2115580

2 files changed

Lines changed: 205 additions & 104 deletions

File tree

stellar-contracts/src/lib.rs

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ pub enum DataKey {
246246
Operator(Address),
247247
OperatorHeartbeat(Address),
248248
OperatorNonce(Address),
249+
WithdrawOperator,
249250
Denied(Address),
250251
DeniedIndex(u64),
251252
DeniedCount,
@@ -545,14 +546,34 @@ impl FiatBridge {
545546
Ok(())
546547
}
547548

548-
pub fn withdraw(env: Env, to: Address, amount: i128, token: Address) -> Result<(), Error> {
549+
pub fn withdraw(
550+
env: Env,
551+
caller: Address,
552+
to: Address,
553+
amount: i128,
554+
token: Address,
555+
) -> Result<(), Error> {
549556
env.storage().instance().extend_ttl(MIN_TTL, MAX_TTL);
550557
let admin: Address = env
551558
.storage()
552559
.instance()
553560
.get(&DataKey::Admin)
554561
.ok_or(Error::NotInitialized)?;
555-
admin.require_auth();
562+
563+
let operator: Option<Address> = env.storage().instance().get(&DataKey::WithdrawOperator);
564+
565+
if caller == admin {
566+
caller.require_auth();
567+
} else if let Some(op) = operator {
568+
if caller == op {
569+
caller.require_auth();
570+
} else {
571+
return Err(Error::Unauthorized);
572+
}
573+
} else {
574+
return Err(Error::Unauthorized);
575+
}
576+
556577
Self::require_not_paused(&env)?;
557578

558579
if amount <= 0 {
@@ -2194,7 +2215,6 @@ impl FiatBridge {
21942215
};
21952216

21962217
env.events().publish(
2197-
(Symbol::new(&env, "batch_ok"), Symbol::new(&env, "v1")),
21982218
(EVENT_VERSION, Symbol::new(&env, "batch_ok")),
21992219
(success_count, failure_count, total_ops),
22002220
);
@@ -2471,6 +2491,40 @@ impl FiatBridge {
24712491
.instance()
24722492
.set(&head_key, &Option::<u64>::None);
24732493
}
2494+
2495+
// ── Single Withdraw Operator Role (Issue #118) ─────────────────────────
2496+
2497+
pub fn set_withdraw_operator(env: Env, operator: Address) -> Result<(), Error> {
2498+
env.storage().instance().extend_ttl(MIN_TTL, MAX_TTL);
2499+
let admin: Address = env
2500+
.storage()
2501+
.instance()
2502+
.get(&DataKey::Admin)
2503+
.ok_or(Error::NotInitialized)?;
2504+
admin.require_auth();
2505+
2506+
env.storage().instance().set(&DataKey::WithdrawOperator, &operator);
2507+
env.events().publish((EVENT_VERSION, Symbol::new(&env, "set_wd_op")), operator);
2508+
Ok(())
2509+
}
2510+
2511+
pub fn remove_withdraw_operator(env: Env) -> Result<(), Error> {
2512+
env.storage().instance().extend_ttl(MIN_TTL, MAX_TTL);
2513+
let admin: Address = env
2514+
.storage()
2515+
.instance()
2516+
.get(&DataKey::Admin)
2517+
.ok_or(Error::NotInitialized)?;
2518+
admin.require_auth();
2519+
2520+
env.storage().instance().remove(&DataKey::WithdrawOperator);
2521+
env.events().publish((EVENT_VERSION, Symbol::new(&env, "rm_wd_op")), ());
2522+
Ok(())
2523+
}
2524+
2525+
pub fn get_withdraw_operator(env: Env) -> Option<Address> {
2526+
env.storage().instance().get(&DataKey::WithdrawOperator)
2527+
}
24742528
}
24752529

24762530
#[cfg(any(test, feature = "testutils"))]

0 commit comments

Comments
 (0)