Smart Contract
TraderflowNFT
A.bb12a6da563a5e8e.TraderflowNFT
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