]> Git Repo - VerusCoin.git/blob - src/pbaas/reserves.h
testnet breaking changes - Implement index address, hardening, makefile 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.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     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
55
56     CTokenOutput(const std::vector<unsigned char> &asVector)
57     {
58         FromVector(asVector, *this);
59     }
60
61     CTokenOutput(const UniValue &obj);
62
63     CTokenOutput() : nVersion(VERSION_CURRENT), nValue(0) { }
64
65     CTokenOutput(const uint160 &curID, CAmount value) : nVersion(VERSION_CURRENT), currencyID(curID), nValue(value) { }
66
67     ADD_SERIALIZE_METHODS;
68
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));
74     }
75
76     std::vector<unsigned char> AsVector()
77     {
78         return ::AsVector(*this);
79     }
80
81     UniValue ToUniValue() const;
82
83     bool IsValid() const
84     {
85         // we don't support op returns, value must be in native or reserve
86         return nVersion >= VERSION_FIRSTVALID && nVersion <= VERSION_LASTVALID;
87     }
88 };
89
90 class CReserveTransfer : public CTokenOutput
91 {
92 public:
93     enum EOptions
94     {
95         VALID = 1,
96         CONVERT = 2,
97         PRECONVERT = 4,
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
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 class CReserveDeposit
159 {
160 public:
161     enum
162     {
163         VERSION_INVALID = 0,
164         VERSION_CURRENT = 1,
165         VERSION_FIRSTVALID = 1,
166         VERSION_LASTVALID = 1,
167     };
168
169     uint32_t nVersion;
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
172
173     CReserveDeposit(const std::vector<unsigned char> &asVector)
174     {
175         FromVector(asVector, *this);
176     }
177
178     CReserveDeposit() : nVersion(VERSION_CURRENT) {}
179
180     CReserveDeposit(const uint160 &controllingID, const CCurrencyValueMap &reserveOut) : 
181         controllingCurrencyID(controllingID), reserveValues(reserveOut) {}
182
183     ADD_SERIALIZE_METHODS;
184
185     template <typename Stream, typename Operation>
186     inline void SerializationOp(Stream& s, Operation ser_action) {
187         READWRITE(controllingCurrencyID);
188         READWRITE(reserveValues);
189     }
190
191     std::vector<unsigned char> AsVector()
192     {
193         return ::AsVector(*this);
194     }
195
196     UniValue ToUniValue() const;
197
198     bool IsValid() const
199     {
200         return nVersion >= VERSION_FIRSTVALID && nVersion <= VERSION_LASTVALID;
201     }
202 };
203
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
209 // exchange fees
210 class CReserveExchange : public CTokenOutput
211 {
212 public:
213     // flags
214     enum EFlags
215     {
216         VALID = 1,
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
222     };
223
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;
232
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
236
237     CReserveExchange(const std::vector<unsigned char> &asVector)
238     {
239         FromVector(asVector, *this);
240     }
241
242     CReserveExchange() : CTokenOutput(), nLimit(0), nValidBefore(0) { }
243
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) {}
246
247     CReserveExchange(const UniValue &uni);
248     CReserveExchange(const CTransaction &tx);
249
250     ADD_SERIALIZE_METHODS;
251
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);
258     }
259
260     std::vector<unsigned char> AsVector()
261     {
262         return ::AsVector(*this);
263     }
264
265     bool IsValid() const
266     {
267         // this needs an actual check
268         return CTokenOutput::IsValid();
269     }
270
271     UniValue ToUniValue() const;
272
273     bool IsExpired(int32_t height)
274     {
275         return height >= nValidBefore;
276     }
277 };
278
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
283 {
284 public:
285     static const uint32_t VERSION_INVALID = 0;
286     static const uint32_t VERSION_CURRENT = 1;
287     static const uint32_t VERSION_LAST = 1;
288     uint32_t nVersion;
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
293
294     CCrossChainImport() : nVersion(VERSION_INVALID) {}
295     CCrossChainImport(const uint160 &sysID, const uint160 &importCID, const CCurrencyValueMap &ImportValue, const CCurrencyValueMap &InitialReserveOutput=CCurrencyValueMap()) : 
296                         nVersion(VERSION_CURRENT),
297                         systemID(sysID),
298                         importCurrencyID(importCID),
299                         importValue(ImportValue),
300                         totalReserveOutMap(InitialReserveOutput) { }
301
302     CCrossChainImport(const std::vector<unsigned char> &asVector)
303     {
304         ::FromVector(asVector, *this);
305     }
306
307     CCrossChainImport(const CTransaction &tx, int32_t *pOutNum=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(importCurrencyID);
316         READWRITE(importValue);
317         READWRITE(totalReserveOutMap);
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 && nVersion <= VERSION_LAST && !systemID.IsNull();
328     }
329
330     UniValue ToUniValue() const;
331 };
332
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
335 {
336 public:
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;
343     uint32_t nVersion;
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
348
349     CCrossChainExport() : nVersion(VERSION_INVALID), numInputs(0) {}
350
351     CCrossChainExport(const std::vector<unsigned char> &asVector)
352     {
353         FromVector(asVector, *this);
354     }
355
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) {}
358
359     CCrossChainExport(const CTransaction &tx, int32_t *pCCXOutputNum=nullptr);
360
361     ADD_SERIALIZE_METHODS;
362
363     template <typename Stream, typename Operation>
364     inline void SerializationOp(Stream& s, Operation ser_action) {
365         READWRITE(nVersion);
366         READWRITE(systemID);
367         READWRITE(numInputs);
368         READWRITE(totalAmounts);
369         READWRITE(totalFees);
370     }
371
372     std::vector<unsigned char> AsVector()
373     {
374         return ::AsVector(*this);
375     }
376
377     bool IsValid() const
378     {
379         return nVersion > VERSION_INVALID && 
380                nVersion <= VERSION_LAST && 
381                !systemID.IsNull();
382     }
383
384     static CCurrencyValueMap CalculateExportFee(const CCurrencyValueMap &fees, int numIn);
385     CCurrencyValueMap CalculateExportFee() const;
386
387     CCurrencyValueMap CalculateImportFee() const;
388     
389     UniValue ToUniValue() const;
390 };
391
392 class CCurrencyState
393 {
394 public:
395     enum FLAGS {
396         FLAG_VALID = 1,
397         FLAG_FRACTIONAL = 2,
398         FLAG_REFUNDING = 4,
399         FLAG_PRELAUNCH = 8
400     };
401     enum CONSTANTS {
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
407     };
408
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
414
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
418
419     //std::vector<CAmount> Reserves; // reserve currencies amounts controlled by this fractional chain - only present for reserve currencies, currency IDs are in chain definition
420
421     CCurrencyState() : flags(0), initialSupply(0), emitted(0), supply(0) {}
422
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, 
428                    CAmount Emitted, 
429                    CAmount Supply, 
430                    uint32_t Flags=FLAG_VALID) : 
431         flags(Flags),
432         currencyID(cID),
433         currencies(Currencies), 
434         weights(Weights), 
435         reserves(Reserves),
436         initialSupply(InitialSupply), 
437         emitted(Emitted),
438         supply(Supply)
439     {}
440
441     CCurrencyState(const std::vector<unsigned char> &asVector)
442     {
443         FromVector(asVector, *this);
444     }
445
446     CCurrencyState(const UniValue &uni);
447
448     ADD_SERIALIZE_METHODS;
449
450     template <typename Stream, typename Operation>
451     inline void SerializationOp(Stream& s, Operation ser_action) {
452         READWRITE(flags);
453         READWRITE(currencyID);        
454         READWRITE(currencies);        
455         READWRITE(weights);        
456         READWRITE(reserves);        
457         READWRITE(VARINT(initialSupply));
458         READWRITE(VARINT(emitted));
459         READWRITE(VARINT(supply));
460     }
461
462     std::vector<unsigned char> AsVector() const
463     {
464         return ::AsVector(*this);
465     }
466
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);
470
471     cpp_dec_float_50 GetReserveRatio(int32_t reserveIndex=0) const
472     {
473         return cpp_dec_float_50(std::to_string(weights[reserveIndex])) / cpp_dec_float_50("100000000");
474     }
475
476     template<typename cpp_dec_float_type>
477     static bool to_int64(const cpp_dec_float_type &input, int64_t &outval)
478     {
479         std::stringstream ss(input.str(0, std::ios_base::fmtflags::_S_fixed));
480         try
481         {
482             ss >> outval;
483             return true;
484         }
485         catch(const std::exception& e)
486         {
487             return false;
488         }
489     }
490
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;
495
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;
498
499     std::vector<CAmount> PricesInReserve() const;
500
501     // This considers one currency at a time
502     CAmount ConvertAmounts(CAmount inputReserve, CAmount inputFractional, CCurrencyState &newState, int32_t reserveIndex=0) const;
503
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;
508
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;
511
512     CAmount ReserveToNative(CAmount reserveAmount, int32_t reserveIndex) const;
513     CAmount ReserveToNative(const CCurrencyValueMap &reserveAmounts) const;
514
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> &currencies, const std::vector<CAmount> &exchangeRates);
518     static CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<uint160> &currencies, const std::vector<cpp_dec_float_50> &exchangeRates);
519     CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<CAmount> &exchangeRates) const;
520
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;
527
528     UniValue ToUniValue() const;
529
530     uint160 GetID() const { return currencyID; }
531
532     bool IsValid() const
533     {
534         return !currencyID.IsNull() && flags & FLAG_VALID;
535     }
536
537     bool IsFractional() const
538     {
539         return flags & FLAG_FRACTIONAL;
540     }
541
542     bool IsRefunding() const
543     {
544         return flags & FLAG_REFUNDING;
545     }
546
547     bool IsPrelaunch() const
548     {
549         return flags & FLAG_PRELAUNCH;
550     }
551
552     void SetPrelaunch(bool newState=true)
553     {
554         if (newState)
555         {
556             flags |= FLAG_PRELAUNCH;
557         }
558         else
559         {
560             flags &= ~FLAG_PRELAUNCH;
561         }
562     }
563
564     void SetRefunding(bool newState=true)
565     {
566         if (newState)
567         {
568             flags |= FLAG_REFUNDING;
569         }
570         else
571         {
572             flags &= ~FLAG_REFUNDING;
573         }
574     }
575
576     std::map<uint160, int32_t> GetReserveMap() const
577     {
578         std::map<uint160, int32_t> retVal;
579         for (int i = 0; i < currencies.size(); i++)
580         {
581             retVal[currencies[i]] = i;
582         }
583         return retVal;
584     }
585 };
586
587 class CCoinbaseCurrencyState : public CCurrencyState
588 {
589 public:
590     CAmount nativeFees;
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
598
599     CCoinbaseCurrencyState() : nativeFees(0), nativeConversionFees(0) {}
600
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),
611         nativeIn(NativeIn),
612         reserveOut(ReserveOut),
613         conversionPrice(ConversionPrice),
614         fees(Fees),
615         conversionFees(ConversionFees)        
616     {
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());
623     }
624
625     CCoinbaseCurrencyState(const UniValue &uni);
626
627     CCoinbaseCurrencyState(const std::vector<unsigned char> asVector)
628     {
629         ::FromVector(asVector, *this);
630     }
631
632     CCoinbaseCurrencyState(const CTransaction &tx, int *pOutIdx=NULL);
633
634     ADD_SERIALIZE_METHODS;
635
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);
642         READWRITE(nativeIn);
643         READWRITE(reserveOut);
644         READWRITE(conversionPrice);
645         READWRITE(fees);
646         READWRITE(conversionFees);
647     }
648
649     std::vector<unsigned char> AsVector() const
650     {
651         return ::AsVector(*this);
652     }
653
654     UniValue ToUniValue() const;
655
656     void ClearForNextBlock()
657     {
658         emitted = 0;
659         nativeFees = 0;
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());
666     }
667
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;
677     
678     template <typename NUMBERVECTOR>
679     NUMBERVECTOR AddVectors(const NUMBERVECTOR &a, const NUMBERVECTOR &b) const
680     {
681         const NUMBERVECTOR *shortVec, *longVec;
682         int64_t count, max;
683         if (a.size() <= b.size())
684         {
685             count = a.size();
686             max = b.size();
687             shortVec = &a;
688             longVec = &b;
689         }
690         else
691         {
692             count = b.size();
693             max = a.size();
694             shortVec = &b;
695             longVec = &a;
696         }
697
698         NUMBERVECTOR ret;
699         ret.reserve(max);
700         for (int i = 0; i < count; i++)
701         {
702             ret[i] = (*longVec)[i] + (*shortVec)[i];
703         }
704         for (int i = count; i < max; i++)
705         {
706             ret[i] = (*longVec)[i];
707         }
708         return ret;
709     }
710 };
711
712 class CReserveInOuts
713 {
714 public:
715     int64_t reserveIn;
716     int64_t reserveOut;
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) {}
727 };
728
729 class CReserveTransactionDescriptor
730 {
731 public:
732     enum {
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"
745     };
746
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
757
758     CReserveTransactionDescriptor() : 
759         flags(0),
760         ptx(NULL),
761         numBuys(0),                             // each limit conversion that is valid before a certain block should account for FILL_OR_KILL_FEE
762         numSells(0),
763         numTransfers(0),
764         nativeIn(0),
765         nativeOut(0),
766         nativeConversionFees(0) {}              // non-zero only if there is a conversion, stored vs. calculated to get exact number with each calculated seperately
767
768     CReserveTransactionDescriptor(const CTransaction &tx, const CCoinsViewCache &view, int32_t nHeight);
769
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; }
781
782     static CAmount CalculateConversionFee(CAmount inputAmount);
783     static CAmount CalculateAdditionalConversionFee(CAmount inputAmount);
784
785     CAmount TotalNativeOutConverted() const
786     {
787         CAmount nativeOutConverted = 0;
788         for (auto &one : currencies)
789         {
790             nativeOutConverted += one.second.nativeOutConverted;
791         }
792         return nativeOutConverted;
793     }
794
795     CAmount NativeFees() const
796     {
797         return nativeIn - nativeOut;     // native out converted does not include conversion
798     }
799
800     CCurrencyValueMap ReserveFees() const
801     {
802         CCurrencyValueMap retFees;
803         for (auto &one : currencies)
804         {
805             CAmount oneFee = one.second.reserveIn - (one.second.reserveOut - one.second.reserveOutConverted);
806             if (oneFee)
807             {
808                 retFees.valueMap[one.first] = oneFee;
809             }
810         }
811         return retFees;
812     }
813
814     CAmount AllFeesAsNative(const CCurrencyState &currencyState) const;
815     CAmount AllFeesAsNative(const CCurrencyState &currencyState, const std::vector<CAmount> &exchangeRates) const;
816     CCurrencyValueMap AllFeesAsReserve(const CCurrencyState &currencyState, int defaultReserve=0) const;
817     CCurrencyValueMap AllFeesAsReserve(const CCurrencyState &currencyState, const std::vector<CAmount> &exchangeRates, int defaultReserve=0) const;
818
819     // does not check for errors
820     void AddReserveInput(const uint160 &currency, CAmount value);
821     void AddReserveOutput(const uint160 &currency, CAmount value);
822     void AddReserveOutConverted(const uint160 &currency, CAmount value);
823     void AddNativeOutConverted(const uint160 &currency, CAmount value);
824     void AddReserveConversionFees(const uint160 &currency, CAmount value);
825
826     CCurrencyValueMap ReserveInputMap() const;
827     CCurrencyValueMap ReserveOutputMap() const;
828     CCurrencyValueMap ReserveOutConvertedMap() const;
829     CCurrencyValueMap NativeOutConvertedMap() const;
830     CCurrencyValueMap ReserveConversionFeesMap() const;
831
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;
838
839     void AddReserveOutput(const CTokenOutput &ro)
840     {
841         flags |= IS_RESERVE;
842         if (!(flags & IS_IMPORT))
843         {
844             AddReserveOutput(ro.currencyID, ro.nValue);
845         }
846     }
847
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);
850
851     void AddReserveTransfer(CReserveTransfer &rt)
852     {
853         flags |= IS_RESERVE;
854         if (!(flags & IS_IMPORT))
855         {
856             AddReserveOutput(rt.currencyID, rt.nValue + rt.nFees);
857             numTransfers++;
858         }
859     }
860
861     CMutableTransaction &AddConversionInOuts(CMutableTransaction &conversionTx, 
862                                              std::vector<CInputDescriptor> &conversionInputs, 
863                                              const CCurrencyValueMap &exchangeRates=CCurrencyValueMap(), 
864                                              const CCurrencyState *pCurrencyState=nullptr) const;
865
866     bool AddReserveTransferImportOutputs(const uint160 &currencySourceID, 
867                                          const CCurrencyDefinition &importCurrencyDef, 
868                                          const CCoinbaseCurrencyState &importCurrencyState,
869                                          const std::vector<CBaseChainObject *> &exportObjects, 
870                                          std::vector<CTxOut> &vOutputs,
871                                          CCoinbaseCurrencyState *pNewCurrencyState=nullptr);
872 };
873
874 #endif // PBAAS_RESERVES_H
This page took 0.07471 seconds and 4 git commands to generate.