Smart Contract

FindAirdropper

A.097bafa4e0b48eef.FindAirdropper

Deployed

2d ago
Feb 26, 2026, 03:12:51 AM UTC

Dependents

0 imports
1import NonFungibleToken from 0x1d7e57aa55817448
2import FIND from 0x097bafa4e0b48eef
3import FungibleToken from 0xf233dcee88fe0abe
4import FlowToken from 0x1654653399040a61
5import FindMarket from 0x097bafa4e0b48eef
6import FindViews from 0x097bafa4e0b48eef
7import FindLostAndFoundWrapper from 0x097bafa4e0b48eef
8import MetadataViews from 0x1d7e57aa55817448
9
10access(all) contract FindAirdropper {
11    // Events
12    access(all) event Airdropped(from: Address ,fromName: String?, to: Address, toName: String?,uuid: UInt64, nftInfo: FindMarket.NFTInfo, context: {String : String}, remark: String?)
13    access(all) event AirdroppedToLostAndFound(from: Address, fromName: String? , to: Address, toName: String?, uuid: UInt64, nftInfo: FindMarket.NFTInfo, context: {String : String}, remark: String?, ticketID: UInt64)
14    access(all) event AirdropFailed(from: Address, fromName: String? , to: Address, toName: String?, uuid: UInt64, id: UInt64, type: String, context: {String : String}, reason: String)
15
16    // The normal way of airdrop. If the user didn't init account, they cannot receive it
17    access(all) fun safeAirdrop(pointer: FindViews.AuthNFTPointer, receiver: Address, path: PublicPath, context: {String : String}, deepValidation: Bool) {
18        let toName = FIND.reverseLookup(receiver)
19        let from = pointer.owner()
20        let fromName = FIND.reverseLookup(from)
21        if deepValidation && !pointer.valid() {
22            emit AirdropFailed(from: pointer.owner() , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid, id: pointer.id, type: pointer.itemType.identifier,  context: context, reason: "Invalid NFT Pointer")
23            return
24        }
25
26        let vr = pointer.getViewResolver()
27        let nftInfo = FindMarket.NFTInfo(vr, id: pointer.id, detail: true)
28
29        let receiverCap = getAccount(receiver).capabilities.get<&{NonFungibleToken.Receiver}>(path)
30        // calculate the required storage and check sufficient balance
31        let senderStorageBeforeSend = getAccount(from).storage.used
32
33        let item <- pointer.withdraw()
34
35        let requiredStorage = senderStorageBeforeSend - getAccount(from).storage.used
36        let receiverAvailableStorage = getAccount(receiver).storage.capacity - getAccount(receiver).storage.used
37        // If requiredStorage > receiverAvailableStorage, deposit will not be successful, we will emit fail event and deposit back to the sender's collection
38        if receiverAvailableStorage < requiredStorage {
39            emit AirdropFailed(from: pointer.owner() , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid, id: pointer.id, type: pointer.itemType.identifier, context: context, reason: "Insufficient User Storage")
40            pointer.deposit(<- item)
41            return
42        }
43
44        if  receiverCap.check() {
45            emit Airdropped(from: from , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid, nftInfo: nftInfo, context: context, remark: nil)
46            receiverCap.borrow()!.deposit(token: <- item)
47            return
48        } else {
49            let collectionPublic = getAccount(receiver).capabilities.borrow<&{NonFungibleToken.Collection}>(path)
50            if collectionPublic !=nil {
51
52                let from = pointer.owner()
53                emit Airdropped(from: from , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid,  nftInfo: nftInfo, context: context, remark: "Receiver Not Linked")
54
55                collectionPublic!.deposit(token: <- item)
56                return
57            }
58        }
59
60        emit AirdropFailed(from: pointer.owner() , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid, id: pointer.id, type: pointer.itemType.identifier, context: context, reason: "Invalid Receiver Capability")
61        pointer.deposit(<- item)
62    }
63
64    access(all) fun forcedAirdrop(pointer: FindViews.AuthNFTPointer, receiver: Address, path: PublicPath, context: {String : String}, storagePayment: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, flowTokenRepayment: Capability<&FlowToken.Vault>, deepValidation: Bool) {
65
66        let toName = FIND.reverseLookup(receiver)
67        let from = pointer.owner()
68        let fromName = FIND.reverseLookup(from)
69
70        if deepValidation && !pointer.valid() {
71            emit AirdropFailed(from: pointer.owner() , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid, id: pointer.id, type: pointer.itemType.identifier, context: context, reason: "Invalid NFT Pointer")
72            return
73        }
74
75        let vr = pointer.getViewResolver()
76        let nftInfo = FindMarket.NFTInfo(vr, id: pointer.id, detail: true)
77
78        // use LostAndFound for dropping
79        let ticketID = FindLostAndFoundWrapper.depositNFT(
80            receiver: receiver,
81            collectionPublicPath: path,
82            item: pointer,
83            memo: context["message"],
84            storagePayment: storagePayment,
85            flowTokenRepayment: flowTokenRepayment,
86            subsidizeReceiverStorage: false
87        )
88
89        if ticketID == nil {
90            emit Airdropped(from: pointer.owner() , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid, nftInfo: nftInfo, context: context, remark: nil)
91            return
92        }
93        emit AirdroppedToLostAndFound(from: pointer.owner() , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid, nftInfo: nftInfo, context: context, remark: nil, ticketID: ticketID!)
94    }
95
96    access(all) fun subsidizedAirdrop(pointer: FindViews.AuthNFTPointer, receiver: Address, path: PublicPath, context: {String : String}, storagePayment: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, flowTokenRepayment: Capability<&FlowToken.Vault>, deepValidation: Bool) {
97
98        let toName = FIND.reverseLookup(receiver)
99        let from = pointer.owner()
100        let fromName = FIND.reverseLookup(from)
101
102        if deepValidation && !pointer.valid() {
103            emit AirdropFailed(from: pointer.owner() , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid, id: pointer.id, type: pointer.itemType.identifier, context: context, reason: "Invalid NFT Pointer")
104            return
105        }
106
107        let vr = pointer.getViewResolver()
108        let nftInfo = FindMarket.NFTInfo(vr, id: pointer.id, detail: true)
109
110        let receiverCap = getAccount(receiver).capabilities.get<&{NonFungibleToken.Receiver}>(path)
111
112        // use LostAndFound for dropping
113        let ticketID = FindLostAndFoundWrapper.depositNFT(
114            receiver: receiver,
115            collectionPublicPath: path,
116            item: pointer,
117            memo: context["message"],
118            storagePayment: storagePayment,
119            flowTokenRepayment: flowTokenRepayment,
120            subsidizeReceiverStorage: true
121        )
122
123        if ticketID == nil {
124            emit Airdropped(from: pointer.owner() , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid, nftInfo: nftInfo, context: context, remark: nil)
125            return
126        }
127        emit AirdroppedToLostAndFound(from: pointer.owner() , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid,  nftInfo: nftInfo, context: context, remark: nil, ticketID: ticketID!)
128    }
129}
130
131