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