tx · 9jrnk6eaDFn3JSrhCYTNQrWB6fCrrvHEwrWZgsVdM7To 3PPpppPpSCRStzVGeZTPsZb5h467qbyqadm: -0.01400000 Waves 2019.10.16 21:28 [1753083] smart account 3PPpppPpSCRStzVGeZTPsZb5h467qbyqadm > SELF 0.00000000 Waves
{ "type": 13, "id": "9jrnk6eaDFn3JSrhCYTNQrWB6fCrrvHEwrWZgsVdM7To", "fee": 1400000, "feeAssetId": null, "timestamp": 1571250514464, "version": 1, "sender": "3PPpppPpSCRStzVGeZTPsZb5h467qbyqadm", "senderPublicKey": "9h8XTnBfjfoV5MWJVDUMkaLNMZbWpUqrTz1wjaAejUez", "proofs": [ "58EFCfy66QgZzEMKSzABMcE4HhjBp69PXtXRwNSQVj3NL9hae1Ak9faXoGo5vYnmNPcj5G7u2hPxk5anfYSTXprf" ], "script": "base64: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", "chainId": 87, "height": 1753083, "spentComplexity": 0 } View: original | compacted Prev: 5kgVNdUpiToDFQ5vmM3zu5PjfCRgS8upsjn4DfcdzhVn Next: 4se9jS3yRz5YkVqs8GzYoAebzjYt7pRxR8Xso2PL4Esn Diff:
Old | New | Differences | |
---|---|---|---|
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | 4 | let uTokenId = base58'GHh7EMnVnUBCYNJMktuLPVr3P2oCqBCb4c87fBCZ5CzY' | |
5 | + | ||
6 | + | let admin = addressFromStringValue("3P96VpN2dBS1111111ydADa5a6AD1Un9iUv") | |
7 | + | ||
8 | + | let shutdownFlag = match getBoolean(this, "shutdown_flag") { | |
9 | + | case bool: Boolean => | |
10 | + | bool | |
11 | + | case _: Unit => | |
12 | + | false | |
13 | + | case _ => | |
14 | + | throw() | |
15 | + | } | |
16 | + | ||
17 | + | let shutdownMessage = match getString(this, "shutdown_message") { | |
18 | + | case str: String => | |
19 | + | str | |
20 | + | case _: Unit => | |
21 | + | "Forbidden" | |
22 | + | case _ => | |
23 | + | throw() | |
24 | + | } | |
25 | + | ||
26 | + | let reserve = match getInteger(this, "reserve") { | |
27 | + | case int: Int => | |
28 | + | int | |
29 | + | case _: Unit => | |
30 | + | 0 | |
31 | + | case _ => | |
32 | + | throw() | |
33 | + | } | |
34 | + | ||
35 | + | let balance = match getInteger(this, "balance") { | |
36 | + | case int: Int => | |
37 | + | int | |
38 | + | case _: Unit => | |
39 | + | 0 | |
40 | + | case _ => | |
41 | + | throw() | |
42 | + | } | |
5 | 43 | ||
6 | 44 | func checkStatus (address) = { | |
7 | 45 | let statusUnlimited = match getBoolean(this, (address + "_unlimited")) { | |
27 | 65 | ||
28 | 66 | ||
29 | 67 | @Callable(i) | |
30 | - | func addAsset (assetId) = { | |
31 | - | let addingPrice = (100 * 100000000) | |
32 | - | let addingPriceStr = "100" | |
33 | - | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
34 | - | if (if (isDefined(payment.assetId)) | |
35 | - | then (payment.assetId != uTokenId) | |
36 | - | else false) | |
37 | - | then throw("OTCu or WAVES only") | |
38 | - | else if ((payment.amount != addingPrice)) | |
39 | - | then throw((("You have to pay " + addingPriceStr) + " OTCu or WAVES")) | |
40 | - | else if (!(isDefined(assetInfo(fromBase58String(assetId))))) | |
41 | - | then throw("There is no asset with specified id") | |
68 | + | func addAsset (assetId) = if (shutdownFlag) | |
69 | + | then throw(shutdownMessage) | |
70 | + | else { | |
71 | + | let addingPrice = (100 * 100000000) | |
72 | + | let addingPriceStr = "100" | |
73 | + | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
74 | + | if (if (isDefined(payment.assetId)) | |
75 | + | then (payment.assetId != uTokenId) | |
76 | + | else false) | |
77 | + | then throw("OTCu or WAVES only") | |
78 | + | else if ((payment.amount != addingPrice)) | |
79 | + | then throw((("You have to pay " + addingPriceStr) + " OTCu or WAVES")) | |
80 | + | else if (!(isDefined(assetInfo(fromBase58String(assetId))))) | |
81 | + | then throw("There is no asset with specified id") | |
82 | + | else { | |
83 | + | let assets = match getString(this, "assets") { | |
84 | + | case str: String => | |
85 | + | str | |
86 | + | case _: Unit => | |
87 | + | "" | |
88 | + | case _ => | |
89 | + | throw() | |
90 | + | } | |
91 | + | if (isDefined(indexOf(assets, assetId))) | |
92 | + | then throw("Asset is already available") | |
93 | + | else { | |
94 | + | let list0 = [DataEntry("assets", ((assets + assetId) + ","))] | |
95 | + | let list1 = if ((payment.assetId == uTokenId)) | |
96 | + | then DataEntry("reserve", (reserve + payment.amount)) :: list0 | |
97 | + | else if (!(isDefined(payment.assetId))) | |
98 | + | then DataEntry("balance", (balance + payment.amount)) :: list0 | |
99 | + | else list0 | |
100 | + | WriteSet(list1) | |
101 | + | } | |
102 | + | } | |
103 | + | } | |
104 | + | ||
105 | + | ||
106 | + | ||
107 | + | @Callable(i) | |
108 | + | func pro () = if (shutdownFlag) | |
109 | + | then throw(shutdownMessage) | |
110 | + | else { | |
111 | + | let address = toBase58String(i.caller.bytes) | |
112 | + | let unlimitedPrice = (50 * 100000000) | |
113 | + | let unlimitedPriceStr = "50" | |
114 | + | let monthPrice = (10 * 100000000) | |
115 | + | let monthPriceStr = "10" | |
116 | + | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
117 | + | if (if (isDefined(payment.assetId)) | |
118 | + | then (payment.assetId != uTokenId) | |
119 | + | else false) | |
120 | + | then throw("OTCu or WAVES only") | |
121 | + | else if (if ((payment.amount != unlimitedPrice)) | |
122 | + | then (payment.amount != monthPrice) | |
123 | + | else false) | |
124 | + | then throw("Invalid payment") | |
42 | 125 | else { | |
43 | - | let assets = match getString(this, "assets") { | |
44 | - | case str: String => | |
45 | - | str | |
126 | + | let unlimited = (payment.amount == unlimitedPrice) | |
127 | + | let currentUnlimited = match getBoolean(this, (address + "_unlimited")) { | |
128 | + | case bool: Boolean => | |
129 | + | bool | |
46 | 130 | case _: Unit => | |
47 | - | | |
131 | + | false | |
48 | 132 | case _ => | |
49 | 133 | throw() | |
50 | 134 | } | |
51 | - | if (isDefined(indexOf(assets, assetId))) | |
52 | - | then throw("Asset is already available") | |
135 | + | let currentTime = match getInteger(this, (address + "_time")) { | |
136 | + | case int: Int => | |
137 | + | int | |
138 | + | case _: Unit => | |
139 | + | lastBlock.timestamp | |
140 | + | case _ => | |
141 | + | throw() | |
142 | + | } | |
143 | + | if (currentUnlimited) | |
144 | + | then throw("You have unlimited PRO status already. What do you want?") | |
53 | 145 | else { | |
54 | - | let list0 = [DataEntry("assets", ((assets + assetId) + ","))] | |
55 | - | let reserve = match getInteger(this, "reserve") { | |
56 | - | case int: Int => | |
57 | - | int | |
58 | - | case _: Unit => | |
59 | - | 0 | |
60 | - | case _ => | |
61 | - | throw() | |
62 | - | } | |
63 | - | let balance = match getInteger(this, "balance") { | |
64 | - | case int: Int => | |
65 | - | int | |
66 | - | case _: Unit => | |
67 | - | 0 | |
68 | - | case _ => | |
69 | - | throw() | |
70 | - | } | |
146 | + | let month = 2629743000 | |
147 | + | let list0 = [DataEntry((address + "_unlimited"), unlimited), DataEntry((address + "_time"), if (unlimited) | |
148 | + | then 0 | |
149 | + | else (currentTime + month))] | |
71 | 150 | let list1 = if ((payment.assetId == uTokenId)) | |
72 | 151 | then DataEntry("reserve", (reserve + payment.amount)) :: list0 | |
73 | 152 | else if (!(isDefined(payment.assetId))) | |
76 | 155 | WriteSet(list1) | |
77 | 156 | } | |
78 | 157 | } | |
79 | - | } | |
158 | + | } | |
80 | 159 | ||
81 | 160 | ||
82 | 161 | ||
83 | 162 | @Callable(i) | |
84 | - | func pro () = { | |
85 | - | let address = toBase58String(i.caller.bytes) | |
86 | - | let unlimitedPrice = (50 * 100000000) | |
87 | - | let unlimitedPriceStr = "50" | |
88 | - | let monthPrice = (10 * 100000000) | |
89 | - | let monthPriceStr = "10" | |
90 | - | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
91 | - | if (if (isDefined(payment.assetId)) | |
92 | - | then (payment.assetId != uTokenId) | |
93 | - | else false) | |
94 | - | then throw("OTCu or WAVES only") | |
95 | - | else if (if ((payment.amount != unlimitedPrice)) | |
96 | - | then (payment.amount != monthPrice) | |
97 | - | else false) | |
98 | - | then throw("Invalid payment") | |
99 | - | else { | |
100 | - | let unlimited = (payment.amount == unlimitedPrice) | |
101 | - | let currentUnlimited = match getBoolean(this, (address + "_unlimited")) { | |
102 | - | case bool: Boolean => | |
103 | - | bool | |
104 | - | case _: Unit => | |
105 | - | false | |
106 | - | case _ => | |
107 | - | throw() | |
108 | - | } | |
109 | - | let currentTime = match getInteger(this, (address + "_time")) { | |
110 | - | case int: Int => | |
111 | - | int | |
112 | - | case _: Unit => | |
113 | - | lastBlock.timestamp | |
114 | - | case _ => | |
115 | - | throw() | |
116 | - | } | |
117 | - | if (currentUnlimited) | |
118 | - | then throw("You have unlimited PRO status already. What do you want?") | |
119 | - | else { | |
120 | - | let month = 2629743000 | |
121 | - | let list0 = [DataEntry((address + "_unlimited"), unlimited), DataEntry((address + "_time"), if (unlimited) | |
122 | - | then 0 | |
123 | - | else (currentTime + month))] | |
124 | - | let reserve = match getInteger(this, "reserve") { | |
125 | - | case int: Int => | |
126 | - | int | |
127 | - | case _: Unit => | |
128 | - | 0 | |
129 | - | case _ => | |
130 | - | throw() | |
131 | - | } | |
132 | - | let balance = match getInteger(this, "balance") { | |
133 | - | case int: Int => | |
134 | - | int | |
135 | - | case _: Unit => | |
136 | - | 0 | |
137 | - | case _ => | |
138 | - | throw() | |
139 | - | } | |
140 | - | let list1 = if ((payment.assetId == uTokenId)) | |
141 | - | then DataEntry("reserve", (reserve + payment.amount)) :: list0 | |
142 | - | else if (!(isDefined(payment.assetId))) | |
143 | - | then DataEntry("balance", (balance + payment.amount)) :: list0 | |
144 | - | else list0 | |
145 | - | WriteSet(list1) | |
146 | - | } | |
147 | - | } | |
148 | - | } | |
163 | + | func buyUtilityToken () = if (shutdownFlag) | |
164 | + | then throw(shutdownMessage) | |
165 | + | else { | |
166 | + | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
167 | + | if (isDefined(payment.assetId)) | |
168 | + | then throw("WAVES only") | |
169 | + | else if ((payment.amount > reserve)) | |
170 | + | then throw("Not enougth asset in dApp") | |
171 | + | else ScriptResult(WriteSet([DataEntry("reserve", (reserve - payment.amount)), DataEntry("balance", (balance + payment.amount))]), TransferSet([ScriptTransfer(i.caller, payment.amount, uTokenId)])) | |
172 | + | } | |
149 | 173 | ||
150 | 174 | ||
151 | 175 | ||
152 | 176 | @Callable(i) | |
153 | - | func buyUtilityToken () = { | |
154 | - | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
155 | - | if (isDefined(payment.assetId)) | |
156 | - | then throw("WAVES only") | |
157 | - | else { | |
158 | - | let reserve = match getInteger(this, "reserve") { | |
159 | - | case int: Int => | |
160 | - | int | |
161 | - | case _: Unit => | |
162 | - | 0 | |
163 | - | case _ => | |
164 | - | throw() | |
165 | - | } | |
166 | - | let balance = match getInteger(this, "balance") { | |
167 | - | case int: Int => | |
168 | - | int | |
169 | - | case _: Unit => | |
170 | - | 0 | |
171 | - | case _ => | |
172 | - | throw() | |
173 | - | } | |
174 | - | if ((payment.amount > reserve)) | |
175 | - | then throw("Not enougth asset in dApp") | |
176 | - | else ScriptResult(WriteSet([DataEntry("reserve", (reserve - payment.amount)), DataEntry("balance", (balance + payment.amount))]), TransferSet([ScriptTransfer(i.caller, payment.amount, uTokenId)])) | |
177 | - | } | |
178 | - | } | |
177 | + | func makeSell (priceAsset,priceAssetAmount,all,password) = if (shutdownFlag) | |
178 | + | then throw(shutdownMessage) | |
179 | + | else if (if ((priceAsset != "WAVES")) | |
180 | + | then !(isDefined(assetInfo(fromBase58String(priceAsset)))) | |
181 | + | else false) | |
182 | + | then throw("There is no asset with specified id") | |
183 | + | else if ((0 >= priceAssetAmount)) | |
184 | + | then throw("Amount of price asset must be positive") | |
185 | + | else { | |
186 | + | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
187 | + | if ((0 >= payment.amount)) | |
188 | + | then throw("Amount must be positive") | |
189 | + | else { | |
190 | + | let amountAsset = match payment.assetId { | |
191 | + | case p: ByteVector => | |
192 | + | toBase58String(p) | |
193 | + | case _ => | |
194 | + | "WAVES" | |
195 | + | } | |
196 | + | let assets = valueOrErrorMessage(getString(this, "assets"), "There are not available assets") | |
197 | + | if (if (!(isDefined(indexOf(assets, priceAsset)))) | |
198 | + | then true | |
199 | + | else !(isDefined(indexOf(assets, amountAsset)))) | |
200 | + | then throw("Asset are not available for trading") | |
201 | + | else { | |
202 | + | let address = toBase58String(i.caller.bytes) | |
203 | + | if (if (!(checkStatus(address))) | |
204 | + | then if (all) | |
205 | + | then true | |
206 | + | else (password != "") | |
207 | + | else false) | |
208 | + | then throw("You must have pro status to use these features") | |
209 | + | else { | |
210 | + | let orderId = ("order_" + toBase58String(i.transactionId)) | |
211 | + | let passwordValid = fromBase58String(password) | |
212 | + | let data = (((((((((((((((("sell" + "_") + toString(payment.amount)) + "_") + amountAsset) + "_") + toString(priceAssetAmount)) + "_") + priceAsset) + "_") + address) + "_") + toString(all)) + "_") + password) + "_") + toString(0)) | |
213 | + | WriteSet([DataEntry(orderId, data)]) | |
214 | + | } | |
215 | + | } | |
216 | + | } | |
217 | + | } | |
179 | 218 | ||
180 | 219 | ||
181 | 220 | ||
182 | 221 | @Callable(i) | |
183 | - | func makeSell (priceAsset,priceAssetAmount,all,password) = if (if ((priceAsset != "WAVES")) | |
184 | - | then !(isDefined(assetInfo(fromBase58String(priceAsset)))) | |
185 | - | else false) | |
186 | - | then throw("There is no asset with specified id") | |
187 | - | else if ((0 >= priceAssetAmount)) | |
188 | - | then throw("Amount of price asset must be positive") | |
189 | - | else { | |
190 | - | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
191 | - | if ((0 >= payment.amount)) | |
192 | - | then throw("Amount must be positive") | |
193 | - | else { | |
194 | - | let amountAsset = match payment.assetId { | |
195 | - | case p: ByteVector => | |
196 | - | toBase58String(p) | |
197 | - | case _ => | |
198 | - | "WAVES" | |
199 | - | } | |
200 | - | let assets = valueOrErrorMessage(getString(this, "assets"), "There are not available assets") | |
201 | - | if (if (!(isDefined(indexOf(assets, priceAsset)))) | |
202 | - | then true | |
203 | - | else !(isDefined(indexOf(assets, amountAsset)))) | |
204 | - | then throw("Asset are not available for trading") | |
205 | - | else { | |
206 | - | let address = toBase58String(i.caller.bytes) | |
207 | - | if (if (!(checkStatus(address))) | |
208 | - | then if (all) | |
209 | - | then true | |
210 | - | else (password != "") | |
211 | - | else false) | |
212 | - | then throw("You must have pro status to use these features") | |
213 | - | else { | |
214 | - | let orderId = ("order_" + toBase58String(i.transactionId)) | |
215 | - | let passwordValid = fromBase58String(password) | |
216 | - | let data = (((((((((((((((("sell" + "_") + toString(payment.amount)) + "_") + amountAsset) + "_") + toString(priceAssetAmount)) + "_") + priceAsset) + "_") + address) + "_") + toString(all)) + "_") + password) + "_") + toString(0)) | |
217 | - | WriteSet([DataEntry(orderId, data)]) | |
218 | - | } | |
219 | - | } | |
220 | - | } | |
221 | - | } | |
222 | + | func makeBuy (amountAsset,amount,all,password) = if (shutdownFlag) | |
223 | + | then throw(shutdownMessage) | |
224 | + | else if (if ((amountAsset != "WAVES")) | |
225 | + | then !(isDefined(assetInfo(fromBase58String(amountAsset)))) | |
226 | + | else false) | |
227 | + | then throw("There is no asset with specified id") | |
228 | + | else if ((0 >= amount)) | |
229 | + | then throw("Amount must be positive") | |
230 | + | else { | |
231 | + | let payment = valueOrErrorMessage(i.payment, "where is payment?") | |
232 | + | let priceAssetAmount = payment.amount | |
233 | + | if ((0 >= priceAssetAmount)) | |
234 | + | then throw("amount must be positive") | |
235 | + | else { | |
236 | + | let priceAsset = match payment.assetId { | |
237 | + | case p: ByteVector => | |
238 | + | toBase58String(p) | |
239 | + | case _ => | |
240 | + | "WAVES" | |
241 | + | } | |
242 | + | let assets = valueOrErrorMessage(getString(this, "assets"), "There are not available assets") | |
243 | + | if (if (!(isDefined(indexOf(assets, priceAsset)))) | |
244 | + | then true | |
245 | + | else !(isDefined(indexOf(assets, amountAsset)))) | |
246 | + | then throw("Asset are not available for trading") | |
247 | + | else { | |
248 | + | let address = toBase58String(i.caller.bytes) | |
249 | + | if (if (!(checkStatus(address))) | |
250 | + | then if (all) | |
251 | + | then true | |
252 | + | else (password != "") | |
253 | + | else false) | |
254 | + | then throw("You must have pro status to use these features") | |
255 | + | else { | |
256 | + | let orderId = ("order_" + toBase58String(i.transactionId)) | |
257 | + | if ((amount == 0)) | |
258 | + | then throw("invalid buy amount") | |
259 | + | else { | |
260 | + | let data = (((((((((((((((("buy" + "_") + toString(amount)) + "_") + amountAsset) + "_") + toString(priceAssetAmount)) + "_") + priceAsset) + "_") + address) + "_") + toString(all)) + "_") + password) + "_") + toString(0)) | |
261 | + | WriteSet([DataEntry(orderId, data)]) | |
262 | + | } | |
263 | + | } | |
264 | + | } | |
265 | + | } | |
266 | + | } | |
222 | 267 | ||
223 | 268 | ||
224 | 269 | ||
225 | 270 | @Callable(i) | |
226 | - | func makeBuy (amountAsset,amount,all,password) = if (if ((amountAsset != "WAVES")) | |
227 | - | then !(isDefined(assetInfo(fromBase58String(amountAsset)))) | |
228 | - | else false) | |
229 | - | then throw("There is no asset with specified id") | |
230 | - | else if ((0 >= amount)) | |
231 | - | then throw("Amount must be positive") | |
232 | - | else { | |
233 | - | let payment = valueOrErrorMessage(i.payment, "where is payment?") | |
234 | - | let priceAssetAmount = payment.amount | |
235 | - | if ((0 >= priceAssetAmount)) | |
236 | - | then throw("amount must be positive") | |
237 | - | else { | |
238 | - | let priceAsset = match payment.assetId { | |
239 | - | case p: ByteVector => | |
240 | - | toBase58String(p) | |
241 | - | case _ => | |
242 | - | "WAVES" | |
243 | - | } | |
244 | - | let assets = valueOrErrorMessage(getString(this, "assets"), "There are not available assets") | |
245 | - | if (if (!(isDefined(indexOf(assets, priceAsset)))) | |
246 | - | then true | |
247 | - | else !(isDefined(indexOf(assets, amountAsset)))) | |
248 | - | then throw("Asset are not available for trading") | |
271 | + | func takeSell (orderId,sig) = if (shutdownFlag) | |
272 | + | then throw(shutdownMessage) | |
273 | + | else { | |
274 | + | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
275 | + | let priceAssetAmount = payment.amount | |
276 | + | if ((0 >= priceAssetAmount)) | |
277 | + | then throw("Amount must be positive") | |
278 | + | else { | |
279 | + | let priceAsset = match payment.assetId { | |
280 | + | case p: ByteVector => | |
281 | + | toBase58String(p) | |
282 | + | case _ => | |
283 | + | "WAVES" | |
284 | + | } | |
285 | + | let data = valueOrErrorMessage(getString(this, orderId), "Invalid order id") | |
286 | + | let parts = split(data, "_") | |
287 | + | let orderType = parts[0] | |
288 | + | let orderAmount = parseIntValue(parts[1]) | |
289 | + | let orderAmountAsset = parts[2] | |
290 | + | let orderPriceAssetAmount = parseIntValue(parts[3]) | |
291 | + | let orderPriceAsset = parts[4] | |
292 | + | let orderOwner = value(addressFromString(parts[5])) | |
293 | + | let orderAll = if ((parts[6] == "true")) | |
294 | + | then true | |
295 | + | else false | |
296 | + | let orderPassword = parts[7] | |
297 | + | let orderSpent = parseIntValue(parts[8]) | |
298 | + | if ((orderType != "sell")) | |
299 | + | then throw("Invalid order type") | |
300 | + | else if ((orderPriceAsset != priceAsset)) | |
301 | + | then throw(("Payment asset must be " + orderPriceAsset)) | |
249 | 302 | else { | |
250 | - | let address = toBase58String(i.caller.bytes) | |
251 | - | if (if (!(checkStatus(address))) | |
252 | - | then if (all) | |
253 | - | then true | |
254 | - | else (password != "") | |
255 | - | else false) | |
256 | - | then throw("You must have pro status to use these features") | |
303 | + | let valid = if ((orderPassword != "")) | |
304 | + | then sigVerify(i.callerPublicKey, fromBase58String(sig), fromBase58String(orderPassword)) | |
305 | + | else true | |
306 | + | if (!(valid)) | |
307 | + | then throw("The order is private") | |
257 | 308 | else { | |
258 | - | let | |
309 | + | let amount = ((priceAssetAmount * orderAmount) / orderPriceAssetAmount) | |
259 | 310 | if ((amount == 0)) | |
260 | - | then throw("invalid buy amount") | |
261 | - | else { | |
262 | - | let data = (((((((((((((((("buy" + "_") + toString(amount)) + "_") + amountAsset) + "_") + toString(priceAssetAmount)) + "_") + priceAsset) + "_") + address) + "_") + toString(all)) + "_") + password) + "_") + toString(0)) | |
263 | - | WriteSet([DataEntry(orderId, data)]) | |
264 | - | } | |
311 | + | then throw("Invalid amount") | |
312 | + | else if (if (orderAll) | |
313 | + | then (orderAmount > amount) | |
314 | + | else false) | |
315 | + | then throw("You must take all or none") | |
316 | + | else if ((amount > (orderAmount - orderSpent))) | |
317 | + | then throw("Not enougth asset in order") | |
318 | + | else { | |
319 | + | let newData = (dropRight(data, size(parts[8])) + toString((orderSpent + amount))) | |
320 | + | let toCaller = ScriptTransfer(i.caller, amount, if ((orderAmountAsset == "WAVES")) | |
321 | + | then unit | |
322 | + | else fromBase58String(orderAmountAsset)) | |
323 | + | let toOwner = ScriptTransfer(orderOwner, priceAssetAmount, if ((orderPriceAsset == "WAVES")) | |
324 | + | then unit | |
325 | + | else fromBase58String(orderPriceAsset)) | |
326 | + | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([toCaller, toOwner])) | |
327 | + | } | |
265 | 328 | } | |
266 | 329 | } | |
267 | - | ||
268 | - | ||
330 | + | } | |
331 | + | } | |
269 | 332 | ||
270 | 333 | ||
271 | 334 | ||
272 | 335 | @Callable(i) | |
273 | - | func takeSell (orderId,sig) = { | |
274 | - | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
275 | - | let priceAssetAmount = payment.amount | |
276 | - | if ((0 >= priceAssetAmount)) | |
277 | - | then throw("Amount must be positive") | |
278 | - | else { | |
279 | - | let priceAsset = match payment.assetId { | |
280 | - | case p: ByteVector => | |
281 | - | toBase58String(p) | |
282 | - | case _ => | |
283 | - | "WAVES" | |
284 | - | } | |
285 | - | let data = valueOrErrorMessage(getString(this, orderId), "Invalid order id") | |
286 | - | let parts = split(data, "_") | |
287 | - | let orderType = parts[0] | |
288 | - | let orderAmount = parseIntValue(parts[1]) | |
289 | - | let orderAmountAsset = parts[2] | |
290 | - | let orderPriceAssetAmount = parseIntValue(parts[3]) | |
291 | - | let orderPriceAsset = parts[4] | |
292 | - | let orderOwner = value(addressFromString(parts[5])) | |
293 | - | let orderAll = if ((parts[6] == "true")) | |
294 | - | then true | |
295 | - | else false | |
296 | - | let orderPassword = parts[7] | |
297 | - | let orderSpent = parseIntValue(parts[8]) | |
298 | - | if ((orderType != "sell")) | |
299 | - | then throw("Invalid order type") | |
300 | - | else if ((orderPriceAsset != priceAsset)) | |
301 | - | then throw(("Payment asset must be " + orderPriceAsset)) | |
302 | - | else { | |
303 | - | let valid = if ((orderPassword != "")) | |
304 | - | then sigVerify(i.callerPublicKey, fromBase58String(sig), fromBase58String(orderPassword)) | |
305 | - | else true | |
306 | - | if (!(valid)) | |
307 | - | then throw("The order is private") | |
308 | - | else { | |
309 | - | let amount = ((priceAssetAmount * orderAmount) / orderPriceAssetAmount) | |
310 | - | if ((amount == 0)) | |
311 | - | then throw("Invalid amount") | |
312 | - | else if (if (orderAll) | |
313 | - | then (orderAmount > amount) | |
314 | - | else false) | |
315 | - | then throw("You must take all or none") | |
316 | - | else if ((amount > (orderAmount - orderSpent))) | |
317 | - | then throw("Not enougth asset in order") | |
318 | - | else { | |
319 | - | let newData = (dropRight(data, size(parts[8])) + toString((orderSpent + amount))) | |
320 | - | let toCaller = ScriptTransfer(i.caller, amount, if ((orderAmountAsset == "WAVES")) | |
321 | - | then unit | |
322 | - | else fromBase58String(orderAmountAsset)) | |
323 | - | let toOwner = ScriptTransfer(orderOwner, priceAssetAmount, if ((orderPriceAsset == "WAVES")) | |
324 | - | then unit | |
325 | - | else fromBase58String(orderPriceAsset)) | |
326 | - | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([toCaller, toOwner])) | |
327 | - | } | |
328 | - | } | |
329 | - | } | |
330 | - | } | |
331 | - | } | |
332 | - | ||
333 | - | ||
334 | - | ||
335 | - | @Callable(i) | |
336 | - | func takeBuy (orderId,sig) = { | |
337 | - | let payment = valueOrErrorMessage(i.payment, "where is payment?") | |
338 | - | let amount = payment.amount | |
339 | - | if ((0 >= amount)) | |
340 | - | then throw("amount must be positive") | |
341 | - | else { | |
342 | - | let amountAsset = match payment.assetId { | |
343 | - | case p: ByteVector => | |
344 | - | toBase58String(p) | |
345 | - | case _ => | |
346 | - | "WAVES" | |
347 | - | } | |
348 | - | let data = valueOrErrorMessage(getString(this, orderId), "Invalid order id") | |
349 | - | let parts = split(data, "_") | |
350 | - | let orderType = parts[0] | |
351 | - | let orderAmount = parseIntValue(parts[1]) | |
352 | - | let orderAmountAsset = parts[2] | |
353 | - | let orderPriceAssetAmount = parseIntValue(parts[3]) | |
354 | - | let orderPriceAsset = parts[4] | |
355 | - | let orderOwner = value(addressFromString(parts[5])) | |
356 | - | let orderAll = if ((parts[6] == "true")) | |
357 | - | then true | |
358 | - | else false | |
359 | - | let orderPassword = parts[7] | |
360 | - | let orderSpent = parseIntValue(parts[8]) | |
361 | - | if ((orderType != "buy")) | |
362 | - | then throw("Invalid order type") | |
363 | - | else if ((orderAmountAsset != amountAsset)) | |
364 | - | then throw(("payment asset must be " + orderAmountAsset)) | |
365 | - | else { | |
366 | - | let valid = if ((orderPassword != "")) | |
367 | - | then sigVerify(i.callerPublicKey, fromBase58String(sig), fromBase58String(orderPassword)) | |
368 | - | else true | |
369 | - | if (!(valid)) | |
370 | - | then throw("The order is private") | |
371 | - | else { | |
372 | - | let priceAssetAmount = ((amount * orderPriceAssetAmount) / orderAmount) | |
373 | - | if ((priceAssetAmount == 0)) | |
374 | - | then throw("Invalid amount") | |
375 | - | else if (if (orderAll) | |
376 | - | then (orderPriceAssetAmount > priceAssetAmount) | |
377 | - | else false) | |
378 | - | then throw("You must take all or none") | |
379 | - | else if ((priceAssetAmount > (orderPriceAssetAmount - orderSpent))) | |
380 | - | then throw("not enougth asset in order") | |
381 | - | else { | |
382 | - | let newData = (dropRight(data, size(parts[8])) + toString((orderSpent + priceAssetAmount))) | |
383 | - | let toCaller = ScriptTransfer(i.caller, priceAssetAmount, if ((orderPriceAsset == "WAVES")) | |
384 | - | then unit | |
385 | - | else fromBase58String(orderPriceAsset)) | |
386 | - | let toOwner = ScriptTransfer(orderOwner, amount, if ((orderAmountAsset == "WAVES")) | |
387 | - | then unit | |
388 | - | else fromBase58String(orderAmountAsset)) | |
389 | - | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([toCaller, toOwner])) | |
390 | - | } | |
391 | - | } | |
392 | - | } | |
393 | - | } | |
394 | - | } | |
336 | + | func takeBuy (orderId,sig) = if (shutdownFlag) | |
337 | + | then throw(shutdownMessage) | |
338 | + | else { | |
339 | + | let payment = valueOrErrorMessage(i.payment, "where is payment?") | |
340 | + | let amount = payment.amount | |
341 | + | if ((0 >= amount)) | |
342 | + | then throw("amount must be positive") | |
343 | + | else { | |
344 | + | let amountAsset = match payment.assetId { | |
345 | + | case p: ByteVector => | |
346 | + | toBase58String(p) | |
347 | + | case _ => | |
348 | + | "WAVES" | |
349 | + | } | |
350 | + | let data = valueOrErrorMessage(getString(this, orderId), "Invalid order id") | |
351 | + | let parts = split(data, "_") | |
352 | + | let orderType = parts[0] | |
353 | + | let orderAmount = parseIntValue(parts[1]) | |
354 | + | let orderAmountAsset = parts[2] | |
355 | + | let orderPriceAssetAmount = parseIntValue(parts[3]) | |
356 | + | let orderPriceAsset = parts[4] | |
357 | + | let orderOwner = value(addressFromString(parts[5])) | |
358 | + | let orderAll = if ((parts[6] == "true")) | |
359 | + | then true | |
360 | + | else false | |
361 | + | let orderPassword = parts[7] | |
362 | + | let orderSpent = parseIntValue(parts[8]) | |
363 | + | if ((orderType != "buy")) | |
364 | + | then throw("Invalid order type") | |
365 | + | else if ((orderAmountAsset != amountAsset)) | |
366 | + | then throw(("payment asset must be " + orderAmountAsset)) | |
367 | + | else { | |
368 | + | let valid = if ((orderPassword != "")) | |
369 | + | then sigVerify(i.callerPublicKey, fromBase58String(sig), fromBase58String(orderPassword)) | |
370 | + | else true | |
371 | + | if (!(valid)) | |
372 | + | then throw("The order is private") | |
373 | + | else { | |
374 | + | let priceAssetAmount = ((amount * orderPriceAssetAmount) / orderAmount) | |
375 | + | if ((priceAssetAmount == 0)) | |
376 | + | then throw("Invalid amount") | |
377 | + | else if (if (orderAll) | |
378 | + | then (orderPriceAssetAmount > priceAssetAmount) | |
379 | + | else false) | |
380 | + | then throw("You must take all or none") | |
381 | + | else if ((priceAssetAmount > (orderPriceAssetAmount - orderSpent))) | |
382 | + | then throw("not enougth asset in order") | |
383 | + | else { | |
384 | + | let newData = (dropRight(data, size(parts[8])) + toString((orderSpent + priceAssetAmount))) | |
385 | + | let toCaller = ScriptTransfer(i.caller, priceAssetAmount, if ((orderPriceAsset == "WAVES")) | |
386 | + | then unit | |
387 | + | else fromBase58String(orderPriceAsset)) | |
388 | + | let toOwner = ScriptTransfer(orderOwner, amount, if ((orderAmountAsset == "WAVES")) | |
389 | + | then unit | |
390 | + | else fromBase58String(orderAmountAsset)) | |
391 | + | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([toCaller, toOwner])) | |
392 | + | } | |
393 | + | } | |
394 | + | } | |
395 | + | } | |
396 | + | } | |
395 | 397 | ||
396 | 398 | ||
397 | 399 | ||
412 | 414 | let orderSpent = parseIntValue(parts[8]) | |
413 | 415 | if ((orderType != "sell")) | |
414 | 416 | then throw("Invalid order type") | |
415 | - | else if ((orderOwner != i.caller)) | |
417 | + | else if (if ((orderOwner != i.caller)) | |
418 | + | then !(shutdownFlag) | |
419 | + | else false) | |
416 | 420 | then throw("return should be called by order owner") | |
417 | 421 | else { | |
418 | 422 | let returnAmount = (orderAmount - orderSpent) | |
420 | 424 | then throw("nothing to return") | |
421 | 425 | else { | |
422 | 426 | let newData = (dropRight(data, size(parts[8])) + toString(orderAmount)) | |
423 | - | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([ScriptTransfer( | |
427 | + | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([ScriptTransfer(orderOwner, returnAmount, if ((orderAmountAsset == "WAVES")) | |
424 | 428 | then unit | |
425 | 429 | else fromBase58String(orderAmountAsset))])) | |
426 | 430 | } | |
446 | 450 | let orderSpent = parseIntValue(parts[8]) | |
447 | 451 | if ((orderType != "buy")) | |
448 | 452 | then throw("Invalid order type") | |
449 | - | else if ((orderOwner != i.caller)) | |
453 | + | else if (if ((orderOwner != i.caller)) | |
454 | + | then !(shutdownFlag) | |
455 | + | else false) | |
450 | 456 | then throw("Return should be called by order owner") | |
451 | 457 | else { | |
452 | 458 | let returnAmount = (orderPriceAssetAmount - orderSpent) | |
454 | 460 | then throw("nothing to return") | |
455 | 461 | else { | |
456 | 462 | let newData = (dropRight(data, size(parts[8])) + toString(orderPriceAssetAmount)) | |
457 | - | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([ScriptTransfer( | |
463 | + | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([ScriptTransfer(orderOwner, returnAmount, if ((orderPriceAsset == "WAVES")) | |
458 | 464 | then unit | |
459 | 465 | else fromBase58String(orderPriceAsset))])) | |
460 | 466 | } | |
462 | 468 | } | |
463 | 469 | ||
464 | 470 | ||
471 | + | ||
472 | + | @Callable(i) | |
473 | + | func withdraw (mode) = if ((i.caller != admin)) | |
474 | + | then throw("You should be an admin") | |
475 | + | else if (if (if ((mode != "balance")) | |
476 | + | then (mode != "reserve") | |
477 | + | else false) | |
478 | + | then (mode != "all") | |
479 | + | else false) | |
480 | + | then throw("Specify the mode: balance, reserve or all") | |
481 | + | else { | |
482 | + | let balanceEntry = DataEntry("balance", 0) | |
483 | + | let balanceTransfer = ScriptTransfer(admin, balance, unit) | |
484 | + | let reserveEntry = DataEntry("reserve", 0) | |
485 | + | let reserveTransfer = ScriptTransfer(admin, reserve, unit) | |
486 | + | let writeSet = if ((mode == "balance")) | |
487 | + | then [balanceEntry] | |
488 | + | else if ((mode == "reserve")) | |
489 | + | then [reserveEntry] | |
490 | + | else if ((mode == "all")) | |
491 | + | then [balanceEntry, reserveEntry] | |
492 | + | else nil | |
493 | + | let transferSet = if ((mode == "balance")) | |
494 | + | then [balanceTransfer] | |
495 | + | else if ((mode == "reserve")) | |
496 | + | then [reserveTransfer] | |
497 | + | else if ((mode == "all")) | |
498 | + | then [balanceTransfer, reserveTransfer] | |
499 | + | else nil | |
500 | + | ScriptResult(WriteSet(writeSet), TransferSet(transferSet)) | |
501 | + | } | |
502 | + | ||
503 | + | ||
504 | + | ||
505 | + | @Callable(i) | |
506 | + | func doShutdown (msg) = if ((i.caller != admin)) | |
507 | + | then throw("You should be an admin") | |
508 | + | else WriteSet([DataEntry("shutdown_flag", true), DataEntry("shutdown_message", msg)]) | |
509 | + | ||
510 | + |
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 3 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | 4 | let uTokenId = base58'GHh7EMnVnUBCYNJMktuLPVr3P2oCqBCb4c87fBCZ5CzY' | |
5 | + | ||
6 | + | let admin = addressFromStringValue("3P96VpN2dBS1111111ydADa5a6AD1Un9iUv") | |
7 | + | ||
8 | + | let shutdownFlag = match getBoolean(this, "shutdown_flag") { | |
9 | + | case bool: Boolean => | |
10 | + | bool | |
11 | + | case _: Unit => | |
12 | + | false | |
13 | + | case _ => | |
14 | + | throw() | |
15 | + | } | |
16 | + | ||
17 | + | let shutdownMessage = match getString(this, "shutdown_message") { | |
18 | + | case str: String => | |
19 | + | str | |
20 | + | case _: Unit => | |
21 | + | "Forbidden" | |
22 | + | case _ => | |
23 | + | throw() | |
24 | + | } | |
25 | + | ||
26 | + | let reserve = match getInteger(this, "reserve") { | |
27 | + | case int: Int => | |
28 | + | int | |
29 | + | case _: Unit => | |
30 | + | 0 | |
31 | + | case _ => | |
32 | + | throw() | |
33 | + | } | |
34 | + | ||
35 | + | let balance = match getInteger(this, "balance") { | |
36 | + | case int: Int => | |
37 | + | int | |
38 | + | case _: Unit => | |
39 | + | 0 | |
40 | + | case _ => | |
41 | + | throw() | |
42 | + | } | |
5 | 43 | ||
6 | 44 | func checkStatus (address) = { | |
7 | 45 | let statusUnlimited = match getBoolean(this, (address + "_unlimited")) { | |
8 | 46 | case bool: Boolean => | |
9 | 47 | bool | |
10 | 48 | case _: Unit => | |
11 | 49 | false | |
12 | 50 | case _ => | |
13 | 51 | throw() | |
14 | 52 | } | |
15 | 53 | let statusTime = match getInteger(this, (address + "_time")) { | |
16 | 54 | case int: Int => | |
17 | 55 | int | |
18 | 56 | case _: Unit => | |
19 | 57 | 0 | |
20 | 58 | case _ => | |
21 | 59 | throw() | |
22 | 60 | } | |
23 | 61 | if (statusUnlimited) | |
24 | 62 | then true | |
25 | 63 | else (statusTime > lastBlock.timestamp) | |
26 | 64 | } | |
27 | 65 | ||
28 | 66 | ||
29 | 67 | @Callable(i) | |
30 | - | func addAsset (assetId) = { | |
31 | - | let addingPrice = (100 * 100000000) | |
32 | - | let addingPriceStr = "100" | |
33 | - | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
34 | - | if (if (isDefined(payment.assetId)) | |
35 | - | then (payment.assetId != uTokenId) | |
36 | - | else false) | |
37 | - | then throw("OTCu or WAVES only") | |
38 | - | else if ((payment.amount != addingPrice)) | |
39 | - | then throw((("You have to pay " + addingPriceStr) + " OTCu or WAVES")) | |
40 | - | else if (!(isDefined(assetInfo(fromBase58String(assetId))))) | |
41 | - | then throw("There is no asset with specified id") | |
68 | + | func addAsset (assetId) = if (shutdownFlag) | |
69 | + | then throw(shutdownMessage) | |
70 | + | else { | |
71 | + | let addingPrice = (100 * 100000000) | |
72 | + | let addingPriceStr = "100" | |
73 | + | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
74 | + | if (if (isDefined(payment.assetId)) | |
75 | + | then (payment.assetId != uTokenId) | |
76 | + | else false) | |
77 | + | then throw("OTCu or WAVES only") | |
78 | + | else if ((payment.amount != addingPrice)) | |
79 | + | then throw((("You have to pay " + addingPriceStr) + " OTCu or WAVES")) | |
80 | + | else if (!(isDefined(assetInfo(fromBase58String(assetId))))) | |
81 | + | then throw("There is no asset with specified id") | |
82 | + | else { | |
83 | + | let assets = match getString(this, "assets") { | |
84 | + | case str: String => | |
85 | + | str | |
86 | + | case _: Unit => | |
87 | + | "" | |
88 | + | case _ => | |
89 | + | throw() | |
90 | + | } | |
91 | + | if (isDefined(indexOf(assets, assetId))) | |
92 | + | then throw("Asset is already available") | |
93 | + | else { | |
94 | + | let list0 = [DataEntry("assets", ((assets + assetId) + ","))] | |
95 | + | let list1 = if ((payment.assetId == uTokenId)) | |
96 | + | then DataEntry("reserve", (reserve + payment.amount)) :: list0 | |
97 | + | else if (!(isDefined(payment.assetId))) | |
98 | + | then DataEntry("balance", (balance + payment.amount)) :: list0 | |
99 | + | else list0 | |
100 | + | WriteSet(list1) | |
101 | + | } | |
102 | + | } | |
103 | + | } | |
104 | + | ||
105 | + | ||
106 | + | ||
107 | + | @Callable(i) | |
108 | + | func pro () = if (shutdownFlag) | |
109 | + | then throw(shutdownMessage) | |
110 | + | else { | |
111 | + | let address = toBase58String(i.caller.bytes) | |
112 | + | let unlimitedPrice = (50 * 100000000) | |
113 | + | let unlimitedPriceStr = "50" | |
114 | + | let monthPrice = (10 * 100000000) | |
115 | + | let monthPriceStr = "10" | |
116 | + | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
117 | + | if (if (isDefined(payment.assetId)) | |
118 | + | then (payment.assetId != uTokenId) | |
119 | + | else false) | |
120 | + | then throw("OTCu or WAVES only") | |
121 | + | else if (if ((payment.amount != unlimitedPrice)) | |
122 | + | then (payment.amount != monthPrice) | |
123 | + | else false) | |
124 | + | then throw("Invalid payment") | |
42 | 125 | else { | |
43 | - | let assets = match getString(this, "assets") { | |
44 | - | case str: String => | |
45 | - | str | |
126 | + | let unlimited = (payment.amount == unlimitedPrice) | |
127 | + | let currentUnlimited = match getBoolean(this, (address + "_unlimited")) { | |
128 | + | case bool: Boolean => | |
129 | + | bool | |
46 | 130 | case _: Unit => | |
47 | - | | |
131 | + | false | |
48 | 132 | case _ => | |
49 | 133 | throw() | |
50 | 134 | } | |
51 | - | if (isDefined(indexOf(assets, assetId))) | |
52 | - | then throw("Asset is already available") | |
135 | + | let currentTime = match getInteger(this, (address + "_time")) { | |
136 | + | case int: Int => | |
137 | + | int | |
138 | + | case _: Unit => | |
139 | + | lastBlock.timestamp | |
140 | + | case _ => | |
141 | + | throw() | |
142 | + | } | |
143 | + | if (currentUnlimited) | |
144 | + | then throw("You have unlimited PRO status already. What do you want?") | |
53 | 145 | else { | |
54 | - | let list0 = [DataEntry("assets", ((assets + assetId) + ","))] | |
55 | - | let reserve = match getInteger(this, "reserve") { | |
56 | - | case int: Int => | |
57 | - | int | |
58 | - | case _: Unit => | |
59 | - | 0 | |
60 | - | case _ => | |
61 | - | throw() | |
62 | - | } | |
63 | - | let balance = match getInteger(this, "balance") { | |
64 | - | case int: Int => | |
65 | - | int | |
66 | - | case _: Unit => | |
67 | - | 0 | |
68 | - | case _ => | |
69 | - | throw() | |
70 | - | } | |
146 | + | let month = 2629743000 | |
147 | + | let list0 = [DataEntry((address + "_unlimited"), unlimited), DataEntry((address + "_time"), if (unlimited) | |
148 | + | then 0 | |
149 | + | else (currentTime + month))] | |
71 | 150 | let list1 = if ((payment.assetId == uTokenId)) | |
72 | 151 | then DataEntry("reserve", (reserve + payment.amount)) :: list0 | |
73 | 152 | else if (!(isDefined(payment.assetId))) | |
74 | 153 | then DataEntry("balance", (balance + payment.amount)) :: list0 | |
75 | 154 | else list0 | |
76 | 155 | WriteSet(list1) | |
77 | 156 | } | |
78 | 157 | } | |
79 | - | } | |
158 | + | } | |
80 | 159 | ||
81 | 160 | ||
82 | 161 | ||
83 | 162 | @Callable(i) | |
84 | - | func pro () = { | |
85 | - | let address = toBase58String(i.caller.bytes) | |
86 | - | let unlimitedPrice = (50 * 100000000) | |
87 | - | let unlimitedPriceStr = "50" | |
88 | - | let monthPrice = (10 * 100000000) | |
89 | - | let monthPriceStr = "10" | |
90 | - | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
91 | - | if (if (isDefined(payment.assetId)) | |
92 | - | then (payment.assetId != uTokenId) | |
93 | - | else false) | |
94 | - | then throw("OTCu or WAVES only") | |
95 | - | else if (if ((payment.amount != unlimitedPrice)) | |
96 | - | then (payment.amount != monthPrice) | |
97 | - | else false) | |
98 | - | then throw("Invalid payment") | |
99 | - | else { | |
100 | - | let unlimited = (payment.amount == unlimitedPrice) | |
101 | - | let currentUnlimited = match getBoolean(this, (address + "_unlimited")) { | |
102 | - | case bool: Boolean => | |
103 | - | bool | |
104 | - | case _: Unit => | |
105 | - | false | |
106 | - | case _ => | |
107 | - | throw() | |
108 | - | } | |
109 | - | let currentTime = match getInteger(this, (address + "_time")) { | |
110 | - | case int: Int => | |
111 | - | int | |
112 | - | case _: Unit => | |
113 | - | lastBlock.timestamp | |
114 | - | case _ => | |
115 | - | throw() | |
116 | - | } | |
117 | - | if (currentUnlimited) | |
118 | - | then throw("You have unlimited PRO status already. What do you want?") | |
119 | - | else { | |
120 | - | let month = 2629743000 | |
121 | - | let list0 = [DataEntry((address + "_unlimited"), unlimited), DataEntry((address + "_time"), if (unlimited) | |
122 | - | then 0 | |
123 | - | else (currentTime + month))] | |
124 | - | let reserve = match getInteger(this, "reserve") { | |
125 | - | case int: Int => | |
126 | - | int | |
127 | - | case _: Unit => | |
128 | - | 0 | |
129 | - | case _ => | |
130 | - | throw() | |
131 | - | } | |
132 | - | let balance = match getInteger(this, "balance") { | |
133 | - | case int: Int => | |
134 | - | int | |
135 | - | case _: Unit => | |
136 | - | 0 | |
137 | - | case _ => | |
138 | - | throw() | |
139 | - | } | |
140 | - | let list1 = if ((payment.assetId == uTokenId)) | |
141 | - | then DataEntry("reserve", (reserve + payment.amount)) :: list0 | |
142 | - | else if (!(isDefined(payment.assetId))) | |
143 | - | then DataEntry("balance", (balance + payment.amount)) :: list0 | |
144 | - | else list0 | |
145 | - | WriteSet(list1) | |
146 | - | } | |
147 | - | } | |
148 | - | } | |
163 | + | func buyUtilityToken () = if (shutdownFlag) | |
164 | + | then throw(shutdownMessage) | |
165 | + | else { | |
166 | + | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
167 | + | if (isDefined(payment.assetId)) | |
168 | + | then throw("WAVES only") | |
169 | + | else if ((payment.amount > reserve)) | |
170 | + | then throw("Not enougth asset in dApp") | |
171 | + | else ScriptResult(WriteSet([DataEntry("reserve", (reserve - payment.amount)), DataEntry("balance", (balance + payment.amount))]), TransferSet([ScriptTransfer(i.caller, payment.amount, uTokenId)])) | |
172 | + | } | |
149 | 173 | ||
150 | 174 | ||
151 | 175 | ||
152 | 176 | @Callable(i) | |
153 | - | func buyUtilityToken () = { | |
154 | - | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
155 | - | if (isDefined(payment.assetId)) | |
156 | - | then throw("WAVES only") | |
157 | - | else { | |
158 | - | let reserve = match getInteger(this, "reserve") { | |
159 | - | case int: Int => | |
160 | - | int | |
161 | - | case _: Unit => | |
162 | - | 0 | |
163 | - | case _ => | |
164 | - | throw() | |
165 | - | } | |
166 | - | let balance = match getInteger(this, "balance") { | |
167 | - | case int: Int => | |
168 | - | int | |
169 | - | case _: Unit => | |
170 | - | 0 | |
171 | - | case _ => | |
172 | - | throw() | |
173 | - | } | |
174 | - | if ((payment.amount > reserve)) | |
175 | - | then throw("Not enougth asset in dApp") | |
176 | - | else ScriptResult(WriteSet([DataEntry("reserve", (reserve - payment.amount)), DataEntry("balance", (balance + payment.amount))]), TransferSet([ScriptTransfer(i.caller, payment.amount, uTokenId)])) | |
177 | - | } | |
178 | - | } | |
177 | + | func makeSell (priceAsset,priceAssetAmount,all,password) = if (shutdownFlag) | |
178 | + | then throw(shutdownMessage) | |
179 | + | else if (if ((priceAsset != "WAVES")) | |
180 | + | then !(isDefined(assetInfo(fromBase58String(priceAsset)))) | |
181 | + | else false) | |
182 | + | then throw("There is no asset with specified id") | |
183 | + | else if ((0 >= priceAssetAmount)) | |
184 | + | then throw("Amount of price asset must be positive") | |
185 | + | else { | |
186 | + | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
187 | + | if ((0 >= payment.amount)) | |
188 | + | then throw("Amount must be positive") | |
189 | + | else { | |
190 | + | let amountAsset = match payment.assetId { | |
191 | + | case p: ByteVector => | |
192 | + | toBase58String(p) | |
193 | + | case _ => | |
194 | + | "WAVES" | |
195 | + | } | |
196 | + | let assets = valueOrErrorMessage(getString(this, "assets"), "There are not available assets") | |
197 | + | if (if (!(isDefined(indexOf(assets, priceAsset)))) | |
198 | + | then true | |
199 | + | else !(isDefined(indexOf(assets, amountAsset)))) | |
200 | + | then throw("Asset are not available for trading") | |
201 | + | else { | |
202 | + | let address = toBase58String(i.caller.bytes) | |
203 | + | if (if (!(checkStatus(address))) | |
204 | + | then if (all) | |
205 | + | then true | |
206 | + | else (password != "") | |
207 | + | else false) | |
208 | + | then throw("You must have pro status to use these features") | |
209 | + | else { | |
210 | + | let orderId = ("order_" + toBase58String(i.transactionId)) | |
211 | + | let passwordValid = fromBase58String(password) | |
212 | + | let data = (((((((((((((((("sell" + "_") + toString(payment.amount)) + "_") + amountAsset) + "_") + toString(priceAssetAmount)) + "_") + priceAsset) + "_") + address) + "_") + toString(all)) + "_") + password) + "_") + toString(0)) | |
213 | + | WriteSet([DataEntry(orderId, data)]) | |
214 | + | } | |
215 | + | } | |
216 | + | } | |
217 | + | } | |
179 | 218 | ||
180 | 219 | ||
181 | 220 | ||
182 | 221 | @Callable(i) | |
183 | - | func makeSell (priceAsset,priceAssetAmount,all,password) = if (if ((priceAsset != "WAVES")) | |
184 | - | then !(isDefined(assetInfo(fromBase58String(priceAsset)))) | |
185 | - | else false) | |
186 | - | then throw("There is no asset with specified id") | |
187 | - | else if ((0 >= priceAssetAmount)) | |
188 | - | then throw("Amount of price asset must be positive") | |
189 | - | else { | |
190 | - | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
191 | - | if ((0 >= payment.amount)) | |
192 | - | then throw("Amount must be positive") | |
193 | - | else { | |
194 | - | let amountAsset = match payment.assetId { | |
195 | - | case p: ByteVector => | |
196 | - | toBase58String(p) | |
197 | - | case _ => | |
198 | - | "WAVES" | |
199 | - | } | |
200 | - | let assets = valueOrErrorMessage(getString(this, "assets"), "There are not available assets") | |
201 | - | if (if (!(isDefined(indexOf(assets, priceAsset)))) | |
202 | - | then true | |
203 | - | else !(isDefined(indexOf(assets, amountAsset)))) | |
204 | - | then throw("Asset are not available for trading") | |
205 | - | else { | |
206 | - | let address = toBase58String(i.caller.bytes) | |
207 | - | if (if (!(checkStatus(address))) | |
208 | - | then if (all) | |
209 | - | then true | |
210 | - | else (password != "") | |
211 | - | else false) | |
212 | - | then throw("You must have pro status to use these features") | |
213 | - | else { | |
214 | - | let orderId = ("order_" + toBase58String(i.transactionId)) | |
215 | - | let passwordValid = fromBase58String(password) | |
216 | - | let data = (((((((((((((((("sell" + "_") + toString(payment.amount)) + "_") + amountAsset) + "_") + toString(priceAssetAmount)) + "_") + priceAsset) + "_") + address) + "_") + toString(all)) + "_") + password) + "_") + toString(0)) | |
217 | - | WriteSet([DataEntry(orderId, data)]) | |
218 | - | } | |
219 | - | } | |
220 | - | } | |
221 | - | } | |
222 | + | func makeBuy (amountAsset,amount,all,password) = if (shutdownFlag) | |
223 | + | then throw(shutdownMessage) | |
224 | + | else if (if ((amountAsset != "WAVES")) | |
225 | + | then !(isDefined(assetInfo(fromBase58String(amountAsset)))) | |
226 | + | else false) | |
227 | + | then throw("There is no asset with specified id") | |
228 | + | else if ((0 >= amount)) | |
229 | + | then throw("Amount must be positive") | |
230 | + | else { | |
231 | + | let payment = valueOrErrorMessage(i.payment, "where is payment?") | |
232 | + | let priceAssetAmount = payment.amount | |
233 | + | if ((0 >= priceAssetAmount)) | |
234 | + | then throw("amount must be positive") | |
235 | + | else { | |
236 | + | let priceAsset = match payment.assetId { | |
237 | + | case p: ByteVector => | |
238 | + | toBase58String(p) | |
239 | + | case _ => | |
240 | + | "WAVES" | |
241 | + | } | |
242 | + | let assets = valueOrErrorMessage(getString(this, "assets"), "There are not available assets") | |
243 | + | if (if (!(isDefined(indexOf(assets, priceAsset)))) | |
244 | + | then true | |
245 | + | else !(isDefined(indexOf(assets, amountAsset)))) | |
246 | + | then throw("Asset are not available for trading") | |
247 | + | else { | |
248 | + | let address = toBase58String(i.caller.bytes) | |
249 | + | if (if (!(checkStatus(address))) | |
250 | + | then if (all) | |
251 | + | then true | |
252 | + | else (password != "") | |
253 | + | else false) | |
254 | + | then throw("You must have pro status to use these features") | |
255 | + | else { | |
256 | + | let orderId = ("order_" + toBase58String(i.transactionId)) | |
257 | + | if ((amount == 0)) | |
258 | + | then throw("invalid buy amount") | |
259 | + | else { | |
260 | + | let data = (((((((((((((((("buy" + "_") + toString(amount)) + "_") + amountAsset) + "_") + toString(priceAssetAmount)) + "_") + priceAsset) + "_") + address) + "_") + toString(all)) + "_") + password) + "_") + toString(0)) | |
261 | + | WriteSet([DataEntry(orderId, data)]) | |
262 | + | } | |
263 | + | } | |
264 | + | } | |
265 | + | } | |
266 | + | } | |
222 | 267 | ||
223 | 268 | ||
224 | 269 | ||
225 | 270 | @Callable(i) | |
226 | - | func makeBuy (amountAsset,amount,all,password) = if (if ((amountAsset != "WAVES")) | |
227 | - | then !(isDefined(assetInfo(fromBase58String(amountAsset)))) | |
228 | - | else false) | |
229 | - | then throw("There is no asset with specified id") | |
230 | - | else if ((0 >= amount)) | |
231 | - | then throw("Amount must be positive") | |
232 | - | else { | |
233 | - | let payment = valueOrErrorMessage(i.payment, "where is payment?") | |
234 | - | let priceAssetAmount = payment.amount | |
235 | - | if ((0 >= priceAssetAmount)) | |
236 | - | then throw("amount must be positive") | |
237 | - | else { | |
238 | - | let priceAsset = match payment.assetId { | |
239 | - | case p: ByteVector => | |
240 | - | toBase58String(p) | |
241 | - | case _ => | |
242 | - | "WAVES" | |
243 | - | } | |
244 | - | let assets = valueOrErrorMessage(getString(this, "assets"), "There are not available assets") | |
245 | - | if (if (!(isDefined(indexOf(assets, priceAsset)))) | |
246 | - | then true | |
247 | - | else !(isDefined(indexOf(assets, amountAsset)))) | |
248 | - | then throw("Asset are not available for trading") | |
271 | + | func takeSell (orderId,sig) = if (shutdownFlag) | |
272 | + | then throw(shutdownMessage) | |
273 | + | else { | |
274 | + | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
275 | + | let priceAssetAmount = payment.amount | |
276 | + | if ((0 >= priceAssetAmount)) | |
277 | + | then throw("Amount must be positive") | |
278 | + | else { | |
279 | + | let priceAsset = match payment.assetId { | |
280 | + | case p: ByteVector => | |
281 | + | toBase58String(p) | |
282 | + | case _ => | |
283 | + | "WAVES" | |
284 | + | } | |
285 | + | let data = valueOrErrorMessage(getString(this, orderId), "Invalid order id") | |
286 | + | let parts = split(data, "_") | |
287 | + | let orderType = parts[0] | |
288 | + | let orderAmount = parseIntValue(parts[1]) | |
289 | + | let orderAmountAsset = parts[2] | |
290 | + | let orderPriceAssetAmount = parseIntValue(parts[3]) | |
291 | + | let orderPriceAsset = parts[4] | |
292 | + | let orderOwner = value(addressFromString(parts[5])) | |
293 | + | let orderAll = if ((parts[6] == "true")) | |
294 | + | then true | |
295 | + | else false | |
296 | + | let orderPassword = parts[7] | |
297 | + | let orderSpent = parseIntValue(parts[8]) | |
298 | + | if ((orderType != "sell")) | |
299 | + | then throw("Invalid order type") | |
300 | + | else if ((orderPriceAsset != priceAsset)) | |
301 | + | then throw(("Payment asset must be " + orderPriceAsset)) | |
249 | 302 | else { | |
250 | - | let address = toBase58String(i.caller.bytes) | |
251 | - | if (if (!(checkStatus(address))) | |
252 | - | then if (all) | |
253 | - | then true | |
254 | - | else (password != "") | |
255 | - | else false) | |
256 | - | then throw("You must have pro status to use these features") | |
303 | + | let valid = if ((orderPassword != "")) | |
304 | + | then sigVerify(i.callerPublicKey, fromBase58String(sig), fromBase58String(orderPassword)) | |
305 | + | else true | |
306 | + | if (!(valid)) | |
307 | + | then throw("The order is private") | |
257 | 308 | else { | |
258 | - | let | |
309 | + | let amount = ((priceAssetAmount * orderAmount) / orderPriceAssetAmount) | |
259 | 310 | if ((amount == 0)) | |
260 | - | then throw("invalid buy amount") | |
261 | - | else { | |
262 | - | let data = (((((((((((((((("buy" + "_") + toString(amount)) + "_") + amountAsset) + "_") + toString(priceAssetAmount)) + "_") + priceAsset) + "_") + address) + "_") + toString(all)) + "_") + password) + "_") + toString(0)) | |
263 | - | WriteSet([DataEntry(orderId, data)]) | |
264 | - | } | |
311 | + | then throw("Invalid amount") | |
312 | + | else if (if (orderAll) | |
313 | + | then (orderAmount > amount) | |
314 | + | else false) | |
315 | + | then throw("You must take all or none") | |
316 | + | else if ((amount > (orderAmount - orderSpent))) | |
317 | + | then throw("Not enougth asset in order") | |
318 | + | else { | |
319 | + | let newData = (dropRight(data, size(parts[8])) + toString((orderSpent + amount))) | |
320 | + | let toCaller = ScriptTransfer(i.caller, amount, if ((orderAmountAsset == "WAVES")) | |
321 | + | then unit | |
322 | + | else fromBase58String(orderAmountAsset)) | |
323 | + | let toOwner = ScriptTransfer(orderOwner, priceAssetAmount, if ((orderPriceAsset == "WAVES")) | |
324 | + | then unit | |
325 | + | else fromBase58String(orderPriceAsset)) | |
326 | + | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([toCaller, toOwner])) | |
327 | + | } | |
265 | 328 | } | |
266 | 329 | } | |
267 | - | ||
268 | - | ||
330 | + | } | |
331 | + | } | |
269 | 332 | ||
270 | 333 | ||
271 | 334 | ||
272 | 335 | @Callable(i) | |
273 | - | func takeSell (orderId,sig) = { | |
274 | - | let payment = valueOrErrorMessage(i.payment, "Where is payment?") | |
275 | - | let priceAssetAmount = payment.amount | |
276 | - | if ((0 >= priceAssetAmount)) | |
277 | - | then throw("Amount must be positive") | |
278 | - | else { | |
279 | - | let priceAsset = match payment.assetId { | |
280 | - | case p: ByteVector => | |
281 | - | toBase58String(p) | |
282 | - | case _ => | |
283 | - | "WAVES" | |
284 | - | } | |
285 | - | let data = valueOrErrorMessage(getString(this, orderId), "Invalid order id") | |
286 | - | let parts = split(data, "_") | |
287 | - | let orderType = parts[0] | |
288 | - | let orderAmount = parseIntValue(parts[1]) | |
289 | - | let orderAmountAsset = parts[2] | |
290 | - | let orderPriceAssetAmount = parseIntValue(parts[3]) | |
291 | - | let orderPriceAsset = parts[4] | |
292 | - | let orderOwner = value(addressFromString(parts[5])) | |
293 | - | let orderAll = if ((parts[6] == "true")) | |
294 | - | then true | |
295 | - | else false | |
296 | - | let orderPassword = parts[7] | |
297 | - | let orderSpent = parseIntValue(parts[8]) | |
298 | - | if ((orderType != "sell")) | |
299 | - | then throw("Invalid order type") | |
300 | - | else if ((orderPriceAsset != priceAsset)) | |
301 | - | then throw(("Payment asset must be " + orderPriceAsset)) | |
302 | - | else { | |
303 | - | let valid = if ((orderPassword != "")) | |
304 | - | then sigVerify(i.callerPublicKey, fromBase58String(sig), fromBase58String(orderPassword)) | |
305 | - | else true | |
306 | - | if (!(valid)) | |
307 | - | then throw("The order is private") | |
308 | - | else { | |
309 | - | let amount = ((priceAssetAmount * orderAmount) / orderPriceAssetAmount) | |
310 | - | if ((amount == 0)) | |
311 | - | then throw("Invalid amount") | |
312 | - | else if (if (orderAll) | |
313 | - | then (orderAmount > amount) | |
314 | - | else false) | |
315 | - | then throw("You must take all or none") | |
316 | - | else if ((amount > (orderAmount - orderSpent))) | |
317 | - | then throw("Not enougth asset in order") | |
318 | - | else { | |
319 | - | let newData = (dropRight(data, size(parts[8])) + toString((orderSpent + amount))) | |
320 | - | let toCaller = ScriptTransfer(i.caller, amount, if ((orderAmountAsset == "WAVES")) | |
321 | - | then unit | |
322 | - | else fromBase58String(orderAmountAsset)) | |
323 | - | let toOwner = ScriptTransfer(orderOwner, priceAssetAmount, if ((orderPriceAsset == "WAVES")) | |
324 | - | then unit | |
325 | - | else fromBase58String(orderPriceAsset)) | |
326 | - | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([toCaller, toOwner])) | |
327 | - | } | |
328 | - | } | |
329 | - | } | |
330 | - | } | |
331 | - | } | |
332 | - | ||
333 | - | ||
334 | - | ||
335 | - | @Callable(i) | |
336 | - | func takeBuy (orderId,sig) = { | |
337 | - | let payment = valueOrErrorMessage(i.payment, "where is payment?") | |
338 | - | let amount = payment.amount | |
339 | - | if ((0 >= amount)) | |
340 | - | then throw("amount must be positive") | |
341 | - | else { | |
342 | - | let amountAsset = match payment.assetId { | |
343 | - | case p: ByteVector => | |
344 | - | toBase58String(p) | |
345 | - | case _ => | |
346 | - | "WAVES" | |
347 | - | } | |
348 | - | let data = valueOrErrorMessage(getString(this, orderId), "Invalid order id") | |
349 | - | let parts = split(data, "_") | |
350 | - | let orderType = parts[0] | |
351 | - | let orderAmount = parseIntValue(parts[1]) | |
352 | - | let orderAmountAsset = parts[2] | |
353 | - | let orderPriceAssetAmount = parseIntValue(parts[3]) | |
354 | - | let orderPriceAsset = parts[4] | |
355 | - | let orderOwner = value(addressFromString(parts[5])) | |
356 | - | let orderAll = if ((parts[6] == "true")) | |
357 | - | then true | |
358 | - | else false | |
359 | - | let orderPassword = parts[7] | |
360 | - | let orderSpent = parseIntValue(parts[8]) | |
361 | - | if ((orderType != "buy")) | |
362 | - | then throw("Invalid order type") | |
363 | - | else if ((orderAmountAsset != amountAsset)) | |
364 | - | then throw(("payment asset must be " + orderAmountAsset)) | |
365 | - | else { | |
366 | - | let valid = if ((orderPassword != "")) | |
367 | - | then sigVerify(i.callerPublicKey, fromBase58String(sig), fromBase58String(orderPassword)) | |
368 | - | else true | |
369 | - | if (!(valid)) | |
370 | - | then throw("The order is private") | |
371 | - | else { | |
372 | - | let priceAssetAmount = ((amount * orderPriceAssetAmount) / orderAmount) | |
373 | - | if ((priceAssetAmount == 0)) | |
374 | - | then throw("Invalid amount") | |
375 | - | else if (if (orderAll) | |
376 | - | then (orderPriceAssetAmount > priceAssetAmount) | |
377 | - | else false) | |
378 | - | then throw("You must take all or none") | |
379 | - | else if ((priceAssetAmount > (orderPriceAssetAmount - orderSpent))) | |
380 | - | then throw("not enougth asset in order") | |
381 | - | else { | |
382 | - | let newData = (dropRight(data, size(parts[8])) + toString((orderSpent + priceAssetAmount))) | |
383 | - | let toCaller = ScriptTransfer(i.caller, priceAssetAmount, if ((orderPriceAsset == "WAVES")) | |
384 | - | then unit | |
385 | - | else fromBase58String(orderPriceAsset)) | |
386 | - | let toOwner = ScriptTransfer(orderOwner, amount, if ((orderAmountAsset == "WAVES")) | |
387 | - | then unit | |
388 | - | else fromBase58String(orderAmountAsset)) | |
389 | - | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([toCaller, toOwner])) | |
390 | - | } | |
391 | - | } | |
392 | - | } | |
393 | - | } | |
394 | - | } | |
336 | + | func takeBuy (orderId,sig) = if (shutdownFlag) | |
337 | + | then throw(shutdownMessage) | |
338 | + | else { | |
339 | + | let payment = valueOrErrorMessage(i.payment, "where is payment?") | |
340 | + | let amount = payment.amount | |
341 | + | if ((0 >= amount)) | |
342 | + | then throw("amount must be positive") | |
343 | + | else { | |
344 | + | let amountAsset = match payment.assetId { | |
345 | + | case p: ByteVector => | |
346 | + | toBase58String(p) | |
347 | + | case _ => | |
348 | + | "WAVES" | |
349 | + | } | |
350 | + | let data = valueOrErrorMessage(getString(this, orderId), "Invalid order id") | |
351 | + | let parts = split(data, "_") | |
352 | + | let orderType = parts[0] | |
353 | + | let orderAmount = parseIntValue(parts[1]) | |
354 | + | let orderAmountAsset = parts[2] | |
355 | + | let orderPriceAssetAmount = parseIntValue(parts[3]) | |
356 | + | let orderPriceAsset = parts[4] | |
357 | + | let orderOwner = value(addressFromString(parts[5])) | |
358 | + | let orderAll = if ((parts[6] == "true")) | |
359 | + | then true | |
360 | + | else false | |
361 | + | let orderPassword = parts[7] | |
362 | + | let orderSpent = parseIntValue(parts[8]) | |
363 | + | if ((orderType != "buy")) | |
364 | + | then throw("Invalid order type") | |
365 | + | else if ((orderAmountAsset != amountAsset)) | |
366 | + | then throw(("payment asset must be " + orderAmountAsset)) | |
367 | + | else { | |
368 | + | let valid = if ((orderPassword != "")) | |
369 | + | then sigVerify(i.callerPublicKey, fromBase58String(sig), fromBase58String(orderPassword)) | |
370 | + | else true | |
371 | + | if (!(valid)) | |
372 | + | then throw("The order is private") | |
373 | + | else { | |
374 | + | let priceAssetAmount = ((amount * orderPriceAssetAmount) / orderAmount) | |
375 | + | if ((priceAssetAmount == 0)) | |
376 | + | then throw("Invalid amount") | |
377 | + | else if (if (orderAll) | |
378 | + | then (orderPriceAssetAmount > priceAssetAmount) | |
379 | + | else false) | |
380 | + | then throw("You must take all or none") | |
381 | + | else if ((priceAssetAmount > (orderPriceAssetAmount - orderSpent))) | |
382 | + | then throw("not enougth asset in order") | |
383 | + | else { | |
384 | + | let newData = (dropRight(data, size(parts[8])) + toString((orderSpent + priceAssetAmount))) | |
385 | + | let toCaller = ScriptTransfer(i.caller, priceAssetAmount, if ((orderPriceAsset == "WAVES")) | |
386 | + | then unit | |
387 | + | else fromBase58String(orderPriceAsset)) | |
388 | + | let toOwner = ScriptTransfer(orderOwner, amount, if ((orderAmountAsset == "WAVES")) | |
389 | + | then unit | |
390 | + | else fromBase58String(orderAmountAsset)) | |
391 | + | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([toCaller, toOwner])) | |
392 | + | } | |
393 | + | } | |
394 | + | } | |
395 | + | } | |
396 | + | } | |
395 | 397 | ||
396 | 398 | ||
397 | 399 | ||
398 | 400 | @Callable(i) | |
399 | 401 | func returnSell (orderId) = { | |
400 | 402 | let data = valueOrErrorMessage(getString(this, orderId), "Invalid order id") | |
401 | 403 | let parts = split(data, "_") | |
402 | 404 | let orderType = parts[0] | |
403 | 405 | let orderAmount = parseIntValue(parts[1]) | |
404 | 406 | let orderAmountAsset = parts[2] | |
405 | 407 | let orderPriceAssetAmount = parseIntValue(parts[3]) | |
406 | 408 | let orderPriceAsset = parts[4] | |
407 | 409 | let orderOwner = value(addressFromString(parts[5])) | |
408 | 410 | let orderAll = if ((parts[6] == "true")) | |
409 | 411 | then true | |
410 | 412 | else false | |
411 | 413 | let orderPassword = parts[7] | |
412 | 414 | let orderSpent = parseIntValue(parts[8]) | |
413 | 415 | if ((orderType != "sell")) | |
414 | 416 | then throw("Invalid order type") | |
415 | - | else if ((orderOwner != i.caller)) | |
417 | + | else if (if ((orderOwner != i.caller)) | |
418 | + | then !(shutdownFlag) | |
419 | + | else false) | |
416 | 420 | then throw("return should be called by order owner") | |
417 | 421 | else { | |
418 | 422 | let returnAmount = (orderAmount - orderSpent) | |
419 | 423 | if ((0 >= returnAmount)) | |
420 | 424 | then throw("nothing to return") | |
421 | 425 | else { | |
422 | 426 | let newData = (dropRight(data, size(parts[8])) + toString(orderAmount)) | |
423 | - | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([ScriptTransfer( | |
427 | + | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([ScriptTransfer(orderOwner, returnAmount, if ((orderAmountAsset == "WAVES")) | |
424 | 428 | then unit | |
425 | 429 | else fromBase58String(orderAmountAsset))])) | |
426 | 430 | } | |
427 | 431 | } | |
428 | 432 | } | |
429 | 433 | ||
430 | 434 | ||
431 | 435 | ||
432 | 436 | @Callable(i) | |
433 | 437 | func returnBuy (orderId) = { | |
434 | 438 | let data = valueOrErrorMessage(getString(this, orderId), "Invalid order id") | |
435 | 439 | let parts = split(data, "_") | |
436 | 440 | let orderType = parts[0] | |
437 | 441 | let orderAmount = parseIntValue(parts[1]) | |
438 | 442 | let orderAmountAsset = parts[2] | |
439 | 443 | let orderPriceAssetAmount = parseIntValue(parts[3]) | |
440 | 444 | let orderPriceAsset = parts[4] | |
441 | 445 | let orderOwner = value(addressFromString(parts[5])) | |
442 | 446 | let orderAll = if ((parts[6] == "true")) | |
443 | 447 | then true | |
444 | 448 | else false | |
445 | 449 | let orderPassword = parts[7] | |
446 | 450 | let orderSpent = parseIntValue(parts[8]) | |
447 | 451 | if ((orderType != "buy")) | |
448 | 452 | then throw("Invalid order type") | |
449 | - | else if ((orderOwner != i.caller)) | |
453 | + | else if (if ((orderOwner != i.caller)) | |
454 | + | then !(shutdownFlag) | |
455 | + | else false) | |
450 | 456 | then throw("Return should be called by order owner") | |
451 | 457 | else { | |
452 | 458 | let returnAmount = (orderPriceAssetAmount - orderSpent) | |
453 | 459 | if ((0 >= returnAmount)) | |
454 | 460 | then throw("nothing to return") | |
455 | 461 | else { | |
456 | 462 | let newData = (dropRight(data, size(parts[8])) + toString(orderPriceAssetAmount)) | |
457 | - | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([ScriptTransfer( | |
463 | + | ScriptResult(WriteSet([DataEntry(orderId, newData)]), TransferSet([ScriptTransfer(orderOwner, returnAmount, if ((orderPriceAsset == "WAVES")) | |
458 | 464 | then unit | |
459 | 465 | else fromBase58String(orderPriceAsset))])) | |
460 | 466 | } | |
461 | 467 | } | |
462 | 468 | } | |
463 | 469 | ||
464 | 470 | ||
471 | + | ||
472 | + | @Callable(i) | |
473 | + | func withdraw (mode) = if ((i.caller != admin)) | |
474 | + | then throw("You should be an admin") | |
475 | + | else if (if (if ((mode != "balance")) | |
476 | + | then (mode != "reserve") | |
477 | + | else false) | |
478 | + | then (mode != "all") | |
479 | + | else false) | |
480 | + | then throw("Specify the mode: balance, reserve or all") | |
481 | + | else { | |
482 | + | let balanceEntry = DataEntry("balance", 0) | |
483 | + | let balanceTransfer = ScriptTransfer(admin, balance, unit) | |
484 | + | let reserveEntry = DataEntry("reserve", 0) | |
485 | + | let reserveTransfer = ScriptTransfer(admin, reserve, unit) | |
486 | + | let writeSet = if ((mode == "balance")) | |
487 | + | then [balanceEntry] | |
488 | + | else if ((mode == "reserve")) | |
489 | + | then [reserveEntry] | |
490 | + | else if ((mode == "all")) | |
491 | + | then [balanceEntry, reserveEntry] | |
492 | + | else nil | |
493 | + | let transferSet = if ((mode == "balance")) | |
494 | + | then [balanceTransfer] | |
495 | + | else if ((mode == "reserve")) | |
496 | + | then [reserveTransfer] | |
497 | + | else if ((mode == "all")) | |
498 | + | then [balanceTransfer, reserveTransfer] | |
499 | + | else nil | |
500 | + | ScriptResult(WriteSet(writeSet), TransferSet(transferSet)) | |
501 | + | } | |
502 | + | ||
503 | + | ||
504 | + | ||
505 | + | @Callable(i) | |
506 | + | func doShutdown (msg) = if ((i.caller != admin)) | |
507 | + | then throw("You should be an admin") | |
508 | + | else WriteSet([DataEntry("shutdown_flag", true), DataEntry("shutdown_message", msg)]) | |
509 | + | ||
510 | + |
github/deemru/w8io/3ef1775 101.78 ms ◑