💨

[Astar]コントラクト備忘録20(AccessControlについて)

2023/03/01に公開

こちらの知見がたまったので、備忘録として残します。

1 概要

  1. AccessControlについて

2 内容

こちらのコントラクトを作成しました。

OpenBrushのexampleの中身に「Minter」を確認するための「get_minter」関数を追加しました。

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

#[openbrush::contract]
pub mod psp34 {
    use ink_storage::traits::SpreadAllocate;
    use openbrush::{
        contracts::{
            access_control::*,
            psp34::extensions::{
                burnable::*,
                mintable::*,
            },
        },
        modifiers,
        traits::Storage,
    };

    #[ink(storage)]
    #[derive(Default, SpreadAllocate, Storage)]
    pub struct Contract {
        #[storage_field]
        psp34: psp34::Data,
        #[storage_field]
        access: access_control::Data,
    }

    // You can manually set the number for the role.
    // But better to use a hash of the variable name.
    // It will generate a unique identifier of this role.
    // And will reduce the chance to have overlapping roles.
    const MINTER: RoleType = ink_lang::selector_id!("MINTER");

    impl Contract {
        #[ink(constructor)]
        pub fn new() -> Self {
            ink_lang::codegen::initialize_contract(|instance: &mut Self| {
                let caller = instance.env().caller();
                instance._init_with_admin(caller);
                // We grant minter role to caller in constructor, so he can mint/burn tokens
                instance.grant_role(MINTER, caller).expect("Should grant MINTER role");
            })
        }
        #[ink(message)]
        pub fn get_minter(&self) -> RoleType {
            MINTER
        }
    }

    impl PSP34 for Contract {}

    impl AccessControl for Contract {}

    impl PSP34Mintable for Contract {
        #[ink(message)]
        #[modifiers(only_role(MINTER))]
        fn mint(&mut self, account: AccountId, id: Id) -> Result<(), PSP34Error> {
            self._mint_to(account, id)
        }
    }

    impl PSP34Burnable for Contract {
        #[ink(message)]
        #[modifiers(only_role(MINTER))]
        fn burn(&mut self, account: AccountId, id: Id) -> Result<(), PSP34Error> {
            self._burn_from(account, id)
        }
    }
}

まずは、こちらのように、RoleType型の「MINTER」に対し、「MINTER」をハッシュ化したものを入れています。

「selector_id!」についてはこちらをご確認ください。


https://paritytech.github.io/ink/ink/macro.selector_id.html

また、こちらのように、「RoleType」はただの「u32」型であるということもわかりました。


https://github.dev/Supercolony-net/openbrush-contracts

そして、下のようにして、「grant_role」関数に「MINTER」を渡しています。

では、「grant_role」関数を見てみましょう。

その名の通り、ロール(役割)を与えます。

具体的には「members」というデータに対して、そのロールが付与されているのかを確認し、なければ、ロールを付与しています。


https://github.dev/Supercolony-net/openbrush-contracts

では、その「members」を見てみましょう。

whereの部分で「トレイトバウンド」を利用して、「members::MembersManagerトレイト」を実装していることを要求しています。

では「MembersManagerトレイト」を見てみましょう。

https://github.dev/Supercolony-net/openbrush-contracts

このように、「MembersManager」トレイトを確認すると、3つの関数が実装されていることが確認できます。

これがあるからこそ、「members」は「has_role」や「add」を使うことができたとわかりました。


https://github.dev/Supercolony-net/openbrush-contracts

では、実際のコードに戻りましょう。

「get_minter」関数は簡単に作ったものですが、これで、「MINTER」の値を確認できるようにしました。

では、実際に動かしてみましょう。

下のように、「get_minter」を使って、「MINTER」が「4,254,773,782」であることがわかりました。

そして、デプロイ時に、実行したウォレットに「MINTER」が付与されています。

そのため、「has_role」関数を使い、実行したウォレットに権限がついていることが確認できました。

一方、少し数字を変えて、「4,254,773,783」というロールの権限は付与していないので、下のように、「false」という結果が返ってきました。

その他、「test2」というウォレットには「MINTER」の権限を付与していないので、このように「false」となることが確認できました。

shibuya

bJz21JKwPDaNHtMN9KeQJQJxHWTHxYoaoWb3ux3wr1KnJEf

今回は以上です。

Discussion