]> Git Repo - VerusCoin.git/blob - src/pbaas/reserves.h
Conversion fixes
[VerusCoin.git] / src / pbaas / reserves.h
1 /********************************************************************
2  * (C) 2019 Michael Toutonghi
3  * 
4  * Distributed under the MIT software license, see the accompanying
5  * file COPYING or http://www.opensource.org/licenses/mit-license.php.
6  * 
7  * This provides reserve currency functions, leveraging the multi-precision boost libraries to calculate reserve currency conversions
8  * in a predictable manner that can achieve consensus.
9  * 
10  */
11
12 #ifndef PBAAS_RESERVES_H
13 #define PBAAS_RESERVES_H
14
15 #include <sstream>
16 #include <univalue/include/univalue.h>
17 #include "pbaas/crosschainrpc.h"
18 #include "arith_uint256.h"
19 #include <boost/multiprecision/cpp_dec_float.hpp>
20 #include "librustzcash.h"
21 #include "pubkey.h"
22 #include "amount.h"
23 #include <map>
24
25 #ifndef SATOSHIDEN
26 #define SATOSHIDEN ((uint64_t)100000000L)
27 #endif
28
29 using boost::multiprecision::cpp_dec_float_50;
30 class CCoinsViewCache;
31 class CInputDescriptor;
32 class CBaseChainObject;
33 class CTransaction;
34 class CMutableTransaction;
35 class CTxOut;
36 class CReserveTransactionDescriptor;
37 class CCurrencyState;
38
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.
41 class CTokenOutput
42 {
43 public:
44     enum
45     {
46         VERSION_INVALID = 0,
47         VERSION_CURRENT = 1,
48         VERSION_FIRSTVALID = 1,
49         VERSION_LASTVALID = 1,
50     };
51
52     static std::vector<uint160> *reserveIDs;
53
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
57
58     CTokenOutput(const std::vector<unsigned char> &asVector)
59     {
60         FromVector(asVector, *this);
61     }
62
63     CTokenOutput(const UniValue &obj);
64
65     CTokenOutput() : nVersion(VERSION_CURRENT), nValue(0) { }
66
67     CTokenOutput(const uint160 &curID, CAmount value) : nVersion(VERSION_CURRENT), currencyID(curID), nValue(value) { }
68
69     ADD_SERIALIZE_METHODS;
70
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));
76     }
77
78     std::vector<unsigned char> AsVector()
79     {
80         return ::AsVector(*this);
81     }
82
83     UniValue ToUniValue() const;
84
85     bool IsValid() const
86     {
87         // we don't support op returns, value must be in native or reserve
88         return nVersion >= VERSION_FIRSTVALID && nVersion <= VERSION_LASTVALID;
89     }
90 };
91
92 class CReserveTransfer : public CTokenOutput
93 {
94 public:
95     enum EOptions
96     {
97         VALID = 1,
98         CONVERT = 2,
99         PRECONVERT = 4,
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
104     };
105
106     enum EConstants
107     {
108         DESTINATION_BYTE_DIVISOR = 128      // destination vector is divided by this and result is multiplied by normal fee and added to transfer fee
109     };
110
111     static const CAmount DEFAULT_PER_STEP_FEE = 10000; // default fee for each step of each transfer (initial mining, transfer, mining on new chain)
112
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
117
118     CReserveTransfer(const std::vector<unsigned char> &asVector)
119     {
120         FromVector(asVector, *this);
121     }
122
123     CReserveTransfer() : CTokenOutput(), flags(0), nFees(0) { }
124
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) { }
127
128     ADD_SERIALIZE_METHODS;
129
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);
137     }
138
139     std::vector<unsigned char> AsVector()
140     {
141         return ::AsVector(*this);
142     }
143
144     UniValue ToUniValue() const;
145
146     CCurrencyValueMap CalculateFee(uint32_t flags, CAmount transferTotal) const;
147
148     static CAmount CalculateTransferFee(const CTransferDestination &destination);
149
150     CAmount CalculateTransferFee() const;
151
152     bool IsValid() const
153     {
154         return CTokenOutput::IsValid() && (nFees > 0 || flags & FEE_OUTPUT) && destination.destination.size();
155     }
156 };
157
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
163 // exchange fees
164 class CReserveExchange : public CTokenOutput
165 {
166 public:
167     // flags
168     enum EFlags
169     {
170         VALID = 1,
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
176     };
177
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;
186
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
190
191     CReserveExchange(const std::vector<unsigned char> &asVector)
192     {
193         FromVector(asVector, *this);
194     }
195
196     CReserveExchange() : CTokenOutput(), nLimit(0), nValidBefore(0) { }
197
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) {}
200
201     CReserveExchange(const UniValue &uni);
202     CReserveExchange(const CTransaction &tx);
203
204     ADD_SERIALIZE_METHODS;
205
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);
212     }
213
214     std::vector<unsigned char> AsVector()
215     {
216         return ::AsVector(*this);
217     }
218
219     bool IsValid() const
220     {
221         // this needs an actual check
222         return CTokenOutput::IsValid();
223     }
224
225     UniValue ToUniValue() const;
226
227     bool IsExpired(int32_t height)
228     {
229         return height >= nValidBefore;
230     }
231 };
232
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
237 {
238 public:
239     static const uint32_t VERSION_INVALID = 0;
240     static const uint32_t VERSION_CURRENT = 1;
241     static const uint32_t VERSION_LAST = 1;
242     uint32_t nVersion;
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
246
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) { }
250
251     CCrossChainImport(const std::vector<unsigned char> &asVector)
252     {
253         ::FromVector(asVector, *this);
254     }
255
256     CCrossChainImport(const CTransaction &tx, int32_t *pOutNum=nullptr);
257
258     ADD_SERIALIZE_METHODS;
259
260     template <typename Stream, typename Operation>
261     inline void SerializationOp(Stream& s, Operation ser_action) {
262         READWRITE(nVersion);
263         READWRITE(systemID);
264         READWRITE(importValue);
265         READWRITE(totalReserveOutMap);
266     }
267
268     std::vector<unsigned char> AsVector()
269     {
270         return ::AsVector(*this);
271     }
272
273     bool IsValid() const
274     {
275         return nVersion > VERSION_INVALID && nVersion <= VERSION_LAST && !systemID.IsNull();
276     }
277
278     UniValue ToUniValue() const;
279 };
280
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
283 {
284 public:
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;
291     uint32_t nVersion;
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
296
297     CCrossChainExport() : nVersion(VERSION_INVALID), numInputs(0) {}
298
299     CCrossChainExport(const std::vector<unsigned char> &asVector)
300     {
301         FromVector(asVector, *this);
302     }
303
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) {}
306
307     CCrossChainExport(const CTransaction &tx, int32_t *pCCXOutputNum=nullptr);
308
309     ADD_SERIALIZE_METHODS;
310
311     template <typename Stream, typename Operation>
312     inline void SerializationOp(Stream& s, Operation ser_action) {
313         READWRITE(nVersion);
314         READWRITE(systemID);
315         READWRITE(numInputs);
316         READWRITE(totalAmounts);
317         READWRITE(totalFees);
318     }
319
320     std::vector<unsigned char> AsVector()
321     {
322         return ::AsVector(*this);
323     }
324
325     bool IsValid() const
326     {
327         return nVersion > VERSION_INVALID && 
328                nVersion <= VERSION_LAST && 
329                !systemID.IsNull();
330     }
331
332     static CCurrencyValueMap CalculateExportFee(const CCurrencyValueMap &fees, int numIn);
333     CCurrencyValueMap CalculateExportFee() const;
334
335     CCurrencyValueMap CalculateImportFee() const;
336     
337     UniValue ToUniValue() const;
338 };
339
340 class CCurrencyState
341 {
342 public:
343     enum FLAGS {
344         FLAG_VALID = 1,
345         FLAG_FRACTIONAL = 2,
346         FLAG_REFUNDING = 4,
347         FLAG_PRELAUNCH = 8
348     };
349     enum CONSTANTS {
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
355     };
356
357     uint32_t flags;         // currency flags (valid, reserve currency, etc.)
358
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
362
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
366
367     //std::vector<CAmount> Reserves; // reserve currencies amounts controlled by this fractional chain - only present for reserve currencies, currency IDs are in chain definition
368
369     CCurrencyState() : flags(0), initialSupply(0), emitted(0), supply(0) {}
370
371     CCurrencyState(const std::vector<uint160> &Currencies, 
372                       const std::vector<int32_t> &Weights, 
373                       const std::vector<int64_t> &Reserves, 
374                       CAmount InitialSupply, 
375                       CAmount Emitted, 
376                       CAmount Supply, 
377                       uint32_t Flags=FLAG_VALID) : 
378         flags(Flags),
379         currencies(Currencies), 
380         weights(Weights), 
381         reserves(Reserves),
382         initialSupply(InitialSupply), 
383         emitted(Emitted),
384         supply(Supply)
385     {}
386
387     CCurrencyState(const std::vector<unsigned char> &asVector)
388     {
389         FromVector(asVector, *this);
390     }
391
392     CCurrencyState(const UniValue &uni);
393
394     ADD_SERIALIZE_METHODS;
395
396     template <typename Stream, typename Operation>
397     inline void SerializationOp(Stream& s, Operation ser_action) {
398         READWRITE(flags);
399         READWRITE(currencies);        
400         READWRITE(weights);        
401         READWRITE(reserves);        
402         READWRITE(VARINT(initialSupply));
403         READWRITE(VARINT(emitted));
404         READWRITE(VARINT(supply));
405     }
406
407     std::vector<unsigned char> AsVector() const
408     {
409         return ::AsVector(*this);
410     }
411
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);
415
416     cpp_dec_float_50 GetReserveRatio(int32_t reserveIndex=0) const
417     {
418         return cpp_dec_float_50(std::to_string(weights[reserveIndex])) / cpp_dec_float_50("100000000");
419     }
420
421     template<typename cpp_dec_float_type>
422     static bool to_int64(const cpp_dec_float_type &input, int64_t &outval)
423     {
424         std::stringstream ss(input.str(0, std::ios_base::fmtflags::_S_fixed));
425         try
426         {
427             ss >> outval;
428             return true;
429         }
430         catch(const std::exception& e)
431         {
432             return false;
433         }
434     }
435
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;
440
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;
443
444     std::vector<CAmount> PricesInReserve() const;
445
446     // This considers one currency at a time
447     CAmount ConvertAmounts(CAmount inputReserve, CAmount inputFractional, CCurrencyState &newState, int32_t reserveIndex=0) const;
448
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;
453
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;
456
457     CAmount ReserveToNative(CAmount reserveAmount, int32_t reserveIndex) const;
458     CAmount ReserveToNative(const CCurrencyValueMap &reserveAmounts) const;
459
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> &currencies, const std::vector<CAmount> &exchangeRates);
463     static CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<uint160> &currencies, const std::vector<cpp_dec_float_50> &exchangeRates);
464     CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<CAmount> &exchangeRates) const;
465
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;
472
473     UniValue ToUniValue() const;
474
475     bool IsValid() const
476     {
477         return flags & FLAG_VALID;
478     }
479
480     bool IsFractional() const
481     {
482         return flags & FLAG_FRACTIONAL;
483     }
484
485     bool IsRefunding() const
486     {
487         return flags & FLAG_REFUNDING;
488     }
489
490     bool IsPrelaunch() const
491     {
492         return flags & FLAG_PRELAUNCH;
493     }
494
495     void SetPrelaunch(bool newState=true)
496     {
497         if (newState)
498         {
499             flags |= FLAG_PRELAUNCH;
500         }
501         else
502         {
503             flags &= ~FLAG_PRELAUNCH;
504         }
505     }
506
507     void SetRefunding(bool newState=true)
508     {
509         if (newState)
510         {
511             flags |= FLAG_REFUNDING;
512         }
513         else
514         {
515             flags &= ~FLAG_REFUNDING;
516         }
517     }
518
519     std::map<uint160, int32_t> GetReserveMap() const
520     {
521         std::map<uint160, int32_t> retVal;
522         for (int i = 0; i < currencies.size(); i++)
523         {
524             retVal[currencies[i]] = i;
525         }
526         return retVal;
527     }
528 };
529
530 class CCoinbaseCurrencyState : public CCurrencyState
531 {
532 public:
533     CAmount nativeFees;
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
541
542     CCoinbaseCurrencyState() : nativeFees(0), nativeConversionFees(0) {}
543
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),
554         nativeIn(NativeIn),
555         reserveOut(ReserveOut),
556         conversionPrice(ConversionPrice),
557         fees(Fees),
558         conversionFees(ConversionFees)        
559     {
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());
566     }
567
568     CCoinbaseCurrencyState(const UniValue &uni);
569
570     CCoinbaseCurrencyState(const std::vector<unsigned char> asVector)
571     {
572         ::FromVector(asVector, *this);
573     }
574
575     CCoinbaseCurrencyState(const CTransaction &tx, int *pOutIdx=NULL);
576
577     ADD_SERIALIZE_METHODS;
578
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);
585         READWRITE(nativeIn);
586         READWRITE(reserveOut);
587         READWRITE(conversionPrice);
588         READWRITE(fees);
589         READWRITE(conversionFees);
590     }
591
592     std::vector<unsigned char> AsVector() const
593     {
594         return ::AsVector(*this);
595     }
596
597     UniValue ToUniValue() const;
598
599     void ClearForNextBlock()
600     {
601         emitted = 0;
602         nativeFees = 0;
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());
609     }
610
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;
620     
621     template <typename NUMBERVECTOR>
622     NUMBERVECTOR AddVectors(const NUMBERVECTOR &a, const NUMBERVECTOR &b) const
623     {
624         const NUMBERVECTOR *shortVec, *longVec;
625         int64_t count, max;
626         if (a.size() <= b.size())
627         {
628             count = a.size();
629             max = b.size();
630             shortVec = &a;
631             longVec = &b;
632         }
633         else
634         {
635             count = b.size();
636             max = a.size();
637             shortVec = &b;
638             longVec = &a;
639         }
640
641         NUMBERVECTOR ret;
642         ret.reserve(max);
643         for (int i = 0; i < count; i++)
644         {
645             ret[i] = (*longVec)[i] + (*shortVec)[i];
646         }
647         for (int i = count; i < max; i++)
648         {
649             ret[i] = (*longVec)[i];
650         }
651         return ret;
652     }
653 };
654
655 class CReserveInOuts
656 {
657 public:
658     int64_t reserveIn;
659     int64_t reserveOut;
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) {}
670 };
671
672 class CReserveTransactionDescriptor
673 {
674 public:
675     enum {
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"
688     };
689
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
700
701     CReserveTransactionDescriptor() : 
702         flags(0),
703         ptx(NULL),
704         numBuys(0),                             // each limit conversion that is valid before a certain block should account for FILL_OR_KILL_FEE
705         numSells(0),
706         numTransfers(0),
707         nativeIn(0),
708         nativeOut(0),
709         nativeConversionFees(0) {}              // non-zero only if there is a conversion, stored vs. calculated to get exact number with each calculated seperately
710
711     CReserveTransactionDescriptor(const CTransaction &tx, const CCoinsViewCache &view, int32_t nHeight);
712
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; }
724
725     static CAmount CalculateConversionFee(CAmount inputAmount);
726     static CAmount CalculateAdditionalConversionFee(CAmount inputAmount);
727
728     CAmount NativeFees() const
729     {
730         return nativeIn - nativeOut;                                // native out converted does not include conversion
731     }
732
733     CCurrencyValueMap ReserveFees() const
734     {
735         CCurrencyValueMap retFees;
736         for (auto &one : currencies)
737         {
738             CAmount oneFee = one.second.reserveIn - one.second.reserveOut;
739             if (oneFee)
740             {
741                 retFees.valueMap[one.first] = oneFee;
742             }
743         }
744         return retFees;
745     }
746
747     CAmount AllFeesAsNative(const CCurrencyState &currencyState) const;
748     CAmount AllFeesAsNative(const CCurrencyState &currencyState, const std::vector<CAmount> &exchangeRates) const;
749     CCurrencyValueMap AllFeesAsReserve(const CCurrencyState &currencyState, int defaultReserve=0) const;
750     CCurrencyValueMap AllFeesAsReserve(const CCurrencyState &currencyState, const std::vector<CAmount> &exchangeRates, int defaultReserve=0) const;
751
752     // does not check for errors
753     void AddReserveInput(const uint160 &currency, CAmount value);
754     void AddReserveOutput(const uint160 &currency, CAmount value);
755     void AddReserveOutConverted(const uint160 &currency, CAmount value);
756     void AddNativeOutConverted(const uint160 &currency, CAmount value);
757     void AddReserveConversionFees(const uint160 &currency, CAmount value);
758
759     CCurrencyValueMap ReserveInputMap() const;
760     CCurrencyValueMap ReserveOutputMap() const;
761     CCurrencyValueMap ReserveOutConvertedMap() const;
762     CCurrencyValueMap NativeOutConvertedMap() const;
763     CCurrencyValueMap ReserveConversionFeesMap() const;
764
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;
771
772     void AddReserveOutput(const CTokenOutput &ro)
773     {
774         flags |= IS_RESERVE;
775         if (!(flags & IS_IMPORT))
776         {
777             AddReserveOutput(ro.currencyID, ro.nValue);
778         }
779     }
780
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);
783
784     void AddReserveTransfer(CReserveTransfer &rt)
785     {
786         flags |= IS_RESERVE;
787         if (!(flags & IS_IMPORT))
788         {
789             AddReserveOutput(rt.currencyID, rt.nValue + rt.nFees);
790             numTransfers++;
791         }
792     }
793
794     CMutableTransaction &AddConversionInOuts(CMutableTransaction &conversionTx, 
795                                              std::vector<CInputDescriptor> &conversionInputs, 
796                                              const CCurrencyValueMap &exchangeRates=CCurrencyValueMap(), 
797                                              const CCurrencyState *pCurrencyState=nullptr) const;
798
799     bool AddReserveTransferImportOutputs(const uint160 &currencySourceID, 
800                                          const CCurrencyDefinition &importCurrencyDef, 
801                                          const CCoinbaseCurrencyState &importCurrencyState,
802                                          const std::vector<CBaseChainObject *> &exportObjects, 
803                                          std::vector<CTxOut> &vOutputs,
804                                          CCoinbaseCurrencyState *pNewCurrencyState=nullptr);
805 };
806
807 #endif // PBAAS_RESERVES_H
This page took 0.069904 seconds and 4 git commands to generate.