Smart Contract

CryptoPiggo

A.d3df824bf81910a4.CryptoPiggo

Valid From

84,965,581

Deployed

1d ago
Feb 26, 2026, 02:13:35 AM UTC

Dependents

3369 imports
1/**
2 This program is free software: you can redistribute it and/or modify
3    it under the terms of the GNU General Public License as published by
4    the Free Software Foundation, either version 3 of the License, or
5    (at your option) any later version.
6
7    This program is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10    GNU General Public License for more details.
11
12    You should have received a copy of the GNU General Public License
13    along with this program.  If not, see <https://www.gnu.org/licenses/>.
14**/
15import NonFungibleToken from 0x1d7e57aa55817448
16import MetadataViews from 0x1d7e57aa55817448
17import ViewResolver from 0x1d7e57aa55817448
18import FungibleToken from 0xf233dcee88fe0abe
19
20access(all) contract CryptoPiggo: NonFungibleToken {
21  access(all) var totalSupply: UInt64
22  access(all) let maxSupply: UInt64
23
24  access(all) event Minted(id: UInt64, initMeta: {String: String})
25
26  access(all) let CollectionStoragePath: StoragePath
27  access(all) let CollectionPublicPath: PublicPath
28  access(all) let MinterStoragePath: StoragePath
29
30  // idToAddress
31  // Maps each item ID to its current owner
32  //
33  access(self) let idToAddress: [Address]
34
35  access(all) resource NFT: NonFungibleToken.NFT {
36    access(all) let id: UInt64
37    access(self) let metadata: {String: String}
38
39    access(all) fun getMetadata(): {String: String} {
40      return self.metadata
41    }
42
43    init(initID: UInt64, initMeta: {String: String}) {
44      self.id = initID
45      self.metadata = initMeta
46    }
47
48    access(all) view fun getViews(): [Type] {
49      return [
50        Type<MetadataViews.Display>(),
51        Type<MetadataViews.Royalties>(),
52        Type<MetadataViews.Editions>(),
53        Type<MetadataViews.ExternalURL>(),
54        Type<MetadataViews.NFTCollectionData>(),
55        Type<MetadataViews.NFTCollectionDisplay>(),
56        Type<MetadataViews.Serial>(),
57        Type<MetadataViews.Traits>()
58      ]
59    }
60
61    access(all) fun resolveView(_ view: Type): AnyStruct? {
62      switch view {
63        case Type<MetadataViews.Display>():
64          return MetadataViews.Display(
65            name: "Crypto Piggo NFT",
66            description: "Crypto Piggo NFT #".concat(self.id.toString()),
67            thumbnail: MetadataViews.HTTPFile(
68              url: "https://s3.us-west-2.amazonaws.com/crypto-piggo.nft/piggo-".concat(self.id.toString()).concat(".png")
69            )
70          )
71
72        case Type<MetadataViews.Editions>():
73          // There is no max number of NFTs that can be minted from this contract
74          // so the max edition field value is set to nil
75          return MetadataViews.Editions([
76            MetadataViews.Edition(
77              name: "Crypto Piggo NFT Edition", 
78              number: self.id, 
79              max: nil
80            )
81          ])
82
83        case Type<MetadataViews.Serial>():
84          return MetadataViews.Serial(self.id)
85
86        case Type<MetadataViews.Royalties>():
87          let royalties: [MetadataViews.Royalty] = []
88          let receiver = getAccount(0x4cfbe4c6abc0e12a)
89              .capabilities.get<&{FungibleToken.Receiver}>(
90                MetadataViews.getRoyaltyReceiverPublicPath()
91              )
92          if receiver.check() {
93            royalties.append(
94              MetadataViews.Royalty(
95                receiver: receiver, 
96                cut: 0.07, 
97                description: ""
98              )
99            )
100          }
101
102          return MetadataViews.Royalties(royalties)
103
104        case Type<MetadataViews.ExternalURL>():
105          return MetadataViews.ExternalURL("https://s3.us-west-2.amazonaws.com/crypto-piggo.nft/piggo-".concat(self.id.toString()).concat(".png"))
106
107        case Type<MetadataViews.NFTCollectionData>():
108          return CryptoPiggo.resolveContractView(resourceType: Type<@NFT>(), viewType: Type<MetadataViews.NFTCollectionData>())
109        
110        case Type<MetadataViews.NFTCollectionDisplay>():
111          return CryptoPiggo.resolveContractView(resourceType: Type<@NFT>(), viewType: Type<MetadataViews.NFTCollectionDisplay>())
112
113        case Type<MetadataViews.Traits>():
114          return MetadataViews.dictToTraits(dict: self.metadata, excludedNames: [])
115      }
116      return nil
117    }
118
119    access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
120      return <- CryptoPiggo.createEmptyCollection(nftType: Type<@NFT>())
121    }
122  }
123
124  access(all) resource interface CryptoPiggoCollectionPublic {}
125
126  access(all) resource Collection: CryptoPiggoCollectionPublic, NonFungibleToken.Collection {
127    // dictionary of NFT conforming tokens
128    // NFT is a resource type with an `UInt64` ID field
129    access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
130
131    init () {
132      self.ownedNFTs <- {}
133    }
134
135    // withdraw removes an NFT from the collection and moves it to the caller
136    access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
137      let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
138
139      return <-token
140    }
141
142    // deposit takes a NFT and adds it to the collections dictionary
143    // and adds the ID to the id array
144    access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
145      let token <- token as! @CryptoPiggo.NFT
146
147      let id: UInt64 = token.id
148
149      // add the new token to the dictionary which removes the old one
150      let oldToken <- self.ownedNFTs[id] <- token
151
152      // update owner
153      CryptoPiggo.idToAddress[id] = self.owner!.address
154
155      destroy oldToken
156    }
157
158    // transfer takes an NFT ID and a reference to a recipient's collection
159    // and transfers the NFT corresponding to that ID to the recipient
160    access(all) fun transfer(id: UInt64, recipient: &{NonFungibleToken.CollectionPublic}) {
161      post {
162        self.ownedNFTs[id] == nil: "The specified NFT was not transferred"
163        recipient.borrowNFT(id) != nil: "Recipient did not receive the intended NFT"
164      }
165
166      let nft <- self.withdraw(withdrawID: id)
167      
168      recipient.deposit(token: <- nft)
169    }
170
171    // burn destroys an NFT
172    access(all) fun burn(id: UInt64) {
173      post {
174        self.ownedNFTs[id] == nil: "The specified NFT was not burned"
175      }
176
177      destroy <- self.withdraw(withdrawID: id)
178    }
179
180    access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
181        let supportedTypes: {Type: Bool} = {}
182        supportedTypes[Type<@NFT>()] = true
183        return supportedTypes
184    }
185
186    access(all) view fun isSupportedNFTType(type: Type): Bool {
187        return type == Type<@NFT>()
188    }
189
190    // getIDs returns an array of the IDs that are in the collection
191    access(all) view fun getIDs(): [UInt64] {
192      return self.ownedNFTs.keys
193    }
194
195    // borrowNFT gets a reference to an NFT in the collection
196    // so that the caller can read its metadata and call its methods
197    access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
198      return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)
199    }
200
201    // borrowItem gets a reference to an NFT in the collection as a CryptoPiggo,
202    // exposing all of its fields. This is safe as there are no functions that 
203    // can be called on the CryptoPiggo.
204    access(all) fun borrowItem(id: UInt64): &CryptoPiggo.NFT? {
205      if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
206        return nft as! &NFT
207      }
208      return nil
209    }
210
211    access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
212      if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
213          return nft as &{ViewResolver.Resolver}
214      }
215      return nil
216    }
217
218    access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
219        return <- CryptoPiggo.createEmptyCollection(nftType: Type<@NFT>())
220    }
221  }
222
223  // createEmptyCollection
224  // public function that anyone can call to create a new empty collection
225  //
226  access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
227    return <- create Collection()
228  }
229
230  // getMetadataCID
231  // public function that anyone can call to get the IPFS CID of the JSON file with 
232  // all the NFT metadata of this collection. The file will not contain any of the 
233  // NFTs burned by the admin account.
234  //
235  access(all) fun getMetadataCID(): MetadataViews.IPFSFile {
236    return MetadataViews.IPFSFile(
237      cid: "QmTd2TspsYLNLsg7HrGcmHhCAJcSkQbLKGWJKPwsLGQuvq",
238      path: nil
239    )
240  }
241
242  // getMetadataURL
243  // public function that anyone can call to get the IPFS URL of the JSON file with 
244  // all the NFT metadata of this collection. The file will not contain any of the 
245  // NFTs burned by the admin account.
246  //
247  access(all) fun getMetadataURL(): String {
248    return "https://ipfs.tenzingai.com/ipfs/QmTd2TspsYLNLsg7HrGcmHhCAJcSkQbLKGWJKPwsLGQuvq"
249  }
250
251  // NFTMinter
252  // Resource that an admin or something similar would own to be
253  // able to mint new NFTs
254  //
255	access(all) resource NFTMinter {
256    // mintNFT
257    // Mints a new NFT with a new ID
258		// and deposit it in the recipients collection using their collection reference
259    //
260		access(all) fun mintNFT(recipient: Address, initMetadata: {String: String}) {
261      let nftID = CryptoPiggo.totalSupply
262      if nftID < CryptoPiggo.maxSupply {
263        let receiver = getAccount(recipient)
264          .capabilities.borrow<&{NonFungibleToken.CollectionPublic}>(CryptoPiggo.CollectionPublicPath)
265          ?? panic("Could not get receiver reference to the NFT Collection")
266        emit Minted(id: nftID, initMeta: initMetadata)
267        CryptoPiggo.idToAddress.append(recipient)
268        CryptoPiggo.totalSupply = nftID + 1
269        receiver.deposit(token: <-create CryptoPiggo.NFT(initID: nftID, initMeta: initMetadata))
270      } else {
271        panic("No more piggos can be minted")
272      }
273		}
274	}
275
276  // getOwner
277  // Gets the current owner of the given item
278  //
279  access(all) fun getOwner(itemID: UInt64): Address? {
280    if itemID >= 0 && itemID < self.maxSupply {
281      if (itemID < CryptoPiggo.totalSupply) {
282        return CryptoPiggo.idToAddress[itemID]
283      } else {
284        return nil
285      }
286    }
287    return nil
288  }
289
290  access(all) view fun getContractViews(resourceType: Type?): [Type] {
291        return [
292            Type<MetadataViews.NFTCollectionData>(),
293            Type<MetadataViews.NFTCollectionDisplay>()
294        ]
295    }
296
297    access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
298      switch viewType {
299        case Type<MetadataViews.NFTCollectionData>():
300          let collectionData = MetadataViews.NFTCollectionData(
301              storagePath: self.CollectionStoragePath,
302              publicPath: self.CollectionPublicPath,
303              publicCollection: Type<&Collection>(),
304              publicLinkedType: Type<&Collection>(),
305              createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} {
306                  return <- CryptoPiggo.createEmptyCollection(nftType: Type<@NFT>())
307              })
308          )
309          return collectionData
310        case Type<MetadataViews.NFTCollectionDisplay>():
311          let media = MetadataViews.Media(
312            file: MetadataViews.HTTPFile(url: "https://ipfs.tenzingai.com/ipfs/QmUk3s7BoVSS56V2U4rxd1syVp8USUEygu7NmARppH183U"),
313            mediaType: "image/png"
314          )
315          return MetadataViews.NFTCollectionDisplay(
316            name: "The Crypto Piggo NFT Collection",
317            description: "",
318            externalURL: MetadataViews.ExternalURL("https://www.rareworx.com/"),
319            squareImage: media,
320            bannerImage: media,
321            socials: {}
322          )
323      }
324      return nil
325    }
326
327    // initializer
328    //
329    // test update
330	init() {
331    // Set our named paths
332    self.CollectionStoragePath = /storage/CryptoPiggoCollection
333    self.CollectionPublicPath = /public/CryptoPiggoCollection
334    self.MinterStoragePath = /storage/CryptoPiggoMinter
335
336    // Initialize the total supply
337    self.totalSupply = 0
338
339    // Initialize the max supply
340    self.maxSupply = 10000
341
342    // Initalize mapping from ID to address
343    self.idToAddress = []
344
345    // Create a Minter resource and save it to storage
346    let minter <- create NFTMinter()
347    self.account.storage.save(<-minter, to: self.MinterStoragePath)
348	}
349}
350