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
16 #include <univalue/include/univalue.h>
17 #include "pbaas/crosschainrpc.h"
18 #include "arith_uint256.h"
19 #include <boost/multiprecision/cpp_dec_float.hpp>
20 #include "librustzcash.h"
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;
39 // reserve output is a special kind of token output that does not have to carry it's identifier, as it
40 // is always assumed to be the reserve currency of the current chain.
48 VERSION_FIRSTVALID = 1,
49 VERSION_LASTVALID = 1,
52 static std::vector<uint160> *reserveIDs;
54 uint32_t nVersion; // information about this currency
55 uint160 currencyID; // currency ID
56 CAmount nValue; // amount of input reserve coins this UTXO represents before any conversion
58 CTokenOutput(const std::vector<unsigned char> &asVector)
60 FromVector(asVector, *this);
63 CTokenOutput(const UniValue &obj);
65 CTokenOutput() : nVersion(VERSION_CURRENT), nValue(0) { }
67 CTokenOutput(const uint160 &curID, CAmount value) : nVersion(VERSION_CURRENT), currencyID(curID), nValue(value) { }
69 ADD_SERIALIZE_METHODS;
71 template <typename Stream, typename Operation>
72 inline void SerializationOp(Stream& s, Operation ser_action) {
73 READWRITE(VARINT(nVersion));
74 READWRITE(currencyID);
75 READWRITE(VARINT(nValue));
78 std::vector<unsigned char> AsVector()
80 return ::AsVector(*this);
83 UniValue ToUniValue() const;
87 // we don't support op returns, value must be in native or reserve
88 return nVersion >= VERSION_FIRSTVALID && nVersion <= VERSION_LASTVALID;
92 class CReserveTransfer : public CTokenOutput
100 FEE_OUTPUT = 8, // one per import, amount must match total percentage of fees for exporter, no pre-convert allowed
101 SEND_BACK = 0x10, // fee is sent back immediately to destination on exporting chain
102 MINT_CURRENCY = 0x20, // set when this output is being minted on import
103 PREALLOCATE = 0x40 // combined with minting for pre-allocation of currency
108 DESTINATION_BYTE_DIVISOR = 128 // destination vector is divided by this and result is multiplied by normal fee and added to transfer fee
111 static const CAmount DEFAULT_PER_STEP_FEE = 10000; // default fee for each step of each transfer (initial mining, transfer, mining on new chain)
113 uint32_t flags; // type of transfer and options
114 CAmount nFees; // cross-chain network fees only, separated out to enable market conversions, conversion fees are additional
115 uint160 destCurrencyID; // system to export to, which may represent a PBaaS chain or external bridge
116 CTransferDestination destination; // system specific address to send funds to on the target chain
118 CReserveTransfer(const std::vector<unsigned char> &asVector)
120 FromVector(asVector, *this);
123 CReserveTransfer() : CTokenOutput(), flags(0), nFees(0) { }
125 CReserveTransfer(uint32_t Flags, const uint160 &cID, CAmount value, CAmount fees, const uint160 &destCurID, const CTransferDestination &dest) :
126 CTokenOutput(cID, value), flags(Flags), nFees(fees), destCurrencyID(destCurID), destination(dest) { }
128 ADD_SERIALIZE_METHODS;
130 template <typename Stream, typename Operation>
131 inline void SerializationOp(Stream& s, Operation ser_action) {
132 READWRITE(*(CTokenOutput *)this);
133 READWRITE(VARINT(flags));
134 READWRITE(VARINT(nFees));
135 READWRITE(destCurrencyID);
136 READWRITE(destination);
139 std::vector<unsigned char> AsVector()
141 return ::AsVector(*this);
144 UniValue ToUniValue() const;
146 CCurrencyValueMap CalculateFee(uint32_t flags, CAmount transferTotal) const;
148 static CAmount CalculateTransferFee(const CTransferDestination &destination);
150 CAmount CalculateTransferFee() const;
154 return CTokenOutput::IsValid() && (nFees > 0 || flags & FEE_OUTPUT) && destination.destination.size();
158 // convert from $VRSC to fractional reserve coin or vice versa. coinID determines which
159 // in either direction, this is burned in the block. if burned, the block must contain less than a
160 // maximum reasonable number of exchange outputs, which must be sorted, hashed, and used to validate
161 // the outputs that must match exactly on any transaction spending the output. since fees are not
162 // included in outputs, it is assumed that a miner will spend the output in the same block to recover
164 class CReserveExchange : public CTokenOutput
171 TO_RESERVE = 0x80000, // from fractional currency to reserve, default is reserve to fractional
172 LIMIT = 0x100000, // observe the limit when converting
173 FILL_OR_KILL = 0x200000, // if not filled before nValidBefore but before expiry, no execution, mined with fee, output pass through
174 ALL_OR_NONE = 0x400000, // will not execute partial order
175 SEND_OUTPUT = 0x800000 // send the output of this exchange to the target chain, only valid if output is reserve
178 // 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
179 // 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
180 // it is deducted in the success case from the success fee, so there is no fee beyond the success fee paid
181 static const CAmount SUCCESS_FEE = 25000;
182 static const CAmount MIN_SUCCESS_FEE = 50000;
183 static const CAmount MIN_PARTIAL = 10000000; // making partial fill minimum the number at which minimum fee meets standard percent fee,
184 static const CAmount MIN_NET_CONVERSION = 10000000; // minimum conversion for input
185 static const CAmount FILL_OR_KILL_FEE = 10000;
187 uint32_t flags; // type of transfer and options
188 CAmount nLimit; // limit price to sell or buy currency
189 uint32_t nValidBefore; // if not filled on or after this block, can mine tx, but is spendable to refund input
191 CReserveExchange(const std::vector<unsigned char> &asVector)
193 FromVector(asVector, *this);
196 CReserveExchange() : CTokenOutput(), nLimit(0), nValidBefore(0) { }
198 CReserveExchange(uint32_t Flags, const uint160 &cID, CAmount amountIn, CAmount Limit=0, uint32_t ValidBefore=0) :
199 CTokenOutput(cID, amountIn), flags(Flags), nLimit(Limit), nValidBefore(ValidBefore) {}
201 CReserveExchange(const UniValue &uni);
202 CReserveExchange(const CTransaction &tx);
204 ADD_SERIALIZE_METHODS;
206 template <typename Stream, typename Operation>
207 inline void SerializationOp(Stream& s, Operation ser_action) {
208 READWRITE(*(CTokenOutput *)this);
209 READWRITE(VARINT(flags));
210 READWRITE(VARINT(nLimit));
211 READWRITE(nValidBefore);
214 std::vector<unsigned char> AsVector()
216 return ::AsVector(*this);
221 // this needs an actual check
222 return CTokenOutput::IsValid();
225 UniValue ToUniValue() const;
227 bool IsExpired(int32_t height)
229 return height >= nValidBefore;
233 // import transactions and tokens from another chain
234 // this represents the chain, the currencies, and the amounts of each
235 // it may also import IDs from the chain on which they were defined
236 class CCrossChainImport
239 static const uint32_t VERSION_INVALID = 0;
240 static const uint32_t VERSION_CURRENT = 1;
241 static const uint32_t VERSION_LAST = 1;
243 uint160 systemID; // the blockchain or currency system source from where these transactions come
244 CCurrencyValueMap importValue; // total amount of coins imported from chain with or without conversion, including fees
245 CCurrencyValueMap totalReserveOutMap; // all non-native currencies being held in this thread and released on import
247 CCrossChainImport() : nVersion(VERSION_INVALID) {}
248 CCrossChainImport(const uint160 &cID, const CCurrencyValueMap &ImportValue, const CCurrencyValueMap &InitialReserveOutput=CCurrencyValueMap()) :
249 nVersion(VERSION_CURRENT), systemID(cID), importValue(ImportValue), totalReserveOutMap(InitialReserveOutput) { }
251 CCrossChainImport(const std::vector<unsigned char> &asVector)
253 ::FromVector(asVector, *this);
256 CCrossChainImport(const CTransaction &tx, int32_t *pOutNum=nullptr);
258 ADD_SERIALIZE_METHODS;
260 template <typename Stream, typename Operation>
261 inline void SerializationOp(Stream& s, Operation ser_action) {
264 READWRITE(importValue);
265 READWRITE(totalReserveOutMap);
268 std::vector<unsigned char> AsVector()
270 return ::AsVector(*this);
275 return nVersion > VERSION_INVALID && nVersion <= VERSION_LAST && !systemID.IsNull();
278 UniValue ToUniValue() const;
281 // describes an entire output that will be realized on a target chain. target is specified as part of an aggregated transaction.
282 class CCrossChainExport
285 static const int MIN_BLOCKS = 10;
286 static const int MIN_INPUTS = 10;
287 static const int MAX_EXPORT_INPUTS = 50;
288 static const uint32_t VERSION_INVALID = 0;
289 static const uint32_t VERSION_CURRENT = 1;
290 static const uint32_t VERSION_LAST = 1;
292 uint160 systemID; // target blockchain or currency system ID
293 int32_t numInputs; // number of inputs aggregated to calculate the fee percentage
294 CCurrencyValueMap totalAmounts; // total amount of inputs of each currency, including fees
295 CCurrencyValueMap totalFees; // total amount of fees of each currency to split between miner on exporting chain and importing chain
297 CCrossChainExport() : nVersion(VERSION_INVALID), numInputs(0) {}
299 CCrossChainExport(const std::vector<unsigned char> &asVector)
301 FromVector(asVector, *this);
304 CCrossChainExport(uint160 SystemID, int32_t numin, const CCurrencyValueMap &values, const CCurrencyValueMap &fees) :
305 nVersion(VERSION_CURRENT), systemID(SystemID), numInputs(numin), totalAmounts(values), totalFees(fees) {}
307 CCrossChainExport(const CTransaction &tx, int32_t *pCCXOutputNum=nullptr);
309 ADD_SERIALIZE_METHODS;
311 template <typename Stream, typename Operation>
312 inline void SerializationOp(Stream& s, Operation ser_action) {
315 READWRITE(numInputs);
316 READWRITE(totalAmounts);
317 READWRITE(totalFees);
320 std::vector<unsigned char> AsVector()
322 return ::AsVector(*this);
327 return nVersion > VERSION_INVALID &&
328 nVersion <= VERSION_LAST &&
332 static CCurrencyValueMap CalculateExportFee(const CCurrencyValueMap &fees, int numIn);
333 CCurrencyValueMap CalculateExportFee() const;
335 CCurrencyValueMap CalculateImportFee() const;
337 UniValue ToUniValue() const;
350 MIN_RESERVE_RATIO = 1000000, // we will not start a chain with less than 1% reserve ratio in any single currency
351 MAX_RESERVE_RATIO = 100000000, // we will not start a chain with greater than 100% reserve ratio
352 SHUTDOWN_RESERVE_RATIO = 500000, // if we hit this reserve ratio in any currency, initiate chain shutdown
353 CONVERSION_TX_SIZE_MIN = 1024, // minimum size accounted for in a conversion transaction
354 MAX_RESERVE_CURRENCIES = 10 // maximum number of reserve currencies that can underly a fractional reserve
357 uint32_t flags; // currency flags (valid, reserve currency, etc.)
359 std::vector<uint160> currencies; // the ID in uin160 form (maps to CIdentityID) if each currency in the reserve
360 std::vector<int32_t> weights; // current, individual weights for all currencies to use in calculations
361 std::vector<int64_t> reserves; // total amount of reserves in each currency
363 int64_t initialSupply; // initial premine + pre-converted coins
364 int64_t emitted; // emitted coins reduce the reserve ratio and are used to calculate current ratio
365 CAmount supply; // current supply: total of initial, all emitted, and all purchased coins
367 //std::vector<CAmount> Reserves; // reserve currencies amounts controlled by this fractional chain - only present for reserve currencies, currency IDs are in chain definition
369 CCurrencyState() : flags(0), initialSupply(0), emitted(0), supply(0) {}
371 CCurrencyState(const std::vector<uint160> &Currencies,
372 const std::vector<int32_t> &Weights,
373 const std::vector<int64_t> &Reserves,
374 CAmount InitialSupply,
377 uint32_t Flags=FLAG_VALID) :
379 currencies(Currencies),
382 initialSupply(InitialSupply),
387 CCurrencyState(const std::vector<unsigned char> &asVector)
389 FromVector(asVector, *this);
392 CCurrencyState(const UniValue &uni);
394 ADD_SERIALIZE_METHODS;
396 template <typename Stream, typename Operation>
397 inline void SerializationOp(Stream& s, Operation ser_action) {
399 READWRITE(currencies);
402 READWRITE(VARINT(initialSupply));
403 READWRITE(VARINT(emitted));
404 READWRITE(VARINT(supply));
407 std::vector<unsigned char> AsVector() const
409 return ::AsVector(*this);
412 // this should be done no more than once to prepare a currency state to be moved to the next state
413 // emission occurs for a block before any conversion or exchange and that impact on the currency state is calculated
414 CCurrencyState &UpdateWithEmission(CAmount emitted);
416 cpp_dec_float_50 GetReserveRatio(int32_t reserveIndex=0) const
418 return cpp_dec_float_50(std::to_string(weights[reserveIndex])) / cpp_dec_float_50("100000000");
421 template<typename cpp_dec_float_type>
422 static bool to_int64(const cpp_dec_float_type &input, int64_t &outval)
424 std::stringstream ss(input.str(0, std::ios_base::fmtflags::_S_fixed));
430 catch(const std::exception& e)
436 // in a fractional reserve with no reserve or supply, this will always return
437 // a price of the reciprocal (1/x) of the fractional reserve ratio of the indexed reserve,
438 // which will always be >= 1
439 CAmount PriceInReserve(int32_t reserveIndex=0, bool roundUp=false) const;
441 // return the current price of the fractional reserve in the reserve currency in Satoshis
442 cpp_dec_float_50 PriceInReserveDecFloat50(int32_t reserveIndex=0) const;
444 std::vector<CAmount> PricesInReserve() const;
446 // This considers one currency at a time
447 CAmount ConvertAmounts(CAmount inputReserve, CAmount inputFractional, CCurrencyState &newState, int32_t reserveIndex=0) const;
449 // convert amounts for multi-reserve fractional reserve currencies
450 // one entry in the vector for each currency in and one fractional input for each
451 // currency expected as output
452 std::vector<CAmount> ConvertAmounts(const std::vector<CAmount> &inputReserve, const std::vector<CAmount> &inputFractional, CCurrencyState &newState) const;
454 CAmount CalculateConversionFee(CAmount inputAmount, bool convertToNative = false, int32_t reserveIndex=0) const;
455 CAmount ReserveFeeToNative(CAmount inputAmount, CAmount outputAmount, int32_t reserveIndex=0) const;
457 CAmount ReserveToNative(CAmount reserveAmount, int32_t reserveIndex) const;
458 CAmount ReserveToNative(const CCurrencyValueMap &reserveAmounts) const;
460 static CAmount ReserveToNativeRaw(CAmount reserveAmount, const cpp_dec_float_50 &exchangeRate);
461 static CAmount ReserveToNativeRaw(CAmount reserveAmount, CAmount exchangeRate);
462 static CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<uint160> ¤cies, const std::vector<CAmount> &exchangeRates);
463 static CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<uint160> ¤cies, const std::vector<cpp_dec_float_50> &exchangeRates);
464 CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<CAmount> &exchangeRates) const;
466 const CCurrencyValueMap &NativeToReserve(std::vector<CAmount> nativeAmount, int32_t reserveIndex=0) const;
467 CAmount NativeToReserve(CAmount nativeAmount, int32_t reserveIndex=0) const;
468 static CAmount NativeToReserveRaw(CAmount nativeAmount, const cpp_dec_float_50 &exchangeRate);
469 static CAmount NativeToReserveRaw(CAmount nativeAmount, CAmount exchangeRate);
470 CCurrencyValueMap NativeToReserveRaw(const std::vector<CAmount> &, const std::vector<CAmount> &exchangeRates) const;
471 CCurrencyValueMap NativeToReserveRaw(const std::vector<CAmount> &, const std::vector<cpp_dec_float_50> &exchangeRates) const;
473 UniValue ToUniValue() const;
477 return flags & FLAG_VALID;
480 bool IsFractional() const
482 return flags & FLAG_FRACTIONAL;
485 bool IsRefunding() const
487 return flags & FLAG_REFUNDING;
490 bool IsPrelaunch() const
492 return flags & FLAG_PRELAUNCH;
495 void SetPrelaunch(bool newState=true)
499 flags |= FLAG_PRELAUNCH;
503 flags &= ~FLAG_PRELAUNCH;
507 void SetRefunding(bool newState=true)
511 flags |= FLAG_REFUNDING;
515 flags &= ~FLAG_REFUNDING;
519 std::map<uint160, int32_t> GetReserveMap() const
521 std::map<uint160, int32_t> retVal;
522 for (int i = 0; i < currencies.size(); i++)
524 retVal[currencies[i]] = i;
530 class CCoinbaseCurrencyState : public CCurrencyState
534 CAmount nativeConversionFees;
535 std::vector<CAmount> reserveIn; // reserve currency converted to native
536 std::vector<CAmount> nativeIn; // native currency converted to reserve
537 std::vector<CAmount> reserveOut; // output can have both normal and reserve output value, if non-0, this is spent by the required output transactions
538 std::vector<CAmount> conversionPrice; // calculated price in reserve for all conversions * 100000000
539 std::vector<CAmount> fees; // fee values in native (or reserve if specified) coins for reserve transaction fees for the block
540 std::vector<CAmount> conversionFees; // total of only conversion fees, which will accrue to the conversion transaction
542 CCoinbaseCurrencyState() : nativeFees(0), nativeConversionFees(0) {}
544 CCoinbaseCurrencyState(const CCurrencyState &CurrencyState,
545 CAmount NativeFees=0, CAmount NativeConversionFees=0,
546 const std::vector<CAmount> &ReserveIn=std::vector<CAmount>(),
547 const std::vector<CAmount> &NativeIn=std::vector<CAmount>(),
548 const std::vector<CAmount> &ReserveOut=std::vector<CAmount>(),
549 const std::vector<CAmount> &ConversionPrice=std::vector<CAmount>(),
550 const std::vector<CAmount> &Fees=std::vector<CAmount>(),
551 const std::vector<CAmount> &ConversionFees=std::vector<CAmount>()) :
552 CCurrencyState(CurrencyState), nativeFees(NativeFees), nativeConversionFees(NativeConversionFees),
553 reserveIn(ReserveIn),
555 reserveOut(ReserveOut),
556 conversionPrice(ConversionPrice),
558 conversionFees(ConversionFees)
560 if (!reserveIn.size()) reserveIn = std::vector<CAmount>(currencies.size());
561 if (!nativeIn.size()) nativeIn = std::vector<CAmount>(currencies.size());
562 if (!reserveOut.size()) reserveOut = std::vector<CAmount>(currencies.size());
563 if (!conversionPrice.size()) conversionPrice = std::vector<CAmount>(currencies.size());
564 if (!fees.size()) fees = std::vector<CAmount>(currencies.size());
565 if (!conversionFees.size()) conversionFees = std::vector<CAmount>(currencies.size());
568 CCoinbaseCurrencyState(const UniValue &uni);
570 CCoinbaseCurrencyState(const std::vector<unsigned char> asVector)
572 ::FromVector(asVector, *this);
575 CCoinbaseCurrencyState(const CTransaction &tx, int *pOutIdx=NULL);
577 ADD_SERIALIZE_METHODS;
579 template <typename Stream, typename Operation>
580 inline void SerializationOp(Stream& s, Operation ser_action) {
581 READWRITE(*(CCurrencyState *)this);
582 READWRITE(nativeFees);
583 READWRITE(nativeConversionFees);
584 READWRITE(reserveIn);
586 READWRITE(reserveOut);
587 READWRITE(conversionPrice);
589 READWRITE(conversionFees);
592 std::vector<unsigned char> AsVector() const
594 return ::AsVector(*this);
597 UniValue ToUniValue() const;
599 void ClearForNextBlock()
603 nativeConversionFees = 0;
604 reserveIn = std::vector<CAmount>(currencies.size());
605 nativeIn = std::vector<CAmount>(currencies.size());
606 reserveOut = std::vector<CAmount>(currencies.size());
607 fees = std::vector<CAmount>(currencies.size());
608 conversionFees = std::vector<CAmount>(currencies.size());
611 CCoinbaseCurrencyState MatchOrders(const std::vector<CReserveTransactionDescriptor> &orders,
612 std::vector<CReserveTransactionDescriptor> &reserveFills,
613 std::vector<CReserveTransactionDescriptor> &noFills,
614 std::vector<const CReserveTransactionDescriptor *> &expiredFillOrKills,
615 std::vector<const CReserveTransactionDescriptor *> &rejects,
616 std::vector<CAmount> &exchangeRates,
617 int32_t height, std::vector<CInputDescriptor> &conversionInputs,
618 int64_t maxSerializedSize=LONG_MAX, int64_t *ptotalSerializeSize=NULL, CMutableTransaction *pConversionTx=NULL,
619 bool feesAsReserve=false) const;
621 template <typename NUMBERVECTOR>
622 NUMBERVECTOR AddVectors(const NUMBERVECTOR &a, const NUMBERVECTOR &b) const
624 const NUMBERVECTOR *shortVec, *longVec;
626 if (a.size() <= b.size())
643 for (int i = 0; i < count; i++)
645 ret[i] = (*longVec)[i] + (*shortVec)[i];
647 for (int i = count; i < max; i++)
649 ret[i] = (*longVec)[i];
660 int64_t reserveOutConverted;
661 int64_t nativeOutConverted;
662 int64_t reserveConversionFees;
663 CReserveInOuts() : reserveIn(0), reserveOut(0), reserveOutConverted(0), nativeOutConverted(0), reserveConversionFees(0) {}
664 CReserveInOuts(int64_t ReserveIn, int64_t ReserveOut, int64_t ReserveOutConverted, int64_t NativeOutConverted, int64_t ReserveConversionFees) :
665 reserveIn(ReserveIn),
666 reserveOut(ReserveOut),
667 reserveOutConverted(ReserveOutConverted),
668 nativeOutConverted(NativeOutConverted),
669 reserveConversionFees(ReserveConversionFees) {}
672 class CReserveTransactionDescriptor
676 IS_VALID=1, // known to be valid
677 IS_REJECT=2, // if set, tx is known to be invalid
678 IS_RESERVE=4, // if set, this transaction affects reserves and/or price if mined
679 IS_RESERVEEXCHANGE=8, // is this a reserve/exchange transaction?
680 IS_LIMIT=0x10, // if reserve exchange, is it a limit order?
681 IS_FILLORKILL=0x20, // If set, this can expire
682 IS_FILLORKILLFAIL=0x40, // If set, this is an expired fill or kill in a valid tx
683 IS_IMPORT=0x80, // If set, this is an expired fill or kill in a valid tx
684 IS_EXPORT=0x100, // If set, this is an expired fill or kill in a valid tx
685 IS_IDENTITY=0x200, // If set, this is an identity definition or update
686 IS_IDENTITY_DEFINITION=0x400, // If set, this is an identity definition
687 IS_HIGH_FEE=0x800 // If set, this may have "absurdly high fees"
690 const CTransaction *ptx; // pointer to the actual transaction if valid
691 uint16_t flags; // indicates transaction state
692 std::map<uint160, CReserveInOuts> currencies; // currency entries in this transaction
693 int16_t numBuys = 0; // each limit conversion that is valid before a certain block should account for FILL_OR_KILL_FEE
694 int16_t numSells = 0;
695 int16_t numTransfers = 0; // number of transfers, each of which also requires a transfer fee
696 CAmount nativeIn = 0;
697 CAmount nativeOut = 0;
698 CAmount nativeConversionFees = 0; // non-zero only if there is a conversion
699 std::vector<std::pair<int, CReserveExchange>> vRex; // index and rehydrated, validated reserve exchange outputs
701 CReserveTransactionDescriptor() :
704 numBuys(0), // each limit conversion that is valid before a certain block should account for FILL_OR_KILL_FEE
709 nativeConversionFees(0) {} // non-zero only if there is a conversion, stored vs. calculated to get exact number with each calculated seperately
711 CReserveTransactionDescriptor(const CTransaction &tx, const CCoinsViewCache &view, int32_t nHeight);
713 bool IsReject() const { return flags & IS_REJECT; }
714 bool IsValid() const { return flags & IS_VALID && !IsReject(); }
715 bool IsReserve() const { return IsValid() && flags & IS_RESERVE; }
716 bool IsReserveExchange() const { return flags & IS_RESERVEEXCHANGE; }
717 bool IsLimit() const { return flags & IS_LIMIT; }
718 bool IsFillOrKill() const { return flags & IS_FILLORKILL; }
719 bool IsMarket() const { return IsReserveExchange() && !IsLimit(); }
720 bool IsFillOrKillFail() const { return flags & IS_FILLORKILLFAIL; }
721 bool IsIdentity() const { return flags & IS_IDENTITY; }
722 bool IsIdentityDefinition() const { return flags & IS_IDENTITY_DEFINITION; }
723 bool IsHighFee() const { return flags & IS_HIGH_FEE; }
725 static CAmount CalculateConversionFee(CAmount inputAmount);
726 static CAmount CalculateAdditionalConversionFee(CAmount inputAmount);
728 CAmount NativeFees() const
730 return nativeIn - nativeOut; // native out converted does not include conversion
733 CCurrencyValueMap ReserveFees() const
735 CCurrencyValueMap retFees;
736 for (auto &one : currencies)
738 CAmount oneFee = one.second.reserveIn - one.second.reserveOut;
741 retFees.valueMap[one.first] = oneFee;
747 CAmount AllFeesAsNative(const CCurrencyState ¤cyState) const;
748 CAmount AllFeesAsNative(const CCurrencyState ¤cyState, const std::vector<CAmount> &exchangeRates) const;
749 CCurrencyValueMap AllFeesAsReserve(const CCurrencyState ¤cyState, int defaultReserve=0) const;
750 CCurrencyValueMap AllFeesAsReserve(const CCurrencyState ¤cyState, const std::vector<CAmount> &exchangeRates, int defaultReserve=0) const;
752 // does not check for errors
753 void AddReserveInput(const uint160 ¤cy, CAmount value);
754 void AddReserveOutput(const uint160 ¤cy, CAmount value);
755 void AddReserveOutConverted(const uint160 ¤cy, CAmount value);
756 void AddNativeOutConverted(const uint160 ¤cy, CAmount value);
757 void AddReserveConversionFees(const uint160 ¤cy, CAmount value);
759 CCurrencyValueMap ReserveInputMap() const;
760 CCurrencyValueMap ReserveOutputMap() const;
761 CCurrencyValueMap ReserveOutConvertedMap() const;
762 CCurrencyValueMap NativeOutConvertedMap() const;
763 CCurrencyValueMap ReserveConversionFeesMap() const;
765 // returns vectors in same size and order as reserve currencies
766 std::vector<CAmount> ReserveInputVec(const CCurrencyState &cState) const;
767 std::vector<CAmount> ReserveOutputVec(const CCurrencyState &cState) const;
768 std::vector<CAmount> ReserveOutConvertedVec(const CCurrencyState &cState) const;
769 std::vector<CAmount> NativeOutConvertedVec(const CCurrencyState &cState) const;
770 std::vector<CAmount> ReserveConversionFeesVec(const CCurrencyState &cState) const;
772 void AddReserveOutput(const CTokenOutput &ro)
775 if (!(flags & IS_IMPORT))
777 AddReserveOutput(ro.currencyID, ro.nValue);
781 // is boolean, since it can fail, which would render the tx invalid
782 void AddReserveExchange(const CReserveExchange &rex, int32_t outputIndex, int32_t nHeight);
784 void AddReserveTransfer(CReserveTransfer &rt)
787 if (!(flags & IS_IMPORT))
789 AddReserveOutput(rt.currencyID, rt.nValue + rt.nFees);
794 CMutableTransaction &AddConversionInOuts(CMutableTransaction &conversionTx,
795 std::vector<CInputDescriptor> &conversionInputs,
796 const CCurrencyValueMap &exchangeRates=CCurrencyValueMap(),
797 const CCurrencyState *pCurrencyState=nullptr) const;
799 bool AddReserveTransferImportOutputs(const uint160 ¤cySourceID,
800 const CCurrencyDefinition &importCurrencyDef,
801 const CCoinbaseCurrencyState &importCurrencyState,
802 const std::vector<CBaseChainObject *> &exportObjects,
803 std::vector<CTxOut> &vOutputs,
804 CCoinbaseCurrencyState *pNewCurrencyState=nullptr);
807 #endif // PBAAS_RESERVES_H