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