github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/grc/grc721/grc721_royalty.gno (about)

     1  package grc721
     2  
     3  import (
     4  	"std"
     5  
     6  	"gno.land/p/demo/avl"
     7  )
     8  
     9  // royaltyNFT represents a non-fungible token (NFT) with royalty functionality.
    10  type royaltyNFT struct {
    11  	*metadataNFT                   // Embedding metadataNFT for NFT functionality
    12  	tokenRoyaltyInfo     *avl.Tree // AVL tree to store royalty information for each token
    13  	maxRoyaltyPercentage uint64    // maxRoyaltyPercentage represents the maximum royalty percentage that can be charged every sale
    14  }
    15  
    16  // Ensure that royaltyNFT implements the IGRC2981 interface.
    17  var _ IGRC2981 = (*royaltyNFT)(nil)
    18  
    19  // NewNFTWithRoyalty creates a new royalty NFT with the specified name, symbol, and royalty calculator.
    20  func NewNFTWithRoyalty(name string, symbol string) *royaltyNFT {
    21  	// Create a new NFT with metadata
    22  	nft := NewNFTWithMetadata(name, symbol)
    23  
    24  	return &royaltyNFT{
    25  		metadataNFT:          nft,
    26  		tokenRoyaltyInfo:     avl.NewTree(),
    27  		maxRoyaltyPercentage: 100,
    28  	}
    29  }
    30  
    31  // SetTokenRoyalty sets the royalty information for a specific token ID.
    32  func (r *royaltyNFT) SetTokenRoyalty(tid TokenID, royaltyInfo RoyaltyInfo) error {
    33  	// Validate the payment address
    34  	if err := isValidAddress(royaltyInfo.PaymentAddress); err != nil {
    35  		return ErrInvalidRoyaltyPaymentAddress
    36  	}
    37  
    38  	// Check if royalty percentage exceeds maxRoyaltyPercentage
    39  	if royaltyInfo.Percentage > r.maxRoyaltyPercentage {
    40  		return ErrInvalidRoyaltyPercentage
    41  	}
    42  
    43  	// Check if the caller is the owner of the token
    44  	owner, err := r.metadataNFT.OwnerOf(tid)
    45  	if err != nil {
    46  		return err
    47  	}
    48  	caller := std.PrevRealm().Addr()
    49  	if caller != owner {
    50  		return ErrCallerIsNotOwner
    51  	}
    52  
    53  	// Set royalty information for the token
    54  	r.tokenRoyaltyInfo.Set(string(tid), royaltyInfo)
    55  
    56  	return nil
    57  }
    58  
    59  // RoyaltyInfo returns the royalty information for the given token ID and sale price.
    60  func (r *royaltyNFT) RoyaltyInfo(tid TokenID, salePrice uint64) (std.Address, uint64, error) {
    61  	// Retrieve royalty information for the token
    62  	val, found := r.tokenRoyaltyInfo.Get(string(tid))
    63  	if !found {
    64  		return "", 0, ErrInvalidTokenId
    65  	}
    66  
    67  	royaltyInfo := val.(RoyaltyInfo)
    68  
    69  	// Calculate royalty amount
    70  	royaltyAmount, _ := r.calculateRoyaltyAmount(salePrice, royaltyInfo.Percentage)
    71  
    72  	return royaltyInfo.PaymentAddress, royaltyAmount, nil
    73  }
    74  
    75  func (r *royaltyNFT) calculateRoyaltyAmount(salePrice, percentage uint64) (uint64, error) {
    76  	royaltyAmount := (salePrice * percentage) / 100
    77  	return royaltyAmount, nil
    78  }