r0gue-io / pop-node

Pop Network makes it easy for smart contract developers to use the Power of Polkadot.
The Unlicense
24 stars 6 forks source link

feat: local non-fungible use cases #259

Closed chungquantin closed 1 month ago

chungquantin commented 2 months ago

Implement the non-fungible feature to pop-api to support interact with non-fungible tokens.

Basic Specification

PSP34Mintable Interface

WRITE API METHODS

/// Create a new non-fungible token to the collection.
mint(collection: CollectionId, item: ItemId, to: AccountId);

[!IMPORTANT]
Contract mints the collection item to the designated account

PSP34Burnable Interface

WRITE API METHODS

/// Destroy a new non-fungible token to the collection
burn(collection: CollectionId, item: ItemId);

[!IMPORTANT]
Only the owner of the collection item has the authority to destroy it

PSP34 Interface

Because PSP34 is a standard for a non-fungible token. We need to adjust it a bit to support collectable use cases:

READ API METHODS

// Returns the owner of a collection.
collection_owner(collection: CollectionId) ➔ Option<AccountId>;
// Returns the owner of an item.
owner_of(collection: CollectionId, item: ItemId) ➔ Option<AccountId>;
// Returns the total number of items in the collection owned by the account
balance_of(collection_id: CollectionId, owner: AccountId) ➔ u32;
// Whether an operator is allowed to transfer an item or items from owner.
allowance(owner: AccountId, operator: AccountId, id: Option) ➔ bool;
// Returns the details of an item.
item(collection: CollectionId, item: ItemId) -> Option<ItemDetail>;
// Returns the details of a collection.
collection(collection: CollectionId) -> Option<CollectionDetail>;
// Returns the total number of items in the collection
total_supply(collection: CollectionId) ➔ Balance;

[!WARNING]
Got a blocker because there is no method supported in the pallet-nfts to retrieve the approvals information of an item. One way is to fork the ItemDetail struct and encode on our own to retrieve the field approvals (this field is private in the pallet-nfts)

WRITE API METHODS

/// Delegate a permission to perform actions on the collection item to an account.
approve(collection: CollectionId, item: ItemId, spender: AccountId) -> Result;
/// Transfer a token from one account to the another account.
transfer(to: AccountId, collection: CollectionId, item: ItemId) -> Result;
/// Cancel one of the transfer approvals for a specific item.
cancel_approval(collection: CollectionId, item: ItemId, spender: AccountId) -> Result;

PSP34Metadata Interface

WRITE API METHODS

// Set the attribute of collection item with `value` for the given key `key`
set_attribute(collection: CollectionId, item: ItemId, key: [u8], value: [u8]) -> Result;

READ API METHODS

// Returns the attribute of collection item for the given `key`.
get_attribute(collection: CollectionId, item: ItemId, key: [u8]) ➔ Option<[u8]>;

PSP34Enumerable

READ API METHODS

// Returns a token `Id` owned by `owner` at a given `index` of its token list.
owners_token_by_index(owner: AccountId, index: u128) ➔ Option;
// Returns a token `Id` at a given `index` of all the tokens stored by the contract.
token_by_index(index: u128) -> Option;

Extensions

[Proposed] PSP34Admin

WRITE API METHODS

// Issue a new collection of non-fungible items from a public origin.
create(admin: AccountId, config: CollectionConfig) -> Result;
// Destroy a collection of fungible items.
destroy(collection: T::CollectionId) -> Result;

[!IMPORTANT]
Remove the witness data parameter and handle the witness date in the pallet logic instead.

[Proposed] PSP34Swappable

TBA

[Proposed] PSP34Ownanle

WRITE API METHODS

/// Transfer the ownership of the collection to the new owner. 
transfer_ownership(collection: CollectionId, spender: AccountId, owner: AccountId) -> Result;
chungquantin commented 1 month ago

My concerns for this specification is should we support collection (introduce in the trait crate non_fungible_v2)? IMO, we should because it has become the standard of the NFT space. PSP34 interface is a bit out-dated right now and it does not have the supported standard on the ink! side for the NFT collection manager contract.

If we agree to support collection creation / item management, we will need to make some adjustments to the specification of the PSP34. For collection item, we can follow PSP34, for collection we will come up with our own PSP34Collectable spec.

cc: @Daanvdplas @peterwht

peterwht commented 1 month ago

Please use the PSP34 spec from here: https://github.com/inkdevhub/standards/tree/master/PSPs (slightly more up-to-date)

peterwht commented 1 month ago

Here is also a good reference implementation: https://github.com/Cardinal-Cryptography/PSP34

(note, it is on ink! v4.3.0, so there are some improvements with ink! v5)

peterwht commented 1 month ago

I would remove the ERC-721 milestone for now. It can remain in the spec if you want, but I don't think we should prioritize its implementation.

We should have a base PSP34 that matches the PSP standard exactly. No extra functions (dispatch or read).

And then, the remaining functionality listed in Permissionless / Permissioned dispatchables should be an extension. For example, a PSP34Swappable, and PSP34Manager (for admin stuff), etc. etc.

peterwht commented 1 month ago

My concerns for this specification is should we support collection (introduce in the trait crate non_fungible_v2)? IMO, we should because it has become the standard of the NFT space. PSP34 interface is a bit out-dated right now and it does not have the supported standard on the ink! side for the NFT collection manager contract.

If we agree to support collection creation / item management, we will need to make some adjustments to the specification of the PSP34. For collection item, we can follow PSP34, for collection we will come up with our own PSP34Collectable spec.

cc: @Daanvdplas @peterwht

Yes, we should definitely support this.