Smart Contract
GeniesAirdrop
A.12450e4bb3b7666e.GeniesAirdrop
1
2import Genies from 0x12450e4bb3b7666e
3import NonFungibleToken from 0x1d7e57aa55817448
4
5pub contract GeniesAirdrop {
6
7 pub event ContractInitialized()
8
9 pub event GeniesNFTAirdropVaultCreateted(geniesVaultID: UInt64)
10
11 // when Airdrop is created
12 pub event AirdropCreated(
13 nftId: UInt64,
14 owner: Address?,
15 receiver: Address?
16 )
17
18 // when Airdrop is claimed or deleted
19 pub event AirdropCompleted(
20 nftId: UInt64,
21 owner: Address?,
22 receiver: Address?,
23 claimed: Bool
24 )
25
26 pub event CapabilityAdded(
27 address: Address
28 )
29
30 pub let GeniesAdminStoragePath: StoragePath
31 pub let GeniesNFTAirdropVaultStoragePath: StoragePath
32 pub let GeniesNFTAirdropVaultPrivatePath: PrivatePath
33 pub let GeniesNFTAirdropVaultPublicPath: PublicPath
34
35 pub resource Admin {
36 access(self) var claimCapabilities: {Address: Capability<&{GeniesNFTAirdropVaultClaim}>}
37
38 init() {
39 self.claimCapabilities = {}
40 }
41
42 // This gives Admin the capability to claim the Airdrop on behalf of you.
43 pub fun addClaimCapability(cap: Capability<&{GeniesNFTAirdropVaultClaim}>) {
44 self.claimCapabilities[cap.address] = cap
45 emit CapabilityAdded(address: cap.address)
46 }
47
48 // get the GeniesNFTAirdropVaultClaim capability for the resource owner
49 pub fun getClaimCapability(address: Address): Capability<&{GeniesNFTAirdropVaultClaim}>? {
50 pre {
51 self.claimCapabilities[address] != nil: "No capability for this address."
52 }
53 return self.claimCapabilities[address]
54 }
55
56 pub fun createEmptyGeniesNFTAirdropVault(): @GeniesAirdrop.GeniesNFTAirdropVault {
57 return <-create GeniesNFTAirdropVault()
58 }
59 }
60
61 pub resource interface GeniesNFTAirdropVaultPublic {
62 pub fun getIDs(): [UInt64]
63 }
64
65 pub resource interface GeniesNFTAirdropVaultClaim {
66 pub fun claim(nftId: UInt64, address: Address)
67 }
68
69 pub resource GeniesNFTAirdropVault: GeniesNFTAirdropVaultPublic, GeniesNFTAirdropVaultClaim {
70
71 pub var ownerships: {UInt64: Address}
72 pub var giftNFTs: {UInt64: Capability<&Genies.Collection{NonFungibleToken.Provider, Genies.GeniesNFTCollectionPublic}>}
73
74 init() {
75 self.giftNFTs = {}
76 self.ownerships = {}
77 }
78 destroy() {
79 self.giftNFTs = {}
80 self.ownerships = {}
81 }
82 // nft owner can create airdrop and store the nft in their vault with optional receiverAddress.
83 // If the receiverAddress is provided, only that address will be able to claim this nft. Otherwise, anyone can claim.
84 pub fun createAirdrop(nftProviderCap: Capability<&Genies.Collection{NonFungibleToken.Provider, Genies.GeniesNFTCollectionPublic}>, nftId: UInt64, receiverAddress: Address?) {
85 // Make sure the dictionary doesn't contain this nft id, so we don't accidentally destroy resource.
86 // This should not happen in theory given nft id is unique.
87 pre {
88 !self.giftNFTs.containsKey(nftId): "Duplicate NFT Id"
89 nftProviderCap.address == self.owner!.address: "Capability owner should be the same as the Vault resource owner"
90 }
91 self.giftNFTs[nftId] = nftProviderCap
92 // setting the ownership of the nft if address is provided. Otherwise, this nft is ownershipless.
93 if receiverAddress != nil {
94 self.ownerships[nftId] = receiverAddress
95 }
96
97 emit AirdropCreated(nftId: nftId, owner: self.owner?.address, receiver: receiverAddress)
98 }
99
100 // claim an airdrop. nftId has to be valid.
101 pub fun claim(nftId: UInt64, address: Address) {
102 pre {
103 self.giftNFTs.containsKey(nftId): "Invalid nftId to claim"
104
105 // if the nft being claimed has assigned ownership, check the claimer's address first.
106 !self.ownerships.containsKey(nftId) || self.ownerships[nftId] == address: "Invalid owner to claim"
107 }
108
109 let receiverAccount = getAccount(address)
110 let claimerCollection = receiverAccount.getCapability(Genies.CollectionPublicPath)
111 .borrow<&Genies.Collection{NonFungibleToken.Receiver}>()!
112
113 let nftProviderCap = self.giftNFTs.remove(key: nftId) ?? panic("missing NFT id")
114 let token <- nftProviderCap.borrow()!.withdraw(withdrawID: nftId)
115
116 // Remove the nft id from the ownership table if the table contains.
117 if self.ownerships.containsKey(nftId) {
118 self.ownerships.remove(key: nftId)
119 }
120 claimerCollection.deposit(token: <-token)
121
122 emit AirdropCompleted(nftId: nftId, owner: self.owner?.address, receiver: address, claimed: true)
123
124 }
125
126 // delisting the Airdrop back to the owner, nftId must be valid.
127 pub fun delistingAirdrop(nftId: UInt64) {
128 pre {
129 self.giftNFTs.containsKey(nftId): "Invalid nftId to remove"
130 }
131
132 self.giftNFTs.remove(key: nftId) ?? panic("missing NFT id")
133
134 if self.ownerships.containsKey(nftId) {
135 self.ownerships.remove(key: nftId)
136 }
137
138 emit AirdropCompleted(nftId: nftId, owner: self.owner?.address, receiver: self.owner?.address, claimed: false)
139 }
140
141 // remove all Airdrops and store them back to the Genies.Collection resource.
142 pub fun delistingAllAirdrops(claimerCollection: &Genies.Collection{NonFungibleToken.Receiver}) {
143 let keys = self.getIDs()
144 for key in keys {
145 self.delistingAirdrop(nftId: key)
146 }
147 }
148
149 pub fun getIDs(): [UInt64] {
150 return self.giftNFTs.keys
151 }
152 }
153
154 init() {
155 // set the named paths
156 self.GeniesNFTAirdropVaultStoragePath = /storage/GeniesNFTAirdropVaultStoragePath
157 self.GeniesNFTAirdropVaultPrivatePath = /private/GeniesNFTAirdropVaultPrivatePath
158 self.GeniesNFTAirdropVaultPublicPath = /public/GeniesNFTAirdropVaultPublicPath
159
160 self.GeniesAdminStoragePath = /storage/GeniesAdminStoragePath
161
162 // create Admin resource.
163 let admin <- create Admin()
164 self.account.save(<-admin, to: self.GeniesAdminStoragePath)
165 emit ContractInitialized()
166
167 // create GeniesNFTAirdropVault resource
168 let vault <- create GeniesNFTAirdropVault()
169 self.account.save(<-vault, to: self.GeniesNFTAirdropVaultStoragePath)
170 self.account.link<&GeniesAirdrop.GeniesNFTAirdropVault{GeniesAirdrop.GeniesNFTAirdropVaultPublic}>(
171 GeniesAirdrop.GeniesNFTAirdropVaultPublicPath,
172 target: GeniesAirdrop.GeniesNFTAirdropVaultStoragePath
173 )
174 self.account.link<&GeniesAirdrop.GeniesNFTAirdropVault{GeniesAirdrop.GeniesNFTAirdropVaultClaim}>(
175 GeniesAirdrop.GeniesNFTAirdropVaultPrivatePath,
176 target: GeniesAirdrop.GeniesNFTAirdropVaultStoragePath
177 )
178 }
179}