Skip to main content
Version: 3.2.0

PSP22 Wrapper

This example shows how you can reuse the implementation of PSP22 token with PSP22 Wrapper extension, which allows you to wrap your PSP22 token in a PSP22Wrapper token which can be used for example for governance.

First, you should implement basic version of PSP22.

Step 1: Add imports and enable unstable feature

  • Use openbrush::contract macro instead of ink::contract.
  • Use openbrush::implementation macro to inherit implementations of PSP22 and PSP22Wrapper traits.
#![cfg_attr(not(feature = "std"), no_std, no_main)]

#[openbrush::implementation(PSP22, PSP22Wrapper)]
#[openbrush::contract]
pub mod my_psp22_wrapper {
...

Step 2: Define storage

Declare storage struct and declare the field related to the wrapper module data structure. Then you need to derive the Storage trait and mark the corresponding field with the #[storage_field] attribute. Deriving this trait allows you to reuse the PSP22Wrapper extension in your PSP22 implementation.

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

Step 3: Define constructor

Define constructor where you init address of wrapper fungible token(PSP22) and recover message.

impl Contract {
#[ink(constructor)]
pub fn new(token_address: AccountId) -> Self {
let mut instance = Self::default();

Internal::_init(&mut instance, token_address);

instance
}

/// Exposes the `_recover` function for message caller
#[ink(message)]
pub fn recover(&mut self) -> Result<Balance, PSP22Error> {
Internal::_recover(self, Self::env().caller())
}
}

Final code

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

#[openbrush::implementation(PSP22, PSP22Wrapper)]
#[openbrush::contract]
pub mod my_psp22_wrapper {
use openbrush::traits::Storage;

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

impl Contract {
#[ink(constructor)]
pub fn new(token_address: AccountId) -> Self {
let mut instance = Self::default();

Internal::_init(&mut instance, token_address);

instance
}

/// Exposes the `_recover` function for message caller
#[ink(message)]
pub fn recover(&mut self) -> Result<Balance, PSP22Error> {
Internal::_recover(self, Self::env().caller())
}
}
}

You can check an example of the usage of PSP22 Wrapper.