From 5b1ac0b1e5e43e91fb8263738414b7aad0c898ed Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 3 Oct 2012 14:44:59 -0700 Subject: [PATCH] Add transfer support to offer taking. --- src/Amount.cpp | 74 ++++++++++++++++++++++++++++++--------- src/LedgerEntrySet.cpp | 9 +++++ src/LedgerEntrySet.h | 1 + src/SerializedTypes.h | 4 ++- src/TransactionAction.cpp | 28 +++++++-------- 5 files changed, 83 insertions(+), 33 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index ef8f417c7a..b78dbd491e 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -883,40 +883,56 @@ STAmount STAmount::setRate(uint64 rate) } // Taker gets all taker can pay for with saTakerFunds, limited by saOfferPays and saOfferFunds. -// --> saOfferFunds: Limit for saOfferPays -// --> saTakerFunds: Limit for saOfferGets : How much taker really wants. : Driver -// --> saOfferPays: Request : this should be reduced as the offer is fullfilled. -// --> saOfferGets: Request : this should be reduced as the offer is fullfilled. -// --> saTakerPays: Total : Used to know the approximate ratio of the exchange. -// --> saTakerGets: Total : Used to know the approximate ratio of the exchange. -// <-- saTakerPaid: Actual -// <-- saTakerGot: Actual -// <-- bRemove: remove offer it is either fullfilled or unfunded +// --> uTakerPaysRate: >= QUALITY_ONE +// --> uOfferPaysRate: >= QUALITY_ONE +// --> saOfferFunds: Limit for saOfferPays +// --> saTakerFunds: Limit for saOfferGets : How much taker really wants. : Driver +// --> saOfferPays: Request : this should be reduced as the offer is fullfilled. +// --> saOfferGets: Request : this should be reduced as the offer is fullfilled. +// --> saTakerPays: Total : Used to know the approximate ratio of the exchange. +// --> saTakerGets: Total : Used to know the approximate ratio of the exchange. +// <-- saTakerPaid: Actual +// <-- saTakerGot: Actual +// <-- saTakerIssuerFee: Actual +// <-- saOfferIssuerFee: Actual +// <-- bRemove: remove offer it is either fullfilled or unfunded bool STAmount::applyOffer( + const uint32 uTakerPaysRate, const uint32 uOfferPaysRate, const STAmount& saOfferFunds, const STAmount& saTakerFunds, const STAmount& saOfferPays, const STAmount& saOfferGets, const STAmount& saTakerPays, const STAmount& saTakerGets, - STAmount& saTakerPaid, STAmount& saTakerGot) + STAmount& saTakerPaid, STAmount& saTakerGot, + STAmount& saTakerIssuerFee, STAmount& saOfferIssuerFee) { saOfferGets.throwComparable(saTakerPays); assert(!saOfferFunds.isZero() && !saTakerFunds.isZero()); // Must have funds. assert(!saOfferGets.isZero() && !saOfferPays.isZero()); // Must not be a null offer. + // Amount offer can pay out, limited by funds and fees. + STAmount saOfferFundsAvailable = QUALITY_ONE == uOfferPaysRate + ? saOfferFunds + : STAmount::divide(saOfferFunds, STAmount(CURRENCY_ONE, uOfferPaysRate, -9)); + // Amount offer can pay out, limited by offer and funds. - STAmount saOfferPaysAvailable = saOfferFunds < saOfferPays ? saOfferFunds : saOfferPays; + STAmount saOfferPaysAvailable = std::min(saOfferFundsAvailable, saOfferPays); // Amount offer can get in proportion, limited by offer funds. STAmount saOfferGetsAvailable = - saOfferFunds == saOfferPays + saOfferFundsAvailable == saOfferPays ? saOfferGets // Offer was fully funded, avoid shenanigans. : divide(multiply(saTakerPays, saOfferPaysAvailable, CURRENCY_ONE, ACCOUNT_ONE), saTakerGets, saOfferGets.getCurrency(), saOfferGets.getIssuer()); - if (saOfferGets == saOfferGetsAvailable && saTakerFunds >= saOfferGets) + // Amount taker can spend, limited by funds and fees. + STAmount saTakerFundsAvailable = QUALITY_ONE == uTakerPaysRate + ? saTakerFunds + : STAmount::divide(saTakerFunds, STAmount(CURRENCY_ONE, uTakerPaysRate, -9)); + + if (saOfferGets == saOfferGetsAvailable && saTakerFundsAvailable >= saOfferGets) { // Taker gets all of offer available. - saTakerPaid = saOfferGets; // Taker paid what offer could get. - saTakerGot = saOfferPays; // Taker got what offer could pay. + saTakerPaid = saOfferGets; // Taker paid what offer could get. + saTakerGot = saOfferPays; // Taker got what offer could pay. Log(lsINFO) << "applyOffer: took all outright"; } @@ -934,8 +950,32 @@ bool STAmount::applyOffer( saTakerPaid = saTakerFunds; // Taker paid all he had. saTakerGot = divide(multiply(saTakerFunds, saOfferPaysAvailable, CURRENCY_ONE, ACCOUNT_ONE), saOfferGetsAvailable, saOfferPays.getCurrency(), saOfferPays.getIssuer()); - Log(lsINFO) << "applyOffer: saTakerGot=" << saTakerGot; - Log(lsINFO) << "applyOffer: saOfferPaysAvailable=" << saOfferPaysAvailable; + Log(lsINFO) << "applyOffer: saTakerGot=" << saTakerGot.getFullText(); + Log(lsINFO) << "applyOffer: saOfferPaysAvailable=" << saOfferPaysAvailable.getFullText(); + } + + if (uTakerPaysRate == QUALITY_ONE) + { + saTakerIssuerFee = STAmount(saTakerPaid.getCurrency(), saTakerPaid.getIssuer()); + } + else + { + // Compute fees in a rounding safe way. + STAmount saTotal = STAmount::multiply(saTakerPaid, STAmount(CURRENCY_ONE, uTakerPaysRate, -9)); + + saTakerIssuerFee = (saTotal > saTakerFunds) ? saTakerFunds-saTakerPaid : saTotal - saTakerPaid; + } + + if (uOfferPaysRate == QUALITY_ONE) + { + saOfferIssuerFee = STAmount(saTakerGot.getCurrency(), saTakerGot.getIssuer()); + } + else + { + // Compute fees in a rounding safe way. + STAmount saTotal = STAmount::multiply(saTakerPaid, STAmount(CURRENCY_ONE, uTakerPaysRate, -9)); + + saOfferIssuerFee = (saTotal > saOfferFunds) ? saOfferFunds-saTakerGot : saTotal - saTakerGot; } return saTakerGot >= saOfferPays; diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 22f0798422..478290bb33 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -875,6 +875,15 @@ uint32 LedgerEntrySet::rippleTransferRate(const uint160& uIssuerID) return uQuality; } +uint32 LedgerEntrySet::rippleTransferRate(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID) +{ + uint32 uQuality; + + return uSenderID == uIssuerID || uReceiverID == uIssuerID + ? QUALITY_ONE + : rippleTransferRate(uIssuerID); +} + // XXX Might not need this, might store in nodes on calc reverse. uint32 LedgerEntrySet::rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID, SField::ref sfLow, SField::ref sfHigh) { diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index 8a7c926c4e..be44b0e973 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -102,6 +102,7 @@ public: // Balance functions. uint32 rippleTransferRate(const uint160& uIssuerID); + uint32 rippleTransferRate(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID); STAmount rippleOwed(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID); STAmount rippleLimit(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID); uint32 rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID, diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 7bafa039d5..a91e2fe97c 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -343,10 +343,12 @@ public: // Someone is offering X for Y, I try to pay Z, how much do I get? // And what's left of the offer? And how much do I actually pay? static bool applyOffer( + const uint32 uTakerPaysRate, const uint32 uOfferPaysRate, const STAmount& saOfferFunds, const STAmount& saTakerFunds, const STAmount& saOfferPays, const STAmount& saOfferGets, const STAmount& saTakerPays, const STAmount& saTakerGets, - STAmount& saTakerPaid, STAmount& saTakerGot); + STAmount& saTakerPaid, STAmount& saTakerGot, + STAmount& saTakerIssuerFee, STAmount& saOfferIssuerFee); // Someone is offering X for Y, I need Z, how much do I pay static STAmount getPay(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed); diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index bf96f344f8..35ed8397dc 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -822,6 +822,8 @@ TER TransactionEngine::takeOffers( saPay = saTakerFunds; STAmount saSubTakerPaid; STAmount saSubTakerGot; + STAmount saTakerIssuerFee; + STAmount saOfferIssuerFee; Log(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText(); Log(lsINFO) << "takeOffers: applyOffer: saTakerPaid: " << saTakerPaid.getFullText(); @@ -832,20 +834,10 @@ TER TransactionEngine::takeOffers( Log(lsINFO) << "takeOffers: applyOffer: saOfferGets: " << saOfferGets.getFullText(); Log(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText(); Log(lsINFO) << "takeOffers: applyOffer: saTakerGets: " << saTakerGets.getFullText(); -#if 0 - STAmount saTakerPaysRate = - uTakerPaysAccountID == uTakerAccountID // Taker is issuing, no fee. - || uTakerPaysAccountID == uOfferAccountID // Taker is redeeming, no fee. - ? 0.0 - : getRate(uTakerPaysAccountID); - STAmount saOfferPaysRate = - uTakerGetsAccountID == uTakerGetsAccountID // Offerer is redeeming, no fee. - || uTakerGetsAccountID == uOfferAccountID // Offerer is issuing, no fee. - ? 0.0 - : getRate(uTakerGetsAccountID); -#endif bool bOfferDelete = STAmount::applyOffer( + mNodes.rippleTransferRate(uTakerAccountID, uOfferOwnerID, uTakerPaysAccountID), + mNodes.rippleTransferRate(uOfferOwnerID, uTakerAccountID, uTakerGetsAccountID), saOfferFunds, saPay, // Driver XXX need to account for fees. saOfferPays, @@ -853,7 +845,9 @@ TER TransactionEngine::takeOffers( saTakerPays, saTakerGets, saSubTakerPaid, - saSubTakerGot); + saSubTakerGot, + saTakerIssuerFee, + saOfferIssuerFee); Log(lsINFO) << "takeOffers: applyOffer: saSubTakerPaid: " << saSubTakerPaid.getFullText(); Log(lsINFO) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText(); @@ -884,16 +878,20 @@ TER TransactionEngine::takeOffers( } // Offer owner pays taker. - saSubTakerGot.setIssuer(uTakerGetsAccountID); // XXX Move this earlier? + // saSubTakerGot.setIssuer(uTakerGetsAccountID); // XXX Move this earlier? + assert(!!saSubTakerGot.getIssuer()); mNodes.accountSend(uOfferOwnerID, uTakerAccountID, saSubTakerGot); + mNodes.accountSend(uOfferOwnerID, uTakerGetsAccountID, saOfferIssuerFee); saTakerGot += saSubTakerGot; // Taker pays offer owner. - saSubTakerPaid.setIssuer(uTakerPaysAccountID); + // saSubTakerPaid.setIssuer(uTakerPaysAccountID); + assert(!!saSubTakerPaid.getIssuer()); mNodes.accountSend(uTakerAccountID, uOfferOwnerID, saSubTakerPaid); + mNodes.accountSend(uTakerAccountID, uTakerPaysAccountID, saTakerIssuerFee); saTakerPaid += saSubTakerPaid; }