Smart Contract
TobiraNeko
A.e217638793f1e461.TobiraNeko
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}