Openbrush Wizard
Use the Wizard to generate generic PSP34 code
To create a smart contract which follows PSP34 standard use Openbrush Wizard:
- Open Openbrush.io website and go to bottom of the page.
- Select PSP34.
- Select the version to match the rest of the tutorial. Check What will be used in the opening chapter.
- Name your contract. In this tutorial we will use
Shiden34
. - Add your symbol name. In this tutorial we will use
SH34
. - Select extensions: Metadata, Mintable, Enumerable.
- Under Security pick Ownable.
- Copy
lib.rs
andCargo.toml
.
At the time of writing this tutorial, Openbrush wizard does not properly generate contract. Use code from this tutorial.
Your lib.rs
file should look like this:
#![cfg_attr(not(feature = "std"), no_std, no_main)]
#[openbrush::implementation(PSP34, Ownable, PSP34Enumerable, PSP34Metadata, PSP34Mintable)]
#[openbrush::contract]
pub mod shiden34 {
use openbrush::traits::Storage;
#[ink(storage)]
#[derive(Default, Storage)]
pub struct Shiden34 {
#[storage_field]
psp34: psp34::Data,
#[storage_field]
ownable: ownable::Data,
#[storage_field]
metadata: metadata::Data,
#[storage_field]
enumerable: enumerable::Data,
}
#[overrider(PSP34Mintable)]
#[openbrush::modifiers(only_owner)]
fn mint(&mut self, account: AccountId, id: Id) -> Result<(), PSP34Error> {
psp34::InternalImpl::_mint_to(self, account, id)
}
impl Shiden34 {
#[ink(constructor)]
pub fn new() -> Self {
let mut _instance = Self::default();
ownable::Internal::_init_with_owner(&mut _instance, Self::env().caller());
psp34::Internal::_mint_to(&mut _instance, Self::env().caller(), Id::U8(1))
.expect("Can mint");
let collection_id = psp34::PSP34Impl::collection_id(&_instance);
metadata::Internal::_set_attribute(
&mut _instance,
collection_id.clone(),
String::from("name"),
String::from("Shiden34"),
);
metadata::Internal::_set_attribute(
&mut _instance,
collection_id,
String::from("symbol"),
String::from("SH34"),
);
_instance
}
}
}
Your Cargo.toml
should now look like this:
[package]
name = "shiden34"
version = "3.1.0"
authors = ["Astar builder"]
edition = "2021"
[dependencies]
ink = { version = "4.2.1", default-features = false }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true }
openbrush = { tag = "4.0.0-beta", git = "https://github.com/Brushfam/openbrush-contracts", default-features = false, features = ["psp34", "ownable"] }
[lib]
path = "lib.rs"
[features]
default = ["std"]
std = [
"ink/std",
"scale/std",
"scale-info/std",
"openbrush/std",
]
ink-as-dependency = []
Make the folder structure or use Swanky-cli
like this:
.
└── contracts
└── shiden34
├── Cargo.toml
└── lib.rs
Add another Cargo.toml
with workspace definition to your project's root folder:
[workspace]
members = [
"contracts/**",
]
exclude = [
]
And your folder structure will look like:
.
├── Cargo.toml
└── contracts
└── shiden34
├── Cargo.toml
└── lib.rs
You are now ready to check if all is set. Run in root project folder:
cargo check
Examine Openbrush Traits
Let's examine what we have inside module shiden34
(lib.rs) so far:
- Defined structure
Shiden34
for contract storage. - Implemented constructor
new()
forShiden34
structure. - Implemented Openbrush traits PSP34, PSP34Metadata, PSP34Mintable, PSP34Enumberable, Ownable for structure
Shiden34
. - Overridden
mint()
method from trait PSP34Mintable. More about this in next section.
Each of implemented traits will enrich shiden34
contract with a set of methods. To examine which methods you now have available check:
- Openbrush PSP34 trait brings all familiar functions from ERC721 plus a few extra:
collection_id()
balance_of()
owner_of()
allowance()
approve()
transfer()
total_supply()
- Openbrush Metadata
get_attribute()
- Openbrush Mintable
mint()
- Openbrush Enumerable
owners_token_by_index()
token_by_index()
- Openbrush Ownable
renounceOwnership ()
transferOwnership()
owner()
Major differences when compared with ERC721 are:
Metadata
trait brings possibility to define numerous attributesPSP34
trait brings collection_id() which can be used or ignored in contracts
We could have used Burnable
trait as well but for simplicity it is skipped in this tutorial since burning can be performed by sending a token to address 0x00.
After this step your code should look like this.
Build, Deploy and Interact with the Contract
Build your contract:
cd contracts/shiden34
cargo contract build --release
Use shiden34.contract target to deploy contract. The file is located in this folder:
ls target/ink/shiden34/
To deploy your contract using the Polkadot.js apps portal, follow the previous guide, or use the contracts-ui.
You can start interacting with your contract. You will notice that one token is already minted. This is due to the mint()
call in the contract's constructor new()
.
- Try minting another token by calling
mint()
. - Read the token
ownerOf()
for your newly minted token. - Check that
totalSupply()
has increased.