mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Compare commits
28 Commits
ximinez/le
...
ximinez/le
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03a2e10600 | ||
|
|
d475cb96c1 | ||
|
|
24a0af37d8 | ||
|
|
c740b06861 | ||
|
|
8e4be94f4a | ||
|
|
1f3ded7116 | ||
|
|
aa1234199a | ||
|
|
14888c6d1f | ||
|
|
da9a483b79 | ||
|
|
f447827474 | ||
|
|
aa93a779a4 | ||
|
|
19c72b30e4 | ||
|
|
07497322de | ||
|
|
530fccaa7e | ||
|
|
e8cb14c522 | ||
|
|
12a5c0a698 | ||
|
|
30cda21f24 | ||
|
|
fc280d42bf | ||
|
|
683c9c31c9 | ||
|
|
a9793b2565 | ||
|
|
4ef7f18f20 | ||
|
|
e6c6d0f5d1 | ||
|
|
f0326dcbb4 | ||
|
|
85af14295c | ||
|
|
8a16afc23b | ||
|
|
8b7da79f64 | ||
|
|
f9c9b1d2e3 | ||
|
|
d0c4adf202 |
@@ -521,6 +521,35 @@ protected:
|
|||||||
.paymentInterval = loan->at(sfPaymentInterval),
|
.paymentInterval = loan->at(sfPaymentInterval),
|
||||||
.interestRate = TenthBips32{loan->at(sfInterestRate)},
|
.interestRate = TenthBips32{loan->at(sfInterestRate)},
|
||||||
};
|
};
|
||||||
|
BEAST_EXPECT(state.previousPaymentDate == 0);
|
||||||
|
BEAST_EXPECT(
|
||||||
|
tp{d{state.nextPaymentDate}} == state.startDate + 600s);
|
||||||
|
BEAST_EXPECT(state.paymentRemaining == 12);
|
||||||
|
BEAST_EXPECT(
|
||||||
|
state.principalOutstanding == broker.asset(loanAmount).value());
|
||||||
|
BEAST_EXPECT(
|
||||||
|
state.loanScale ==
|
||||||
|
(broker.asset.integral()
|
||||||
|
? 0
|
||||||
|
: state.principalOutstanding.exponent()));
|
||||||
|
BEAST_EXPECT(state.paymentInterval == 600);
|
||||||
|
BEAST_EXPECT(
|
||||||
|
state.totalValue ==
|
||||||
|
roundToAsset(
|
||||||
|
broker.asset,
|
||||||
|
state.periodicPayment * state.paymentRemaining,
|
||||||
|
state.loanScale));
|
||||||
|
BEAST_EXPECT(
|
||||||
|
state.managementFeeOutstanding ==
|
||||||
|
computeFee(
|
||||||
|
broker.asset,
|
||||||
|
state.totalValue - state.principalOutstanding,
|
||||||
|
managementFeeRateParameter,
|
||||||
|
state.loanScale));
|
||||||
|
|
||||||
|
verifyLoanStatus(state);
|
||||||
|
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
return LoanState{};
|
return LoanState{};
|
||||||
}
|
}
|
||||||
@@ -532,6 +561,7 @@ protected:
|
|||||||
jtx::Env const& env,
|
jtx::Env const& env,
|
||||||
BrokerInfo const& broker,
|
BrokerInfo const& broker,
|
||||||
Keylet const& loanKeylet,
|
Keylet const& loanKeylet,
|
||||||
|
Number const& loanAmount,
|
||||||
VerifyLoanStatus const& verifyLoanStatus)
|
VerifyLoanStatus const& verifyLoanStatus)
|
||||||
{
|
{
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
@@ -1369,10 +1399,10 @@ protected:
|
|||||||
.counterpartyExplicit = false,
|
.counterpartyExplicit = false,
|
||||||
.principalRequest = loanAmount,
|
.principalRequest = loanAmount,
|
||||||
.setFee = loanSetFee,
|
.setFee = loanSetFee,
|
||||||
.originationFee = 1,
|
.originationFee = loanAmount * Number(1, -3),
|
||||||
.serviceFee = 2,
|
.serviceFee = loanAmount * Number(2, -3),
|
||||||
.lateFee = 3,
|
.lateFee = loanAmount * Number(3, -3),
|
||||||
.closeFee = 4,
|
.closeFee = loanAmount * Number(4, -3),
|
||||||
.overFee = applyExponent(percentageToTenthBips(5) / 10),
|
.overFee = applyExponent(percentageToTenthBips(5) / 10),
|
||||||
.interest = applyExponent(percentageToTenthBips(12)),
|
.interest = applyExponent(percentageToTenthBips(12)),
|
||||||
// 2.4%
|
// 2.4%
|
||||||
@@ -1473,7 +1503,8 @@ protected:
|
|||||||
loan->at(sfPrincipalOutstanding) == principalRequestAmount);
|
loan->at(sfPrincipalOutstanding) == principalRequestAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto state = getCurrentState(env, broker, keylet, verifyLoanStatus);
|
auto state =
|
||||||
|
getCurrentState(env, broker, keylet, loanAmount, verifyLoanStatus);
|
||||||
|
|
||||||
auto const loanProperties = computeLoanProperties(
|
auto const loanProperties = computeLoanProperties(
|
||||||
broker.asset.raw(),
|
broker.asset.raw(),
|
||||||
@@ -1648,8 +1679,8 @@ protected:
|
|||||||
auto const currencyLabel = getCurrencyLabel(asset);
|
auto const currencyLabel = getCurrencyLabel(asset);
|
||||||
auto const caseLabel = [&]() {
|
auto const caseLabel = [&]() {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Lifecycle: " << loanAmount << " " << currencyLabel
|
ss << "Lifecycle: " << " " << currencyLabel << " Interest scale: "
|
||||||
<< " Scale interest to: " << interestExponent << " ";
|
<< Number(1, interestExponent) " Amount: " << loanAmount;
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}();
|
}();
|
||||||
testcase << caseLabel;
|
testcase << caseLabel;
|
||||||
@@ -2150,8 +2181,8 @@ protected:
|
|||||||
// Default the loan
|
// Default the loan
|
||||||
|
|
||||||
// Initialize values with the current state
|
// Initialize values with the current state
|
||||||
auto state =
|
auto state = getCurrentState(
|
||||||
getCurrentState(env, broker, loanKeylet, verifyLoanStatus);
|
env, broker, loanKeylet, loanAmount, verifyLoanStatus);
|
||||||
BEAST_EXPECT(state.flags == baseFlag);
|
BEAST_EXPECT(state.flags == baseFlag);
|
||||||
|
|
||||||
auto const& broker = verifyLoanStatus.broker;
|
auto const& broker = verifyLoanStatus.broker;
|
||||||
@@ -2379,8 +2410,9 @@ protected:
|
|||||||
VerifyLoanStatus const& verifyLoanStatus) {
|
VerifyLoanStatus const& verifyLoanStatus) {
|
||||||
// toEndOfLife
|
// toEndOfLife
|
||||||
//
|
//
|
||||||
auto state =
|
auto state = getCurrentState(
|
||||||
getCurrentState(env, broker, loanKeylet, verifyLoanStatus);
|
env, broker, loanKeylet, loanAmount, verifyLoanStatus);
|
||||||
|
BEAST_EXPECT(state.flags == baseFlag);
|
||||||
env.close(state.startDate + 20s);
|
env.close(state.startDate + 20s);
|
||||||
auto const loanAge = (env.now() - state.startDate).count();
|
auto const loanAge = (env.now() - state.startDate).count();
|
||||||
BEAST_EXPECT(loanAge == 30);
|
BEAST_EXPECT(loanAge == 30);
|
||||||
@@ -2407,22 +2439,38 @@ protected:
|
|||||||
interval};
|
interval};
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
accruedInterest ==
|
accruedInterest ==
|
||||||
broker.asset(Number(1141552511415525, -19)));
|
broker.asset(loanAmount * Number(1141552511415525, -22)));
|
||||||
STAmount const prepaymentPenalty{
|
STAmount const prepaymentPenalty{
|
||||||
broker.asset, state.principalOutstanding * Number(36, -3)};
|
broker.asset,
|
||||||
BEAST_EXPECT(prepaymentPenalty == broker.asset(36));
|
state.principalOutstanding *
|
||||||
STAmount const closePaymentFee = broker.asset(4);
|
Number(36, interestExponent - 3)};
|
||||||
|
BEAST_EXPECT(
|
||||||
|
prepaymentPenalty ==
|
||||||
|
broker.asset(
|
||||||
|
loanAmount * Number(36, interestExponent - 3)));
|
||||||
|
STAmount const closePaymentFee =
|
||||||
|
broker.asset(loanAmount * Number(4, -3));
|
||||||
auto const payoffAmount = roundToScale(
|
auto const payoffAmount = roundToScale(
|
||||||
principalOutstanding + accruedInterest + prepaymentPenalty +
|
principalOutstanding + accruedInterest + prepaymentPenalty +
|
||||||
closePaymentFee,
|
closePaymentFee,
|
||||||
state.loanScale);
|
state.loanScale);
|
||||||
|
// TODO: Figure out what's wrong with this calculation
|
||||||
|
// STAmount{broker.asset, state.principalOutstanding} +
|
||||||
|
// accruedInterest + prepaymentPenalty + closePaymentFee;
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
payoffAmount ==
|
payoffAmount ==
|
||||||
roundToAsset(
|
roundToAsset(
|
||||||
broker.asset,
|
broker.asset,
|
||||||
broker.asset(Number(1040000114155251, -12)).number(),
|
broker.asset(loanAmount * Number(1040000114155251, -15))
|
||||||
|
.number(),
|
||||||
state.loanScale));
|
state.loanScale));
|
||||||
|
|
||||||
|
// Try to pay a little extra to show that it's _not_
|
||||||
|
// taken
|
||||||
|
auto const transactionAmount =
|
||||||
|
payoffAmount + broker.asset(loanAmount * Number(1, -2));
|
||||||
|
env(pay(borrower, loanKeylet.key, transactionAmount));
|
||||||
|
|
||||||
// The terms of this loan actually make the early payoff
|
// The terms of this loan actually make the early payoff
|
||||||
// more expensive than just making payments
|
// more expensive than just making payments
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
@@ -2611,8 +2659,8 @@ protected:
|
|||||||
// toEndOfLife
|
// toEndOfLife
|
||||||
//
|
//
|
||||||
// Draw and make multiple payments
|
// Draw and make multiple payments
|
||||||
auto state =
|
auto state = getCurrentState(
|
||||||
getCurrentState(env, broker, loanKeylet, verifyLoanStatus);
|
env, broker, loanKeylet, loanAmount, verifyLoanStatus);
|
||||||
BEAST_EXPECT(state.flags == 0);
|
BEAST_EXPECT(state.flags == 0);
|
||||||
env.close();
|
env.close();
|
||||||
|
|
||||||
@@ -2724,6 +2772,21 @@ protected:
|
|||||||
|
|
||||||
while (state.paymentRemaining > 0)
|
while (state.paymentRemaining > 0)
|
||||||
{
|
{
|
||||||
|
// Try to pay a little extra to show that it's _not_
|
||||||
|
// taken
|
||||||
|
STAmount const transactionAmount =
|
||||||
|
STAmount{broker.asset, totalDue} +
|
||||||
|
broker.asset(loanAmount * Number(1, -2));
|
||||||
|
// Only check the first payment since the rounding may
|
||||||
|
// drift as payments are made
|
||||||
|
BEAST_EXPECT(
|
||||||
|
transactionAmount ==
|
||||||
|
roundToScale(
|
||||||
|
broker.asset(
|
||||||
|
Number(9533457001162141, -14), Number::upward),
|
||||||
|
state.loanScale,
|
||||||
|
Number::upward));
|
||||||
|
|
||||||
// Compute the expected principal amount
|
// Compute the expected principal amount
|
||||||
auto const paymentComponents =
|
auto const paymentComponents =
|
||||||
detail::computePaymentComponents(
|
detail::computePaymentComponents(
|
||||||
@@ -2805,7 +2868,7 @@ protected:
|
|||||||
Number::upward) ==
|
Number::upward) ==
|
||||||
roundToScale(
|
roundToScale(
|
||||||
broker.asset(
|
broker.asset(
|
||||||
Number(8333228695260180, -14),
|
loanAmount * Number(8333228695260180, -17),
|
||||||
Number::upward),
|
Number::upward),
|
||||||
state.loanScale,
|
state.loanScale,
|
||||||
Number::upward));
|
Number::upward));
|
||||||
@@ -2917,6 +2980,10 @@ protected:
|
|||||||
ter(tecNO_PERMISSION));
|
ter(tecNO_PERMISSION));
|
||||||
env(manage(lender, loanKeylet.key, tfLoanDefault),
|
env(manage(lender, loanKeylet.key, tfLoanDefault),
|
||||||
ter(tecNO_PERMISSION));
|
ter(tecNO_PERMISSION));
|
||||||
|
|
||||||
|
// Can't make a payment on it either
|
||||||
|
env(pay(borrower, loanKeylet.key, broker.asset(loanAmount)),
|
||||||
|
ter(tecKILLED));
|
||||||
});
|
});
|
||||||
|
|
||||||
#if LOANTODO
|
#if LOANTODO
|
||||||
@@ -3659,19 +3726,23 @@ protected:
|
|||||||
// Create and update Loans
|
// Create and update Loans
|
||||||
for (auto const& broker : brokers)
|
for (auto const& broker : brokers)
|
||||||
{
|
{
|
||||||
for (int amountExponent = 3; amountExponent >= 3; --amountExponent)
|
for (int amountMantissa : {1, 3, 7})
|
||||||
{
|
{
|
||||||
Number const loanAmount{1, amountExponent};
|
for (int amountExponent = 3; amountExponent >= -5;
|
||||||
for (int interestExponent = 0; interestExponent >= 0;
|
amountExponent -= 4)
|
||||||
--interestExponent)
|
|
||||||
{
|
{
|
||||||
testCaseWrapper(
|
Number const loanAmount{amountMantissa, amountExponent};
|
||||||
env,
|
for (int interestExponent = 1 - 1; interestExponent >= -2;
|
||||||
mptt,
|
--interestExponent)
|
||||||
assets,
|
{
|
||||||
broker,
|
testCaseWrapper(
|
||||||
loanAmount,
|
env,
|
||||||
interestExponent);
|
mptt,
|
||||||
|
assets,
|
||||||
|
broker,
|
||||||
|
loanAmount,
|
||||||
|
interestExponent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user