git.delta.rocks / unique-network / refs/commits / 390a1544bccf

difftreelog

feat burn_from

Yaroslav Bolyukin2021-10-06parent: #6c4c550.patch.diff
in: master

1 file changed

modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
987 /// * item_id: ID of NFT to burn.987 /// * item_id: ID of NFT to burn.
988 #[weight = <SelfWeightOf<T>>::burn_item()]988 #[weight = <SelfWeightOf<T>>::burn_item()]
989 #[transactional]989 #[transactional]
990 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, item_owner: T::CrossAccountId, value: u128) -> DispatchResult {990 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {
991
992 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
993 let target_collection = Self::get_collection(collection_id)?;
994
995 Self::burn_item_internal(&sender, &target_collection, item_id, value, true)?;
996
997 target_collection.submit_logs()
998 }
999
1000 /// Destroys a concrete instance of NFT on behalf of the owner
1001 /// See also: [`approve`]
1002 ///
1003 /// # Permissions
1004 ///
1005 /// * Collection Owner.
1006 /// * Collection Admin.
1007 /// * Current NFT Owner.
1008 ///
1009 /// # Arguments
1010 ///
1011 /// * collection_id: ID of the collection.
1012 ///
1013 /// * item_id: ID of NFT to burn.
1014 ///
1015 /// * from: owner of item
1016 #[weight = <SelfWeightOf<T>>::burn_item()]
1017 #[transactional]
1018 pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResult {
9911019
992 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1020 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
993 let target_collection = Self::get_collection(collection_id)?;1021 let target_collection = Self::get_collection(collection_id)?;
9941022
995 Self::burn_item_internal(&sender, &target_collection, item_id, &item_owner, value)?;1023 Self::burn_from_internal(&sender, &target_collection, &from, item_id, value)?;
9961024
997 target_collection.submit_logs()1025 target_collection.submit_logs()
998 }1026 }
1593 }1621 }
15941622
1595 pub fn burn_item_internal(1623 pub fn burn_item_internal(
1596 sender: &T::CrossAccountId,1624 owner: &T::CrossAccountId,
1597 collection: &CollectionHandle<T>,1625 collection: &CollectionHandle<T>,
1598 item_id: TokenId,1626 item_id: TokenId,
1599 item_owner: &T::CrossAccountId,1627 value: u128,
1600 value: u128,1628 allow_escalation: bool,
1601 ) -> DispatchResult {1629 ) -> DispatchResult {
1602 ensure!(1630 ensure!(
1603 Self::is_item_owner(sender, collection, item_id)?1631 Self::is_item_owner(owner, collection, item_id)?
1604 || (collection.limits.owner_can_transfer1632 || (allow_escalation
1633 && collection.limits.owner_can_transfer
1605 && Self::is_owner_or_admin_permissions(collection, sender)?),1634 && Self::is_owner_or_admin_permissions(collection, owner)?),
1606 Error::<T>::NoPermission1635 Error::<T>::NoPermission
1607 );1636 );
16081637
1609 if collection.access == AccessMode::WhiteList {1638 if collection.access == AccessMode::WhiteList {
1610 Self::check_white_list(collection, sender)?;1639 Self::check_white_list(collection, owner)?;
1611 }1640 }
16121641
1613 match collection.mode {1642 match collection.mode {
1617 _ => fail!(<Error<T>>::TokenValueTooLow),1646 _ => fail!(<Error<T>>::TokenValueTooLow),
1618 },1647 },
1619 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection, owner, value)?,1648 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection, owner, value)?,
1620 CollectionMode::ReFungible => Self::burn_refungible_item(collection, item_id, owner, value)?,1649 CollectionMode::ReFungible => {
1650 Self::burn_refungible_item(collection, item_id, owner, value)?
1651 }
1621 _ => (),1652 _ => (),
1622 };1653 };
16231654
1624 Ok(())1655 Ok(())
1625 }1656 }
1657
1658 pub fn burn_from_internal(
1659 sender: &T::CrossAccountId,
1660 collection: &CollectionHandle<T>,
1661 from: &T::CrossAccountId,
1662 item_id: TokenId,
1663 amount: u128,
1664 ) -> DispatchResult {
1665 if sender == from {
1666 // Transfer by `from`, because it is either equal to sender, or derived from him
1667 return Self::burn_item_internal(from, collection, item_id, amount, true);
1668 }
1669
1670 // Check approval
1671 collection.consume_sload()?;
1672 let approval: u128 =
1673 <Allowances<T>>::get(collection.id, (item_id, from.as_sub(), sender.as_sub()));
1674
1675 // Transfer permissions check
1676 ensure!(
1677 approval >= amount
1678 || (collection.limits.owner_can_transfer
1679 && Self::is_owner_or_admin_permissions(collection, sender)?),
1680 Error::<T>::NoPermission
1681 );
1682
1683 if collection.access == AccessMode::WhiteList {
1684 Self::check_white_list(collection, sender)?;
1685 }
1686
1687 // Reduce approval by transferred amount or remove if remaining approval drops to 0
1688 let allowance = approval.saturating_sub(amount);
1689 collection.consume_sstore()?;
1690 if allowance > 0 {
1691 <Allowances<T>>::insert(
1692 collection.id,
1693 (item_id, from.as_sub(), sender.as_sub()),
1694 allowance,
1695 );
1696 } else {
1697 <Allowances<T>>::remove(collection.id, (item_id, from.as_sub(), sender.as_sub()));
1698 }
1699
1700 // Escalation is disallowed here, because we need to be sure that passed owner is real
1701 Self::burn_item_internal(from, collection, item_id, amount, false)?;
1702
1703 if matches!(collection.mode, CollectionMode::Fungible(_)) {
1704 collection.log(ERC20Events::Approval {
1705 owner: *from.as_eth(),
1706 spender: *sender.as_eth(),
1707 value: allowance.into(),
1708 })?;
1709 }
1710
1711 Ok(())
1712 }
16261713
1627 pub fn toggle_white_list_internal(1714 pub fn toggle_white_list_internal(
1628 sender: &T::CrossAccountId,1715 sender: &T::CrossAccountId,