Skip to main content

PSP22 Capped

This example shows how you can implement a PSP22 contract with a supply cap, analogue to ERC20Capped.

Step 1: Include dependencies#

Include brush as dependency in the cargo file or you can use default Cargo.toml template. After you need to enable default implementation of PSP22 via brush features.

brush = { tag = "v1.6.1", git = "https://github.com/Supercolony-net/openbrush-contracts", default-features = false, features = ["psp22"] }

Step 2: Add imports and enable unstable feature#

Use brush::contract macro instead of ink::contract. Import everything from brush::contracts::psp22.

#![cfg_attr(not(feature = "std"), no_std)]#![feature(min_specialization)]
#[brush::contract]pub mod my_psp22_capped {    use brush::contracts::psp22::*;    use ink_prelude::string::String;    use ink_storage::traits::SpreadAllocate;...

Step 3: Define storage#

Declare the storage struct and the field related to the PSP22Storage trait, derive the PSP22Storage trait and mark the corresponding field with the #[PSP22StorageField] attribute. Also add the storage variable for cap.

#[ink(storage)]#[derive(Default, SpreadAllocate, PSP22Storage)]pub struct MyPSP22Capped {    #[PSP22StorageField]    psp22: PSP22Data,    cap: Balance,}

Step 4: Define constructor and contract functions#

Define constructor, inherit PSP22, and override the basic functions for capped implementation. Your PSP22Capped contract is ready!

impl PSP22 for MyPSP22Capped {}
impl MyPSP22Capped {    /// Constructor which mints `initial_supply` of the token to sender    /// Will set the token's cap to `cap`    #[ink(constructor)]    pub fn new(inital_supply: Balance, cap: Balance) -> Self {        ink_lang::codegen::initialize_contract(|instance: &mut Self| {            assert!(instance.init_cap(cap).is_ok());            assert!(instance._mint(instance.env().caller(), inital_supply).is_ok());        })    }
    /// Expose the `_mint` function    #[ink(message)]    pub fn mint(&mut self, account: AccountId, amount: Balance) -> Result<(), PSP22Error> {        self._mint(account, amount)    }
    #[ink(message)]    /// Returns the token's cap    pub fn cap(&self) -> Balance {        self.cap    }
    /// Overrides the `_mint` function to check for cap overflow before minting tokens    /// Performs `PSP22::_mint` after the check succeeds    fn _mint(&mut self, account: AccountId, amount: Balance) -> Result<(), PSP22Error> {        if (self.total_supply() + amount) > self.cap() {            return Err(PSP22Error::Custom(String::from("Cap exceeded")))        }        PSP22Internal::_mint(self, account, amount)    }
    /// Initializes the token's cap    fn init_cap(&mut self, cap: Balance) -> Result<(), PSP22Error> {        if cap <= 0 {            return Err(PSP22Error::Custom(String::from("Cap must be above 0")))        }        self.cap = cap;        Ok(())    }}

You can check an implementation example of PSP22 Capped.

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