feat(nfts): add CollectionApprovals and AccountBalance storages, and general improvements#387
feat(nfts): add CollectionApprovals and AccountBalance storages, and general improvements#387chungquantin merged 104 commits intomainfrom
CollectionApprovals and AccountBalance storages, and general improvements#387Conversation
…fts' into chungquantin/feat-nfts
Codecov ReportAttention: Patch coverage is
@@ Coverage Diff @@
## main #387 +/- ##
==========================================
+ Coverage 68.41% 71.39% +2.97%
==========================================
Files 70 72 +2
Lines 11838 13520 +1682
Branches 11838 13520 +1682
==========================================
+ Hits 8099 9652 +1553
- Misses 3482 3595 +113
- Partials 257 273 +16
|
There was a problem hiding this comment.
Great progress but there are things that need more consideration. As for the comments that need discussion and decision making, please lead this effort. I would advise to tackle them one by one, separately, so that it is easiest for other team members to understand the problem. What is always hugely helpful is to research yourself and find all the possible solutions. Then provide the best solutions to the team to make a decision as effective as possible.
Besides my comments in the code you also have to reconsider the destroy process. Right now we are removing the AccountBalance and Allowances when destroying the collection. This should be done earlier in the burning process. One potential solution which you'd have to research more is burning is only possible when there is no allowance set for the item. As for the account balance, this should already be 0 as all the items should already be burned before destroying the collection. Note the changes you made for the curious implementation, if my suggestion is correct these have to be removed again.
Moreover, we might want to consider to change the destroy process like done in pallet assets. This needs discussion and decision making with the team as well.
Finally, I would really appreciate if we could separate this PR in three PRs:
- AccountBalance
- Allowances
- destroy
This will be much more effective. Another thing to look for; there are a lot of clippy warnings which has to be resolved.
Why do I think we should not go with the implementation of |
Co-authored-by: chungquantin <56880684+chungquantin@users.noreply.github.com>
peterwht
left a comment
There was a problem hiding this comment.
Amazing work! Very clean, and I can definitely see how this will be better for smart contract devs.
One thing I noted (likely already known), but this applies to both PSP-34 and ERC-721. So, upstreaming this change will be useful to us and to Plaza.
I have not reviewed tests or benchmarks yet.
I have left various comments for improvements. The biggest concerns are:
- Force granting approval rights seems wrong. See comment for more details
- If we are not allowing collection destruction until all approvals have been cleared, then an
Adminaccount of the collection should be able to force clear as well.
Co-authored-by: Frank Bell <frank@r0gue.io> Co-authored-by: Daan van der Plas <93204684+Daanvdplas@users.noreply.github.com>
peterwht
left a comment
There was a problem hiding this comment.
Approving! Really great job with this.
Before merging, could you please just change the PR title to something like: "feat(nfts): add CollectionApprovals and AccountBalance storages, and general improvements"
Not a blocker, but if we are upstreaming to P-SDK, we could fix the outdated comment on the Admin role and change the name of the misleading test: cancel_approval_works_with_admin. Up to you if you make those changes though.
There was a problem hiding this comment.
I have found one little mistake which was already in the original pallet. The transfer benchmarking function should have a delegate as origin as it is the worst case scenario. This was already a mistake in the original pallet. Probably a parameter of whether or not the transfer is signed by a delegate is the best approach. The dest account should also pay for the deposit which is I think the case from looking at the result (there is the System::Account write + read, and the caller is whitelisted). Could we change line 306 in benchmarking.rs to:
T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance() + T::AccountBalance::get());
So that we are sure this is the case and also indicates that it is expected behaviour.
We might also want to rerun the benchmarks after the above change.
Other than that the PR is looking amazing!
Daanvdplas
left a comment
There was a problem hiding this comment.
Hell fucking yeah!!! Amazing work!
evilrobot-01
left a comment
There was a problem hiding this comment.
Have not re-reviewed, just approving to unblock based on approvals from Daan and Peter.
Edited: 09/12/2024
DESCRIPTION
This pull request introduces new storage items to the
pallet-nftsto optimize the performance for the use case of the Pop API contract library implementation.DESIGN DECISION
New configuration parameters
CollectionApprovalDeposit: The basic amount of funds that must be reserved for collection approvals.This is held for an additional storage item whose value size is
sizeof((Option<BlockNumber>, Balance))bytes and whose key size issizeof((CollectionId, AccountId, AccountId))bytes.CollectionApprovalDepositwill be reserved from the owner on collection approval creation. The same amount of reservedCollectionApprovalDepositwill be unreserved back to the owner on collection approval cancellation.New storage items and related changes
AccountBalance: Keep track of the total number of collection items an account has. This storage item needs to be updated on collection item transferred (fn do_transfer()), burnt (fn do_burn()) and minted (fn do_mint()).Explanation and implementation for the
AccountBalance's deposit can be found here: #413CollectionApprovals: Keep track of the collection approval status for a delegated account.Changes made to dispatchable functions
Introducing new dispatchable functions and update the pallet call indices of most of functions:
approve_collection_transfer: Approve collection items owned by the origin to be transferred by a delegated third-party account. This function reserves the required depositCollectionApprovalDepositfrom theoriginaccount.force_approve_collection_transfer: Force-approve collection items owned by the specifiedownerto be transferred by a delegated third-party account. This function reserves the required depositCollectionApprovalDepositfrom theoriginaccount.cancel_collection_approval: Cancel one of the collection approvals.force_cancel_collection_approval: Force-cancel one of the collection approvals granted by the specifiedowneraccount. Returning the reserved funds to thedelegate.clear_all_collection_approvals: Cancel all the collection approvals. Returning the reserved funds to thedelegate.force_clear_all_collection_approvals: Force-cancel all the collection approvals granted by the specifiedowneraccount. Returning the reserved funds to thedelegate.check_collection_approval
Checks whether the
delegatehas the necessary allowance to transfer items in thecollectionthat are owned by theaccount.check_approval
Checks whether the
delegatehas the necessary allowance to transfer items within the collection or a specific item in the collection. If thedelegatehas an approval to transfer all items in the collection that are owned by theaccount, they can transfer every item without requiring explicit approval for that item.Item = NoneItem = Somedo_approve_collection_transfer
Store the new approval with deadline. Approving a
delegateto transfer items owned by the signedoriginin the collection will reserve some deposit amount (configured viaT::CollectionApprovalDeposit) from theorigin. With the reserved deposit, we don't need to worry about the unbounded storage map and the depositor is incentivised to remove the collection approval to unblock the collection from destruction.do_cancel_collection_approval
Cancels the transfer of items in the collection that owned by the origin to a delegate. This method will remove the collection approval granted to a delegate and unreserve the deposited fund to the delegate.
do_clear_all_collection_approvals
This function is used to clear
limitcollection approvals for the collection items ofowner. After clearing all approvals, the deposit of each collection approval is returned to theowneraccount and theApprovalsCancelledevent is emitted.Weight of this method is calculated by the provided
limit.do_destroy_collection
To destroy a collection, all collection approvals must be removed first. Destroying a collection can only be called when there is no collection approval exists. If yes, requires the accounts that granted those collection approvals to remove all them first through new methods
clear_all_collection_approvalsorcancel_collection_approval. These methods unreserve the deposited funds back to theoriginon called.Introducing new error types
NoItemOwned: Account owns zero item in the collection.DelegateApprovalConflict: Collection approval and item approval conflicts.do_cancel_approval()if there is an existing collection approval with key(collection, account, delegate).do_clear_all_transfer_approvals()if there are collection approvals exist. All collection approvals must be removed first before the method can be called.CollectionApprovalsExist: There are collection approvals exist.do_destroy_collection()if there are collection approvals. All collection approvals must be removed first before the method can be called.