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;
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 uint32_t nVersion; // version of the token output class
53 uint160 currencyID; // currency ID
54 CAmount nValue; // amount of input reserve coins this UTXO represents before any conversion
56 CTokenOutput(const std::vector<unsigned char> &asVector)
58 FromVector(asVector, *this);
61 CTokenOutput(const UniValue &obj);
63 CTokenOutput() : nVersion(VERSION_CURRENT), nValue(0) { }
65 CTokenOutput(const uint160 &curID, CAmount value) : nVersion(VERSION_CURRENT), currencyID(curID), nValue(value) { }
67 ADD_SERIALIZE_METHODS;
69 template <typename Stream, typename Operation>
70 inline void SerializationOp(Stream& s, Operation ser_action) {
71 READWRITE(VARINT(nVersion));
72 READWRITE(currencyID);
73 READWRITE(VARINT(nValue));
76 std::vector<unsigned char> AsVector()
78 return ::AsVector(*this);
81 UniValue ToUniValue() const;
85 // we don't support op returns, value must be in native or reserve
86 return nVersion >= VERSION_FIRSTVALID && nVersion <= VERSION_LASTVALID;
90 class CReserveTransfer : public CTokenOutput
98 FEE_OUTPUT = 8, // one per import, amount must match total percentage of fees for exporter, no pre-convert allowed
99 SEND_BACK = 0x10, // fee is sent back immediately to destination on exporting chain
100 MINT_CURRENCY = 0x20, // set when this output is being minted on import
101 PREALLOCATE = 0x40, // combined with minting for pre-allocation of currency
102 BURN_CHANGE_PRICE = 0x80, // set when this output is being minted on import
103 BURN_CHANGE_WEIGHT = 0x100 // set when this output is being minted on import
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 class CReserveDeposit
165 VERSION_FIRSTVALID = 1,
166 VERSION_LASTVALID = 1,
170 uint160 controllingCurrencyID; // system to export to, which may represent a PBaaS chain or external bridge
171 CCurrencyValueMap reserveValues; // all outputs of this reserve deposit
173 CReserveDeposit(const std::vector<unsigned char> &asVector)
175 FromVector(asVector, *this);
178 CReserveDeposit() : nVersion(VERSION_CURRENT) {}
180 CReserveDeposit(const uint160 &controllingID, const CCurrencyValueMap &reserveOut) :
181 controllingCurrencyID(controllingID), reserveValues(reserveOut) {}
183 ADD_SERIALIZE_METHODS;
185 template <typename Stream, typename Operation>
186 inline void SerializationOp(Stream& s, Operation ser_action) {
187 READWRITE(controllingCurrencyID);
188 READWRITE(reserveValues);
191 std::vector<unsigned char> AsVector()
193 return ::AsVector(*this);
196 UniValue ToUniValue() const;
200 return nVersion >= VERSION_FIRSTVALID && nVersion <= VERSION_LASTVALID;
204 // convert from $VRSC to fractional reserve coin or vice versa. coinID determines which
205 // in either direction, this is burned in the block. if burned, the block must contain less than a
206 // maximum reasonable number of exchange outputs, which must be sorted, hashed, and used to validate
207 // the outputs that must match exactly on any transaction spending the output. since fees are not
208 // included in outputs, it is assumed that a miner will spend the output in the same block to recover
210 class CReserveExchange : public CTokenOutput
217 TO_RESERVE = 0x80000, // from fractional currency to reserve, default is reserve to fractional
218 LIMIT = 0x100000, // observe the limit when converting
219 FILL_OR_KILL = 0x200000, // if not filled before nValidBefore but before expiry, no execution, mined with fee, output pass through
220 ALL_OR_NONE = 0x400000, // will not execute partial order
221 SEND_OUTPUT = 0x800000 // send the output of this exchange to the target chain, only valid if output is reserve
224 // 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
225 // 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
226 // it is deducted in the success case from the success fee, so there is no fee beyond the success fee paid
227 static const CAmount SUCCESS_FEE = 25000;
228 static const CAmount MIN_SUCCESS_FEE = 50000;
229 static const CAmount MIN_PARTIAL = 10000000; // making partial fill minimum the number at which minimum fee meets standard percent fee,
230 static const CAmount MIN_NET_CONVERSION = 10000000; // minimum conversion for input
231 static const CAmount FILL_OR_KILL_FEE = 10000;
233 uint32_t flags; // type of transfer and options
234 CAmount nLimit; // limit price to sell or buy currency
235 uint32_t nValidBefore; // if not filled on or after this block, can mine tx, but is spendable to refund input
237 CReserveExchange(const std::vector<unsigned char> &asVector)
239 FromVector(asVector, *this);
242 CReserveExchange() : CTokenOutput(), nLimit(0), nValidBefore(0) { }
244 CReserveExchange(uint32_t Flags, const uint160 &cID, CAmount amountIn, CAmount Limit=0, uint32_t ValidBefore=0) :
245 CTokenOutput(cID, amountIn), flags(Flags), nLimit(Limit), nValidBefore(ValidBefore) {}
247 CReserveExchange(const UniValue &uni);
248 CReserveExchange(const CTransaction &tx);
250 ADD_SERIALIZE_METHODS;
252 template <typename Stream, typename Operation>
253 inline void SerializationOp(Stream& s, Operation ser_action) {
254 READWRITE(*(CTokenOutput *)this);
255 READWRITE(VARINT(flags));
256 READWRITE(VARINT(nLimit));
257 READWRITE(nValidBefore);
260 std::vector<unsigned char> AsVector()
262 return ::AsVector(*this);
267 // this needs an actual check
268 return CTokenOutput::IsValid();
271 UniValue ToUniValue() const;
273 bool IsExpired(int32_t height)
275 return height >= nValidBefore;
279 // import transactions and tokens from another chain
280 // this represents the chain, the currencies, and the amounts of each
281 // it may also import IDs from the chain on which they were defined
282 class CCrossChainImport
285 static const uint32_t VERSION_INVALID = 0;
286 static const uint32_t VERSION_CURRENT = 1;
287 static const uint32_t VERSION_LAST = 1;
289 uint160 systemID; // the source currency system from where these transactions are being imported
290 uint160 importCurrencyID; // the import currency ID
291 CCurrencyValueMap importValue; // total amount of coins imported from chain with or without conversion, including fees
292 CCurrencyValueMap totalReserveOutMap; // all non-native currencies being held in this thread and released on import
294 CCrossChainImport() : nVersion(VERSION_INVALID) {}
295 CCrossChainImport(const uint160 &sysID, const uint160 &importCID, const CCurrencyValueMap &ImportValue, const CCurrencyValueMap &InitialReserveOutput=CCurrencyValueMap()) :
296 nVersion(VERSION_CURRENT),
298 importCurrencyID(importCID),
299 importValue(ImportValue),
300 totalReserveOutMap(InitialReserveOutput) { }
302 CCrossChainImport(const std::vector<unsigned char> &asVector)
304 ::FromVector(asVector, *this);
307 CCrossChainImport(const CTransaction &tx, int32_t *pOutNum=nullptr);
309 ADD_SERIALIZE_METHODS;
311 template <typename Stream, typename Operation>
312 inline void SerializationOp(Stream& s, Operation ser_action) {
315 READWRITE(importCurrencyID);
316 READWRITE(importValue);
317 READWRITE(totalReserveOutMap);
320 std::vector<unsigned char> AsVector()
322 return ::AsVector(*this);
327 return nVersion > VERSION_INVALID && nVersion <= VERSION_LAST && !systemID.IsNull();
330 UniValue ToUniValue() const;
333 // describes an entire output that will be realized on a target chain. target is specified as part of an aggregated transaction.
334 class CCrossChainExport
337 static const int MIN_BLOCKS = 10;
338 static const int MIN_INPUTS = 10;
339 static const int MAX_EXPORT_INPUTS = 50;
340 static const uint32_t VERSION_INVALID = 0;
341 static const uint32_t VERSION_CURRENT = 1;
342 static const uint32_t VERSION_LAST = 1;
344 uint160 systemID; // target blockchain or currency system ID
345 int32_t numInputs; // number of inputs aggregated to calculate the fee percentage
346 CCurrencyValueMap totalAmounts; // total amount of inputs of each currency, including fees
347 CCurrencyValueMap totalFees; // total amount of fees of each currency to split between miner on exporting chain and importing chain
349 CCrossChainExport() : nVersion(VERSION_INVALID), numInputs(0) {}
351 CCrossChainExport(const std::vector<unsigned char> &asVector)
353 FromVector(asVector, *this);
356 CCrossChainExport(uint160 SystemID, int32_t numin, const CCurrencyValueMap &values, const CCurrencyValueMap &fees) :
357 nVersion(VERSION_CURRENT), systemID(SystemID), numInputs(numin), totalAmounts(values), totalFees(fees) {}
359 CCrossChainExport(const CTransaction &tx, int32_t *pCCXOutputNum=nullptr);
361 ADD_SERIALIZE_METHODS;
363 template <typename Stream, typename Operation>
364 inline void SerializationOp(Stream& s, Operation ser_action) {
367 READWRITE(numInputs);
368 READWRITE(totalAmounts);
369 READWRITE(totalFees);
372 std::vector<unsigned char> AsVector()
374 return ::AsVector(*this);
379 return nVersion > VERSION_INVALID &&
380 nVersion <= VERSION_LAST &&
384 static CCurrencyValueMap CalculateExportFee(const CCurrencyValueMap &fees, int numIn);
385 CCurrencyValueMap CalculateExportFee() const;
387 CCurrencyValueMap CalculateImportFee() const;
389 UniValue ToUniValue() const;
402 MIN_RESERVE_RATIO = 1000000, // we will not start a chain with less than 1% reserve ratio in any single currency
403 MAX_RESERVE_RATIO = 100000000, // we will not start a chain with greater than 100% reserve ratio
404 SHUTDOWN_RESERVE_RATIO = 500000, // if we hit this reserve ratio in any currency, initiate chain shutdown
405 CONVERSION_TX_SIZE_MIN = 1024, // minimum size accounted for in a conversion transaction
406 MAX_RESERVE_CURRENCIES = 10 // maximum number of reserve currencies that can underly a fractional reserve
409 uint32_t flags; // currency flags (valid, reserve currency, etc.)
410 uint160 currencyID; // ID of this currency
411 std::vector<uint160> currencies; // the ID in uin160 form (maps to CIdentityID) if each currency in the reserve
412 std::vector<int32_t> weights; // current, individual weights for all currencies to use in calculations
413 std::vector<int64_t> reserves; // total amount of reserves in each currency
415 int64_t initialSupply; // initial premine + pre-converted coins
416 int64_t emitted; // emitted coins reduce the reserve ratio and are used to calculate current ratio
417 CAmount supply; // current supply: total of initial, all emitted, and all purchased coins
419 //std::vector<CAmount> Reserves; // reserve currencies amounts controlled by this fractional chain - only present for reserve currencies, currency IDs are in chain definition
421 CCurrencyState() : flags(0), initialSupply(0), emitted(0), supply(0) {}
423 CCurrencyState(const uint160 &cID,
424 const std::vector<uint160> &Currencies,
425 const std::vector<int32_t> &Weights,
426 const std::vector<int64_t> &Reserves,
427 CAmount InitialSupply,
430 uint32_t Flags=FLAG_VALID) :
433 currencies(Currencies),
436 initialSupply(InitialSupply),
441 CCurrencyState(const std::vector<unsigned char> &asVector)
443 FromVector(asVector, *this);
446 CCurrencyState(const UniValue &uni);
448 ADD_SERIALIZE_METHODS;
450 template <typename Stream, typename Operation>
451 inline void SerializationOp(Stream& s, Operation ser_action) {
453 READWRITE(currencyID);
454 READWRITE(currencies);
457 READWRITE(VARINT(initialSupply));
458 READWRITE(VARINT(emitted));
459 READWRITE(VARINT(supply));
462 std::vector<unsigned char> AsVector() const
464 return ::AsVector(*this);
467 // this should be done no more than once to prepare a currency state to be moved to the next state
468 // emission occurs for a block before any conversion or exchange and that impact on the currency state is calculated
469 CCurrencyState &UpdateWithEmission(CAmount emitted);
471 cpp_dec_float_50 GetReserveRatio(int32_t reserveIndex=0) const
473 return cpp_dec_float_50(std::to_string(weights[reserveIndex])) / cpp_dec_float_50("100000000");
476 template<typename cpp_dec_float_type>
477 static bool to_int64(const cpp_dec_float_type &input, int64_t &outval)
479 std::stringstream ss(input.str(0, std::ios_base::fmtflags::_S_fixed));
485 catch(const std::exception& e)
491 // in a fractional reserve with no reserve or supply, this will always return
492 // a price of the reciprocal (1/x) of the fractional reserve ratio of the indexed reserve,
493 // which will always be >= 1
494 CAmount PriceInReserve(int32_t reserveIndex=0, bool roundUp=false) const;
496 // return the current price of the fractional reserve in the reserve currency in Satoshis
497 cpp_dec_float_50 PriceInReserveDecFloat50(int32_t reserveIndex=0) const;
499 std::vector<CAmount> PricesInReserve() const;
501 // This considers one currency at a time
502 CAmount ConvertAmounts(CAmount inputReserve, CAmount inputFractional, CCurrencyState &newState, int32_t reserveIndex=0) const;
504 // convert amounts for multi-reserve fractional reserve currencies
505 // one entry in the vector for each currency in and one fractional input for each
506 // currency expected as output
507 std::vector<CAmount> ConvertAmounts(const std::vector<CAmount> &inputReserve, const std::vector<CAmount> &inputFractional, CCurrencyState &newState) const;
509 CAmount CalculateConversionFee(CAmount inputAmount, bool convertToNative = false, int32_t reserveIndex=0) const;
510 CAmount ReserveFeeToNative(CAmount inputAmount, CAmount outputAmount, int32_t reserveIndex=0) const;
512 CAmount ReserveToNative(CAmount reserveAmount, int32_t reserveIndex) const;
513 CAmount ReserveToNative(const CCurrencyValueMap &reserveAmounts) const;
515 static CAmount ReserveToNativeRaw(CAmount reserveAmount, const cpp_dec_float_50 &exchangeRate);
516 static CAmount ReserveToNativeRaw(CAmount reserveAmount, CAmount exchangeRate);
517 static CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<uint160> ¤cies, const std::vector<CAmount> &exchangeRates);
518 static CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<uint160> ¤cies, const std::vector<cpp_dec_float_50> &exchangeRates);
519 CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<CAmount> &exchangeRates) const;
521 const CCurrencyValueMap &NativeToReserve(std::vector<CAmount> nativeAmount, int32_t reserveIndex=0) const;
522 CAmount NativeToReserve(CAmount nativeAmount, int32_t reserveIndex=0) const;
523 static CAmount NativeToReserveRaw(CAmount nativeAmount, const cpp_dec_float_50 &exchangeRate);
524 static CAmount NativeToReserveRaw(CAmount nativeAmount, CAmount exchangeRate);
525 CCurrencyValueMap NativeToReserveRaw(const std::vector<CAmount> &, const std::vector<CAmount> &exchangeRates) const;
526 CCurrencyValueMap NativeToReserveRaw(const std::vector<CAmount> &, const std::vector<cpp_dec_float_50> &exchangeRates) const;
528 UniValue ToUniValue() const;
530 uint160 GetID() const { return currencyID; }
534 return !currencyID.IsNull() && flags & FLAG_VALID;
537 bool IsFractional() const
539 return flags & FLAG_FRACTIONAL;
542 bool IsRefunding() const
544 return flags & FLAG_REFUNDING;
547 bool IsPrelaunch() const
549 return flags & FLAG_PRELAUNCH;
552 void SetPrelaunch(bool newState=true)
556 flags |= FLAG_PRELAUNCH;
560 flags &= ~FLAG_PRELAUNCH;
564 void SetRefunding(bool newState=true)
568 flags |= FLAG_REFUNDING;
572 flags &= ~FLAG_REFUNDING;
576 std::map<uint160, int32_t> GetReserveMap() const
578 std::map<uint160, int32_t> retVal;
579 for (int i = 0; i < currencies.size(); i++)
581 retVal[currencies[i]] = i;
587 class CCoinbaseCurrencyState : public CCurrencyState
591 CAmount nativeConversionFees;
592 std::vector<CAmount> reserveIn; // reserve currency converted to native
593 std::vector<CAmount> nativeIn; // native currency converted to reserve
594 std::vector<CAmount> reserveOut; // output can have both normal and reserve output value, if non-0, this is spent by the required output transactions
595 std::vector<CAmount> conversionPrice; // calculated price in reserve for all conversions * 100000000
596 std::vector<CAmount> fees; // fee values in native (or reserve if specified) coins for reserve transaction fees for the block
597 std::vector<CAmount> conversionFees; // total of only conversion fees, which will accrue to the conversion transaction
599 CCoinbaseCurrencyState() : nativeFees(0), nativeConversionFees(0) {}
601 CCoinbaseCurrencyState(const CCurrencyState &CurrencyState,
602 CAmount NativeFees=0, CAmount NativeConversionFees=0,
603 const std::vector<CAmount> &ReserveIn=std::vector<CAmount>(),
604 const std::vector<CAmount> &NativeIn=std::vector<CAmount>(),
605 const std::vector<CAmount> &ReserveOut=std::vector<CAmount>(),
606 const std::vector<CAmount> &ConversionPrice=std::vector<CAmount>(),
607 const std::vector<CAmount> &Fees=std::vector<CAmount>(),
608 const std::vector<CAmount> &ConversionFees=std::vector<CAmount>()) :
609 CCurrencyState(CurrencyState), nativeFees(NativeFees), nativeConversionFees(NativeConversionFees),
610 reserveIn(ReserveIn),
612 reserveOut(ReserveOut),
613 conversionPrice(ConversionPrice),
615 conversionFees(ConversionFees)
617 if (!reserveIn.size()) reserveIn = std::vector<CAmount>(currencies.size());
618 if (!nativeIn.size()) nativeIn = std::vector<CAmount>(currencies.size());
619 if (!reserveOut.size()) reserveOut = std::vector<CAmount>(currencies.size());
620 if (!conversionPrice.size()) conversionPrice = std::vector<CAmount>(currencies.size());
621 if (!fees.size()) fees = std::vector<CAmount>(currencies.size());
622 if (!conversionFees.size()) conversionFees = std::vector<CAmount>(currencies.size());
625 CCoinbaseCurrencyState(const UniValue &uni);
627 CCoinbaseCurrencyState(const std::vector<unsigned char> asVector)
629 ::FromVector(asVector, *this);
632 CCoinbaseCurrencyState(const CTransaction &tx, int *pOutIdx=NULL);
634 ADD_SERIALIZE_METHODS;
636 template <typename Stream, typename Operation>
637 inline void SerializationOp(Stream& s, Operation ser_action) {
638 READWRITE(*(CCurrencyState *)this);
639 READWRITE(nativeFees);
640 READWRITE(nativeConversionFees);
641 READWRITE(reserveIn);
643 READWRITE(reserveOut);
644 READWRITE(conversionPrice);
646 READWRITE(conversionFees);
649 std::vector<unsigned char> AsVector() const
651 return ::AsVector(*this);
654 UniValue ToUniValue() const;
656 void ClearForNextBlock()
660 nativeConversionFees = 0;
661 reserveIn = std::vector<CAmount>(currencies.size());
662 nativeIn = std::vector<CAmount>(currencies.size());
663 reserveOut = std::vector<CAmount>(currencies.size());
664 fees = std::vector<CAmount>(currencies.size());
665 conversionFees = std::vector<CAmount>(currencies.size());
668 CCoinbaseCurrencyState MatchOrders(const std::vector<CReserveTransactionDescriptor> &orders,
669 std::vector<CReserveTransactionDescriptor> &reserveFills,
670 std::vector<CReserveTransactionDescriptor> &noFills,
671 std::vector<const CReserveTransactionDescriptor *> &expiredFillOrKills,
672 std::vector<const CReserveTransactionDescriptor *> &rejects,
673 std::vector<CAmount> &exchangeRates,
674 int32_t height, std::vector<CInputDescriptor> &conversionInputs,
675 int64_t maxSerializedSize=LONG_MAX, int64_t *ptotalSerializeSize=NULL, CMutableTransaction *pConversionTx=NULL,
676 bool feesAsReserve=false) const;
678 template <typename NUMBERVECTOR>
679 NUMBERVECTOR AddVectors(const NUMBERVECTOR &a, const NUMBERVECTOR &b) const
681 const NUMBERVECTOR *shortVec, *longVec;
683 if (a.size() <= b.size())
700 for (int i = 0; i < count; i++)
702 ret[i] = (*longVec)[i] + (*shortVec)[i];
704 for (int i = count; i < max; i++)
706 ret[i] = (*longVec)[i];
717 int64_t reserveOutConverted;
718 int64_t nativeOutConverted;
719 int64_t reserveConversionFees;
720 CReserveInOuts() : reserveIn(0), reserveOut(0), reserveOutConverted(0), nativeOutConverted(0), reserveConversionFees(0) {}
721 CReserveInOuts(int64_t ReserveIn, int64_t ReserveOut, int64_t ReserveOutConverted, int64_t NativeOutConverted, int64_t ReserveConversionFees) :
722 reserveIn(ReserveIn),
723 reserveOut(ReserveOut),
724 reserveOutConverted(ReserveOutConverted),
725 nativeOutConverted(NativeOutConverted),
726 reserveConversionFees(ReserveConversionFees) {}
729 class CReserveTransactionDescriptor
733 IS_VALID=1, // known to be valid
734 IS_REJECT=2, // if set, tx is known to be invalid
735 IS_RESERVE=4, // if set, this transaction affects reserves and/or price if mined
736 IS_RESERVEEXCHANGE=8, // is this a reserve/exchange transaction?
737 IS_LIMIT=0x10, // if reserve exchange, is it a limit order?
738 IS_FILLORKILL=0x20, // If set, this can expire
739 IS_FILLORKILLFAIL=0x40, // If set, this is an expired fill or kill in a valid tx
740 IS_IMPORT=0x80, // If set, this is an expired fill or kill in a valid tx
741 IS_EXPORT=0x100, // If set, this is an expired fill or kill in a valid tx
742 IS_IDENTITY=0x200, // If set, this is an identity definition or update
743 IS_IDENTITY_DEFINITION=0x400, // If set, this is an identity definition
744 IS_HIGH_FEE=0x800 // If set, this may have "absurdly high fees"
747 const CTransaction *ptx; // pointer to the actual transaction if valid
748 uint16_t flags; // indicates transaction state
749 std::map<uint160, CReserveInOuts> currencies; // currency entries in this transaction
750 int16_t numBuys = 0; // each limit conversion that is valid before a certain block should account for FILL_OR_KILL_FEE
751 int16_t numSells = 0;
752 int16_t numTransfers = 0; // number of transfers, each of which also requires a transfer fee
753 CAmount nativeIn = 0;
754 CAmount nativeOut = 0;
755 CAmount nativeConversionFees = 0; // non-zero only if there is a conversion
756 std::vector<std::pair<int, CReserveExchange>> vRex; // index and rehydrated, validated reserve exchange outputs
758 CReserveTransactionDescriptor() :
761 numBuys(0), // each limit conversion that is valid before a certain block should account for FILL_OR_KILL_FEE
766 nativeConversionFees(0) {} // non-zero only if there is a conversion, stored vs. calculated to get exact number with each calculated seperately
768 CReserveTransactionDescriptor(const CTransaction &tx, const CCoinsViewCache &view, int32_t nHeight);
770 bool IsReject() const { return flags & IS_REJECT; }
771 bool IsValid() const { return flags & IS_VALID && !IsReject(); }
772 bool IsReserve() const { return IsValid() && flags & IS_RESERVE; }
773 bool IsReserveExchange() const { return flags & IS_RESERVEEXCHANGE; }
774 bool IsLimit() const { return flags & IS_LIMIT; }
775 bool IsFillOrKill() const { return flags & IS_FILLORKILL; }
776 bool IsMarket() const { return IsReserveExchange() && !IsLimit(); }
777 bool IsFillOrKillFail() const { return flags & IS_FILLORKILLFAIL; }
778 bool IsIdentity() const { return flags & IS_IDENTITY; }
779 bool IsIdentityDefinition() const { return flags & IS_IDENTITY_DEFINITION; }
780 bool IsHighFee() const { return flags & IS_HIGH_FEE; }
782 static CAmount CalculateConversionFee(CAmount inputAmount);
783 static CAmount CalculateAdditionalConversionFee(CAmount inputAmount);
785 CAmount TotalNativeOutConverted() const
787 CAmount nativeOutConverted = 0;
788 for (auto &one : currencies)
790 nativeOutConverted += one.second.nativeOutConverted;
792 return nativeOutConverted;
795 CAmount NativeFees() const
797 return nativeIn - nativeOut; // native out converted does not include conversion
800 CCurrencyValueMap ReserveFees() const
802 CCurrencyValueMap retFees;
803 for (auto &one : currencies)
805 CAmount oneFee = one.second.reserveIn - (one.second.reserveOut - one.second.reserveOutConverted);
808 retFees.valueMap[one.first] = oneFee;
814 CAmount AllFeesAsNative(const CCurrencyState ¤cyState) const;
815 CAmount AllFeesAsNative(const CCurrencyState ¤cyState, const std::vector<CAmount> &exchangeRates) const;
816 CCurrencyValueMap AllFeesAsReserve(const CCurrencyState ¤cyState, int defaultReserve=0) const;
817 CCurrencyValueMap AllFeesAsReserve(const CCurrencyState ¤cyState, const std::vector<CAmount> &exchangeRates, int defaultReserve=0) const;
819 // does not check for errors
820 void AddReserveInput(const uint160 ¤cy, CAmount value);
821 void AddReserveOutput(const uint160 ¤cy, CAmount value);
822 void AddReserveOutConverted(const uint160 ¤cy, CAmount value);
823 void AddNativeOutConverted(const uint160 ¤cy, CAmount value);
824 void AddReserveConversionFees(const uint160 ¤cy, CAmount value);
826 CCurrencyValueMap ReserveInputMap() const;
827 CCurrencyValueMap ReserveOutputMap() const;
828 CCurrencyValueMap ReserveOutConvertedMap() const;
829 CCurrencyValueMap NativeOutConvertedMap() const;
830 CCurrencyValueMap ReserveConversionFeesMap() const;
832 // returns vectors in same size and order as reserve currencies
833 std::vector<CAmount> ReserveInputVec(const CCurrencyState &cState) const;
834 std::vector<CAmount> ReserveOutputVec(const CCurrencyState &cState) const;
835 std::vector<CAmount> ReserveOutConvertedVec(const CCurrencyState &cState) const;
836 std::vector<CAmount> NativeOutConvertedVec(const CCurrencyState &cState) const;
837 std::vector<CAmount> ReserveConversionFeesVec(const CCurrencyState &cState) const;
839 void AddReserveOutput(const CTokenOutput &ro)
842 if (!(flags & IS_IMPORT))
844 AddReserveOutput(ro.currencyID, ro.nValue);
848 // is boolean, since it can fail, which would render the tx invalid
849 void AddReserveExchange(const CReserveExchange &rex, int32_t outputIndex, int32_t nHeight);
851 void AddReserveTransfer(CReserveTransfer &rt)
854 if (!(flags & IS_IMPORT))
856 AddReserveOutput(rt.currencyID, rt.nValue + rt.nFees);
861 CMutableTransaction &AddConversionInOuts(CMutableTransaction &conversionTx,
862 std::vector<CInputDescriptor> &conversionInputs,
863 const CCurrencyValueMap &exchangeRates=CCurrencyValueMap(),
864 const CCurrencyState *pCurrencyState=nullptr) const;
866 bool AddReserveTransferImportOutputs(const uint160 ¤cySourceID,
867 const CCurrencyDefinition &importCurrencyDef,
868 const CCoinbaseCurrencyState &importCurrencyState,
869 const std::vector<CBaseChainObject *> &exportObjects,
870 std::vector<CTxOut> &vOutputs,
871 CCoinbaseCurrencyState *pNewCurrencyState=nullptr);
874 #endif // PBAAS_RESERVES_H