Smart Contract

GeniesAirdrop

A.12450e4bb3b7666e.GeniesAirdrop

Deployed

2h ago
Feb 28, 2026, 09:42:44 PM UTC

Dependents

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