mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
templates
This commit is contained in:
@@ -243,7 +243,7 @@ EscrowCreate::doApply()
|
|||||||
// check if the escrow is capable of being
|
// check if the escrow is capable of being
|
||||||
// finished before we allow it to be created
|
// finished before we allow it to be created
|
||||||
if (TER result =
|
if (TER result =
|
||||||
trustXferAllowed(
|
trustTransferAllowed(
|
||||||
ctx_.view(),
|
ctx_.view(),
|
||||||
{account, ctx_.tx[sfDestination]},
|
{account, ctx_.tx[sfDestination]},
|
||||||
amount.issue());
|
amount.issue());
|
||||||
@@ -253,7 +253,12 @@ EscrowCreate::doApply()
|
|||||||
// perform the lock as a dry run before
|
// perform the lock as a dry run before
|
||||||
// we modify anything on-ledger
|
// we modify anything on-ledger
|
||||||
sleLine = ctx_.view().peek(keylet::line(account, amount.getIssuer(), amount.getCurrency()));
|
sleLine = ctx_.view().peek(keylet::line(account, amount.getIssuer(), amount.getCurrency()));
|
||||||
if (TER result = trustAdjustLockedBalance(ctx_.view(), sleLine, amount, true);
|
if (TER result =
|
||||||
|
trustAdjustLockedBalance(
|
||||||
|
ctx_.view(),
|
||||||
|
sleLine,
|
||||||
|
amount,
|
||||||
|
true);
|
||||||
result != tesSUCCESS)
|
result != tesSUCCESS)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -320,7 +325,12 @@ EscrowCreate::doApply()
|
|||||||
|
|
||||||
// do the lock-up for real now
|
// do the lock-up for real now
|
||||||
TER result =
|
TER result =
|
||||||
trustAdjustLockedBalance(ctx_.view(), sleLine, amount, false);
|
trustAdjustLockedBalance(
|
||||||
|
ctx_.view(),
|
||||||
|
sleLine,
|
||||||
|
amount,
|
||||||
|
false);
|
||||||
|
|
||||||
if (result != tesSUCCESS)
|
if (result != tesSUCCESS)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -423,6 +433,10 @@ EscrowFinish::doApply()
|
|||||||
if (!slep)
|
if (!slep)
|
||||||
return tecNO_TARGET;
|
return tecNO_TARGET;
|
||||||
|
|
||||||
|
AccountID const account = (*slep)[sfAccount];
|
||||||
|
auto const sle = ctx_.view().peek(keylet::account(account));
|
||||||
|
auto amount = slep->getFieldAmount(sfAmount);
|
||||||
|
|
||||||
// If a cancel time is present, a finish operation should only succeed prior
|
// If a cancel time is present, a finish operation should only succeed prior
|
||||||
// to that time. fix1571 corrects a logic error in the check that would make
|
// to that time. fix1571 corrects a logic error in the check that would make
|
||||||
// a finish only succeed strictly after the cancel time.
|
// a finish only succeed strictly after the cancel time.
|
||||||
@@ -523,7 +537,28 @@ EscrowFinish::doApply()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AccountID const account = (*slep)[sfAccount];
|
|
||||||
|
if (!isXRP(amount))
|
||||||
|
{
|
||||||
|
if (!ctx_.view().rules().enabled(featurePaychanAndEscrowForTokens))
|
||||||
|
return tefINTERNAL;
|
||||||
|
|
||||||
|
// perform a dry run of the transfer before we
|
||||||
|
// change anything on-ledger
|
||||||
|
TER result =
|
||||||
|
trustTransferLockedBalance(
|
||||||
|
ctx_.view(),
|
||||||
|
account_, // txn signing account
|
||||||
|
sle, // src account
|
||||||
|
sled, // dst account
|
||||||
|
amount, // xfer amount
|
||||||
|
ctx_.journal,
|
||||||
|
true // dry run
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != tesSUCCESS)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove escrow from owner directory
|
// Remove escrow from owner directory
|
||||||
{
|
{
|
||||||
@@ -547,28 +582,25 @@ EscrowFinish::doApply()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const sle = ctx_.view().peek(keylet::account(account));
|
|
||||||
|
|
||||||
auto amount = slep->getFieldAmount(sfAmount);
|
|
||||||
|
|
||||||
if (isXRP(amount))
|
if (isXRP(amount))
|
||||||
(*sled)[sfBalance] = (*sled)[sfBalance] + (*slep)[sfAmount];
|
(*sled)[sfBalance] = (*sled)[sfBalance] + (*slep)[sfAmount];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!ctx_.view().rules().enabled(featurePaychanAndEscrowForTokens))
|
|
||||||
return tefINTERNAL;
|
|
||||||
|
|
||||||
// all the significant complexity of checking the validity of this
|
// all the significant complexity of checking the validity of this
|
||||||
// transfer and ensuring the lines exist etc is hidden away in 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.
|
// function, all we need to do is call it and return if unsuccessful.
|
||||||
TER result =
|
TER result =
|
||||||
trustXferLockedBalance(
|
trustTransferLockedBalance(
|
||||||
ctx_.view(),
|
ctx_.view(),
|
||||||
account_, // txn signing account
|
account_, // txn signing account
|
||||||
sle, // src account
|
sle, // src account
|
||||||
sled, // dst account
|
sled, // dst account
|
||||||
amount, // xfer amount
|
amount, // xfer amount
|
||||||
ctx_.journal);
|
ctx_.journal,
|
||||||
|
false // wet run;
|
||||||
|
);
|
||||||
|
|
||||||
if (result != tesSUCCESS)
|
if (result != tesSUCCESS)
|
||||||
return result;
|
return result;
|
||||||
@@ -646,7 +678,8 @@ EscrowCancel::doApply()
|
|||||||
keylet::line(account, amount.getIssuer(), amount.getCurrency()));
|
keylet::line(account, amount.getIssuer(), amount.getCurrency()));
|
||||||
|
|
||||||
// dry run before we make any changes to ledger
|
// dry run before we make any changes to ledger
|
||||||
if (TER result = trustAdjustLockedBalance(
|
if (TER result =
|
||||||
|
trustAdjustLockedBalance(
|
||||||
ctx_.view(),
|
ctx_.view(),
|
||||||
sleLine,
|
sleLine,
|
||||||
-amount,
|
-amount,
|
||||||
@@ -689,7 +722,8 @@ EscrowCancel::doApply()
|
|||||||
return tefINTERNAL;
|
return tefINTERNAL;
|
||||||
|
|
||||||
// unlock previously locked tokens from source line
|
// unlock previously locked tokens from source line
|
||||||
TER result = trustAdjustLockedBalance(
|
TER result =
|
||||||
|
trustAdjustLockedBalance(
|
||||||
ctx_.view(),
|
ctx_.view(),
|
||||||
sleLine,
|
sleLine,
|
||||||
-amount,
|
-amount,
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ PayChanCreate::preclaim(PreclaimContext const& ctx)
|
|||||||
// check for any possible bars to a channel existing
|
// check for any possible bars to a channel existing
|
||||||
// between these accounts for this asset
|
// between these accounts for this asset
|
||||||
if (TER result =
|
if (TER result =
|
||||||
trustXferAllowed(
|
trustTransferAllowed(
|
||||||
ctx.view,
|
ctx.view,
|
||||||
{account, dst},
|
{account, dst},
|
||||||
amount.issue());
|
amount.issue());
|
||||||
@@ -269,10 +269,12 @@ PayChanCreate::preclaim(PreclaimContext const& ctx)
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
// check if the amount can be locked
|
// check if the amount can be locked
|
||||||
std::shared_ptr<SLE const> sleLine =
|
auto sleLine =
|
||||||
ctx.view.read(keylet::line(account, amount.getIssuer(), amount.getCurrency()));
|
ctx.view.read(
|
||||||
|
keylet::line(account, amount.getIssuer(), amount.getCurrency()));
|
||||||
|
|
||||||
if (TER result =
|
if (TER result =
|
||||||
trustAdjustLockedBalance<ReadView const, std::shared_ptr<SLE const>>(
|
trustAdjustLockedBalance(
|
||||||
ctx.view,
|
ctx.view,
|
||||||
sleLine,
|
sleLine,
|
||||||
amount,
|
amount,
|
||||||
@@ -671,7 +673,7 @@ PayChanClaim::doApply()
|
|||||||
// nothing requested
|
// nothing requested
|
||||||
return tecUNFUNDED_PAYMENT;
|
return tecUNFUNDED_PAYMENT;
|
||||||
|
|
||||||
auto const sled = ctx_.view().peek(keylet::account(dst));
|
auto sled = ctx_.view().peek(keylet::account(dst));
|
||||||
if (!sled)
|
if (!sled)
|
||||||
return tecNO_DST;
|
return tecNO_DST;
|
||||||
|
|
||||||
@@ -710,13 +712,15 @@ PayChanClaim::doApply()
|
|||||||
|
|
||||||
auto sleSrcAcc = ctx_.view().peek(keylet::account(src));
|
auto sleSrcAcc = ctx_.view().peek(keylet::account(src));
|
||||||
TER result =
|
TER result =
|
||||||
trustXferLockedBalance(
|
trustTransferLockedBalance
|
||||||
|
(
|
||||||
ctx_.view(),
|
ctx_.view(),
|
||||||
txAccount,
|
txAccount,
|
||||||
sleSrcAcc,
|
sleSrcAcc,
|
||||||
sled,
|
sled,
|
||||||
reqDelta,
|
reqDelta,
|
||||||
ctx_.journal);
|
ctx_.journal,
|
||||||
|
false);
|
||||||
|
|
||||||
if (result != tesSUCCESS)
|
if (result != tesSUCCESS)
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -34,11 +34,12 @@
|
|||||||
#include <ripple/protocol/Serializer.h>
|
#include <ripple/protocol/Serializer.h>
|
||||||
#include <ripple/protocol/TER.h>
|
#include <ripple/protocol/TER.h>
|
||||||
#include <ripple/protocol/Feature.h>
|
#include <ripple/protocol/Feature.h>
|
||||||
|
#include <ripple/basics/Log.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
@@ -314,14 +315,19 @@ trustAdjustLockedBalance(
|
|||||||
{
|
{
|
||||||
|
|
||||||
static_assert(
|
static_assert(
|
||||||
(std::is_same<V, ReadView const>::value && std::is_same<S, std::shared_ptr<SLE const>>::value) ||
|
(std::is_same<V, ReadView const>::value &&
|
||||||
(std::is_same<V, ApplyView>::value && std::is_same<S, std::shared_ptr<SLE>>::value));
|
std::is_same<S, std::shared_ptr<SLE const>>::value) ||
|
||||||
|
(std::is_same<V, ApplyView>::value &&
|
||||||
|
std::is_same<S, std::shared_ptr<SLE>>::value));
|
||||||
|
|
||||||
// dry runs are explicit in code, but really the view type determines
|
// dry runs are explicit in code, but really the view type determines
|
||||||
// what occurs here, so this combination is invalid.
|
// what occurs here, so this combination is invalid.
|
||||||
|
|
||||||
assert(!(std::is_same<V, ReadView const>::value && !dryRun));
|
assert(!(std::is_same<V, ReadView const>::value && !dryRun));
|
||||||
|
|
||||||
|
if (!view.rules().enabled(featurePaychanAndEscrowForTokens))
|
||||||
|
return tefINTERNAL;
|
||||||
|
|
||||||
auto const currency = deltaAmt.getCurrency();
|
auto const currency = deltaAmt.getCurrency();
|
||||||
auto const issuer = deltaAmt.getIssuer();
|
auto const issuer = deltaAmt.getIssuer();
|
||||||
|
|
||||||
@@ -337,13 +343,13 @@ trustAdjustLockedBalance(
|
|||||||
|
|
||||||
// check for freezes & auth
|
// check for freezes & auth
|
||||||
if (TER result =
|
if (TER result =
|
||||||
trustXferAllowed(
|
trustTransferAllowed(
|
||||||
view,
|
view,
|
||||||
parties,
|
parties,
|
||||||
deltaAmt.issue());
|
deltaAmt.issue());
|
||||||
result != tesSUCCESS)
|
result != tesSUCCESS)
|
||||||
{
|
{
|
||||||
printf("trustXferAllowed failed on trustAdjustLockedBalance\n");
|
printf("trustTransferAllowed failed on trustAdjustLockedBalance\n");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,30 +397,6 @@ trustAdjustLockedBalance(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class V>
|
|
||||||
ReadView const&
|
|
||||||
forceReadView(V& view)
|
|
||||||
{
|
|
||||||
static_assert(
|
|
||||||
std::is_same<V, std::shared_ptr<ReadView const>>::value ||
|
|
||||||
std::is_same<V, std::shared_ptr<ApplyView>>::value ||
|
|
||||||
std::is_same<V, ApplyView>::value ||
|
|
||||||
std::is_same<V, ReadView const>::value);
|
|
||||||
|
|
||||||
ReadView const* rv = NULL;
|
|
||||||
|
|
||||||
if constexpr (
|
|
||||||
std::is_same<V, std::shared_ptr<ReadView const>>::value ||
|
|
||||||
std::is_same<V, std::shared_ptr<ApplyView>>::value)
|
|
||||||
rv = dynamic_cast<ReadView const*>(&(*view));
|
|
||||||
else if constexpr(
|
|
||||||
std::is_same<V, ApplyView>::value ||
|
|
||||||
std::is_same<V, ReadView const>::value)
|
|
||||||
rv = dynamic_cast<ReadView const*>(&view);
|
|
||||||
|
|
||||||
return *rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if movement of a particular token between 1 or more accounts
|
// Check if movement of a particular token between 1 or more accounts
|
||||||
// (including unlocking) is forbidden by any flag or condition.
|
// (including unlocking) is forbidden by any flag or condition.
|
||||||
// If parties contains 1 entry then noRipple is not a bar to xfer.
|
// If parties contains 1 entry then noRipple is not a bar to xfer.
|
||||||
@@ -422,13 +404,20 @@ forceReadView(V& view)
|
|||||||
|
|
||||||
template<class V>
|
template<class V>
|
||||||
[[nodiscard]]TER
|
[[nodiscard]]TER
|
||||||
trustXferAllowed(
|
trustTransferAllowed(
|
||||||
V& view_,
|
V& view,
|
||||||
std::vector<AccountID> const& parties,
|
std::vector<AccountID> const& parties,
|
||||||
Issue const& issue)
|
Issue const& issue)
|
||||||
{
|
{
|
||||||
|
static_assert(
|
||||||
|
std::is_same<V, ReadView const>::value ||
|
||||||
|
std::is_same<V, ApplyView>::value);
|
||||||
|
|
||||||
ReadView const& view = forceReadView(view_);
|
typedef typename std::conditional<
|
||||||
|
std::is_same<V, ApplyView>::value,
|
||||||
|
std::shared_ptr<SLE>,
|
||||||
|
std::shared_ptr<SLE const>>::type SLEPtr;
|
||||||
|
|
||||||
|
|
||||||
if (isFakeXRP(issue.currency))
|
if (isFakeXRP(issue.currency))
|
||||||
return tecNO_PERMISSION;
|
return tecNO_PERMISSION;
|
||||||
@@ -452,7 +441,7 @@ trustXferAllowed(
|
|||||||
|
|
||||||
for (AccountID const& p: parties)
|
for (AccountID const& p: parties)
|
||||||
{
|
{
|
||||||
auto line = view.read(keylet::line(p, issue.account, issue.currency));
|
auto const line = view.read(keylet::line(p, issue.account, issue.currency));
|
||||||
if (!line)
|
if (!line)
|
||||||
{
|
{
|
||||||
if (requireAuth)
|
if (requireAuth)
|
||||||
@@ -467,7 +456,7 @@ trustXferAllowed(
|
|||||||
// missing line is a line in default state, this is not
|
// missing line is a line in default state, this is not
|
||||||
// a general bar to xfer, however additional conditions
|
// a general bar to xfer, however additional conditions
|
||||||
// do attach to completing an xfer into a default line
|
// do attach to completing an xfer into a default line
|
||||||
// but these are checked in trustXferLockedBalance at
|
// but these are checked in trustTransferLockedBalance at
|
||||||
// the point of transfer.
|
// the point of transfer.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -514,7 +503,7 @@ trustXferAllowed(
|
|||||||
|
|
||||||
if (flags & flagIssuerFreeze)
|
if (flags & flagIssuerFreeze)
|
||||||
{
|
{
|
||||||
printf("trustXferAllowed: issuerFreeze\n");
|
printf("trustTransferAllowed: issuerFreeze\n");
|
||||||
return tecFROZEN;
|
return tecFROZEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,7 +512,7 @@ trustXferAllowed(
|
|||||||
// blocks any possible xfer
|
// blocks any possible xfer
|
||||||
if (parties.size() > 1 && (flags & flagIssuerNoRipple))
|
if (parties.size() > 1 && (flags & flagIssuerNoRipple))
|
||||||
{
|
{
|
||||||
printf("trustXferAllowed: issuerNoRipple\n");
|
printf("trustTransferAllowed: issuerNoRipple\n");
|
||||||
return tecPATH_DRY;
|
return tecPATH_DRY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,7 +520,7 @@ trustXferAllowed(
|
|||||||
// the issuer has specified lsfRequireAuth
|
// the issuer has specified lsfRequireAuth
|
||||||
if (requireAuth && !(flags & flagIssuerAuth))
|
if (requireAuth && !(flags & flagIssuerAuth))
|
||||||
{
|
{
|
||||||
printf("trustXferAllowed: issuerRequireAuth\n");
|
printf("trustTransferAllowed: issuerRequireAuth\n");
|
||||||
return tecNO_AUTH;
|
return tecNO_AUTH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -540,15 +529,242 @@ trustXferAllowed(
|
|||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class V, class S>
|
||||||
[[nodiscard]] TER
|
[[nodiscard]] TER
|
||||||
trustXferLockedBalance(
|
trustTransferLockedBalance(
|
||||||
ApplyView& view,
|
V& view,
|
||||||
AccountID const& actingAccID, // the account whose tx is actioning xfer
|
AccountID const& actingAccID, // the account whose tx is actioning xfer
|
||||||
std::shared_ptr<SLE> const& sleSrcAcc,
|
S& sleSrcAcc,
|
||||||
std::shared_ptr<SLE> const& sleDstAcc,
|
S& sleDstAcc,
|
||||||
STAmount const& amount, // issuer, currency are in this field
|
STAmount const& amount, // issuer, currency are in this field
|
||||||
beast::Journal const& j);
|
beast::Journal const& j,
|
||||||
|
bool dryRun)
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef typename std::conditional<
|
||||||
|
std::is_same<V, ApplyView>::value,
|
||||||
|
std::shared_ptr<SLE>,
|
||||||
|
std::shared_ptr<SLE const>>::type SLEPtr;
|
||||||
|
|
||||||
|
auto peek = [&](Keylet& k)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same<V, ApplyView>::value)
|
||||||
|
return const_cast<ApplyView&>(view).peek(k);
|
||||||
|
else
|
||||||
|
return view.read(k);
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(!(std::is_same<V, ApplyView>::value && !dryRun));
|
||||||
|
|
||||||
|
if (!view.rules().enabled(featurePaychanAndEscrowForTokens))
|
||||||
|
return tefINTERNAL;
|
||||||
|
|
||||||
|
if (!sleSrcAcc || !sleDstAcc)
|
||||||
|
{
|
||||||
|
JLOG(j.warn())
|
||||||
|
<< "trustTransferLockedBalance without sleSrc/sleDst";
|
||||||
|
return tecINTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amount <= beast::zero)
|
||||||
|
{
|
||||||
|
JLOG(j.warn())
|
||||||
|
<< "trustTransferLockedBalance with non-positive amount";
|
||||||
|
return tecINTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto issuerAccID = amount.getIssuer();
|
||||||
|
auto currency = amount.getCurrency();
|
||||||
|
auto srcAccID = sleSrcAcc->getAccountID(sfAccount);
|
||||||
|
auto dstAccID = sleDstAcc->getAccountID(sfAccount);
|
||||||
|
|
||||||
|
bool srcHigh = srcAccID > issuerAccID;
|
||||||
|
bool dstHigh = dstAccID > issuerAccID;
|
||||||
|
|
||||||
|
// check for freezing, auth, no ripple and TL sanity
|
||||||
|
if (TER result =
|
||||||
|
trustTransferAllowed(view, {srcAccID, dstAccID}, {currency, issuerAccID});
|
||||||
|
result != tesSUCCESS)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// ensure source line exists
|
||||||
|
Keylet klSrcLine { keylet::line(srcAccID, issuerAccID, currency)};
|
||||||
|
SLEPtr sleSrcLine = peek(klSrcLine);
|
||||||
|
|
||||||
|
if (!sleSrcLine)
|
||||||
|
return tecNO_LINE;
|
||||||
|
|
||||||
|
// can't transfer a locked balance that does not exist
|
||||||
|
if (!sleSrcLine->isFieldPresent(sfLockedBalance))
|
||||||
|
{
|
||||||
|
JLOG(j.trace())
|
||||||
|
<< "trustTransferLockedBalance could not find sfLockedBalance on source line";
|
||||||
|
return tecUNFUNDED_PAYMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
STAmount lockedBalance = sleSrcLine->getFieldAmount(sfLockedBalance);
|
||||||
|
|
||||||
|
// check they have sufficient funds
|
||||||
|
if (amount > lockedBalance)
|
||||||
|
return tecUNFUNDED_PAYMENT;
|
||||||
|
|
||||||
|
// decrement source balance
|
||||||
|
{
|
||||||
|
STAmount priorBalance =
|
||||||
|
srcHigh ? -((*sleSrcLine)[sfBalance]) : (*sleSrcLine)[sfBalance];
|
||||||
|
|
||||||
|
// ensure the currency/issuer in the locked balance matches the xfer amount
|
||||||
|
if (priorBalance.getIssuer() != issuerAccID || priorBalance.getCurrency() != currency)
|
||||||
|
return tecNO_PERMISSION;
|
||||||
|
|
||||||
|
STAmount finalBalance = priorBalance - amount;
|
||||||
|
|
||||||
|
STAmount priorLockedBalance =
|
||||||
|
srcHigh ? -((*sleSrcLine)[sfLockedBalance]) : (*sleSrcLine)[sfLockedBalance];
|
||||||
|
|
||||||
|
STAmount finalLockedBalance = priorLockedBalance - amount;
|
||||||
|
|
||||||
|
// this should never happen but defensively check it here before updating sle
|
||||||
|
if (finalBalance < beast::zero || finalLockedBalance < beast::zero)
|
||||||
|
{
|
||||||
|
JLOG(j.warn())
|
||||||
|
<< "trustTransferLockedBalance results in a negative balance on source line";
|
||||||
|
return tecINTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleSrcLine->setFieldAmount(sfBalance, srcHigh ? -finalBalance : finalBalance);
|
||||||
|
|
||||||
|
if (finalLockedBalance == beast::zero)
|
||||||
|
sleSrcLine->makeFieldAbsent(sfLockedBalance);
|
||||||
|
else
|
||||||
|
sleSrcLine->setFieldAmount(sfLockedBalance, srcHigh ? -finalLockedBalance : finalLockedBalance);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// dstLow XNOR srcLow tells us if we need to flip the balance amount
|
||||||
|
// on the destination line
|
||||||
|
bool flipDstAmt = !((dstHigh && srcHigh) || (!dstHigh && !srcHigh));
|
||||||
|
|
||||||
|
// compute transfer fee, if any
|
||||||
|
auto xferRate = transferRate(view, issuerAccID);
|
||||||
|
|
||||||
|
// the destination will sometimes get less depending on xfer rate
|
||||||
|
// with any difference in tokens burned
|
||||||
|
auto dstAmt =
|
||||||
|
xferRate == parityRate
|
||||||
|
? amount
|
||||||
|
: multiplyRound(amount, xferRate, amount.issue(), true);
|
||||||
|
|
||||||
|
// check for a destination line
|
||||||
|
Keylet klDstLine = keylet::line(dstAccID, issuerAccID, currency);
|
||||||
|
SLEPtr sleDstLine = peek(klDstLine);
|
||||||
|
|
||||||
|
if (!sleDstLine)
|
||||||
|
{
|
||||||
|
// in most circumstances a missing destination line is a deal breaker
|
||||||
|
if (actingAccID != dstAccID && srcAccID != dstAccID)
|
||||||
|
return tecNO_PERMISSION;
|
||||||
|
|
||||||
|
STAmount dstBalanceDrops = sleDstAcc->getFieldAmount(sfBalance);
|
||||||
|
|
||||||
|
// no dst line exists, we might be able to create one...
|
||||||
|
if (std::uint32_t const ownerCount = {sleDstAcc->at(sfOwnerCount)};
|
||||||
|
dstBalanceDrops < view.fees().accountReserve(ownerCount + 1))
|
||||||
|
return tecNO_LINE_INSUF_RESERVE;
|
||||||
|
|
||||||
|
// yes we can... we will
|
||||||
|
|
||||||
|
if (!dryRun)
|
||||||
|
{
|
||||||
|
if constexpr(std::is_same<V, ApplyView>::value)
|
||||||
|
{
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
if (TER const ter = trustCreate(
|
||||||
|
view,
|
||||||
|
!dstHigh, // is dest low?
|
||||||
|
issuerAccID, // source
|
||||||
|
dstAccID, // destination
|
||||||
|
klDstLine.key, // ledger index
|
||||||
|
sleDstAcc, // Account to add to
|
||||||
|
false, // authorize account
|
||||||
|
(sleDstAcc->getFlags() & lsfDefaultRipple) == 0,
|
||||||
|
false, // freeze trust line
|
||||||
|
flipDstAmt ? -dstAmt : dstAmt, // initial balance
|
||||||
|
Issue(currency, dstAccID), // limit of zero
|
||||||
|
0, // quality in
|
||||||
|
0, // quality out
|
||||||
|
j); // journal
|
||||||
|
!isTesSuccess(ter))
|
||||||
|
{
|
||||||
|
return ter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// the dst line does exist, and it would have been checked above
|
||||||
|
// in trustTransferAllowed for NoRipple and Freeze flags
|
||||||
|
|
||||||
|
// check the limit
|
||||||
|
STAmount dstLimit =
|
||||||
|
dstHigh ? (*sleDstLine)[sfHighLimit] : (*sleDstLine)[sfLowLimit];
|
||||||
|
|
||||||
|
STAmount priorBalance =
|
||||||
|
dstHigh ? -((*sleDstLine)[sfBalance]) : (*sleDstLine)[sfBalance];
|
||||||
|
|
||||||
|
STAmount finalBalance = priorBalance + (flipDstAmt ? -dstAmt : dstAmt);
|
||||||
|
|
||||||
|
if (finalBalance < priorBalance)
|
||||||
|
{
|
||||||
|
JLOG(j.warn())
|
||||||
|
<< "trustTransferLockedBalance resulted in a lower final balance on dest line";
|
||||||
|
return tecINTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (finalBalance > dstLimit && actingAccID != dstAccID)
|
||||||
|
{
|
||||||
|
JLOG(j.trace())
|
||||||
|
<< "trustTransferLockedBalance would increase dest line above limit without permission";
|
||||||
|
return tecPATH_DRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleDstLine->setFieldAmount(sfBalance, dstHigh ? -finalBalance : finalBalance);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dryRun)
|
||||||
|
return tesSUCCESS;
|
||||||
|
|
||||||
|
static_assert(std::is_same<V, ApplyView>::value);
|
||||||
|
|
||||||
|
// check if source line ended up in default state and adjust owner count if it did
|
||||||
|
if (isTrustDefault(sleSrcAcc, sleSrcLine))
|
||||||
|
{
|
||||||
|
uint32_t flags = sleSrcLine->getFieldU32(sfFlags);
|
||||||
|
uint32_t fReserve { srcHigh ? lsfHighReserve : lsfLowReserve };
|
||||||
|
if (flags & fReserve)
|
||||||
|
{
|
||||||
|
sleSrcLine->setFieldU32(sfFlags, flags & ~fReserve);
|
||||||
|
if (!dryRun)
|
||||||
|
{
|
||||||
|
adjustOwnerCount(view, sleSrcAcc, -1, j);
|
||||||
|
view.update(sleSrcAcc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view.update(sleSrcLine);
|
||||||
|
|
||||||
|
if (sleDstLine)
|
||||||
|
{
|
||||||
|
// a destination line already existed and was updated
|
||||||
|
view.update(sleDstLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tesSUCCESS;
|
||||||
|
}
|
||||||
/** Delete an offer.
|
/** Delete an offer.
|
||||||
|
|
||||||
Requirements:
|
Requirements:
|
||||||
|
|||||||
@@ -961,209 +961,6 @@ bool isTrustDefault(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
|
||||||
trustXferLockedBalance(
|
|
||||||
ApplyView& view,
|
|
||||||
AccountID const& actingAccID, // the account whose tx is actioning xfer
|
|
||||||
std::shared_ptr<SLE> const& sleSrcAcc,
|
|
||||||
std::shared_ptr<SLE> const& sleDstAcc,
|
|
||||||
STAmount const& amount, // issuer, currency are in this field
|
|
||||||
beast::Journal const& j)
|
|
||||||
{
|
|
||||||
if (!view.rules().enabled(featurePaychanAndEscrowForTokens))
|
|
||||||
return tefINTERNAL;
|
|
||||||
|
|
||||||
if (!sleSrcAcc || !sleDstAcc)
|
|
||||||
{
|
|
||||||
JLOG(j.warn())
|
|
||||||
<< "trustXferLockedBalance without sleSrc/sleDst";
|
|
||||||
return tecINTERNAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (amount <= beast::zero)
|
|
||||||
{
|
|
||||||
JLOG(j.warn())
|
|
||||||
<< "trustXferLockedBalance with non-positive amount";
|
|
||||||
return tecINTERNAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto issuerAccID = amount.getIssuer();
|
|
||||||
auto currency = amount.getCurrency();
|
|
||||||
auto srcAccID = sleSrcAcc->getAccountID(sfAccount);
|
|
||||||
auto dstAccID = sleDstAcc->getAccountID(sfAccount);
|
|
||||||
|
|
||||||
bool srcHigh = srcAccID > issuerAccID;
|
|
||||||
bool dstHigh = dstAccID > issuerAccID;
|
|
||||||
|
|
||||||
// check for freezing, auth, no ripple and TL sanity
|
|
||||||
if (TER result =
|
|
||||||
trustXferAllowed(view, {srcAccID, dstAccID}, {currency, issuerAccID});
|
|
||||||
result != tesSUCCESS)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
// ensure source line exists
|
|
||||||
auto sleSrcLine = view.peek(keylet::line(srcAccID, issuerAccID, currency));
|
|
||||||
|
|
||||||
if (!sleSrcLine)
|
|
||||||
return tecNO_LINE;
|
|
||||||
|
|
||||||
// can't transfer a locked balance that does not exist
|
|
||||||
if (!sleSrcLine->isFieldPresent(sfLockedBalance))
|
|
||||||
{
|
|
||||||
JLOG(j.trace())
|
|
||||||
<< "trustXferLockedBalance could not find sfLockedBalance on source line";
|
|
||||||
return tecUNFUNDED_PAYMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
STAmount lockedBalance = sleSrcLine->getFieldAmount(sfLockedBalance);
|
|
||||||
|
|
||||||
// check they have sufficient funds
|
|
||||||
if (amount > lockedBalance)
|
|
||||||
return tecUNFUNDED_PAYMENT;
|
|
||||||
|
|
||||||
// decrement source balance
|
|
||||||
{
|
|
||||||
STAmount priorBalance =
|
|
||||||
srcHigh ? -((*sleSrcLine)[sfBalance]) : (*sleSrcLine)[sfBalance];
|
|
||||||
|
|
||||||
// ensure the currency/issuer in the locked balance matches the xfer amount
|
|
||||||
if (priorBalance.getIssuer() != issuerAccID || priorBalance.getCurrency() != currency)
|
|
||||||
return tecNO_PERMISSION;
|
|
||||||
|
|
||||||
STAmount finalBalance = priorBalance - amount;
|
|
||||||
|
|
||||||
STAmount priorLockedBalance =
|
|
||||||
srcHigh ? -((*sleSrcLine)[sfLockedBalance]) : (*sleSrcLine)[sfLockedBalance];
|
|
||||||
|
|
||||||
STAmount finalLockedBalance = priorLockedBalance - amount;
|
|
||||||
|
|
||||||
// this should never happen but defensively check it here before updating sle
|
|
||||||
if (finalBalance < beast::zero || finalLockedBalance < beast::zero)
|
|
||||||
{
|
|
||||||
JLOG(j.warn())
|
|
||||||
<< "trustXferLockedBalance results in a negative balance on source line";
|
|
||||||
return tecINTERNAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sleSrcLine->setFieldAmount(sfBalance, srcHigh ? -finalBalance : finalBalance);
|
|
||||||
|
|
||||||
if (finalLockedBalance == beast::zero)
|
|
||||||
sleSrcLine->makeFieldAbsent(sfLockedBalance);
|
|
||||||
else
|
|
||||||
sleSrcLine->setFieldAmount(sfLockedBalance, srcHigh ? -finalLockedBalance : finalLockedBalance);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// dstLow XNOR srcLow tells us if we need to flip the balance amount
|
|
||||||
// on the destination line
|
|
||||||
bool flipDstAmt = !((dstHigh && srcHigh) || (!dstHigh && !srcHigh));
|
|
||||||
|
|
||||||
// compute transfer fee, if any
|
|
||||||
auto xferRate = transferRate(view, issuerAccID);
|
|
||||||
|
|
||||||
// the destination will sometimes get less depending on xfer rate
|
|
||||||
// with any difference in tokens burned
|
|
||||||
auto dstAmt =
|
|
||||||
xferRate == parityRate
|
|
||||||
? amount
|
|
||||||
: multiplyRound(amount, xferRate, amount.issue(), true);
|
|
||||||
|
|
||||||
// check for a destination line
|
|
||||||
Keylet klDstLine = keylet::line(dstAccID, issuerAccID, currency);
|
|
||||||
auto sleDstLine = view.peek(klDstLine);
|
|
||||||
|
|
||||||
if (!sleDstLine)
|
|
||||||
{
|
|
||||||
// in most circumstances a missing destination line is a deal breaker
|
|
||||||
if (actingAccID != dstAccID && srcAccID != dstAccID)
|
|
||||||
return tecNO_PERMISSION;
|
|
||||||
|
|
||||||
STAmount dstBalanceDrops = sleDstAcc->getFieldAmount(sfBalance);
|
|
||||||
|
|
||||||
// no dst line exists, we might be able to create one...
|
|
||||||
if (std::uint32_t const ownerCount = {sleDstAcc->at(sfOwnerCount)};
|
|
||||||
dstBalanceDrops < view.fees().accountReserve(ownerCount + 1))
|
|
||||||
return tecNO_LINE_INSUF_RESERVE;
|
|
||||||
|
|
||||||
// yes we can... we will
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
if (TER const ter = trustCreate(
|
|
||||||
view,
|
|
||||||
!dstHigh, // is dest low?
|
|
||||||
issuerAccID, // source
|
|
||||||
dstAccID, // destination
|
|
||||||
klDstLine.key, // ledger index
|
|
||||||
sleDstAcc, // Account to add to
|
|
||||||
false, // authorize account
|
|
||||||
(sleDstAcc->getFlags() & lsfDefaultRipple) == 0,
|
|
||||||
false, // freeze trust line
|
|
||||||
flipDstAmt ? -dstAmt : dstAmt, // initial balance
|
|
||||||
Issue(currency, dstAccID), // limit of zero
|
|
||||||
0, // quality in
|
|
||||||
0, // quality out
|
|
||||||
j); // journal
|
|
||||||
!isTesSuccess(ter))
|
|
||||||
{
|
|
||||||
return ter;
|
|
||||||
}
|
|
||||||
// clang-format on
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// the dst line does exist, and it would have been checked above
|
|
||||||
// in trustXferAllowed for NoRipple and Freeze flags
|
|
||||||
|
|
||||||
// check the limit
|
|
||||||
STAmount dstLimit =
|
|
||||||
dstHigh ? (*sleDstLine)[sfHighLimit] : (*sleDstLine)[sfLowLimit];
|
|
||||||
|
|
||||||
STAmount priorBalance =
|
|
||||||
dstHigh ? -((*sleDstLine)[sfBalance]) : (*sleDstLine)[sfBalance];
|
|
||||||
|
|
||||||
STAmount finalBalance = priorBalance + (flipDstAmt ? -dstAmt : dstAmt);
|
|
||||||
|
|
||||||
if (finalBalance < priorBalance)
|
|
||||||
{
|
|
||||||
JLOG(j.warn())
|
|
||||||
<< "trustXferLockedBalance resulted in a lower final balance on dest line";
|
|
||||||
return tecINTERNAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (finalBalance > dstLimit && actingAccID != dstAccID)
|
|
||||||
{
|
|
||||||
JLOG(j.trace())
|
|
||||||
<< "trustXferLockedBalance would increase dest line above limit without permission";
|
|
||||||
return tecPATH_DRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
sleDstLine->setFieldAmount(sfBalance, dstHigh ? -finalBalance : finalBalance);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if source line ended up in default state and adjust owner count if it did
|
|
||||||
if (isTrustDefault(sleSrcAcc, sleSrcLine))
|
|
||||||
{
|
|
||||||
uint32_t flags = sleSrcLine->getFieldU32(sfFlags);
|
|
||||||
uint32_t fReserve { srcHigh ? lsfHighReserve : lsfLowReserve };
|
|
||||||
if (flags & fReserve)
|
|
||||||
{
|
|
||||||
sleSrcLine->setFieldU32(sfFlags, flags & ~fReserve);
|
|
||||||
adjustOwnerCount(view, sleSrcAcc, -1, j);
|
|
||||||
view.update(sleSrcAcc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
view.update(sleSrcLine);
|
|
||||||
|
|
||||||
if (sleDstLine)
|
|
||||||
{
|
|
||||||
// a destination line already existed and was updated
|
|
||||||
view.update(sleDstLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tesSUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
TER
|
TER
|
||||||
offerDelete(ApplyView& view, std::shared_ptr<SLE> const& sle, beast::Journal j)
|
offerDelete(ApplyView& view, std::shared_ptr<SLE> const& sle, beast::Journal j)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user