1 /********************************************************************
2 * (C) 2019 Michael Toutonghi
4 * Distributed under the MIT software license, see the accompanying
5 * file COPYING or http://www.opensource.org/licenses/mit-license.php.
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.
12 #ifndef PBAAS_RESERVES_H
13 #define PBAAS_RESERVES_H
17 #include "pbaas/crosschainrpc.h"
18 #include "arith_uint256.h"
19 #include <boost/multiprecision/cpp_dec_float.hpp>
20 #include "librustzcash.h"
26 #define SATOSHIDEN ((uint64_t)100000000L)
29 using boost::multiprecision::cpp_dec_float_50;
30 class CCoinsViewCache;
31 class CInputDescriptor;
32 class CBaseChainObject;
34 class CMutableTransaction;
36 class CReserveTransactionDescriptor;
38 class CValidationState;
39 class CPBaaSNotarization;
40 extern uint160 ASSETCHAINS_CHAINID;
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.
51 VERSION_FIRSTVALID = 1,
52 VERSION_LASTVALID = 1,
53 VERSION_MULTIVALUE = 0x80000000 // used for serialization/deserialization
56 uint32_t nVersion; // version of the token output class
57 CCurrencyValueMap reserveValues; // all outputs of this reserve deposit
59 CTokenOutput(const std::vector<unsigned char> &asVector)
61 FromVector(asVector, *this);
64 CTokenOutput(const UniValue &obj);
66 CTokenOutput(uint32_t ver=VERSION_CURRENT) : nVersion(ver) {}
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) {}
71 ADD_SERIALIZE_METHODS;
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())
79 READWRITE(VARINT(nVersion));
80 if (nVersion & VERSION_MULTIVALUE)
82 READWRITE(currencies);
84 if (currencies.size() == values.size())
86 reserveValues = CCurrencyValueMap(currencies, values);
90 nVersion = VERSION_INVALID;
91 reserveValues = CCurrencyValueMap();
93 nVersion &= ~VERSION_MULTIVALUE;
99 READWRITE(currencyID);
100 READWRITE(VARINT(nValue));
101 reserveValues = CCurrencyValueMap(std::vector<uint160>({currencyID}), std::vector<int64_t>({nValue}));
106 if (reserveValues.valueMap.size() == 1)
108 nVersion &= ~VERSION_MULTIVALUE;
109 READWRITE(VARINT(nVersion));
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));
119 nVersion |= VERSION_MULTIVALUE;
120 READWRITE(VARINT(nVersion));
122 for (auto &oneCur : reserveValues.valueMap)
124 currencies.push_back(oneCur.first);
125 values.push_back(oneCur.second);
127 READWRITE(currencies);
133 std::vector<unsigned char> AsVector()
135 return ::AsVector(*this);
138 UniValue ToUniValue() const;
140 uint160 FirstCurrency() const
142 auto it = reserveValues.valueMap.begin();
143 return it == reserveValues.valueMap.end() ? uint160() : it->first;
146 CAmount FirstValue() const
148 auto it = reserveValues.valueMap.begin();
149 return it == reserveValues.valueMap.end() ? 0 : it->second;
152 uint32_t Version() const
159 // we don't support op returns, value must be in native or reserve
160 return nVersion >= VERSION_FIRSTVALID && nVersion <= VERSION_LASTVALID;
164 class CReserveTransfer : public CTokenOutput
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
185 DESTINATION_BYTE_DIVISOR = 128, // destination vector is divided by this and result is multiplied by normal fee and added to transfer fee
187 MIN_SUCCESS_FEE = 20000
190 static const CAmount DEFAULT_PER_STEP_FEE = 10000; // default fee for each step of each transfer (initial mining, transfer, mining on new chain)
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
200 CReserveTransfer() : CTokenOutput(), flags(0), nFees(0) { }
202 CReserveTransfer(const UniValue &uni);
204 CReserveTransfer(const std::vector<unsigned char> &asVector)
207 FromVector(asVector, *this, &success);
210 nVersion = VERSION_INVALID;
214 CReserveTransfer(uint32_t version) : CTokenOutput(version), flags(0), nFees(0) { }
216 CReserveTransfer(uint32_t Flags,
217 const CCurrencyValueMap values,
218 const uint160 &FeeCurrencyID,
220 const uint160 &destCurID,
221 const CTransferDestination &dest,
222 const uint160 &secondCID=uint160(),
223 const uint160 &destinationSystemID=uint160()) :
224 CTokenOutput(values),
226 feeCurrencyID(FeeCurrencyID),
228 destCurrencyID(destCurID),
230 secondReserveID(secondCID),
231 destSystemID(destinationSystemID)
233 if (!secondReserveID.IsNull())
235 flags |= RESERVE_TO_RESERVE;
239 CReserveTransfer(uint32_t Flags,
242 const uint160 &FeeCurrencyID,
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}))),
250 feeCurrencyID(FeeCurrencyID),
252 destCurrencyID(destCurID),
254 secondReserveID(secondCID),
255 destSystemID(destinationSystemID)
257 if (!secondReserveID.IsNull())
259 flags |= RESERVE_TO_RESERVE;
263 ADD_SERIALIZE_METHODS;
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)
275 READWRITE(secondReserveID);
277 if (flags & CROSS_SYSTEM)
279 READWRITE(destSystemID);
283 std::vector<unsigned char> AsVector()
285 return ::AsVector(*this);
288 UniValue ToUniValue() const;
290 CCurrencyValueMap TotalTransferFee() const;
291 CCurrencyValueMap ConversionFee() const;
292 CCurrencyValueMap CalculateFee(uint32_t flags, CAmount transferTotal) const;
293 CCurrencyValueMap TotalCurrencyOut() const;
295 static CAmount CalculateTransferFee(const CTransferDestination &destination, uint32_t flags=VALID);
297 CAmount CalculateTransferFee() const;
299 uint160 GetImportCurrency() const
301 return (flags & IMPORT_TO_SOURCE) ? FirstCurrency() : destCurrencyID;
306 bool isCrossSystemIDNull = destSystemID.IsNull();
307 return CTokenOutput::IsValid() &&
308 reserveValues.valueMap.size() == 1 &&
309 destination.IsValid() &&
310 ((IsCrossSystem() && !isCrossSystemIDNull) || (!IsCrossSystem() && isCrossSystemIDNull));
313 bool IsConversion() const
315 return flags & CONVERT;
318 bool IsRefund() const
320 return flags & REFUND;
323 bool IsCrossSystem() const
325 return flags & CROSS_SYSTEM;
328 uint160 SystemDestination() const
330 return IsCrossSystem() ? destSystemID : ASSETCHAINS_CHAINID;
333 bool IsPreConversion() const
335 return flags & PRECONVERT;
338 uint160 FeeCurrencyID() const
340 return feeCurrencyID;
343 bool IsFeeOutput() const
345 return flags & FEE_OUTPUT;
350 return flags & (BURN_CHANGE_PRICE | BURN_CHANGE_WEIGHT);
353 bool IsBurnChangePrice() const
355 return flags & BURN_CHANGE_PRICE;
358 bool IsBurnChangeWeight() const
360 return flags & BURN_CHANGE_WEIGHT;
365 return flags & MINT_CURRENCY;
368 bool IsReserveToReserve() const
370 return flags & RESERVE_TO_RESERVE;
373 CReserveTransfer GetRefundTransfer() const;
375 static std::string ReserveTransferKeyName()
377 return "vrsc::system.currency.reservetransfer";
380 static uint160 ReserveTransferKey()
382 static uint160 nameSpace;
383 static uint160 reserveTransferKey = CVDXF::GetDataKey(ReserveTransferKeyName(), nameSpace);
384 return reserveTransferKey;
387 static uint160 ReserveTransferSystemKey(const uint160 &systemID)
389 return CCrossChainRPCData::GetConditionID(systemID, ReserveTransferKey());
392 uint160 ReserveTransferSystemSourceKey()
394 return ReserveTransferSystemKey(ASSETCHAINS_CHAINID);
397 bool HasNextLeg() const
399 return destination.HasGatewayLeg();
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;
407 class CReserveDeposit : public CTokenOutput
410 uint160 controllingCurrencyID; // system to export to, which may represent a PBaaS chain or external bridge
412 CReserveDeposit() : CTokenOutput() {}
414 CReserveDeposit(const std::vector<unsigned char> &asVector)
416 FromVector(asVector, *this);
419 CReserveDeposit(const uint160 &controllingID, const CCurrencyValueMap &reserveOut) :
420 CTokenOutput(reserveOut), controllingCurrencyID(controllingID) {}
422 ADD_SERIALIZE_METHODS;
424 template <typename Stream, typename Operation>
425 inline void SerializationOp(Stream& s, Operation ser_action) {
426 READWRITE(*(CTokenOutput *)this);
427 READWRITE(controllingCurrencyID);
430 std::vector<unsigned char> AsVector()
432 return ::AsVector(*this);
435 UniValue ToUniValue() const;
439 return CTokenOutput::IsValid() && !controllingCurrencyID.IsNull();
442 static std::string ReserveDepositKeyName()
444 return "vrsc::system.currency.reservetransfer";
447 static uint160 ReserveDepositKey()
449 static uint160 nameSpace;
450 static uint160 reserveDepositKey = CVDXF::GetDataKey(ReserveDepositKeyName(), nameSpace);
451 return reserveDepositKey;
454 uint160 ReserveDepositIndexKey() const
456 return CCrossChainRPCData::GetConditionID(controllingCurrencyID, ReserveDepositKey());
459 static uint160 ReserveDepositIndexKey(const uint160 ¤cyID)
461 return CCrossChainRPCData::GetConditionID(currencyID, ReserveDepositKey());
465 class CFeePool : public CTokenOutput
470 PER_BLOCK_RATIO = 1000000,
471 MIN_SHARE_SIZE = 10000,
472 FLAG_COINBASE_POOL = 1,
473 FLAG_CURRENCY_NOTARY_POOL = 2
476 uint160 notaryCurrencyID;
477 CFeePool(uint32_t ver=VERSION_CURRENT, uint32_t Flags=FLAG_COINBASE_POOL) : CTokenOutput(ver), flags(FLAG_COINBASE_POOL) {}
479 CFeePool(const std::vector<unsigned char> &asVector)
481 FromVector(asVector, *this);
484 CFeePool(const CTransaction &coinbaseTx);
486 CFeePool(const CCurrencyValueMap &reserveOut, uint32_t Flags=FLAG_COINBASE_POOL, const uint160 ¬aryCID=uint160()) :
487 flags(Flags), notaryCurrencyID(notaryCID), CTokenOutput(reserveOut) {}
489 ADD_SERIALIZE_METHODS;
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)
497 READWRITE(notaryCurrencyID);
501 notaryCurrencyID = uint160();
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);
509 CFeePool OneFeeShare()
512 for (auto &oneCur : reserveValues.valueMap)
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)
517 share = MIN_SHARE_SIZE;
521 retVal.reserveValues.valueMap[oneCur.first] = share;
529 nVersion = VERSION_INVALID;
534 return CTokenOutput::IsValid();
538 class CCrossChainExport;
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
552 FLAG_DEFINITIONIMPORT = 1,
553 FLAG_INITIALLAUNCHIMPORT = 2,
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,
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
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
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) :
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)
598 CCrossChainImport(const std::vector<unsigned char> &asVector)
600 ::FromVector(asVector, *this);
603 CCrossChainImport(const CTransaction &tx, int32_t *pOutNum=nullptr);
604 CCrossChainImport(const CScript &script);
605 CCrossChainImport(const UniValue &obj);
607 ADD_SERIALIZE_METHODS;
609 template <typename Stream, typename Operation>
610 inline void SerializationOp(Stream& s, Operation ser_action) {
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);
624 std::vector<unsigned char> AsVector()
626 return ::AsVector(*this);
631 return nVersion > VERSION_INVALID && nVersion <= VERSION_LAST && !sourceSystemID.IsNull();
634 bool IsSameChain() const
636 return flags & FLAG_SAMECHAIN;
639 void SetSameChain(bool isSameChain)
643 flags |= FLAG_SAMECHAIN;
647 flags &= ~FLAG_SAMECHAIN;
651 void SetDefinitionImport(bool isDefinition)
655 flags |= FLAG_DEFINITIONIMPORT;
659 flags &= ~FLAG_DEFINITIONIMPORT;
663 bool IsDefinitionImport() const
665 return flags & FLAG_DEFINITIONIMPORT;
668 bool IsPostLaunch() const
670 return flags & FLAG_POSTLAUNCH;
673 void SetPostLaunch(bool isPostLaunch=true)
677 flags |= FLAG_POSTLAUNCH;
681 flags &= ~FLAG_POSTLAUNCH;
685 bool IsSourceSystemImport() const
687 return flags & FLAG_SOURCESYSTEM;
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
694 return flags & FLAG_INITIALLAUNCHIMPORT;
697 void SetInitialLaunchImport(bool isInitialLaunchImport=true)
699 if (isInitialLaunchImport)
701 flags |= FLAG_INITIALLAUNCHIMPORT;
705 flags &= ~FLAG_INITIALLAUNCHIMPORT;
709 UniValue ToUniValue() const;
711 static std::string CurrencyImportKeyName()
713 return "vrsc::system.currency.currencyimport";
716 static uint160 CurrencyImportKey()
718 static uint160 nameSpace;
719 static uint160 key = CVDXF::GetDataKey(CurrencyImportKeyName(), nameSpace);
723 static std::string CurrencySystemImportKeyName()
725 return "vrsc::system.currency.systemimport";
728 static uint160 CurrencySystemImportKey()
730 static uint160 nameSpace;
731 static uint160 key = CVDXF::GetDataKey(CurrencySystemImportKeyName(), nameSpace);
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,
740 CCrossChainExport &ccx,
741 CCrossChainImport &sysCCI,
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,
752 CCrossChainExport &ccx,
753 CCrossChainImport &sysCCI,
755 CPBaaSNotarization &importNotarization,
756 int32_t &importNotarizationOut,
757 int32_t &evidenceOutStart,
758 int32_t &evidenceOutEnd,
759 std::vector<CReserveTransfer> &reserveTransfers) const;
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,
766 CCrossChainExport &ccx,
767 CPBaaSNotarization &importNotarization,
768 std::vector<CReserveTransfer> &reserveTransfers,
769 CValidationState &state) const;
770 bool ValidateImport(const CTransaction &tx,
773 CCrossChainExport &ccx,
774 CPBaaSNotarization &importNotarization,
775 std::vector<CReserveTransfer> &reserveTransfers) const;
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
785 MAX_FEE_INPUTS = 50 // when we reach 50 or more inputs, we get maximum fees as an exporter
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,
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
815 uint16_t nVersion; // current version
816 uint16_t flags; // controls serialization and active state
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
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
835 CCrossChainExport() : nVersion(VERSION_INVALID), flags(0), sourceHeightStart(0), sourceHeightEnd(0), numInputs(0), firstInput(0) {}
837 CCrossChainExport(const std::vector<unsigned char> &asVector)
839 FromVector(asVector, *this);
842 CCrossChainExport(const uint160 &SourceSystemID,
843 int32_t SourceHeightStart,
844 int32_t SourceHeightEnd,
845 const uint160 &DestSystemID,
846 const uint160 &DestCurrencyID,
848 const CCurrencyValueMap &values,
849 const CCurrencyValueMap &transferFees,
850 const uint256 &HashReserveTransfers,
851 const CCurrencyValueMap &TotalBurned=CCurrencyValueMap(),
853 const CTransferDestination Exporter=CTransferDestination(),
854 const std::vector<CReserveTransfer> &ReserveTransfers=std::vector<CReserveTransfer>(),
855 int16_t Flags=0, int16_t Version=VERSION_CURRENT) :
858 sourceSystemID(SourceSystemID),
859 sourceHeightStart(SourceHeightStart),
860 sourceHeightEnd(SourceHeightEnd),
861 destSystemID(DestSystemID),
862 destCurrencyID(DestCurrencyID),
864 totalBurned(TotalBurned),
866 totalAmounts(values),
867 totalFees(transferFees),
868 hashReserveTransfers(HashReserveTransfers),
871 reserveTransfers(ReserveTransfers)
874 CCrossChainExport(const CScript &script);
875 CCrossChainExport(const UniValue &obj);
876 CCrossChainExport(const CTransaction &tx, int32_t *pCCXOutputNum=nullptr);
878 ADD_SERIALIZE_METHODS;
880 template <typename Stream, typename Operation>
881 inline void SerializationOp(Stream& s, Operation ser_action) {
884 READWRITE(sourceSystemID);
885 if (!(flags & FLAG_SUPPLEMENTAL))
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);
897 READWRITE(firstInput);
899 READWRITE(reserveTransfers);
902 std::vector<unsigned char> AsVector()
904 return ::AsVector(*this);
907 bool IsSupplemental() const
909 return flags & FLAG_SUPPLEMENTAL;
912 bool HasSupplement() const
914 return flags & FLAG_HASSUPPLEMENT;
919 return nVersion >= VERSION_FIRST &&
920 nVersion <= VERSION_LAST &&
921 !sourceSystemID.IsNull() &&
923 (!destSystemID.IsNull() &&
924 !destCurrencyID.IsNull()));
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);
933 UniValue ToUniValue() const;
935 bool IsSameChain() const
937 return sourceSystemID == ASSETCHAINS_CHAINID;
940 bool IsPrelaunch() const
942 return flags & FLAG_PRELAUNCH;
945 void SetPreLaunch(bool setTrue=true)
949 flags |= FLAG_PRELAUNCH;
953 flags &= ~FLAG_PRELAUNCH;
957 bool IsPostlaunch() const
959 return flags & FLAG_POSTLAUNCH;
962 void SetPostLaunch(bool setTrue=true)
966 flags |= FLAG_POSTLAUNCH;
970 flags &= ~FLAG_POSTLAUNCH;
974 bool IsSystemThreadExport() const
976 return flags & FLAG_SYSTEMTHREAD;
979 void SetSystemThreadExport(bool setTrue=true)
983 flags |= FLAG_SYSTEMTHREAD;
987 flags &= ~FLAG_SYSTEMTHREAD;
991 bool IsChainDefinition() const
993 return flags & FLAG_DEFINITIONEXPORT;
996 void SetChainDefinition(bool setTrue=true)
1000 flags |= FLAG_DEFINITIONEXPORT;
1004 flags &= ~FLAG_DEFINITIONEXPORT;
1008 bool IsClearLaunch() const
1010 return flags & FLAG_CLEARLAUNCH;
1013 void SetClearLaunch(bool setTrue=true)
1017 flags |= FLAG_CLEARLAUNCH;
1021 flags &= ~FLAG_CLEARLAUNCH;
1025 bool GetExportInfo(const CTransaction &exportTx,
1027 int &primaryExportOutNumOut,
1028 int32_t &nextOutput,
1029 CPBaaSNotarization &exportNotarization,
1030 std::vector<CReserveTransfer> &reserveTransfers,
1031 CValidationState &state) const;
1033 bool GetExportInfo(const CTransaction &exportTx,
1035 int &primaryExportOutNumOut,
1036 int32_t &nextOutput,
1037 CPBaaSNotarization &exportNotarization,
1038 std::vector<CReserveTransfer> &reserveTransfers) const;
1040 static std::string CurrencyExportKeyName()
1042 return "vrsc::system.currency.export";
1045 static uint160 CurrencyExportKey()
1047 static uint160 nameSpace;
1048 static uint160 key = CVDXF::GetDataKey(CurrencyExportKeyName(), nameSpace);
1052 static std::string SystemExportKeyName()
1054 return "vrsc::system.currency.systemexport";
1057 static uint160 SystemExportKey()
1059 static uint160 nameSpace;
1060 static uint160 key = CVDXF::GetDataKey(SystemExportKeyName(), nameSpace);
1065 class CCurrencyState
1069 VERSION_INVALID = 0,
1072 VERSION_CURRENT = 1,
1076 FLAG_FRACTIONAL = 1,
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
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
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
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
1105 //std::vector<CAmount> Reserves; // reserve currencies amounts controlled by this fractional chain - only present for reserve currencies, currency IDs are in chain definition
1107 CCurrencyState() : version(VERSION_INVALID), flags(0), initialSupply(0), emitted(0), supply(0) {}
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,
1117 uint16_t Version=VERSION_CURRENT) :
1121 currencies(Currencies),
1124 initialSupply(InitialSupply),
1128 if (weights.size() != currencies.size())
1130 weights = std::vector<int32_t>(currencies.size());
1132 if (reserves.size() != reserves.size())
1134 reserves = std::vector<int64_t>(currencies.size());
1138 CCurrencyState(const std::vector<unsigned char> &asVector)
1140 FromVector(asVector, *this);
1143 CCurrencyState(const UniValue &uni);
1145 ADD_SERIALIZE_METHODS;
1147 template <typename Stream, typename Operation>
1148 inline void SerializationOp(Stream& s, Operation ser_action) {
1151 READWRITE(currencyID);
1152 READWRITE(currencies);
1154 READWRITE(reserves);
1155 READWRITE(VARINT(initialSupply));
1156 READWRITE(VARINT(emitted));
1157 READWRITE(VARINT(supply));
1160 std::vector<unsigned char> AsVector() const
1162 return ::AsVector(*this);
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);
1169 cpp_dec_float_50 GetReserveRatio(int32_t reserveIndex=0) const
1171 return cpp_dec_float_50(std::to_string(weights[reserveIndex])) / cpp_dec_float_50("100000000");
1174 template<typename cpp_dec_float_type>
1175 static bool to_int64(const cpp_dec_float_type &input, int64_t &outval)
1177 std::stringstream ss(input.str(0, std::ios_base::fmtflags::_S_fixed));
1183 catch(const std::exception& e)
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;
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;
1197 std::vector<CAmount> PricesInReserve() const;
1199 // This considers one currency at a time
1200 CAmount ConvertAmounts(CAmount inputReserve, CAmount inputFractional, CCurrencyState &newState, int32_t reserveIndex=0) const;
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;
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;
1214 CAmount ReserveToNative(CAmount reserveAmount, int32_t reserveIndex) const;
1215 CAmount ReserveToNative(const CCurrencyValueMap &reserveAmounts) const;
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> ¤cies, const std::vector<CAmount> &exchangeRates);
1220 static CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<uint160> ¤cies, const std::vector<cpp_dec_float_50> &exchangeRates);
1221 CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<CAmount> &exchangeRates) const;
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;
1230 UniValue ToUniValue() const;
1232 uint160 GetID() const { return currencyID; }
1234 bool IsValid() const
1236 return version >= VERSION_FIRST && version <= VERSION_LAST && !currencyID.IsNull();
1239 bool IsFractional() const
1241 return flags & FLAG_FRACTIONAL;
1244 bool IsRefunding() const
1246 return flags & FLAG_REFUNDING;
1249 bool IsPrelaunch() const
1251 return flags & FLAG_PRELAUNCH;
1254 bool IsLaunchClear() const
1256 return flags & FLAG_LAUNCHCLEAR;
1259 bool IsLaunchConfirmed() const
1261 return flags & FLAG_LAUNCHCONFIRMED;
1264 bool IsLaunchCompleteMarker() const
1266 return flags & FLAG_LAUNCHCOMPLETEMARKER;
1269 // this is only set after the import that completes all pre-conversions
1270 void SetLaunchCompleteMarker(bool newState=true)
1274 flags &= ~FLAG_PRELAUNCH;
1275 flags |= FLAG_LAUNCHCOMPLETEMARKER;
1279 flags &= ~FLAG_LAUNCHCOMPLETEMARKER;
1283 void SetPrelaunch(bool newState=true)
1287 flags |= FLAG_PRELAUNCH;
1291 flags &= ~FLAG_PRELAUNCH;
1295 void SetLaunchClear(bool newState=true)
1299 flags |= FLAG_LAUNCHCLEAR;
1303 flags &= ~FLAG_LAUNCHCLEAR;
1307 void SetLaunchConfirmed(bool newState=true)
1311 flags |= FLAG_LAUNCHCONFIRMED;
1315 flags &= ~FLAG_LAUNCHCONFIRMED;
1319 void SetRefunding(bool newState=true)
1323 flags |= FLAG_REFUNDING;
1327 flags &= ~FLAG_REFUNDING;
1331 std::map<uint160, int32_t> GetReserveMap() const
1333 std::map<uint160, int32_t> retVal;
1334 for (int i = 0; i < currencies.size(); i++)
1336 retVal[currencies[i]] = i;
1342 class CCoinbaseCurrencyState : public CCurrencyState
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
1357 CCoinbaseCurrencyState() : primaryCurrencyOut(0), preConvertedOut(0), primaryCurrencyFees(0), primaryCurrencyConversionFees(0) {}
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),
1376 conversionFees(ConversionFees),
1377 preConvertedOut(PreConvertedOut)
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());
1388 CCoinbaseCurrencyState(const UniValue &uni);
1390 CCoinbaseCurrencyState(const std::vector<unsigned char> asVector)
1392 ::FromVector(asVector, *this);
1395 CCoinbaseCurrencyState(const CTransaction &tx, int *pOutIdx=NULL);
1397 ADD_SERIALIZE_METHODS;
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);
1412 READWRITE(conversionFees);
1415 std::vector<unsigned char> AsVector() const
1417 return ::AsVector(*this);
1420 UniValue ToUniValue() const;
1422 CCoinbaseCurrencyState &UpdateWithEmission(CAmount toEmit);
1424 void ClearForNextBlock()
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());
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);
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();
1455 template <typename NUMBERVECTOR>
1456 NUMBERVECTOR AddVectors(const NUMBERVECTOR &a, const NUMBERVECTOR &b) const
1458 const NUMBERVECTOR *shortVec, *longVec;
1460 if (a.size() <= b.size())
1477 for (int i = 0; i < count; i++)
1479 ret[i] = (*longVec)[i] + (*shortVec)[i];
1481 for (int i = count; i < max; i++)
1483 ret[i] = (*longVec)[i];
1488 inline static int64_t IndexConverterReserveMinimum()
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
1493 return MIN_CONVERTER_RESERVE_TO_INDEX;
1496 inline static int32_t IndexConverterReserveRatio()
1498 // currencies must have at least 10% native reserve to be considered a converter
1499 return MIN_CONVERTER_RATIO_TO_INDEX;
1502 static std::string CurrencyStateKeyName()
1504 return "vrsc::system.currency.state";
1507 static uint160 CurrencyStateKey()
1509 static uint160 nameSpace;
1510 static uint160 currencyStateKey = CVDXF::GetDataKey(CurrencyStateKeyName(), nameSpace);
1511 return currencyStateKey;
1514 static std::string CurrencyConverterKeyName()
1516 return "vrsc::system.currency.converter";
1519 static uint160 CurrencyConverterKey()
1521 static uint160 nameSpace;
1522 static uint160 converterKey = CVDXF::GetDataKey(CurrencyConverterKeyName(), nameSpace);
1523 return converterKey;
1526 inline static uint160 IndexConverterKey(const uint160 ¤cyID)
1528 return CCrossChainRPCData::GetConditionID(currencyID, CurrencyConverterKey());
1532 class CReserveInOuts
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;
1550 class CReserveTransactionDescriptor
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"
1568 enum ESubIndexCodes {
1569 ONE_RESERVE_IDX = 1 // used to create a condition code that indexed reserves of a fractional currency
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
1582 CReserveTransactionDescriptor() :
1585 numBuys(0), // each limit conversion that is valid before a certain block should account for FILL_OR_KILL_FEE
1590 nativeConversionFees(0) {} // non-zero only if there is a conversion, stored vs. calculated to get exact number with each calculated seperately
1592 CReserveTransactionDescriptor(const CTransaction &tx, const CCoinsViewCache &view, int32_t nHeight);
1594 UniValue ToUniValue() const;
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; }
1608 static CAmount CalculateConversionFee(CAmount inputAmount);
1609 static CAmount CalculateConversionFeeNoMin(CAmount inputAmount);
1610 static CAmount CalculateAdditionalConversionFee(CAmount inputAmount);
1612 CAmount TotalNativeOutConverted() const
1614 CAmount nativeOutConverted = 0;
1615 for (auto &one : currencies)
1617 nativeOutConverted += one.second.nativeOutConverted;
1619 return nativeOutConverted;
1622 CCurrencyValueMap ReserveFees(const uint160 &nativeID=uint160()) const;
1623 CAmount NativeFees() const;
1625 CAmount AllFeesAsNative(const CCurrencyState ¤cyState) const;
1626 CAmount AllFeesAsNative(const CCurrencyState ¤cyState, const std::vector<CAmount> &exchangeRates) const;
1627 CCurrencyValueMap AllFeesAsReserve(const CCurrencyState ¤cyState, int defaultReserve=0) const;
1628 CCurrencyValueMap AllFeesAsReserve(const CCurrencyState ¤cyState, const std::vector<CAmount> &exchangeRates, int defaultReserve=0) const;
1630 // does not check for errors
1631 void AddReserveInput(const uint160 ¤cy, CAmount value);
1632 void AddReserveOutput(const uint160 ¤cy, CAmount value);
1633 void AddReserveOutConverted(const uint160 ¤cy, CAmount value);
1634 void AddNativeOutConverted(const uint160 ¤cy, CAmount value);
1635 void AddReserveConversionFees(const uint160 ¤cy, CAmount value);
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;
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;
1651 void AddReserveOutput(const CTokenOutput &ro);
1652 void AddReserveTransfer(const CReserveTransfer &rt);
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);
1666 struct CCcontract_info;
1668 class CValidationState;
1670 typedef std::tuple<uint32_t, CInputDescriptor, CReserveTransfer> ChainTransferData;
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);
1677 #endif // PBAAS_RESERVES_H