6

Hello all developers and community members, I am very new to Substrate and Rust.

I am creating a pallet for NFT marketplace.

for storing out the NFT details I've created a struct as mentioned below.

pub struct NFTStruct<T: Config> {
        pub dna: [u8; 16],   // Using 16 bytes to represent a NFT DNA
        pub price: Option<BalanceOf<T>>,
        pub gender: Gender,
        pub owner: AccountOf<T>,
        pub creator: AccountOf<T>,
        pub royalty: Option<BalanceOf<T>>,
    }

I have two fields here 1) price 2) royalty.

I am able to set the price of nft using set_price function , and royalty using set_creator_royalty function . upto this things are working fine.

Now I have a challenge, whenever user wants to buy NFT he can buy using buy_nft function which I have defined inside my pallet.

        // buy_nft
        #[transactional]
        #[pallet::weight(100)]
        pub fn buy_nft(
            origin: OriginFor<T>,
            nft_id: T::Hash,
            bid_price: BalanceOf<T>
        ) -> DispatchResult {
            let buyer = ensure_signed(origin)?;
    
            // Check the nft exists and buyer is not the current nft owner
            let nft = Self::nfts(&nft_id).ok_or(<Error<T>>::NFTNotExist)?;
            ensure!(nft.owner != buyer, <Error<T>>::BuyerIsNFTOwner);
            
            //Check if the nft is for sale.
            // Check the nft is for sale and the nft ask price <= bid_price
            if let Some(ask_price) = nft.price {
                ensure!(ask_price <= bid_price, <Error<T>>::NFTBidPriceTooLow);
            } else {
                Err(<Error<T>>::NFTNotForSale)?;
            }
            // Check the buyer has enough free balance
            ensure!(T::Currency::free_balance(&buyer) >= bid_price, <Error<T>>::NotEnoughBalance);

            // Verify the buyer has the capacity to receive one more nft
            let to_owned = <NFTsOwned<T>>::get(&buyer);
            ensure!((to_owned.len() as u32) < T::MaxNFTsOwned::get(), <Error<T>>::ExceedMaxNFTOwned);
            let seller = nft.owner.clone();
        
            //Transfer the amount from buyer to seller
            T::Currency::transfer(&buyer, &seller, bid_price, ExistenceRequirement::KeepAlive)?;
            // Transfer the nft from seller to buyer
            Self::transfer_nft_to(&nft_id, &buyer)?;

            // Deposit relevant Event
            Self::deposit_event(Event::Bought(buyer, seller, nft_id, bid_price));
    
            Ok(())
        }

but in this function I want to make changes for royalty_split , I mean, whenever user tends to buy NFT at the price which owner has set and the royalty in percent which creator set using set_creator_royalty function should be spitted from the actual price and should be transferred to creator's address and the rest should be transferred to the owner's address.

For ex-

nft with hash 0x11c5g5 has the price of 100 and the royalty is 10%. user came to buy_nft, he made a payment of 100 Tokens, 90 Tokens should be transferred to owner's wallet and 10 Tokens should be transferred to creator's wallet.

Approaches I tried

1

Inside the buy_nft function, I tried multiplying nft.price and nft.royalty both are of same type Option<BalanceOf>. And divide it with 100 to get the percentages/share of creator


            let nft_price = nft.price;
            let creator_royalty = nft.royalty;
            let creator_share_percent = nft_price * creator_royalty /100;

I got this errror

cannot multiply `std::option::Option<<<T as pallet::Config>::Currency as frame_support::traits::Currency<<T as frame_system::Config>::AccountId>>::Balance>` by `std::option::Option<<<T as pallet::Config>::Currency as frame_support::traits::Currency<<T as frame_system::Config>::AccountId>>::Balance>`

2

I have tried to solve it with different approaches as well, I thought I should convert/typecast both of these values to U64 (Rust primitive type).

For it I used a function

        //function to  convert balance to u64
        pub fn balance_to_u64(input: BalanceOf<T>) -> Option<u64> {
            TryInto::<u64>::try_into(input).ok()
        }

But the issue is, the function balance_to_u64 only takes BalanceOf<T>> as an argument and my type is Option<BalanceOf<T>>.

If I try to pass nft.price or nft.royalty as a parameter inside balance_to_u64 function I got this error.

mismatched types

expected associated type, found enum `std::option::Option`

note: expected associated type `<<T as pallet::Config>::Currency as frame_support::traits::Currency<<T as frame_system::Config>::AccountId>>::Balance`
                    found enum `std::option::Option<<<T as pallet::Config>::Currency as frame_support::traits::Currency<<T as frame_system::Config>::AccountId>>::Balance>`
help: consider constraining the associated type `<<T as pallet::Config>::Currency as frame_support::traits::Currency<<T as frame_system::Config>::AccountId>>::Balance` to `std::option::Option<<<T as pallet::Config>::Currency as frame_support::traits::Currency<<T as frame_system::Config>::AccountId>>::Balance>`
note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

I have spent around 1 week to solve this problem but unfortunately I got no solution. I am totally frustrated and looking for some help from any of the senior person.

If you have any solution or any suggestion for me, please help me out.

Thank you

2
  • 1
    Hi, could I ask why you're using an option for the royalties? Does this mean that the royalties might not be set on nfts? Wouldn't it be better to either have a fixed or default to zero? That way you can avoid the whole option situation
    – islami00
    Mar 31, 2022 at 11:07
  • Hi Yes depends on creator weather he wants to set royalty for his NFT or not, that's why I used Option here. I don't know if there is any better approach to solve this problem. As I am very new to Substrate. Thank you for your response. Mar 31, 2022 at 18:43

1 Answer 1

5
let creator_share_percent = nft.royalty.map(|creator_roality| {
    nft.price.unwrap_or_default() * creator_roality /100
});

But be aware that creator_share_percent is again an Option. So, you need to handle it as Option as well. You will then probably do something like:

if let Some(creator_share_percent) = creator_share_percent {
    // pay the creator share.
}
6
  • Thank you for your response, But I am still facing errors. Mar 31, 2022 at 13:15
  • mismatched types expected associated type, found integer note: expected associated type <<T as pallet::Config>::Currency as frame_support::traits::Currency<<T as frame_system::Config>::AccountId>>::Balance found type {integer} help: consider constraining the associated type <<T as pallet::Config>::Currency as frame_support::traits::Currency<<T as frame_system::Config>::AccountId>>::Balance to {integer} note: for more information, visit doc.rust-lang.org/book/ch19-03-advanced-traits.html Mar 31, 2022 at 13:17
  • This is the error I got as I used your code. 0 let creator_share_percent = nft.royalty.map(|creator_roality| { nft.price.unwrap_or_default() * creator_roality /100 }); Mar 31, 2022 at 13:17
  • I think it's due the the number 100 which we are dividing. Mar 31, 2022 at 13:18
  • 1
    Ahh yeah sorry, just write 100u32.into().
    – bkchr
    Mar 31, 2022 at 16:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.