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