Master Core  v0.0.9 - 2abfd2849db8ba7a83957c64eb976b406713c123
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
mastercore_dex.cpp
Go to the documentation of this file.
1 // DEx & MetaDEx
2 
3 #include "base58.h"
4 #include "rpcserver.h"
5 #include "init.h"
6 #include "util.h"
7 #include "wallet.h"
8 
9 #include <stdint.h>
10 #include <string.h>
11 
12 #include <map>
13 #include <set>
14 
15 #include <fstream>
16 #include <algorithm>
17 
18 #include <vector>
19 
20 #include <utility>
21 #include <string>
22 
23 #include <boost/assign/list_of.hpp>
24 #include <boost/algorithm/string.hpp>
25 #include <boost/algorithm/string/find.hpp>
26 #include <boost/algorithm/string/join.hpp>
27 #include <boost/lexical_cast.hpp>
28 #include <boost/format.hpp>
29 #include <boost/filesystem.hpp>
30 #include "json/json_spirit_utils.h"
31 #include "json/json_spirit_value.h"
32 
33 #include "leveldb/db.h"
34 #include "leveldb/write_batch.h"
35 
36 #include <openssl/sha.h>
37 
38 #include <boost/math/constants/constants.hpp>
39 #include <boost/multiprecision/cpp_int.hpp>
40 #include <boost/multiprecision/cpp_dec_float.hpp>
41 
42 using boost::multiprecision::int128_t;
43 using boost::multiprecision::cpp_int;
44 using boost::multiprecision::cpp_dec_float;
45 using boost::multiprecision::cpp_dec_float_100;
46 
47 using namespace std;
48 using namespace boost;
49 using namespace boost::assign;
50 using namespace json_spirit;
51 using namespace leveldb;
52 
53 #include "mastercore.h"
54 
55 using namespace mastercore;
56 
57 #include "mastercore_convert.h"
58 #include "mastercore_dex.h"
59 #include "mastercore_tx.h"
60 
62 
64 
66 {
67 md_PropertiesMap::iterator it = metadex.find(prop);
68 
69  if (it != metadex.end()) return &(it->second);
70 
71  return (md_PricesMap *) NULL;
72 }
73 
75 {
76 md_PricesMap::iterator it = p->find(price);
77 
78  if (it != p->end()) return &(it->second);
79 
80  return (md_Set *) NULL;
81 }
82 
84 {
85  NOTHING = 0,
86  TRADED = 1,
91 };
92 
94 {
95  switch (ret)
96  {
97  case NOTHING: return string("NOTHING");
98  case TRADED: return string("TRADED");
99  case TRADED_MOREINSELLER: return string("TRADED_MOREINSELLER");
100  case TRADED_MOREINBUYER: return string("TRADED_MOREINBUYER");
101  case ADDED: return string("ADDED");
102  case CANCELLED: return string("CANCELLED");
103  default: return string("* unknown *");
104  }
105 }
106 
107 bool operator==(XDOUBLE first, XDOUBLE second)
108 {
109  return (first.str(INTERNAL_PRECISION_LEN, std::ios_base::fixed) == second.str(INTERNAL_PRECISION_LEN, std::ios_base::fixed));
110 }
111 
112 bool operator!=(XDOUBLE first, XDOUBLE second)
113 {
114  return !(first == second);
115 }
116 
117 bool operator<=(XDOUBLE first, XDOUBLE second)
118 {
119  return ((first.str(INTERNAL_PRECISION_LEN, std::ios_base::fixed) < second.str(INTERNAL_PRECISION_LEN, std::ios_base::fixed)) || (first == second));
120 }
121 
122 bool operator>=(XDOUBLE first, XDOUBLE second)
123 {
124  return ((first.str(INTERNAL_PRECISION_LEN, std::ios_base::fixed) > second.str(INTERNAL_PRECISION_LEN, std::ios_base::fixed)) || (first == second));
125 }
126 
127 static void PriceCheck(const string &label, XDOUBLE left, XDOUBLE right)
128 {
129 const bool bOK = (left == right);
130 
131  file_log("PRICE CHECK %s: buyer = %s , inserted = %s : %s\n", label,
132  left.str(DISPLAY_PRECISION_LEN, std::ios_base::fixed),
133  right.str(DISPLAY_PRECISION_LEN, std::ios_base::fixed), bOK ? "good":"PROBLEM!");
134 }
135 
136 // find the best match on the market
137 // NOTE: sometimes I refer to the older order as seller & the newer order as buyer, in this trade
138 // INPUT: property, desprop, desprice = of the new order being inserted; the new object being processed
139 // RETURN:
141 {
142 const CMPMetaDEx *p_older = NULL;
143 md_PricesMap *prices = NULL;
144 const unsigned int prop = newo->getProperty();
145 const unsigned int desprop = newo->getDesProperty();
146 MatchReturnType NewReturn = NOTHING;
147 bool bBuyerSatisfied = false;
148 const XDOUBLE buyersprice = newo->effectivePrice();
149 const XDOUBLE desprice = (1/buyersprice); // inverse, to be matched against that of the existing older order
150 
151  if (msc_debug_metadex1)
152  {
153  file_log("%s(%s: prop=%u, desprop=%u, desprice= %s);newo: %s\n",
154  __FUNCTION__, newo->getAddr(), prop, desprop, desprice.str(DISPLAY_PRECISION_LEN, std::ios_base::fixed), newo->ToString());
155  }
156 
157  prices = get_Prices(desprop);
158 
159  // nothing for the desired property exists in the market, sorry!
160  if (!prices)
161  {
162  file_log("%s()=%u:%s NOT FOUND ON THE MARKET\n", __FUNCTION__, NewReturn, getTradeReturnType(NewReturn));
163  return NewReturn;
164  }
165 
166  // within the desired property map (given one property) iterate over the items looking at prices
167  for (md_PricesMap::iterator my_it = prices->begin(); my_it != prices->end(); ++my_it)
168  { // check all prices
169  XDOUBLE sellers_price = (my_it->first);
170 
171  if (msc_debug_metadex2) file_log("comparing prices: desprice %s needs to be GREATER THAN OR EQUAL TO %s\n",
172  desprice.str(DISPLAY_PRECISION_LEN, std::ios_base::fixed), sellers_price.str(DISPLAY_PRECISION_LEN, std::ios_base::fixed));
173 
174  // Is the desired price check satisfied? The buyer's inverse price must be larger than that of the seller.
175  if (desprice < sellers_price) continue;
176 
177  md_Set *indexes = &(my_it->second);
178 
179  // at good (single) price level and property iterate over offers looking at all parameters to find the match
180  md_Set::iterator iitt;
181  for (iitt = indexes->begin(); iitt != indexes->end();)
182  { // specific price, check all properties
183  p_older = &(*iitt);
184 
185  if (msc_debug_metadex1) file_log("Looking at existing: %s (its prop= %u, its des prop= %u) = %s\n",
186  sellers_price.str(DISPLAY_PRECISION_LEN, std::ios_base::fixed), p_older->getProperty(), p_older->getDesProperty(), p_older->ToString());
187 
188  // is the desired property correct?
189  if (p_older->getDesProperty() != prop)
190  {
191  ++iitt;
192  continue;
193  }
194 
195  if (msc_debug_metadex1) file_log("MATCH FOUND, Trade: %s = %s\n", sellers_price.str(DISPLAY_PRECISION_LEN, std::ios_base::fixed), p_older->ToString());
196 
197  // All Matched ! Trade now.
198  // p_older is the old order pointer
199  // newo is the new order pointer
200  // the price in the older order is used
201  const int64_t seller_amountForSale = p_older->getAmountForSale();
202  const int64_t seller_amountWanted = p_older->getAmountDesired();
203  const int64_t buyer_amountOffered = newo->getAmountForSale();
204 
205  if (msc_debug_metadex1) file_log("$$ trading using price: %s; seller: forsale= %ld, wanted= %ld, buyer amount offered= %ld\n",
206  sellers_price.str(DISPLAY_PRECISION_LEN, std::ios_base::fixed), seller_amountForSale, seller_amountWanted, buyer_amountOffered);
207 
208  if (msc_debug_metadex1) file_log("$$ old: %s\n", p_older->ToString());
209  if (msc_debug_metadex1) file_log("$$ new: %s\n", newo->ToString());
210 
211  int64_t seller_amountGot = seller_amountWanted;
212 
213  if (buyer_amountOffered < seller_amountWanted)
214  {
215  seller_amountGot = buyer_amountOffered;
216  }
217 
218  const int64_t buyer_amountStillForSale = buyer_amountOffered - seller_amountGot;
219 
221  XDOUBLE x_buyer_got = (XDOUBLE) seller_amountGot / sellers_price;
222 
223  x_buyer_got += (XDOUBLE) 0.5; // ROUND UP
224 
225  std::string str_buyer_got = x_buyer_got.str(INTERNAL_PRECISION_LEN, std::ios_base::fixed);
226  std::string str_buyer_got_int_part = str_buyer_got.substr(0, str_buyer_got.find_first_of("."));
227  const int64_t buyer_amountGot = boost::lexical_cast<int64_t>( str_buyer_got_int_part );
228 
229  const int64_t seller_amountLeft = p_older->getAmountForSale() - buyer_amountGot;
230 
231  if (msc_debug_metadex1) file_log("$$ buyer_got= %ld, seller_got= %ld, seller_left_for_sale= %ld, buyer_still_for_sale= %ld\n",
232  buyer_amountGot, seller_amountGot, seller_amountLeft, buyer_amountStillForSale);
233 
234  XDOUBLE seller_amount_stilldesired = (XDOUBLE) seller_amountLeft * sellers_price;
235 
236  seller_amount_stilldesired += (XDOUBLE) 0.5; // ROUND UP
237 
238  std::string str_amount_stilldesired = seller_amount_stilldesired.str(INTERNAL_PRECISION_LEN, std::ios_base::fixed);
239  std::string str_stilldesired_int_part = str_amount_stilldesired.substr(0, str_amount_stilldesired.find_first_of("."));
240 
242  CMPMetaDEx seller_replacement = *p_older;
243 
244  seller_replacement.setAmountForSale(seller_amountLeft, "seller_replacement");
245  seller_replacement.setAmountDesired(boost::lexical_cast<int64_t>( str_stilldesired_int_part ), "seller_replacement");
246 
247  // transfer the payment property from buyer to seller
248  // TODO: do something when failing here............
249  // FIXME
250  // ...
251  if (update_tally_map(newo->getAddr(), newo->getProperty(), - seller_amountGot, BALANCE))
252  {
253  if (update_tally_map(p_older->getAddr(), p_older->getDesProperty(), seller_amountGot, BALANCE))
254  {
255  }
256  }
257 
258  // transfer the market (the one being sold) property from seller to buyer
259  // TODO: do something when failing here............
260  // FIXME
261  // ...
262  if (update_tally_map(p_older->getAddr(), p_older->getProperty(), - buyer_amountGot, METADEX_RESERVE))
263  {
264  update_tally_map(newo->getAddr(), newo->getDesProperty(), buyer_amountGot, BALANCE);
265  }
266 
267  NewReturn = TRADED;
268 
269  XDOUBLE will_pay = (XDOUBLE) buyer_amountStillForSale * newo->effectivePrice();
270 
271  will_pay += (XDOUBLE) 0.5; // ROUND UP
272 
273  std::string str_will_pay = will_pay.str(INTERNAL_PRECISION_LEN, std::ios_base::fixed);
274  std::string str_will_pay_int_part = str_will_pay.substr(0, str_will_pay.find_first_of("."));
275 
276  newo->setAmountForSale(buyer_amountStillForSale, "buyer");
277  newo->setAmountDesired(boost::lexical_cast<int64_t>( str_will_pay_int_part ), "buyer");
278 
279  if (0 < buyer_amountStillForSale)
280  {
281  NewReturn = TRADED_MOREINBUYER;
282 
283  PriceCheck(getTradeReturnType(NewReturn), buyersprice, newo->effectivePrice());
284  }
285  else
286  {
287  bBuyerSatisfied = true;
288  }
289 
290  if (0 < seller_amountLeft) // done with all loops, update the seller, buyer is fully satisfied
291  {
292  NewReturn = TRADED_MOREINSELLER;
293  bBuyerSatisfied = true;
294 
295  PriceCheck(getTradeReturnType(NewReturn), p_older->effectivePrice(), seller_replacement.effectivePrice());
296  }
297 
298  if (msc_debug_metadex1) file_log("==== TRADED !!! %u=%s\n", NewReturn, getTradeReturnType(NewReturn));
299 
300  t_tradelistdb->recordTrade(p_older->getHash(), newo->getHash(),
301  p_older->getAddr(), newo->getAddr(), p_older->getDesProperty(), newo->getDesProperty(), seller_amountGot, buyer_amountGot, newo->getBlock());
302 
303  if (msc_debug_metadex1) file_log("++ erased old: %s\n", iitt->ToString());
304  // erase the old seller element
305  indexes->erase(iitt++);
306 
307  if (bBuyerSatisfied)
308  {
309  // insert the updated one in place of the old
310  if (0 < seller_replacement.getAmountForSale())
311  {
312  file_log("++ inserting seller_replacement: %s\n", seller_replacement.ToString());
313  indexes->insert(seller_replacement);
314  }
315  break;
316  }
317  } // specific price, check all properties
318 
319  if (bBuyerSatisfied) break;
320  } // check all prices
321 
322  file_log("%s()=%u:%s\n", __FUNCTION__, NewReturn, getTradeReturnType(NewReturn));
323 
324  return NewReturn;
325 }
326 
327 void mastercore::MetaDEx_debug_print(bool bShowPriceLevel, bool bDisplay)
328 {
329  file_log("<<<\n");
330  for (md_PropertiesMap::iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it)
331  {
332  unsigned int prop = my_it->first;
333 
334  file_log(" ## property: %u\n", prop);
335  md_PricesMap & prices = my_it->second;
336 
337  for (md_PricesMap::iterator it = prices.begin(); it != prices.end(); ++it)
338  {
339  XDOUBLE price = (it->first);
340  md_Set & indexes = (it->second);
341 
342  if (bShowPriceLevel) file_log(" # Price Level: %s\n", price.str(DISPLAY_PRECISION_LEN, std::ios_base::fixed));
343 
344  for (md_Set::iterator it = indexes.begin(); it != indexes.end(); ++it)
345  {
346  CMPMetaDEx obj = *it;
347 
348  if (bDisplay) printf("%s= %s\n", price.str(DISPLAY_PRECISION_LEN, std::ios_base::fixed).c_str() , obj.ToString().c_str());
349  else file_log("%s= %s\n", price.str(DISPLAY_PRECISION_LEN, std::ios_base::fixed) , obj.ToString());
350 
351  // extra checks: price or either of the amounts is 0
352 // assert((XDOUBLE)0 != obj.effectivePrice());
353 // assert(obj.getAmountForSale());
354 // assert(obj.getAmountDesired());
355  }
356  }
357  }
358  file_log(">>>\n");
359 }
360 
361 void CMPMetaDEx::Set(const string &sa, int b, unsigned int c, uint64_t nValue, unsigned int cd, uint64_t ad, const uint256 &tx, unsigned int i, unsigned char suba)
362 {
363  addr = sa;
364  block = b;
365  txid = tx;
366  property = c;
367  amount_forsale = nValue;
368  desired_property = cd;
369  amount_desired = ad;
370  idx = i;
371  subaction = suba;
372 }
373 
374 CMPMetaDEx::CMPMetaDEx(const string &addr, int b, unsigned int c, uint64_t nValue, unsigned int cd, uint64_t ad, const uint256 &tx, unsigned int i, unsigned char suba, uint64_t lfors)
375 {
376  still_left_forsale = lfors;
377  Set(addr, b,c,nValue,cd,ad,tx,i,suba);
378 }
379 
380 std::string CMPMetaDEx::ToString() const
381 {
382  return strprintf("%s:%34s in %d/%03u, txid: %s , trade #%u %s for #%u %s",
383  effectivePrice().str(DISPLAY_PRECISION_LEN, std::ios_base::fixed),
384  addr.c_str(), block, idx, txid.ToString().substr(0,10).c_str(),
385  property, FormatMP(property, amount_forsale), desired_property, FormatMP(desired_property, amount_desired));
386 }
387 
388 // check to see if such a sell offer exists
389 bool mastercore::DEx_offerExists(const string &seller_addr, unsigned int prop)
390 {
391 // if (msc_debug_dex) file_log("%s()\n", __FUNCTION__);
392 const string combo = STR_SELLOFFER_ADDR_PROP_COMBO(seller_addr);
393 OfferMap::iterator my_it = my_offers.find(combo);
394 
395  return !(my_it == my_offers.end());
396 }
397 
398 // getOffer may replace DEx_offerExists() in the near future
399 // TODO: locks are needed around map's insert & erase
400 CMPOffer *mastercore::DEx_getOffer(const string &seller_addr, unsigned int prop)
401 {
402  if (msc_debug_dex) file_log("%s(%s, %u)\n", __FUNCTION__, seller_addr, prop);
403 const string combo = STR_SELLOFFER_ADDR_PROP_COMBO(seller_addr);
404 OfferMap::iterator my_it = my_offers.find(combo);
405 
406  if (my_it != my_offers.end()) return &(my_it->second);
407 
408  return (CMPOffer *) NULL;
409 }
410 
411 // TODO: locks are needed around map's insert & erase
412 CMPAccept *mastercore::DEx_getAccept(const string &seller_addr, unsigned int prop, const string &buyer_addr)
413 {
414  if (msc_debug_dex) file_log("%s(%s, %u, %s)\n", __FUNCTION__, seller_addr, prop, buyer_addr);
415 const string combo = STR_ACCEPT_ADDR_PROP_ADDR_COMBO(seller_addr, buyer_addr);
416 AcceptMap::iterator my_it = my_accepts.find(combo);
417 
418  if (my_it != my_accepts.end()) return &(my_it->second);
419 
420  return (CMPAccept *) NULL;
421 }
422 
423 // returns 0 if everything is OK
424 int mastercore::DEx_offerCreate(string seller_addr, unsigned int prop, uint64_t nValue, int block, uint64_t amount_des, uint64_t fee, unsigned char btl, const uint256 &txid, uint64_t *nAmended)
425 {
426 int rc = DEX_ERROR_SELLOFFER;
427 
428  // sanity check our params are OK
429  if ((!btl) || (!amount_des)) return (DEX_ERROR_SELLOFFER -101); // time limit or amount desired empty
430 
431  if (DEx_getOffer(seller_addr, prop)) return (DEX_ERROR_SELLOFFER -10); // offer already exists
432 
433  const string combo = STR_SELLOFFER_ADDR_PROP_COMBO(seller_addr);
434 
435  if (msc_debug_dex)
436  file_log("%s(%s|%s), nValue=%lu)\n", __FUNCTION__, seller_addr, combo, nValue);
437 
438  const uint64_t balanceReallyAvailable = getMPbalance(seller_addr, prop, BALANCE);
439 
440  // if offering more than available -- put everything up on sale
441  if (nValue > balanceReallyAvailable)
442  {
443  double BTC;
444 
445  // AND we must also re-adjust the BTC desired in this case...
446  BTC = amount_des * balanceReallyAvailable;
447  BTC /= (double)nValue;
448  amount_des = rounduint64(BTC);
449 
450  nValue = balanceReallyAvailable;
451 
452  if (nAmended) *nAmended = nValue;
453  }
454 
455  if (update_tally_map(seller_addr, prop, - nValue, BALANCE)) // subtract from what's available
456  {
457  update_tally_map(seller_addr, prop, nValue, SELLOFFER_RESERVE); // put in reserve
458 
459  my_offers.insert(std::make_pair(combo, CMPOffer(block, nValue, prop, amount_des, fee, btl, txid)));
460 
461  rc = 0;
462  }
463 
464  return rc;
465 }
466 
467 // returns 0 if everything is OK
468 int mastercore::DEx_offerDestroy(const string &seller_addr, unsigned int prop)
469 {
470 const uint64_t amount = getMPbalance(seller_addr, prop, SELLOFFER_RESERVE);
471 
472  if (!DEx_offerExists(seller_addr, prop)) return (DEX_ERROR_SELLOFFER -11); // offer does not exist
473 
474  const string combo = STR_SELLOFFER_ADDR_PROP_COMBO(seller_addr);
475 
476  OfferMap::iterator my_it;
477 
478  my_it = my_offers.find(combo);
479 
480  if (amount)
481  {
482  update_tally_map(seller_addr, prop, amount, BALANCE); // give back to the seller from SellOffer-Reserve
483  update_tally_map(seller_addr, prop, - amount, SELLOFFER_RESERVE);
484  }
485 
486  // delete the offer
487  my_offers.erase(my_it);
488 
489  if (msc_debug_dex)
490  file_log("%s(%s|%s)\n", __FUNCTION__, seller_addr, combo);
491 
492  return 0;
493 }
494 
495 // returns 0 if everything is OK
496 int mastercore::DEx_offerUpdate(const string &seller_addr, unsigned int prop, uint64_t nValue, int block, uint64_t desired, uint64_t fee, unsigned char btl, const uint256 &txid, uint64_t *nAmended)
497 {
498 int rc = DEX_ERROR_SELLOFFER;
499 
500  file_log("%s(%s, %d)\n", __FUNCTION__, seller_addr, prop);
501 
502  if (!DEx_offerExists(seller_addr, prop)) return (DEX_ERROR_SELLOFFER -12); // offer does not exist
503 
504  rc = DEx_offerDestroy(seller_addr, prop);
505 
506  if (!rc)
507  {
508  rc = DEx_offerCreate(seller_addr, prop, nValue, block, desired, fee, btl, txid, nAmended);
509  }
510 
511  return rc;
512 }
513 
514 // returns 0 if everything is OK
515 int mastercore::DEx_acceptCreate(const string &buyer, const string &seller, int prop, uint64_t nValue, int block, uint64_t fee_paid, uint64_t *nAmended)
516 {
517 int rc = DEX_ERROR_ACCEPT - 10;
518 OfferMap::iterator my_it;
519 const string selloffer_combo = STR_SELLOFFER_ADDR_PROP_COMBO(seller);
520 const string accept_combo = STR_ACCEPT_ADDR_PROP_ADDR_COMBO(seller, buyer);
521 uint64_t nActualAmount = getMPbalance(seller, prop, SELLOFFER_RESERVE);
522 
523  my_it = my_offers.find(selloffer_combo);
524 
525  if (my_it == my_offers.end()) return DEX_ERROR_ACCEPT -15;
526 
527  CMPOffer &offer = my_it->second;
528 
529  if (msc_debug_dex) file_log("%s(offer: %s)\n", __FUNCTION__, offer.getHash().GetHex());
530 
531  // here we ensure the correct BTC fee was paid in this acceptance message, per spec
532  if (fee_paid < offer.getMinFee())
533  {
534  file_log("ERROR: fee too small -- the ACCEPT is rejected! (%lu is smaller than %lu)\n", fee_paid, offer.getMinFee());
535  return DEX_ERROR_ACCEPT -105;
536  }
537 
538  file_log("%s(%s) OFFER FOUND\n", __FUNCTION__, selloffer_combo);
539 
540  // the older accept is the valid one: do not accept any new ones!
541  if (DEx_getAccept(seller, prop, buyer))
542  {
543  file_log("%s() ERROR: an accept from this same seller for this same offer is already open !!!!!\n", __FUNCTION__);
544  return DEX_ERROR_ACCEPT -205;
545  }
546 
547  if (nActualAmount > nValue)
548  {
549  nActualAmount = nValue;
550 
551  if (nAmended) *nAmended = nActualAmount;
552  }
553 
554  // TODO: think if we want to save nValue -- as the amount coming off the wire into the object or not
555  if (update_tally_map(seller, prop, - nActualAmount, SELLOFFER_RESERVE))
556  {
557  if (update_tally_map(seller, prop, nActualAmount, ACCEPT_RESERVE))
558  {
559  // insert into the map !
560  my_accepts.insert(std::make_pair(accept_combo, CMPAccept(nActualAmount, block,
561  offer.getBlockTimeLimit(), offer.getProperty(), offer.getOfferAmountOriginal(), offer.getBTCDesiredOriginal(), offer.getHash() )));
562 
563  rc = 0;
564  }
565  }
566 
567  return rc;
568 }
569 
570 // this function is called by handler_block() for each Accept that has expired
571 // this function is also called when the purchase has been completed (the buyer bought everything he was allocated)
572 //
573 // returns 0 if everything is OK
574 int mastercore::DEx_acceptDestroy(const string &buyer, const string &seller, int prop, bool bForceErase)
575 {
576 int rc = DEX_ERROR_ACCEPT - 20;
577 CMPOffer *p_offer = DEx_getOffer(seller, prop);
578 CMPAccept *p_accept = DEx_getAccept(seller, prop, buyer);
579 bool bReturnToMoney; // return to BALANCE of the seller, otherwise return to SELLOFFER_RESERVE
580 const string accept_combo = STR_ACCEPT_ADDR_PROP_ADDR_COMBO(seller, buyer);
581 
582  if (!p_accept) return rc; // sanity check
583 
584  const uint64_t nActualAmount = p_accept->getAcceptAmountRemaining();
585 
586  // if the offer is gone ACCEPT_RESERVE should go back to BALANCE
587  if (!p_offer)
588  {
589  bReturnToMoney = true;
590  }
591  else
592  {
593  file_log("%s() HASHES: offer=%s, accept=%s\n", __FUNCTION__, p_offer->getHash().GetHex(), p_accept->getHash().GetHex());
594 
595  // offer exists, determine whether it's the original offer or some random new one
596  if (p_offer->getHash() == p_accept->getHash())
597  {
598  // same offer, return to SELLOFFER_RESERVE
599  bReturnToMoney = false;
600  }
601  else
602  {
603  // old offer is gone !
604  bReturnToMoney = true;
605  }
606  }
607 
608  if (bReturnToMoney)
609  {
610  if (update_tally_map(seller, prop, - nActualAmount, ACCEPT_RESERVE))
611  {
612  update_tally_map(seller, prop, nActualAmount, BALANCE);
613  rc = 0;
614  }
615  }
616  else
617  {
618  // return to SELLOFFER_RESERVE
619  if (update_tally_map(seller, prop, - nActualAmount, ACCEPT_RESERVE))
620  {
621  update_tally_map(seller, prop, nActualAmount, SELLOFFER_RESERVE);
622  rc = 0;
623  }
624  }
625 
626  // can only erase when is NOT called from an iterator loop
627  if (bForceErase)
628  {
629  const AcceptMap::iterator my_it = my_accepts.find(accept_combo);
630 
631  if (my_accepts.end() !=my_it) my_accepts.erase(my_it);
632  }
633 
634  return rc;
635 }
636 
637 // incoming BTC payment for the offer
638 // TODO: verify proper partial payment handling
639 int mastercore::DEx_payment(uint256 txid, unsigned int vout, string seller, string buyer, uint64_t BTC_paid, int blockNow, uint64_t *nAmended)
640 {
641 // if (msc_debug_dex) file_log("%s()\n", __FUNCTION__);
642 int rc = DEX_ERROR_PAYMENT;
643 CMPAccept *p_accept;
644 int prop;
645 
646 prop = OMNI_PROPERTY_MSC; //test for MSC accept first
647 p_accept = DEx_getAccept(seller, prop, buyer);
648 
649  if (!p_accept)
650  {
651  prop = OMNI_PROPERTY_TMSC; //test for TMSC accept second
652  p_accept = DEx_getAccept(seller, prop, buyer);
653  }
654 
655  if (msc_debug_dex) file_log("%s(%s, %s)\n", __FUNCTION__, seller, buyer);
656 
657  if (!p_accept) return (DEX_ERROR_PAYMENT -1); // there must be an active Accept for this payment
658 
659  const double BTC_desired_original = p_accept->getBTCDesiredOriginal();
660  const double offer_amount_original = p_accept->getOfferAmountOriginal();
661 
662  if (0==(double)BTC_desired_original) return (DEX_ERROR_PAYMENT -2); // divide by 0 protection
663 
664  double perc_X = (double)BTC_paid/BTC_desired_original;
665  double Purchased = offer_amount_original * perc_X;
666 
667  uint64_t units_purchased = rounduint64(Purchased);
668 
669  const uint64_t nActualAmount = p_accept->getAcceptAmountRemaining(); // actual amount desired, in the Accept
670 
671  if (msc_debug_dex)
672  file_log("BTC_desired= %30.20lf , offer_amount=%30.20lf , perc_X= %30.20lf , Purchased= %30.20lf , units_purchased= %lu\n",
673  BTC_desired_original, offer_amount_original, perc_X, Purchased, units_purchased);
674 
675  // if units_purchased is greater than what's in the Accept, the buyer gets only what's in the Accept
676  if (nActualAmount < units_purchased)
677  {
678  units_purchased = nActualAmount;
679 
680  if (nAmended) *nAmended = units_purchased;
681  }
682 
683  if (update_tally_map(seller, prop, - units_purchased, ACCEPT_RESERVE))
684  {
685  update_tally_map(buyer, prop, units_purchased, BALANCE);
686  rc = 0;
687  bool bValid = true;
688  p_txlistdb->recordPaymentTX(txid, bValid, blockNow, vout, prop, units_purchased, buyer, seller);
689 
690  file_log("#######################################################\n");
691  }
692 
693  // reduce the amount of units still desired by the buyer and if 0 must destroy the Accept
694  if (p_accept->reduceAcceptAmountRemaining_andIsZero(units_purchased))
695  {
696  const uint64_t selloffer_reserve = getMPbalance(seller, prop, SELLOFFER_RESERVE);
697  const uint64_t accept_reserve = getMPbalance(seller, prop, ACCEPT_RESERVE);
698 
699  DEx_acceptDestroy(buyer, seller, prop, true);
700 
701  // delete the Offer object if there is nothing in its Reserves -- everything got puchased and paid for
702  if ((0 == selloffer_reserve) && (0 == accept_reserve))
703  {
704  DEx_offerDestroy(seller, prop);
705  }
706  }
707 
708  return rc;
709 }
710 
711 unsigned int eraseExpiredAccepts(int blockNow)
712 {
713 unsigned int how_many_erased = 0;
714 AcceptMap::iterator my_it = my_accepts.begin();
715 
716  while (my_accepts.end() != my_it)
717  {
718  // my_it->first = key
719  // my_it->second = value
720 
721  CMPAccept &mpaccept = my_it->second;
722 
723  if ((blockNow - mpaccept.block) >= (int) mpaccept.getBlockTimeLimit())
724  {
725  file_log("%s() FOUND EXPIRED ACCEPT, erasing: blockNow=%d, offer block=%d, blocktimelimit= %d\n",
726  __FUNCTION__, blockNow, mpaccept.block, mpaccept.getBlockTimeLimit());
727 
728  // extract the seller, buyer & property from the Key
729  std::vector<std::string> vstr;
730  boost::split(vstr, my_it->first, boost::is_any_of("-+"), token_compress_on);
731  string seller = vstr[0];
732  int property = atoi(vstr[1]);
733  string buyer = vstr[2];
734 
735  DEx_acceptDestroy(buyer, seller, property);
736 
737  my_accepts.erase(my_it++);
738 
739  ++how_many_erased;
740  }
741  else my_it++;
742 
743  }
744 
745  return how_many_erased;
746 }
747 
748 // pretty much directly linked to the ADD TX21 command off the wire
749 int mastercore::MetaDEx_ADD(const string &sender_addr, unsigned int prop, uint64_t amount, int block, unsigned int property_desired, uint64_t amount_desired, const uint256 &txid, unsigned int idx)
750 {
751 int rc = METADEX_ERROR -1;
752 
753  // MetaDEx implementation phase 1 check
754  if ((prop != OMNI_PROPERTY_MSC) && (property_desired != OMNI_PROPERTY_MSC) &&
755  (prop != OMNI_PROPERTY_TMSC) && (property_desired != OMNI_PROPERTY_TMSC))
756  {
757  return METADEX_ERROR -800;
758  }
759 
760  // store the data into the temp MetaDEx object here
761  CMPMetaDEx new_mdex(sender_addr, block, prop, amount, property_desired, amount_desired, txid, idx, CMPTransaction::ADD);
762  XDOUBLE neworder_buyersprice = new_mdex.effectivePrice();
763 
764  if (msc_debug_metadex1) file_log("%s(); buyer obj: %s\n", __FUNCTION__, new_mdex.ToString());
765 
766  // given the property & the price find the proper place for insertion
767 
768  // TODO: reconsider for boost::multiprecision
769  // FIXME
770  if (0 >= neworder_buyersprice)
771  {
772  // do not work with 0 prices
773  return METADEX_ERROR -66;
774  }
775 
776  if (msc_debug_metadex3) MetaDEx_debug_print();
777 
778  // TRADE, check matches, remainder of the order will be put into the order book
779  x_Trade(&new_mdex);
780 
781  if (msc_debug_metadex3) MetaDEx_debug_print();
782 
783 #if 0
784  // if anything is left in the new order, INSERT
785  if ((0 < new_mdex.getAmountForSale()) && (!disable_Combo))
786  {
787  x_AddOrCancel(&new_mdex); // straight match to ADD
788  }
789 #endif
790 
791  if (msc_debug_metadex3) MetaDEx_debug_print();
792 
793  // plain insert
794  if (0 < new_mdex.getAmountForSale())
795  { // not added nor subtracted, insert as new or post-traded amounts
796  md_PricesMap temp_prices, *p_prices = get_Prices(prop);
797  md_Set temp_indexes, *p_indexes = NULL;
798  std::pair<md_Set::iterator,bool> ret;
799 
800  if (p_prices)
801  {
802  p_indexes = get_Indexes(p_prices, neworder_buyersprice);
803  }
804 
805  if (!p_indexes) p_indexes = &temp_indexes;
806 
807  ret = p_indexes->insert(new_mdex);
808 
809  if (false == ret.second)
810  {
811  file_log("%s() ERROR: ALREADY EXISTS, line %d, file: %s\n", __FUNCTION__, __LINE__, __FILE__);
812  }
813  else
814  {
815  // TODO: think about failure scenarios
816  // FIXME
817  if (update_tally_map(sender_addr, prop, - new_mdex.getAmountForSale(), BALANCE)) // subtract from what's available
818  {
819  // TODO: think about failure scenarios
820  // FIXME
821  update_tally_map(sender_addr, prop, new_mdex.getAmountForSale(), METADEX_RESERVE); // put in reserve
822  }
823 
824  // price check
825  PriceCheck("Insert", neworder_buyersprice, new_mdex.effectivePrice());
826 
827  if (msc_debug_metadex1) file_log("==== INSERTED: %s= %s\n", neworder_buyersprice.str(DISPLAY_PRECISION_LEN, std::ios_base::fixed), new_mdex.ToString());
828  }
829 
830  if (!p_prices) p_prices = &temp_prices;
831 
832  (*p_prices)[neworder_buyersprice] = *p_indexes;
833 
834  metadex[prop] = *p_prices;
835  } // Must Insert
836 
837  rc = 0;
838 
839  if (msc_debug_metadex3) MetaDEx_debug_print();
840 
841  return rc;
842 }
843 
844 int mastercore::MetaDEx_CANCEL_AT_PRICE(const uint256 txid, unsigned int block, const string &sender_addr, unsigned int prop, uint64_t amount, unsigned int property_desired, uint64_t amount_desired)
845 {
846 int rc = METADEX_ERROR -20;
847 CMPMetaDEx mdex(sender_addr, 0, prop, amount, property_desired, amount_desired, 0, 0, CMPTransaction::CANCEL_AT_PRICE);
848 md_PricesMap *prices = get_Prices(prop);
849 const CMPMetaDEx *p_mdex = NULL;
850 
851  if (msc_debug_metadex1) file_log("%s():%s\n", __FUNCTION__, mdex.ToString());
852 
853  if (msc_debug_metadex2) MetaDEx_debug_print();
854 
855  if (!prices)
856  {
857  file_log("%s() NOTHING FOUND for %s\n", __FUNCTION__, mdex.ToString());
858  return rc -1;
859  }
860 
861  // within the desired property map (given one property) iterate over the items
862  for (md_PricesMap::iterator my_it = prices->begin(); my_it != prices->end(); ++my_it)
863  {
864  XDOUBLE sellers_price = (my_it->first);
865 
866  if (mdex.effectivePrice() != sellers_price) continue;
867 
868  md_Set *indexes = &(my_it->second);
869 
870  for (md_Set::iterator iitt = indexes->begin(); iitt != indexes->end();)
871  { // for iitt
872  p_mdex = &(*iitt);
873 
874  if (msc_debug_metadex3) file_log("%s(): %s\n", __FUNCTION__, p_mdex->ToString());
875 
876  if ((p_mdex->getDesProperty() != property_desired) || (p_mdex->getAddr() != sender_addr))
877  {
878  ++iitt;
879  continue;
880  }
881 
882  rc = 0;
883  file_log("%s(): REMOVING %s\n", __FUNCTION__, p_mdex->ToString());
884 
885  // move from reserve to main
886  update_tally_map(p_mdex->getAddr(), p_mdex->getProperty(), - p_mdex->getAmountForSale(), METADEX_RESERVE);
887  update_tally_map(p_mdex->getAddr(), p_mdex->getProperty(), p_mdex->getAmountForSale(), BALANCE);
888 
889  // record the cancellation
890  bool bValid = true;
891  p_txlistdb->recordMetaDExCancelTX(txid, p_mdex->getHash(), bValid, block, p_mdex->getProperty(), p_mdex->getAmountForSale());
892 
893  indexes->erase(iitt++);
894  }
895  }
896 
897  if (msc_debug_metadex2) MetaDEx_debug_print();
898 
899  return rc;
900 }
901 
902 int mastercore::MetaDEx_CANCEL_ALL_FOR_PAIR(const uint256 txid, unsigned int block, const string &sender_addr, unsigned int prop, unsigned int property_desired)
903 {
904 int rc = METADEX_ERROR -30;
905 md_PricesMap *prices = get_Prices(prop);
906 const CMPMetaDEx *p_mdex = NULL;
907 
908  file_log("%s(%d,%d)\n", __FUNCTION__, prop, property_desired);
909 
910  if (msc_debug_metadex3) MetaDEx_debug_print();
911 
912  if (!prices)
913  {
914  file_log("%s() NOTHING FOUND\n", __FUNCTION__);
915  return rc -1;
916  }
917 
918  // within the desired property map (given one property) iterate over the items
919  for (md_PricesMap::iterator my_it = prices->begin(); my_it != prices->end(); ++my_it)
920  {
921  md_Set *indexes = &(my_it->second);
922 
923  for (md_Set::iterator iitt = indexes->begin(); iitt != indexes->end();)
924  { // for iitt
925  p_mdex = &(*iitt);
926 
927  if (msc_debug_metadex3) file_log("%s(): %s\n", __FUNCTION__, p_mdex->ToString());
928 
929  if ((p_mdex->getDesProperty() != property_desired) || (p_mdex->getAddr() != sender_addr))
930  {
931  ++iitt;
932  continue;
933  }
934 
935  rc = 0;
936  file_log("%s(): REMOVING %s\n", __FUNCTION__, p_mdex->ToString());
937 
938  // move from reserve to main
939  update_tally_map(p_mdex->getAddr(), p_mdex->getProperty(), - p_mdex->getAmountForSale(), METADEX_RESERVE);
940  update_tally_map(p_mdex->getAddr(), p_mdex->getProperty(), p_mdex->getAmountForSale(), BALANCE);
941 
942  // record the cancellation
943  bool bValid = true;
944  p_txlistdb->recordMetaDExCancelTX(txid, p_mdex->getHash(), bValid, block, p_mdex->getProperty(), p_mdex->getAmountForSale());
945 
946  indexes->erase(iitt++);
947  }
948  }
949 
950  if (msc_debug_metadex3) MetaDEx_debug_print();
951 
952  return rc;
953 }
954 
955 // scan the orderbook and remove everything for an address
956 int mastercore::MetaDEx_CANCEL_EVERYTHING(const uint256 txid, unsigned int block, const string &sender_addr)
957 {
958 int rc = METADEX_ERROR -40;
959 
960  file_log("%s()\n", __FUNCTION__);
961 
962  if (msc_debug_metadex2) MetaDEx_debug_print();
963 
964  file_log("<<<<<<\n");
965 
966  for (md_PropertiesMap::iterator my_it = metadex.begin(); my_it != metadex.end(); ++my_it)
967  {
968  unsigned int prop = my_it->first;
969 
970  file_log(" ## property: %u\n", prop);
971  md_PricesMap & prices = my_it->second;
972 
973  for (md_PricesMap::iterator it = prices.begin(); it != prices.end(); ++it)
974  {
975  XDOUBLE price = (it->first);
976  md_Set & indexes = (it->second);
977 
978  file_log(" # Price Level: %s\n", price.str(DISPLAY_PRECISION_LEN, std::ios_base::fixed));
979 
980  for (md_Set::iterator it = indexes.begin(); it != indexes.end();)
981  {
982  file_log("%s= %s\n", price.str(DISPLAY_PRECISION_LEN, std::ios_base::fixed) , it->ToString());
983 
984  if ((it->getAddr() != sender_addr))
985  {
986  ++it;
987  continue;
988  }
989 
990  rc = 0;
991  file_log("%s(): REMOVING %s\n", __FUNCTION__, it->ToString());
992 
993  // move from reserve to balance
994  update_tally_map(it->getAddr(), it->getProperty(), - it->getAmountForSale(), METADEX_RESERVE);
995  update_tally_map(it->getAddr(), it->getProperty(), it->getAmountForSale(), BALANCE);
996 
997  // record the cancellation
998  bool bValid = true;
999  p_txlistdb->recordMetaDExCancelTX(txid, it->getHash(), bValid, block, it->getProperty(), it->getAmountForSale());
1000 
1001  indexes.erase(it++);
1002  }
1003  }
1004  }
1005  file_log(">>>>>>\n");
1006 
1007  if (msc_debug_metadex2) MetaDEx_debug_print();
1008 
1009  return rc;
1010 }
1011 
1012 bool MetaDEx_compare::operator()(const CMPMetaDEx &lhs, const CMPMetaDEx &rhs) const
1013 {
1014  if (lhs.getBlock() == rhs.getBlock()) return lhs.getIdx() < rhs.getIdx();
1015  else return lhs.getBlock() < rhs.getBlock();
1016 }
1017 
1018 void CMPMetaDEx::saveOffer(ofstream &file, SHA256_CTX *shaCtx) const
1019 {
1020  string lineOut = (boost::format("%s,%d,%d,%d,%d,%d,%d,%d,%s,%d")
1021  % addr
1022  % block
1023  % amount_forsale
1024  % property
1025  % amount_desired
1026  % desired_property
1027  % (unsigned int) subaction
1028  % idx
1029  % txid.ToString()
1030  % still_left_forsale
1031  ).str();
1032 
1033  // add the line to the hash
1034  SHA256_Update(shaCtx, lineOut.c_str(), lineOut.length());
1035 
1036  // write the line
1037  file << lineOut << endl;
1038 }
1039 
#define METADEX_ERROR
Definition: mastercore.h:126
static MatchReturnType x_Trade(CMPMetaDEx *newo)
const string & getAddr() const
const int msc_debug_dex
Definition: mastercore.cpp:109
int DEx_offerCreate(string seller_addr, unsigned int, uint64_t nValue, int block, uint64_t amount_desired, uint64_t fee, unsigned char btl, const uint256 &txid, uint64_t *nAmended=NULL)
void saveOffer(ofstream &file, SHA256_CTX *shaCtx) const
bool DEx_offerExists(const string &seller_addr, unsigned int)
int64_t getAmountDesired() const
Definition: init.h:13
md_PricesMap * get_Prices(unsigned int prop)
CMPOffer * DEx_getOffer(const string &seller_addr, unsigned int)
int MetaDEx_CANCEL_AT_PRICE(const uint256, unsigned int, const string &, unsigned int, uint64_t, unsigned int, uint64_t)
bool operator>=(XDOUBLE first, XDOUBLE second)
bool update_tally_map(string who, unsigned int which_currency, int64_t amount, TallyType ttype)
Definition: mastercore.cpp:687
#define INTERNAL_PRECISION_LEN
AcceptMap my_accepts
Definition: mastercore.cpp:360
cpp_dec_float_100 XDOUBLE
bool operator==(XDOUBLE first, XDOUBLE second)
void recordMetaDExCancelTX(const uint256 &txidMaster, const uint256 &txidSub, bool fValid, int nBlock, unsigned int propertyId, uint64_t nValue)
bool operator!=(XDOUBLE first, XDOUBLE second)
void setAmountDesired(int64_t ad, const string &label="")
uint64_t getOfferAmountOriginal() const
#define strprintf
Definition: util.h:116
STL namespace.
XDOUBLE effectivePrice() const
int MetaDEx_ADD(const string &sender_addr, unsigned int, uint64_t, int block, unsigned int property_desired, uint64_t amount_desired, const uint256 &txid, unsigned int idx)
#define STR_ACCEPT_ADDR_PROP_ADDR_COMBO(_seller, _buyer)
Definition: mastercore_dex.h:8
int msc_debug_metadex1
Definition: mastercore.cpp:121
uint64_t getBTCDesiredOriginal()
#define DISPLAY_PRECISION_LEN
#define OMNI_PROPERTY_MSC
Definition: mastercore.h:130
CMPAccept * DEx_getAccept(const string &seller_addr, unsigned int, const string &buyer_addr)
MatchReturnType
#define DEX_ERROR_SELLOFFER
Definition: mastercore.h:116
void recordPaymentTX(const uint256 &txid, bool fValid, int nBlock, unsigned int vout, unsigned int propertyId, uint64_t nValue, string buyer, string seller)
unsigned char getBlockTimeLimit()
unsigned int eraseExpiredAccepts(int blockNow)
uint64_t getAmountForSale() const
int MetaDEx_CANCEL_ALL_FOR_PAIR(const uint256, unsigned int, const string &, unsigned int, unsigned int)
uint64_t getOfferAmountOriginal()
#define OMNI_PROPERTY_TMSC
Definition: mastercore.h:131
uint64_t getAcceptAmountRemaining() const
int DEx_payment(uint256 txid, unsigned int vout, string seller, string buyer, uint64_t BTC_paid, int blockNow, uint64_t *nAmended=NULL)
OfferMap my_offers
Definition: mastercore.cpp:359
CMPTradeList * t_tradelistdb
Definition: mastercore.cpp:156
uint256 getHash() const
std::string ToString() const
uint64_t rounduint64(long double ld)
Converts numbers to 64 bit wide unsigned integer whereby any signedness is ignored.
uint64_t getBTCDesiredOriginal() const
uint64_t getMinFee() const
bool reduceAcceptAmountRemaining_andIsZero(const uint64_t really_purchased)
md_PropertiesMap metadex
void MetaDEx_debug_print(bool bShowPriceLevel=false, bool bDisplay=false)
int MetaDEx_CANCEL_EVERYTHING(const uint256, unsigned int, const string &)
std::map< XDOUBLE, md_Set > md_PricesMap
int DEx_acceptCreate(const string &buyer, const string &seller, int, uint64_t nValue, int block, uint64_t fee_paid, uint64_t *nAmended=NULL)
unsigned int getProperty() const
int getBlock() const
int DEx_offerUpdate(const string &seller_addr, unsigned int, uint64_t nValue, int block, uint64_t desired, uint64_t fee, unsigned char btl, const uint256 &txid, uint64_t *nAmended=NULL)
unsigned int getProperty() const
std::string GetHex() const
Definition: uint256.h:297
void setAmountForSale(int64_t ao, const string &label="")
int DEx_offerDestroy(const string &seller_addr, unsigned int)
CMPTxList * p_txlistdb
Definition: mastercore.cpp:155
const string getTradeReturnType(MatchReturnType ret)
256-bit unsigned integer
Definition: uint256.h:531
std::set< CMPMetaDEx, MetaDEx_compare > md_Set
uint256 getHash() const
int msc_debug_metadex3
Definition: mastercore.cpp:123
unsigned char getBlockTimeLimit() const
int DEx_acceptDestroy(const string &buyer, const string &seller, int, bool bForceErase=false)
md_Set * get_Indexes(md_PricesMap *p, XDOUBLE price)
bool operator<=(XDOUBLE first, XDOUBLE second)
#define DEX_ERROR_ACCEPT
Definition: mastercore.h:117
#define DEX_ERROR_PAYMENT
Definition: mastercore.h:118
std::string FormatMP(unsigned int property, int64_t n, bool fSign)
Definition: mastercore.cpp:349
void Set(const string &, int, unsigned int, uint64_t, unsigned int, uint64_t, const uint256 &, unsigned int, unsigned char)
int msc_debug_metadex2
Definition: mastercore.cpp:122
static void PriceCheck(const string &label, XDOUBLE left, XDOUBLE right)
unsigned int getIdx() const
#define STR_SELLOFFER_ADDR_PROP_COMBO(x)
Definition: mastercore_dex.h:7
void format(FormatIterator &fmtIter)
Definition: tinyformat.h:869
int64_t getMPbalance(const string &Address, unsigned int property, TallyType ttype)
Definition: mastercore.cpp:437
std::map< unsigned int, md_PricesMap > md_PropertiesMap
uint256 getHash() const
int atoi(const std::string &str)
Definition: util.h:242
void recordTrade(const uint256 txid1, const uint256 txid2, string address1, string address2, unsigned int prop1, unsigned int prop2, uint64_t amount1, uint64_t amount2, int blockNum)
unsigned int getDesProperty() const