Smart Contract
ChainzPack
A.ff342b6df9ef019d.ChainzPack
1import ChainzNFT from 0xff342b6df9ef019d
2import NonFungibleToken from 0x1d7e57aa55817448
3import DapperUtilityCoin from 0xead892083b3e2c6c
4import FungibleToken from 0xf233dcee88fe0abe
5
6pub contract ChainzPack: NonFungibleToken {
7
8 pub var totalSupply: UInt64
9 pub var nextPackTypeId: UInt64
10 access(self) let packTypes: {UInt64: PackType}
11
12 pub struct PackType {
13 pub let id: UInt64
14 pub let name: String
15 pub let price: UFix64
16 pub var amountMinted: UInt64
17 pub let reserved: UInt64
18 pub var takenFromReserved: UInt64
19 pub let maxSupply: UInt64
20 pub var isSaleActive: Bool
21 pub let extra: {String: String}
22
23 pub fun minted() {
24 self.amountMinted = self.amountMinted + 1
25 }
26
27 pub fun usedReserve() {
28 self.takenFromReserved = self.takenFromReserved + 1
29 }
30
31 pub fun toggleActive() {
32 self.isSaleActive = !self.isSaleActive
33 }
34
35 init(_name: String, _price: UFix64, _maxSupply: UInt64, _reserved: UInt64, _extra: {String: String}) {
36 self.id = ChainzPack.nextPackTypeId
37 self.name = _name
38 self.price = _price
39 self.amountMinted = 0
40 self.maxSupply = _maxSupply
41 self.reserved = _reserved
42 self.takenFromReserved = 0
43 self.isSaleActive = false
44 self.extra = _extra
45 }
46 }
47
48 pub event ContractInitialized()
49 pub event Withdraw(id: UInt64, from: Address?)
50 pub event Deposit(id: UInt64, to: Address?)
51
52 pub let CollectionStoragePath: StoragePath
53 pub let CollectionPublicPath: PublicPath
54
55 pub resource NFT: NonFungibleToken.INFT {
56 // The Pack's id
57 pub let id: UInt64
58 pub let sequence: UInt64
59 pub let packTypeId: UInt64
60
61 init(_packTypeId: UInt64) {
62 self.id = self.uuid
63 ChainzPack.totalSupply = ChainzPack.totalSupply + 1
64 self.sequence = ChainzPack.totalSupply
65 self.packTypeId = _packTypeId
66 }
67 }
68
69 pub resource interface CollectionPublic {
70 pub fun deposit(token: @NonFungibleToken.NFT)
71 pub fun getIDs(): [UInt64]
72 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
73 pub fun borrowPack(id: UInt64): &ChainzPack.NFT? {
74 // If the result isn't nil, the id of the returned reference
75 // should be the same as the argument to the function
76 post {
77 (result == nil) || (result?.id == id):
78 "Cannot borrow Pack reference: The ID of the returned reference is incorrect"
79 }
80 }
81 }
82
83 // IPackCollectionAdminAccessible
84 // Exposes the openPack which allows an admin to
85 // open a pack in this collection.
86 //
87 pub resource interface AdminAccessible {
88 access(account) fun openPack(id: UInt64, cardCollectionRef: &ChainzNFT.Collection{ChainzNFT.CollectionPublic}, names: [String], descriptions: [String], thumbnails: [String], metadatas: [{String: String}])
89 }
90
91 // Collection
92 // a collection of Pack resources so that users can
93 // own Packs in a collection and trade them back and forth.
94 //
95 pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, CollectionPublic, AdminAccessible {
96 pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
97
98 pub fun deposit(token: @NonFungibleToken.NFT) {
99 let token <- token as! @ChainzPack.NFT
100 let id: UInt64 = token.id
101 self.ownedNFTs[id] <-! token
102 emit Deposit(id: id, to: self.owner?.address)
103 }
104
105 pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
106 let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing Pack")
107 emit Withdraw(id: token.id, from: self.owner?.address)
108 return <-token
109 }
110
111 // openPack
112 // This method removes a Pack from this Collection and then
113 // deposits newly minted Cards into the Collection reference by
114 // calling depositBatch on the reference.
115 //
116 // The Pack is also destroyed in the process so it will no longer
117 // exist
118 //
119 access(account) fun openPack(id: UInt64, cardCollectionRef: &ChainzNFT.Collection{ChainzNFT.CollectionPublic}, names: [String], descriptions: [String], thumbnails: [String], metadatas: [{String: String}]) {
120 let pack <- self.withdraw(withdrawID: id)
121 var i: Int = 0
122 // Mints new Cards into this empty Collection
123 while i < names.length {
124 let newCard: @ChainzNFT.NFT <- ChainzNFT.createNFT(name: names[i], description: descriptions[i], thumbnail: thumbnails[i], metadata: metadatas[i])
125 cardCollectionRef.deposit(token: <-newCard)
126 i = i + 1
127 }
128
129 destroy pack
130 }
131
132 pub fun getIDs(): [UInt64] {
133 return self.ownedNFTs.keys
134 }
135
136 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
137 return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)!
138 }
139
140 pub fun borrowPack(id: UInt64): &ChainzPack.NFT? {
141 let ref = &self.ownedNFTs[id] as auth &NonFungibleToken.NFT?
142 return ref as! &ChainzPack.NFT?
143 }
144
145 destroy() {
146 destroy self.ownedNFTs
147 }
148
149 init() {
150 self.ownedNFTs <- {}
151 }
152 }
153
154 pub fun createEmptyCollection(): @Collection {
155 return <- create Collection()
156 }
157
158 access(account) fun createPackType(name: String, price: UFix64, maxSupply: UInt64, reserved: UInt64, extra: {String: String}) {
159 self.packTypes[self.nextPackTypeId] = PackType(_name: name, _price: price, _maxSupply: maxSupply, _reserved: reserved, _extra: extra)
160 self.nextPackTypeId = self.nextPackTypeId + 1
161 }
162
163 access(account) fun toggleActive(packTypeId: UInt64) {
164 let packType = (&self.packTypes[packTypeId] as &PackType?) ?? panic("This Pack Type does not exist.")
165 packType.toggleActive()
166 }
167
168 pub fun getPackType(packTypeId: UInt64): PackType? {
169 return self.packTypes[packTypeId]
170 }
171
172 pub fun mintPack(packCollectionRef: &ChainzPack.Collection{ChainzPack.CollectionPublic}, packTypeId: UInt64, payment: @DapperUtilityCoin.Vault) {
173 let packType = (&self.packTypes[packTypeId] as &PackType?) ?? panic("This Pack Type does not exist.")
174 assert(payment.balance == packType.price, message: "The correct payment amount was not passed in.")
175 assert(packType.amountMinted < packType.maxSupply - packType.reserved, message: "This Pack Type is sold out.")
176 assert(packType.isSaleActive, message: "The drop is not currently active.")
177 packCollectionRef.deposit(token: <- create NFT(_packTypeId: packTypeId))
178 packType.minted()
179
180 // WHERE DOES THE PAYMENT GO?
181 let treasury = getAccount(0xd1120ae332f528f0).getCapability(/public/dapperUtilityCoinReceiver)
182 .borrow<&{FungibleToken.Receiver}>()
183 ?? panic("This is not a Dapper Wallet account.")
184 treasury.deposit(from: <- payment)
185 }
186
187 access(account) fun reserveMint(packCollectionRef: &ChainzPack.Collection{ChainzPack.CollectionPublic}, packTypeId: UInt64) {
188 let packType = (&self.packTypes[packTypeId] as &PackType?) ?? panic("This Pack Type does not exist.")
189 assert(packType.amountMinted < packType.maxSupply, message: "This Pack Type is sold out.")
190 assert(packType.takenFromReserved < packType.reserved, message: "You have used up all of the reserves.")
191 packCollectionRef.deposit(token: <- create NFT(_packTypeId: packTypeId))
192 packType.minted()
193 packType.usedReserve()
194 }
195
196 init() {
197 self.totalSupply = 0
198 self.nextPackTypeId = 0
199 self.packTypes = {}
200
201 self.CollectionStoragePath = /storage/ChainzPackCollection
202 self.CollectionPublicPath = /public/ChainzPackCollection
203
204 emit ContractInitialized()
205 }
206}
207