#[trait_definition]
Expand description

Defines extensible trait in the scope of brush::contract. It is a common rust trait, so you can use any features of rust inside of this trait. If this trait contains some methods marked with #[ink(message)] or #[ink(constructor)] attributes, this macro will extract these attributes and will put them into a separate trait (the separate trait only is used to call methods from the original trait), but the macro will not touch methods.

This macro stores definition of the trait in a temporary file during build process. Based on this definition #[brush::contract] will generate implementation of additional traits.

** Note ** The name of the trait defined via this macro must be unique for the whole project. ** Note ** You can’t use aliases, generics, and other rust’s stuff in signatures of ink!’s methods.

Example: Definition

mod doc {
use ink_prelude::collections::BTreeMap;
use brush::traits::{AccountId, Balance, InkStorage};

#[derive(Default, Debug)]
pub struct Data {
    pub balances: BTreeMap<AccountId, Balance>,
}

#[brush::trait_definition]
pub trait PSP22Storage: InkStorage {
    fn get(&self) -> &Data;
    fn get_mut(&mut self) -> &mut Data;
}

#[brush::trait_definition]
pub trait PSP22: PSP22Storage {
    /// Returns the account Balance for the specified `owner`.
    #[ink(message)]
    fn balance_of(&self, owner: AccountId) -> Balance {
        self.get().balances.get(&owner).copied().unwrap_or(0)
    }

    /// Transfers `value` amount of tokens from the caller's account to account `to`.
    #[ink(message)]
    fn transfer(&mut self, to: AccountId, value: Balance) {
        self._transfer_from_to(to, to, value)
    }

    fn _transfer_from_to(&mut self, from: AccountId, to: AccountId, amount: Balance) {
        let from_balance = self.balance_of(from);
        assert!(from_balance >= amount, "InsufficientBalance");
        self.get_mut().balances.insert(from, from_balance - amount);
        let to_balance = self.balance_of(to);
        self.get_mut().balances.insert(to, to_balance + amount);
    }
}
}

Example: Implementation

It uses storage trait from above.

#[brush::contract]
mod base_psp22 {
    use ink_prelude::collections::BTreeMap;
    use brush::traits::InkStorage;
    use ink_storage::traits::StorageLayout;
    use ink_storage::traits::SpreadLayout;

    #[derive(Default, Debug, SpreadLayout)]
    #[cfg_attr(feature = "std", derive(scale_info::TypeInfo, StorageLayout))]
    pub struct Data {
        pub supply: Balance,
        pub balances: BTreeMap<AccountId, Balance>,
        pub allowances: BTreeMap<(AccountId, AccountId), Balance>,
    }

    #[brush::trait_definition]
    pub trait PSP22ExampleStorage: InkStorage {
        fn get(&self) -> &Data;
        fn get_mut(&mut self) -> &mut Data;
    }

    #[brush::trait_definition]
    pub trait PSP22Example: PSP22ExampleStorage {
        /// Returns the account Balance for the specified `owner`.
        #[ink(message)]
        fn balance_of(&self, owner: AccountId) -> Balance {
            self.get().balances.get(&owner).copied().unwrap_or(0)
        }

        /// Transfers `value` amount of tokens from the caller's account to account `to`.
        #[ink(message)]
        fn transfer(&mut self, to: AccountId, value: Balance) {
            let from = Self::env().caller();
            self._transfer_from_to(from, to, value)
        }

        fn _transfer_from_to(&mut self, from: AccountId, to: AccountId, amount: Balance) {
            let from_balance = self.balance_of(from);
            assert!(from_balance >= amount, "InsufficientBalance");
            self.get_mut().balances.insert(from, from_balance - amount);
            let to_balance = self.balance_of(to);
            self.get_mut().balances.insert(to, to_balance + amount);
        }
    }

    #[ink(storage)]
    #[derive(Default)]
    pub struct PSP22Struct {
        example: Data,
        hated_account: AccountId,
    }

    impl PSP22ExampleStorage for PSP22Struct {
        fn get(&self) -> &Data {
            &self.example
        }

        fn get_mut(&mut self) -> &mut Data {
            &mut self.example
        }
    }

    impl PSP22Example for PSP22Struct {
        // Let's override method to reject transactions to bad account
        fn _transfer_from_to(&mut self, from: AccountId, to: AccountId, amount: Balance) {
            assert!(to != self.hated_account, "I hate this account!");

            let from_balance = self.balance_of(from);
            assert!(from_balance >= amount, "InsufficientBalance");
            self.get_mut().balances.insert(from, from_balance - amount);
            let to_balance = self.balance_of(to);
            self.get_mut().balances.insert(to, to_balance + amount);
        }
    }

    impl PSP22Struct {
        #[ink(constructor)]
        pub fn new(hated_account: AccountId) -> Self {
            let mut instance = Self::default();
            instance.hated_account = hated_account;
            instance
        }
    }
}