fix finalAmount + guard dest Issuer

This commit is contained in:
Denis Angell
2023-01-29 05:49:54 -05:00
committed by Richard Holland
parent 31da4bf8d4
commit f8591d0fd6

View File

@@ -811,7 +811,8 @@ trustTransferLockedBalance(
bool srcHigh = srcAccID > issuerAccID; bool srcHigh = srcAccID > issuerAccID;
bool dstHigh = dstAccID > issuerAccID; bool dstHigh = dstAccID > issuerAccID;
bool isIssuer = issuerAccID == srcAccID; bool srcIssuer = issuerAccID == srcAccID;
bool dstIssuer = issuerAccID == dstAccID;
// check for freezing, auth, no ripple and TL sanity // check for freezing, auth, no ripple and TL sanity
{ {
@@ -825,13 +826,36 @@ trustTransferLockedBalance(
return result; return result;
} }
// dstLow XNOR srcLow tells us if we need to flip the balance amount
// on the destination line
bool flipDstAmt = !((dstHigh && srcHigh) || (!dstHigh && !srcHigh));
// default dstAmount to amount
auto dstAmt = amount;
// if tx acct not source issuer or dest issuer
// and xfer rate is not parity
if ((!srcIssuer || !dstIssuer) && lXferRate != parityRate)
{
// compute transfer fee, if any
auto const xferFee = amount.value() -
divideRound(
amount,
lXferRate,
amount.issue(),
true);
// compute balance to transfer
dstAmt = amount.value() - xferFee;
}
// ensure source line exists // ensure source line exists
Keylet klSrcLine{keylet::line(srcAccID, issuerAccID, currency)}; Keylet klSrcLine{keylet::line(srcAccID, issuerAccID, currency)};
SLEPtr sleSrcLine = peek(klSrcLine); SLEPtr sleSrcLine = peek(klSrcLine);
// source account is not issuer use locked balance // if source account is not issuer
if (!isIssuer) if (!srcIssuer)
{ {
// if source account has no trust line - fail
if (!sleSrcLine) if (!sleSrcLine)
return tecNO_LINE; return tecNO_LINE;
@@ -916,28 +940,17 @@ trustTransferLockedBalance(
} }
} }
// dstLow XNOR srcLow tells us if we need to flip the balance amount
// on the destination line
bool flipDstAmt = !((dstHigh && srcHigh) || (!dstHigh && !srcHigh));
// default to amount
auto dstAmt = amount;
// if transfer rate
if (lXferRate != parityRate)
{
// compute transfer fee, if any
auto const xferFee = amount.value() -
divideRound(amount, lXferRate, amount.issue(), true);
// compute balance to transfer
dstAmt = amount.value() - xferFee;
}
// check for a destination line // check for a destination line
Keylet klDstLine = keylet::line(dstAccID, issuerAccID, currency); Keylet klDstLine = keylet::line(dstAccID, issuerAccID, currency);
SLEPtr sleDstLine = peek(klDstLine); SLEPtr sleDstLine = peek(klDstLine);
// if dest account is not issuer
if (!dstIssuer)
{
// if dest acct has no trustline
if (!sleDstLine) if (!sleDstLine)
{ {
// in most circumstances a missing destination line is a deal breaker // if tx acct is not dest acct and src acct is not dest acct
if (actingAccID != dstAccID && srcAccID != dstAccID) if (actingAccID != dstAccID && srcAccID != dstAccID)
return tecNO_LINE; return tecNO_LINE;
@@ -947,10 +960,10 @@ trustTransferLockedBalance(
if (std::uint32_t const ownerCount = {sleDstAcc->at(sfOwnerCount)}; if (std::uint32_t const ownerCount = {sleDstAcc->at(sfOwnerCount)};
dstBalanceDrops < view.fees().accountReserve(ownerCount + 1)) dstBalanceDrops < view.fees().accountReserve(ownerCount + 1))
return tecNO_LINE_INSUF_RESERVE; return tecNO_LINE_INSUF_RESERVE;
// yes we can... we will
auto const finalDstAmt = // compute final destination amount
isIssuer ? dstAmt : flipDstAmt ? -dstAmt : dstAmt; auto const finalDstAmt = flipDstAmt ? -dstAmt : dstAmt;
// create destination trust line
if constexpr (!dryRun) if constexpr (!dryRun)
{ {
// clang-format off // clang-format off
@@ -978,18 +991,21 @@ trustTransferLockedBalance(
} }
else else
{ {
// the dst line does exist, and it would have been checked above // dest trust line does exist
// in trustTransferAllowed for NoRipple and Freeze flags // checked NoRipple and Freeze flags in trustTransferAllowed
// check the limit // check the limit
STAmount dstLimit = STAmount dstLimit =
dstHigh ? (*sleDstLine)[sfHighLimit] : (*sleDstLine)[sfLowLimit]; dstHigh ? (*sleDstLine)[sfHighLimit] : (*sleDstLine)[sfLowLimit];
// get prior balance
STAmount priorBalance = STAmount priorBalance =
dstHigh ? -((*sleDstLine)[sfBalance]) : (*sleDstLine)[sfBalance]; dstHigh ? -((*sleDstLine)[sfBalance]) : (*sleDstLine)[sfBalance];
// combine prior with dest amount for final
STAmount finalBalance = priorBalance + dstAmt; STAmount finalBalance = priorBalance + dstAmt;
// if final is less than prior - fail
if (finalBalance < priorBalance) if (finalBalance < priorBalance)
{ {
JLOG(j.warn()) << "trustTransferLockedBalance resulted in a " JLOG(j.warn()) << "trustTransferLockedBalance resulted in a "
@@ -997,6 +1013,7 @@ trustTransferLockedBalance(
return tecINTERNAL; return tecINTERNAL;
} }
// if final is more than dest limit and tx acct is not dest acct - fail
if (finalBalance > dstLimit && actingAccID != dstAccID) if (finalBalance > dstLimit && actingAccID != dstAccID)
{ {
JLOG(j.trace()) << "trustTransferLockedBalance would increase dest " JLOG(j.trace()) << "trustTransferLockedBalance would increase dest "
@@ -1004,26 +1021,30 @@ trustTransferLockedBalance(
return tecPATH_DRY; return tecPATH_DRY;
} }
// check if there is significant precision loss // if there is significant precision loss - fail
if (!isAddable(priorBalance, dstAmt)) if (!isAddable(priorBalance, dstAmt))
return tecPRECISION_LOSS; return tecPRECISION_LOSS;
finalBalance = // compute final balance to send - reverse sign for high dest
isIssuer ? -finalBalance : dstHigh ? -finalBalance : finalBalance; finalBalance = dstHigh ? -finalBalance : finalBalance;
// if not dry run - set dst line field
if constexpr (!dryRun) if constexpr (!dryRun)
sleDstLine->setFieldAmount(sfBalance, finalBalance); sleDstLine->setFieldAmount(sfBalance, finalBalance);
} }
}
if constexpr (!dryRun) if constexpr (!dryRun)
{ {
static_assert(std::is_same<V, ApplyView>::value); static_assert(std::is_same<V, ApplyView>::value);
// check if source line ended up in default state and adjust owner count // if source account is not issuer
// if it did if (!srcIssuer)
if (!isIssuer)
{ {
// check if source line ended up in default state
if (isTrustDefault(sleSrcAcc, sleSrcLine)) if (isTrustDefault(sleSrcAcc, sleSrcLine))
{ {
// adjust owner count
uint32_t flags = sleSrcLine->getFieldU32(sfFlags); uint32_t flags = sleSrcLine->getFieldU32(sfFlags);
uint32_t fReserve{srcHigh ? lsfHighReserve : lsfLowReserve}; uint32_t fReserve{srcHigh ? lsfHighReserve : lsfLowReserve};
if (flags & fReserve) if (flags & fReserve)
@@ -1033,11 +1054,13 @@ trustTransferLockedBalance(
view.update(sleSrcAcc); view.update(sleSrcAcc);
} }
} }
// update source line
view.update(sleSrcLine); view.update(sleSrcLine);
} }
// a destination line already existed and was updated // if dest line exists
if (sleDstLine) if (sleDstLine)
// update dest line
view.update(sleDstLine); view.update(sleDstLine);
} }
return tesSUCCESS; return tesSUCCESS;