mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-27 06:25:51 +00:00
Merge branch 'ximinez/lending-XLS-66' into ximinez/lending-shortages
This commit is contained in:
@@ -611,7 +611,9 @@ protected:
|
|||||||
auto const limit = asset(
|
auto const limit = asset(
|
||||||
100 *
|
100 *
|
||||||
(brokerParams.vaultDeposit + brokerParams.coverDeposit));
|
(brokerParams.vaultDeposit + brokerParams.coverDeposit));
|
||||||
|
if (lender != issuer)
|
||||||
env(trust(lender, limit));
|
env(trust(lender, limit));
|
||||||
|
if (borrower != issuer)
|
||||||
env(trust(borrower, limit));
|
env(trust(borrower, limit));
|
||||||
|
|
||||||
return asset;
|
return asset;
|
||||||
@@ -639,7 +641,9 @@ protected:
|
|||||||
PrettyAsset const asset{mptt.issuanceID(), 10'000};
|
PrettyAsset const asset{mptt.issuanceID(), 10'000};
|
||||||
// Need to do the authorization here because mptt isn't
|
// Need to do the authorization here because mptt isn't
|
||||||
// accessible outside
|
// accessible outside
|
||||||
|
if (lender != issuer)
|
||||||
mptt.authorize({.account = lender});
|
mptt.authorize({.account = lender});
|
||||||
|
if (borrower != issuer)
|
||||||
mptt.authorize({.account = borrower});
|
mptt.authorize({.account = borrower});
|
||||||
|
|
||||||
env.close();
|
env.close();
|
||||||
@@ -657,17 +661,15 @@ protected:
|
|||||||
jtx::Env& env,
|
jtx::Env& env,
|
||||||
BrokerParameters const& brokerParams,
|
BrokerParameters const& brokerParams,
|
||||||
LoanParameters const& loanParams,
|
LoanParameters const& loanParams,
|
||||||
AssetType assetType)
|
AssetType assetType,
|
||||||
|
jtx::Account const& issuer,
|
||||||
|
jtx::Account const& lender,
|
||||||
|
jtx::Account const& borrower)
|
||||||
{
|
{
|
||||||
using namespace jtx;
|
using namespace jtx;
|
||||||
|
|
||||||
auto const asset = createAsset(
|
auto const asset =
|
||||||
env,
|
createAsset(env, assetType, brokerParams, issuer, lender, borrower);
|
||||||
assetType,
|
|
||||||
brokerParams,
|
|
||||||
Account("issuer"),
|
|
||||||
Account("lender"),
|
|
||||||
Account("borrower"));
|
|
||||||
auto const principal = asset(loanParams.principalRequest).number();
|
auto const principal = asset(loanParams.principalRequest).number();
|
||||||
auto const interest = loanParams.interest.value_or(TenthBips32{});
|
auto const interest = loanParams.interest.value_or(TenthBips32{});
|
||||||
auto const interval =
|
auto const interval =
|
||||||
@@ -720,20 +722,27 @@ protected:
|
|||||||
using namespace jtx;
|
using namespace jtx;
|
||||||
|
|
||||||
// Enough to cover initial fees
|
// Enough to cover initial fees
|
||||||
|
env.fund(env.current()->fees().accountReserve(10) * 10, issuer);
|
||||||
|
if (lender != issuer)
|
||||||
env.fund(
|
env.fund(
|
||||||
env.current()->fees().accountReserve(10) * 10,
|
env.current()->fees().accountReserve(10) * 10,
|
||||||
issuer,
|
noripple(lender));
|
||||||
noripple(lender, borrower));
|
if (borrower != issuer && borrower != lender)
|
||||||
|
env.fund(
|
||||||
|
env.current()->fees().accountReserve(10) * 10,
|
||||||
|
noripple(borrower));
|
||||||
|
|
||||||
describeLoan(env, brokerParams, loanParams, assetType);
|
describeLoan(
|
||||||
|
env, brokerParams, loanParams, assetType, issuer, lender, borrower);
|
||||||
|
|
||||||
// Make the asset
|
// Make the asset
|
||||||
auto const asset =
|
auto const asset =
|
||||||
createAsset(env, assetType, brokerParams, issuer, lender, borrower);
|
createAsset(env, assetType, brokerParams, issuer, lender, borrower);
|
||||||
|
|
||||||
env.close();
|
env.close();
|
||||||
env(
|
if (asset.native() || lender != issuer)
|
||||||
pay((asset.native() ? env.master : issuer),
|
env(pay(
|
||||||
|
(asset.native() ? env.master : issuer),
|
||||||
lender,
|
lender,
|
||||||
asset(brokerParams.vaultDeposit + brokerParams.coverDeposit)));
|
asset(brokerParams.vaultDeposit + brokerParams.coverDeposit)));
|
||||||
// Fund the borrower later once we know the total loan
|
// Fund the borrower later once we know the total loan
|
||||||
@@ -808,7 +817,8 @@ protected:
|
|||||||
|
|
||||||
auto const shortage = totalNeeded - borrowerBalance.number();
|
auto const shortage = totalNeeded - borrowerBalance.number();
|
||||||
|
|
||||||
if (shortage > beast::zero)
|
if (shortage > beast::zero &&
|
||||||
|
(broker.asset.native() || issuer != borrower))
|
||||||
env(
|
env(
|
||||||
pay((broker.asset.native() ? env.master : issuer),
|
pay((broker.asset.native() ? env.master : issuer),
|
||||||
borrower,
|
borrower,
|
||||||
@@ -822,6 +832,9 @@ protected:
|
|||||||
LoanParameters const& loanParams,
|
LoanParameters const& loanParams,
|
||||||
Keylet const& loanKeylet,
|
Keylet const& loanKeylet,
|
||||||
VerifyLoanStatus const& verifyLoanStatus,
|
VerifyLoanStatus const& verifyLoanStatus,
|
||||||
|
jtx::Account const& issuer,
|
||||||
|
jtx::Account const& lender,
|
||||||
|
jtx::Account const& borrower,
|
||||||
bool showStepBalances = false)
|
bool showStepBalances = false)
|
||||||
{
|
{
|
||||||
// Make all the individual payments
|
// Make all the individual payments
|
||||||
@@ -830,9 +843,6 @@ protected:
|
|||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
using d = NetClock::duration;
|
using d = NetClock::duration;
|
||||||
|
|
||||||
Account const issuer{"issuer"};
|
|
||||||
Account const lender{"lender"};
|
|
||||||
Account const borrower{"borrower"};
|
|
||||||
// Account const evan{"evan"};
|
// Account const evan{"evan"};
|
||||||
// Account const alice{"alice"};
|
// Account const alice{"alice"};
|
||||||
|
|
||||||
@@ -939,6 +949,8 @@ protected:
|
|||||||
broker.params.managementFeeRate);
|
broker.params.managementFeeRate);
|
||||||
|
|
||||||
auto validateBorrowerBalance = [&]() {
|
auto validateBorrowerBalance = [&]() {
|
||||||
|
if (borrower == issuer)
|
||||||
|
return;
|
||||||
auto const totalSpent =
|
auto const totalSpent =
|
||||||
(totalPaid.trackedValueDelta + totalFeesPaid +
|
(totalPaid.trackedValueDelta + totalFeesPaid +
|
||||||
(broker.asset.native() ? Number(baseFee) * totalPaymentsMade
|
(broker.asset.native() ? Number(baseFee) * totalPaymentsMade
|
||||||
@@ -1213,7 +1225,15 @@ protected:
|
|||||||
|
|
||||||
VerifyLoanStatus verifyLoanStatus(env, broker, pseudoAcct, loanKeylet);
|
VerifyLoanStatus verifyLoanStatus(env, broker, pseudoAcct, loanKeylet);
|
||||||
|
|
||||||
makeLoanPayments(env, broker, loanParams, loanKeylet, verifyLoanStatus);
|
makeLoanPayments(
|
||||||
|
env,
|
||||||
|
broker,
|
||||||
|
loanParams,
|
||||||
|
loanKeylet,
|
||||||
|
verifyLoanStatus,
|
||||||
|
issuer,
|
||||||
|
lender,
|
||||||
|
borrower);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Runs through the complete lifecycle of a loan
|
/** Runs through the complete lifecycle of a loan
|
||||||
@@ -6432,8 +6452,6 @@ protected:
|
|||||||
.principalRequest = Number{100'000, -4},
|
.principalRequest = Number{100'000, -4},
|
||||||
.interest = TenthBips32{100'000},
|
.interest = TenthBips32{100'000},
|
||||||
.payTotal = 10,
|
.payTotal = 10,
|
||||||
// Guess
|
|
||||||
// .payInterval = 10,
|
|
||||||
.gracePd = 0};
|
.gracePd = 0};
|
||||||
|
|
||||||
auto const assetType = AssetType::MPT;
|
auto const assetType = AssetType::MPT;
|
||||||
@@ -6464,7 +6482,15 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
makeLoanPayments(
|
makeLoanPayments(
|
||||||
env, broker, loanParams, loanKeylet, verifyLoanStatus, true);
|
env,
|
||||||
|
broker,
|
||||||
|
loanParams,
|
||||||
|
loanKeylet,
|
||||||
|
verifyLoanStatus,
|
||||||
|
issuer,
|
||||||
|
lender,
|
||||||
|
borrower,
|
||||||
|
true);
|
||||||
|
|
||||||
if (auto const brokerSle = env.le(broker.brokerKeylet());
|
if (auto const brokerSle = env.le(broker.brokerKeylet());
|
||||||
BEAST_EXPECT(brokerSle))
|
BEAST_EXPECT(brokerSle))
|
||||||
@@ -6669,7 +6695,15 @@ protected:
|
|||||||
VerifyLoanStatus verifyLoanStatus(env, broker, pseudoAcct, loanKeylet);
|
VerifyLoanStatus verifyLoanStatus(env, broker, pseudoAcct, loanKeylet);
|
||||||
|
|
||||||
makeLoanPayments(
|
makeLoanPayments(
|
||||||
env, broker, loanParams, loanKeylet, verifyLoanStatus, true);
|
env,
|
||||||
|
broker,
|
||||||
|
loanParams,
|
||||||
|
loanKeylet,
|
||||||
|
verifyLoanStatus,
|
||||||
|
issuer,
|
||||||
|
lender,
|
||||||
|
borrower,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -6797,6 +6831,55 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testIssuerIsBorrower()
|
||||||
|
{
|
||||||
|
testcase("RIPD-4096 - Issuer as borrower");
|
||||||
|
|
||||||
|
using namespace jtx;
|
||||||
|
|
||||||
|
Account const issuer("issuer");
|
||||||
|
Account const lender("lender");
|
||||||
|
|
||||||
|
BrokerParameters const brokerParams{
|
||||||
|
.vaultDeposit = 100'000,
|
||||||
|
.debtMax = 0,
|
||||||
|
.coverRateMin = TenthBips32{0},
|
||||||
|
.managementFeeRate = TenthBips16{0},
|
||||||
|
.coverRateLiquidation = TenthBips32{0}};
|
||||||
|
LoanParameters const loanParams{
|
||||||
|
.account = lender,
|
||||||
|
.counter = issuer,
|
||||||
|
.principalRequest = Number{10000}};
|
||||||
|
|
||||||
|
auto const assetType = AssetType::IOU;
|
||||||
|
|
||||||
|
Env env(*this, all);
|
||||||
|
|
||||||
|
auto loanResult = createLoan(
|
||||||
|
env, assetType, brokerParams, loanParams, issuer, lender, issuer);
|
||||||
|
|
||||||
|
if (!BEAST_EXPECT(loanResult))
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto broker = std::get<BrokerInfo>(*loanResult);
|
||||||
|
auto loanKeylet = std::get<Keylet>(*loanResult);
|
||||||
|
auto pseudoAcct = std::get<Account>(*loanResult);
|
||||||
|
|
||||||
|
VerifyLoanStatus verifyLoanStatus(env, broker, pseudoAcct, loanKeylet);
|
||||||
|
|
||||||
|
makeLoanPayments(
|
||||||
|
env,
|
||||||
|
broker,
|
||||||
|
loanParams,
|
||||||
|
loanKeylet,
|
||||||
|
verifyLoanStatus,
|
||||||
|
issuer,
|
||||||
|
lender,
|
||||||
|
issuer,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void
|
void
|
||||||
run() override
|
run() override
|
||||||
@@ -6843,6 +6926,7 @@ public:
|
|||||||
testRIPD3902();
|
testRIPD3902();
|
||||||
testRoundingAllowsUndercoverage();
|
testRoundingAllowsUndercoverage();
|
||||||
testBorrowerIsBroker();
|
testBorrowerIsBroker();
|
||||||
|
testIssuerIsBorrower();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -553,7 +553,8 @@ LoanPay::doApply()
|
|||||||
"ripple::LoanPay::doApply",
|
"ripple::LoanPay::doApply",
|
||||||
"positive account balance");
|
"positive account balance");
|
||||||
XRPL_ASSERT_PARTS(
|
XRPL_ASSERT_PARTS(
|
||||||
accountBalanceAfter < accountBalanceBefore,
|
accountBalanceAfter < accountBalanceBefore ||
|
||||||
|
account_ == asset.getIssuer(),
|
||||||
"ripple::LoanPay::doApply",
|
"ripple::LoanPay::doApply",
|
||||||
"account balance decreased");
|
"account balance decreased");
|
||||||
XRPL_ASSERT_PARTS(
|
XRPL_ASSERT_PARTS(
|
||||||
|
|||||||
Reference in New Issue
Block a user