]> Git Repo - VerusCoin.git/blame - src/pbaas/reserves.h
Move CCurrencyValueMap to the lighter weight, crosschainrpc module
[VerusCoin.git] / src / pbaas / reserves.h
CommitLineData
a6e612cc
MT
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>
56fe75cb 16#include <univalue/include/univalue.h>
e7e14f44 17#include "pbaas/crosschainrpc.h"
56fe75cb 18#include "arith_uint256.h"
a6e612cc 19#include <boost/multiprecision/cpp_dec_float.hpp>
989b1de1 20#include "librustzcash.h"
e7e14f44 21#include "pubkey.h"
56fe75cb 22#include "amount.h"
f88ddf77 23#include <map>
a6e612cc 24
56fe75cb 25#ifndef SATOSHIDEN
26#define SATOSHIDEN ((uint64_t)100000000L)
27#endif
28
a6e612cc 29using boost::multiprecision::cpp_dec_float_50;
e7c700b5 30class CCoinsViewCache;
0574c740 31class CInputDescriptor;
15e4d481 32class CBaseChainObject;
56fe75cb 33class CTransaction;
34class CMutableTransaction;
35class CTxOut;
36class CReserveTransactionDescriptor;
c8c677c9 37class CCurrencyState;
56fe75cb 38
f88ddf77 39// reserve output is a special kind of token output that does not have to carry it's identifier, as it
989b1de1 40// is always assumed to be the reserve currency of the current chain.
56fe75cb 41class CTokenOutput
a6e612cc
MT
42{
43public:
56fe75cb 44 enum
45 {
46 VERSION_INVALID = 0,
47 VERSION_CURRENT = 1,
48 VERSION_FIRSTVALID = 1,
49 VERSION_LASTVALID = 1,
50 };
a6e612cc 51
56fe75cb 52 static std::vector<uint160> *reserveIDs;
53
54 uint32_t nVersion; // information about this currency
f88ddf77 55 uint160 currencyID; // currency ID
56fe75cb 56 CAmount nValue; // amount of input reserve coins this UTXO represents before any conversion
a6e612cc 57
56fe75cb 58 CTokenOutput(const std::vector<unsigned char> &asVector)
a6e612cc
MT
59 {
60 FromVector(asVector, *this);
61 }
62
56fe75cb 63 CTokenOutput(const UniValue &obj);
a6e612cc 64
56fe75cb 65 CTokenOutput() : nVersion(VERSION_CURRENT), nValue(0) { }
f88ddf77 66
56fe75cb 67 CTokenOutput(const uint160 &curID, CAmount value) : nVersion(VERSION_CURRENT), currencyID(curID), nValue(value) { }
a6e612cc
MT
68
69 ADD_SERIALIZE_METHODS;
70
71 template <typename Stream, typename Operation>
72 inline void SerializationOp(Stream& s, Operation ser_action) {
56fe75cb 73 READWRITE(VARINT(nVersion));
74 READWRITE(currencyID);
a6e612cc 75 READWRITE(VARINT(nValue));
a6e612cc
MT
76 }
77
78 std::vector<unsigned char> AsVector()
79 {
80 return ::AsVector(*this);
81 }
82
41f170fd
MT
83 UniValue ToUniValue() const;
84
a613ac6c 85 bool IsValid() const
a6e612cc 86 {
b7c685b8 87 // we don't support op returns, value must be in native or reserve
5781675d 88 return nVersion >= VERSION_FIRSTVALID && nVersion <= VERSION_LASTVALID;
a6e612cc
MT
89 }
90};
91
56fe75cb 92class CReserveTransfer : public CTokenOutput
a6e612cc
MT
93{
94public:
56fe75cb 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
15197dca 102 MINT_CURRENCY = 0x20, // set when this output is being minted on import
103 PREALLOCATE = 0x40 // combined with minting for pre-allocation of currency
56fe75cb 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 };
a6e612cc 110
56fe75cb 111 static const CAmount DEFAULT_PER_STEP_FEE = 10000; // default fee for each step of each transfer (initial mining, transfer, mining on new chain)
989b1de1 112
56fe75cb 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
2f416b17 115 uint160 destCurrencyID; // system to export to, which may represent a PBaaS chain or external bridge
56fe75cb 116 CTransferDestination destination; // system specific address to send funds to on the target chain
989b1de1
MT
117
118 CReserveTransfer(const std::vector<unsigned char> &asVector)
a6e612cc
MT
119 {
120 FromVector(asVector, *this);
121 }
122
56fe75cb 123 CReserveTransfer() : CTokenOutput(), flags(0), nFees(0) { }
a6e612cc 124
f7917c6b 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) { }
a6e612cc
MT
127
128 ADD_SERIALIZE_METHODS;
129
130 template <typename Stream, typename Operation>
131 inline void SerializationOp(Stream& s, Operation ser_action) {
56fe75cb 132 READWRITE(*(CTokenOutput *)this);
133 READWRITE(VARINT(flags));
989b1de1 134 READWRITE(VARINT(nFees));
f7917c6b 135 READWRITE(destCurrencyID);
989b1de1 136 READWRITE(destination);
a6e612cc
MT
137 }
138
139 std::vector<unsigned char> AsVector()
140 {
141 return ::AsVector(*this);
142 }
143
cb265a66 144 UniValue ToUniValue() const;
145
2f416b17 146 CCurrencyValueMap CalculateFee(uint32_t flags, CAmount transferTotal) const;
147
148 static CAmount CalculateTransferFee(const CTransferDestination &destination);
56fe75cb 149
150 CAmount CalculateTransferFee() const;
951413c7 151
a613ac6c 152 bool IsValid() const
a6e612cc 153 {
56fe75cb 154 return CTokenOutput::IsValid() && (nFees > 0 || flags & FEE_OUTPUT) && destination.destination.size();
a6e612cc
MT
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
56fe75cb 164class CReserveExchange : public CTokenOutput
a6e612cc
MT
165{
166public:
a6e612cc 167 // flags
56fe75cb 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 };
a6e612cc
MT
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
e7e14f44
MT
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
56fe75cb 181 static const CAmount SUCCESS_FEE = 25000;
e7e14f44 182 static const CAmount MIN_SUCCESS_FEE = 50000;
a6e612cc 183 static const CAmount MIN_PARTIAL = 10000000; // making partial fill minimum the number at which minimum fee meets standard percent fee,
e7c700b5 184 static const CAmount MIN_NET_CONVERSION = 10000000; // minimum conversion for input
e7c700b5 185 static const CAmount FILL_OR_KILL_FEE = 10000;
a6e612cc 186
56fe75cb 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
a6e612cc
MT
190
191 CReserveExchange(const std::vector<unsigned char> &asVector)
192 {
193 FromVector(asVector, *this);
194 }
195
56fe75cb 196 CReserveExchange() : CTokenOutput(), nLimit(0), nValidBefore(0) { }
a6e612cc 197
56fe75cb 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) {}
a6e612cc 200
56fe75cb 201 CReserveExchange(const UniValue &uni);
202 CReserveExchange(const CTransaction &tx);
a6e612cc
MT
203
204 ADD_SERIALIZE_METHODS;
205
206 template <typename Stream, typename Operation>
207 inline void SerializationOp(Stream& s, Operation ser_action) {
56fe75cb 208 READWRITE(*(CTokenOutput *)this);
209 READWRITE(VARINT(flags));
a6e612cc
MT
210 READWRITE(VARINT(nLimit));
211 READWRITE(nValidBefore);
212 }
213
214 std::vector<unsigned char> AsVector()
215 {
216 return ::AsVector(*this);
217 }
218
a613ac6c 219 bool IsValid() const
a6e612cc
MT
220 {
221 // this needs an actual check
56fe75cb 222 return CTokenOutput::IsValid();
a6e612cc
MT
223 }
224
cb265a66 225 UniValue ToUniValue() const;
226
a6e612cc
MT
227 bool IsExpired(int32_t height)
228 {
229 return height >= nValidBefore;
230 }
231};
232
56fe75cb 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
cdbadc7f 236class CCrossChainImport
237{
238public:
56fe75cb 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
0ab273d2 245 CCurrencyValueMap totalReserveOutMap; // all non-native currencies being held in this thread and released on import
56fe75cb 246
247 CCrossChainImport() : nVersion(VERSION_INVALID) {}
0ab273d2 248 CCrossChainImport(const uint160 &cID, const CCurrencyValueMap &ImportValue, const CCurrencyValueMap &InitialReserveOutput=CCurrencyValueMap()) :
249 nVersion(VERSION_CURRENT), systemID(cID), importValue(ImportValue), totalReserveOutMap(InitialReserveOutput) { }
cdbadc7f 250
251 CCrossChainImport(const std::vector<unsigned char> &asVector)
252 {
253 ::FromVector(asVector, *this);
254 }
255
0ab273d2 256 CCrossChainImport(const CTransaction &tx, int32_t *pOutNum=nullptr);
cdbadc7f 257
258 ADD_SERIALIZE_METHODS;
259
260 template <typename Stream, typename Operation>
261 inline void SerializationOp(Stream& s, Operation ser_action) {
56fe75cb 262 READWRITE(nVersion);
263 READWRITE(systemID);
264 READWRITE(importValue);
0ab273d2 265 READWRITE(totalReserveOutMap);
cdbadc7f 266 }
267
268 std::vector<unsigned char> AsVector()
269 {
270 return ::AsVector(*this);
271 }
272
273 bool IsValid() const
274 {
2f416b17 275 return nVersion > VERSION_INVALID && nVersion <= VERSION_LAST && !systemID.IsNull();
cdbadc7f 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.
282class CCrossChainExport
283{
284public:
285 static const int MIN_BLOCKS = 10;
286 static const int MIN_INPUTS = 10;
287 static const int MAX_EXPORT_INPUTS = 50;
56fe75cb 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
56a7b665 294 CCurrencyValueMap totalAmounts; // total amount of inputs of each currency, including fees
56fe75cb 295 CCurrencyValueMap totalFees; // total amount of fees of each currency to split between miner on exporting chain and importing chain
cdbadc7f 296
56fe75cb 297 CCrossChainExport() : nVersion(VERSION_INVALID), numInputs(0) {}
cdbadc7f 298
299 CCrossChainExport(const std::vector<unsigned char> &asVector)
300 {
301 FromVector(asVector, *this);
302 }
303
56fe75cb 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) {}
cdbadc7f 306
56fe75cb 307 CCrossChainExport(const CTransaction &tx, int32_t *pCCXOutputNum=nullptr);
cdbadc7f 308
309 ADD_SERIALIZE_METHODS;
310
311 template <typename Stream, typename Operation>
312 inline void SerializationOp(Stream& s, Operation ser_action) {
56fe75cb 313 READWRITE(nVersion);
314 READWRITE(systemID);
cdbadc7f 315 READWRITE(numInputs);
56fe75cb 316 READWRITE(totalAmounts);
317 READWRITE(totalFees);
cdbadc7f 318 }
319
320 std::vector<unsigned char> AsVector()
321 {
322 return ::AsVector(*this);
323 }
324
325 bool IsValid() const
326 {
56fe75cb 327 return nVersion > VERSION_INVALID &&
328 nVersion <= VERSION_LAST &&
c8c677c9 329 !systemID.IsNull();
cdbadc7f 330 }
331
815a42a6 332 static CCurrencyValueMap CalculateExportFee(const CCurrencyValueMap &fees, int numIn);
56fe75cb 333 CCurrencyValueMap CalculateExportFee() const;
cdbadc7f 334
56fe75cb 335 CCurrencyValueMap CalculateImportFee() const;
cdbadc7f 336
337 UniValue ToUniValue() const;
338};
339
c8c677c9 340class CCurrencyState
f88ddf77 341{
342public:
56fe75cb 343 enum {
344 VALID = 1,
345 ISRESERVE = 2,
346 MIN_RESERVE_RATIO = 1000000, // we will not start a chain with less than 1% reserve ratio in any single currency
347 MAX_RESERVE_RATIO = 100000000, // we will not start a chain with greater than 100% reserve ratio
348 SHUTDOWN_RESERVE_RATIO = 500000, // if we hit this reserve ratio in any currency, initiate chain shutdown
349 CONVERSION_TX_SIZE_MIN = 1024, // minimum size accounted for in a conversion transaction
350 MAX_RESERVE_CURRENCIES = 10 // maximum number of reserve currencies that can underly a fractional reserve
351 };
f88ddf77 352
353 uint32_t flags; // currency flags (valid, reserve currency, etc.)
354
56fe75cb 355 std::vector<uint160> currencies; // the ID in uin160 form (maps to CIdentityID) if each currency in the reserve
356 std::vector<int32_t> weights; // current, individual weights for all currencies to use in calculations
357 std::vector<int64_t> reserves; // total amount of reserves in each currency
f88ddf77 358
56fe75cb 359 int64_t initialSupply; // initial premine + pre-converted coins
360 int64_t emitted; // emitted coins reduce the reserve ratio and are used to calculate current ratio
361 CAmount supply; // current supply: total of initial, all emitted, and all purchased coins
f88ddf77 362
363 //std::vector<CAmount> Reserves; // reserve currencies amounts controlled by this fractional chain - only present for reserve currencies, currency IDs are in chain definition
364
c8c677c9 365 CCurrencyState() : flags(0), initialSupply(0), emitted(0), supply(0) {}
f88ddf77 366
c8c677c9 367 CCurrencyState(const std::vector<uint160> &Currencies,
56fe75cb 368 const std::vector<int32_t> &Weights,
369 const std::vector<int64_t> &Reserves,
370 CAmount InitialSupply,
371 CAmount Emitted,
372 CAmount Supply,
373 uint32_t Flags=VALID) :
f88ddf77 374 flags(Flags), supply(Supply), initialSupply(InitialSupply), emitted(Emitted), weights(Weights), reserves(Reserves)
56fe75cb 375 {}
f88ddf77 376
c8c677c9 377 CCurrencyState(const std::vector<unsigned char> &asVector)
f88ddf77 378 {
379 FromVector(asVector, *this);
380 }
381
c8c677c9 382 CCurrencyState(const UniValue &uni);
f88ddf77 383
384 ADD_SERIALIZE_METHODS;
385
386 template <typename Stream, typename Operation>
387 inline void SerializationOp(Stream& s, Operation ser_action) {
388 READWRITE(flags);
389 READWRITE(currencies);
390 READWRITE(weights);
391 READWRITE(reserves);
f88ddf77 392 READWRITE(VARINT(initialSupply));
393 READWRITE(VARINT(emitted));
394 READWRITE(VARINT(supply));
395 }
396
397 std::vector<unsigned char> AsVector() const
398 {
399 return ::AsVector(*this);
400 }
401
402 // this should be done no more than once to prepare a currency state to be moved to the next state
403 // emission occurs for a block before any conversion or exchange and that impact on the currency state is calculated
c8c677c9 404 CCurrencyState &UpdateWithEmission(CAmount emitted);
f88ddf77 405
56fe75cb 406 cpp_dec_float_50 GetReserveRatio(int32_t reserveIndex=0) const
f88ddf77 407 {
56fe75cb 408 return cpp_dec_float_50(std::to_string(weights[reserveIndex])) / cpp_dec_float_50("100000000");
f88ddf77 409 }
410
411 template<typename cpp_dec_float_type>
412 static bool to_int64(const cpp_dec_float_type &input, int64_t &outval)
413 {
414 std::stringstream ss(input.str(0));
415 try
416 {
417 ss >> outval;
418 return true;
419 }
420 catch(const std::exception& e)
421 {
422 return false;
423 }
424 }
425
426 CAmount PriceInReserve(int32_t reserveIndex=0) const
427 {
428 if (reserveIndex >= reserves.size())
429 {
430 return 0;
431 }
56fe75cb 432 if (supply == 0 || weights[reserveIndex] == 0)
f88ddf77 433 {
56fe75cb 434 return weights[reserveIndex];
f88ddf77 435 }
436 arith_uint256 Supply(supply);
437
438 arith_uint256 Reserve(reserves[reserveIndex]);
439
56fe75cb 440 arith_uint256 Ratio(weights[reserveIndex]);
f88ddf77 441
56fe75cb 442 arith_uint256 BigSatoshi(SATOSHIDEN);
f88ddf77 443
56fe75cb 444 return ((Reserve * arith_uint256(SATOSHIDEN) * arith_uint256(SATOSHIDEN)) / (Supply * Ratio)).GetLow64();
f88ddf77 445 }
446
447 // return the current price of the fractional reserve in the reserve currency in Satoshis
448 cpp_dec_float_50 GetPriceInReserve(int32_t reserveIndex=0) const
449 {
450 return cpp_dec_float_50(PriceInReserve(reserveIndex));
451 }
452
56fe75cb 453 std::vector<CAmount> PricesInReserve() const
454 {
455 std::vector<CAmount> retVal(currencies.size());
456 for (int i = 0; i < currencies.size(); i++)
457 {
458 retVal[i] = PriceInReserve(i);
459 }
460 return retVal;
461 }
462
463 // This considers one currency at a time
c8c677c9 464 CAmount ConvertAmounts(CAmount inputReserve, CAmount inputFractional, CCurrencyState &newState, int32_t reserveIndex=0) const;
f88ddf77 465
466 // convert amounts for multi-reserve fractional reserve currencies
467 // one entry in the vector for each currency in and one fractional input for each
468 // currency expected as output
c8c677c9 469 std::vector<CAmount> ConvertAmounts(const std::vector<CAmount> &inputReserve, const std::vector<CAmount> &inputFractional, CCurrencyState &newState) const;
f88ddf77 470
471 CAmount CalculateConversionFee(CAmount inputAmount, bool convertToNative = false, int32_t reserveIndex=0) const;
472 CAmount ReserveFeeToNative(CAmount inputAmount, CAmount outputAmount, int32_t reserveIndex=0) const;
473
56fe75cb 474 CAmount ReserveToNative(CAmount reserveAmount, int32_t reserveIndex) const
475 {
476 static arith_uint256 bigSatoshi(SATOSHIDEN);
477 arith_uint256 bigAmount(reserveAmount);
478
479 int64_t price = PriceInReserve(reserveIndex);
480 bigAmount = price ? (bigAmount * bigSatoshi) / arith_uint256(price) : 0;
481
482 return bigAmount.GetLow64();
483 }
484
485 CAmount ReserveToNative(const CCurrencyValueMap &reserveAmounts) const
486 {
487 CAmount nativeOut = 0;
488 for (int i = 0; i < currencies.size(); i++)
489 {
490 auto it = reserveAmounts.valueMap.find(currencies[i]);
491 if (it != reserveAmounts.valueMap.end())
492 {
493 nativeOut += ReserveToNative(it->second, i);
494 }
495 }
3b45a268 496 return nativeOut;
56fe75cb 497 }
498
56fe75cb 499 CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<CAmount> &exchangeRates) const;
f88ddf77 500 static CAmount ReserveToNativeRaw(CAmount reserveAmount, CAmount exchangeRate);
56fe75cb 501 static CAmount ReserveToNativeRaw(const CCurrencyValueMap &reserveAmounts, const std::vector<uint160> &currencies, const std::vector<CAmount> &exchangeRates);
f88ddf77 502
503 CAmount NativeToReserve(CAmount nativeAmount, int32_t reserveIndex=0) const
504 {
56fe75cb 505 static arith_uint256 bigSatoshi(SATOSHIDEN);
f88ddf77 506 arith_uint256 bigAmount(nativeAmount);
507 arith_uint256 price = arith_uint256(PriceInReserve());
508 return ((bigAmount * arith_uint256(price)) / bigSatoshi).GetLow64();
509 }
510
56fe75cb 511 const CCurrencyValueMap &NativeToReserve(std::vector<CAmount> nativeAmount, int32_t reserveIndex=0) const;
512 static CAmount NativeToReserveRaw(CAmount nativeAmount, CAmount exchangeRate);
513 CCurrencyValueMap NativeToReserveRaw(const std::vector<CAmount> &, const std::vector<CAmount> &exchangeRates) const;
f88ddf77 514
515 UniValue ToUniValue() const;
516
517 bool IsValid() const
518 {
c8c677c9 519 return flags & CCurrencyState::VALID;
f88ddf77 520 }
521
522 bool IsReserve() const
523 {
c8c677c9 524 return flags & CCurrencyState::ISRESERVE;
f88ddf77 525 }
526
527 std::map<uint160, int32_t> GetReserveMap() const
528 {
529 std::map<uint160, int32_t> retVal;
530 for (int i = 0; i < currencies.size(); i++)
531 {
532 retVal[currencies[i]] = i;
533 }
534 return retVal;
535 }
536};
537
c8c677c9 538class CCoinbaseCurrencyState : public CCurrencyState
a6e612cc
MT
539{
540public:
56fe75cb 541 CAmount nativeFees;
542 CAmount nativeConversionFees;
543 std::vector<CAmount> reserveIn; // reserve currency converted to native
544 std::vector<CAmount> nativeIn; // native currency converted to reserve
545 std::vector<CAmount> reserveOut; // output can have both normal and reserve output value, if non-0, this is spent by the required output transactions
546 std::vector<CAmount> conversionPrice; // calculated price in reserve for all conversions * 100000000
547 std::vector<CAmount> fees; // fee values in native (or reserve if specified) coins for reserve transaction fees for the block
548 std::vector<CAmount> conversionFees; // total of only conversion fees, which will accrue to the conversion transaction
549
550 CCoinbaseCurrencyState() : nativeFees(0), nativeConversionFees(0) {}
551
c8c677c9 552 CCoinbaseCurrencyState(const CCurrencyState &CurrencyState,
56fe75cb 553 CAmount NativeFees=0, CAmount NativeConversionFees=0,
554 const std::vector<CAmount> &ReserveIn=std::vector<CAmount>(),
555 const std::vector<CAmount> &NativeIn=std::vector<CAmount>(),
556 const std::vector<CAmount> &ReserveOut=std::vector<CAmount>(),
557 const std::vector<CAmount> &ConversionPrice=std::vector<CAmount>(),
558 const std::vector<CAmount> &Fees=std::vector<CAmount>(),
559 const std::vector<CAmount> &ConversionFees=std::vector<CAmount>()) :
c8c677c9 560 CCurrencyState(CurrencyState), nativeFees(NativeFees), nativeConversionFees(NativeConversionFees)
56fe75cb 561 {
562 if (!reserveIn.size()) reserveIn = std::vector<CAmount>(currencies.size());
563 if (!nativeIn.size()) nativeIn = std::vector<CAmount>(currencies.size());
564 if (!reserveOut.size()) reserveOut = std::vector<CAmount>(currencies.size());
565 if (!conversionPrice.size()) conversionPrice = std::vector<CAmount>(currencies.size());
566 if (!fees.size()) fees = std::vector<CAmount>(currencies.size());
567 if (!conversionFees.size()) conversionFees = std::vector<CAmount>(currencies.size());
a6e612cc 568 }
e7e14f44 569
56fe75cb 570 CCoinbaseCurrencyState(const UniValue &uni);
571
572 CCoinbaseCurrencyState(const std::vector<unsigned char> asVector)
e7e14f44 573 {
56fe75cb 574 ::FromVector(asVector, *this);
e7e14f44
MT
575 }
576
56fe75cb 577 CCoinbaseCurrencyState(const CTransaction &tx, int *pOutIdx=NULL);
a6e612cc
MT
578
579 ADD_SERIALIZE_METHODS;
580
581 template <typename Stream, typename Operation>
582 inline void SerializationOp(Stream& s, Operation ser_action) {
c8c677c9 583 READWRITE(*(CCurrencyState *)this);
56fe75cb 584 READWRITE(nativeFees);
585 READWRITE(nativeConversionFees);
586 READWRITE(reserveIn);
587 READWRITE(nativeIn);
588 READWRITE(reserveOut);
589 READWRITE(conversionPrice);
590 READWRITE(fees);
591 READWRITE(conversionFees);
a6e612cc
MT
592 }
593
594 std::vector<unsigned char> AsVector() const
595 {
596 return ::AsVector(*this);
597 }
598
56fe75cb 599 UniValue ToUniValue() const;
a6e612cc 600
56fe75cb 601 void ClearForNextBlock()
602 {
603 nativeFees = 0;
604 nativeConversionFees = 0;
605 reserveIn = std::vector<CAmount>(currencies.size());
606 nativeIn = std::vector<CAmount>(currencies.size());
607 reserveOut = std::vector<CAmount>(currencies.size());
608 fees = std::vector<CAmount>(currencies.size());
609 conversionFees = std::vector<CAmount>(currencies.size());
610 }
611
612 CCoinbaseCurrencyState MatchOrders(const std::vector<CReserveTransactionDescriptor> &orders,
613 std::vector<CReserveTransactionDescriptor> &reserveFills,
614 std::vector<CReserveTransactionDescriptor> &noFills,
615 std::vector<const CReserveTransactionDescriptor *> &expiredFillOrKills,
616 std::vector<const CReserveTransactionDescriptor *> &rejects,
617 std::vector<CAmount> &exchangeRates,
618 int32_t height, std::vector<CInputDescriptor> &conversionInputs,
619 int64_t maxSerializedSize=LONG_MAX, int64_t *ptotalSerializeSize=NULL, CMutableTransaction *pConversionTx=NULL,
620 bool feesAsReserve=false) const;
621
622 template <typename NUMBERVECTOR>
623 NUMBERVECTOR AddVectors(const NUMBERVECTOR &a, const NUMBERVECTOR &b) const
989b1de1 624 {
56fe75cb 625 const NUMBERVECTOR *shortVec, *longVec;
626 int64_t count, max;
627 if (a.size() <= b.size())
989b1de1 628 {
56fe75cb 629 count = a.size();
630 max = b.size();
631 shortVec = &a;
632 longVec = &b;
989b1de1 633 }
56fe75cb 634 else
989b1de1 635 {
56fe75cb 636 count = b.size();
637 max = a.size();
638 shortVec = &b;
639 longVec = &a;
989b1de1 640 }
989b1de1 641
56fe75cb 642 NUMBERVECTOR ret;
643 ret.reserve(max);
644 for (int i = 0; i < count; i++)
eac5415b 645 {
56fe75cb 646 ret[i] = (*longVec)[i] + (*shortVec)[i];
eac5415b 647 }
56fe75cb 648 for (int i = count; i < max; i++)
649 {
650 ret[i] = (*longVec)[i];
651 }
652 return ret;
a6e612cc 653 }
56fe75cb 654};
a6e612cc 655
56fe75cb 656class CReserveInOuts
657{
658public:
659 int64_t reserveIn;
660 int64_t reserveOut;
661 int64_t reserveOutConverted;
662 int64_t nativeOutConverted;
663 int64_t reserveConversionFees;
664 CReserveInOuts() : reserveIn(0), reserveOut(0), reserveOutConverted(0), nativeOutConverted(0), reserveConversionFees(0) {}
665 CReserveInOuts(int64_t ReserveIn, int64_t ReserveOut, int64_t ReserveOutConverted, int64_t NativeOutConverted, int64_t ReserveConversionFees) :
666 reserveIn(ReserveIn),
667 reserveOut(ReserveOut),
668 reserveOutConverted(ReserveOutConverted),
669 nativeOutConverted(NativeOutConverted),
670 reserveConversionFees(ReserveConversionFees) {}
671};
a6e612cc 672
56fe75cb 673class CReserveTransactionDescriptor
674{
675public:
676 enum {
677 IS_VALID=1, // known to be valid
678 IS_REJECT=2, // if set, tx is known to be invalid
679 IS_RESERVE=4, // if set, this transaction affects reserves and/or price if mined
680 IS_RESERVEEXCHANGE=8, // is this a reserve/exchange transaction?
681 IS_LIMIT=0x10, // if reserve exchange, is it a limit order?
682 IS_FILLORKILL=0x20, // If set, this can expire
683 IS_FILLORKILLFAIL=0x40, // If set, this is an expired fill or kill in a valid tx
684 IS_IMPORT=0x80, // If set, this is an expired fill or kill in a valid tx
685 IS_EXPORT=0x100, // If set, this is an expired fill or kill in a valid tx
686 IS_IDENTITY=0x200, // If set, this is an identity definition or update
687 IS_IDENTITY_DEFINITION=0x400, // If set, this is an identity definition
688 IS_HIGH_FEE=0x800 // If set, this may have "absurdly high fees"
689 };
b7c685b8 690
56fe75cb 691 const CTransaction *ptx; // pointer to the actual transaction if valid
692 uint16_t flags; // indicates transaction state
693 std::map<uint160, CReserveInOuts> currencies; // currency entries in this transaction
694 int16_t numBuys = 0; // each limit conversion that is valid before a certain block should account for FILL_OR_KILL_FEE
695 int16_t numSells = 0;
696 int16_t numTransfers = 0; // number of transfers, each of which also requires a transfer fee
697 CAmount nativeIn = 0;
698 CAmount nativeOut = 0;
699 CAmount nativeConversionFees = 0; // non-zero only if there is a conversion
700 std::vector<std::pair<int, CReserveExchange>> vRex; // index and rehydrated, validated reserve exchange outputs
e7e14f44 701
56fe75cb 702 CReserveTransactionDescriptor() :
703 flags(0),
704 ptx(NULL),
705 numBuys(0), // each limit conversion that is valid before a certain block should account for FILL_OR_KILL_FEE
706 numSells(0),
707 numTransfers(0),
708 nativeIn(0),
709 nativeOut(0),
710 nativeConversionFees(0) {} // non-zero only if there is a conversion, stored vs. calculated to get exact number with each calculated seperately
e7e14f44 711
56fe75cb 712 CReserveTransactionDescriptor(const CTransaction &tx, const CCoinsViewCache &view, int32_t nHeight);
e7e14f44 713
56fe75cb 714 bool IsReject() const { return flags & IS_REJECT; }
715 bool IsValid() const { return flags & IS_VALID && !IsReject(); }
716 bool IsReserve() const { return IsValid() && flags & IS_RESERVE; }
717 bool IsReserveExchange() const { return flags & IS_RESERVEEXCHANGE; }
718 bool IsLimit() const { return flags & IS_LIMIT; }
719 bool IsFillOrKill() const { return flags & IS_FILLORKILL; }
720 bool IsMarket() const { return IsReserveExchange() && !IsLimit(); }
721 bool IsFillOrKillFail() const { return flags & IS_FILLORKILLFAIL; }
722 bool IsIdentity() const { return flags & IS_IDENTITY; }
723 bool IsIdentityDefinition() const { return flags & IS_IDENTITY_DEFINITION; }
724 bool IsHighFee() const { return flags & IS_HIGH_FEE; }
41f170fd 725
56fe75cb 726 static CAmount CalculateConversionFee(CAmount inputAmount);
727 static CAmount CalculateAdditionalConversionFee(CAmount inputAmount);
a6e612cc 728
56fe75cb 729 CAmount NativeFees() const
a6e612cc 730 {
56fe75cb 731 return nativeIn - nativeOut; // native out converted does not include conversion
a6e612cc 732 }
45d7e5d5 733
56fe75cb 734 CCurrencyValueMap ReserveFees() const
45d7e5d5 735 {
56fe75cb 736 CCurrencyValueMap retFees;
737 for (auto &one : currencies)
738 {
739 CAmount oneFee = one.second.reserveIn - one.second.reserveOut;
740 if (oneFee)
741 {
742 retFees.valueMap[one.first] = oneFee;
743 }
744 }
745 return retFees;
45d7e5d5 746 }
a6e612cc 747
c8c677c9 748 CAmount AllFeesAsNative(const CCurrencyState &currencyState) const;
749 CAmount AllFeesAsNative(const CCurrencyState &currencyState, const std::vector<CAmount> &exchangeRates) const;
750 CCurrencyValueMap AllFeesAsReserve(const CCurrencyState &currencyState, int defaultReserve=0) const;
751 CCurrencyValueMap AllFeesAsReserve(const CCurrencyState &currencyState, const std::vector<CAmount> &exchangeRates, int defaultReserve=0) const;
989b1de1 752
56fe75cb 753 // does not check for errors
754 void AddReserveInput(const uint160 &currency, CAmount value);
755 void AddReserveOutput(const uint160 &currency, CAmount value);
756 void AddReserveOutConverted(const uint160 &currency, CAmount value);
757 void AddNativeOutConverted(const uint160 &currency, CAmount value);
758 void AddReserveConversionFees(const uint160 &currency, CAmount value);
989b1de1 759
56fe75cb 760 CCurrencyValueMap ReserveInputMap() const;
761 CCurrencyValueMap ReserveOutputMap() const;
762 CCurrencyValueMap ReserveOutConvertedMap() const;
763 CCurrencyValueMap NativeOutConvertedMap() const;
764 CCurrencyValueMap ReserveConversionFeesMap() const;
41f170fd 765
56fe75cb 766 // returns vectors in same size and order as reserve currencies
c8c677c9 767 std::vector<CAmount> ReserveInputVec(const CCurrencyState &cState) const;
768 std::vector<CAmount> ReserveOutputVec(const CCurrencyState &cState) const;
769 std::vector<CAmount> ReserveOutConvertedVec(const CCurrencyState &cState) const;
770 std::vector<CAmount> NativeOutConvertedVec(const CCurrencyState &cState) const;
771 std::vector<CAmount> ReserveConversionFeesVec(const CCurrencyState &cState) const;
41f170fd 772
56fe75cb 773 void AddReserveOutput(const CTokenOutput &ro)
41f170fd 774 {
56fe75cb 775 flags |= IS_RESERVE;
776 if (!(flags & IS_IMPORT))
777 {
778 AddReserveOutput(ro.currencyID, ro.nValue);
779 }
41f170fd
MT
780 }
781
56fe75cb 782 // is boolean, since it can fail, which would render the tx invalid
783 void AddReserveExchange(const CReserveExchange &rex, int32_t outputIndex, int32_t nHeight);
989b1de1 784
56fe75cb 785 void AddReserveTransfer(CReserveTransfer &rt)
989b1de1 786 {
56fe75cb 787 flags |= IS_RESERVE;
788 if (!(flags & IS_IMPORT))
789 {
790 AddReserveOutput(rt.currencyID, rt.nValue + rt.nFees);
791 numTransfers++;
792 }
989b1de1 793 }
41f170fd 794
56fe75cb 795 CMutableTransaction &AddConversionInOuts(CMutableTransaction &conversionTx,
796 std::vector<CInputDescriptor> &conversionInputs,
797 const CCurrencyValueMap &exchangeRates=CCurrencyValueMap(),
c8c677c9 798 const CCurrencyState *pCurrencyState=nullptr) const;
41f170fd 799
56fe75cb 800 bool AddReserveTransferImportOutputs(const uint160 &currencySourceID,
09551a1c 801 const CCurrencyDefinition &systemDest,
56fe75cb 802 const std::vector<CBaseChainObject *> &exportObjects,
803 std::vector<CTxOut> &vOutputs);
989b1de1
MT
804};
805
a6e612cc 806#endif // PBAAS_RESERVES_H
This page took 0.214697 seconds and 4 git commands to generate.