Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OTAssetContract.cpp
Go to the documentation of this file.
1 /************************************************************
2  *
3  * OTAssetContract.cpp
4  *
5  */
6 
7 /************************************************************
8  -----BEGIN PGP SIGNED MESSAGE-----
9  Hash: SHA1
10 
11  * OPEN TRANSACTIONS
12  *
13  * Financial Cryptography and Digital Cash
14  * Library, Protocol, API, Server, CLI, GUI
15  *
16  * -- Anonymous Numbered Accounts.
17  * -- Untraceable Digital Cash.
18  * -- Triple-Signed Receipts.
19  * -- Cheques, Vouchers, Transfers, Inboxes.
20  * -- Basket Currencies, Markets, Payment Plans.
21  * -- Signed, XML, Ricardian-style Contracts.
22  * -- Scripted smart contracts.
23  *
24  * Copyright (C) 2010-2013 by "Fellow Traveler" (A pseudonym)
25  *
26  * EMAIL:
28  *
29  * BITCOIN: 1NtTPVVjDsUfDWybS4BwvHpG2pdS9RnYyQ
30  *
31  * KEY FINGERPRINT (PGP Key in license file):
32  * 9DD5 90EB 9292 4B48 0484 7910 0308 00ED F951 BB8E
33  *
34  * OFFICIAL PROJECT WIKI(s):
35  * https://github.com/FellowTraveler/Moneychanger
36  * https://github.com/FellowTraveler/Open-Transactions/wiki
37  *
38  * WEBSITE:
39  * http://www.OpenTransactions.org/
40  *
41  * Components and licensing:
42  * -- Moneychanger..A Java client GUI.....LICENSE:.....GPLv3
43  * -- otlib.........A class library.......LICENSE:...LAGPLv3
44  * -- otapi.........A client API..........LICENSE:...LAGPLv3
45  * -- opentxs/ot....Command-line client...LICENSE:...LAGPLv3
46  * -- otserver......Server Application....LICENSE:....AGPLv3
47  * Github.com/FellowTraveler/Open-Transactions/wiki/Components
48  *
49  * All of the above OT components were designed and written by
50  * Fellow Traveler, with the exception of Moneychanger, which
51  * was contracted out to Vicky C ([email protected]).
52  * The open-source community has since actively contributed.
53  *
54  * -----------------------------------------------------
55  *
56  * LICENSE:
57  * This program is free software: you can redistribute it
58  * and/or modify it under the terms of the GNU Affero
59  * General Public License as published by the Free Software
60  * Foundation, either version 3 of the License, or (at your
61  * option) any later version.
62  *
63  * ADDITIONAL PERMISSION under the GNU Affero GPL version 3
64  * section 7: (This paragraph applies only to the LAGPLv3
65  * components listed above.) If you modify this Program, or
66  * any covered work, by linking or combining it with other
67  * code, such other code is not for that reason alone subject
68  * to any of the requirements of the GNU Affero GPL version 3.
69  * (==> This means if you are only using the OT API, then you
70  * don't have to open-source your code--only your changes to
71  * Open-Transactions itself must be open source. Similar to
72  * LGPLv3, except it applies to software-as-a-service, not
73  * just to distributing binaries.)
74  *
75  * Extra WAIVER for OpenSSL, Lucre, and all other libraries
76  * used by Open Transactions: This program is released under
77  * the AGPL with the additional exemption that compiling,
78  * linking, and/or using OpenSSL is allowed. The same is true
79  * for any other open source libraries included in this
80  * project: complete waiver from the AGPL is hereby granted to
81  * compile, link, and/or use them with Open-Transactions,
82  * according to their own terms, as long as the rest of the
83  * Open-Transactions terms remain respected, with regard to
84  * the Open-Transactions code itself.
85  *
86  * Lucre License:
87  * This code is also "dual-license", meaning that Ben Lau-
88  * rie's license must also be included and respected, since
89  * the code for Lucre is also included with Open Transactions.
90  * See Open-Transactions/src/otlib/lucre/LUCRE_LICENSE.txt
91  * The Laurie requirements are light, but if there is any
92  * problem with his license, simply remove the Lucre code.
93  * Although there are no other blind token algorithms in Open
94  * Transactions (yet. credlib is coming), the other functions
95  * will continue to operate.
96  * See Lucre on Github: https://github.com/benlaurie/lucre
97  * -----------------------------------------------------
98  * You should have received a copy of the GNU Affero General
99  * Public License along with this program. If not, see:
100  * http://www.gnu.org/licenses/
101  *
102  * If you would like to use this software outside of the free
103  * software license, please contact FellowTraveler.
104  * (Unfortunately many will run anonymously and untraceably,
105  * so who could really stop them?)
106  *
107  * DISCLAIMER:
108  * This program is distributed in the hope that it will be
109  * useful, but WITHOUT ANY WARRANTY; without even the implied
110  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
111  * PURPOSE. See the GNU Affero General Public License for
112  * more details.
113 
114  -----BEGIN PGP SIGNATURE-----
115  Version: GnuPG v1.4.9 (Darwin)
116 
117  iQIcBAEBAgAGBQJRSsfJAAoJEAMIAO35UbuOQT8P/RJbka8etf7wbxdHQNAY+2cC
118  vDf8J3X8VI+pwMqv6wgTVy17venMZJa4I4ikXD/MRyWV1XbTG0mBXk/7AZk7Rexk
119  KTvL/U1kWiez6+8XXLye+k2JNM6v7eej8xMrqEcO0ZArh/DsLoIn1y8p8qjBI7+m
120  aE7lhstDiD0z8mwRRLKFLN2IH5rAFaZZUvj5ERJaoYUKdn4c+RcQVei2YOl4T0FU
121  LWND3YLoH8naqJXkaOKEN4UfJINCwxhe5Ke9wyfLWLUO7NamRkWD2T7CJ0xocnD1
122  sjAzlVGNgaFDRflfIF4QhBx1Ddl6wwhJfw+d08bjqblSq8aXDkmFA7HeunSFKkdn
123  oIEOEgyj+veuOMRJC5pnBJ9vV+7qRdDKQWaCKotynt4sWJDGQ9kWGWm74SsNaduN
124  TPMyr9kNmGsfR69Q2Zq/FLcLX/j8ESxU+HYUB4vaARw2xEOu2xwDDv6jt0j3Vqsg
125  x7rWv4S/Eh18FDNDkVRChiNoOIilLYLL6c38uMf1pnItBuxP3uhgY6COm59kVaRh
126  nyGTYCDYD2TK+fI9o89F1297uDCwEJ62U0Q7iTDp5QuXCoxkPfv8/kX6lS6T3y9G
127  M9mqIoLbIQ1EDntFv7/t6fUTS2+46uCrdZWbQ5RjYXdrzjij02nDmJAm2BngnZvd
128  kamH0Y/n11lCvo1oQxM+
129  =uSzz
130  -----END PGP SIGNATURE-----
131  **************************************************************/
132 
133 #include "stdafx.hpp"
134 
135 #include "OTAssetContract.hpp"
136 #include "OTAccount.hpp"
137 #include "AccountVisitor.hpp"
138 #include "util/OTFolders.hpp"
139 #include "OTLog.hpp"
140 #include "OTStorage.hpp"
141 
142 #include <irrxml/irrXML.hpp>
143 
144 #include <fstream>
145 #include <memory>
146 #include <iomanip>
147 
148 using namespace irr;
149 using namespace io;
150 
151 namespace opentxs
152 {
153 
154 bool OTAssetContract::ParseFormatted(int64_t& lResult,
155  const std::string& str_input,
156  int32_t nFactor, int32_t nPower,
157  const char* szThousandSeparator,
158  const char* szDecimalPoint)
159 {
160  OT_ASSERT(nullptr != szThousandSeparator);
161  OT_ASSERT(nullptr != szDecimalPoint);
162 
163  lResult = 0;
164 
165  char theSeparator = szThousandSeparator[0];
166  char theDecimalPoint = szDecimalPoint[0];
167 
168  int64_t lDollars = 0;
169  int64_t lCents = 0;
170  int64_t lOutput = 0;
171  int64_t lSign = 1;
172 
173  bool bHasEnteredDollars = false;
174  bool bHasEnteredCents = false;
175 
176  int32_t nDigitsCollectedBeforeDot = 0;
177  int32_t nDigitsCollectedAfterDot = 0;
178 
179  // BUG: &mp isn't used.
180  // const std::moneypunct<char, false> &mp = std::use_facet<
181  // std::moneypunct<char, false> >(std::locale ());
182 
183  std::deque<int64_t> deque_cents;
184 
185  for (uint32_t uIndex = 0; uIndex < str_input.length(); ++uIndex) {
186  char theChar = str_input[uIndex];
187 
188  if (iscntrl(theChar)) // Break at any newline or other control
189  // character.
190  break;
191 
192  if (0 == isdigit(theChar)) // if it's not a numerical digit.
193  {
194  if (theSeparator == theChar) continue;
195 
196  if (theDecimalPoint == theChar) {
197  if (bHasEnteredCents) {
198  // There shouldn't be ANOTHER decimal point if we are
199  // already in the cents.
200  // Therefore, we're done here. Break.
201  //
202  break;
203  }
204 
205  // If we HAVEN'T entered the cents yet, then this decimal point
206  // marks the spot where we DO.
207  //
208  bHasEnteredDollars = true;
209  bHasEnteredCents = true;
210  continue;
211  } // theChar is the decimal point
212 
213  // Once a negative sign appears, it's negative, period.
214  // If you put two or three negative signs in a row, it's STILL
215  // negative.
216 
217  if ('-' == theChar) {
218  lSign = -1;
219  continue;
220  }
221 
222  // Okay, by this point, we know it's not numerical, and it's not a
223  // separator or decimal point, or
224  // sign.
225  // We allow letters and symbols BEFORE the numbers start, but not
226  // AFTER (that would terminate the
227  // number.) Therefore we need to see if the dollars or cents have
228  // started yet. If they have, then
229  // this is the end, and we break. Otherwise if they haven't, then
230  // we're still at the beginning, so
231  // we continue.
232  //
233  if (bHasEnteredDollars || bHasEnteredCents)
234  break;
235  else
236  continue;
237  } // not numerical
238 
239  // By this point, we KNOW that it's a numeric digit.
240  // Are we collecting cents yet? How about dollars?
241  // Also, if nPower is 2, then we only collect 2 digits
242  // after the decimal point. If we've already collected
243  // those, then we need to break.
244  //
245  if (bHasEnteredCents) {
246  ++nDigitsCollectedAfterDot;
247 
248  // If "cents" occupy 2 digits after the decimal point,
249  // and we are now on the THIRD digit -- then we're done.
250  if (nDigitsCollectedAfterDot > nPower) break;
251 
252  // Okay, we're in the cents, so let's add this digit...
253  //
254  deque_cents.push_back(static_cast<int64_t>(theChar - '0'));
255 
256  continue;
257  }
258 
259  // Okay, it's a digit, and we haven't started processing cents yet.
260  // How about dollars?
261  //
262  if (!bHasEnteredDollars) bHasEnteredDollars = true;
263 
264  ++nDigitsCollectedBeforeDot;
265 
266  // Let's add this digit...
267  //
268  lDollars *=
269  10; // Multiply existing dollars by 10, and then add the new digit.
270  lDollars += static_cast<int64_t>(theChar - '0');
271  }
272 
273  // Time to put it all together...
274  //
275  lOutput += lDollars;
276  lOutput *= static_cast<int64_t>(nFactor); // 1 dollar becomes 100 cents.
277 
278  int32_t nTempPower = nPower;
279 
280  while (nTempPower > 0) {
281  --nTempPower;
282 
283  if (deque_cents.size() > 0) {
284  lCents += deque_cents.front();
285  deque_cents.pop_front();
286  }
287 
288  lCents *= 10;
289  }
290  lCents /= 10; // There won't be any rounding errors here, since the last
291  // thing we did in the loop was multiply by 10.
292 
293  lOutput += lCents;
294 
295  lResult = (lOutput * lSign);
296 
297  return true;
298 }
299 
300 inline void separateThousands(std::stringstream& sss, int64_t value,
301  const char* szSeparator)
302 {
303  if (value < 1000) {
304  sss << value;
305  return;
306  }
307 
308  separateThousands(sss, value / 1000, szSeparator);
309  sss << szSeparator << std::setfill('0') << std::setw(3) << value % 1000;
310 }
311 
312 std::string OTAssetContract::formatLongAmount(int64_t lValue, int32_t nFactor,
313  int32_t nPower,
314  const char* szCurrencySymbol,
315  const char* szThousandSeparator,
316  const char* szDecimalPoint)
317 {
318  std::stringstream sss;
319 
320  // Handle negative values
321  if (lValue < 0) {
322  sss << "-";
323  lValue = -lValue;
324  }
325 
326  sss << szCurrencySymbol << " ";
327 
328  // For example, if 506 is supposed to be $5.06, then dividing by a factor of
329  // 100 results in 5 dollars (integer value) and 6 cents (fractional value).
330 
331  // Handle integer value with thousand separaters
332  separateThousands(sss, lValue / nFactor, szThousandSeparator);
333 
334  // Handle fractional value
335  if (1 < nFactor) {
336  sss << szDecimalPoint << std::setfill('0') << std::setw(nPower)
337  << (lValue % nFactor);
338  }
339 
340  return sss.str();
341 }
342 
343 // Convert 912545 to "$9,125.45"
344 //
345 // (Assuming a Factor of 100, Decimal Power of 2, Currency Symbol of "$",
346 // separator of "," and decimal point of ".")
347 //
348 bool OTAssetContract::FormatAmount(int64_t amount,
349  std::string& str_output) const // Convert 545
350  // to $5.45.
351 {
352  int32_t nFactor = atoi(
353  m_strCurrencyFactor.Get()); // default is 100 (100 cents in a dollar)
354  if (nFactor < 1) nFactor = 1;
355  OT_ASSERT(nFactor > 0); // should be 1, 10, 100, etc.
356 
357  int32_t nPower = atoi(m_strCurrencyDecimalPower.Get()); // default is 2.
358  // ($5.05 is moved 2
359  // decimal places.)
360  if (nPower < 0) nPower = 0;
361  OT_ASSERT(nPower >= 0); // should be 0, 1, 2, etc.
362 
363  // Lookup separator and decimal point symbols based on locale.
364 
365  // Get a moneypunct facet from the global ("C") locale
366  //
367  // NOTE: Turns out moneypunct kind of sucks.
368  // As a result, for internationalization purposes,
369  // these values have to be set here before compilation.
370  //
371  static OTString strSeparator(OT_THOUSANDS_SEP);
372  static OTString strDecimalPoint(OT_DECIMAL_POINT);
373 
374  // NOTE: from web searching, I've determined that locale / moneypunct has
375  // internationalization problems. Therefore it looks like if you want to
376  // build OT for various languages / regions, you're just going to have to
377  // edit stdafx.hpp and change the OT_THOUSANDS_SEP and OT_DECIMAL_POINT
378  // variables.
379  //
380  // The best improvement I can think on that is to check locale and then use
381  // it to choose from our own list of hardcoded values. Todo.
382 
383  str_output = OTAssetContract::formatLongAmount(
384  amount, nFactor, nPower, m_strCurrencySymbol.Get(), strSeparator.Get(),
385  strDecimalPoint.Get());
386  return true;
387 }
388 
389 // Convert "$9,125.45" to 912545.
390 //
391 // (Assuming a Factor of 100, Decimal Power of 2, separator of "," and decimal
392 // point of ".")
393 //
394 bool OTAssetContract::StringToAmount(
395  int64_t& amount,
396  const std::string& str_input) const // Convert $5.45 to amount 545.
397 {
398  int32_t nFactor = atoi(
399  m_strCurrencyFactor.Get()); // default is 100 (100 cents in a dollar)
400  if (nFactor < 1) nFactor = 1;
401  OT_ASSERT(nFactor > 0); // should be 1, 10, 100, etc.
402 
403  int32_t nPower = atoi(m_strCurrencyDecimalPower.Get()); // default is 2.
404  // ($5.05 is moved 2
405  // decimal places.)
406  if (nPower < 0) nPower = 0;
407  OT_ASSERT(nPower >= 0); // should be 0, 1, 2, etc.
408 
409  // Lookup separator and decimal point symbols based on locale.
410 
411  // Get a moneypunct facet from the global ("C") locale
412  //
413 
414  // NOTE: from web searching, I've determined that locale / moneypunct has
415  // internationalization problems. Therefore it looks like if you want to
416  // build OT for various languages / regions, you're just going to have to
417  // edit stdafx.hpp and change the OT_THOUSANDS_SEP and OT_DECIMAL_POINT
418  // variables.
419  //
420  // The best improvement I can think on that is to check locale and then use
421  // it to choose from our own list of hardcoded values. Todo.
422 
423  static OTString strSeparator(",");
424  static OTString strDecimalPoint(".");
425 
426  bool bSuccess = OTAssetContract::ParseFormatted(amount, str_input, nFactor,
427  nPower, strSeparator.Get(),
428  strDecimalPoint.Get());
429 
430  return bSuccess;
431 }
432 
433 OTAssetContract::OTAssetContract()
434  : OTContract()
435  , m_bIsCurrency(true)
436  , m_bIsShares(false)
437 {
438 }
439 
441  OTString& filename, OTString& strID)
442  : OTContract(name, foldername, filename, strID)
443  , m_bIsCurrency(true)
444  , m_bIsShares(false)
445 {
446 }
447 
449 {
450 }
451 
453 {
454  const OTString strID(m_ID);
455 
456  strContents.Concatenate(" Asset Type: %s\n"
457  " AssetTypeID: %s\n"
458  "\n",
459  m_strName.Get(), strID.Get());
460  return true;
461 }
462 
464 {
465  const OTString strID(m_ID);
466 
467  OTASCIIArmor ascName;
468 
469  if (m_strName.Exists()) // name is in the clear in memory, and base64 in
470  // storage.
471  {
472  ascName.SetString(m_strName, false); // linebreaks == false
473  }
474 
475  strContents.Concatenate("<assetType name=\"%s\"\n"
476  " assetTypeID=\"%s\" />\n\n",
477  m_strName.Exists() ? ascName.Get() : "",
478  strID.Get());
479 
480  return true;
481 }
482 
483 bool OTAssetContract::SaveContractWallet(std::ofstream& ofs) const
484 {
485  OTString strOutput;
486 
487  if (SaveContractWallet(strOutput)) {
488  ofs << strOutput;
489  return true;
490  }
491 
492  return false;
493 }
494 
495 // currently only "simple" accounts (normal user asset accounts) are added to
496 // this list Any "special" accounts, such as basket reserve accounts, or voucher
497 // reserve accounts, or cash reserve accounts, are not included on this list.
499 {
500  OTString strAssetTypeID, strAcctRecordFile;
501  GetIdentifier(strAssetTypeID);
502  strAcctRecordFile.Format("%s.a", strAssetTypeID.Get());
503 
504  std::unique_ptr<OTDB::Storable> pStorable(OTDB::QueryObject(
506  strAcctRecordFile.Get()));
507 
508  OTDB::StringMap* pMap = dynamic_cast<OTDB::StringMap*>(pStorable.get());
509 
510  // There was definitely a StringMap loaded from local storage.
511  // (Even an empty one, possibly.) This is the only block that matters in
512  // this function.
513  //
514  if (nullptr != pMap) {
515  OTIdentifier* pServerID = visitor.GetServerID();
516  OT_ASSERT_MSG(nullptr != pServerID,
517  "Assert: nullptr Server ID on functor. "
518  "(How did you even construct the "
519  "thing?)");
520 
521  auto& theMap = pMap->the_map;
522 
523  // todo: optimize: will probably have to use a database for this,
524  // int64_t term.
525  // (What if there are a million acct IDs in this flat file? Not
526  // scaleable.)
527  //
528  for (auto& it : theMap) {
529  const std::string& str_acct_id =
530  it.first; // Containing the account ID.
531  const std::string& str_asset_id =
532  it.second; // Containing the asset type ID. (Just in case
533  // someone copied the wrong file here...)
534 
535  if (!strAssetTypeID.Compare(str_asset_id.c_str())) {
536  otErr << "OTAssetContract::VisitAccountRecords: Error: wrong "
537  "asset type ID (" << str_asset_id
538  << ") when expecting: " << strAssetTypeID << "\n";
539  }
540  else {
541  OTAccount* pAccount = nullptr;
542  std::unique_ptr<OTAccount> theAcctAngel;
543 
544  const OTIdentifier theAccountID(str_acct_id.c_str());
545 
546  // Before loading it from local storage, let's first make sure
547  // it's not already loaded.
548  // (visitor functor has a list of 'already loaded' accounts,
549  // just in case.)
550  //
551  mapOfAccounts* pLoadedAccounts = visitor.GetLoadedAccts();
552 
553  if (nullptr !=
554  pLoadedAccounts) // there are some accounts already loaded,
555  { // let's see if the one we're looking for is there...
556  auto found_it = pLoadedAccounts->find(str_acct_id);
557 
558  if (pLoadedAccounts->end() != found_it) // FOUND IT.
559  {
560  pAccount = found_it->second;
561  OT_ASSERT(nullptr != pAccount);
562 
563  if (theAccountID != pAccount->GetPurportedAccountID()) {
564  otErr << "Error: the actual account didn't have "
565  "the ID that the std::map SAID it had! "
566  "(Should never happen.)\n";
567  pAccount = nullptr;
568  }
569  }
570  }
571 
572  // I guess it wasn't already loaded...
573  // Let's try to load it.
574  //
575  if (nullptr == pAccount) {
576  pAccount = OTAccount::LoadExistingAccount(theAccountID,
577  *pServerID);
578  theAcctAngel.reset(pAccount);
579  }
580 
581  bool bSuccessLoadingAccount =
582  ((pAccount != nullptr) ? true : false);
583  if (bSuccessLoadingAccount) {
584  bool bTriggerSuccess = visitor.Trigger(*pAccount);
585  if (!bTriggerSuccess)
586  otErr << __FUNCTION__ << ": Error: Trigger Failed.";
587  }
588  else {
589  otErr << __FUNCTION__ << ": Error: Failed Loading Account!";
590  }
591  }
592  }
593  return true;
594  }
595  return true;
596 }
597 
599  const OTAccount& theAccount) const // adds the
600  // account
601  // to the
602  // list.
603  // (When
604  // account
605  // is
606  // created.)
607 {
608  // Load up account list StringMap. Create it if doesn't already exist.
609  // See if account is already there in the map. Add it otherwise.
610  // Save the StringMap back again. (The account records list for a given
611  // asset type.)
612 
613  const char* szFunc = "OTAssetContract::AddAccountRecord";
614 
615  if (theAccount.GetAssetTypeID() != m_ID) {
616  otErr << szFunc << ": Error: theAccount doesn't have the same asset "
617  "type ID as *this does.\n";
618  return false;
619  }
620 
621  const OTIdentifier theAcctID(theAccount);
622  const OTString strAcctID(theAcctID);
623 
624  OTString strAssetTypeID, strAcctRecordFile;
625  GetIdentifier(strAssetTypeID);
626  strAcctRecordFile.Format("%s.a", strAssetTypeID.Get());
627 
628  OTDB::Storable* pStorable = nullptr;
629  std::unique_ptr<OTDB::Storable> theAngel;
630  OTDB::StringMap* pMap = nullptr;
631 
632  if (OTDB::Exists(OTFolders::Contract().Get(),
633  strAcctRecordFile.Get())) // the file already exists; let's
634  // try to load it up.
636  OTFolders::Contract().Get(),
637  strAcctRecordFile.Get());
638  else // the account records file (for this asset type) doesn't exist.
639  pStorable = OTDB::CreateObject(
640  OTDB::STORED_OBJ_STRING_MAP); // this asserts already, on failure.
641 
642  theAngel.reset(pStorable);
643  pMap = (nullptr == pStorable) ? nullptr
644  : dynamic_cast<OTDB::StringMap*>(pStorable);
645 
646  // It exists.
647  //
648  if (nullptr == pMap) {
649  otErr << szFunc
650  << ": Error: failed trying to load or create the account records "
651  "file for asset type: " << strAssetTypeID << "\n";
652  return false;
653  }
654 
655  auto& theMap = pMap->the_map;
656  auto map_it = theMap.find(strAcctID.Get());
657 
658  if (theMap.end() != map_it) // we found it.
659  { // We were ADDING IT, but it was ALREADY THERE.
660  // (Thus, we're ALREADY DONE.)
661  // Let's just make sure the right asset type ID is associated with this
662  // account
663  // (it better be, since we loaded the account records file based on the
664  // asset type ID as its filename...)
665  //
666  const std::string& str2 =
667  map_it->second; // Containing the asset type ID. (Just in case
668  // someone copied the wrong file here,
669  // -------------------------------- // every account should map
670  // to the SAME asset ID.)
671 
672  if (false ==
673  strAssetTypeID.Compare(str2.c_str())) // should never happen.
674  {
675  otErr << szFunc
676  << ": Error: wrong asset type found in account records "
677  "file...\n For asset type: " << strAssetTypeID
678  << "\n "
679  "For account: " << strAcctID
680  << "\n Found wrong asset type: " << str2 << "\n";
681  return false;
682  }
683 
684  return true; // already there (no need to add.) + the asset type ID
685  // matches.
686  }
687 
688  // it wasn't already on the list...
689 
690  // ...so add it.
691  //
692  theMap[strAcctID.Get()] = strAssetTypeID.Get();
693 
694  // Then save it back to local storage:
695  //
696  if (!OTDB::StoreObject(*pMap, OTFolders::Contract().Get(),
697  strAcctRecordFile.Get())) {
698  otErr << szFunc
699  << ": Failed trying to StoreObject, while saving updated "
700  "account records file for asset type: " << strAssetTypeID
701  << "\n to contain account ID: " << strAcctID << "\n";
702  return false;
703  }
704 
705  // Okay, we saved the updated file, with the account added. (done, success.)
706  //
707  return true;
708 }
709 
711  const // removes the account from the list. (When
712  // account is deleted.)
713 {
714  // Load up account list StringMap. Create it if doesn't already exist.
715  // See if account is already there in the map. Erase it, if it is.
716  // Save the StringMap back again. (The account records list for a given
717  // asset type.)
718 
719  const char* szFunc = "OTAssetContract::EraseAccountRecord";
720 
721  const OTString strAcctID(theAcctID);
722 
723  OTString strAssetTypeID, strAcctRecordFile;
724  GetIdentifier(strAssetTypeID);
725  strAcctRecordFile.Format("%s.a", strAssetTypeID.Get());
726 
727  OTDB::Storable* pStorable = nullptr;
728  std::unique_ptr<OTDB::Storable> theAngel;
729  OTDB::StringMap* pMap = nullptr;
730 
731  if (OTDB::Exists(OTFolders::Contract().Get(),
732  strAcctRecordFile.Get())) // the file already exists; let's
733  // try to load it up.
735  OTFolders::Contract().Get(),
736  strAcctRecordFile.Get());
737  else // the account records file (for this asset type) doesn't exist.
738  pStorable = OTDB::CreateObject(
739  OTDB::STORED_OBJ_STRING_MAP); // this asserts already, on failure.
740 
741  theAngel.reset(pStorable);
742  pMap = (nullptr == pStorable) ? nullptr
743  : dynamic_cast<OTDB::StringMap*>(pStorable);
744 
745  // It exists.
746  //
747  if (nullptr == pMap) {
748  otErr << szFunc
749  << ": Error: failed trying to load or create the account records "
750  "file for asset type: " << strAssetTypeID << "\n";
751  return false;
752  }
753 
754  // Before we can erase it, let's see if it's even there....
755  //
756  auto& theMap = pMap->the_map;
757  auto map_it = theMap.find(strAcctID.Get());
758 
759  // we found it!
760  if (theMap.end() != map_it) // Acct ID was already there...
761  {
762  theMap.erase(map_it); // remove it
763  }
764 
765  // it wasn't already on the list...
766  // (So it's like success, since the end result is, acct ID will not appear
767  // on this list--whether
768  // it was there or not beforehand, it's definitely not there now.)
769 
770  // Then save it back to local storage:
771  //
772  if (!OTDB::StoreObject(*pMap, OTFolders::Contract().Get(),
773  strAcctRecordFile.Get())) {
774  otErr << szFunc
775  << ": Failed trying to StoreObject, while saving updated "
776  "account records file for asset type: " << strAssetTypeID
777  << "\n to erase account ID: " << strAcctID << "\n";
778  return false;
779  }
780 
781  // Okay, we saved the updated file, with the account removed. (done,
782  // success.)
783  //
784  return true;
785 }
786 
788 {
789  m_strVersion = "2.0"; // 2.0 since adding credentials.
790 
792  m_xmlUnsigned.Concatenate("<?xml version=\"%s\"?>\n", "1.0");
793 
794  m_xmlUnsigned.Concatenate("<%s version=\"%s\">\n\n", "digitalAssetContract",
795  m_strVersion.Get());
796 
797  // Entity
798  m_xmlUnsigned.Concatenate("<entity shortname=\"%s\"\n"
799  " longname=\"%s\"\n"
800  " email=\"%s\"/>\n\n",
804 
805  // Issue
806  m_xmlUnsigned.Concatenate("<issue company=\"%s\"\n"
807  " email=\"%s\"\n"
808  " contractUrl=\"%s\"\n"
809  " type=\"%s\"/>\n\n",
812  m_strIssueType.Get());
813 
814  // [currency|shares]
815  if (m_bIsCurrency)
817  "<currency name=\"%s\" tla=\"%s\" symbol=\"%s\" type=\"%s\" "
818  "factor=\"%s\" decimal_power=\"%s\" fraction=\"%s\" />\n\n",
823  else if (m_bIsShares)
825  "<shares name=\"%s\" symbol=\"%s\" type=\"%s\" "
826  "issuedate=\"%s\" />\n\n",
829 
830  // This is where OTContract scribes m_xmlUnsigned with its keys, conditions,
831  // etc.
833 
834  m_xmlUnsigned.Concatenate("</%s>\n", "digitalAssetContract");
835 }
836 
837 // return -1 if error, 0 if nothing, and 1 if the node was processed.
838 //
840 {
841  int32_t nReturnVal = OTContract::ProcessXMLNode(xml);
842 
843  // Here we call the parent class first.
844  // If the node is found there, or there is some error,
845  // then we just return either way. But if it comes back
846  // as '0', then nothing happened, and we'll continue executing.
847  //
848  // -- Note you can choose not to call the parent if
849  // you don't want to use any of those xml tags.
850 
851  if (nReturnVal == 1 || nReturnVal == (-1)) return nReturnVal;
852 
853  const OTString strNodeName(xml->getNodeName());
854 
855  if (strNodeName.Compare("digitalAssetContract")) {
856  m_strVersion = xml->getAttributeValue("version");
857 
858  otWarn << "\n"
859  "===> Loading XML portion of asset contract into memory "
860  "structures...\n\n"
861  "Digital Asset Contract: " << m_strName
862  << "\nContract version: " << m_strVersion << "\n----------\n";
863  nReturnVal = 1;
864  }
865  else if (strNodeName.Compare("issue")) {
866  m_strIssueCompany = xml->getAttributeValue("company");
867  m_strIssueEmail = xml->getAttributeValue("email");
868  m_strIssueContractURL = xml->getAttributeValue("contractUrl");
869  m_strIssueType = xml->getAttributeValue("type");
870 
871  otInfo << "Loaded Issue company: " << m_strIssueCompany
872  << "\nEmail: " << m_strIssueEmail
873  << "\nContractURL: " << m_strIssueContractURL
874  << "\nType: " << m_strIssueType << "\n----------\n";
875  nReturnVal = 1;
876  }
877  // TODO security validation: validate all the above and below values.
878  else if (strNodeName.Compare("currency")) {
879  m_bIsCurrency = true; // silver grams
880  m_bIsShares = false;
881 
882  m_strName = xml->getAttributeValue("name");
883  m_strCurrencyName = xml->getAttributeValue("name");
884  m_strCurrencySymbol = xml->getAttributeValue("symbol");
885  m_strCurrencyType = xml->getAttributeValue("type");
886 
887  m_strCurrencyTLA = xml->getAttributeValue("tla");
888  m_strCurrencyFactor = xml->getAttributeValue("factor");
889  m_strCurrencyDecimalPower = xml->getAttributeValue("decimal_power");
890  m_strCurrencyFraction = xml->getAttributeValue("fraction");
891 
892  otInfo << "Loaded " << strNodeName << ", Name: " << m_strCurrencyName
893  << ", TLA: " << m_strCurrencyTLA
894  << ", Symbol: " << m_strCurrencySymbol
895  << "\n"
896  "Type: " << m_strCurrencyType
897  << ", Factor: " << m_strCurrencyFactor
898  << ", Decimal Power: " << m_strCurrencyDecimalPower
899  << ", Fraction: " << m_strCurrencyFraction << "\n----------\n";
900  nReturnVal = 1;
901  }
902 
903  // share_type some type, for example, A or B, or NV (non voting)
904  //
905  // share_name this is the int64_t legal name of the company
906  //
907  // share_symbol this is the trading name (8 chars max), as it might be
908  // displayed in a market contect, and should be unique within some
909  // given market
910  //
911  // share_issue_date date of start of this share item (not necessarily IPO)
912  else if (strNodeName.Compare("shares")) {
913  m_bIsShares = true; // shares of pepsi
914  m_bIsCurrency = false;
915 
916  m_strName = xml->getAttributeValue("name");
917  m_strCurrencyName = xml->getAttributeValue("name");
918  m_strCurrencySymbol = xml->getAttributeValue("symbol");
919  m_strCurrencyType = xml->getAttributeValue("type");
920 
921  m_strIssueDate = xml->getAttributeValue("issuedate");
922 
923  otInfo << "Loaded " << strNodeName << ", Name: " << m_strCurrencyName
924  << ", Symbol: " << m_strCurrencySymbol
925  << "\n"
926  "Type: " << m_strCurrencyType
927  << ", Issue Date: " << m_strIssueDate << "\n----------\n";
928  nReturnVal = 1;
929  }
930 
931  return nReturnVal;
932 }
933 
934 } // namespace opentxs
virtual EXPORT bool DisplayStatistics(OTString &strContents) const
EXPORT Storable * CreateObject(StoredObjectType eType)
Definition: OTStorage.cpp:530
EXPORT void CreateInnerContents()
virtual EXPORT int32_t ProcessXMLNode(irr::io::IrrXMLReader *&xml)
void separateThousands(std::stringstream &sss, int64_t value, const char *szSeparator)
EXPORT void Concatenate(const char *arg,...)
Definition: OTString.cpp:1334
static EXPORT const OTString & Contract()
Definition: OTFolders.cpp:303
EXPORT Storable * QueryObject(StoredObjectType theObjectType, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:788
EXPORT bool Exists() const
Definition: OTString.cpp:1035
EXPORT bool SetString(const OTString &theData, bool bLineBreaks=true)
EXPORT void Format(const char *fmt,...)
Definition: OTString.cpp:1319
EXPORT bool Compare(const char *compare) const
Definition: OTString.cpp:1102
virtual EXPORT void CreateContents()
EXPORT bool AddAccountRecord(const OTAccount &theAccount) const
OTString m_strEntityShortName
Definition: OTContract.hpp:207
#define OT_ASSERT(x)
Definition: Assert.hpp:150
#define OT_ASSERT_MSG(x, s)
Definition: Assert.hpp:155
std::map< std::string, OTAccount * > mapOfAccounts
Definition: OTWallet.hpp:157
OTLOG_IMPORT OTLogStream otInfo
OTIdentifier m_ID
Definition: OTContract.hpp:172
virtual EXPORT void GetIdentifier(OTIdentifier &theIdentifier) const
Definition: OTContract.cpp:317
OTString m_strEntityLongName
Definition: OTContract.hpp:208
OTStringXML m_xmlUnsigned
Definition: OTContract.hpp:174
OTLOG_IMPORT OTLogStream otWarn
virtual EXPORT ~OTAssetContract()
EXPORT const char * Get() const
Definition: OTString.cpp:1045
EXPORT bool VisitAccountRecords(AccountVisitor &visitor) const
OTLOG_IMPORT OTLogStream otErr
virtual EXPORT int32_t ProcessXMLNode(irr::io::IrrXMLReader *&xml)
const OTIdentifier & GetPurportedAccountID() const
std::map< std::string, std::string > the_map
Definition: OTStorage.hpp:981
#define OT_DECIMAL_POINT
Definition: stdafx.hpp:46
EXPORT bool Exists(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:584
OTString m_strEntityEmail
Definition: OTContract.hpp:209
EXPORT bool EraseAccountRecord(const OTIdentifier &theAcctID) const
EXPORT bool StoreObject(Storable &theContents, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:759
EXPORT mapOfAccounts * GetLoadedAccts()
EXPORT OTIdentifier * GetServerID()
static EXPORT OTAccount * LoadExistingAccount(const OTIdentifier &accountId, const OTIdentifier &serverId)
Definition: OTAccount.cpp:480
virtual EXPORT void Release()
Definition: OTString.cpp:765
virtual EXPORT bool SaveContractWallet(OTString &strContents) const
virtual EXPORT bool Trigger(OTAccount &account)=0
#define OT_THOUSANDS_SEP
Definition: stdafx.hpp:45