]> Git Repo - VerusCoin.git/blob - src/pbaas/reserves.h
Reject malformed reserve transfers
[VerusCoin.git] / src / pbaas / reserves.h
1 /********************************************************************
2  * (C) 2019 Michael Toutonghi
3  * 
4  * Distributed under the MIT software license, see the accompanying
5  * file COPYING or http://www.opensource.org/licenses/mit-license.php.
6  * 
7  * This provides reserve currency functions, leveraging the multi-precision boost libraries to calculate reserve currency conversions
8  * in a predictable manner that can achieve consensus.
9  * 
10  */
11
12 #ifndef PBAAS_RESERVES_H
13 #define PBAAS_RESERVES_H
14
15 #include <sstream>
16 #include <univalue.h>
17 #include "pbaas/crosschainrpc.h"
18 #include "arith_uint256.h"
19 #include <boost/multiprecision/cpp_dec_float.hpp>
20 #include "librustzcash.h"
21 #include "pubkey.h"
22 #include "amount.h"
23 #include <map>
24
25 #ifndef SATOSHIDEN
26 #define SATOSHIDEN ((uint64_t)100000000L)
27 #endif
28
29 using boost::multiprecision::cpp_dec_float_50;
30 class CCoinsViewCache;
31 class CInputDescriptor;
32 class CBaseChainObject;
33 class CTransaction;
34 class CMutableTransaction;
35 class CTxOut;
36 class CReserveTransactionDescriptor;
37 class CCurrencyState;
38 class CValidationState;
39 class CPBaaSNotarization;
40 extern uint160 ASSETCHAINS_CHAINID;
41
42 // reserve output is a special kind of token output that does not have to carry it's identifier, as it
43 // is always assumed to be the reserve currency of the current chain.
44 class CTokenOutput
45 {
46 public:
47     enum
48     {
49         VERSION_INVALID = 0,
50         VERSION_CURRENT = 1,
51         VERSION_FIRSTVALID = 1,
52         VERSION_LASTVALID = 1,
53         VERSION_MULTIVALUE = 0x80000000 // used for serialization/deserialization
54     };
55
56     uint32_t nVersion;                  // version of the token output class
57     CCurrencyValueMap reserveValues;    // all outputs of this reserve deposit
58
59     CTokenOutput(const std::vector<unsigned char> &asVector)
60     {
61         FromVector(asVector, *this);
62     }
63
64     CTokenOutput(const UniValue &obj);
65
66     CTokenOutput(uint32_t ver=VERSION_CURRENT) : nVersion(ver) {}
67
68     CTokenOutput(const uint160 &curID, CAmount value) : nVersion(VERSION_CURRENT), reserveValues(std::vector<uint160>({curID}), std::vector<int64_t>({value})) {}
69     CTokenOutput(CCurrencyValueMap values) : nVersion(VERSION_CURRENT), reserveValues(values) {}
70
71     ADD_SERIALIZE_METHODS;
72
73     template <typename Stream, typename Operation>
74     inline void SerializationOp(Stream& s, Operation ser_action) {
75         std::vector<uint160> currencies;
76         std::vector<int64_t> values;
77         if (ser_action.ForRead())
78         {
79             READWRITE(VARINT(nVersion));
80             if (nVersion & VERSION_MULTIVALUE)
81             {
82                 READWRITE(currencies);
83                 READWRITE(values);
84                 if (currencies.size() == values.size())
85                 {
86                     reserveValues = CCurrencyValueMap(currencies, values);
87                 }
88                 else
89                 {
90                     nVersion = VERSION_INVALID;
91                     reserveValues = CCurrencyValueMap();
92                 }
93                 nVersion &= ~VERSION_MULTIVALUE;
94             }
95             else
96             {
97                 uint160 currencyID;
98                 CAmount nValue;
99                 READWRITE(currencyID);
100                 READWRITE(VARINT(nValue));
101                 reserveValues = CCurrencyValueMap(std::vector<uint160>({currencyID}), std::vector<int64_t>({nValue}));
102             }
103         }
104         else
105         {
106             if (reserveValues.valueMap.size() == 1)
107             {
108                 nVersion &= ~VERSION_MULTIVALUE;
109                 READWRITE(VARINT(nVersion));
110
111                 std::pair<uint160, int64_t> oneValPair = *reserveValues.valueMap.begin();
112                 uint160 currencyID = oneValPair.first;
113                 CAmount nValue = oneValPair.second;
114                 READWRITE(currencyID);
115                 READWRITE(VARINT(nValue));
116             }
117             else
118             {
119                 nVersion |= VERSION_MULTIVALUE;
120                 READWRITE(VARINT(nVersion));
121
122                 for (auto &oneCur : reserveValues.valueMap)
123                 {
124                     currencies.push_back(oneCur.first);
125                     values.push_back(oneCur.second);
126                 }
127                 READWRITE(currencies);
128                 READWRITE(values);
129             }
130         }
131     }
132
133     std::vector<unsigned char> AsVector()
134     {
135         return ::AsVector(*this);
136     }
137
138     UniValue ToUniValue() const;
139
140     uint160 FirstCurrency() const
141     {
142         auto it = reserveValues.valueMap.begin();
143         return it == reserveValues.valueMap.end() ? uint160() : it->first;
144     }
145
146     CAmount FirstValue() const
147     {
148         auto it = reserveValues.valueMap.begin();
149         return it == reserveValues.valueMap.end() ? 0 : it->second;
150     }
151
152     uint32_t Version() const
153     {
154         return nVersion;
155     }
156
157     bool IsValid() const
158     {
159         // we don't support op returns, value must be in native or reserve
160         return nVersion >= VERSION_FIRSTVALID && nVersion <= VERSION_LASTVALID;
161     }
162 };
163
164 class CReserveTransfer : public CTokenOutput
165 {
166 public:
167     enum EOptions
168     {
169         VALID = 1,
170         CONVERT = 2,
171         PRECONVERT = 4,
172         FEE_OUTPUT = 8,                     // one per import, amount must match total percentage of fees for exporter, no pre-convert allowed
173         DOUBLE_SEND = 0x10,                 // this is used along with increasing the fee to send one transaction on two hops
174         MINT_CURRENCY = 0x20,               // set when this output is being minted on import
175         CROSS_SYSTEM = 0x40,                // if this is set, there is a systemID serialized and deserialized as well for destination
176         BURN_CHANGE_PRICE = 0x80,           // this output is being burned on import and will change the price
177         BURN_CHANGE_WEIGHT = 0x100,         // this output is being burned on import and will change the reserve ratio
178         IMPORT_TO_SOURCE = 0x200,           // set when the source currency, not destination is the import currency
179         RESERVE_TO_RESERVE = 0x400,         // for arbitrage or transient conversion, 2 stage solving (2nd from new fractional to reserves)
180         REFUND = 0x800,                     // this transfer should be refunded, individual property when conversions exceed limits
181     };
182
183     enum EConstants
184     {
185         DESTINATION_BYTE_DIVISOR = 128,     // destination vector is divided by this and result is multiplied by normal fee and added to transfer fee
186         SUCCESS_FEE = 25000,
187         MIN_SUCCESS_FEE = 20000
188     };
189
190     static const CAmount DEFAULT_PER_STEP_FEE = 10000; // default fee for each step of each transfer (initial mining, transfer, mining on new chain)
191
192     uint32_t flags;                         // type of transfer and options
193     uint160 feeCurrencyID;                  // explicit fee currency
194     CAmount nFees;                          // cross-chain network fees only, separated out to enable market conversions, conversion fees are additional
195     CTransferDestination destination;       // system specific address to send funds to on the target system
196     uint160 destCurrencyID;                 // system to export to, which may represent a PBaaS chain or external bridge
197     uint160 secondReserveID;                // set if this is a reserve to reserve conversion
198     uint160 destSystemID;                   // set if this is a cross-system send
199
200     CReserveTransfer() : CTokenOutput(), flags(0), nFees(0) { }
201
202     CReserveTransfer(const UniValue &uni);
203
204     CReserveTransfer(const std::vector<unsigned char> &asVector)
205     {
206         bool success;
207         FromVector(asVector, *this, &success);
208         if (!success)
209         {
210             nVersion = VERSION_INVALID;
211         }
212     }
213
214     CReserveTransfer(uint32_t version) : CTokenOutput(version), flags(0), nFees(0) { }
215
216     CReserveTransfer(uint32_t Flags,
217                      const CCurrencyValueMap values,
218                      const uint160 &FeeCurrencyID,
219                      CAmount fees,
220                      const uint160 &destCurID,
221                      const CTransferDestination &dest,
222                      const uint160 &secondCID=uint160(),
223                      const uint160 &destinationSystemID=uint160()) : 
224         CTokenOutput(values), 
225         flags(Flags), 
226         feeCurrencyID(FeeCurrencyID), 
227         nFees(fees), 
228         destCurrencyID(destCurID), 
229         destination(dest), 
230         secondReserveID(secondCID),
231         destSystemID(destinationSystemID)
232     {
233         if (!secondReserveID.IsNull())
234         {
235             flags |= RESERVE_TO_RESERVE;
236         }
237     }
238
239     CReserveTransfer(uint32_t Flags,
240                      const uint160 &cID,
241                      CAmount value,
242                      const uint160 &FeeCurrencyID,
243                      CAmount fees,
244                      const uint160 &destCurID,
245                      const CTransferDestination &dest,
246                      const uint160 &secondCID=uint160(),
247                      const uint160 &destinationSystemID=uint160()) : 
248         CTokenOutput(CCurrencyValueMap(std::vector<uint160>({cID}), std::vector<int64_t>({value}))),
249         flags(Flags), 
250         feeCurrencyID(FeeCurrencyID), 
251         nFees(fees), 
252         destCurrencyID(destCurID), 
253         destination(dest), 
254         secondReserveID(secondCID),
255         destSystemID(destinationSystemID)
256     {
257         if (!secondReserveID.IsNull())
258         {
259             flags |= RESERVE_TO_RESERVE;
260         }
261     }
262
263     ADD_SERIALIZE_METHODS;
264
265     template <typename Stream, typename Operation>
266     inline void SerializationOp(Stream& s, Operation ser_action) {
267         READWRITE(*(CTokenOutput *)this);
268         READWRITE(VARINT(flags));
269         READWRITE(feeCurrencyID);
270         READWRITE(VARINT(nFees));
271         READWRITE(destination);
272         READWRITE(destCurrencyID);
273         if (flags & RESERVE_TO_RESERVE)
274         {
275             READWRITE(secondReserveID);
276         }
277         if (flags & CROSS_SYSTEM)
278         {
279             READWRITE(destSystemID);
280         }
281     }
282
283     std::vector<unsigned char> AsVector()
284     {
285         return ::AsVector(*this);
286     }
287
288     UniValue ToUniValue() const;
289
290     CCurrencyValueMap TotalTransferFee() const;
291     CCurrencyValueMap ConversionFee() const;
292     CCurrencyValueMap CalculateFee(uint32_t flags, CAmount transferTotal) const;
293     CCurrencyValueMap TotalCurrencyOut() const;
294
295     static CAmount CalculateTransferFee(const CTransferDestination &destination, uint32_t flags=VALID);
296
297     CAmount CalculateTransferFee() const;
298
299     uint160 GetImportCurrency() const
300     {
301         return (flags & IMPORT_TO_SOURCE) ? FirstCurrency() : destCurrencyID;
302     }
303
304     bool IsValid() const
305     {
306         bool isCrossSystemIDNull = destSystemID.IsNull();
307         return CTokenOutput::IsValid() &&
308                 reserveValues.valueMap.size() == 1 && 
309                 destination.IsValid() &&
310                 ((IsCrossSystem() &&  !isCrossSystemIDNull) || (!IsCrossSystem() &&  isCrossSystemIDNull));
311     }
312
313     bool IsConversion() const
314     {
315         return flags & CONVERT;
316     }
317
318     bool IsRefund() const
319     {
320         return flags & REFUND;
321     }
322
323     bool IsCrossSystem() const
324     {
325         return flags & CROSS_SYSTEM;
326     }
327
328     uint160 SystemDestination() const
329     {
330         return IsCrossSystem() ? destSystemID : ASSETCHAINS_CHAINID;
331     }
332
333     bool IsPreConversion() const
334     {
335         return flags & PRECONVERT;
336     }
337
338     uint160 FeeCurrencyID() const
339     {
340         return feeCurrencyID;
341     }
342
343     bool IsFeeOutput() const
344     {
345         return flags & FEE_OUTPUT;
346     }
347
348     bool IsBurn() const
349     {
350         return flags & (BURN_CHANGE_PRICE | BURN_CHANGE_WEIGHT);
351     }
352
353     bool IsBurnChangePrice() const
354     {
355         return flags & BURN_CHANGE_PRICE;
356     }
357
358     bool IsBurnChangeWeight() const
359     {
360         return flags & BURN_CHANGE_WEIGHT;
361     }
362
363     bool IsMint() const
364     {
365         return flags & MINT_CURRENCY;
366     }
367
368     bool IsReserveToReserve() const
369     {
370         return flags & RESERVE_TO_RESERVE;
371     }
372
373     CReserveTransfer GetRefundTransfer() const;
374
375     static std::string ReserveTransferKeyName()
376     {
377         return "vrsc::system.currency.reservetransfer";
378     }
379
380     static uint160 ReserveTransferKey()
381     {
382         static uint160 nameSpace;
383         static uint160 reserveTransferKey = CVDXF::GetDataKey(ReserveTransferKeyName(), nameSpace);
384         return reserveTransferKey;
385     }
386
387     static uint160 ReserveTransferSystemKey(const uint160 &systemID)
388     {
389         return CCrossChainRPCData::GetConditionID(systemID, ReserveTransferKey());
390     }
391
392     uint160 ReserveTransferSystemSourceKey()
393     {
394         return ReserveTransferSystemKey(ASSETCHAINS_CHAINID);
395     }
396
397     bool HasNextLeg() const
398     {
399         return destination.HasGatewayLeg();
400     }
401
402     // this returns either an output for the next leg or a normal output if there is no next leg
403     // the next leg output can enable chaining of conversions and system transfers
404     bool GetTxOut(const CCurrencyValueMap &reserves, int64_t nativeAmount, CTxOut &txOut) const;
405 };
406
407 class CReserveDeposit : public CTokenOutput
408 {
409 public:
410     uint160 controllingCurrencyID;          // system to export to, which may represent a PBaaS chain or external bridge
411
412     CReserveDeposit() : CTokenOutput() {}
413
414     CReserveDeposit(const std::vector<unsigned char> &asVector)
415     {
416         FromVector(asVector, *this);
417     }
418
419     CReserveDeposit(const uint160 &controllingID, const CCurrencyValueMap &reserveOut) : 
420         CTokenOutput(reserveOut), controllingCurrencyID(controllingID) {}
421
422     ADD_SERIALIZE_METHODS;
423
424     template <typename Stream, typename Operation>
425     inline void SerializationOp(Stream& s, Operation ser_action) {
426         READWRITE(*(CTokenOutput *)this);
427         READWRITE(controllingCurrencyID);
428     }
429
430     std::vector<unsigned char> AsVector()
431     {
432         return ::AsVector(*this);
433     }
434
435     UniValue ToUniValue() const;
436
437     bool IsValid() const
438     {
439         return CTokenOutput::IsValid() && !controllingCurrencyID.IsNull();
440     }
441
442     static std::string ReserveDepositKeyName()
443     {
444         return "vrsc::system.currency.reservetransfer";
445     }
446
447     static uint160 ReserveDepositKey()
448     {
449         static uint160 nameSpace;
450         static uint160 reserveDepositKey = CVDXF::GetDataKey(ReserveDepositKeyName(), nameSpace);
451         return reserveDepositKey;
452     }
453
454     uint160 ReserveDepositIndexKey() const
455     {
456         return CCrossChainRPCData::GetConditionID(controllingCurrencyID, ReserveDepositKey());
457     }
458
459     static uint160 ReserveDepositIndexKey(const uint160 &currencyID)
460     {
461         return CCrossChainRPCData::GetConditionID(currencyID, ReserveDepositKey());
462     }
463 };
464
465 class CFeePool : public CTokenOutput
466 {
467 public:
468     enum
469     {
470         PER_BLOCK_RATIO = 1000000,
471         MIN_SHARE_SIZE = 10000,
472         FLAG_COINBASE_POOL = 1,
473         FLAG_CURRENCY_NOTARY_POOL = 2
474     };
475     uint32_t flags;
476     uint160 notaryCurrencyID;
477     CFeePool(uint32_t ver=VERSION_CURRENT, uint32_t Flags=FLAG_COINBASE_POOL) : CTokenOutput(ver), flags(FLAG_COINBASE_POOL) {}
478
479     CFeePool(const std::vector<unsigned char> &asVector)
480     {
481         FromVector(asVector, *this);
482     }
483
484     CFeePool(const CTransaction &coinbaseTx);
485
486     CFeePool(const CCurrencyValueMap &reserveOut, uint32_t Flags=FLAG_COINBASE_POOL, const uint160 &notaryCID=uint160()) : 
487         flags(Flags), notaryCurrencyID(notaryCID), CTokenOutput(reserveOut) {}
488
489     ADD_SERIALIZE_METHODS;
490
491     template <typename Stream, typename Operation>
492     inline void SerializationOp(Stream& s, Operation ser_action) {
493         READWRITE(*(CTokenOutput *)this);
494         READWRITE(VARINT(flags));
495         if (flags & FLAG_CURRENCY_NOTARY_POOL)
496         {
497             READWRITE(notaryCurrencyID);
498         }
499         else
500         {
501             notaryCurrencyID = uint160();
502         }
503     }
504
505     // returns false if fails to get block, otherwise, CFeePool if present
506     // invalid CFeePool if not
507     static bool GetCoinbaseFeePool(CFeePool &feePool, uint32_t height=0);
508
509     CFeePool OneFeeShare()
510     {
511         CFeePool retVal;
512         for (auto &oneCur : reserveValues.valueMap)
513         {
514             CAmount share = (oneCur.second <= MIN_SHARE_SIZE) ? oneCur.second : CCurrencyDefinition::CalculateRatioOfValue(oneCur.second, PER_BLOCK_RATIO);
515             if (oneCur.second > MIN_SHARE_SIZE && share < MIN_SHARE_SIZE)
516             {
517                 share = MIN_SHARE_SIZE;
518             }
519             if (share)
520             {
521                 retVal.reserveValues.valueMap[oneCur.first] = share;
522             }
523         }
524         return retVal;
525     }
526
527     void SetInvalid()
528     {
529         nVersion = VERSION_INVALID;
530     }
531
532     bool IsValid() const
533     {
534         return CTokenOutput::IsValid();
535     }
536 };
537
538 class CCrossChainExport;
539
540 // import transactions and tokens from another chain
541 // this represents the chain, the currencies, and the amounts of each
542 // it may also import IDs from the chain on which they were defined
543 class CCrossChainImport
544 {
545 public:
546     enum EVersion {
547         VERSION_INVALID = 0,
548         VERSION_CURRENT = 1,
549         VERSION_LAST = 1,
550     };
551     enum EFlags {
552         FLAG_DEFINITIONIMPORT = 1,
553         FLAG_INITIALLAUNCHIMPORT = 2,
554         FLAG_POSTLAUNCH = 4,
555         FLAG_SAMECHAIN = 8,                             // means proof/reerve transfers are from export on chain
556         FLAG_HASSUPPLEMENT = 0x10,                      // indicates that we have additional outputs containing the reservetransfers for this export
557         FLAG_SUPPLEMENTAL = 0x20,                       // this flag indicates that this is a supplemental output to a prior output
558         FLAG_SOURCESYSTEM = 0x40,
559     };
560     uint16_t nVersion;
561     uint16_t flags;
562     uint160 sourceSystemID;                             // the native source currency system from where these transactions are imported
563     uint32_t sourceSystemHeight;                        // export system height at export
564     uint160 importCurrencyID;                           // the import currency ID
565     CCurrencyValueMap importValue;                      // total amount of coins imported from source system with or without conversion, including fees
566     CCurrencyValueMap totalReserveOutMap;               // all non-native currencies being held in this thread and released on import
567     int32_t numOutputs;                                 // number of outputs generated by this import on this transaction for validation
568
569     uint256 hashReserveTransfers;                       // hash of complete reserve transfer list in order if (txinputs, m=0, m=1, ..., m=(n-1))
570     uint256 exportTxId;                                 // txid of export
571     int32_t exportTxOutNum;                             // output of the tx
572
573     CCrossChainImport() : nVersion(VERSION_INVALID), flags(0), sourceSystemHeight(0), numOutputs(0) {}
574     CCrossChainImport(const uint160 &sourceSysID, 
575                       uint32_t sourceSysHeight,
576                       const uint160 &importCID, 
577                       const CCurrencyValueMap &ImportValue, 
578                       const CCurrencyValueMap &InitialReserveOutput=CCurrencyValueMap(),
579                       int32_t NumOutputs=0,
580                       uint256 HashReserveTransfers=uint256(),
581                       uint256 ExportTxId=uint256(),
582                       int32_t ExportTxOutNum=-1,
583                       uint16_t Flags=FLAG_SAMECHAIN,
584                       uint16_t version=VERSION_CURRENT) : 
585                         nVersion(version),
586                         flags(Flags),
587                         sourceSystemID(sourceSysID),
588                         sourceSystemHeight(sourceSysHeight),
589                         importCurrencyID(importCID),
590                         importValue(ImportValue),
591                         totalReserveOutMap(InitialReserveOutput),
592                         numOutputs(NumOutputs),
593                         hashReserveTransfers(HashReserveTransfers),
594                         exportTxId(ExportTxId),
595                         exportTxOutNum(ExportTxOutNum)
596                         { }
597
598     CCrossChainImport(const std::vector<unsigned char> &asVector)
599     {
600         ::FromVector(asVector, *this);
601     }
602
603     CCrossChainImport(const CTransaction &tx, int32_t *pOutNum=nullptr);
604     CCrossChainImport(const CScript &script);
605     CCrossChainImport(const UniValue &obj);
606
607     ADD_SERIALIZE_METHODS;
608
609     template <typename Stream, typename Operation>
610     inline void SerializationOp(Stream& s, Operation ser_action) {
611         READWRITE(nVersion);
612         READWRITE(flags);
613         READWRITE(sourceSystemID);
614         READWRITE(sourceSystemHeight);
615         READWRITE(importCurrencyID);
616         READWRITE(importValue);
617         READWRITE(totalReserveOutMap);
618         READWRITE(numOutputs);
619         READWRITE(hashReserveTransfers);
620         READWRITE(exportTxId);
621         READWRITE(exportTxOutNum);
622     }
623
624     std::vector<unsigned char> AsVector()
625     {
626         return ::AsVector(*this);
627     }
628
629     bool IsValid() const
630     {
631         return nVersion > VERSION_INVALID && nVersion <= VERSION_LAST && !sourceSystemID.IsNull();
632     }
633
634     bool IsSameChain() const
635     {
636         return flags & FLAG_SAMECHAIN;
637     }
638
639     void SetSameChain(bool isSameChain)
640     {
641         if (isSameChain)
642         {
643             flags |= FLAG_SAMECHAIN;
644         }
645         else
646         {
647             flags &= ~FLAG_SAMECHAIN;
648         }
649     }
650
651     void SetDefinitionImport(bool isDefinition)
652     {
653         if (isDefinition)
654         {
655             flags |= FLAG_DEFINITIONIMPORT;
656         }
657         else
658         {
659             flags &= ~FLAG_DEFINITIONIMPORT;
660         }
661     }
662
663     bool IsDefinitionImport() const
664     {
665         return flags & FLAG_DEFINITIONIMPORT;
666     }
667
668     bool IsPostLaunch() const
669     {
670         return flags & FLAG_POSTLAUNCH;
671     }
672
673     void SetPostLaunch(bool isPostLaunch=true)
674     {
675         if (isPostLaunch)
676         {
677             flags |= FLAG_POSTLAUNCH;
678         }
679         else
680         {
681             flags &= ~FLAG_POSTLAUNCH;
682         }
683     }
684
685     bool IsSourceSystemImport() const
686     {
687         return flags & FLAG_SOURCESYSTEM;
688     }
689
690     // still importing from pre-launch exports that may contain pre-conversions but not conversions
691     // after all of those imports are complete, we can import post-launch exports
692     bool IsInitialLaunchImport() const
693     {
694         return flags & FLAG_INITIALLAUNCHIMPORT;
695     }
696
697     void SetInitialLaunchImport(bool isInitialLaunchImport=true)
698     {
699         if (isInitialLaunchImport)
700         {
701             flags |= FLAG_INITIALLAUNCHIMPORT;
702         }
703         else
704         {
705             flags &= ~FLAG_INITIALLAUNCHIMPORT;
706         }
707     }
708
709     UniValue ToUniValue() const;
710
711     static std::string CurrencyImportKeyName()
712     {
713         return "vrsc::system.currency.currencyimport";
714     }
715
716     static uint160 CurrencyImportKey()
717     {
718         static uint160 nameSpace;
719         static uint160 key = CVDXF::GetDataKey(CurrencyImportKeyName(), nameSpace);
720         return key;
721     }
722
723     static std::string CurrencySystemImportKeyName()
724     {
725         return "vrsc::system.currency.systemimport";
726     }
727
728     static uint160 CurrencySystemImportKey()
729     {
730         static uint160 nameSpace;
731         static uint160 key = CVDXF::GetDataKey(CurrencySystemImportKeyName(), nameSpace);
732         return key;
733     }
734
735     // returns false if the information is unavailable, indicating an invalid, out of context, or
736     // incomplete import transaction
737     bool GetImportInfo(const CTransaction &importTx,
738                        uint32_t nHeight,
739                        int numImportOut, 
740                        CCrossChainExport &ccx,
741                        CCrossChainImport &sysCCI,
742                        int32_t &sysCCIOut,
743                        CPBaaSNotarization &importNotarization, 
744                        int32_t &importNotarizationOut,
745                        int32_t &evidenceOutStart,
746                        int32_t &evidenceOutEnd,
747                        std::vector<CReserveTransfer> &reserveTransfers,
748                        CValidationState &state) const;
749     bool GetImportInfo(const CTransaction &importTx, 
750                        uint32_t nHeight,
751                        int numImportOut, 
752                        CCrossChainExport &ccx,
753                        CCrossChainImport &sysCCI,
754                        int32_t &sysCCIOut,
755                        CPBaaSNotarization &importNotarization, 
756                        int32_t &importNotarizationOut,
757                        int32_t &evidenceOutStart,
758                        int32_t &evidenceOutEnd,
759                        std::vector<CReserveTransfer> &reserveTransfers) const;
760
761     // ensures that all import rules were properly followed to create
762     // the import inputs and outputs on this transaction
763     bool ValidateImport(const CTransaction &tx,
764                         int numImportin,
765                         int numImportOut,
766                         CCrossChainExport &ccx,
767                         CPBaaSNotarization &importNotarization,
768                         std::vector<CReserveTransfer> &reserveTransfers,
769                         CValidationState &state) const;
770     bool ValidateImport(const CTransaction &tx,
771                         int numImportin,
772                         int numImportOut,
773                         CCrossChainExport &ccx,
774                         CPBaaSNotarization &importNotarization,
775                         std::vector<CReserveTransfer> &reserveTransfers) const;
776 };
777
778 // describes an entire output that will be realized on a target chain. target is specified as part of an aggregated transaction.
779 class CCrossChainExport
780 {
781 public:
782     enum {
783         MIN_BLOCKS = 10,
784         MIN_INPUTS = 10,
785         MAX_FEE_INPUTS = 50                         // when we reach 50 or more inputs, we get maximum fees as an exporter
786     };
787
788     enum
789     {
790         MIN_FEES_BEFORE_FEEPOOL = 20000,            // MAX(MIN(this, max avail), RATIO_OF_EXPORT_FEE of export fees) is sent to exporter
791         RATIO_OF_EXPORT_FEE = 10000000,
792     };
793
794     enum EVersions
795     {
796         VERSION_INVALID = 0,
797         VERSION_CURRENT = 1,
798         VERSION_FIRST = 1,
799         VERSION_LAST = 1,
800     };
801
802     enum EFlags
803     {
804         FLAG_PRELAUNCH = 1,                     // prior to launch
805         FLAG_CLEARLAUNCH = 2,                   // when launch state is determined, there is one of these
806         FLAG_HASSUPPLEMENT = 4,                 // indicates that we have additional outputs containing the reservetransfers for this export
807         FLAG_SUPPLEMENTAL = 8,                  // this flag indicates that this is a supplemental output to a prior output
808         FLAG_EVIDENCEONLY = 0x10,               // when set, this is not indexed as an active export
809         FLAG_GATEWAYEXPORT = 0x20,              // when set, will be exported to a gateway currency, which may get routed from this chain as systemID
810         FLAG_DEFINITIONEXPORT = 0x40,           // set on only the first export
811         FLAG_POSTLAUNCH = 0x80,                 // set post launch
812         FLAG_SYSTEMTHREAD = 0x100               // export that is there to ensure continuous export thread only
813     };
814
815     uint16_t nVersion;                          // current version
816     uint16_t flags;                             // controls serialization and active state
817
818     // these amounts are not serialized for supplemental export outputs, which identify themselves,
819     // indicate their position in the relative group of outputs, and carry the additional reserve transfers.
820     uint160 sourceSystemID;                     // imported from native system or gateway (notarization payout to this system)
821     uint32_t sourceHeightStart;                 // exporting all items to the destination from source system height...
822     uint32_t sourceHeightEnd;                   // to height, inclusive of end, last before start block from launch chain is needed to start a currency
823     uint160 destSystemID;                       // exported to target blockchain or system
824     uint160 destCurrencyID;                     // exported to target currency
825     int32_t numInputs;                          // total number of inputs aggregated for validation
826     CCurrencyValueMap totalAmounts;             // total amount exported of each currency, including fees
827     CCurrencyValueMap totalFees;                // total fees in all currencies to split between this export and import
828     uint256 hashReserveTransfers;               // hash of complete reserve transfer list in order of (txinputs, m=0, m=1, ..., m=(n-1))
829     CCurrencyValueMap totalBurned;              // if this is a cross chain export, some currencies will be burned, the rest held in deposits
830     CTransferDestination exporter;              // typically the exporting miner or staker's address, to accept deferred payment for the export
831
832     int32_t firstInput;                         // if export is from inputs, on chain of reserveTransfers, this is first input
833     std::vector<CReserveTransfer> reserveTransfers; // reserve transfers for this export, can be split across multiple outputs
834
835     CCrossChainExport() : nVersion(VERSION_INVALID), flags(0), sourceHeightStart(0), sourceHeightEnd(0), numInputs(0), firstInput(0) {}
836
837     CCrossChainExport(const std::vector<unsigned char> &asVector)
838     {
839         FromVector(asVector, *this);
840     }
841
842     CCrossChainExport(const uint160 &SourceSystemID, 
843                       int32_t SourceHeightStart,
844                       int32_t SourceHeightEnd,
845                       const uint160 &DestSystemID, 
846                       const uint160 &DestCurrencyID, 
847                       int32_t numin, 
848                       const CCurrencyValueMap &values, 
849                       const CCurrencyValueMap &transferFees, 
850                       const uint256 &HashReserveTransfers,
851                       const CCurrencyValueMap &TotalBurned=CCurrencyValueMap(),
852                       int32_t firstin=-1, 
853                       const CTransferDestination Exporter=CTransferDestination(),
854                       const std::vector<CReserveTransfer> &ReserveTransfers=std::vector<CReserveTransfer>(),
855                       int16_t Flags=0, int16_t Version=VERSION_CURRENT) : 
856                       nVersion(Version), 
857                       flags(Flags), 
858                       sourceSystemID(SourceSystemID), 
859                       sourceHeightStart(SourceHeightStart), 
860                       sourceHeightEnd(SourceHeightEnd), 
861                       destSystemID(DestSystemID), 
862                       destCurrencyID(DestCurrencyID), 
863                       numInputs(numin),
864                       totalBurned(TotalBurned),
865                       firstInput(firstin), 
866                       totalAmounts(values), 
867                       totalFees(transferFees), 
868                       hashReserveTransfers(HashReserveTransfers),
869
870                       exporter(Exporter), 
871                       reserveTransfers(ReserveTransfers)
872     {}
873
874     CCrossChainExport(const CScript &script);
875     CCrossChainExport(const UniValue &obj);
876     CCrossChainExport(const CTransaction &tx, int32_t *pCCXOutputNum=nullptr);
877
878     ADD_SERIALIZE_METHODS;
879
880     template <typename Stream, typename Operation>
881     inline void SerializationOp(Stream& s, Operation ser_action) {
882         READWRITE(nVersion);
883         READWRITE(flags);
884         READWRITE(sourceSystemID);
885         if (!(flags & FLAG_SUPPLEMENTAL))
886         {
887             READWRITE(VARINT(sourceHeightStart));
888             READWRITE(VARINT(sourceHeightEnd));
889             READWRITE(destSystemID);
890             READWRITE(destCurrencyID);
891             READWRITE(numInputs);
892             READWRITE(totalAmounts);
893             READWRITE(totalFees);
894             READWRITE(hashReserveTransfers);
895             READWRITE(totalBurned);
896             READWRITE(exporter);
897             READWRITE(firstInput);
898         }
899         READWRITE(reserveTransfers);
900     }
901
902     std::vector<unsigned char> AsVector()
903     {
904         return ::AsVector(*this);
905     }
906
907     bool IsSupplemental() const
908     {
909         return flags & FLAG_SUPPLEMENTAL;
910     }
911
912     bool HasSupplement() const
913     {
914         return flags & FLAG_HASSUPPLEMENT;
915     }
916
917     bool IsValid() const
918     {
919         return nVersion >= VERSION_FIRST && 
920                nVersion <= VERSION_LAST && 
921                !sourceSystemID.IsNull() &&
922                (IsSupplemental() ||
923                (!destSystemID.IsNull() &&
924                 !destCurrencyID.IsNull()));
925     }
926
927     static CCurrencyValueMap CalculateExportFee(const CCurrencyValueMap &fees, int numIn);
928     static CAmount CalculateExportFeeRaw(CAmount fee, int numIn);
929     CCurrencyValueMap CalculateExportFee() const;
930     CCurrencyValueMap CalculateImportFee() const;
931     static CAmount ExportReward(int64_t exportFee);
932
933     UniValue ToUniValue() const;
934
935     bool IsSameChain() const
936     {
937         return sourceSystemID == ASSETCHAINS_CHAINID;
938     }
939
940     bool IsPrelaunch() const
941     {
942         return flags & FLAG_PRELAUNCH;
943     }
944
945     void SetPreLaunch(bool setTrue=true)
946     {
947         if (setTrue)
948         {
949             flags |= FLAG_PRELAUNCH;
950         }
951         else
952         {
953             flags &= ~FLAG_PRELAUNCH;
954         }
955     }
956
957     bool IsPostlaunch() const
958     {
959         return flags & FLAG_POSTLAUNCH;
960     }
961
962     void SetPostLaunch(bool setTrue=true)
963     {
964         if (setTrue)
965         {
966             flags |= FLAG_POSTLAUNCH;
967         }
968         else
969         {
970             flags &= ~FLAG_POSTLAUNCH;
971         }
972     }
973
974     bool IsSystemThreadExport() const
975     {
976         return flags & FLAG_SYSTEMTHREAD;
977     }
978
979     void SetSystemThreadExport(bool setTrue=true)
980     {
981         if (setTrue)
982         {
983             flags |= FLAG_SYSTEMTHREAD;
984         }
985         else
986         {
987             flags &= ~FLAG_SYSTEMTHREAD;
988         }
989     }
990
991     bool IsChainDefinition() const
992     {
993         return flags & FLAG_DEFINITIONEXPORT;
994     }
995
996     void SetChainDefinition(bool setTrue=true)
997     {
998         if (setTrue)
999         {
1000             flags |= FLAG_DEFINITIONEXPORT;
1001         }
1002         else
1003         {
1004             flags &= ~FLAG_DEFINITIONEXPORT;
1005         }
1006     }
1007
1008     bool IsClearLaunch() const
1009     {
1010         return flags & FLAG_CLEARLAUNCH;
1011     }
1012
1013     void SetClearLaunch(bool setTrue=true)
1014     {
1015         if (setTrue)
1016         {
1017             flags |= FLAG_CLEARLAUNCH;
1018         }
1019         else
1020         {
1021             flags &= ~FLAG_CLEARLAUNCH;
1022         }
1023     }
1024
1025     bool GetExportInfo(const CTransaction &exportTx, 
1026                        int numExportOut,
1027                        int &primaryExportOutNumOut,
1028                        int32_t &nextOutput,
1029                        CPBaaSNotarization &exportNotarization, 
1030                        std::vector<CReserveTransfer> &reserveTransfers,
1031                        CValidationState &state) const;
1032
1033     bool GetExportInfo(const CTransaction &exportTx, 
1034                        int numExportOut, 
1035                        int &primaryExportOutNumOut,
1036                        int32_t &nextOutput,
1037                        CPBaaSNotarization &exportNotarization, 
1038                        std::vector<CReserveTransfer> &reserveTransfers) const;
1039
1040     static std::string CurrencyExportKeyName()
1041     {
1042         return "vrsc::system.currency.export";
1043     }
1044
1045     static uint160 CurrencyExportKey()
1046     {
1047         static uint160 nameSpace;
1048         static uint160 key = CVDXF::GetDataKey(CurrencyExportKeyName(), nameSpace);
1049         return key;
1050     }
1051
1052     static std::string SystemExportKeyName()
1053     {
1054         return "vrsc::system.currency.systemexport";
1055     }
1056
1057     static uint160 SystemExportKey()
1058     {
1059         static uint160 nameSpace;
1060         static uint160 key = CVDXF::GetDataKey(SystemExportKeyName(), nameSpace);
1061         return key;
1062     }
1063 };
1064
1065 class CCurrencyState
1066 {
1067 public:
1068     enum EVersion {
1069         VERSION_INVALID = 0,
1070         VERSION_FIRST = 1,
1071         VERSION_LAST = 1,
1072         VERSION_CURRENT = 1,
1073     };
1074
1075     enum EFlags {
1076         FLAG_FRACTIONAL = 1,
1077         FLAG_PRELAUNCH = 2,
1078         FLAG_REFUNDING = 4,
1079         FLAG_LAUNCHCLEAR = 8,               // set only on the first import after launch has been cleared, whether refunding or confirmed
1080         FLAG_LAUNCHCONFIRMED = 0x10,
1081         FLAG_LAUNCHCOMPLETEMARKER = 0x20    // only set on the currency state when importing the last transfers exported during pre-launch
1082     };
1083
1084     enum EConstants {
1085         MIN_RESERVE_RATIO = 1000000,        // we will not start a chain with less than 1% reserve ratio in any single currency
1086         MAX_RESERVE_RATIO = 100000000,      // we will not start a chain with greater than 100% reserve ratio
1087         SHUTDOWN_RESERVE_RATIO = 500000,    // if we hit this reserve ratio in any currency, initiate chain shutdown
1088         CONVERSION_TX_SIZE_MIN = 1024,      // minimum size accounted for in a conversion transaction
1089         MAX_RESERVE_CURRENCIES = 10,        // maximum number of reserve currencies that can underly a fractional reserve
1090         MIN_CONVERTER_RESERVE_TO_INDEX = 1000, // must have at least this much in native reserves to be indexed as a converter
1091         MIN_CONVERTER_RATIO_TO_INDEX = 10000000 // must have at least 10% reserve ratio of native as well
1092     };
1093
1094     uint16_t version;
1095     uint16_t flags;                         // currency flags (valid, reserve currency, etc.)
1096     uint160 currencyID;                     // ID of this currency
1097     std::vector<uint160> currencies;        // the ID in uin160 form (maps to CIdentityID) if each currency in the reserve
1098     std::vector<int32_t> weights;           // current, individual weights for all currencies to use in calculations
1099     std::vector<int64_t> reserves;          // total amount of reserves in each currency
1100
1101     int64_t initialSupply;                  // initial premine + pre-converted coins
1102     int64_t emitted;                        // emitted coins reduce the reserve ratio and are used to calculate current ratio
1103     CAmount supply;                         // current supply: total of initial, all emitted, and all purchased coins
1104
1105     //std::vector<CAmount> Reserves; // reserve currencies amounts controlled by this fractional chain - only present for reserve currencies, currency IDs are in chain definition
1106
1107     CCurrencyState() : version(VERSION_INVALID), flags(0), initialSupply(0), emitted(0), supply(0) {}
1108
1109     CCurrencyState(const uint160 &cID,
1110                    const std::vector<uint160> &Currencies, 
1111                    const std::vector<int32_t> &Weights, 
1112                    const std::vector<int64_t> &Reserves, 
1113                    CAmount InitialSupply, 
1114                    CAmount Emitted, 
1115                    CAmount Supply, 
1116                    uint16_t Flags=0,
1117                    uint16_t Version=VERSION_CURRENT) : 
1118         version(Version),
1119         flags(Flags),
1120         currencyID(cID),
1121         currencies(Currencies), 
1122         weights(Weights), 
1123         reserves(Reserves),
1124         initialSupply(InitialSupply), 
1125         emitted(Emitted),
1126         supply(Supply)
1127     {
1128         if (weights.size() != currencies.size())
1129         {
1130             weights = std::vector<int32_t>(currencies.size());
1131         }
1132         if (reserves.size() != reserves.size())
1133         {
1134             reserves = std::vector<int64_t>(currencies.size());
1135         }
1136     }
1137
1138     CCurrencyState(const std::vector<unsigned char> &asVector)
1139     {
1140         FromVector(asVector, *this);
1141     }
1142
1143     CCurrencyState(const UniValue &uni);
1144
1145     ADD_SERIALIZE_METHODS;
1146
1147     template <typename Stream, typename Operation>
1148     inline void SerializationOp(Stream& s, Operation ser_action) {
1149         READWRITE(version);
1150         READWRITE(flags);
1151         READWRITE(currencyID);        
1152         READWRITE(currencies);        
1153         READWRITE(weights);        
1154         READWRITE(reserves);        
1155         READWRITE(VARINT(initialSupply));
1156         READWRITE(VARINT(emitted));
1157         READWRITE(VARINT(supply));
1158     }
1159
1160     std::vector<unsigned char> AsVector() const
1161     {
1162         return ::AsVector(*this);
1163     }
1164
1165     // this should be done no more than once to prepare a currency state to be moved to the next state
1166     // emission occurs for a block before any conversion or exchange and that impact on the currency state is calculated
1167     CCurrencyState &UpdateWithEmission(CAmount emitted);
1168
1169     cpp_dec_float_50 GetReserveRatio(int32_t reserveIndex=0) const
1170     {
1171         return cpp_dec_float_50(std::to_string(weights[reserveIndex])) / cpp_dec_float_50("100000000");
1172     }
1173
1174     template<typename cpp_dec_float_type>
1175     static bool to_int64(const cpp_dec_float_type &input, int64_t &outval)
1176     {
1177         std::stringstream ss(input.str(0, std::ios_base::fmtflags::_S_fixed));
1178         try
1179         {
1180             ss >> outval;
1181             return true;
1182         }
1183         catch(const std::exception& e)
1184         {
1185             return false;
1186         }
1187     }
1188
1189     // in a fractional reserve with no reserve or supply, this will always return
1190     // a price of the reciprocal (1/x) of the fractional reserve ratio of the indexed reserve,
1191     // which will always be >= 1
1192     CAmount PriceInReserve(int32_t reserveIndex=0, bool roundUp=false) const;
1193
1194     // return the current price of the fractional reserve in the reserve currency in Satoshis
1195     cpp_dec_float_50 PriceInReserveDecFloat50(int32_t reserveIndex=0) const;
1196
1197     std::vector<CAmount> PricesInReserve() const;
1198
1199     // This considers one currency at a time
1200     CAmount ConvertAmounts(CAmount inputReserve, CAmount inputFractional, CCurrencyState &newState, int32_t reserveIndex=0) const;
1201
1202     // convert amounts for multi-reserve fractional reserve currencies
1203     // one entry in the vector for each currency in and one fractional input for each
1204     // currency expected as output
1205     std::vector<CAmount> ConvertAmounts(const std::vector<CAmount> &inputReserve,    // reserves to convert to fractional
1206                                         const std::vector<CAmount> &inputFractional,    // fractional to convert to each reserve
1207                                         CCurrencyState &newState,
1208                                         const std::vector<std::vector<CAmount>> *pCrossConversions=nullptr,
1209                                         std::vector<CAmount> *pViaPrices=nullptr) const;
1210
1211     CAmount CalculateConversionFee(CAmount inputAmount, bool convertToNative = false, int32_t reserveIndex=0) const;
1212     CAmount ReserveFeeToNative(CAmount inputAmount, CAmount outputAmount, int32_t reserveIndex=0) const;
1213
1214     CAmount ReserveToNative(CAmount reserveAmount, int32_t reserveIndex) const;
1215     CAmount ReserveToNative(const CCurrencyValueMap &reserveAmounts) const;
1216
1217     static CAmount ReserveToNativeRaw(CAmount reserveAmount, const cpp_dec_float_50 &exchangeRate);
1218     static CAmount ReserveToNativeRaw(CAmount reserveAmount, CAmount exchangeRate);
1219     static CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<uint160> &currencies, const std::vector<CAmount> &exchangeRates);
1220     static CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<uint160> &currencies, const std::vector<cpp_dec_float_50> &exchangeRates);
1221     CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<CAmount> &exchangeRates) const;
1222
1223     const CCurrencyValueMap &NativeToReserve(std::vector<CAmount> nativeAmount, int32_t reserveIndex=0) const;
1224     CAmount NativeToReserve(CAmount nativeAmount, int32_t reserveIndex=0) const;
1225     static CAmount NativeToReserveRaw(CAmount nativeAmount, const cpp_dec_float_50 &exchangeRate);
1226     static CAmount NativeToReserveRaw(CAmount nativeAmount, CAmount exchangeRate);
1227     CCurrencyValueMap NativeToReserveRaw(const std::vector<CAmount> &, const std::vector<CAmount> &exchangeRates) const;
1228     CCurrencyValueMap NativeToReserveRaw(const std::vector<CAmount> &, const std::vector<cpp_dec_float_50> &exchangeRates) const;
1229
1230     UniValue ToUniValue() const;
1231
1232     uint160 GetID() const { return currencyID; }
1233
1234     bool IsValid() const
1235     {
1236         return version >= VERSION_FIRST && version <= VERSION_LAST && !currencyID.IsNull();
1237     }
1238
1239     bool IsFractional() const
1240     {
1241         return flags & FLAG_FRACTIONAL;
1242     }
1243
1244     bool IsRefunding() const
1245     {
1246         return flags & FLAG_REFUNDING;
1247     }
1248
1249     bool IsPrelaunch() const
1250     {
1251         return flags & FLAG_PRELAUNCH;
1252     }
1253
1254     bool IsLaunchClear() const
1255     {
1256         return flags & FLAG_LAUNCHCLEAR;
1257     }
1258
1259     bool IsLaunchConfirmed() const
1260     {
1261         return flags & FLAG_LAUNCHCONFIRMED;
1262     }
1263
1264     bool IsLaunchCompleteMarker() const
1265     {
1266         return flags & FLAG_LAUNCHCOMPLETEMARKER;
1267     }
1268
1269     // this is only set after the import that completes all pre-conversions
1270     void SetLaunchCompleteMarker(bool newState=true)
1271     {
1272         if (newState)
1273         {
1274             flags &= ~FLAG_PRELAUNCH;
1275             flags |= FLAG_LAUNCHCOMPLETEMARKER;
1276         }
1277         else
1278         {
1279             flags &= ~FLAG_LAUNCHCOMPLETEMARKER;
1280         }
1281     }
1282
1283     void SetPrelaunch(bool newState=true)
1284     {
1285         if (newState)
1286         {
1287             flags |= FLAG_PRELAUNCH;
1288         }
1289         else
1290         {
1291             flags &= ~FLAG_PRELAUNCH;
1292         }
1293     }
1294
1295     void SetLaunchClear(bool newState=true)
1296     {
1297         if (newState)
1298         {
1299             flags |= FLAG_LAUNCHCLEAR;
1300         }
1301         else
1302         {
1303             flags &= ~FLAG_LAUNCHCLEAR;
1304         }
1305     }
1306
1307     void SetLaunchConfirmed(bool newState=true)
1308     {
1309         if (newState)
1310         {
1311             flags |= FLAG_LAUNCHCONFIRMED;
1312         }
1313         else
1314         {
1315             flags &= ~FLAG_LAUNCHCONFIRMED;
1316         }
1317     }
1318
1319     void SetRefunding(bool newState=true)
1320     {
1321         if (newState)
1322         {
1323             flags |= FLAG_REFUNDING;
1324         }
1325         else
1326         {
1327             flags &= ~FLAG_REFUNDING;
1328         }
1329     }
1330
1331     std::map<uint160, int32_t> GetReserveMap() const
1332     {
1333         std::map<uint160, int32_t> retVal;
1334         for (int i = 0; i < currencies.size(); i++)
1335         {
1336             retVal[currencies[i]] = i;
1337         }
1338         return retVal;
1339     }
1340 };
1341
1342 class CCoinbaseCurrencyState : public CCurrencyState
1343 {
1344 public:
1345     CAmount primaryCurrencyOut;             // converted or generated currency output, emitted, converted, etc. is stored in parent class
1346     CAmount preConvertedOut;                // how much of the currency out was pre-converted, which is asynchronously added to supply
1347     CAmount primaryCurrencyFees;
1348     CAmount primaryCurrencyConversionFees;
1349     std::vector<CAmount> reserveIn;         // reserve currency converted to native
1350     std::vector<CAmount> primaryCurrencyIn; // native currency converted to reserve
1351     std::vector<CAmount> reserveOut;        // output can have both normal and reserve output value, if non-0, this is spent by the required output transactions
1352     std::vector<CAmount> conversionPrice;   // calculated price in reserve for all conversions * 100000000
1353     std::vector<CAmount> viaConversionPrice; // the via conversion stage prices
1354     std::vector<CAmount> fees;              // fee values in native (or reserve if specified) coins for reserve transaction fees for the block
1355     std::vector<CAmount> conversionFees;    // total of only conversion fees, which will accrue to the conversion transaction
1356
1357     CCoinbaseCurrencyState() : primaryCurrencyOut(0), preConvertedOut(0), primaryCurrencyFees(0), primaryCurrencyConversionFees(0) {}
1358
1359     CCoinbaseCurrencyState(const CCurrencyState &CurrencyState,
1360                            CAmount NativeOut=0, CAmount NativeFees=0, CAmount NativeConversionFees=0,
1361                            const std::vector<CAmount> &ReserveIn=std::vector<CAmount>(),
1362                            const std::vector<CAmount> &NativeIn=std::vector<CAmount>(), 
1363                            const std::vector<CAmount> &ReserveOut=std::vector<CAmount>(), 
1364                            const std::vector<CAmount> &ConversionPrice=std::vector<CAmount>(), 
1365                            const std::vector<CAmount> &ViaConversionPrice=std::vector<CAmount>(), 
1366                            const std::vector<CAmount> &Fees=std::vector<CAmount>(), 
1367                            const std::vector<CAmount> &ConversionFees=std::vector<CAmount>(),
1368                            CAmount PreConvertedOut=0) : 
1369         CCurrencyState(CurrencyState), primaryCurrencyOut(NativeOut), primaryCurrencyFees(NativeFees), primaryCurrencyConversionFees(NativeConversionFees),
1370         reserveIn(ReserveIn),
1371         primaryCurrencyIn(NativeIn),
1372         reserveOut(ReserveOut),
1373         conversionPrice(ConversionPrice),
1374         viaConversionPrice(ViaConversionPrice),
1375         fees(Fees),
1376         conversionFees(ConversionFees),
1377         preConvertedOut(PreConvertedOut)
1378     {
1379         if (!reserveIn.size()) reserveIn = std::vector<CAmount>(currencies.size());
1380         if (!primaryCurrencyIn.size()) primaryCurrencyIn = std::vector<CAmount>(currencies.size());
1381         if (!reserveOut.size()) reserveOut = std::vector<CAmount>(currencies.size());
1382         if (!conversionPrice.size()) conversionPrice = std::vector<CAmount>(currencies.size());
1383         if (!viaConversionPrice.size()) viaConversionPrice = std::vector<CAmount>(currencies.size());
1384         if (!fees.size()) fees = std::vector<CAmount>(currencies.size());
1385         if (!conversionFees.size()) conversionFees = std::vector<CAmount>(currencies.size());
1386     }
1387
1388     CCoinbaseCurrencyState(const UniValue &uni);
1389
1390     CCoinbaseCurrencyState(const std::vector<unsigned char> asVector)
1391     {
1392         ::FromVector(asVector, *this);
1393     }
1394
1395     CCoinbaseCurrencyState(const CTransaction &tx, int *pOutIdx=NULL);
1396
1397     ADD_SERIALIZE_METHODS;
1398
1399     template <typename Stream, typename Operation>
1400     inline void SerializationOp(Stream& s, Operation ser_action) {
1401         READWRITE(*(CCurrencyState *)this);
1402         READWRITE(primaryCurrencyOut);
1403         READWRITE(preConvertedOut);
1404         READWRITE(primaryCurrencyFees);
1405         READWRITE(primaryCurrencyConversionFees);
1406         READWRITE(reserveIn);
1407         READWRITE(primaryCurrencyIn);
1408         READWRITE(reserveOut);
1409         READWRITE(conversionPrice);
1410         READWRITE(viaConversionPrice);
1411         READWRITE(fees);
1412         READWRITE(conversionFees);
1413     }
1414
1415     std::vector<unsigned char> AsVector() const
1416     {
1417         return ::AsVector(*this);
1418     }
1419
1420     UniValue ToUniValue() const;
1421
1422     CCoinbaseCurrencyState &UpdateWithEmission(CAmount toEmit);
1423
1424     void ClearForNextBlock()
1425     {
1426         emitted = 0;
1427         primaryCurrencyOut = 0;
1428         preConvertedOut = 0;
1429         primaryCurrencyFees = 0;
1430         primaryCurrencyConversionFees = 0;
1431         reserveIn = std::vector<CAmount>(currencies.size());
1432         primaryCurrencyIn = std::vector<CAmount>(currencies.size());
1433         reserveOut = std::vector<CAmount>(currencies.size());
1434         fees = std::vector<CAmount>(currencies.size());
1435         conversionFees = std::vector<CAmount>(currencies.size());
1436     }
1437
1438     // given that all reserves in and out are accurate, this reverts the reserves and supply to the prior state,
1439     // while leaving conversion prices the same
1440     void RevertFees(const std::vector<CAmount> &conversionPrice,
1441                     const std::vector<CAmount> &viaConversionPrice,
1442                     const uint160 &systemID=ASSETCHAINS_CHAINID);
1443
1444     // returns all unconverted fees, liquidity fees, and converted fees
1445     // convertedFees are only added to if fees are found and never modified other than that, so this can
1446     // be used for accumulation.
1447     CCurrencyValueMap CalculateConvertedFees(const std::vector<CAmount> &normalConversionPrice,
1448                                              const std::vector<CAmount> &outgoingConversionPrice,
1449                                              const uint160 &systemID,
1450                                              bool &feesConverted,
1451                                              CCurrencyValueMap &liquidityFees,
1452                                              CCurrencyValueMap &convertedFees) const;
1453     void RevertReservesAndSupply();
1454
1455     template <typename NUMBERVECTOR>
1456     NUMBERVECTOR AddVectors(const NUMBERVECTOR &a, const NUMBERVECTOR &b) const
1457     {
1458         const NUMBERVECTOR *shortVec, *longVec;
1459         int64_t count, max;
1460         if (a.size() <= b.size())
1461         {
1462             count = a.size();
1463             max = b.size();
1464             shortVec = &a;
1465             longVec = &b;
1466         }
1467         else
1468         {
1469             count = b.size();
1470             max = a.size();
1471             shortVec = &b;
1472             longVec = &a;
1473         }
1474
1475         NUMBERVECTOR ret;
1476         ret.resize(max);
1477         for (int i = 0; i < count; i++)
1478         {
1479             ret[i] = (*longVec)[i] + (*shortVec)[i];
1480         }
1481         for (int i = count; i < max; i++)
1482         {
1483             ret[i] = (*longVec)[i];
1484         }
1485         return ret;
1486     }
1487
1488     inline static int64_t IndexConverterReserveMinimum()
1489     {
1490         // TODO: this needs to be specific to the current blockchain
1491         // on Verus, we will consider any currency with 1000 or more in Verus reserves and >= 10% reserve a possible
1492         // converter
1493         return MIN_CONVERTER_RESERVE_TO_INDEX; 
1494     }
1495
1496     inline static int32_t IndexConverterReserveRatio()
1497     {
1498         // currencies must have at least 10% native reserve to be considered a converter
1499         return MIN_CONVERTER_RATIO_TO_INDEX; 
1500     }
1501
1502     static std::string CurrencyStateKeyName()
1503     {
1504         return "vrsc::system.currency.state";
1505     }
1506
1507     static uint160 CurrencyStateKey()
1508     {
1509         static uint160 nameSpace;
1510         static uint160 currencyStateKey = CVDXF::GetDataKey(CurrencyStateKeyName(), nameSpace);
1511         return currencyStateKey;
1512     }
1513
1514     static std::string CurrencyConverterKeyName()
1515     {
1516         return "vrsc::system.currency.converter";
1517     }
1518
1519     static uint160 CurrencyConverterKey()
1520     {
1521         static uint160 nameSpace;
1522         static uint160 converterKey = CVDXF::GetDataKey(CurrencyConverterKeyName(), nameSpace);
1523         return converterKey;
1524     }
1525
1526     inline static uint160 IndexConverterKey(const uint160 &currencyID)
1527     {
1528         return CCrossChainRPCData::GetConditionID(currencyID, CurrencyConverterKey());
1529     }
1530 };
1531
1532 class CReserveInOuts
1533 {
1534 public:
1535     int64_t reserveIn;
1536     int64_t reserveOut;
1537     int64_t reserveOutConverted;
1538     int64_t nativeOutConverted;
1539     int64_t reserveConversionFees;
1540     CReserveInOuts() : reserveIn(0), reserveOut(0), reserveOutConverted(0), nativeOutConverted(0), reserveConversionFees(0) {}
1541     CReserveInOuts(int64_t ReserveIn, int64_t ReserveOut, int64_t ReserveOutConverted, int64_t NativeOutConverted, int64_t ReserveConversionFees) : 
1542                     reserveIn(ReserveIn), 
1543                     reserveOut(ReserveOut), 
1544                     reserveOutConverted(ReserveOutConverted), 
1545                     nativeOutConverted(NativeOutConverted), 
1546                     reserveConversionFees(ReserveConversionFees) {}
1547     UniValue ToUniValue() const;
1548 };
1549
1550 class CReserveTransactionDescriptor
1551 {
1552 public:
1553     enum EFlagBits {
1554         IS_VALID=1,                             // known to be valid
1555         IS_REJECT=2,                            // if set, tx is known to be invalid
1556         IS_RESERVE=4,                           // if set, this transaction affects reserves and/or price if mined
1557         IS_RESERVEEXCHANGE=8,                   // is this a reserve/exchange transaction?
1558         IS_LIMIT=0x10,                          // if reserve exchange, is it a limit order?
1559         IS_FILLORKILL=0x20,                     // If set, this can expire
1560         IS_FILLORKILLFAIL=0x40,                 // If set, this is an expired fill or kill in a valid tx
1561         IS_IMPORT=0x80,                         // If set, this is an expired fill or kill in a valid tx
1562         IS_EXPORT=0x100,                        // If set, this is an expired fill or kill in a valid tx
1563         IS_IDENTITY=0x200,                      // If set, this is an identity definition or update
1564         IS_IDENTITY_DEFINITION=0x400,           // If set, this is an identity definition
1565         IS_HIGH_FEE=0x800                       // If set, this may have "absurdly high fees"
1566     };
1567
1568     enum ESubIndexCodes {
1569         ONE_RESERVE_IDX = 1                     // used to create a condition code that indexed reserves of a fractional currency
1570     };
1571
1572     const CTransaction *ptx;                    // pointer to the actual transaction if valid
1573     uint16_t flags;                             // indicates transaction state
1574     std::map<uint160, CReserveInOuts> currencies; // currency entries in this transaction
1575     int16_t numBuys = 0;                        // each limit conversion that is valid before a certain block should account for FILL_OR_KILL_FEE
1576     int16_t numSells = 0;
1577     int16_t numTransfers = 0;                   // number of transfers, each of which also requires a transfer fee
1578     CAmount nativeIn = 0;
1579     CAmount nativeOut = 0;
1580     CAmount nativeConversionFees = 0;           // non-zero only if there is a conversion
1581
1582     CReserveTransactionDescriptor() : 
1583         flags(0),
1584         ptx(NULL),
1585         numBuys(0),                             // each limit conversion that is valid before a certain block should account for FILL_OR_KILL_FEE
1586         numSells(0),
1587         numTransfers(0),
1588         nativeIn(0),
1589         nativeOut(0),
1590         nativeConversionFees(0) {}              // non-zero only if there is a conversion, stored vs. calculated to get exact number with each calculated seperately
1591
1592     CReserveTransactionDescriptor(const CTransaction &tx, const CCoinsViewCache &view, int32_t nHeight);
1593
1594     UniValue ToUniValue() const;
1595
1596     bool IsReject() const { return flags & IS_REJECT; }
1597     bool IsValid() const { return flags & IS_VALID && !IsReject(); }
1598     bool IsReserve() const { return IsValid() && flags & IS_RESERVE; }
1599     bool IsReserveExchange() const { return flags & IS_RESERVEEXCHANGE; }
1600     bool IsLimit() const { return flags & IS_LIMIT; }
1601     bool IsFillOrKill() const { return flags & IS_FILLORKILL; }
1602     bool IsMarket() const { return IsReserveExchange() && !IsLimit(); }
1603     bool IsFillOrKillFail() const { return flags & IS_FILLORKILLFAIL; }
1604     bool IsIdentity() const { return flags & IS_IDENTITY; }
1605     bool IsIdentityDefinition() const { return flags & IS_IDENTITY_DEFINITION; }
1606     bool IsHighFee() const { return flags & IS_HIGH_FEE; }
1607
1608     static CAmount CalculateConversionFee(CAmount inputAmount);
1609     static CAmount CalculateConversionFeeNoMin(CAmount inputAmount);
1610     static CAmount CalculateAdditionalConversionFee(CAmount inputAmount);
1611
1612     CAmount TotalNativeOutConverted() const
1613     {
1614         CAmount nativeOutConverted = 0;
1615         for (auto &one : currencies)
1616         {
1617             nativeOutConverted += one.second.nativeOutConverted;
1618         }
1619         return nativeOutConverted;
1620     }
1621
1622     CCurrencyValueMap ReserveFees(const uint160 &nativeID=uint160()) const;
1623     CAmount NativeFees() const;
1624
1625     CAmount AllFeesAsNative(const CCurrencyState &currencyState) const;
1626     CAmount AllFeesAsNative(const CCurrencyState &currencyState, const std::vector<CAmount> &exchangeRates) const;
1627     CCurrencyValueMap AllFeesAsReserve(const CCurrencyState &currencyState, int defaultReserve=0) const;
1628     CCurrencyValueMap AllFeesAsReserve(const CCurrencyState &currencyState, const std::vector<CAmount> &exchangeRates, int defaultReserve=0) const;
1629
1630     // does not check for errors
1631     void AddReserveInput(const uint160 &currency, CAmount value);
1632     void AddReserveOutput(const uint160 &currency, CAmount value);
1633     void AddReserveOutConverted(const uint160 &currency, CAmount value);
1634     void AddNativeOutConverted(const uint160 &currency, CAmount value);
1635     void AddReserveConversionFees(const uint160 &currency, CAmount value);
1636
1637     CCurrencyValueMap ReserveInputMap(const uint160 &nativeID=uint160()) const;
1638     CCurrencyValueMap ReserveOutputMap(const uint160 &nativeID=uint160()) const;
1639     CCurrencyValueMap ReserveOutConvertedMap(const uint160 &nativeID=uint160()) const;
1640     CCurrencyValueMap NativeOutConvertedMap() const;
1641     CCurrencyValueMap ReserveConversionFeesMap() const;
1642     CCurrencyValueMap GeneratedImportCurrency(const uint160 &fromSystemID, const uint160 &importSystemID, const uint160 &importCurrencyID) const;
1643
1644     // returns vectors in same size and order as reserve currencies
1645     std::vector<CAmount> ReserveInputVec(const CCurrencyState &cState) const;
1646     std::vector<CAmount> ReserveOutputVec(const CCurrencyState &cState) const;
1647     std::vector<CAmount> ReserveOutConvertedVec(const CCurrencyState &cState) const;
1648     std::vector<CAmount> NativeOutConvertedVec(const CCurrencyState &cState) const;
1649     std::vector<CAmount> ReserveConversionFeesVec(const CCurrencyState &cState) const;
1650
1651     void AddReserveOutput(const CTokenOutput &ro);
1652     void AddReserveTransfer(const CReserveTransfer &rt);
1653
1654     bool AddReserveTransferImportOutputs(const CCurrencyDefinition &systemSource, 
1655                                          const CCurrencyDefinition &systemDest, 
1656                                          const CCurrencyDefinition &importCurrencyDef, 
1657                                          const CCoinbaseCurrencyState &importCurrencyState,
1658                                          const std::vector<CReserveTransfer> &exportObjects, 
1659                                          std::vector<CTxOut> &vOutputs,
1660                                          CCurrencyValueMap &importedCurrency,
1661                                          CCurrencyValueMap &gatewayDepositsIn,
1662                                          CCurrencyValueMap &spentCurrencyOut,
1663                                          CCoinbaseCurrencyState *pNewCurrencyState=nullptr);
1664 };
1665
1666 struct CCcontract_info;
1667 struct Eval;
1668 class CValidationState;
1669
1670 typedef std::tuple<uint32_t, CInputDescriptor, CReserveTransfer> ChainTransferData;
1671
1672 bool ValidateFeePool(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn, bool fulfilled);
1673 bool IsFeePoolInput(const CScript &scriptSig);
1674 bool PrecheckFeePool(const CTransaction &tx, int32_t outNum, CValidationState &state, uint32_t height);
1675 bool PrecheckReserveTransfer(const CTransaction &tx, int32_t outNum, CValidationState &state, uint32_t height);
1676
1677 #endif // PBAAS_RESERVES_H
This page took 0.119506 seconds and 4 git commands to generate.