diff --git a/src/cpp/ripple/OfferCreateTransactor.cpp b/src/cpp/ripple/OfferCreateTransactor.cpp index ce1206d35..5055e8715 100644 --- a/src/cpp/ripple/OfferCreateTransactor.cpp +++ b/src/cpp/ripple/OfferCreateTransactor.cpp @@ -339,31 +339,32 @@ TER OfferCreateTransactor::takeOffers( TER OfferCreateTransactor::doApply() { cLog(lsWARNING) << "OfferCreate> " << mTxn.getJson(0); - const uint32 uTxFlags = mTxn.getFlags(); - const bool bPassive = isSetBit(uTxFlags, tfPassive); - const bool bMarket = isSetBit(uTxFlags, tfMarket); - STAmount saTakerPays = mTxn.getFieldAmount(sfTakerPays); - STAmount saTakerGets = mTxn.getFieldAmount(sfTakerGets); + const uint32 uTxFlags = mTxn.getFlags(); + const bool bPassive = isSetBit(uTxFlags, tfPassive); + const bool bImmediateOrCancel = isSetBit(uTxFlags, tfImmediateOrCancel); + const bool bFillOrKill = isSetBit(uTxFlags, tfFillOrKill); + STAmount saTakerPays = mTxn.getFieldAmount(sfTakerPays); + STAmount saTakerGets = mTxn.getFieldAmount(sfTakerGets); cLog(lsINFO) << boost::str(boost::format("OfferCreate: saTakerPays=%s saTakerGets=%s") % saTakerPays.getFullText() % saTakerGets.getFullText()); - const uint160 uPaysIssuerID = saTakerPays.getIssuer(); - const uint160 uGetsIssuerID = saTakerGets.getIssuer(); - const uint32 uExpiration = mTxn.getFieldU32(sfExpiration); - const bool bHaveExpiration = mTxn.isFieldPresent(sfExpiration); - const uint32 uSequence = mTxn.getSequence(); + const uint160 uPaysIssuerID = saTakerPays.getIssuer(); + const uint160 uGetsIssuerID = saTakerGets.getIssuer(); + const uint32 uExpiration = mTxn.getFieldU32(sfExpiration); + const bool bHaveExpiration = mTxn.isFieldPresent(sfExpiration); + const uint32 uSequence = mTxn.getSequence(); - const uint256 uLedgerIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); + const uint256 uLedgerIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); cLog(lsINFO) << "OfferCreate: Creating offer node: " << uLedgerIndex.ToString() << " uSequence=" << uSequence; - const uint160 uPaysCurrency = saTakerPays.getCurrency(); - const uint160 uGetsCurrency = saTakerGets.getCurrency(); - const uint64 uRate = STAmount::getRate(saTakerGets, saTakerPays); + const uint160 uPaysCurrency = saTakerPays.getCurrency(); + const uint160 uGetsCurrency = saTakerGets.getCurrency(); + const uint64 uRate = STAmount::getRate(saTakerGets, saTakerPays); - TER terResult = tesSUCCESS; + TER terResult = tesSUCCESS; uint256 uDirectory; // Delete hints. uint64 uOwnerNode; uint64 uBookNode; @@ -374,6 +375,12 @@ TER OfferCreateTransactor::doApply() return temINVALID_FLAG; } + else if (bImmediateOrCancel && bFillOrKill) + { + cLog(lsINFO) << "OfferCreate: Malformed transaction: both IoC and FoK set."; + + return temINVALID_FLAG; + } else if (bHaveExpiration && !uExpiration) { cLog(lsWARNING) << "OfferCreate: Malformed offer: bad expiration"; @@ -490,10 +497,15 @@ TER OfferCreateTransactor::doApply() // If ledger is not final, can vote no. terResult = bOpenLedger ? telFAILED_PROCESSING : tecFAILED_PROCESSING; } + else if (bFillOrKill && (saTakerPays || saTakerGets)) + { + // Fill or kill and have leftovers. + terResult = tecKILL; + } else if ( !saTakerPays // Wants nothing more. || !saTakerGets // Offering nothing more. - || bMarket // Do not persist. + || bImmediateOrCancel // Do not persist. || !mEngine->getNodes().accountFunds(mTxnAccountID, saTakerGets).isPositive() // Not funded. || bUnfunded) // Consider unfunded. { diff --git a/src/cpp/ripple/TransactionErr.h b/src/cpp/ripple/TransactionErr.h index a1d9fb690..05c5c9ad6 100644 --- a/src/cpp/ripple/TransactionErr.h +++ b/src/cpp/ripple/TransactionErr.h @@ -123,6 +123,7 @@ enum TER // aka TransactionEngineResult tecUNFUNDED_OFFER = 103, tecUNFUNDED_PAYMENT = 104, tecFAILED_PROCESSING = 105, + tecKILL = 106, // tesSUCCESS is not retryable. tecDIR_FULL = 121, tecINSUF_RESERVE_LINE = 122, tecINSUF_RESERVE_OFFER = 123, diff --git a/src/cpp/ripple/TransactionFormats.h b/src/cpp/ripple/TransactionFormats.h index a1c9161bb..7b285c73d 100644 --- a/src/cpp/ripple/TransactionFormats.h +++ b/src/cpp/ripple/TransactionFormats.h @@ -68,8 +68,9 @@ const uint32 tfAccountSetMask = ~(tfRequireDestTag|tfOptionalDestTag|tfRequireA // OfferCreate flags: const uint32 tfPassive = 0x00010000; -const uint32 tfMarket = 0x00020000; -const uint32 tfOfferCreateMask = ~(tfPassive|tfMarket); +const uint32 tfImmediateOrCancel = 0x00020000; +const uint32 tfFillOrKill = 0x00040000; +const uint32 tfOfferCreateMask = ~(tfPassive|tfImmediateOrCancel|tfFillOrKill); // Payment flags: const uint32 tfNoRippleDirect = 0x00010000;