Compare commits

..

13 Commits

10 changed files with 107 additions and 97 deletions

View File

@@ -141,7 +141,7 @@ protected:
using namespace jtx; using namespace jtx;
auto const vaultSle = env.le(keylet::vault(vaultID)); auto const vaultSle = env.le(keylet::vault(vaultID));
return getAssetsTotalScale(vaultSle); return getVaultScale(vaultSle);
} }
}; };
@@ -551,15 +551,12 @@ protected:
broker.vaultScale(env), broker.vaultScale(env),
state.principalOutstanding.exponent()))); state.principalOutstanding.exponent())));
BEAST_EXPECT(state.paymentInterval == 600); BEAST_EXPECT(state.paymentInterval == 600);
{
NumberRoundModeGuard mg(Number::upward);
BEAST_EXPECT( BEAST_EXPECT(
state.totalValue == state.totalValue ==
roundToAsset( roundToAsset(
broker.asset, broker.asset,
state.periodicPayment * state.paymentRemaining, state.periodicPayment * state.paymentRemaining,
state.loanScale)); state.loanScale));
}
BEAST_EXPECT( BEAST_EXPECT(
state.managementFeeOutstanding == state.managementFeeOutstanding ==
computeManagementFee( computeManagementFee(
@@ -700,8 +697,7 @@ protected:
interval, interval,
total, total,
feeRate, feeRate,
asset(brokerParams.vaultDeposit).number().exponent(), asset(brokerParams.vaultDeposit).number().exponent());
env.journal);
log << "Loan properties:\n" log << "Loan properties:\n"
<< "\tPrincipal: " << principal << std::endl << "\tPrincipal: " << principal << std::endl
<< "\tInterest rate: " << interest << std::endl << "\tInterest rate: " << interest << std::endl
@@ -1481,8 +1477,7 @@ protected:
state.paymentInterval, state.paymentInterval,
state.paymentRemaining, state.paymentRemaining,
broker.params.managementFeeRate, broker.params.managementFeeRate,
state.loanScale, state.loanScale);
env.journal);
verifyLoanStatus( verifyLoanStatus(
0, 0,
@@ -2453,18 +2448,13 @@ protected:
// Make all the payments in one transaction // Make all the payments in one transaction
// service fee is 2 // service fee is 2
auto const startingPayments = state.paymentRemaining; auto const startingPayments = state.paymentRemaining;
STAmount const payoffAmount = [&]() {
NumberRoundModeGuard mg(Number::upward);
auto const rawPayoff = startingPayments * auto const rawPayoff = startingPayments *
(state.periodicPayment + broker.asset(2).value()); (state.periodicPayment + broker.asset(2).value());
STAmount const payoffAmount{broker.asset, rawPayoff}; STAmount const payoffAmount{broker.asset, rawPayoff};
BEAST_EXPECTS( BEAST_EXPECT(
payoffAmount == payoffAmount ==
broker.asset(Number(1024014840139457, -12)), broker.asset(Number(1024014840139457, -12)));
to_string(payoffAmount));
BEAST_EXPECT(payoffAmount > state.principalOutstanding); BEAST_EXPECT(payoffAmount > state.principalOutstanding);
return payoffAmount;
}();
singlePayment( singlePayment(
loanKeylet, loanKeylet,
@@ -4019,7 +4009,7 @@ protected:
createJson = env.json(createJson, sig(sfCounterpartySignature, lender)); createJson = env.json(createJson, sig(sfCounterpartySignature, lender));
// Fails in preclaim because principal requested can't be // Fails in preclaim because principal requested can't be
// represented as XRP // represented as XRP
env(createJson, ter(tecPRECISION_LOSS), THISLINE); env(createJson, ter(tecPRECISION_LOSS));
env.close(); env.close();
BEAST_EXPECT(!env.le(keylet)); BEAST_EXPECT(!env.le(keylet));
@@ -4031,7 +4021,7 @@ protected:
createJson = env.json(createJson, sig(sfCounterpartySignature, lender)); createJson = env.json(createJson, sig(sfCounterpartySignature, lender));
// Fails in doApply because the payment is too small to be // Fails in doApply because the payment is too small to be
// represented as XRP. // represented as XRP.
env(createJson, ter(tecPRECISION_LOSS), THISLINE); env(createJson, ter(tecPRECISION_LOSS));
env.close(); env.close();
} }
@@ -5006,7 +4996,7 @@ protected:
auto const keylet = keylet::loan(broker.brokerID, loanSequence); auto const keylet = keylet::loan(broker.brokerID, loanSequence);
createJson = env.json(createJson, sig(sfCounterpartySignature, lender)); createJson = env.json(createJson, sig(sfCounterpartySignature, lender));
env(createJson, ter(tecPRECISION_LOSS), THISLINE); env(createJson, ter(tecPRECISION_LOSS));
env.close(startDate); env.close(startDate);
auto loanPayTx = env.json( auto loanPayTx = env.json(

View File

@@ -10,6 +10,7 @@
#include <doctest/doctest.h> #include <doctest/doctest.h>
#include <atomic> #include <atomic>
#include <iostream>
#include <map> #include <map>
#include <thread> #include <thread>
@@ -17,6 +18,40 @@ using namespace ripple;
namespace { namespace {
struct logger
{
std::string name;
logger const* const parent = nullptr;
static std::size_t depth;
logger(std::string n) : name(n)
{
std::clog << indent() << name << " begin\n";
++depth;
}
logger(logger const& p, std::string n) : parent(&p), name(n)
{
std::clog << indent() << parent->name << " : " << name << " begin\n";
++depth;
}
~logger()
{
--depth;
if (parent)
std::clog << indent() << parent->name << " : " << name << " end\n";
else
std::clog << indent() << name << " end\n";
}
std::string
indent()
{
return std::string(depth, ' ');
}
};
std::size_t logger::depth = 0;
// Simple HTTP server using Beast for testing // Simple HTTP server using Beast for testing
class TestHTTPServer class TestHTTPServer
{ {
@@ -35,6 +70,7 @@ private:
public: public:
TestHTTPServer() : acceptor_(ioc_), port_(0) TestHTTPServer() : acceptor_(ioc_), port_(0)
{ {
logger l("TestHTTPServer()");
// Bind to any available port // Bind to any available port
endpoint_ = {boost::asio::ip::tcp::v4(), 0}; endpoint_ = {boost::asio::ip::tcp::v4(), 0};
acceptor_.open(endpoint_.protocol()); acceptor_.open(endpoint_.protocol());
@@ -50,6 +86,7 @@ public:
~TestHTTPServer() ~TestHTTPServer()
{ {
logger l("~TestHTTPServer()");
stop(); stop();
} }
@@ -87,6 +124,7 @@ private:
void void
stop() stop()
{ {
logger l("TestHTTPServer::stop");
running_ = false; running_ = false;
acceptor_.close(); acceptor_.close();
} }
@@ -94,6 +132,7 @@ private:
void void
accept() accept()
{ {
logger l("TestHTTPServer::accept");
if (!running_) if (!running_)
return; return;
@@ -115,31 +154,37 @@ private:
void void
handleConnection(boost::asio::ip::tcp::socket socket) handleConnection(boost::asio::ip::tcp::socket socket)
{ {
logger l("TestHTTPServer::handleConnection");
try try
{ {
std::optional<logger> r(std::in_place, l, "read the http request");
// Read the HTTP request // Read the HTTP request
boost::beast::flat_buffer buffer; boost::beast::flat_buffer buffer;
boost::beast::http::request<boost::beast::http::string_body> req; boost::beast::http::request<boost::beast::http::string_body> req;
boost::beast::http::read(socket, buffer, req); boost::beast::http::read(socket, buffer, req);
// Create response // Create response
r.emplace(l, "create response");
boost::beast::http::response<boost::beast::http::string_body> res; boost::beast::http::response<boost::beast::http::string_body> res;
res.version(req.version()); res.version(req.version());
res.result(status_code_); res.result(status_code_);
res.set(boost::beast::http::field::server, "TestServer"); res.set(boost::beast::http::field::server, "TestServer");
// Add custom headers // Add custom headers
r.emplace(l, "add custom headers");
for (auto const& [name, value] : custom_headers_) for (auto const& [name, value] : custom_headers_)
{ {
res.set(name, value); res.set(name, value);
} }
// Set body and prepare payload first // Set body and prepare payload first
r.emplace(l, "set body and prepare payload");
res.body() = response_body_; res.body() = response_body_;
res.prepare_payload(); res.prepare_payload();
// Override Content-Length with custom headers after prepare_payload // Override Content-Length with custom headers after prepare_payload
// This allows us to test case-insensitive header parsing // This allows us to test case-insensitive header parsing
r.emplace(l, "override content-length");
for (auto const& [name, value] : custom_headers_) for (auto const& [name, value] : custom_headers_)
{ {
if (boost::iequals(name, "Content-Length")) if (boost::iequals(name, "Content-Length"))
@@ -150,20 +195,26 @@ private:
} }
// Send response // Send response
r.emplace(l, "send response");
boost::beast::http::write(socket, res); boost::beast::http::write(socket, res);
// Shutdown socket gracefully // Shutdown socket gracefully
r.emplace(l, "shutdown socket");
boost::system::error_code ec; boost::system::error_code ec;
socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec); socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
} }
catch (std::exception const&) catch (std::exception const&)
{ {
// Connection handling errors are expected // Connection handling errors are expected
logger c(l, "catch");
} }
if (running_) if (running_)
{
logger r(l, "accept");
accept(); accept();
} }
}
}; };
// Helper function to run HTTP client test // Helper function to run HTTP client test
@@ -176,12 +227,16 @@ runHTTPTest(
std::string& result_data, std::string& result_data,
boost::system::error_code& result_error) boost::system::error_code& result_error)
{ {
logger l("runHTTPTest");
// Create a null journal for testing // Create a null journal for testing
beast::Journal j{beast::Journal::getNullSink()}; beast::Journal j{beast::Journal::getNullSink()};
std::optional<logger> r(std::in_place, l, "initializeSSLContext");
// Initialize HTTPClient SSL context // Initialize HTTPClient SSL context
HTTPClient::initializeSSLContext("", "", false, j); HTTPClient::initializeSSLContext("", "", false, j);
r.emplace(l, "HTTPClient::get");
HTTPClient::get( HTTPClient::get(
false, // no SSL false, // no SSL
server.ioc(), server.ioc(),
@@ -206,6 +261,7 @@ runHTTPTest(
while (!completed && while (!completed &&
std::chrono::steady_clock::now() - start < std::chrono::seconds(10)) std::chrono::steady_clock::now() - start < std::chrono::seconds(10))
{ {
r.emplace(l, "ioc.run_one");
if (server.ioc().run_one() == 0) if (server.ioc().run_one() == 0)
{ {
break; break;
@@ -219,6 +275,8 @@ runHTTPTest(
TEST_CASE("HTTPClient case insensitive Content-Length") TEST_CASE("HTTPClient case insensitive Content-Length")
{ {
logger l("HTTPClient case insensitive Content-Length");
// Test different cases of Content-Length header // Test different cases of Content-Length header
std::vector<std::string> header_cases = { std::vector<std::string> header_cases = {
"Content-Length", // Standard case "Content-Length", // Standard case
@@ -230,6 +288,7 @@ TEST_CASE("HTTPClient case insensitive Content-Length")
for (auto const& header_name : header_cases) for (auto const& header_name : header_cases)
{ {
logger h(l, header_name);
TestHTTPServer server; TestHTTPServer server;
std::string test_body = "Hello World!"; std::string test_body = "Hello World!";
server.setResponseBody(test_body); server.setResponseBody(test_body);
@@ -258,6 +317,7 @@ TEST_CASE("HTTPClient case insensitive Content-Length")
TEST_CASE("HTTPClient basic HTTP request") TEST_CASE("HTTPClient basic HTTP request")
{ {
logger l("HTTPClient basic HTTP request");
TestHTTPServer server; TestHTTPServer server;
std::string test_body = "Test response body"; std::string test_body = "Test response body";
server.setResponseBody(test_body); server.setResponseBody(test_body);
@@ -279,6 +339,7 @@ TEST_CASE("HTTPClient basic HTTP request")
TEST_CASE("HTTPClient empty response") TEST_CASE("HTTPClient empty response")
{ {
logger l("HTTPClient empty response");
TestHTTPServer server; TestHTTPServer server;
server.setResponseBody(""); // Empty body server.setResponseBody(""); // Empty body
server.setHeader("Content-Length", "0"); server.setHeader("Content-Length", "0");
@@ -299,6 +360,7 @@ TEST_CASE("HTTPClient empty response")
TEST_CASE("HTTPClient different status codes") TEST_CASE("HTTPClient different status codes")
{ {
logger l("HTTPClient different status codes");
std::vector<unsigned int> status_codes = {200, 404, 500}; std::vector<unsigned int> status_codes = {200, 404, 500};
for (auto status : status_codes) for (auto status : status_codes)

View File

@@ -179,12 +179,11 @@ adjustImpreciseNumber(
} }
inline int inline int
getAssetsTotalScale(SLE::const_ref vaultSle) getVaultScale(SLE::const_ref vaultSle)
{ {
if (!vaultSle) if (!vaultSle)
return Number::minExponent - 1; // LCOV_EXCL_LINE return Number::minExponent - 1; // LCOV_EXCL_LINE
return STAmount{vaultSle->at(sfAsset), vaultSle->at(sfAssetsTotal)} return vaultSle->at(sfAssetsTotal).exponent();
.exponent();
} }
TER TER
@@ -419,8 +418,7 @@ computeLoanProperties(
std::uint32_t paymentInterval, std::uint32_t paymentInterval,
std::uint32_t paymentsRemaining, std::uint32_t paymentsRemaining,
TenthBips32 managementFeeRate, TenthBips32 managementFeeRate,
std::int32_t minimumScale, std::int32_t minimumScale);
beast::Journal j);
bool bool
isRounded(Asset const& asset, Number const& value, std::int32_t scale); isRounded(Asset const& asset, Number const& value, std::int32_t scale);

View File

@@ -451,8 +451,7 @@ tryOverpayment(
paymentInterval, paymentInterval,
paymentRemaining, paymentRemaining,
managementFeeRate, managementFeeRate,
loanScale, loanScale);
j);
JLOG(j.debug()) << "new periodic payment: " JLOG(j.debug()) << "new periodic payment: "
<< newLoanProperties.periodicPayment << newLoanProperties.periodicPayment
@@ -554,8 +553,8 @@ tryOverpayment(
// Calculate how the loan's value changed due to the overpayment. // Calculate how the loan's value changed due to the overpayment.
// This should be negative (value decreased) or zero. A principal // This should be negative (value decreased) or zero. A principal
// overpayment should never increase the loan's value. // overpayment should never increase the loan's value.
auto const valueChange = newRounded.valueOutstanding - auto const valueChange =
hypotheticalValueOutstanding - deltas.managementFee; newRounded.valueOutstanding - hypotheticalValueOutstanding;
if (valueChange > 0) if (valueChange > 0)
{ {
JLOG(j.warn()) << "Principal overpayment would increase the value of " JLOG(j.warn()) << "Principal overpayment would increase the value of "
@@ -1612,8 +1611,7 @@ computeLoanProperties(
std::uint32_t paymentInterval, std::uint32_t paymentInterval,
std::uint32_t paymentsRemaining, std::uint32_t paymentsRemaining,
TenthBips32 managementFeeRate, TenthBips32 managementFeeRate,
std::int32_t minimumScale, std::int32_t minimumScale)
beast::Journal j)
{ {
auto const periodicRate = loanPeriodicRate(interestRate, paymentInterval); auto const periodicRate = loanPeriodicRate(interestRate, paymentInterval);
XRPL_ASSERT( XRPL_ASSERT(
@@ -1624,22 +1622,13 @@ computeLoanProperties(
principalOutstanding, periodicRate, paymentsRemaining); principalOutstanding, periodicRate, paymentsRemaining);
auto const [totalValueOutstanding, loanScale] = [&]() { auto const [totalValueOutstanding, loanScale] = [&]() {
// only round up if there should be interest NumberRoundModeGuard mg(Number::to_nearest);
NumberRoundModeGuard mg(
periodicRate == 0 ? Number::to_nearest : Number::upward);
// Use STAmount's internal rounding instead of roundToAsset, because // Use STAmount's internal rounding instead of roundToAsset, because
// we're going to use this result to determine the scale for all the // we're going to use this result to determine the scale for all the
// other rounding. // other rounding.
// Equation (30) from XLS-66 spec, Section A-2 Equation Glossary // Equation (30) from XLS-66 spec, Section A-2 Equation Glossary
STAmount amount{asset, periodicPayment * paymentsRemaining}; STAmount amount{asset, periodicPayment * paymentsRemaining};
JLOG(j.debug()) << "computeLoanProperties:" << " Principal requested: "
<< principalOutstanding
<< ". Periodic payment: " << periodicPayment
<< ". Payments remaining: " << paymentsRemaining
<< ". Raw total value: "
<< periodicPayment * paymentsRemaining
<< ". Candidate total value: " << amount << std::endl;
// Base the loan scale on the total value, since that's going to be // Base the loan scale on the total value, since that's going to be
// the biggest number involved (barring unusual parameters for late, // the biggest number involved (barring unusual parameters for late,
@@ -1654,10 +1643,7 @@ computeLoanProperties(
// We may need to truncate the total value because of the minimum // We may need to truncate the total value because of the minimum
// scale // scale
amount = roundToAsset(asset, amount, loanScale); amount = roundToAsset(asset, amount, loanScale, Number::to_nearest);
JLOG(j.debug()) << "computeLoanProperties: Loan scale:" << loanScale
<< ". Actual total value: " << amount << std::endl;
return std::make_pair(amount, loanScale); return std::make_pair(amount, loanScale);
}(); }();

View File

@@ -56,7 +56,7 @@ LoanBrokerDelete::preclaim(PreclaimContext const& ctx)
if (!vault) if (!vault)
return tefINTERNAL; // LCOV_EXCL_LINE return tefINTERNAL; // LCOV_EXCL_LINE
auto const asset = vault->at(sfAsset); auto const asset = vault->at(sfAsset);
auto const scale = getAssetsTotalScale(vault); auto const scale = getVaultScale(vault);
auto const rounded = auto const rounded =
roundToAsset(asset, debtTotal, scale, Number::towards_zero); roundToAsset(asset, debtTotal, scale, Number::towards_zero);

View File

@@ -115,7 +115,7 @@ LoanDelete::doApply()
roundToAsset( roundToAsset(
vaultSle->at(sfAsset), vaultSle->at(sfAsset),
debtTotalProxy, debtTotalProxy,
getAssetsTotalScale(vaultSle), getVaultScale(vaultSle),
Number::towards_zero) == beast::zero, Number::towards_zero) == beast::zero,
"ripple::LoanDelete::doApply", "ripple::LoanDelete::doApply",
"last loan, remaining debt rounds to zero"); "last loan, remaining debt rounds to zero");

View File

@@ -106,7 +106,7 @@ LoanManage::preclaim(PreclaimContext const& ctx)
if (loanBrokerSle->at(sfOwner) != account) if (loanBrokerSle->at(sfOwner) != account)
{ {
JLOG(ctx.j.warn()) JLOG(ctx.j.warn())
<< "LoanBroker for Loan does not belong to the account. LoanManage " << "LoanBroker for Loan does not belong to the account. LoanModify "
"can only be submitted by the Loan Broker."; "can only be submitted by the Loan Broker.";
return tecNO_PERMISSION; return tecNO_PERMISSION;
} }
@@ -178,7 +178,7 @@ LoanManage::defaultLoan(
// The vault may be at a different scale than the loan. Reduce rounding // The vault may be at a different scale than the loan. Reduce rounding
// errors during the accounting by rounding some of the values to that // errors during the accounting by rounding some of the values to that
// scale. // scale.
auto const vaultScale = getAssetsTotalScale(vaultSle); auto const vaultScale = getVaultScale(vaultSle);
{ {
// Decrease the Total Value of the Vault: // Decrease the Total Value of the Vault:
@@ -242,11 +242,7 @@ LoanManage::defaultLoan(
return tefBAD_LEDGER; return tefBAD_LEDGER;
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
adjustImpreciseNumber( vaultLossUnrealizedProxy -= totalDefaultAmount;
vaultLossUnrealizedProxy,
-totalDefaultAmount,
vaultAsset,
vaultScale);
} }
view.update(vaultSle); view.update(vaultSle);
} }
@@ -254,9 +250,11 @@ LoanManage::defaultLoan(
// Update the LoanBroker object: // Update the LoanBroker object:
{ {
auto const asset = *vaultSle->at(sfAsset);
// Decrease the Debt of the LoanBroker: // Decrease the Debt of the LoanBroker:
adjustImpreciseNumber( adjustImpreciseNumber(
brokerDebtTotalProxy, -totalDefaultAmount, vaultAsset, vaultScale); brokerDebtTotalProxy, -totalDefaultAmount, asset, vaultScale);
// Decrease the First-Loss Capital Cover Available: // Decrease the First-Loss Capital Cover Available:
auto coverAvailableProxy = brokerSle->at(sfCoverAvailable); auto coverAvailableProxy = brokerSle->at(sfCoverAvailable);
if (coverAvailableProxy < defaultCovered) if (coverAvailableProxy < defaultCovered)
@@ -299,20 +297,13 @@ LoanManage::impairLoan(
ApplyView& view, ApplyView& view,
SLE::ref loanSle, SLE::ref loanSle,
SLE::ref vaultSle, SLE::ref vaultSle,
Asset const& vaultAsset,
beast::Journal j) beast::Journal j)
{ {
Number const lossUnrealized = owedToVault(loanSle); Number const lossUnrealized = owedToVault(loanSle);
// The vault may be at a different scale than the loan. Reduce rounding
// errors during the accounting by rounding some of the values to that
// scale.
auto const vaultScale = getAssetsTotalScale(vaultSle);
// Update the Vault object(set "paper loss") // Update the Vault object(set "paper loss")
auto vaultLossUnrealizedProxy = vaultSle->at(sfLossUnrealized); auto vaultLossUnrealizedProxy = vaultSle->at(sfLossUnrealized);
adjustImpreciseNumber( vaultLossUnrealizedProxy += lossUnrealized;
vaultLossUnrealizedProxy, lossUnrealized, vaultAsset, vaultScale);
if (vaultLossUnrealizedProxy > if (vaultLossUnrealizedProxy >
vaultSle->at(sfAssetsTotal) - vaultSle->at(sfAssetsAvailable)) vaultSle->at(sfAssetsTotal) - vaultSle->at(sfAssetsAvailable))
{ {
@@ -343,14 +334,8 @@ LoanManage::unimpairLoan(
ApplyView& view, ApplyView& view,
SLE::ref loanSle, SLE::ref loanSle,
SLE::ref vaultSle, SLE::ref vaultSle,
Asset const& vaultAsset,
beast::Journal j) beast::Journal j)
{ {
// The vault may be at a different scale than the loan. Reduce rounding
// errors during the accounting by rounding some of the values to that
// scale.
auto const vaultScale = getAssetsTotalScale(vaultSle);
// Update the Vault object(clear "paper loss") // Update the Vault object(clear "paper loss")
auto vaultLossUnrealizedProxy = vaultSle->at(sfLossUnrealized); auto vaultLossUnrealizedProxy = vaultSle->at(sfLossUnrealized);
Number const lossReversed = owedToVault(loanSle); Number const lossReversed = owedToVault(loanSle);
@@ -362,10 +347,7 @@ LoanManage::unimpairLoan(
return tefBAD_LEDGER; return tefBAD_LEDGER;
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
// Reverse the "paper loss" vaultLossUnrealizedProxy -= lossReversed;
adjustImpreciseNumber(
vaultLossUnrealizedProxy, -lossReversed, vaultAsset, vaultScale);
view.update(vaultSle); view.update(vaultSle);
// Update the Loan object // Update the Loan object
@@ -421,14 +403,12 @@ LoanManage::doApply()
} }
else if (tx.isFlag(tfLoanImpair)) else if (tx.isFlag(tfLoanImpair))
{ {
if (auto const ter = if (auto const ter = impairLoan(view, loanSle, vaultSle, j_))
impairLoan(view, loanSle, vaultSle, vaultAsset, j_))
return ter; return ter;
} }
else if (tx.isFlag(tfLoanUnimpair)) else if (tx.isFlag(tfLoanUnimpair))
{ {
if (auto const ter = if (auto const ter = unimpairLoan(view, loanSle, vaultSle, j_))
unimpairLoan(view, loanSle, vaultSle, vaultAsset, j_))
return ter; return ter;
} }

View File

@@ -44,7 +44,6 @@ public:
ApplyView& view, ApplyView& view,
SLE::ref loanSle, SLE::ref loanSle,
SLE::ref vaultSle, SLE::ref vaultSle,
Asset const& vaultAsset,
beast::Journal j); beast::Journal j);
/** Helper function that might be needed by other transactors /** Helper function that might be needed by other transactors
@@ -54,7 +53,6 @@ public:
ApplyView& view, ApplyView& view,
SLE::ref loanSle, SLE::ref loanSle,
SLE::ref vaultSle, SLE::ref vaultSle,
Asset const& vaultAsset,
beast::Journal j); beast::Journal j);
TER TER

View File

@@ -305,7 +305,7 @@ LoanPay::doApply()
// change will be discarded. // change will be discarded.
if (loanSle->isFlag(lsfLoanImpaired)) if (loanSle->isFlag(lsfLoanImpaired))
{ {
LoanManage::unimpairLoan(view, loanSle, vaultSle, asset, j_); LoanManage::unimpairLoan(view, loanSle, vaultSle, j_);
} }
LoanPaymentType const paymentType = [&tx]() { LoanPaymentType const paymentType = [&tx]() {
@@ -379,7 +379,7 @@ LoanPay::doApply()
// The vault may be at a different scale than the loan. Reduce rounding // The vault may be at a different scale than the loan. Reduce rounding
// errors during the payment by rounding some of the values to that scale. // errors during the payment by rounding some of the values to that scale.
auto const vaultScale = getAssetsTotalScale(vaultSle); auto const vaultScale = assetsTotalProxy.value().exponent();
auto const totalPaidToVaultRaw = auto const totalPaidToVaultRaw =
paymentParts->principalPaid + paymentParts->interestPaid; paymentParts->principalPaid + paymentParts->interestPaid;

View File

@@ -383,7 +383,7 @@ LoanSet::doApply()
auto vaultAvailableProxy = vaultSle->at(sfAssetsAvailable); auto vaultAvailableProxy = vaultSle->at(sfAssetsAvailable);
auto vaultTotalProxy = vaultSle->at(sfAssetsTotal); auto vaultTotalProxy = vaultSle->at(sfAssetsTotal);
auto const vaultScale = getAssetsTotalScale(vaultSle); auto const vaultScale = getVaultScale(vaultSle);
if (vaultAvailableProxy < principalRequested) if (vaultAvailableProxy < principalRequested)
{ {
JLOG(j_.warn()) JLOG(j_.warn())
@@ -404,8 +404,7 @@ LoanSet::doApply()
paymentInterval, paymentInterval,
paymentTotal, paymentTotal,
TenthBips16{brokerSle->at(sfManagementFeeRate)}, TenthBips16{brokerSle->at(sfManagementFeeRate)},
vaultScale, vaultScale);
j_);
// Check that relevant values won't lose precision. This is mostly only // Check that relevant values won't lose precision. This is mostly only
// relevant for IOU assets. // relevant for IOU assets.
@@ -441,10 +440,7 @@ LoanSet::doApply()
{ {
// LCOV_EXCL_START // LCOV_EXCL_START
JLOG(j_.warn()) JLOG(j_.warn())
<< "Computed loan properties are invalid. Does not compute." << "Computed loan properties are invalid. Does not compute.";
<< " Management fee: " << properties.managementFeeOwedToBroker
<< ". Total Value: " << properties.totalValueOutstanding
<< ". PeriodicPayment: " << properties.periodicPayment;
return tecINTERNAL; return tecINTERNAL;
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }