Smart Contract

ChainzPack

A.ff342b6df9ef019d.ChainzPack

Deployed

2h ago
Feb 28, 2026, 06:37:35 PM UTC

Dependents

0 imports
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