Skip to main content
Version: v2.3.0

PSP22 Pausable

This example shows how you can implement a PSP22 contract with a Pausable extension. See an example of PSP22Pausable implementation.

First, you should implement basic version of PSP22.

Step 1: Import default implementation

With default Cargo.toml, you need to import the psp22 and pausable modules, enable corresponding features, and embed modules data structures as described in that section.

The main trait is PSP22 and Pausable.

Step 2: Inherit logic and apply when_not_paused modifier

Inherit the implementation of the PSP22 and Pausable traits. You can customize (override) methods in this impl block. We will apply the when_not_paused modifier for the transfer.

impl PSP22 for Contract {}

impl Transfer for Contract {
/// Return `Paused` error if the token is paused
#[modifiers(when_not_paused)]
fn _before_token_transfer(
&mut self,
_from: Option<&AccountId>,
_to: Option<&AccountId>,
_amount: &Balance,
) -> Result<(), PSP22Error> {
// TODO logic for before token transfer
Ok(())
}
}

impl Pausable for Contract {}

Step 3: Define constructor

Define constructor and add contract functions for pausing and unpausing the contract.

impl Contract {
#[ink(constructor)]
pub fn new(total_supply: Balance) -> Self {
ink_lang::codegen::initialize_contract(|instance: &mut Self| {
assert!(instance._mint_to(Self::env().caller(), total_supply).is_ok());
})
}
}

Step 4: Customize your contract with Pausable logic

Add the change_state function that allow switch pause state.

impl Contract {
...

/// Function which changes state to unpaused if paused and vice versa
#[ink(message)]
pub fn change_state(&mut self) -> Result<(), PSP22Error> {
if self.paused() {
self._unpause()
} else {
self._pause()
}
}
}

Final code:

#![cfg_attr(not(feature = "std"), no_std)]
#![feature(min_specialization)]

#[openbrush::contract]
pub mod my_psp22_pausable {
use ink_storage::traits::SpreadAllocate;
use openbrush::{
contracts::{
pausable::*,
psp22::*,
},
modifiers,
traits::Storage,
};

#[ink(storage)]
#[derive(Default, SpreadAllocate, Storage)]
pub struct Contract {
#[storage_field]
psp22: psp22::Data,
#[storage_field]
pause: pausable::Data,
}

impl PSP22 for Contract {}

impl Transfer for Contract {
/// Return `Paused` error if the token is paused
#[modifiers(when_not_paused)]
fn _before_token_transfer(
&mut self,
_from: Option<&AccountId>,
_to: Option<&AccountId>,
_amount: &Balance,
) -> Result<(), PSP22Error> {
// TODO logic for before token transfer
Ok(())
}
}

impl Pausable for Contract {}

impl Contract {
#[ink(constructor)]
pub fn new(total_supply: Balance) -> Self {
ink_lang::codegen::initialize_contract(|instance: &mut Self| {
assert!(instance._mint_to(Self::env().caller(), total_supply).is_ok());
})
}

/// Function which changes state to unpaused if paused and vice versa
#[ink(message)]
pub fn change_state(&mut self) -> Result<(), PSP22Error> {
if self.paused() {
self._unpause()
} else {
self._pause()
}
}
}
}

You can check an implementation example of PSP22 Pausable.

You can also check the documentation for the basic implementation of PSP22.