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
4 changes: 4 additions & 0 deletions veritixpay/contract/token/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod dispute;
pub mod escrow;
pub mod freeze;
pub mod metadata;
pub mod pause;
pub mod recurring;
pub mod splitter;
pub mod storage_types;
Expand Down Expand Up @@ -42,6 +43,9 @@ mod splitter_test;
#[cfg(test)]
mod dispute_test;

#[cfg(test)]
mod pause_test;

#[cfg(test)]
mod recurring_test;

Expand Down
29 changes: 29 additions & 0 deletions veritixpay/contract/token/src/pause.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use crate::admin::check_admin;
use crate::storage_types::DataKey;
use soroban_sdk::{symbol_short, Address, Env};

/// Returns `true` if the contract is currently paused.
pub fn is_paused(e: &Env) -> bool {
e.storage().instance().get(&DataKey::Paused).unwrap_or(false)
}

/// Panics if the contract is paused; call at the top of transfer/mint/burn.
pub fn require_not_paused(e: &Env) {
if is_paused(e) {
panic!("ContractPaused: all transfers are currently paused");
}
}

/// Admin pauses all token transfers globally.
pub fn pause(e: &Env, admin: Address) {
check_admin(e, &admin);
e.storage().instance().set(&DataKey::Paused, &true);
e.events().publish((symbol_short!("paused"), admin), ());
}

/// Admin unpauses the contract, restoring normal operation.
pub fn unpause(e: &Env, admin: Address) {
check_admin(e, &admin);
e.storage().instance().remove(&DataKey::Paused);
e.events().publish((symbol_short!("unpaused"), admin), ());
}
35 changes: 35 additions & 0 deletions veritixpay/contract/token/src/pause_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use soroban_sdk::{testutils::Address as _, Address, Env};
use crate::contract::VeritixToken;
use crate::pause::{is_paused, pause, require_not_paused, unpause};

fn setup_env() -> Env { let e = Env::default(); e.mock_all_auths(); e }

#[test]
fn test_pause_and_unpause_toggles_state() {
let e = setup_env();
let cid = e.register_contract(None, VeritixToken);
let admin = Address::generate(&e);

e.as_contract(&cid, || {
crate::admin::write_admin(&e, &admin);
assert!(!is_paused(&e));
pause(&e, admin.clone());
assert!(is_paused(&e));
unpause(&e, admin.clone());
assert!(!is_paused(&e));
});
}

#[test]
#[should_panic(expected = "ContractPaused")]
fn test_require_not_paused_panics_when_paused() {
let e = setup_env();
let cid = e.register_contract(None, VeritixToken);
let admin = Address::generate(&e);

e.as_contract(&cid, || {
crate::admin::write_admin(&e, &admin);
pause(&e, admin.clone());
require_not_paused(&e);
});
}
3 changes: 3 additions & 0 deletions veritixpay/contract/token/src/storage_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ pub enum DataKey {

// Stores per-address freeze status.
Freeze(Address),

// Global emergency pause flag.
Paused,
}

pub fn read_persistent_record<T>(e: &Env, key: &DataKey, missing_message: &'static str) -> T
Expand Down