Smart Contract

Resolver

A.b8ea91944fd51c43.Resolver

Valid From

131,135,557

Deployed

5d ago
Feb 21, 2026, 03:38:13 PM UTC

Dependents

32 imports
1import NonFungibleToken from 0x1d7e57aa55817448
2import MetadataViews from 0x1d7e57aa55817448
3import ViewResolver from 0x1d7e57aa55817448
4import TopShot from 0x0b2a3299cc857e29
5
6// Resolver
7//
8// Contract holds the Offer exchange resolution rules.
9//
10// When an Offer is created a ResolverType is included. The ResolverType is also
11// passed into checkOfferResolver() from the Offers contract on exchange validation
12access(all) contract Resolver {
13    // Current list of supported resolution rules.
14    access(all) enum ResolverType: UInt8 {
15        access(all) case NFT
16        access(all) case TopShotEdition
17        access(all) case MetadataViewsEditions
18        access(all) case EditionIdAndSerialNumberTraits
19    }
20
21    // Public resource interface that defines a method signature for checkOfferResolver
22    // which is used within the Resolver resource for offer acceptance validation
23    access(all) resource interface ResolverPublic {
24        access(all) fun checkOfferResolver(
25            item: &{NonFungibleToken.NFT},
26            offerParamsString: {String:String},
27            offerParamsUInt64: {String:UInt64},
28            offerParamsUFix64: {String:UFix64}
29        ): Bool
30    }
31
32
33    // Resolver resource holds the Offer exchange resolution rules.
34    access(all) resource OfferResolver: ResolverPublic {
35        // checkOfferResolver
36        // Holds the validation rules for resolver each type of supported ResolverType
37        // Function returns TRUE if the provided nft item passes the criteria for exchange
38        access(all) fun checkOfferResolver(
39            item: &{NonFungibleToken.NFT},
40            offerParamsString: {String:String},
41            offerParamsUInt64: {String:UInt64},
42            offerParamsUFix64: {String:UFix64}
43        ): Bool {
44            pre {
45                offerParamsString.containsKey("resolver"): "offerParamsString must contain key 'resolver'"
46            }
47            switch offerParamsString["resolver"]! {
48            case ResolverType.NFT.rawValue.toString():
49                return Resolver.resolveNFTType(item, offerParamsString)
50            case ResolverType.TopShotEdition.rawValue.toString():
51                return Resolver.resolveTopShotEditionType(item, offerParamsString)
52            case ResolverType.MetadataViewsEditions.rawValue.toString():
53                return Resolver.resolveMetadataViewsEditionsType(item, offerParamsString)
54            case ResolverType.EditionIdAndSerialNumberTraits.rawValue.toString():
55                return Resolver.resolveEditionIdAndSerialNumberTraitsType(item, offerParamsString)
56            default:
57                panic("Invalid Resolver on Offer: ".concat(offerParamsString["resolver"]!))
58            }
59        }
60    }
61
62    // Resolves an offer for NFT type
63    access(contract) fun resolveNFTType(_ item: &{NonFungibleToken.NFT}, _ offerParamsString: {String:String}): Bool {
64        assert(item.id.toString() == offerParamsString["nftId"], message: "item NFT does not have specified ID")
65        return true
66    }
67
68    // Resolves an offer for TopShotEdition type
69    access(contract) fun resolveTopShotEditionType(_ item: &{NonFungibleToken.NFT}, _ offerParamsString: {String:String}): Bool {
70        let view = item.resolveView(Type<TopShot.TopShotMomentMetadataView>())
71            ?? panic("NFT does not use TopShot.TopShotMomentMetadataView")
72        let metadata = view as! TopShot.TopShotMomentMetadataView
73
74        // Always validate set and play first
75        let setMatch = offerParamsString["setId"] == metadata.setID.toString()
76        let playMatch = offerParamsString["playId"] == metadata.playID.toString()
77
78        if !setMatch || !playMatch {
79            return false
80        }
81
82        // if present, check if subeditionId matches the NFT's subeditionId
83        if let offerSubeditionId = offerParamsString["subeditionId"] {
84            let subeditionID = TopShot.getMomentsSubedition(nftID: item.id) ?? 0
85            return subeditionID.toString() == offerSubeditionId
86        }
87
88        // if subeditionId is not present, return true (any subedition is accepted, not just base edition)
89        return true
90    }
91
92    // Resolves an offer for MetadataViewsEditions type
93    access(contract) fun resolveMetadataViewsEditionsType(_ item: &{NonFungibleToken.NFT}, _ offerParamsString: {String:String}): Bool {
94        let view = item.resolveView(Type<MetadataViews.Editions>())
95            ?? panic("NFT does not use MetadataViews.Editions")
96        let editions = view as! [MetadataViews.Edition]
97        for edition in editions {
98            if edition.name == offerParamsString["editionName"] {
99                return true
100            }
101        }
102        panic("no matching edition name for NFT")
103    }
104
105    // Resolves an offer for EditionIdAndSerialNumberTraits type
106    access(contract) fun resolveEditionIdAndSerialNumberTraitsType(_ item: &{NonFungibleToken.NFT}, _ offerParamsString: {String:String}): Bool {
107        pre {
108            offerParamsString.containsKey("editionId"): "offerParamsString must contain key 'editionId'"
109        }
110
111        let view = item.resolveView(Type<MetadataViews.Traits>())
112            ?? panic("NFT does not use MetadataViews.Traits")
113        let traits = view as! MetadataViews.Traits
114
115        let shouldValidateSerial = offerParamsString.containsKey("serialNumber")
116        var hasValidEditionId = false
117        var hasValidSerialNumber = false
118
119        for trait in traits.traits {
120            if trait.name.toLower() == "editionid" {
121                if let nftEditionIdTrait = trait.value as! UInt64? {
122                    hasValidEditionId = nftEditionIdTrait.toString() == offerParamsString["editionId"]
123                }
124            }
125            if shouldValidateSerial && trait.name.toLower() == "serialnumber" {
126                if let nftSerialNumber = trait.value as! UInt64? {
127                    hasValidSerialNumber = nftSerialNumber.toString() == offerParamsString["serialNumber"]
128                }
129            }
130            // Return early if the required traits are found and match
131            if hasValidEditionId && (!shouldValidateSerial || hasValidSerialNumber) {
132                return true
133            }
134        }
135        return false
136    }
137
138    // Public function to create a new OfferResolver resource
139    access(all) fun createResolver(): @OfferResolver {
140        return <-create OfferResolver()
141    }
142}
143