diff --git a/Builds/CMake/RippledCore.cmake b/Builds/CMake/RippledCore.cmake index 0853513e9..02a59e169 100644 --- a/Builds/CMake/RippledCore.cmake +++ b/Builds/CMake/RippledCore.cmake @@ -449,7 +449,7 @@ target_sources (rippled PRIVATE src/ripple/app/tx/impl/NFTokenMint.cpp src/ripple/app/tx/impl/OfferStream.cpp src/ripple/app/tx/impl/OptionCreate.cpp - src/ripple/app/tx/impl/OptionExecute.cpp + src/ripple/app/tx/impl/OptionExercise.cpp src/ripple/app/tx/impl/OptionList.cpp src/ripple/app/tx/impl/PayChan.cpp src/ripple/app/tx/impl/Payment.cpp diff --git a/src/ripple/app/tx/impl/OptionCreate.cpp b/src/ripple/app/tx/impl/OptionCreate.cpp index 4a81007bb..24928b13a 100644 --- a/src/ripple/app/tx/impl/OptionCreate.cpp +++ b/src/ripple/app/tx/impl/OptionCreate.cpp @@ -124,7 +124,7 @@ sealOption( bool const _isSell = (flags & tfAction) != 0; // Skip Sealed Options - if (sleItem->getFieldU32(sfToSeal) == 0) + if (sleItem->getFieldU32(sfOpenInterest) == 0) { continue; } @@ -165,8 +165,7 @@ OptionCreate::doApply() std::uint32_t const quantity = ctx_.tx.getFieldU32(sfQuantity); std::optional const swapID = ctx_.tx[~sfSwapID]; - STAmount const totalPremium = - STAmount(premium.issue(), (premium.mantissa() * quantity)); + STAmount const totalPremium = mulRound(premium, STAmount(premium.issue(), quantity), premium.issue(), false); auto sleSrcAcc = sb.peek(keylet::account(srcAccID)); if (!sleSrcAcc) @@ -184,9 +183,7 @@ OptionCreate::doApply() STAmount const quantityShares = STAmount(Issue(currency, issuer), quantity); if (strikePrice.issue() != totalPremium.issue() || strikePrice.issue() != totalPremium.issue()) - { return temBAD_ISSUER; - } bool const isPut = (flags & tfType) != 0; bool const isSell = (flags & tfAction) != 0; @@ -218,8 +215,8 @@ OptionCreate::doApply() auto sealedKeylet = ripple::keylet::unchecked(*sealID); auto sealedOption = sb.peek(sealedKeylet); sealedOption->setFieldH256(sfSwapID, optionOfferKeylet.key); - uint32_t currSealed = sealedOption->getFieldU32(sfToSeal); - sealedOption->setFieldU32(sfToSeal, currSealed - quantity); + uint32_t currSealed = sealedOption->getFieldU32(sfOpenInterest); + sealedOption->setFieldU32(sfOpenInterest, currSealed - quantity); oppAccID = sealedOption->getAccountID(sfOwner); sb.update(sealedOption); } @@ -265,14 +262,14 @@ OptionCreate::doApply() optionOffer->setFieldU64(sfOwnerNode, *page); optionOffer->setFieldH256(sfOptionID, optionID); optionOffer->setFieldU32(sfQuantity, quantity); - optionOffer->setFieldU32(sfToSeal, quantity); + optionOffer->setFieldU32(sfOpenInterest, quantity); optionOffer->setFieldAmount(sfAmount, premium); // Premium optionOffer->setFieldAmount(sfLockedBalance, STAmount(0)); // Locked if (sealID) { JLOG(j.warn()) << "Updating Option Offer: sealID"; optionOffer->setFieldH256(sfSwapID, *sealID); - optionOffer->setFieldU32(sfToSeal, 0); + optionOffer->setFieldU32(sfOpenInterest, 0); } if (isSell) { @@ -402,28 +399,29 @@ OptionCreate::doApply() else { // // 1. & 2. - // TER canBuyerXfer = trustTransferAllowed( - // sb, - // std::vector{srcAccID, oppAccID}, - // totalPremium.issue(), - // j); + TER canBuyerXfer = trustTransferAllowed( + sb, + std::vector{srcAccID, oppAccID}, + totalPremium.issue(), + j); - // if (!isTesSuccess(canBuyerXfer)) - // { - // return canBuyerXfer; - // } + if (!isTesSuccess(canBuyerXfer)) + { + return canBuyerXfer; + } - // STAmount availableBuyerFunds{accountFunds( - // sb, srcAccID, totalPremium, fhZERO_IF_FROZEN, j)}; + STAmount availableBuyerFunds{accountFunds( + sb, srcAccID, totalPremium, fhZERO_IF_FROZEN, j)}; - // if (availableBuyerFunds < totalPremium) - // return tecUNFUNDED_PAYMENT; - // if (TER result = accountSend( - // sb, srcAccID, oppAccID, totalPremium, j, true); - // !isTesSuccess(result)) - // return result; - return tecINTERNAL; + JLOG(j.warn()) << "availableBuyerFunds: " << availableBuyerFunds << "/n"; + JLOG(j.warn()) << "totalPremium: " << totalPremium << "/n"; + if (availableBuyerFunds < totalPremium) + return tecUNFUNDED_PAYMENT; + + if (TER result = accountSend(sb, srcAccID, oppAccID, totalPremium, j, true); !isTesSuccess(result)) + return result; + } sb.update(sleOppAcc); @@ -453,9 +451,9 @@ OptionCreate::doApply() if (availableBuyerFunds < quantityShares) return tecUNFUNDED_PAYMENT; - std::shared_ptr sleLine = sb.peek(keylet::line(srcAccID, quantityShares.getIssuer(), quantityShares.getCurrency())); + std::shared_ptr sleLine = ctx_.view().peek(keylet::line(srcAccID, quantityShares.getIssuer(), quantityShares.getCurrency())); - if (TER const result = trustAdjustLockedBalance(ctx_.view(), sleLine, quantityShares, 1, ctx_.journal, true); !isTesSuccess(result)) + if (TER const result = trustAdjustLockedBalance(ctx_.view(), sleLine, quantityShares, 1, ctx_.journal, WetRun); !isTesSuccess(result)) return result; } } diff --git a/src/ripple/app/tx/impl/OptionExecute.cpp b/src/ripple/app/tx/impl/OptionExercise.cpp similarity index 71% rename from src/ripple/app/tx/impl/OptionExecute.cpp rename to src/ripple/app/tx/impl/OptionExercise.cpp index 2176b24ff..fea376195 100644 --- a/src/ripple/app/tx/impl/OptionExecute.cpp +++ b/src/ripple/app/tx/impl/OptionExercise.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include #include @@ -29,13 +29,13 @@ namespace ripple { TxConsequences -OptionExecute::makeTxConsequences(PreflightContext const& ctx) +OptionExercise::makeTxConsequences(PreflightContext const& ctx) { return TxConsequences{ctx.tx, TxConsequences::normal}; } NotTEC -OptionExecute::preflight(PreflightContext const& ctx) +OptionExercise::preflight(PreflightContext const& ctx) { if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; @@ -50,12 +50,12 @@ OptionExecute::preflight(PreflightContext const& ctx) TER -OptionExecute::doApply() +OptionExercise::doApply() { if (!view().rules().enabled(featureOptions)) return temDISABLED; - Sandbox sb(&ctx_.view()); + // Sandbox sb(&ctx_.view()); beast::Journal const& j = ctx_.journal; @@ -64,24 +64,24 @@ OptionExecute::doApply() uint256 const offerID = ctx_.tx.getFieldH256(sfSwapID); auto const flags = ctx_.tx.getFlags(); - auto sleSrcAcc = sb.peek(keylet::account(srcAccID)); + auto sleSrcAcc = ctx_.view().peek(keylet::account(srcAccID)); if (!sleSrcAcc) return terNO_ACCOUNT; auto optionOfferKeylet = ripple::keylet::unchecked(offerID); - auto sleOptionOffer = sb.peek(optionOfferKeylet); + auto sleOptionOffer = ctx_.view().peek(optionOfferKeylet); if (!sleOptionOffer) return tecNO_TARGET; AccountID const ownrAccID = sleOptionOffer->getAccountID(sfOwner); auto const sealedID = sleOptionOffer->getFieldH256(sfSwapID); auto oppOfferKeylet = ripple::keylet::unchecked(sealedID); - auto sleSealedOffer = sb.peek(oppOfferKeylet); + auto sleSealedOffer = ctx_.view().peek(oppOfferKeylet); if (!sleSealedOffer) return tecNO_TARGET; AccountID const oppAccID = sleSealedOffer->getAccountID(sfOwner); - auto sleOppAcc = sb.peek(keylet::account(oppAccID)); + auto sleOppAcc = ctx_.view().peek(keylet::account(oppAccID)); if (!sleOppAcc) return terNO_ACCOUNT; @@ -89,31 +89,32 @@ OptionExecute::doApply() bool const isPut = (optionFlags & tfType) != 0; bool const isSell = (optionFlags & tfAction) != 0; - auto sleOption = sb.peek(keylet::unchecked(optionID)); + auto sleOption = ctx_.view().peek(keylet::unchecked(optionID)); if (!sleOption) return tecINTERNAL; STAmount const strikePrice = sleOption->getFieldAmount(sfStrikePrice); STAmount const quantityShares = sleSealedOffer->getFieldAmount(sfLockedBalance); std::uint32_t const quantity = sleOptionOffer->getFieldU32(sfQuantity); - STAmount const totalValue = STAmount(strikePrice.issue(), (strikePrice.mantissa() * quantity)); + STAmount const totalValue = mulRound(strikePrice, STAmount(strikePrice.issue(), quantity), strikePrice.issue(), false); - JLOG(j.warn()) << "OptionExecute: QUANTITY SHARES" << quantityShares << "\n"; - JLOG(j.warn()) << "OptionExecute: TOTAL VALUE" << totalValue << "\n"; + + JLOG(j.warn()) << "OptionExercise: QUANTITY SHARES" << quantityShares << "\n"; + JLOG(j.warn()) << "OptionExercise: TOTAL VALUE" << totalValue << "\n"; if (flags & tfOptionExpire) { - JLOG(j.warn()) << "OptionExecute: EXPIRE OPTION"; - sb.erase(sleSealedOffer); - sb.erase(sleOptionOffer); - sb.apply(ctx_.rawView()); + JLOG(j.warn()) << "OptionExercise: EXPIRE OPTION"; + ctx_.view().erase(sleSealedOffer); + ctx_.view().erase(sleOptionOffer); + // sb.apply(ctx_.rawView()); return tesSUCCESS; } switch (isPut) { case 0: { - JLOG(j.warn()) << "OptionExecute: EXERCISE CALL"; + JLOG(j.warn()) << "OptionExercise: EXERCISE CALL"; STAmount hBalance = mSourceBalance; @@ -129,7 +130,6 @@ OptionExecute::doApply() if (hBalance < beast::zero || hBalance > mSourceBalance) return tecINTERNAL; - // 2. STAmount wBalance = sleOppAcc->getFieldAmount(sfBalance); STAmount prior = wBalance; @@ -142,7 +142,7 @@ OptionExecute::doApply() { // 1. & 2. TER canBuyerXfer = trustTransferAllowed( - sb, + ctx_.view(), std::vector{srcAccID, oppAccID}, totalValue.issue(), j); @@ -153,13 +153,13 @@ OptionExecute::doApply() } STAmount availableBuyerFunds{accountFunds( - sb, srcAccID, totalValue, fhZERO_IF_FROZEN, j)}; + ctx_.view(), srcAccID, totalValue, fhZERO_IF_FROZEN, j)}; if (availableBuyerFunds < totalValue) return tecUNFUNDED_PAYMENT; if (TER result = accountSend( - sb, srcAccID, oppAccID, totalValue, j, true); + ctx_.view(), srcAccID, oppAccID, totalValue, j, true); !isTesSuccess(result)) return result; } @@ -175,38 +175,34 @@ OptionExecute::doApply() } else { - AccountID const issuerAccID = totalValue.getIssuer(); - { - // check permissions - if (issuerAccID == oppAccID || issuerAccID == srcAccID) - { - // no permission check needed when the issuer sends out or a - // subscriber sends back RH TODO: move this condition into - // trustTransferAllowed, guarded by an amendment - } - else if (TER canXfer = trustTransferAllowed( - sb, - std::vector{oppAccID, srcAccID}, - quantityShares.issue(), - j); - !isTesSuccess(canXfer)) - return canXfer; - - STAmount availableFunds{accountFunds(sb, oppAccID, quantityShares, fhZERO_IF_FROZEN, j)}; - - if (availableFunds < quantityShares) - return tecUNFUNDED_PAYMENT; - - // action the transfer - if (TER result = accountSend(sb, oppAccID, srcAccID, quantityShares, j, true); !isTesSuccess(result)) - return result; - } + // Rate lockedRate = ripple::Rate(slep->getFieldU32(sfTransferRate)); + // auto const issuerAccID = totalPremium.getIssuer(); + // auto const xferRate = transferRate(view(), issuerAccID); + // // // update if issuer rate is less than locked rate + // // if (xferRate < lockedRate) + // // lockedRate = xferRate; + // all the significant complexity of checking the validity of this + // transfer and ensuring the lines exist etc is hidden away in this + // function, all we need to do is call it and return if unsuccessful. + TER const result = trustTransferLockedBalance( + ctx_.view(), + account_, // txn signing account + sleOppAcc, // src account + sleSrcAcc, // dst account + quantityShares, // xfer amount + -1, + parityRate, + j_, + WetRun // wet run; + ); + if (!isTesSuccess(result)) + return result; } break; } case 1: { - JLOG(j.warn()) << "OptionExecute: EXERCISE PUT"; + JLOG(j.warn()) << "OptionExercise: EXERCISE PUT"; if (isXRP(quantityShares)) { // add the total value to the holder @@ -245,16 +241,16 @@ OptionExecute::doApply() } // apply - sb.update(sleOppAcc); - sb.update(sleSrcAcc); - sb.erase(sleSealedOffer); - sb.erase(sleOptionOffer); - sb.apply(ctx_.rawView()); + ctx_.view().update(sleOppAcc); + ctx_.view().update(sleSrcAcc); + ctx_.view().erase(sleSealedOffer); + ctx_.view().erase(sleOptionOffer); + // sb.apply(ctx_.rawView()); return tesSUCCESS; } XRPAmount -OptionExecute::calculateBaseFee(ReadView const& view, STTx const& tx) +OptionExercise::calculateBaseFee(ReadView const& view, STTx const& tx) { return Transactor::calculateBaseFee(view, tx); } diff --git a/src/ripple/app/tx/impl/OptionExecute.h b/src/ripple/app/tx/impl/OptionExercise.h similarity index 94% rename from src/ripple/app/tx/impl/OptionExecute.h rename to src/ripple/app/tx/impl/OptionExercise.h index c6fa1288a..7e7b7c706 100644 --- a/src/ripple/app/tx/impl/OptionExecute.h +++ b/src/ripple/app/tx/impl/OptionExercise.h @@ -27,12 +27,12 @@ namespace ripple { -class OptionExecute : public Transactor +class OptionExercise : public Transactor { public: static constexpr ConsequencesFactoryType ConsequencesFactory{Custom}; - explicit OptionExecute(ApplyContext& ctx) : Transactor(ctx) + explicit OptionExercise(ApplyContext& ctx) : Transactor(ctx) { } diff --git a/src/ripple/app/tx/impl/applySteps.cpp b/src/ripple/app/tx/impl/applySteps.cpp index fee667983..ea6d86a57 100644 --- a/src/ripple/app/tx/impl/applySteps.cpp +++ b/src/ripple/app/tx/impl/applySteps.cpp @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include @@ -129,8 +129,8 @@ invoke_preflight(PreflightContext const& ctx) return invoke_preflight_helper(ctx); case ttOPTION_CREATE: return invoke_preflight_helper(ctx); - case ttOPTION_EXECUTE: - return invoke_preflight_helper(ctx); + case ttOPTION_EXERCISE: + return invoke_preflight_helper(ctx); case ttOPTION_LIST: return invoke_preflight_helper(ctx); case ttPAYCHAN_CLAIM: @@ -256,8 +256,8 @@ invoke_preclaim(PreclaimContext const& ctx) return invoke_preclaim(ctx); case ttOPTION_CREATE: return invoke_preclaim(ctx); - case ttOPTION_EXECUTE: - return invoke_preclaim(ctx); + case ttOPTION_EXERCISE: + return invoke_preclaim(ctx); case ttOPTION_LIST: return invoke_preclaim(ctx); case ttPAYCHAN_CLAIM: @@ -345,8 +345,8 @@ invoke_calculateBaseFee(ReadView const& view, STTx const& tx) return EscrowCancel::calculateBaseFee(view, tx); case ttOPTION_CREATE: return OptionCreate::calculateBaseFee(view, tx); - case ttOPTION_EXECUTE: - return OptionExecute::calculateBaseFee(view, tx); + case ttOPTION_EXERCISE: + return OptionExercise::calculateBaseFee(view, tx); case ttOPTION_LIST: return OptionList::calculateBaseFee(view, tx); case ttPAYCHAN_CLAIM: @@ -496,8 +496,8 @@ invoke_apply(ApplyContext& ctx) OptionCreate p(ctx); return p(); } - case ttOPTION_EXECUTE: { - OptionExecute p(ctx); + case ttOPTION_EXERCISE: { + OptionExercise p(ctx); return p(); } case ttOPTION_LIST: { diff --git a/src/ripple/protocol/SField.h b/src/ripple/protocol/SField.h index 3104aba90..c9248ab55 100644 --- a/src/ripple/protocol/SField.h +++ b/src/ripple/protocol/SField.h @@ -411,7 +411,7 @@ extern SF_UINT32 const sfFirstNFTokenSequence; extern SF_UINT32 const sfImportSequence; extern SF_UINT32 const sfXahauActivationLgrSeq; extern SF_UINT32 const sfQuantity; -extern SF_UINT32 const sfToSeal; +extern SF_UINT32 const sfOpenInterest; // 64-bit integers (common) extern SF_UINT64 const sfIndexNext; diff --git a/src/ripple/protocol/TxFormats.h b/src/ripple/protocol/TxFormats.h index 2da02fcb8..3a5e543e4 100644 --- a/src/ripple/protocol/TxFormats.h +++ b/src/ripple/protocol/TxFormats.h @@ -187,7 +187,7 @@ enum TxType : std::uint16_t ttUNL_REPORT = 104, ttOPTION_LIST = 105, ttOPTION_CREATE = 106, - ttOPTION_EXECUTE = 107, + ttOPTION_EXERCISE = 107, }; // clang-format on diff --git a/src/ripple/protocol/impl/LedgerFormats.cpp b/src/ripple/protocol/impl/LedgerFormats.cpp index e26078b5a..f2f71f7b2 100644 --- a/src/ripple/protocol/impl/LedgerFormats.cpp +++ b/src/ripple/protocol/impl/LedgerFormats.cpp @@ -387,7 +387,7 @@ LedgerFormats::LedgerFormats() {sfLockedBalance, soeREQUIRED}, // Locked Amount {sfAmount, soeREQUIRED}, // Premium {sfQuantity, soeREQUIRED}, // Quantity - {sfToSeal, soeREQUIRED}, // To Seal + {sfOpenInterest, soeREQUIRED}, // To Seal {sfBookDirectory, soeREQUIRED}, {sfBookNode, soeREQUIRED}, {sfSwapID, soeOPTIONAL}, // MatchID diff --git a/src/ripple/protocol/impl/SField.cpp b/src/ripple/protocol/impl/SField.cpp index 7749f5be0..ccf896f00 100644 --- a/src/ripple/protocol/impl/SField.cpp +++ b/src/ripple/protocol/impl/SField.cpp @@ -157,7 +157,7 @@ CONSTRUCT_TYPED_SFIELD(sfLockCount, "LockCount", UINT32, CONSTRUCT_TYPED_SFIELD(sfFirstNFTokenSequence, "FirstNFTokenSequence", UINT32, 50); -CONSTRUCT_TYPED_SFIELD(sfToSeal, "ToSeal", UINT32, 94); +CONSTRUCT_TYPED_SFIELD(sfOpenInterest, "OpenInterest", UINT32, 94); CONSTRUCT_TYPED_SFIELD(sfQuantity, "Quantity", UINT32, 95); CONSTRUCT_TYPED_SFIELD(sfXahauActivationLgrSeq, "XahauActivationLgrSeq",UINT32, 96); CONSTRUCT_TYPED_SFIELD(sfImportSequence, "ImportSequence", UINT32, 97); diff --git a/src/ripple/protocol/impl/TxFormats.cpp b/src/ripple/protocol/impl/TxFormats.cpp index 15a14c6a8..b40959fac 100644 --- a/src/ripple/protocol/impl/TxFormats.cpp +++ b/src/ripple/protocol/impl/TxFormats.cpp @@ -479,8 +479,8 @@ TxFormats::TxFormats() }, commonFields); - add(jss::OptionExecute, - ttOPTION_EXECUTE, + add(jss::OptionExercise, + ttOPTION_EXERCISE, { {sfOptionID, soeREQUIRED}, {sfSwapID, soeOPTIONAL}, diff --git a/src/ripple/protocol/jss.h b/src/ripple/protocol/jss.h index bc0c144b4..204245655 100644 --- a/src/ripple/protocol/jss.h +++ b/src/ripple/protocol/jss.h @@ -113,7 +113,7 @@ JSS(OfferCreate); // transaction type. JSS(OfferSequence); // field. JSS(Option); // ledger type. JSS(OptionCreate); // transaction type. -JSS(OptionExecute); // transaction type. +JSS(OptionExercise); // transaction type. JSS(OptionList); // transaction type. JSS(OptionOffer); // ledger type. JSS(Paths); // in/out: TransactionSign diff --git a/src/test/app/Option_test.cpp b/src/test/app/Option_test.cpp index ea682e13d..37258cb7f 100644 --- a/src/test/app/Option_test.cpp +++ b/src/test/app/Option_test.cpp @@ -106,7 +106,7 @@ struct Option_test : public beast::unit_test::suite { using namespace jtx; Json::Value jv; - jv[jss::TransactionType] = jss::OptionExecute; + jv[jss::TransactionType] = jss::OptionExercise; jv[jss::Account] = account.human(); jv[sfOptionID.jsonName] = to_string(optionId); jv[sfSwapID.jsonName] = to_string(offerId);