From f73e9a221ccae595e886efbe8a66a637e7031d18 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Mon, 17 May 2021 18:07:38 +0200 Subject: [PATCH] ICX Orderbook (#335) * Initial ICX orderbook development * Inital development of ICX Orderbook * Fixes and changes. * Remove prints and small fix. * Fix seed to hash calculation * Optimize data structures. * Fix searching HTLCs. * Refactor data structures and flow, fixed PR issues * Refactor data structures and flow, fixed PR issues * Fix issues. * Added incentives and fees. Fixed issue with CAmount multiply overflow. Fix tests and clean code. (#5) * Add incentives and fees. Fix multiply overflow. * Fix lint rpc mapping check * Add poolpair id to governance variable for DFI/BTC price used in takerFee, minimum timeout for 2nd HTLC, added initial unit test, various fixes and code clean. * Fix calculation of takerFee. Clean code. * Get poolpair id from governance variable. * Adding expiration for minimum timeout to EXT HTLC. * Remove locking funds on makeoffer, fixes. * Add initial test that add creation of poolpair. * Added takerFeePerBTC gov var, adapted timeouts for htlcs, check in rpc for correct htlc timeouts, added more checks in test. * Added key for ext htlc closed, addapted test and rpcs. * Fill partial offer to complete order * Test burn. Wip burn map in ConnectBlock. Tally tokens. * ICX Set order owner on creation * Fix regressions, reproducible crashes Polish Fixes: #374 Signed-off-by: Anthony Fieroni * Remove chain data from DB, refactor address storing only in order/offer, fix auth, polish and clean code. * Add warning disclaimer * Add creation fee for devnet * Fixed HTLC timout check, refund partial takerFee on partial offer accept, added test case for BTC/DFI flow, added error test cases, polished code. * Fixed expiration of offer and htlcs, added check for open offer on submit htlc, added more test cases. * Fix order expiration refund, add checkin rpc for htlc if order expires first, fixed and added tests. * Fix findng poolpair and calculating DFI per BTC, adapted test, rpc fix. * Remove unnecessary check in GetBTCDFIPoolPair(), make BTC isDAT in error tests, change BTC blocks in DFI to 20. * Masternode creation requires authorization (#386) Signed-off-by: Anthony Fieroni * Polish correct offer prices in blockchain layer Signed-off-by: Anthony Fieroni * Moving more checks from RPC to mn_checks, cleanup code * Small fixes. * Follow getburninfo at all steps. Set correct amounts. * Fix lint * Fix lint * Fix typo. Co-authored-by: Peter Bushnell Co-authored-by: monstrobishi Co-authored-by: Anthony Fieroni --- .gitignore | 3 + src/Makefile.am | 9 +- .../govvariables/icx_takerfee_per_btc.cpp | 31 + .../govvariables/icx_takerfee_per_btc.h | 35 + src/masternodes/gv.cpp | 1 + src/masternodes/icxorder.cpp | 417 +++++ src/masternodes/icxorder.h | 467 ++++++ src/masternodes/masternodes.h | 8 +- src/masternodes/mn_checks.cpp | 595 ++++++- src/masternodes/mn_checks.h | 31 +- src/masternodes/mn_rpc.h | 1 + src/masternodes/rpc_accounts.cpp | 6 +- src/masternodes/rpc_customtx.cpp | 67 + src/masternodes/rpc_icxorderbook.cpp | 1399 +++++++++++++++++ src/rpc/client.cpp | 8 + src/rpc/register.h | 4 + src/validation.cpp | 166 ++ test/functional/feature_burn_address.py | 38 +- test/functional/feature_icx_orderbook.py | 779 +++++++++ .../feature_icx_orderbook_errors.py | 640 ++++++++ test/functional/rpc_help.py | 2 +- test/functional/test_runner.py | 2 + test/lint/check-rpc-mappings.py | 1 + test/lint/lint-circular-dependencies.sh | 1 + 24 files changed, 4675 insertions(+), 36 deletions(-) create mode 100644 src/masternodes/govvariables/icx_takerfee_per_btc.cpp create mode 100644 src/masternodes/govvariables/icx_takerfee_per_btc.h create mode 100644 src/masternodes/icxorder.cpp create mode 100644 src/masternodes/icxorder.h create mode 100644 src/masternodes/rpc_icxorderbook.cpp create mode 100755 test/functional/feature_icx_orderbook.py create mode 100644 test/functional/feature_icx_orderbook_errors.py diff --git a/.gitignore b/.gitignore index b6070bfde49..3c373d9d183 100644 --- a/.gitignore +++ b/.gitignore @@ -129,3 +129,6 @@ dist/ # spv !src/spv/Makefile + +# VSCode extension LocalHistory +.history \ No newline at end of file diff --git a/src/Makefile.am b/src/Makefile.am index 714a3531b36..678ff29d17d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -157,9 +157,11 @@ DEFI_CORE_H = \ masternodes/communityaccounttypes.h \ masternodes/criminals.h \ masternodes/factory.h \ + masternodes/govvariables/icx_takerfee_per_btc.h \ masternodes/govvariables/lp_daily_dfi_reward.h \ masternodes/govvariables/lp_splits.h \ masternodes/gv.h \ + masternodes/icxorder.h \ masternodes/incentivefunding.h \ masternodes/masternodes.h \ masternodes/mn_checks.h \ @@ -366,9 +368,11 @@ libdefi_server_a_SOURCES = \ masternodes/anchors.cpp \ masternodes/criminals.cpp \ masternodes/oracles.cpp \ + masternodes/govvariables/icx_takerfee_per_btc.cpp \ masternodes/govvariables/lp_daily_dfi_reward.cpp \ masternodes/govvariables/lp_splits.cpp \ masternodes/gv.cpp \ + masternodes/icxorder.cpp \ masternodes/incentivefunding.cpp \ masternodes/masternodes.cpp \ masternodes/mn_checks.cpp \ @@ -376,9 +380,10 @@ libdefi_server_a_SOURCES = \ masternodes/rpc_accounts.cpp \ masternodes/rpc_customtx.cpp \ masternodes/rpc_masternodes.cpp \ - masternodes/rpc_tokens.cpp \ - masternodes/rpc_poolpair.cpp \ + masternodes/rpc_icxorderbook.cpp \ masternodes/rpc_oracles.cpp \ + masternodes/rpc_poolpair.cpp \ + masternodes/rpc_tokens.cpp \ masternodes/tokens.cpp \ masternodes/poolpairs.cpp \ masternodes/undos.cpp \ diff --git a/src/masternodes/govvariables/icx_takerfee_per_btc.cpp b/src/masternodes/govvariables/icx_takerfee_per_btc.cpp new file mode 100644 index 00000000000..5ccd495da9b --- /dev/null +++ b/src/masternodes/govvariables/icx_takerfee_per_btc.cpp @@ -0,0 +1,31 @@ +// Copyright (c) 2020 The DeFi Foundation +// Distributed under the MIT software license, see the accompanying +// file LICENSE or http://www.opensource.org/licenses/mit-license.php. + +#include +#include /// ValueFromAmount +#include /// CCustomCSView +#include /// AmountFromValue + +Res ICX_TAKERFEE_PER_BTC::Import(const UniValue & val) { + takerFeePerBTC = AmountFromValue(val); + return Res::Ok(); +} + +UniValue ICX_TAKERFEE_PER_BTC::Export() const { + UniValue res(UniValue::VOBJ); + + return ValueFromAmount(takerFeePerBTC); +} + +Res ICX_TAKERFEE_PER_BTC::Validate(const CCustomCSView &mnview) const +{ + if (takerFeePerBTC <= 0) + return Res::Err("takerFeePerBTC cannot be 0 or less"); + return Res::Ok(); +} + +Res ICX_TAKERFEE_PER_BTC::Apply(CCustomCSView & mnview, uint32_t) +{ + return mnview.ICXSetTakerFeePerBTC(takerFeePerBTC); +} diff --git a/src/masternodes/govvariables/icx_takerfee_per_btc.h b/src/masternodes/govvariables/icx_takerfee_per_btc.h new file mode 100644 index 00000000000..162e1025691 --- /dev/null +++ b/src/masternodes/govvariables/icx_takerfee_per_btc.h @@ -0,0 +1,35 @@ +#ifndef DEFI_MASTERNODES_GOVVARIABLES_ICX_TAKERFEE_PER_BTC_H +#define DEFI_MASTERNODES_GOVVARIABLES_ICX_TAKERFEE_PER_BTC_H + +#include +#include + +class ICX_TAKERFEE_PER_BTC : public GovVariable, public AutoRegistrator +{ +public: + virtual ~ICX_TAKERFEE_PER_BTC() override {} + + std::string GetName() const override { + return TypeName(); + } + + Res Import(UniValue const &val) override; + UniValue Export() const override; + Res Validate(CCustomCSView const &mnview) const override; + Res Apply(CCustomCSView &mnview, uint32_t height) override; + + static constexpr char const * TypeName() { return "ICX_TAKERFEE_PER_BTC"; } + static GovVariable * Create() { return new ICX_TAKERFEE_PER_BTC(); } + + ADD_OVERRIDE_VECTOR_SERIALIZE_METHODS + ADD_OVERRIDE_SERIALIZE_METHODS(CDataStream) + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(takerFeePerBTC); + } + + CAmount takerFeePerBTC; +}; + +#endif // DEFI_MASTERNODES_GOVVARIABLES_ICX_TAKERFEE_PER_BTC_H \ No newline at end of file diff --git a/src/masternodes/gv.cpp b/src/masternodes/gv.cpp index 9e0a721afa5..ecfcdeb7f31 100644 --- a/src/masternodes/gv.cpp +++ b/src/masternodes/gv.cpp @@ -3,6 +3,7 @@ // file LICENSE or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include diff --git a/src/masternodes/icxorder.cpp b/src/masternodes/icxorder.cpp new file mode 100644 index 00000000000..f45a3b6afeb --- /dev/null +++ b/src/masternodes/icxorder.cpp @@ -0,0 +1,417 @@ +#include +#include /// AmountFromValue +#include /// ValueFromAmount + +/// @attention make sure that it does not overlap with other views !!! +const unsigned char CICXOrderView::ICXOrderCreationTx ::prefix = '1'; +const unsigned char CICXOrderView::ICXMakeOfferCreationTx ::prefix = '2'; +const unsigned char CICXOrderView::ICXSubmitDFCHTLCCreationTx ::prefix = '3'; +const unsigned char CICXOrderView::ICXSubmitEXTHTLCCreationTx ::prefix = '4'; +const unsigned char CICXOrderView::ICXClaimDFCHTLCCreationTx ::prefix = '5'; +const unsigned char CICXOrderView::ICXCloseOrderCreationTx ::prefix = '6'; +const unsigned char CICXOrderView::ICXCloseOfferCreationTx ::prefix = '7'; + +const unsigned char CICXOrderView::ICXOrderOpenKey ::prefix = 0x01; +const unsigned char CICXOrderView::ICXOrderCloseKey ::prefix = 0x02; +const unsigned char CICXOrderView::ICXMakeOfferOpenKey ::prefix = 0x03; +const unsigned char CICXOrderView::ICXMakeOfferCloseKey ::prefix = 0x04; +const unsigned char CICXOrderView::ICXSubmitDFCHTLCOpenKey ::prefix = 0x05; +const unsigned char CICXOrderView::ICXSubmitDFCHTLCCloseKey ::prefix = 0x06; +const unsigned char CICXOrderView::ICXSubmitEXTHTLCOpenKey ::prefix = 0x07; +const unsigned char CICXOrderView::ICXSubmitEXTHTLCCloseKey ::prefix = 0x08; +const unsigned char CICXOrderView::ICXClaimDFCHTLCKey ::prefix = 0x09; + +const unsigned char CICXOrderView::ICXOrderStatus ::prefix = 0x0A; +const unsigned char CICXOrderView::ICXOfferStatus ::prefix = 0x0B; +const unsigned char CICXOrderView::ICXSubmitDFCHTLCStatus ::prefix = 0x0C; +const unsigned char CICXOrderView::ICXSubmitEXTHTLCStatus ::prefix = 0x0D; + +const unsigned char CICXOrderView::ICXVariables ::prefix = 0x0F; + +const uint32_t CICXOrder::DEFAULT_EXPIRY = 2880; +const uint8_t CICXOrder::TYPE_INTERNAL = 1; +const uint8_t CICXOrder::TYPE_EXTERNAL = 2; +const uint8_t CICXOrder::STATUS_OPEN = 0; +const uint8_t CICXOrder::STATUS_CLOSED = 1; +const uint8_t CICXOrder::STATUS_FILLED = 2; +const uint8_t CICXOrder::STATUS_EXPIRED = 3; +const std::string CICXOrder::CHAIN_BTC = "BTC"; +const std::string CICXOrder::TOKEN_BTC = "BTC"; + +const uint32_t CICXMakeOffer::DEFAULT_EXPIRY = 10; +const uint32_t CICXMakeOffer::MAKER_DEPOSIT_REFUND_TIMEOUT = 100; +const uint8_t CICXMakeOffer::STATUS_OPEN = 0; +const uint8_t CICXMakeOffer::STATUS_CLOSED = 1; +const uint8_t CICXMakeOffer::STATUS_EXPIRED = 2; +const CAmount CICXMakeOffer::DEFAULT_TAKER_FEE_PER_BTC = AmountFromValue(0.003); + +const uint32_t CICXSubmitDFCHTLC::MINIMUM_TIMEOUT = 500; +const uint32_t CICXSubmitDFCHTLC::MINIMUM_2ND_TIMEOUT = 250; +const uint8_t CICXSubmitDFCHTLC::STATUS_OPEN = 0; +const uint8_t CICXSubmitDFCHTLC::STATUS_CLAIMED = 1; +const uint8_t CICXSubmitDFCHTLC::STATUS_REFUNDED = 2; +const uint8_t CICXSubmitDFCHTLC::STATUS_EXPIRED = 3; + +const uint32_t CICXSubmitEXTHTLC::MINIMUM_TIMEOUT = 30; +const uint32_t CICXSubmitEXTHTLC::MINIMUM_2ND_TIMEOUT = 15; +// constant for calculating BTC block period in DFI block period per hour (BTC estimated to 6 blocks/h, DFI to 96 blocks/h) +const uint32_t CICXSubmitEXTHTLC::BTC_BLOCKS_IN_DFI_BLOCKS = 16; +const uint8_t CICXSubmitEXTHTLC::STATUS_OPEN = 0; +const uint8_t CICXSubmitEXTHTLC::STATUS_CLOSED = 1; +const uint8_t CICXSubmitEXTHTLC::STATUS_EXPIRED = 3; + +const CAmount CICXOrderView::DEFAULT_DFI_BTC_PRICE = 15000; + +std::unique_ptr CICXOrderView::GetICXOrderByCreationTx(uint256 const & txid) const +{ + auto order = ReadBy(txid); + if (order) + return MakeUnique(*order); + return {}; +} + +Res CICXOrderView::ICXCreateOrder(CICXOrderImpl const & order) +{ + //this should not happen, but for sure + if (GetICXOrderByCreationTx(order.creationTx)) + return Res::Err("order with creation tx %s already exists!", order.creationTx.GetHex()); + if (order.orderType != CICXOrder::TYPE_INTERNAL && order.orderType != CICXOrder::TYPE_EXTERNAL) + return Res::Err("invalid order type!"); + if (order.amountFrom == 0) + return Res::Err("order amountFrom must be greater than 0!"); + if (order.amountToFill != order.amountFrom) + return Res::Err("order amountToFill does not equal to amountFrom!"); + if (order.orderPrice == 0) + return Res::Err("order price must be greater than 0!"); + if (order.expiry < CICXOrder::DEFAULT_EXPIRY) + return Res::Err("order expiry must be greater than %d!", CICXOrder::DEFAULT_EXPIRY); + + OrderKey key(order.idToken, order.creationTx); + WriteBy(order.creationTx, order); + WriteBy(key, CICXOrder::STATUS_OPEN); + WriteBy(StatusKey(order.creationHeight + order.expiry, order.creationTx), CICXOrder::STATUS_EXPIRED); + + return Res::Ok(); +} + +Res CICXOrderView::ICXUpdateOrder(CICXOrderImpl const & order) +{ + //this should not happen, but for sure + if (!GetICXOrderByCreationTx(order.creationTx)) + return Res::Err("order with creation tx %s doesn't exists!", order.creationTx.GetHex()); + + OrderKey key(order.idToken, order.creationTx); + WriteBy(order.creationTx, order); + + return Res::Ok(); +} + +Res CICXOrderView::ICXCloseOrderTx(CICXOrderImpl const & order, uint8_t const status) +{ + WriteBy(order.creationTx, order); + OrderKey key(order.idToken, order.creationTx); + EraseBy(key); + WriteBy(key, status); + EraseBy(StatusKey(order.creationHeight + order.expiry, order.creationTx)); + + return Res::Ok(); +} + +void CICXOrderView::ForEachICXOrderOpen(std::function callback, DCT_ID const & id) +{ + ForEach(callback, OrderKey{id, {}}); +} + +void CICXOrderView::ForEachICXOrderClose(std::function callback, DCT_ID const & id) +{ + ForEach(callback, OrderKey{id, {}}); +} + +void CICXOrderView::ForEachICXOrderExpire(std::function callback, uint32_t const & height) +{ + ForEach(callback, StatusKey{height, {}}); +} + +std::unique_ptr CICXOrderView::HasICXOrderOpen(DCT_ID const & tokenId, uint256 const & ordertxid) +{ + auto it = LowerBound(OrderKey{tokenId, ordertxid}); + if (it.Valid() && it.Key().first == tokenId && it.Key().second == ordertxid) + return GetICXOrderByCreationTx(it.Key().second); + return {}; +} + + +std::unique_ptr CICXOrderView::GetICXMakeOfferByCreationTx(uint256 const & txid) const +{ + auto makeoffer = ReadBy(txid); + if (makeoffer) + return MakeUnique(*makeoffer); + return {}; +} + +Res CICXOrderView::ICXMakeOffer(CICXMakeOfferImpl const & makeoffer) +{ + //this should not happen, but for sure + if (GetICXMakeOfferByCreationTx(makeoffer.creationTx)) + return Res::Err("makeoffer with creation tx %s already exists!", makeoffer.creationTx.GetHex()); + if (makeoffer.amount == 0) + return Res::Err("offer amount must be greater than 0!"); + if (makeoffer.expiry < CICXMakeOffer::DEFAULT_EXPIRY) + return Res::Err("offer expiry must be greater than %d!", CICXMakeOffer::DEFAULT_EXPIRY); + + WriteBy(makeoffer.creationTx, makeoffer); + WriteBy(TxidPairKey(makeoffer.orderTx, makeoffer.creationTx), CICXMakeOffer::STATUS_OPEN); + WriteBy(StatusKey(makeoffer.creationHeight + makeoffer.expiry, makeoffer.creationTx), CICXMakeOffer::STATUS_EXPIRED); + + return Res::Ok(); +} + +Res CICXOrderView::ICXUpdateMakeOffer(CICXMakeOfferImpl const & makeoffer) +{ + WriteBy(makeoffer.creationTx, makeoffer); + + return Res::Ok(); +} + +Res CICXOrderView::ICXCloseMakeOfferTx(CICXMakeOfferImpl const & makeoffer, uint8_t const status) +{ + TxidPairKey key(makeoffer.orderTx,makeoffer.creationTx); + EraseBy(key); + WriteBy(key, status); + EraseBy(StatusKey(makeoffer.creationHeight + makeoffer.expiry, makeoffer.creationTx)); + + return Res::Ok(); +} + +void CICXOrderView::ForEachICXMakeOfferOpen(std::function callback, uint256 const & txid) +{ + ForEach(callback, TxidPairKey{txid, {}}); +} + +void CICXOrderView::ForEachICXMakeOfferClose(std::function callback, uint256 const & txid) +{ + ForEach(callback, TxidPairKey{txid, {}}); +} + +void CICXOrderView::ForEachICXMakeOfferExpire(std::function callback, uint32_t const & height) +{ + ForEach(callback, StatusKey{height, {}}); +} + +std::unique_ptr CICXOrderView::HasICXMakeOfferOpen(uint256 const & ordertxid, uint256 const & offertxid) +{ + auto it = LowerBound(TxidPairKey{ordertxid, offertxid}); + if (it.Valid() && it.Key().first == ordertxid && it.Key().second == offertxid) + return GetICXMakeOfferByCreationTx(it.Key().second); + return {}; +} + +std::unique_ptr CICXOrderView::GetICXSubmitDFCHTLCByCreationTx(uint256 const & txid) const +{ + auto submitdfchtlc = ReadBy(txid); + if (submitdfchtlc) + return MakeUnique(*submitdfchtlc); + return {}; +} + +Res CICXOrderView::ICXSubmitDFCHTLC(CICXSubmitDFCHTLCImpl const & submitdfchtlc) +{ + //this should not happen, but for sure + if (GetICXSubmitDFCHTLCByCreationTx(submitdfchtlc.creationTx)) + return Res::Err("submitdfchtlc with creation tx %s already exists!", submitdfchtlc.creationTx.GetHex()); + if (submitdfchtlc.amount == 0) + return Res::Err("Invalid amount, must be greater than 0!"); + if (submitdfchtlc.hash.IsNull()) + return Res::Err("Invalid hash, htlc hash is empty and it must be set!"); + if (submitdfchtlc.timeout == 0) + return Res::Err("Invalid timeout, must be greater than 0!"); + + WriteBy(submitdfchtlc.creationTx, submitdfchtlc); + WriteBy(TxidPairKey(submitdfchtlc.offerTx, submitdfchtlc.creationTx), CICXSubmitDFCHTLC::STATUS_OPEN); + WriteBy(StatusKey(submitdfchtlc.creationHeight + CICXMakeOffer::MAKER_DEPOSIT_REFUND_TIMEOUT, submitdfchtlc.creationTx), CICXSubmitDFCHTLC::STATUS_EXPIRED); + WriteBy(StatusKey(submitdfchtlc.creationHeight + submitdfchtlc.timeout, submitdfchtlc.creationTx), CICXSubmitDFCHTLC::STATUS_REFUNDED); + + return Res::Ok(); +} + +Res CICXOrderView::ICXCloseDFCHTLC(CICXSubmitDFCHTLCImpl const & submitdfchtlc, uint8_t const status) +{ + WriteBy(submitdfchtlc.creationTx, submitdfchtlc); + EraseBy(TxidPairKey(submitdfchtlc.offerTx, submitdfchtlc.creationTx)); + WriteBy(TxidPairKey(submitdfchtlc.offerTx, submitdfchtlc.creationTx), status); + + EraseBy(StatusKey(submitdfchtlc.creationHeight + CICXMakeOffer::MAKER_DEPOSIT_REFUND_TIMEOUT, submitdfchtlc.creationTx)); + EraseBy(StatusKey(submitdfchtlc.creationHeight + submitdfchtlc.timeout, submitdfchtlc.creationTx)); + + return Res::Ok(); +} + +void CICXOrderView::ForEachICXSubmitDFCHTLCOpen(std::function callback, uint256 const & offertxid) +{ + ForEach(callback, TxidPairKey{offertxid, {}}); +} + +void CICXOrderView::ForEachICXSubmitDFCHTLCClose(std::function callback, uint256 const & offertxid) +{ + ForEach(callback, TxidPairKey{offertxid, {}}); +} + +void CICXOrderView::ForEachICXSubmitDFCHTLCExpire(std::function callback, uint32_t const & height) +{ + ForEach(callback, StatusKey{height, {}}); +} + +std::unique_ptr CICXOrderView::HasICXSubmitDFCHTLCOpen(uint256 const & offertxid) +{ + auto it = LowerBound(TxidPairKey{offertxid, {}}); + if (it.Valid() && it.Key().first == offertxid) + return GetICXSubmitDFCHTLCByCreationTx(it.Key().second); + return {}; +} + +std::unique_ptr CICXOrderView::GetICXSubmitEXTHTLCByCreationTx(const uint256 & txid) const +{ + auto submitexthtlc = ReadBy(txid); + if (submitexthtlc) + return MakeUnique(*submitexthtlc); + return {}; +} + +Res CICXOrderView::ICXSubmitEXTHTLC(CICXSubmitEXTHTLCImpl const & submitexthtlc) +{ + //this should not happen, but for sure + if (GetICXSubmitEXTHTLCByCreationTx(submitexthtlc.creationTx)) + return Res::Err("submitexthtlc with creation tx %s already exists!", submitexthtlc.creationTx.GetHex()); + if (submitexthtlc.amount == 0) + return Res::Err("Invalid amount, must be greater than 0!"); + if (submitexthtlc.htlcscriptAddress.empty()) + return Res::Err("Invalid htlcscriptAddress, htlcscriptAddress is empty and it must be set!"); + if (submitexthtlc.hash.IsNull()) + return Res::Err("Invalid hash, htlc hash is empty and it must be set!"); + if (!submitexthtlc.ownerPubkey.IsFullyValid()) + return Res::Err("Invalid refundPubkey is not a valid pubkey!"); + if (submitexthtlc.timeout == 0) + return Res::Err("Invalid timout, must be greater than 0!"); + + WriteBy(submitexthtlc.creationTx, submitexthtlc); + WriteBy(TxidPairKey(submitexthtlc.offerTx, submitexthtlc.creationTx), CICXSubmitEXTHTLC::STATUS_OPEN); + WriteBy(StatusKey(submitexthtlc.creationHeight + CICXMakeOffer::MAKER_DEPOSIT_REFUND_TIMEOUT, submitexthtlc.creationTx), CICXSubmitEXTHTLC::STATUS_EXPIRED); + return Res::Ok(); +} + +Res CICXOrderView::ICXCloseEXTHTLC(CICXSubmitEXTHTLCImpl const & submitexthtlc, uint8_t const status) +{ + WriteBy(submitexthtlc.creationTx, submitexthtlc); + EraseBy(TxidPairKey(submitexthtlc.offerTx, submitexthtlc.creationTx)); + WriteBy(TxidPairKey(submitexthtlc.offerTx, submitexthtlc.creationTx), status); + EraseBy(StatusKey(submitexthtlc.creationHeight + CICXMakeOffer::MAKER_DEPOSIT_REFUND_TIMEOUT, submitexthtlc.creationTx)); + + return Res::Ok(); +} + +void CICXOrderView::ForEachICXSubmitEXTHTLCOpen(std::function callback, uint256 const & offertxid) +{ + ForEach(callback, TxidPairKey{offertxid, {}}); +} + +void CICXOrderView::ForEachICXSubmitEXTHTLCClose(std::function callback, uint256 const & offertxid) +{ + ForEach(callback, TxidPairKey{offertxid, {}}); +} + +void CICXOrderView::ForEachICXSubmitEXTHTLCExpire(std::function callback, uint32_t const & height) +{ + ForEach(callback, StatusKey{height, {}}); +} + +std::unique_ptr CICXOrderView::HasICXSubmitEXTHTLCOpen(uint256 const & offertxid) +{ + auto it = LowerBound(TxidPairKey{offertxid, {}}); + if (it.Valid() && it.Key().first == offertxid) + return GetICXSubmitEXTHTLCByCreationTx(it.Key().second); + return {}; +} + +std::unique_ptr CICXOrderView::GetICXClaimDFCHTLCByCreationTx(uint256 const & txid) const +{ + auto claimdfchtlc = ReadBy(txid); + if (claimdfchtlc) + return MakeUnique(*claimdfchtlc); + return {}; +} + +Res CICXOrderView::ICXClaimDFCHTLC(CICXClaimDFCHTLCImpl const & claimdfchtlc, uint256 const & offertxid, CICXOrderImpl const & order) +{ + //this should not happen, but for sure + if (GetICXClaimDFCHTLCByCreationTx(claimdfchtlc.creationTx)) + return Res::Err("claimdfchtlc with creation tx %s already exists!", claimdfchtlc.creationTx.GetHex()); + + WriteBy(claimdfchtlc.creationTx, claimdfchtlc); + WriteBy(TxidPairKey(offertxid, claimdfchtlc.creationTx),CICXSubmitDFCHTLC::STATUS_CLAIMED); + + if (order.amountToFill != 0) + WriteBy(order.creationTx, order); + + return Res::Ok(); +} + +void CICXOrderView::ForEachICXClaimDFCHTLC(std::function callback, uint256 const & offertxid) +{ + ForEach(callback, TxidPairKey{offertxid, {}}); +} + +std::unique_ptr CICXOrderView::GetICXCloseOrderByCreationTx(uint256 const & txid) const +{ + auto closeorderImpl = ReadBy(txid); + if (closeorderImpl) + return MakeUnique(*closeorderImpl); + return {}; +} + +Res CICXOrderView::ICXCloseOrder(CICXCloseOrderImpl const & closeorder) +{ + //this should not happen, but for sure + if (GetICXCloseOrderByCreationTx(closeorder.creationTx)) + return Res::Err("closeorder with creation tx %s already exists!", closeorder.creationTx.GetHex()); + + WriteBy(closeorder.creationTx, closeorder.orderTx); + + return Res::Ok(); +} + +std::unique_ptr CICXOrderView::GetICXCloseOfferByCreationTx(uint256 const & txid) const +{ + auto closeofferImpl = ReadBy(txid); + if (closeofferImpl) + return MakeUnique(*closeofferImpl); + return {}; +} + +Res CICXOrderView::ICXCloseOffer(CICXCloseOfferImpl const & closeoffer) +{ + //this should not happen, but for sure + if (GetICXCloseOrderByCreationTx(closeoffer.creationTx)) + return Res::Err("closeooffer with creation tx %s already exists!", closeoffer.creationTx.GetHex()); + + WriteBy(closeoffer.creationTx, closeoffer.offerTx); + + return Res::Ok(); +} + +Res CICXOrderView::ICXSetTakerFeePerBTC(CAmount amount) +{ + WriteBy('A', amount); + + return Res::Ok(); +} + +CAmount CICXOrderView::ICXGetTakerFeePerBTC() +{ + CAmount takerFeePerBTC = CICXMakeOffer::DEFAULT_TAKER_FEE_PER_BTC; + + auto fee = ReadBy('A'); + if (fee) + takerFeePerBTC = *fee; + + return (takerFeePerBTC); +} diff --git a/src/masternodes/icxorder.h b/src/masternodes/icxorder.h new file mode 100644 index 00000000000..3b39c0344a4 --- /dev/null +++ b/src/masternodes/icxorder.h @@ -0,0 +1,467 @@ +#ifndef DEFI_MASTERNODES_ICXORDER_H +#define DEFI_MASTERNODES_ICXORDER_H + +#include + +#include +#include +#include +#include