Smart Contract

DoodlesWearablesProxy

A.e81193c424cfd3fb.DoodlesWearablesProxy

Valid From

86,747,757

Deployed

3d ago
Feb 24, 2026, 11:43:18 PM UTC

Dependents

28 imports
1import NonFungibleToken from 0x1d7e57aa55817448
2import MetadataViews from 0x1d7e57aa55817448
3import Doodles from 0xe81193c424cfd3fb
4import Wearables from 0xe81193c424cfd3fb
5
6/// A proxy contract that allows users to deposit Doodles and Wearables NFTs,
7/// assigning them to a specific address on the Base chain. An admin can then burn these NFTs.
8access(all) contract DoodlesWearablesProxy {
9    /**//////////////////////////////////////////////////////////////
10    //                           EVENTS                            //
11    //////////////////////////////////////////////////////////////**/
12
13    /// Event emitted when a Doodles NFT is deposited
14    access(all) event DoodlesDeposited(id: UInt64, baseAddress: String, flowAddress: Address)
15
16    /// Event emitted when a Wearables NFT is deposited
17    access(all) event WearablesDeposited(id: UInt64, baseAddress: String, flowAddress: Address)
18
19    /// Event emitted when a Doodles NFT is burned
20    access(all) event DoodlesBurned(id: UInt64, baseAddress: String, flowAddress: Address)
21
22    /// Event emitted when a Wearables NFT is burned
23    access(all) event WearablesBurned(id: UInt64, baseAddress: String, flowAddress: Address)
24
25    /**//////////////////////////////////////////////////////////////
26    //                           STRUCTS                           //
27    //////////////////////////////////////////////////////////////**/
28
29    /// A struct representing an address on the Base chain and burn status
30    access(all) struct BridgeInfo {
31        // The destination address on Base
32        access(all) let baseAddress: String
33        // The source address on Flow
34        access(all) let flowAddress: Address
35        // Whether the NFT has been burned
36        access(self) var burned: Bool
37
38        init(baseAddress: String, flowAddress: Address) {
39            // Make sure the address is a valid Ethereum address
40            assert(baseAddress.length == 42, message: "Invalid address")
41            self.baseAddress = baseAddress
42            self.flowAddress = flowAddress
43            self.burned = false
44        }
45
46        // Set the NFT as burned
47        access(contract) fun setBurned() {
48            self.burned = true
49        }
50
51        // Check if the NFT has been burned
52        access(all) fun isBurned(): Bool {
53            return self.burned
54        }
55    }
56
57    /**//////////////////////////////////////////////////////////////
58    //                          PROPERTIES                         //
59    //////////////////////////////////////////////////////////////**/
60
61    /// A mapping of Doodles NFTs to their BridgeInfo
62    access(contract) var doodles: {UInt64: BridgeInfo}
63
64    /// A mapping of Wearables NFTs to their BridgeInfo
65    access(contract) var wearables: {UInt64: BridgeInfo}
66
67    /// The contract's recipient capability that can receive Doodles NFTs
68    access(contract) var doodlesRecipient: Capability<&Doodles.Collection>
69
70    /// The contract's recipient capability that can receive Wearables NFTs
71    access(contract) var wearablesRecipient: Capability<&Wearables.Collection>
72
73    /// The storage path for the Admin resource
74    access(all) let AdminStoragePath: StoragePath
75
76    /**//////////////////////////////////////////////////////////////
77    //                           METHODS                           //
78    //////////////////////////////////////////////////////////////**/
79
80    /// Deposit an array of Doodles NFTs to the proxy contract
81    access(all) fun depositDoodlesNFT(doodlesProvider: Capability<auth(NonFungibleToken.Withdraw) &Doodles.Collection>, doodlesIDs: [UInt64], baseAddress: String) {
82        // Borrow the Doodles collection
83        let doodlesCollection = doodlesProvider.borrow() ?? panic("Missing Doodles collection")
84        // Iterate over the Doodles NFTs
85        for id in doodlesIDs {
86            // Withdraw the Doodles NFT from the collection
87            let doodle <- doodlesCollection.withdraw(withdrawID: id)
88            // Store bridge info
89            let bridgeInfo = BridgeInfo(baseAddress: baseAddress, flowAddress: doodlesProvider.address)
90            self.doodles[id] = bridgeInfo
91            // Deposit the Doodles NFT to the proxy contract
92            self.doodlesRecipient.borrow()!.deposit(token: <-doodle)
93            // Emit an event
94            emit DoodlesDeposited(id: id, baseAddress: baseAddress, flowAddress: doodlesProvider.address)
95        }
96    }
97
98    /// Deposit an array of Wearables NFTs to the proxy contract
99    access(all) fun depositWearablesNFT(wearablesProvider: Capability<auth(NonFungibleToken.Withdraw) &Wearables.Collection>, wearablesIDs: [UInt64], baseAddress: String) {
100        // Borrow the Wearables collection
101        let wearablesCollection = wearablesProvider.borrow() ?? panic("Missing Wearables collection")
102        // Iterate over the Wearables NFTs
103        for id in wearablesIDs {
104            // Withdraw the Wearables NFT from the collection
105            let wearable <- wearablesCollection.withdraw(withdrawID: id)
106            // Store bridge info
107            let bridgeInfo = BridgeInfo(baseAddress: baseAddress, flowAddress: wearablesProvider.address)
108            self.wearables[id] = bridgeInfo
109            // Deposit the Wearables NFT to the proxy contract
110            self.wearablesRecipient.borrow()!.deposit(token: <-wearable)
111            // Emit an event
112            emit WearablesDeposited(id: id, baseAddress: baseAddress, flowAddress: wearablesProvider.address)
113        }
114    }
115
116    /// Deposit a Doodle NFT to the proxy contract
117    access(all) fun depositDoodle(doodle: @Doodles.NFT, baseAddress: String, flowAddress: Address) {
118        let id = doodle.id
119        // Store bridge info
120        let bridgeInfo = BridgeInfo(baseAddress: baseAddress, flowAddress: flowAddress)
121        self.doodles[id] = bridgeInfo
122        // Deposit the Doodle NFT to the proxy contract
123        self.doodlesRecipient.borrow()!.deposit(token: <-doodle)
124        // Emit an event
125        emit DoodlesDeposited(id: id, baseAddress: baseAddress, flowAddress: flowAddress)
126    }
127
128    /// Deposit a Wearable NFT to the proxy contract
129    access(all) fun depositWearable(wearable: @Wearables.NFT, baseAddress: String, flowAddress: Address) {
130        let id = wearable.id
131        // Store bridge info
132        let bridgeInfo = BridgeInfo(baseAddress: baseAddress, flowAddress: flowAddress)
133        self.wearables[id] = bridgeInfo
134        // Deposit the Wearable NFT to the proxy contract
135        self.wearablesRecipient.borrow()!.deposit(token: <-wearable)
136        // Emit an event
137        emit WearablesDeposited(id: id, baseAddress: baseAddress, flowAddress: flowAddress)
138    }
139
140    /**//////////////////////////////////////////////////////////////
141    //                             ADMIN                           //
142    //////////////////////////////////////////////////////////////**/
143
144    /// An entitlement that allows the admin to burn NFTs
145    access(all) entitlement Burner
146
147    /// The admin resource holds the admin methods, allowing the admin to burn NFTs
148    access(all) resource Admin {
149
150        /// Burn an array of Doodles NFTs
151        access(Burner) fun burnDoodlesNFT(ids: [UInt64]) {
152            // Borrow the Doodles collection provider
153            let doodlesCollectionProvider = DoodlesWearablesProxy.account.storage.borrow<auth(NonFungibleToken.Withdraw) &Doodles.Collection>(from: Doodles.CollectionStoragePath) 
154            ?? panic("Could not borrow a reference to the collection")
155            // Iterate over the Doodles NFTs
156            for id in ids {
157                // Get the BridgeInfo for the Doodles NFT
158                let bridgeInfo = DoodlesWearablesProxy.doodles[id] ?? panic("Doodles NFT not found")
159                // Withdraw the Doodles NFT from the proxy contract
160                let doodle <- doodlesCollectionProvider.withdraw(withdrawID: id)
161                // Destroy the Doodles NFT
162                destroy <-doodle
163                // Ensure the Doodles NFT has not already been burned
164                if !bridgeInfo.isBurned() {
165                    // Set the Doodles NFT as burned
166                    bridgeInfo.setBurned()
167                    // Emit an event
168                    emit DoodlesBurned(id: id, baseAddress: bridgeInfo.baseAddress, flowAddress: bridgeInfo.flowAddress)
169                }
170            }
171        }
172
173        /// Burn an array of Wearables NFTs
174        access(Burner) fun burnWearablesNFT(ids: [UInt64]) {
175            // Borrow the Wearables collection provider
176            let wearablesCollectionProvider = DoodlesWearablesProxy.account.storage.borrow<auth(NonFungibleToken.Withdraw) &Wearables.Collection>(from: Wearables.CollectionStoragePath) 
177            ?? panic("Could not borrow a reference to the collection")
178            // Iterate over the Wearables NFTs
179            for id in ids {
180                // Get the BridgeInfo for the Wearables NFT
181                let bridgeInfo = DoodlesWearablesProxy.wearables[id] ?? panic("Wearables NFT not found")
182                // Withdraw the Wearables NFT from the proxy contract
183                let wearable <- wearablesCollectionProvider.withdraw(withdrawID: id)
184                // Destroy the Wearables NFT
185                destroy <-wearable
186                // Ensure the Wearables NFT has not already been burned
187                if !bridgeInfo.isBurned() {
188                    // Set the Wearables NFT as burned
189                    bridgeInfo.setBurned()
190                    // Emit an event
191                    emit WearablesBurned(id: id, baseAddress: bridgeInfo.baseAddress, flowAddress: bridgeInfo.flowAddress)
192                }
193            }
194        }
195    }
196
197    /**//////////////////////////////////////////////////////////////
198    //                           GETTERS                           //
199    //////////////////////////////////////////////////////////////**/
200
201    /// Get the BridgeInfo for a Doodles NFT
202    access(all) fun getDoodlesBridgeInfo(id: UInt64): BridgeInfo {
203        return self.doodles[id] ?? panic("Doodles NFT not found")
204    }
205
206    /// Get the BridgeInfo for a Wearables NFT
207    access(all) fun getWearablesBridgeInfo(id: UInt64): BridgeInfo {
208        return self.wearables[id] ?? panic("Wearables NFT not found")
209    }
210
211    /// Get all doodles bridge info
212    access(all) fun getAllDoodlesBridgeInfo(): {UInt64: BridgeInfo} {
213        return self.doodles
214    }
215
216    /// Get all wearables bridge info
217    access(all) fun getAllWearablesBridgeInfo(): {UInt64: BridgeInfo} {
218        return self.wearables
219    }
220
221    /**//////////////////////////////////////////////////////////////
222    //                          INITIALIZER                        //
223    //////////////////////////////////////////////////////////////**/
224
225    init() {
226        // Set the storage path for the Admin resource
227        self.AdminStoragePath = /storage/DoodlesWearablesProxyAdmin
228
229        // Init the Doodles and Wearables bridge info mappings
230        self.doodles = {}
231        self.wearables = {}
232
233        // Create the Admin resource
234        let admin <- create Admin()
235
236        // Save the Admin resource to storage
237        self.account.storage.save(<-admin, to: self.AdminStoragePath)
238        self.account.capabilities.storage.issue<auth(Burner) &Admin>(self.AdminStoragePath)
239
240        // Init the Doodles collection
241        let wearableRef= self.account.storage.borrow<&Wearables.Collection>(from: Wearables.CollectionStoragePath)
242        if wearableRef == nil {
243            self.account.storage.save<@{NonFungibleToken.Collection}>( <- Wearables.createEmptyCollection(nftType: Type<@Wearables.NFT>()), to: Wearables.CollectionStoragePath)
244            let cap = self.account.capabilities.storage.issue<&Wearables.Collection>(Wearables.CollectionStoragePath)
245            self.account.capabilities.publish(cap, at: Wearables.CollectionPublicPath)
246        }
247
248        // Init the Wearables collectionß
249        let doodlesRef= self.account.storage.borrow<&Doodles.Collection>(from: Doodles.CollectionStoragePath)
250        if doodlesRef == nil {
251            self.account.storage.save<@{NonFungibleToken.Collection}>( <- Doodles.createEmptyCollection(nftType: Type<@Wearables.NFT>()), to: Doodles.CollectionStoragePath)
252            let cap = self.account.capabilities.storage.issue<&Doodles.Collection>(Doodles.CollectionStoragePath)
253            self.account.capabilities.publish(cap, at: Doodles.CollectionPublicPath)
254        }
255
256        // Get the recipient capability for Doodles NFTs
257        self.doodlesRecipient = self.account.capabilities.get<&Doodles.Collection>(Doodles.CollectionPublicPath)
258
259        // Get the recipient capability for Wearables NFTs
260        self.wearablesRecipient = self.account.capabilities.get<&Wearables.Collection>(Wearables.CollectionPublicPath)
261    }
262}
263