From 32d9b338fb53d07afeb88bd09484e9a4c79c0c16 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Fri, 19 Mar 2021 18:13:31 +0100 Subject: [PATCH] Added only owner can close order. Added optAuthTx. --- src/masternodes/mn_checks.cpp | 6 ++ src/masternodes/rpc_orderbook.cpp | 97 ++++++++++++++++++++++++++++++- 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 0e81db88aee..c169e319421 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -1649,6 +1649,12 @@ Res ApplyCloseOrderTx(CCustomCSView & mnview, CCoinsViewCache const & coins, CTr return Res::Err("order with creation tx %s is already closed!", closeorder.orderTx.GetHex()); } + const Coin& auth = coins.AccessCoin(COutPoint(order->creationTx, 1)); // always n=1 output + // check auth + if (!skipAuth && !HasAuth(tx, coins, auth.out.scriptPubKey)) { + return Res::Err("%s: %s", __func__, "tx must have at least one input from order owner"); + } + order->closeTx = closeorder.creationTx; order->closeHeight = closeorder.creationHeight; diff --git a/src/masternodes/rpc_orderbook.cpp b/src/masternodes/rpc_orderbook.cpp index 28369cf6594..0948e8f48c4 100644 --- a/src/masternodes/rpc_orderbook.cpp +++ b/src/masternodes/rpc_orderbook.cpp @@ -56,6 +56,17 @@ UniValue createorder(const JSONRPCRequest& request) { {"optionDFI", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "Amount in DFI per unit the taker has to pay if they do not complete the order (Default: 8 DFI)"} }, }, + {"inputs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, + "A json array of json objects", + { + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", + { + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, + {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, + }, + }, + }, + }, }, RPCResult{ "\"hash\" (string) The hex-encoded hash of broadcasted transaction\n" @@ -84,6 +95,8 @@ UniValue createorder(const JSONRPCRequest& request) { "{\"ownerAddress\",\"tokenFrom\",\"tokenTo\",\"amountFrom\",\"orderPrice\"}"); } UniValue metaObj = request.params[0].get_obj(); + UniValue const & txInputs = request.params[1]; + COrder order; std::string tokenFromSymbol, tokenToSymbol; @@ -164,15 +177,32 @@ UniValue createorder(const JSONRPCRequest& request) { const auto txVersion = GetTransactionVersion(targetHeight); CMutableTransaction rawTx(txVersion); + CTransactionRef optAuthTx; + std::set auths; + rawTx.vin = GetAuthInputsSmart(pwallet, rawTx.nVersion, auths, false, optAuthTx, txInputs); + rawTx.vout.push_back(CTxOut(0, scriptMeta)); - fund(rawTx, pwallet, {}); + CCoinControl coinControl; + + // Return change to auth address + if (auths.size() == 1) { + CTxDestination dest; + ExtractDestination(*auths.cbegin(), dest); + if (IsValidDestination(dest)) { + coinControl.destChange = dest; + } + } + + fund(rawTx, pwallet, optAuthTx,&coinControl); // check execution { LOCK(cs_main); CCustomCSView mnview_dummy(*pcustomcsview); // don't write into actual DB CCoinsViewCache coinview(&::ChainstateActive().CoinsTip()); + if (optAuthTx) + AddCoins(coinview, *optAuthTx, targetHeight); const auto res = ApplyCreateOrderTx(mnview_dummy, coinview, CTransaction(rawTx), targetHeight, ToByteVector(CDataStream{SER_NETWORK, PROTOCOL_VERSION, order}), Params().GetConsensus()); if (!res.ok) { @@ -196,6 +226,17 @@ UniValue fulfillorder(const JSONRPCRequest& request) { {"amount", RPCArg::Type::NUM, RPCArg::Optional::NO, "coins amount to fulfill the order"}, }, }, + {"inputs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, + "A json array of json objects", + { + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", + { + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, + {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, + }, + }, + }, + }, }, RPCResult{ "\"hash\" (string) The hex-encoded hash of broadcasted transaction\n" @@ -219,6 +260,8 @@ UniValue fulfillorder(const JSONRPCRequest& request) { "{\"ownerAddress\",\"orderTx\",\"amount\"}"); } UniValue metaObj = request.params[0].get_obj(); + UniValue const & txInputs = request.params[1]; + CFulfillOrder fillorder; if (!metaObj["ownerAddress"].isNull()) { @@ -279,15 +322,32 @@ UniValue fulfillorder(const JSONRPCRequest& request) { const auto txVersion = GetTransactionVersion(targetHeight); CMutableTransaction rawTx(txVersion); + CTransactionRef optAuthTx; + std::set auths; + rawTx.vin = GetAuthInputsSmart(pwallet, rawTx.nVersion, auths, false, optAuthTx, txInputs); + rawTx.vout.push_back(CTxOut(0, scriptMeta)); - fund(rawTx, pwallet, {}); + CCoinControl coinControl; + + // Return change to auth address + if (auths.size() == 1) { + CTxDestination dest; + ExtractDestination(*auths.cbegin(), dest); + if (IsValidDestination(dest)) { + coinControl.destChange = dest; + } + } + + fund(rawTx, pwallet, optAuthTx,&coinControl); // check execution { LOCK(cs_main); CCustomCSView mnview_dummy(*pcustomcsview); // don't write into actual DB CCoinsViewCache coinview(&::ChainstateActive().CoinsTip()); + if (optAuthTx) + AddCoins(coinview, *optAuthTx, targetHeight); const auto res = ApplyFulfillOrderTx(mnview_dummy, coinview, CTransaction(rawTx), targetHeight, ToByteVector(CDataStream{SER_NETWORK, PROTOCOL_VERSION, fillorder}), Params().GetConsensus()); if (!res.ok) { @@ -305,7 +365,19 @@ UniValue closeorder(const JSONRPCRequest& request) { HelpRequiringPassphrase(pwallet) + "\n", { {"orderTx", RPCArg::Type::STR, RPCArg::Optional::NO, "txid of maker order"}, + {"inputs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, + "A json array of json objects", + { + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", + { + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, + {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, + }, + }, + }, + }, }, + RPCResult{ "\"hash\" (string) The hex-encoded hash of broadcasted transaction\n" }, @@ -325,6 +397,8 @@ UniValue closeorder(const JSONRPCRequest& request) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameters, arguments 1 must be non-null and expected as \"orderTx\"}"); } + UniValue const & txInputs = request.params[1]; + CCloseOrder closeorder; closeorder.orderTx = uint256S(request.params[0].getValStr()); @@ -350,15 +424,32 @@ UniValue closeorder(const JSONRPCRequest& request) { const auto txVersion = GetTransactionVersion(targetHeight); CMutableTransaction rawTx(txVersion); + CTransactionRef optAuthTx; + std::set auths; + rawTx.vin = GetAuthInputsSmart(pwallet, rawTx.nVersion, auths, false, optAuthTx, txInputs); + rawTx.vout.push_back(CTxOut(0, scriptMeta)); - fund(rawTx, pwallet, {}); + CCoinControl coinControl; + + // Return change to auth address + if (auths.size() == 1) { + CTxDestination dest; + ExtractDestination(*auths.cbegin(), dest); + if (IsValidDestination(dest)) { + coinControl.destChange = dest; + } + } + + fund(rawTx, pwallet, optAuthTx,&coinControl); // check execution { LOCK(cs_main); CCustomCSView mnview_dummy(*pcustomcsview); // don't write into actual DB CCoinsViewCache coinview(&::ChainstateActive().CoinsTip()); + if (optAuthTx) + AddCoins(coinview, *optAuthTx, targetHeight); const auto res = ApplyCloseOrderTx(mnview_dummy, coinview, CTransaction(rawTx), targetHeight, ToByteVector(CDataStream{SER_NETWORK, PROTOCOL_VERSION, closeorder}), Params().GetConsensus()); if (!res.ok) {