Smart Contract

TraderflowNFT

A.bb12a6da563a5e8e.TraderflowNFT

Deployed

2w ago
Feb 11, 2026, 06:34:17 PM UTC

Dependents

7 imports
1/* 
2*
3*  This is an example of how to implement Dynamic NFTs on Flow.
4*  A Dynamic NFT is one that can be changed after minting. In 
5*  this contract, a NFT's metadata can be changed by an Administrator.
6*   
7*/
8
9import NonFungibleToken from 0x1d7e57aa55817448 
10import MetadataViews from 0x1d7e57aa55817448 
11import TraderflowHash from 0xbb12a6da563a5e8e
12import ViewResolver from 0x1d7e57aa55817448
13
14access(all) contract TraderflowNFT: NonFungibleToken {
15
16    access(all) var totalSupply: UInt64
17
18    access(all) event ContractInitialized()
19    access(all) event Withdraw(id: UInt64, from: Address?)
20    access(all) event Deposit(id: UInt64, to: Address?)
21    access(all) event Minted(id: UInt64, by: Address, name: String, description: String, thumbnail: String)
22
23    access(all) let CollectionStoragePath: StoragePath
24    access(all) let CollectionPublicPath: PublicPath
25    access(all) let MinterStoragePath: StoragePath
26
27    access(all) struct NFTMetadata {
28      access(all) let name: String
29      access(all) let description: String
30      access(all) var thumbnail: String
31      
32      init(
33        name: String,
34        description: String,
35        thumbnail: String,
36      ) {
37        self.name = name
38        self.description = description
39        self.thumbnail = thumbnail
40      }
41
42      access(all) fun updateThumbnail(ipfs: String) {
43        self.thumbnail = ipfs
44      }
45
46    }
47
48    access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver {
49        access(all) let id: UInt64
50        access(all) let sequence: UInt64
51        access(all) var metadata: NFTMetadata
52        access(self) let trades: TraderflowHash.TradeHash
53    
54        access(all) view fun getViews(): [Type] {
55          return [
56            Type<MetadataViews.Display>()
57          ]
58        }
59
60        access(all) fun resolveView(_ view: Type): AnyStruct? {
61          let template: NFTMetadata = self.getMetadata()
62          switch view {
63            case Type<MetadataViews.Display>():
64              return MetadataViews.Display(
65                name: template.name,
66                description: template.description,
67                thumbnail: MetadataViews.HTTPFile(
68                  url: template.thumbnail
69                )
70              )
71          }
72          return nil
73        }
74
75        access(all) view fun getTrades(): TraderflowHash.TradeHash {
76          return self.trades
77        }
78
79        access(all) fun getMetadata(): NFTMetadata {
80          return NFTMetadata(name: self.metadata.name, description: self.metadata.description, thumbnail: self.metadata.thumbnail)
81        }
82
83        access(contract) fun borrowTradesRef(): &TraderflowHash.TradeHash {
84          return &self.trades
85        }
86         
87        access(contract) fun updateArtwork(ipfs: String) {
88          self.metadata.updateThumbnail(ipfs: ipfs)
89        }
90
91        access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
92            return <- TraderflowNFT.createEmptyCollection(nftType: Type<@TraderflowNFT.NFT>())
93        }
94
95        init(_name: String, _description: String, _thumbnail: String) {
96          self.id = self.uuid
97          self.sequence = TraderflowNFT.totalSupply
98          self.trades = TraderflowHash.TradeHash()
99          self.metadata = NFTMetadata(name: _name, description: _description, thumbnail: _thumbnail)
100          TraderflowNFT.totalSupply = TraderflowNFT.totalSupply + 1
101        }
102    }
103
104    access(all) resource interface CollectionPublic {
105      access(all) fun deposit(token: @{NonFungibleToken.NFT})
106      access(all) fun getIDs(): [UInt64]
107      access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}?
108      access(all) fun borrowAuthNFT(id: UInt64): &TraderflowNFT.NFT? {
109        post {
110            (result == nil) || (result?.id == id):
111                "Cannot borrow TraderflowNFT reference: the ID of the returned reference is incorrect"
112        }
113      }
114    }
115
116    access(all) resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.Collection, NonFungibleToken.CollectionPublic, ViewResolver.ResolverCollection, CollectionPublic {
117      access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
118
119      access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
120        let token: @{NonFungibleToken.NFT} <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
121        emit Withdraw(id: token.id, from: self.owner?.address)
122        return <- token
123      }
124
125      access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
126        let token: @TraderflowNFT.NFT <- token as! @TraderflowNFT.NFT
127        emit Deposit(id: token.id, to: self.owner?.address)
128        self.ownedNFTs[token.id] <-! token
129      }
130
131      access(all) view fun getIDs(): [UInt64] {
132        return self.ownedNFTs.keys
133      }
134
135      access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
136        return (&self.ownedNFTs[id])
137      }
138
139      access(all) fun borrowAuthNFT(id: UInt64): &TraderflowNFT.NFT? {
140        if self.ownedNFTs[id] != nil {
141                let ref: &{NonFungibleToken.NFT}? = (&self.ownedNFTs[id])
142                return ref as! &TraderflowNFT.NFT?
143            }
144            else {
145                return nil
146            }
147      }
148
149       access(all) view fun getLength(): Int {
150            return self.ownedNFTs.length
151        }
152
153        access(all) fun forEachID(_ f: fun (UInt64): Bool): Void {}
154
155        /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts
156        access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
157            let supportedTypes: {Type: Bool} = {}
158            supportedTypes[Type<@TraderflowNFT.NFT>()] = true
159            return supportedTypes
160        }
161
162        /// Returns whether or not the given type is accepted by the collection
163        /// A collection that can accept any type should just return true by default
164        access(all) view fun isSupportedNFTType(type: Type): Bool {
165            return type == Type<@TraderflowNFT.NFT>()
166        }
167
168        access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
169            return <- TraderflowNFT.createEmptyCollection(nftType: Type<@TraderflowNFT.NFT>())
170        } 
171
172      access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
173          pre {
174            self.ownedNFTs[id] != nil : "NFT not in collection"
175          }
176          let nft: &{NonFungibleToken.NFT} = (&self.ownedNFTs[id])!
177          let dynamicNFT: &TraderflowNFT.NFT = nft as! &TraderflowNFT.NFT
178          return dynamicNFT
179        }
180
181      init () {
182        self.ownedNFTs <- {}
183      }
184    }
185
186    access(all) resource Administrator {
187
188      access(all) fun mintNFT(
189        recipient: &Collection, 
190        name: String, 
191        description: String, 
192        thumbnail: String
193      ) {
194        let nft: @TraderflowNFT.NFT <- create NFT(_name: name, _description: description, _thumbnail: thumbnail)
195        emit Minted(id: nft.id, by: self.owner!.address, name: name, description: description, thumbnail: thumbnail)
196        recipient.deposit(token: <- nft)
197      }
198
199      access(all) fun pushHash(
200        id: UInt64, 
201        currentOwner: Address, 
202        hash: String
203      ) {
204        let ownerCollection: &TraderflowNFT.Collection = getAccount(currentOwner).capabilities.get<&Collection>(TraderflowNFT.CollectionPublicPath)
205                                .borrow()
206                                ?? panic("This person does not have a TraderflowNFT Collection set up properly.")
207        let nftRef: &TraderflowNFT.NFT = ownerCollection.borrowAuthNFT(id: id) ?? panic("This account does not own an NFT with this id.")
208        let tradeRef: &TraderflowHash.TradeHash = nftRef.borrowTradesRef()
209        let res = tradeRef.pushHash(_hash: hash)
210      }
211
212      access(all) fun updateArtwork(
213        id: UInt64, 
214        currentOwner: Address, 
215        ipfs: String
216      ) {
217        let ownerCollection: &TraderflowNFT.Collection = getAccount(currentOwner).capabilities.get<&Collection>(TraderflowNFT.CollectionPublicPath)
218                                .borrow()
219                                ?? panic("This person does not have a TraderflowNFT Collection set up properly.")
220        let nftRef: &TraderflowNFT.NFT = ownerCollection.borrowAuthNFT(id: id) ?? panic("This account does not own an NFT with this id.")
221        
222        nftRef.updateArtwork(ipfs: ipfs)
223      }
224    }
225
226    access(all) view fun getContractViews(resourceType: Type?): [Type] {
227        return [
228            Type<MetadataViews.NFTCollectionData>()
229        ]
230    }
231
232    access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
233        return nil
234    }
235
236    access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
237        return <- create Collection()
238    }
239
240    init() {
241        self.totalSupply = 0
242
243        self.CollectionStoragePath = /storage/TraderflowNFTCollection
244        self.CollectionPublicPath = /public/TraderflowNFTCollection
245        self.MinterStoragePath = /storage/TraderflowNFTMinter
246
247        self.account.storage.save(<- create Administrator(), to: self.MinterStoragePath)
248
249        emit ContractInitialized()
250    }
251}
252