Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pausable inline docs #9

Merged
merged 5 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from 3 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
43 changes: 43 additions & 0 deletions contracts/utils/pausable/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,46 @@
//! Pausable Contract Module.
//!
//! This contract module allows implementing a configurable stop mechanism for your contract.
//!
//! By implementing the trait [`Pausable`] for your contract,
//! you can safely integrate the Pausable functionality.
//! The trait [`Pausable`] has the following methods:
//! - [`storage::paused()`](`paused()`)
//! - [`storage::pause()`](`pause()`)
//! - [`storage::unpause()`](`unpause()`)
//!
//! The trait ensures all the required methods are implemented for your contract,
//! and nothing is forgotten. Additionally, if you are to implement multiple extensions
//! or utilities for your contract, the code will be better organized.
//!
//! We also provide two macros `when_paused` and `when_not_paused` (will be implemented later).
//! These macros act as guards for your functions. For example:
//! ```rust
//! #[when_not_paused]
//! fn transfer(e: &env, from: Address, to: Address) {
//! /* this body will execute ONLY when NOT_PAUSED */
//! }
//! ```
//!
//! For a safe pause/unpause implementation, we expose the underlying
//! functions required for the locking. These functions work with the Soroban
//! environment required for the Smart Contracts `e: &Env`, and take advantage
//! of the storage by storing a flag for the pause mechanism.
//!
//! We expect you to utilize these functions (`storage::*`) for implementing
//! the methods of the `Pausable` trait, along with your custom business logic (authentication, etc.)
//!
//! For god knows why, if you want to opt-out of [`Pausable`] trait, and use
//! `storage::*` functions directly in your contract, well... you can!
//! But we encourage the use of [`Pausable`] trait instead, due to:
//! - there is no additional cost
//! - standardization
//! - you cannot mistakenly forget one of the methods
//! - your code will be better organized, especially if you implement multiple extensions/utils
//!
//! TL;DR
//! to see it all in action, check out the `examples/pausable/src/contract.rs` file.

#![no_std]

mod pausable;
Expand Down
19 changes: 7 additions & 12 deletions contracts/utils/pausable/src/pausable.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,3 @@
//! Pausable Contract Module.
//!
//! Contract module which allows implementing an emergency stop mechanism
//! that can be triggered by an authorized account.
//!
//! It provides functions [`pausable::when_not_paused`]
//! and [`pausable::when_paused`],
//! which can be added to the functions of your contract.
//!
//! Note that your contract will NOT be pausable by simply including this
//! module only once and where you use [`pausable::when_not_paused`].

use soroban_sdk::{contractclient, contracterror, symbol_short, Address, Env};

#[contractclient(name = "PausableClient")]
Expand All @@ -19,6 +7,9 @@ pub trait Pausable {
/// # Arguments
///
/// * `e` - Access to Soroban environment.
///
/// we expect you to use the [`storage::paused()`](`paused()`) function from the `storage` module
/// when implementing this function.
fn paused(e: Env) -> bool;

/// Triggers `Paused` state.
Expand All @@ -37,6 +28,8 @@ pub trait Pausable {
///
/// * topics - `["paused"]`
/// * data - `[caller: Address]`
///
/// we expect you to use the [`storage::pause()`](`pause()`) function from the `storage` module.
fn pause(e: Env, caller: Address);

/// Triggers `Unpaused` state.
Expand All @@ -55,6 +48,8 @@ pub trait Pausable {
///
/// * topics - `["unpaused"]`
/// * data - `[caller: Address]`
///
/// we expect you to use the [`storage::unpause()`](`unpause()`) function from the `storage` module.
fn unpause(e: Env, caller: Address);
}

Expand Down
10 changes: 10 additions & 0 deletions contracts/utils/pausable/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub(crate) const PAUSED: Symbol = symbol_short!("PAUSED");
/// # Arguments
///
/// * `e` - Access to Soroban environment.
///
/// no authorization is required for this function.
pub fn paused(e: &Env) -> bool {
// if not paused, consider default false (unpaused)
e.storage().instance().get(&PAUSED).unwrap_or(false)
Expand All @@ -31,6 +33,8 @@ pub fn paused(e: &Env) -> bool {
///
/// * topics - `["paused"]`
/// * data - `[caller: Address]`
///
/// authorization is required for this function.
pub fn pause(e: &Env, caller: &Address) {
caller.require_auth();
when_not_paused(e);
Expand All @@ -54,6 +58,8 @@ pub fn pause(e: &Env, caller: &Address) {
///
/// * topics - `["unpaused"]`
/// * data - `[caller: Address]`
///
/// authorization is required for this function.
pub fn unpause(e: &Env, caller: &Address) {
caller.require_auth();
when_paused(e);
Expand All @@ -72,6 +78,8 @@ pub fn unpause(e: &Env, caller: &Address) {
///
/// If the contract is in the `Paused` state, then the error
/// [`PausableError::EnforcedPause`] is thrown.
///
/// no authorization is required for this function.
pub fn when_not_paused(e: &Env) {
if paused(e) {
panic_with_error!(e, PausableError::EnforcedPause)
Expand All @@ -89,6 +97,8 @@ pub fn when_not_paused(e: &Env) {
///
/// If the contract is in `Unpaused` state, then the error
/// [`PausableError::ExpectedPause`] is thrown.
///
/// no authorization is required for this function.
pub fn when_paused(e: &Env) {
if !paused(e) {
panic_with_error!(e, PausableError::ExpectedPause)
Expand Down
Loading