Smart Contract

TobiraNeko

A.e217638793f1e461.TobiraNeko

Deployed

2h ago
Feb 28, 2026, 09:41:13 PM UTC

Dependents

0 imports
1import NonFungibleToken from 0x1d7e57aa55817448
2import MetadataViews from 0x1d7e57aa55817448
3import ViewResolver from 0x1d7e57aa55817448
4
5access(all) contract TobiraNeko: NonFungibleToken {
6
7    access(all) var totalSupply: UInt64
8
9    /***********************************************/
10    /******************** PATHS ********************/
11    /***********************************************/
12    access(all) var collectionPublicPath: PublicPath
13    access(all) var collectionStoragePath: StoragePath
14    // access(all) var minterPublicPath: PublicPath
15    access(all) var minterStoragePath: StoragePath
16
17    /************************************************/
18    /******************** EVENTS ********************/
19    /************************************************/
20    access(all) event Mint(id: UInt64, creator: Address, metadata: {String:String})
21
22    access(all) resource NFT: NonFungibleToken.NFT {
23        access(all) let id: UInt64
24        access(all) let creator: Address
25        access(self) let metadata: {String:String}
26
27        init(id: UInt64, creator: Address, metadata: {String:String}) {
28            self.id = id
29            self.creator = creator
30            self.metadata = metadata
31        }
32
33        access(all) view fun getViews(): [Type] {
34            return [Type<MetadataViews.Display>()]
35        }
36
37        access(all) fun resolveView(_ view: Type): AnyStruct? {
38            switch view {
39                case Type<MetadataViews.Display>():
40                    return MetadataViews.Display(
41                        name: self.metadata["name"] ?? "",
42                        description: self.metadata["description"] ?? "",
43                        thumbnail: MetadataViews.HTTPFile(url: self.metadata["thumbnail"] ?? ""),
44                    )
45            }
46            return nil
47        }
48
49        access(all) fun getMetadata(): {String:String} {
50            return self.metadata
51        }
52
53        access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
54            return <- TobiraNeko.createEmptyCollection(nftType: Type<@TobiraNeko.NFT>())
55        }
56    }
57
58    access(all) resource interface CollectionPublic {
59        access(all) view fun borrow(id: UInt64): &NFT?
60    }
61
62    access(all) resource Collection: NonFungibleToken.Collection, CollectionPublic {
63        access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
64
65        init() {
66            self.ownedNFTs <- {}
67        }
68
69        access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
70            let supportedTypes: {Type: Bool} = {}
71            supportedTypes[Type<@TobiraNeko.NFT>()] = true
72            return supportedTypes
73        }
74
75        access(all) view fun isSupportedNFTType(type: Type): Bool {
76            return type == Type<@TobiraNeko.NFT>()
77        }
78
79        access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
80            let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("Missing NFT")
81            return <- token
82        }
83
84        access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
85            let token <- token as! @TobiraNeko.NFT
86            let id: UInt64 = token.id
87            let dummy <- self.ownedNFTs[id] <- token
88            destroy dummy
89        }
90
91        access(all) view fun getIDs(): [UInt64] {
92            return self.ownedNFTs.keys
93        }
94
95        access(all) view fun getLength(): Int {
96            return self.ownedNFTs.length
97        }
98
99        access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
100            return &self.ownedNFTs[id] as &{NonFungibleToken.NFT}?
101        }
102
103        access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
104            if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
105                return nft as &{ViewResolver.Resolver}
106            }
107            return nil
108        }
109
110        access(all) view fun borrow(id: UInt64): &NFT? {
111            let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
112            return ref as! &NFT
113        }
114
115        access(all) fun getMetadata(id: UInt64): {String:String} {
116            let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
117            return (ref as! &TobiraNeko.NFT).getMetadata()
118        }
119
120        access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
121            return <- TobiraNeko.createEmptyCollection(nftType: Type<@TobiraNeko.NFT>())
122        }
123    }
124
125    access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
126        return <- create Collection()
127    }
128
129    access(all) view fun getContractViews(resourceType: Type?): [Type] {
130        return [
131            Type<MetadataViews.NFTCollectionData>()
132        ]
133    }
134
135    access(all) view fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
136        switch viewType {
137            case Type<MetadataViews.NFTCollectionData>():
138                let collectionData = MetadataViews.NFTCollectionData(
139                    storagePath: self.collectionStoragePath,
140                    publicPath: self.collectionPublicPath,
141                    publicCollection: Type<&TobiraNeko.Collection>(),
142                    publicLinkedType: Type<&TobiraNeko.Collection>(),
143                    createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} {
144                        return <- TobiraNeko.createEmptyCollection(nftType: Type<@TobiraNeko.NFT>())
145                    })
146                )
147                return collectionData
148        }
149        return nil
150    }
151
152    access(all) resource Minter {
153        access(all) fun mintTo(creator: Capability<&{NonFungibleToken.Receiver}>, metadata: {String:String}): UInt64 {
154            let id = TobiraNeko.totalSupply
155            let token <- create NFT(
156                id: id,
157                creator: creator.address,
158                metadata: metadata
159            )
160            TobiraNeko.totalSupply = TobiraNeko.totalSupply + 1
161            // emit Mint(id: token.id, creator: creator.address, metadata: metadata)
162            creator.borrow()!.deposit(token: <- token)
163            return id
164        }
165
166        access(all) fun batchMintTo(creator: Capability<&{NonFungibleToken.Receiver}>, quantity: UInt64): UInt64 {
167            var i: UInt64 = 0
168            while i < quantity {
169                let id = TobiraNeko.totalSupply.toString()
170                let idLength = id.length
171                let formattedId = "00000".concat(id).slice(from: idLength, upTo: idLength + 5)
172                self.mintTo(creator: creator, metadata: {
173                    "name": "TOBIRA NEKO #".concat(formattedId),
174                    "description": "",
175                    "thumbnail": "https://storage.googleapis.com/tobiratory-media/nft/tobiraneko/".concat(id).concat(".png"),
176                    "metaURI": "https://nft.tobiratory.com/metadata/".concat(id)
177                })
178                i = i + UInt64(1)
179            }
180            return quantity
181        }
182    }
183
184    // access(all) fun minter(): Capability<&Minter> {
185    //     return self.account.getCapability<&Minter>(self.minterPublicPath)
186    // }
187
188    init() {
189        self.totalSupply = 0
190        self.collectionPublicPath = /public/TobiraNekoCollection001
191        self.collectionStoragePath = /storage/TobiraNekoCollection001
192        // self.minterPublicPath = /public/TobiraNekoMinter001
193        self.minterStoragePath = /storage/TobiraNekoMinter001
194
195        if self.account.storage.borrow<&Minter>(from: self.minterStoragePath) == nil {
196            self.account.storage.save(<- create Minter(), to: self.minterStoragePath)
197        }
198
199        if self.account.storage.borrow<&TobiraNeko.Collection>(from: TobiraNeko.collectionStoragePath) == nil {
200            self.account.storage.save(<- create Collection(), to: self.collectionStoragePath)
201            let cap: Capability = self.account.capabilities.storage.issue<&TobiraNeko.Collection>(self.collectionStoragePath)
202            self.account.capabilities.publish(cap, at: self.collectionPublicPath)
203        }
204    }
205}