Contract con_nft_marketplace_v5


Contract Code


  
1 # auctions + fixes market listings if nft is not unique and exists more than once + fixes royalty to allow for 0 royalty and not breaking the listing
2 I = importlib
3 allowed_currency = Variable()
4 operator = Variable()
5 market = Hash(default_value=0)
6 auctions = Hash(default_value=0)
7 treasury = Variable()
8 royalty_receivers = Hash(default_value=False)
9 old_market_version = ForeignHash(foreign_contract="con_nft_marketplace_v4", foreign_name="market")
10
11 forced_collection_interface = [I.Func('transfer', args=('name', 'amount', 'to')), I.Func(
12 'approve', args=('amount', 'name', 'to')), I.Func('transfer_from', args=(
13 'name', 'amount', 'to', 'main_account'))]
14
15
16 @construct
17 def seed():
18 allowed_currency.set("currency")
19 operator.set("ff61544ea94eaaeb5df08ed863c4a938e9129aba6ceee5f31b6681bdede11b89")
20 treasury.set("ff61544ea94eaaeb5df08ed863c4a938e9129aba6ceee5f31b6681bdede11b89")
21
22
23 @export
24 def sell_nft(name_of_nft: str, collection_contract: str, amount: int, currency_price: float, royalty_percentage: float):
25 assert name_of_nft != "", "Name cannot be empty"
26 assert collection_contract != "", "Collection contract cannot be empty"
27 assert amount > 0, 'Cannot sell negative NFT amount'
28 assert currency_price > 0, 'Cannot sell for negative balances!'
29 collection = I.import_module(collection_contract)
30 assert I.enforce_interface(collection, forced_collection_interface
31 ), 'Invalid collection interface!'
32 collection.transfer_from(name=name_of_nft, amount=amount, to=ctx.this, main_account=ctx.caller)
33
34 listing_unique_id = block_num # block_num is a global enviroment variable that is the current block number
35 for i in range(amount):
36 market[ctx.caller, collection_contract, name_of_nft, listing_unique_id + i] = {"amount": 1, "price": currency_price}
37
38 if royalty_receivers[collection_contract, name_of_nft] == False:
39 if(royalty_percentage == None):
40 royalty_percentage = 0.0
41 assert royalty_percentage <= 50, "Over 50% royalty is not allowed"
42 assert royalty_percentage >= 0, "Under 0% royalty is not allowed"
43 royalty_receivers[collection_contract, name_of_nft] = {"receiver": ctx.caller, "royalty_percentage": royalty_percentage}
44
45 return f"Successfully listed {amount} {name_of_nft} for {currency_price}"
46
47
48 @export
49 def refund_nft(name_of_nft: str, collection_contract: str, listing_id: str, version:int=5):
50 if(version == 4):
51 old_marketplace = I.import_module("con_nft_marketplace_v4")
52 old_marketplace.refund_nft(name_of_nft=name_of_nft, collection_contract=collection_contract)
53 return f"Successfully refunded {name_of_nft}"
54
55 assert name_of_nft != "", "Name cannot be empty"
56 assert collection_contract != "", "Collection contract cannot be empty"
57 assert listing_id != "", "Listing ID cannot be empty"
58 market_entry = market[ctx.caller, collection_contract, name_of_nft, listing_id]
59 collection = I.import_module(collection_contract)
60 collection.transfer(name=name_of_nft, amount=market_entry["amount"], to=ctx.caller)
61 market[ctx.caller, collection_contract, name_of_nft, listing_id] = {"amount":0, "price":market_entry["price"]}
62
63 return f"Successfully refunded {name_of_nft}"
64
65
66 @export
67 def buy_nft(name: str, collection_contract: str, seller: str, listing_id:str, version:int=5):
68 if(version == 4):
69 old_marketplace = I.import_module("con_nft_marketplace_v4")
70 old_marketplace.refund_nft(name=name, collection_contract=collection_contract, seller=seller, amount=1)
71 return f"Successfully bought {name}"
72
73 assert name != "", "Name cannot be empty"
74 assert collection_contract != "", "Collection contract cannot be empty"
75 assert seller != "", "Seller cannot be empty"
76 assert listing_id != "", "Listing ID cannot be empty"
77 collection = I.import_module(collection_contract)
78 currency = I.import_module(allowed_currency.get())
79 assert I.enforce_interface(collection, forced_collection_interface
80 ), 'Invalid collection interface!'
81 fee = ((market[seller, collection_contract, name, listing_id]["price"])/100*2)
82 royalty = ((market[seller, collection_contract, name, listing_id]["price"])/100*royalty_receivers[collection_contract, name]["royalty_percentage"])
83 currency.transfer_from(amount=(market[seller, collection_contract, name, listing_id]["price"]) - fee - royalty, to=seller, main_account=ctx.caller)
84 currency.transfer_from(amount=fee, to=treasury.get(), main_account=ctx.caller)
85
86 if royalty > 0:
87 currency.transfer_from(amount=royalty, to=royalty_receivers[collection_contract, name]["receiver"], main_account=ctx.caller)
88
89 old_market_entry = market[seller, collection_contract, name, listing_id]
90 market[seller, collection_contract, name, listing_id] = {"amount": 0, "price": old_market_entry["price"]}
91 collection.transfer(name=name, amount=1, to=ctx.caller)
92
93 return f"Successfully bought {name}"
94
95 @export
96 def setup_auction(name_of_nft: str, collection_contract: str, start_currency_price: float, future_royalty_percentage: float, auction_start: datetime.datetime, auction_end: datetime.datetime):
97 assert name_of_nft != "", "Name cannot be empty"
98 assert collection_contract != "", "Collection contract cannot be empty"
99 assert start_currency_price > 0, 'Cannot auction for negative balances!'
100 assert future_royalty_percentage <= 50, "Over 50% royalty is not allowed"
101 assert future_royalty_percentage >= 0, "Under 0% royalty is not allowed"
102 assert auction_start > now, 'Auction cannot start in the past!'
103 assert auction_end > auction_start, 'Auction cannot end before it starts!'
104
105 collection = I.import_module(collection_contract)
106 assert I.enforce_interface(collection, forced_collection_interface
107 ), 'Invalid collection interface!'
108 collection.transfer_from(name=name_of_nft, amount=1, to=ctx.this, main_account=ctx.caller)
109
110 listing_unique_id = block_num # block_num is a global enviroment variable that is the current block number
111 auctions[ctx.caller, collection_contract, name_of_nft, listing_unique_id] = {"current_bid": start_currency_price, "current_highest_bidder": ctx.caller, "future_royalty_percentage": future_royalty_percentage, "auction_start": auction_start, "auction_end": auction_end}
112
113 return f"Successfully listed {name_of_nft} for {start_currency_price} for auction"
114
115
116 @export
117 def bid_auction(seller: str, name_of_nft: str, collection_contract: str, auction_id: str, bid: float):
118 assert name_of_nft != "", "Name cannot be empty"
119 assert collection_contract != "", "Collection contract cannot be empty"
120 assert seller != "", "Seller cannot be empty"
121 assert auction_id != "", "Auction ID cannot be empty"
122 assert bid > 0, "Bid must be higher than 0"
123
124 auction = auctions[seller, collection_contract, name_of_nft, auction_id]
125 assert now > auction["auction_start"], "Auction has not started yet"
126 assert now < auction["auction_end"], "Auction has ended"
127
128 highest_bid = auction["current_bid"]
129 highest_bidder = auction["current_highest_bidder"]
130 assert bid > highest_bid, "Bid must be higher than the current highest bid"
131 assert highest_bidder != ctx.caller, "You are already the highest bidder"
132
133 assert seller != ctx.caller, "You cannot bid on your own auction"
134
135
136 currency = I.import_module(allowed_currency.get())
137 # refund the previous highest bidder if not the creator
138 if highest_bidder != seller:
139 currency.transfer(amount=highest_bid, to=highest_bidder)
140 currency.transfer_from(amount=bid, to=ctx.this, main_account=ctx.caller)
141 auction['current_bid'] = bid
142 auction['current_highest_bidder'] = ctx.caller
143 auctions[seller, collection_contract, name_of_nft, auction_id] = auction
144
145 return f"Successfully bid {bid} on {name_of_nft}"
146
147 @export
148 def cancel_auction(seller: str, name_of_nft: str, collection_contract: str, auction_id: str):
149 assert name_of_nft != "", "Name cannot be empty"
150 assert collection_contract != "", "Collection contract cannot be empty"
151 assert seller != "", "Seller cannot be empty"
152 assert auction_id != "", "Auction ID cannot be empty"
153
154 auction = auctions[seller, collection_contract, name_of_nft, auction_id]
155 assert auction != 0, "Auction does not exist"
156 assert now < auction["auction_start"], "Auction has already started"
157 assert ctx.caller == seller, "Only the seller can cancel the auction"
158
159 if(seller != auction["current_highest_bidder"]):
160 currency = I.import_module(allowed_currency.get())
161 currency.transfer(amount=auction["current_bid"], to=auction["current_highest_bidder"])
162 collection = I.import_module(collection_contract)
163 collection.transfer(name=name_of_nft, amount=1, to=ctx.caller)
164
165 auctions[seller, collection_contract, name_of_nft, auction_id] = 0
166
167 return f"Successfully cancelled Auction for {name_of_nft}"
168
169 @export
170 def finalize_auction(seller: str, name_of_nft: str, collection_contract: str, auction_id: str):
171 assert name_of_nft != "", "Name cannot be empty"
172 assert collection_contract != "", "Collection contract cannot be empty"
173 assert seller != "", "Seller cannot be empty"
174 assert auction_id != "", "Auction ID cannot be empty"
175
176 auction = auctions[seller, collection_contract, name_of_nft, auction_id]
177 assert auction != 0, "Auction does not exist"
178 assert now > auction["auction_end"], "Auction has not ended yet"
179
180 currency = I.import_module(allowed_currency.get())
181 currency.transfer(amount=auction["current_bid"], to=seller)
182 collection = I.import_module(collection_contract)
183 collection.transfer(name=name_of_nft, amount=1, to=auction["current_highest_bidder"])
184
185 auctions[seller, collection_contract, name_of_nft, auction_id] = 0
186 royalty_receivers[collection_contract, name_of_nft] = {"receiver": seller, "percentage": auction["future_royalty_percentage"]}
187
188 return f"Successfully finalized Auction for {name_of_nft}"
189
190
191 @export
192 def change_allowed_currency(contract: str):
193 assert ctx.caller == operator.get(), "Only the operator can do this"
194 allowed_currency.set(contract)
195
196 @export
197 def change_treasury(address: str):
198 assert ctx.caller == operator.get(), "Only the operator can do this"
199 treasury.set(address)
200
201 @export
202 def change_operator(address: str):
203 assert ctx.caller == operator.get(), "Only the operator can do this"
204 operator.set(address)
205

Byte Code

e3000000000000000000000000080000004000000073ae01000065005a0165026400640164028d025a0365026400640364028d025a04650564046400640564068d035a06650564046400640764068d035a0765026400640864028d025a08650564096400640a64068d035a09650a640b64056400640c640d8d045a0b65016a0c640e643664128d0265016a0c6413643764128d0265016a0c6414643864128d0267035a0d6416641784005a0e650f640083016510651065116512651264189c056419641a840483015a13650f6400830164396510651065106511641c9c04641d641e840583015a14650f64008301643a65106510651065106511641f9c0564206421840583015a15650f64008301651065106512651265166a1665166a1664229c0664236424840483015a17650f640083016510651065106510651264259c0564266427840483015a18650f64008301651065106510651064289c046429642a840483015a19650f64008301651065106510651064289c04642b642c840483015a1a650f640083016510642d9c01642e642f840483015a1b650f64008301651064309c0164316432840483015a1c650f64008301651064309c0164336434840483015a1d64355300293bda16636f6e5f6e66745f6d61726b6574706c6163655f7635da10616c6c6f7765645f63757272656e63792902da08636f6e7472616374da046e616d65da086f70657261746f72e900000000da066d61726b65742903da0d64656661756c745f76616c756572030000007204000000da0861756374696f6e73da08747265617375727946da11726f79616c74795f726563656976657273da16636f6e5f6e66745f6d61726b6574706c6163655f7634da126f6c645f6d61726b65745f76657273696f6e2904da10666f726569676e5f636f6e7472616374da0c666f726569676e5f6e616d6572030000007204000000da087472616e736665727204000000da06616d6f756e74da02746f2901da0461726773da07617070726f7665da0d7472616e736665725f66726f6dda0c6d61696e5f6163636f756e74630000000000000000000000000200000043000000732200000074006a0164018301010074026a0164028301010074036a016402830101006400530029034eda0863757272656e6379da40666636313534346561393465616165623564663038656438363363346139333865393132396162613663656565356633316236363831626465646531316238392904da125f5f616c6c6f7765645f63757272656e6379da03736574da0a5f5f6f70657261746f72da0a5f5f7472656173757279a900721d000000721d000000da00da045f5f5f5f14000000730a00000000010a01040106010401721f0000002905da0b6e616d655f6f665f6e6674da13636f6c6c656374696f6e5f636f6e74726163747211000000da0e63757272656e63795f7072696365da12726f79616c74795f70657263656e7461676563050000000000000008000000080000004300000073100100007c0064016b03731074006402830182017c0164016b03732074006403830182017c0264046b04733074006405830182017c0364046b047340740064068301820174016a027c0183017d0574016a037c0574048302735e74006407830182017c056a057c007c0274066a0774066a0864088d04010074097d06782c740a7c02830144005d207d0764097c03640a9c02740b74066a087c017c007c067c07170066043c0071825700740c7c017c0066021900640b6b0272fa7c0464006b0272c6740d640c83017d047c04640d6b0173d67400640e830182017c0464046b0573e67400640f8301820174066a087c0464109c02740c7c017c0066023c0064117c029b0064127c009b0064137c039b009d06530029144e721e0000007a144e616d652063616e6e6f7420626520656d7074797a23436f6c6c656374696f6e20636f6e74726163742063616e6e6f7420626520656d70747972060000007a1f43616e6e6f742073656c6c206e65676174697665204e465420616d6f756e747a2243616e6e6f742073656c6c20666f72206e656761746976652062616c616e636573217a1d496e76616c696420636f6c6c656374696f6e20696e746572666163652129047204000000721100000072120000007216000000e90100000029027211000000da057072696365467a03302e30e9320000007a1f4f7665722035302520726f79616c7479206973206e6f7420616c6c6f7765647a1f556e64657220302520726f79616c7479206973206e6f7420616c6c6f7765642902da08726563656976657272230000007a145375636365737366756c6c79206c697374656420fa01207a0520666f7220290eda0e417373657274696f6e4572726f72da0149da0d696d706f72745f6d6f64756c65da11656e666f7263655f696e74657266616365da1b666f726365645f636f6c6c656374696f6e5f696e746572666163657215000000da03637478da0474686973da0663616c6c6572da09626c6f636b5f6e756dda0572616e6765da085f5f6d61726b6574da135f5f726f79616c74795f726563656976657273da07646563696d616c290872200000007221000000721100000072220000007223000000da0a636f6c6c656374696f6eda116c697374696e675f756e697175655f6964da0169721d000000721d000000721e000000da0873656c6c5f6e66741c0000007326000000000310011001100110010a010e0106010c010a0104010e0220011001080108011001100214017239000000e905000000290472200000007221000000da0a6c697374696e675f6964da0776657273696f6e63040000000000000007000000060000004300000073b20000007c0364016b02722a74006a01640283017d047c046a027c007c0164038d02010064047c009b009d0253007c0064056b03733a74036406830182017c0164056b03734a74036407830182017c0264056b03735a7403640883018201740474056a067c017c007c02660419007d0574006a017c0183017d067c066a077c007c056409190074056a06640a8d030100640b7c05640c1900640d9c02740474056a067c017c007c0266043c0064047c009b009d025300290e4ee904000000720c0000002902722000000072210000007a165375636365737366756c6c7920726566756e64656420721e0000007a144e616d652063616e6e6f7420626520656d7074797a23436f6c6c656374696f6e20636f6e74726163742063616e6e6f7420626520656d7074797a1a4c697374696e672049442063616e6e6f7420626520656d70747972110000002903720400000072110000007212000000720600000072250000002902721100000072250000002908722a000000722b000000da0a726566756e645f6e667472290000007233000000722e00000072300000007210000000290772200000007221000000723b000000723c000000da0f6f6c645f6d61726b6574706c616365da0c6d61726b65745f656e7472797236000000721d000000721d000000721e000000723e00000036000000731e000000000308010a01060108010a011001100110010a0108010a010c010a021c01723e000000290572040000007221000000da0673656c6c6572723b000000723c0000006305000000000000000b0000000600000043000000738c0100007c0464016b02722e74006a01640283017d057c056a027c007c017c02640364048d04010064057c009b009d0253007c0064066b03733e74036407830182017c0164066b03734e74036408830182017c0264066b03735e74036409830182017c0364066b03736e7403640a8301820174006a017c0183017d0674006a0174046a05830083017d0774006a067c0674078302739a7403640b8301820174087c027c017c007c0366041900640c1900640d1b00640e14007d0874087c027c017c007c0366041900640c1900640d1b0074097c017c0066021900640f190014007d097c076a0a74087c027c017c007c0366041900640c19007c0818007c0918007c02740b6a0c64108d0301007c076a0a7c08740d6a058300740b6a0c64108d0301007c0964116b04900172467c076a0a7c0974097c017c006602190064121900740b6a0c64108d03010074087c027c017c007c03660419007d0a64117c0a640c190064139c0274087c027c017c007c0366043c007c066a0e7c006403740b6a0c64148d03010064057c009b009d02530029154e723d000000720c0000007224000000290472040000007221000000724100000072110000007a145375636365737366756c6c7920626f7567687420721e0000007a144e616d652063616e6e6f7420626520656d7074797a23436f6c6c656374696f6e20636f6e74726163742063616e6e6f7420626520656d7074797a1653656c6c65722063616e6e6f7420626520656d7074797a1a4c697374696e672049442063616e6e6f7420626520656d7074797a1d496e76616c696420636f6c6c656374696f6e20696e74657266616365217225000000e964000000e90200000072230000002903721100000072120000007216000000720600000072270000002902721100000072250000002903720400000072110000007212000000290f722a000000722b000000723e00000072290000007219000000da03676574722c000000722d000000723300000072340000007215000000722e0000007230000000721c0000007210000000290b720400000072210000007241000000723b000000723c000000723f00000072360000007217000000da03666565da07726f79616c7479da106f6c645f6d61726b65745f656e747279721d000000721d000000721e000000da076275795f6e66744b000000733a000000000308010a0106010c010a0110011001100110010a010e010e0106021c022001080104011c010a010c010a010a010801160110010201180112017248000000290672200000007221000000da1473746172745f63757272656e63795f7072696365da196675747572655f726f79616c74795f70657263656e74616765da0d61756374696f6e5f7374617274da0b61756374696f6e5f656e6463060000000000000008000000060000004300000073da0000007c0064016b03731074006402830182017c0164016b03732074006403830182017c0264046b04733074006405830182017c0364066b01734074006407830182017c0364046b05735074006408830182017c0474016b04736074006409830182017c057c046b0473707400640a8301820174026a037c0183017d0674026a047c0674058302738e7400640b830182017c066a067c00640c74076a0874076a09640d8d040100740a7d077c0274076a097c037c047c05640e9c05740b74076a097c017c007c0766043c00640f7c009b0064107c029b0064119d05530029124e721e0000007a144e616d652063616e6e6f7420626520656d7074797a23436f6c6c656374696f6e20636f6e74726163742063616e6e6f7420626520656d70747972060000007a2543616e6e6f742061756374696f6e20666f72206e656761746976652062616c616e6365732172260000007a1f4f7665722035302520726f79616c7479206973206e6f7420616c6c6f7765647a1f556e64657220302520726f79616c7479206973206e6f7420616c6c6f7765647a2141756374696f6e2063616e6e6f7420737461727420696e207468652070617374217a2441756374696f6e2063616e6e6f7420656e64206265666f726520697420737461727473217a1d496e76616c696420636f6c6c656374696f6e20696e74657266616365217224000000290472040000007211000000721200000072160000002905da0b63757272656e745f626964da1663757272656e745f686967686573745f626964646572724a000000724b000000724c0000007a145375636365737366756c6c79206c6973746564207a0520666f72207a0c20666f722061756374696f6e290c7229000000da036e6f77722a000000722b000000722c000000722d0000007215000000722e000000722f00000072300000007231000000da0a5f5f61756374696f6e732908722000000072210000007249000000724a000000724b000000724c00000072360000007237000000721d000000721d000000721e000000da0d73657475705f61756374696f6e6f0000007322000000000410011001100110011001100110010a010e0106010c010a01040202010601180272510000002905724100000072200000007221000000da0a61756374696f6e5f6964da0362696463050000000000000009000000060000004300000073360100007c0164016b03731074006402830182017c0264016b03732074006403830182017c0064016b03733074006404830182017c0364016b03734074006405830182017c0464066b047350740064078301820174017c007c027c017c03660419007d0574027c05640819006b047374740064098301820174027c05640a19006b0073887400640b830182017c05640c19007d067c05640d19007d077c047c066b0473a87400640e830182017c0774036a046b0373ba7400640f830182017c0074036a046b0373cc740064108301820174056a0674076a08830083017d087c077c006b0372f07c086a097c067c0764118d0201007c086a0a7c0474036a0b74036a0464128d0301007c047c05640c3c0074036a047c05640d3c007c0574017c007c027c017c0366043c0064137c049b0064147c019b009d04530029154e721e0000007a144e616d652063616e6e6f7420626520656d7074797a23436f6c6c656374696f6e20636f6e74726163742063616e6e6f7420626520656d7074797a1653656c6c65722063616e6e6f7420626520656d7074797a1a41756374696f6e2049442063616e6e6f7420626520656d70747972060000007a19426964206d75737420626520686967686572207468616e2030724b0000007a1b41756374696f6e20686173206e6f74207374617274656420796574724c0000007a1141756374696f6e2068617320656e646564724d000000724e0000007a2f426964206d75737420626520686967686572207468616e207468652063757272656e742068696768657374206269647a22596f752061726520616c7265616479207468652068696768657374206269646465727a22596f752063616e6e6f7420626964206f6e20796f7572206f776e2061756374696f6e29027211000000721200000029037211000000721200000072160000007a115375636365737366756c6c7920626964207a04206f6e20290c72290000007250000000724f000000722e0000007230000000722a000000722b0000007219000000724400000072100000007215000000722f000000290972410000007220000000722100000072520000007253000000da0761756374696f6eda0b686967686573745f626964da0e686967686573745f6269646465727217000000721d000000721d000000721e000000da0b6269645f61756374696f6e89000000732a000000000310011001100110011001100114011401080108011001120112010e0108010e01140108010a01100172570000002904724100000072200000007221000000725200000063040000000000000007000000060000004300000073ec0000007c0164016b03731074006402830182017c0264016b03732074006403830182017c0064016b03733074006404830182017c0364016b037340740064058301820174017c007c027c017c03660419007d047c0464066b037360740064078301820174027c04640819006b007374740064098301820174036a047c006b0273867400640a830182017c007c04640b19006b0372b674056a0674076a08830083017d057c056a097c04640c19007c04640b1900640d8d02010074056a067c0283017d067c066a097c01640e74036a04640f8d030100640674017c007c027c017c0366043c0064107c019b009d02530029114e721e0000007a144e616d652063616e6e6f7420626520656d7074797a23436f6c6c656374696f6e20636f6e74726163742063616e6e6f7420626520656d7074797a1653656c6c65722063616e6e6f7420626520656d7074797a1a41756374696f6e2049442063616e6e6f7420626520656d70747972060000007a1641756374696f6e20646f6573206e6f74206578697374724b0000007a1b41756374696f6e2068617320616c726561647920737461727465647a264f6e6c79207468652073656c6c65722063616e2063616e63656c207468652061756374696f6e724e000000724d000000290272110000007212000000722400000029037204000000721100000072120000007a235375636365737366756c6c792063616e63656c6c65642041756374696f6e20666f7220290a72290000007250000000724f000000722e0000007230000000722a000000722b00000072190000007244000000721000000029077241000000722000000072210000007252000000725400000072170000007236000000721d000000721d000000721e000000da0e63616e63656c5f61756374696f6ea300000073200000000003100110011001100110011001140112010c010e010c010a010a0112011001725800000063040000000000000007000000060000004300000073e20000007c0164016b03731074006402830182017c0264016b03732074006403830182017c0064016b03733074006404830182017c0364016b037340740064058301820174017c007c027c017c03660419007d047c0464066b037360740064078301820174027c04640819006b047374740064098301820174036a0474056a06830083017d057c056a077c04640a19007c00640b8d02010074036a047c0283017d067c066a077c01640c7c04640d1900640e8d030100640674017c007c027c017c0366043c007c007c04640f190064109c0274087c027c0166023c0064117c019b009d02530029124e721e0000007a144e616d652063616e6e6f7420626520656d7074797a23436f6c6c656374696f6e20636f6e74726163742063616e6e6f7420626520656d7074797a1653656c6c65722063616e6e6f7420626520656d7074797a1a41756374696f6e2049442063616e6e6f7420626520656d70747972060000007a1641756374696f6e20646f6573206e6f74206578697374724c0000007a1941756374696f6e20686173206e6f7420656e64656420796574724d0000002902721100000072120000007224000000724e0000002903720400000072110000007212000000724a00000029027227000000da0a70657263656e746167657a235375636365737366756c6c792066696e616c697a65642041756374696f6e20666f7220290972290000007250000000724f000000722a000000722b000000721900000072440000007210000000723400000029077241000000722000000072210000007252000000725400000072170000007236000000721d000000721d000000721e000000da1066696e616c697a655f61756374696f6eb8000000731e000000000310011001100110011001100114010e0112010a010a010a0110021601725a00000029017203000000630100000000000000010000000200000043000000732400000074006a0174026a0383006b027316740464018301820174056a067c00830101006400530029024e7a1d4f6e6c7920746865206f70657261746f722063616e20646f20746869732907722e0000007230000000721b000000724400000072290000007219000000721a00000029017203000000721d000000721d000000721e000000da176368616e67655f616c6c6f7765645f63757272656e6379cd000000730400000000021601725b0000002901da0761646472657373630100000000000000010000000200000043000000732400000074006a0174026a0383006b027316740464018301820174056a067c00830101006400530029024e7a1d4f6e6c7920746865206f70657261746f722063616e20646f20746869732907722e0000007230000000721b00000072440000007229000000721c000000721a0000002901725c000000721d000000721d000000721e000000da0f6368616e67655f7472656173757279d3000000730400000000021601725d000000630100000000000000010000000200000043000000732400000074006a0174026a0383006b027316740464018301820174026a057c00830101006400530029024e7a1d4f6e6c7920746865206f70657261746f722063616e20646f20746869732906722e0000007230000000721b00000072440000007229000000721a0000002901725c000000721d000000721d000000721e000000da0f6368616e67655f6f70657261746f72d9000000730400000000021601725e0000004e29037204000000721100000072120000002903721100000072040000007212000000290472040000007211000000721200000072160000002901723a0000002901723a000000291eda09696d706f72746c6962722a000000da085661726961626c657219000000721b000000da044861736872330000007250000000721c0000007234000000da0b466f726569676e48617368da145f5f6f6c645f6d61726b65745f76657273696f6eda0446756e63722d000000721f000000da085f5f6578706f7274da03737472da03696e74da05666c6f61747239000000723e0000007248000000da086461746574696d65725100000072570000007258000000725a000000725b000000725d000000725e000000721d000000721d000000721d000000721e000000da083c6d6f64756c653e0100000073560000000401040108010c0106010801060108010c0104010a01020104010a01060116010c0308080601060112180602181306021a22060104010401161706010601121806010601101306010401121306011005060110050601