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 Version() >= 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 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
185 DESTINATION_BYTE_DIVISOR = 128 // destination vector is divided by this and result is multiplied by normal fee and added to transfer fee
188 static const CAmount DEFAULT_PER_STEP_FEE = 10000; // default fee for each step of each transfer (initial mining, transfer, mining on new chain)
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
197 CReserveTransfer() : CTokenOutput(), flags(0), nFees(0) { }
199 CReserveTransfer(const UniValue &uni);
201 CReserveTransfer(const std::vector<unsigned char> &asVector)
204 FromVector(asVector, *this, &success);
207 nVersion = VERSION_INVALID;
211 CReserveTransfer(uint32_t version) : CTokenOutput(version), flags(0), nFees(0) { }
213 CReserveTransfer(uint32_t Flags,
214 const CCurrencyValueMap values,
215 const uint160 &FeeCurrencyID,
217 const uint160 &destCurID,
218 const CTransferDestination &dest,
219 const uint160 &secondCID=uint160()) :
220 CTokenOutput(values),
222 feeCurrencyID(FeeCurrencyID),
224 destCurrencyID(destCurID),
226 secondReserveID(secondCID)
228 if (!secondReserveID.IsNull())
230 flags |= RESERVE_TO_RESERVE;
234 CReserveTransfer(uint32_t Flags,
237 const uint160 &FeeCurrencyID,
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}))),
244 feeCurrencyID(FeeCurrencyID),
246 destCurrencyID(destCurID),
248 secondReserveID(secondCID)
250 if (!secondReserveID.IsNull())
252 flags |= RESERVE_TO_RESERVE;
256 ADD_SERIALIZE_METHODS;
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)
268 READWRITE(secondReserveID);
272 std::vector<unsigned char> AsVector()
274 return ::AsVector(*this);
277 UniValue ToUniValue() const;
279 CCurrencyValueMap TotalTransferFee() const;
280 CCurrencyValueMap ConversionFee() const;
281 CCurrencyValueMap CalculateFee(uint32_t flags, CAmount transferTotal) const;
282 CCurrencyValueMap TotalCurrencyOut() const;
284 static CAmount CalculateTransferFee(const CTransferDestination &destination, uint32_t flags=VALID);
286 CAmount CalculateTransferFee() const;
288 uint160 GetImportCurrency() const
290 return (flags & IMPORT_TO_SOURCE) ? FirstCurrency() : destCurrencyID;
295 return CTokenOutput::IsValid() && (nFees > 0 || flags & (FEE_OUTPUT | CONVERT)) && reserveValues.valueMap.size() == 1 && destination.destination.size();
298 bool IsConversion() const
300 return flags & CONVERT;
303 bool IsPreConversion() const
305 return flags & PRECONVERT;
308 uint160 FeeCurrencyID() const
310 return feeCurrencyID;
313 bool IsFeeOutput() const
315 return flags & FEE_OUTPUT;
320 return flags & (BURN_CHANGE_PRICE | BURN_CHANGE_WEIGHT);
323 bool IsBurnChangePrice() const
325 return flags & BURN_CHANGE_PRICE;
328 bool IsBurnChangeWeight() const
330 return flags & BURN_CHANGE_WEIGHT;
335 return flags & MINT_CURRENCY;
338 bool IsPreallocate() const
340 return flags & PREALLOCATE;
343 bool IsReserveToReserve() const
345 return flags & RESERVE_TO_RESERVE;
348 CReserveTransfer GetRefundTransfer() const;
350 static std::string ReserveTransferKeyName()
352 return "vrsc::system.currency.reservetransfer";
355 static uint160 ReserveTransferKey()
357 static uint160 nameSpace;
358 static uint160 reserveTransferKey = CVDXF::GetDataKey(ReserveTransferKeyName(), nameSpace);
359 return reserveTransferKey;
362 static uint160 ReserveTransferSystemKey(const uint160 &systemID)
364 return CCrossChainRPCData::GetConditionID(systemID, ReserveTransferKey());
367 uint160 ReserveTransferSystemSourceKey()
369 return ReserveTransferSystemKey(ASSETCHAINS_CHAINID);
372 bool HasNextLeg() const
374 return destination.HasGatewayLeg();
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;
382 class CReserveDeposit : public CTokenOutput
385 uint160 controllingCurrencyID; // system to export to, which may represent a PBaaS chain or external bridge
387 CReserveDeposit() : CTokenOutput() {}
389 CReserveDeposit(const std::vector<unsigned char> &asVector)
391 FromVector(asVector, *this);
394 CReserveDeposit(const uint160 &controllingID, const CCurrencyValueMap &reserveOut) :
395 CTokenOutput(reserveOut), controllingCurrencyID(controllingID) {}
397 ADD_SERIALIZE_METHODS;
399 template <typename Stream, typename Operation>
400 inline void SerializationOp(Stream& s, Operation ser_action) {
401 READWRITE(*(CTokenOutput *)this);
402 READWRITE(controllingCurrencyID);
405 std::vector<unsigned char> AsVector()
407 return ::AsVector(*this);
410 UniValue ToUniValue() const;
414 return CTokenOutput::IsValid() && !controllingCurrencyID.IsNull();
417 static std::string ReserveDepositKeyName()
419 return "vrsc::system.currency.reservetransfer";
422 static uint160 ReserveDepositKey()
424 static uint160 nameSpace;
425 static uint160 reserveDepositKey = CVDXF::GetDataKey(ReserveDepositKeyName(), nameSpace);
426 return reserveDepositKey;
429 uint160 ReserveDepositIndexKey() const
431 return CCrossChainRPCData::GetConditionID(controllingCurrencyID, ReserveDepositKey());
434 static uint160 ReserveDepositIndexKey(const uint160 ¤cyID)
436 return CCrossChainRPCData::GetConditionID(currencyID, ReserveDepositKey());
440 class CFeePool : public CTokenOutput
445 PER_BLOCK_RATIO = 1000000,
446 FLAG_COINBASE_POOL = 1,
447 FLAG_CURRENCY_NOTARY_POOL = 2
450 uint160 notaryCurrencyID;
451 CFeePool(uint32_t ver=VERSION_CURRENT, uint32_t Flags=FLAG_COINBASE_POOL) : CTokenOutput(ver), flags(FLAG_COINBASE_POOL) {}
453 CFeePool(const std::vector<unsigned char> &asVector)
455 FromVector(asVector, *this);
458 CFeePool(const CTransaction &coinbaseTx);
460 CFeePool(const CCurrencyValueMap &reserveOut, uint32_t Flags=FLAG_COINBASE_POOL, const uint160 ¬aryCID=uint160()) :
461 flags(Flags), notaryCurrencyID(notaryCID), CTokenOutput(reserveOut) {}
463 ADD_SERIALIZE_METHODS;
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)
471 READWRITE(notaryCurrencyID);
475 notaryCurrencyID = uint160();
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);
483 CFeePool OneFeeShare()
486 for (auto &oneCur : reserveValues.valueMap)
488 CAmount share = CCurrencyDefinition::CalculateRatioOfValue(oneCur.second, PER_BLOCK_RATIO);
491 retVal.reserveValues.valueMap[oneCur.first] = share;
499 nVersion = VERSION_INVALID;
504 return CTokenOutput::IsValid();
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
514 class CReserveExchange : public CTokenOutput
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
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;
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
541 CReserveExchange(const std::vector<unsigned char> &asVector)
543 FromVector(asVector, *this);
546 CReserveExchange() : CTokenOutput(), nLimit(0), nValidBefore(0) { }
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) {}
551 CReserveExchange(const UniValue &uni);
552 CReserveExchange(const CTransaction &tx);
554 ADD_SERIALIZE_METHODS;
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);
564 std::vector<unsigned char> AsVector()
566 return ::AsVector(*this);
571 // this needs an actual check
572 return CTokenOutput::IsValid();
575 UniValue ToUniValue() const;
577 bool IsExpired(int32_t height)
579 return height >= nValidBefore;
583 class CCrossChainExport;
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
597 FLAG_DEFINITIONIMPORT = 1,
598 FLAG_INITIALLAUNCHIMPORT = 2,
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,
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
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
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) :
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)
643 CCrossChainImport(const std::vector<unsigned char> &asVector)
645 ::FromVector(asVector, *this);
648 CCrossChainImport(const CTransaction &tx, int32_t *pOutNum=nullptr);
649 CCrossChainImport(const CScript &script);
651 ADD_SERIALIZE_METHODS;
653 template <typename Stream, typename Operation>
654 inline void SerializationOp(Stream& s, Operation ser_action) {
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);
668 std::vector<unsigned char> AsVector()
670 return ::AsVector(*this);
675 return nVersion > VERSION_INVALID && nVersion <= VERSION_LAST && !sourceSystemID.IsNull();
678 bool IsSameChain() const
680 return flags & FLAG_SAMECHAIN;
683 void SetSameChain(bool isSameChain)
687 flags |= FLAG_SAMECHAIN;
691 flags &= ~FLAG_SAMECHAIN;
695 void SetDefinitionImport(bool isDefinition)
699 flags |= FLAG_DEFINITIONIMPORT;
703 flags &= ~FLAG_DEFINITIONIMPORT;
707 bool IsDefinitionImport() const
709 return flags & FLAG_DEFINITIONIMPORT;
712 bool IsPostLaunch() const
714 return flags & FLAG_POSTLAUNCH;
717 bool IsSourceSystemImport() const
719 return flags & FLAG_SOURCESYSTEM;
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
726 return flags & FLAG_INITIALLAUNCHIMPORT;
729 void SetInitialLaunchImport(bool isInitialLaunchImport=true)
731 if (isInitialLaunchImport)
733 flags |= FLAG_INITIALLAUNCHIMPORT;
737 flags &= ~FLAG_INITIALLAUNCHIMPORT;
741 UniValue ToUniValue() const;
743 static std::string CurrencyImportKeyName()
745 return "vrsc::system.currency.currencyimport";
748 static uint160 CurrencyImportKey()
750 static uint160 nameSpace;
751 static uint160 key = CVDXF::GetDataKey(CurrencyImportKeyName(), nameSpace);
755 static std::string CurrencySystemImportKeyName()
757 return "vrsc::system.currency.systemimport";
760 static uint160 CurrencySystemImportKey()
762 static uint160 nameSpace;
763 static uint160 key = CVDXF::GetDataKey(CurrencySystemImportKeyName(), nameSpace);
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,
771 CCrossChainExport &ccx,
772 CCrossChainImport &sysCCI,
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,
782 CCrossChainExport &ccx,
783 CCrossChainImport &sysCCI,
785 CPBaaSNotarization &importNotarization,
786 int32_t &importNotarizationOut,
787 int32_t &evidenceOutStart,
788 int32_t &evidenceOutEnd,
789 std::vector<CReserveTransfer> &reserveTransfers) const;
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,
796 CCrossChainExport &ccx,
797 CPBaaSNotarization &importNotarization,
798 std::vector<CReserveTransfer> &reserveTransfers,
799 CValidationState &state) const;
800 bool ValidateImport(const CTransaction &tx,
803 CCrossChainExport &ccx,
804 CPBaaSNotarization &importNotarization,
805 std::vector<CReserveTransfer> &reserveTransfers) const;
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
815 MAX_FEE_INPUTS = 50 // when we reach 50 or more inputs, we get maximum fees as an exporter
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,
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
843 uint16_t nVersion; // current version
844 uint16_t flags; // controls serialization and active state
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
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
862 CCrossChainExport() : nVersion(VERSION_INVALID), flags(0), sourceHeightStart(0), sourceHeightEnd(0), numInputs(0), firstInput(0) {}
864 CCrossChainExport(const std::vector<unsigned char> &asVector)
866 FromVector(asVector, *this);
869 CCrossChainExport(const uint160 &SourceSystemID,
870 int32_t SourceHeightStart,
871 int32_t SourceHeightEnd,
872 const uint160 &DestSystemID,
873 const uint160 &DestCurrencyID,
875 const CCurrencyValueMap &values,
876 const CCurrencyValueMap &transferFees,
877 const uint256 &HashReserveTransfers,
879 const CTransferDestination Exporter=CTransferDestination(),
880 const std::vector<CReserveTransfer> &ReserveTransfers=std::vector<CReserveTransfer>(),
881 int16_t Flags=0, int16_t Version=VERSION_CURRENT) :
884 sourceSystemID(SourceSystemID),
885 sourceHeightStart(SourceHeightStart),
886 sourceHeightEnd(SourceHeightEnd),
887 destSystemID(DestSystemID),
888 destCurrencyID(DestCurrencyID),
891 totalAmounts(values),
892 totalFees(transferFees),
893 hashReserveTransfers(HashReserveTransfers),
895 reserveTransfers(ReserveTransfers)
898 CCrossChainExport(const CScript &script);
899 CCrossChainExport(const CTransaction &tx, int32_t *pCCXOutputNum=nullptr);
901 ADD_SERIALIZE_METHODS;
903 template <typename Stream, typename Operation>
904 inline void SerializationOp(Stream& s, Operation ser_action) {
907 READWRITE(sourceSystemID);
908 if (!(flags & FLAG_SUPPLEMENTAL))
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);
919 READWRITE(firstInput);
921 READWRITE(reserveTransfers);
924 std::vector<unsigned char> AsVector()
926 return ::AsVector(*this);
929 bool IsSupplemental() const
931 return flags & FLAG_SUPPLEMENTAL;
934 bool HasSupplement() const
936 return flags & FLAG_HASSUPPLEMENT;
941 return nVersion >= VERSION_FIRST &&
942 nVersion <= VERSION_LAST &&
943 !sourceSystemID.IsNull() &&
945 (!destSystemID.IsNull() &&
946 !destCurrencyID.IsNull()));
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);
955 UniValue ToUniValue() const;
957 bool IsSameChain() const
959 return sourceSystemID == ASSETCHAINS_CHAINID;
962 bool IsPrelaunch() const
964 return flags & FLAG_PRELAUNCH;
967 void SetPreLaunch(bool setTrue=true)
971 flags |= FLAG_PRELAUNCH;
975 flags &= ~FLAG_PRELAUNCH;
979 bool IsChainDefinition() const
981 return flags & FLAG_DEFINITIONEXPORT;
984 void SetChainDefinition(bool setTrue=true)
988 flags |= FLAG_DEFINITIONEXPORT;
992 flags &= ~FLAG_DEFINITIONEXPORT;
996 bool IsClearLaunch() const
998 return flags & FLAG_CLEARLAUNCH;
1001 void SetClearLaunch(bool setTrue=true)
1005 flags |= FLAG_CLEARLAUNCH;
1009 flags &= ~FLAG_CLEARLAUNCH;
1013 bool GetExportInfo(const CTransaction &exportTx,
1015 int32_t &nextOutput,
1016 CPBaaSNotarization &exportNotarization,
1017 std::vector<CReserveTransfer> &reserveTransfers,
1018 CValidationState &state) const;
1020 bool GetExportInfo(const CTransaction &exportTx,
1022 int32_t &nextOutput,
1023 CPBaaSNotarization &exportNotarization,
1024 std::vector<CReserveTransfer> &reserveTransfers) const;
1026 static std::string CurrencyExportKeyName()
1028 return "vrsc::system.currency.export";
1031 static uint160 CurrencyExportKey()
1033 static uint160 nameSpace;
1034 static uint160 key = CVDXF::GetDataKey(CurrencyExportKeyName(), nameSpace);
1038 static std::string SystemExportKeyName()
1040 return "vrsc::system.currency.systemexport";
1043 static uint160 SystemExportKey()
1045 static uint160 nameSpace;
1046 static uint160 key = CVDXF::GetDataKey(SystemExportKeyName(), nameSpace);
1051 class CCurrencyState
1055 VERSION_INVALID = 0,
1058 VERSION_CURRENT = 1,
1062 FLAG_FRACTIONAL = 1,
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
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
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
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
1091 //std::vector<CAmount> Reserves; // reserve currencies amounts controlled by this fractional chain - only present for reserve currencies, currency IDs are in chain definition
1093 CCurrencyState() : version(VERSION_INVALID), flags(0), initialSupply(0), emitted(0), supply(0) {}
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,
1103 uint16_t Version=VERSION_CURRENT) :
1107 currencies(Currencies),
1110 initialSupply(InitialSupply),
1115 CCurrencyState(const std::vector<unsigned char> &asVector)
1117 FromVector(asVector, *this);
1120 CCurrencyState(const UniValue &uni);
1122 ADD_SERIALIZE_METHODS;
1124 template <typename Stream, typename Operation>
1125 inline void SerializationOp(Stream& s, Operation ser_action) {
1128 READWRITE(currencyID);
1129 READWRITE(currencies);
1131 READWRITE(reserves);
1132 READWRITE(VARINT(initialSupply));
1133 READWRITE(VARINT(emitted));
1134 READWRITE(VARINT(supply));
1137 std::vector<unsigned char> AsVector() const
1139 return ::AsVector(*this);
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);
1146 cpp_dec_float_50 GetReserveRatio(int32_t reserveIndex=0) const
1148 return cpp_dec_float_50(std::to_string(weights[reserveIndex])) / cpp_dec_float_50("100000000");
1151 template<typename cpp_dec_float_type>
1152 static bool to_int64(const cpp_dec_float_type &input, int64_t &outval)
1154 std::stringstream ss(input.str(0, std::ios_base::fmtflags::_S_fixed));
1160 catch(const std::exception& e)
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;
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;
1174 std::vector<CAmount> PricesInReserve() const;
1176 // This considers one currency at a time
1177 CAmount ConvertAmounts(CAmount inputReserve, CAmount inputFractional, CCurrencyState &newState, int32_t reserveIndex=0) const;
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;
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;
1191 CAmount ReserveToNative(CAmount reserveAmount, int32_t reserveIndex) const;
1192 CAmount ReserveToNative(const CCurrencyValueMap &reserveAmounts) const;
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> ¤cies, const std::vector<CAmount> &exchangeRates);
1197 static CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<uint160> ¤cies, const std::vector<cpp_dec_float_50> &exchangeRates);
1198 CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<CAmount> &exchangeRates) const;
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;
1207 UniValue ToUniValue() const;
1209 uint160 GetID() const { return currencyID; }
1211 bool IsValid() const
1213 return version >= VERSION_FIRST && version <= VERSION_LAST && !currencyID.IsNull();
1216 bool IsFractional() const
1218 return flags & FLAG_FRACTIONAL;
1221 bool IsRefunding() const
1223 return flags & FLAG_REFUNDING;
1226 bool IsPrelaunch() const
1228 return flags & FLAG_PRELAUNCH;
1231 bool IsLaunchClear() const
1233 return flags & FLAG_LAUNCHCLEAR;
1236 bool IsLaunchConfirmed() const
1238 return flags & FLAG_LAUNCHCONFIRMED;
1241 bool IsLaunchCompleteMarker() const
1243 return flags & FLAG_LAUNCHCOMPLETEMARKER;
1246 // this is only set after the import that completes all pre-conversions
1247 void SetLaunchCompleteMarker(bool newState=true)
1251 flags &= ~FLAG_PRELAUNCH;
1252 flags |= FLAG_LAUNCHCOMPLETEMARKER;
1256 flags &= ~FLAG_LAUNCHCOMPLETEMARKER;
1260 void SetPrelaunch(bool newState=true)
1264 flags |= FLAG_PRELAUNCH;
1268 flags &= ~FLAG_PRELAUNCH;
1272 void SetLaunchClear(bool newState=true)
1276 flags |= FLAG_LAUNCHCLEAR;
1280 flags &= ~FLAG_LAUNCHCLEAR;
1284 void SetLaunchConfirmed(bool newState=true)
1288 flags |= FLAG_LAUNCHCONFIRMED;
1292 flags &= ~FLAG_LAUNCHCONFIRMED;
1296 void SetRefunding(bool newState=true)
1300 flags |= FLAG_REFUNDING;
1304 flags &= ~FLAG_REFUNDING;
1308 std::map<uint160, int32_t> GetReserveMap() const
1310 std::map<uint160, int32_t> retVal;
1311 for (int i = 0; i < currencies.size(); i++)
1313 retVal[currencies[i]] = i;
1319 class CCoinbaseCurrencyState : public CCurrencyState
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
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
1334 CCoinbaseCurrencyState() : nativeOut(0), preConvertedOut(0), nativeFees(0), nativeConversionFees(0) {}
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),
1349 reserveOut(ReserveOut),
1350 conversionPrice(ConversionPrice),
1351 viaConversionPrice(ViaConversionPrice),
1353 conversionFees(ConversionFees),
1354 preConvertedOut(PreConvertedOut)
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());
1365 CCoinbaseCurrencyState(const UniValue &uni);
1367 CCoinbaseCurrencyState(const std::vector<unsigned char> asVector)
1369 ::FromVector(asVector, *this);
1372 CCoinbaseCurrencyState(const CTransaction &tx, int *pOutIdx=NULL);
1374 ADD_SERIALIZE_METHODS;
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);
1389 READWRITE(conversionFees);
1392 std::vector<unsigned char> AsVector() const
1394 return ::AsVector(*this);
1397 UniValue ToUniValue() const;
1399 void ClearForNextBlock()
1403 preConvertedOut = 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());
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()
1417 // if this is the launch clear notarization, we have only the starting condition
1418 // and we don't revert anything
1419 if (IsLaunchClear())
1421 SetLaunchClear(false);
1425 // add reserves out to reserves
1426 auto currencyMap = GetReserveMap();
1428 // revert changes in reserves and supply to pre conversion state, add reserve outs and subtract reserve ins
1429 for (auto &oneCur : currencyMap)
1431 reserves[oneCur.second] += (reserveOut[oneCur.second] - reserveIn[oneCur.second]);
1432 supply += nativeIn[oneCur.second];
1434 supply -= ((nativeOut + emitted) - preConvertedOut);
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;
1447 template <typename NUMBERVECTOR>
1448 NUMBERVECTOR AddVectors(const NUMBERVECTOR &a, const NUMBERVECTOR &b) const
1450 const NUMBERVECTOR *shortVec, *longVec;
1452 if (a.size() <= b.size())
1469 for (int i = 0; i < count; i++)
1471 ret[i] = (*longVec)[i] + (*shortVec)[i];
1473 for (int i = count; i < max; i++)
1475 ret[i] = (*longVec)[i];
1480 inline static int64_t IndexConverterReserveMinimum()
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
1485 return MIN_CONVERTER_RESERVE_TO_INDEX;
1488 inline static int32_t IndexConverterReserveRatio()
1490 // currencies must have at least 10% native reserve to be considered a converter
1491 return MIN_CONVERTER_RATIO_TO_INDEX;
1494 static std::string CurrencyStateKeyName()
1496 return "vrsc::system.currency.state";
1499 static uint160 CurrencyStateKey()
1501 static uint160 nameSpace;
1502 static uint160 currencyStateKey = CVDXF::GetDataKey(CurrencyStateKeyName(), nameSpace);
1503 return currencyStateKey;
1506 static std::string CurrencyConverterKeyName()
1508 return "vrsc::system.currency.converter";
1511 static uint160 CurrencyConverterKey()
1513 static uint160 nameSpace;
1514 static uint160 converterKey = CVDXF::GetDataKey(CurrencyConverterKeyName(), nameSpace);
1515 return converterKey;
1518 inline static uint160 IndexConverterKey(const uint160 ¤cyID)
1520 return CCrossChainRPCData::GetConditionID(currencyID, CurrencyConverterKey());
1524 class CReserveInOuts
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) {}
1541 class CReserveTransactionDescriptor
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"
1559 enum ESubIndexCodes {
1560 ONE_RESERVE_IDX = 1 // used to create a condition code that indexed reserves of a fractional currency
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
1574 CReserveTransactionDescriptor() :
1577 numBuys(0), // each limit conversion that is valid before a certain block should account for FILL_OR_KILL_FEE
1582 nativeConversionFees(0) {} // non-zero only if there is a conversion, stored vs. calculated to get exact number with each calculated seperately
1584 CReserveTransactionDescriptor(const CTransaction &tx, const CCoinsViewCache &view, int32_t nHeight);
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; }
1598 static CAmount CalculateConversionFee(CAmount inputAmount);
1599 static CAmount CalculateConversionFeeNoMin(CAmount inputAmount);
1600 static CAmount CalculateAdditionalConversionFee(CAmount inputAmount);
1602 CAmount TotalNativeOutConverted() const
1604 CAmount nativeOutConverted = 0;
1605 for (auto &one : currencies)
1607 nativeOutConverted += one.second.nativeOutConverted;
1609 return nativeOutConverted;
1612 CCurrencyValueMap ReserveFees(const uint160 &nativeID=uint160()) const;
1613 CAmount NativeFees() const;
1615 CAmount AllFeesAsNative(const CCurrencyState ¤cyState) const;
1616 CAmount AllFeesAsNative(const CCurrencyState ¤cyState, const std::vector<CAmount> &exchangeRates) const;
1617 CCurrencyValueMap AllFeesAsReserve(const CCurrencyState ¤cyState, int defaultReserve=0) const;
1618 CCurrencyValueMap AllFeesAsReserve(const CCurrencyState ¤cyState, const std::vector<CAmount> &exchangeRates, int defaultReserve=0) const;
1620 // does not check for errors
1621 void AddReserveInput(const uint160 ¤cy, CAmount value);
1622 void AddReserveOutput(const uint160 ¤cy, CAmount value);
1623 void AddReserveOutConverted(const uint160 ¤cy, CAmount value);
1624 void AddNativeOutConverted(const uint160 ¤cy, CAmount value);
1625 void AddReserveConversionFees(const uint160 ¤cy, CAmount value);
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;
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;
1641 void AddReserveOutput(const CTokenOutput &ro);
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);
1646 void AddReserveTransfer(const CReserveTransfer &rt);
1648 CMutableTransaction &AddConversionInOuts(CMutableTransaction &conversionTx,
1649 std::vector<CInputDescriptor> &conversionInputs,
1650 const CCurrencyValueMap &exchangeRates=CCurrencyValueMap(),
1651 const CCurrencyState *pCurrencyState=nullptr) const;
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);
1665 struct CCcontract_info;
1667 class CValidationState;
1669 typedef std::tuple<uint32_t, CInputDescriptor, CReserveTransfer> ChainTransferData;
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);
1675 #endif // PBAAS_RESERVES_H