93 auto const& asset = vault.asset.raw();
99 else if (asset.holds<
Issue>())
109 assetLabel =
"Unknown ";
111 testcase <<
"Lifecycle: " << assetLabel << label;
115 using namespace loanBroker;
120 badMptt.
create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock});
122 return badMptt[
"BAD"];
124 static PrettyAsset const badIouAsset = evan[
"BAD"];
125 static Account const nonExistent{
"NonExistent"};
126 static PrettyAsset const ghostIouAsset = nonExistent[
"GST"];
127 PrettyAsset const vaultPseudoIouAsset = vault.pseudoAccount[
"PSD"];
132 auto const badBrokerPseudo = [&]() {
133 if (
auto const le = env.
le(badKeylet); BEAST_EXPECT(le))
135 return Account{
"Bad Broker pseudo-account", le->at(sfAccount)};
138 return vault.pseudoAccount;
140 PrettyAsset const badBrokerPseudoIouAsset = badBrokerPseudo[
"WAT"];
145 auto jtx = env.
jt(
set(alice, vault.vaultID));
148 jtx = modifyJTx(jtx);
154 if (
auto broker = env.
le(keylet); BEAST_EXPECT(broker))
158 BEAST_EXPECT(broker->at(sfVaultID) == vault.vaultID);
159 BEAST_EXPECT(broker->at(sfAccount) != alice.
id());
160 BEAST_EXPECT(broker->at(sfOwner) == alice.
id());
161 BEAST_EXPECT(broker->at(sfFlags) == 0);
162 BEAST_EXPECT(broker->at(sfSequence) == env.
seq(alice) - 1);
163 BEAST_EXPECT(broker->at(sfOwnerCount) == 0);
164 BEAST_EXPECT(broker->at(sfLoanSequence) == 1);
165 BEAST_EXPECT(broker->at(sfDebtTotal) == 0);
166 BEAST_EXPECT(broker->at(sfCoverAvailable) == 0);
176 Account const pseudoAccount{
"Broker pseudo-account", broker->at(sfAccount)};
179 if (
auto const pseudo = env.
le(pseudoKeylet); BEAST_EXPECT(pseudo))
185 pseudo->at(sfFlags) == (lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth));
186 BEAST_EXPECT(pseudo->at(sfSequence) == 0);
187 BEAST_EXPECT(pseudo->at(sfBalance) == beast::zero);
188 BEAST_EXPECT(pseudo->at(sfOwnerCount) == (vault.asset.raw().native() ? 0 : 1));
189 BEAST_EXPECT(!pseudo->isFieldPresent(sfAccountTxnID));
190 BEAST_EXPECT(!pseudo->isFieldPresent(sfRegularKey));
191 BEAST_EXPECT(!pseudo->isFieldPresent(sfEmailHash));
192 BEAST_EXPECT(!pseudo->isFieldPresent(sfWalletLocator));
193 BEAST_EXPECT(!pseudo->isFieldPresent(sfWalletSize));
194 BEAST_EXPECT(!pseudo->isFieldPresent(sfMessageKey));
195 BEAST_EXPECT(!pseudo->isFieldPresent(sfTransferRate));
196 BEAST_EXPECT(!pseudo->isFieldPresent(sfDomain));
197 BEAST_EXPECT(!pseudo->isFieldPresent(sfTickSize));
198 BEAST_EXPECT(!pseudo->isFieldPresent(sfTicketCount));
199 BEAST_EXPECT(!pseudo->isFieldPresent(sfNFTokenMinter));
200 BEAST_EXPECT(!pseudo->isFieldPresent(sfMintedNFTokens));
201 BEAST_EXPECT(!pseudo->isFieldPresent(sfBurnedNFTokens));
202 BEAST_EXPECT(!pseudo->isFieldPresent(sfFirstNFTokenSequence));
203 BEAST_EXPECT(!pseudo->isFieldPresent(sfAMMID));
204 BEAST_EXPECT(!pseudo->isFieldPresent(sfVaultID));
205 BEAST_EXPECT(pseudo->at(sfLoanBrokerID) == keylet.
key);
211 auto const accountInfo = env.
rpc(
"account_info", pseudoStr);
212 if (BEAST_EXPECT(accountInfo.isObject()))
214 auto const& accountData = accountInfo[jss::result][jss::account_data];
215 if (BEAST_EXPECT(accountData.isObject()))
217 BEAST_EXPECT(accountData[jss::Account] == pseudoStr);
218 BEAST_EXPECT(accountData[sfLoanBrokerID] ==
to_string(keylet.
key));
220 auto const& pseudoInfo = accountInfo[jss::result][jss::pseudo_account];
221 if (BEAST_EXPECT(pseudoInfo.isObject()))
223 BEAST_EXPECT(pseudoInfo[jss::type] ==
"LoanBroker");
228 auto verifyCoverAmount =
229 [&env, &vault, &pseudoAccount, &broker, &keylet,
this](
auto n) {
232 if (BEAST_EXPECT(broker = env.
le(keylet)))
234 auto const amount = vault.asset(n);
235 BEAST_EXPECT(broker->at(sfCoverAvailable) ==
amount.number());
245 env(coverDeposit(alice, vault.vaultID, vault.asset(10)),
ter(
tecNO_ENTRY));
247 verifyCoverAmount(0);
257 env(coverClawback(evan), loanBrokerID(vault.vaultID),
ter(
tecNO_ENTRY));
260 if (vault.asset.raw().native())
267 if (vault.asset.raw().holds<
Issue>())
274 env(coverClawback(alice),
275 amount(vaultPseudoIouAsset(1)),
279 env(coverClawback(issuer),
280 loanBrokerID(keylet.
key),
281 amount(badBrokerPseudoIouAsset(10)),
283 PrettyAsset const brokerWrongCurrencyAsset = pseudoAccount[
"WAT"];
284 env(coverClawback(issuer),
285 loanBrokerID(keylet.
key),
286 amount(brokerWrongCurrencyAsset(10)),
293 BEAST_EXPECT(vault.asset.raw().holds<
MPTIssue>());
298 env(coverClawback(issuer),
299 loanBrokerID(keylet.
key),
306 env(coverDeposit(alice, keylet.
key, vault.asset(10)));
308 verifyCoverAmount(10);
315 env(coverWithdraw(alice, vault.vaultID, vault.asset(10)),
ter(
tecNO_ENTRY));
319 if (!vault.asset.raw().native())
322 env(coverWithdraw(alice, keylet.
key, vault.asset(1)),
323 destination(bystander),
328 env(coverWithdraw(alice, keylet.
key, vault.asset(1)),
333 env(coverWithdraw(alice, keylet.
key, vault.asset(7)));
335 verifyCoverAmount(3);
338 env(coverDeposit(alice, keylet.
key, vault.asset(5)));
340 verifyCoverAmount(8);
344 env(coverWithdraw(alice, keylet.
key, vault.asset(1)), destination(evan));
346 verifyCoverAmount(7);
350 env(coverWithdraw(alice, keylet.
key, vault.asset(1)), destination(evan),
dtag(3));
352 verifyCoverAmount(6);
354 if (!vault.asset.raw().native())
357 env(coverClawback(issuer), loanBrokerID(keylet.
key),
amount(vault.asset(2)));
359 verifyCoverAmount(4);
362 env(coverDeposit(alice, keylet.
key, vault.asset(5)));
364 verifyCoverAmount(9);
367 for (
auto const& tx : {
370 coverClawback(issuer),
371 loanBrokerID(keylet.
key),
376 coverClawback(issuer),
377 loanBrokerID(keylet.
key),
383 coverClawback(issuer),
384 loanBrokerID(keylet.
key),
391 coverClawback(issuer),
392 loanBrokerID(keylet.
key),
402 verifyCoverAmount(0);
405 env(coverDeposit(alice, keylet.
key, vault.asset(6)));
407 verifyCoverAmount(6);
412 env(
set(alice, vault.vaultID), loanBrokerID(keylet.
key));
417 changeBroker(broker);
422 if (BEAST_EXPECT(broker = env.
le(keylet)) && checkChangedBroker)
423 checkChangedBroker(broker);
428 env(
set(alice, vault.vaultID),
429 loanBrokerID(broker->key()),
435 if (BEAST_EXPECT(broker = env.
le(keylet)))
437 BEAST_EXPECT(!broker->isFieldPresent(sfDebtMaximum));
438 BEAST_EXPECT(!broker->isFieldPresent(sfData));
448 env(del(alice, badKeylet.key));
453 auto const aliceBalance = env.
balance(alice, vault.asset);
454 auto const coverFunds = env.
balance(pseudoAccount, vault.asset);
455 BEAST_EXPECT(coverFunds.number() == broker->at(sfCoverAvailable));
456 BEAST_EXPECT(coverFunds != beast::zero);
457 verifyCoverAmount(6);
470 env(del(alice, keylet.
key));
473 broker = env.
le(keylet);
474 BEAST_EXPECT(!broker);
475 auto pseudo = env.
le(pseudoKeylet);
476 BEAST_EXPECT(!pseudo);
478 auto const expectedBalance = aliceBalance + coverFunds -
479 (aliceBalance.value().native() ?
STAmount(env.
current()->fees().base.value())
496 Account const issuer{
"issuer"};
503 Account const bystander{
"bystander"};
511 env(
fset(issuer, asfAllowTrustLineClawback));
517 env(
trust(alice, iouAsset(1'000'000)));
518 env(
trust(evan, iouAsset(1'000'000)));
520 env(
pay(issuer, evan, iouAsset(100'000)));
521 env(
pay(issuer, alice, iouAsset(100'000)));
525 mptt.
create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock});
528 mptt.authorize({.account = alice});
529 mptt.authorize({.account = evan});
531 env(
pay(issuer, alice, mptAsset(100'000)));
532 env(
pay(issuer, evan, mptAsset(100'000)));
535 std::array const assets{xrpAsset, iouAsset, mptAsset};
539 for (
auto const& asset : assets)
541 auto [tx, keylet] = vault.create({.owner = alice, .asset = asset});
544 if (
auto const le = env.
le(keylet); BEAST_EXPECT(env.
le(keylet)))
549 env(vault.deposit({.depositor = alice, .id = keylet.key, .amount = asset(50)}));
553 auto [tx, keylet] = vault.create({.owner = alice, .asset = iouAsset});
556 if (
auto const le = env.
le(keylet); BEAST_EXPECT(env.
le(keylet)))
558 return {iouAsset, keylet.
key, le->at(sfAccount)};
561 return {iouAsset, keylet.
key, evan.
id()};
564 auto const aliceOriginalCount = env.
ownerCount(alice);
567 for (
auto const& vault : vaults)
572 auto const accountInfo = env.
rpc(
"account_info", pseudoStr);
573 if (BEAST_EXPECT(accountInfo.isObject()))
575 auto const& accountData = accountInfo[jss::result][jss::account_data];
576 if (BEAST_EXPECT(accountData.isObject()))
578 BEAST_EXPECT(accountData[jss::Account] == pseudoStr);
579 BEAST_EXPECT(accountData[sfVaultID] ==
to_string(vault.vaultID));
581 auto const& pseudoInfo = accountInfo[jss::result][jss::pseudo_account];
582 if (BEAST_EXPECT(pseudoInfo.isObject()))
584 BEAST_EXPECT(pseudoInfo[jss::type] ==
"Vault");
589 using namespace loanBroker;
604 env(
set(evan, vault.vaultID),
608 env(
set(evan, vault.vaultID),
612 env(
set(evan, vault.vaultID),
613 managementFeeRate(maxManagementFeeRate),
616 env(
set(evan, vault.vaultID),
617 managementFeeRate(maxManagementFeeRate +
TenthBips16(10)),
621 env(
set(evan, vault.vaultID),
622 coverRateMinimum(maxCoverRate),
623 coverRateLiquidation(maxCoverRate),
626 env(
set(evan, vault.vaultID),
627 coverRateMinimum(maxCoverRate + 1),
628 coverRateLiquidation(maxCoverRate + 1),
631 env(
set(evan, vault.vaultID),
632 coverRateMinimum(maxCoverRate / 2),
633 coverRateLiquidation(maxCoverRate + 1),
637 env(
set(evan, vault.vaultID), coverRateLiquidation(maxCoverRate),
ter(
temINVALID));
638 env(
set(evan, vault.vaultID),
639 coverRateMinimum(tenthBipsZero),
640 coverRateLiquidation(maxCoverRate),
644 env(
set(evan, vault.vaultID), coverRateMinimum(maxCoverRate),
ter(
temINVALID));
645 env(
set(evan, vault.vaultID),
646 coverRateMinimum(maxCoverRate),
647 coverRateLiquidation(tenthBipsZero),
670 BEAST_EXPECT(!broker->isFieldPresent(sfManagementFeeRate));
671 BEAST_EXPECT(!broker->isFieldPresent(sfCoverRateMinimum));
672 BEAST_EXPECT(!broker->isFieldPresent(sfCoverRateLiquidation));
673 BEAST_EXPECT(!broker->isFieldPresent(sfData));
674 BEAST_EXPECT(!broker->isFieldPresent(sfDebtMaximum));
675 BEAST_EXPECT(broker->at(sfDebtMaximum) == 0);
676 BEAST_EXPECT(broker->at(sfCoverRateMinimum) == 0);
677 BEAST_EXPECT(broker->at(sfCoverRateLiquidation) == 0);
679 BEAST_EXPECT(env.
ownerCount(alice) == aliceOriginalCount + 4);
693 env(
set(evan, vault.vaultID),
694 loanBrokerID(broker->key()),
697 env(
set(alice, vault.vaultID),
698 loanBrokerID(broker->key()),
699 managementFeeRate(maxManagementFeeRate),
702 env(
set(alice, vault.vaultID),
703 loanBrokerID(broker->key()),
704 coverRateMinimum(maxManagementFeeRate),
707 env(
set(alice, vault.vaultID),
708 loanBrokerID(broker->key()),
709 coverRateLiquidation(maxManagementFeeRate),
713 testData =
"Test Data 1234";
715 env(
set(alice, vault.vaultID),
716 loanBrokerID(broker->key()),
721 env(
set(alice, vault.vaultID),
722 loanBrokerID(broker->key()),
723 debtMaximum(
Number(-175, -1)),
726 if (vault.asset.integral())
728 env(
set(alice, vault.vaultID),
729 loanBrokerID(broker->key()),
731 debtMaximum(debtMax),
736 env(
set(alice, vault.vaultID),
737 loanBrokerID(broker->key()),
739 debtMaximum(debtMax));
743 BEAST_EXPECT(
checkVL(broker->at(sfData), testData));
745 auto const actual = broker->at(sfDebtMaximum);
752 "non-default fields",
761 testData =
"spam spam spam spam";
774 BEAST_EXPECT(broker->at(sfManagementFeeRate) == 123);
775 BEAST_EXPECT(broker->at(sfCoverRateMinimum) == 100);
776 BEAST_EXPECT(broker->at(sfCoverRateLiquidation) == 200);
777 BEAST_EXPECT(broker->at(sfDebtMaximum) ==
Number(9));
778 BEAST_EXPECT(
checkVL(broker->at(sfData), testData));
782 env(
set(alice, vault.vaultID),
783 loanBrokerID(broker->key()),
789 BEAST_EXPECT(!broker->isFieldPresent(sfData));
790 BEAST_EXPECT(!broker->isFieldPresent(sfDebtMaximum));
794 BEAST_EXPECT(env.
ownerCount(alice) == aliceOriginalCount);
806 using namespace loanBroker;
807 Account const issuer{
"issuer"};
810 Vault const vault{env};
812 env.
fund(
XRP(100'000), issuer, alice);
817 return getAsset(env, issuer, alice);
818 env(
trust(alice, issuer[
"IOU"](1'000'000)));
823 env(
pay(issuer, alice, asset(100'000)));
826 auto [tx, vaultKeylet] = vault.create({.owner = alice, .asset = asset});
829 auto const le = env.
le(vaultKeylet);
831 if (BEAST_EXPECT(le))
832 return VaultInfo{asset, vaultKeylet.key, le->at(sfAccount)};
838 env(vault.deposit({.depositor = alice, .id = vaultKeylet.key, .amount = asset(50)}));
842 env(
set(alice, vaultInfo.vaultID));
845 auto broker = env.
le(brokerKeylet);
846 if (!BEAST_EXPECT(broker))
849 auto testZeroBrokerID = [&](
auto&& getTxJv) {
852 jv[sfLoanBrokerID] =
"";
860 auto testZeroVaultID = [&](
auto&& getTxJv) {
875 testZeroBrokerID([&]() {
return coverDeposit(alice, brokerKeylet.key, asset(10)); });
881 env(
pay(alice, issuer, asset(100'000 - 50)));
883 env(
coverDeposit(alice, brokerKeylet.key, vaultInfo.asset(10)),
887 env(
fset(issuer, asfGlobalFreeze));
894 env(
coverDeposit(alice, brokerKeylet.key, vaultInfo.asset(10)));
901 testZeroBrokerID([&]() {
return coverWithdraw(alice, brokerKeylet.key, asset(10)); });
907 Account
const bogus{
"bogus"};
913 Account
const dest{
"dest"};
915 env(
fset(dest, asfRequireDest));
922 env(
fclear(dest, asfRequireDest));
923 env(
fset(dest, asfDepositAuth));
930 env(
trust(dest, asset(1'000)));
931 env(
fclear(dest, asfDepositAuth));
932 env(
fset(issuer, asfGlobalFreeze));
939 env(
fclear(issuer, asfGlobalFreeze));
940 env(
trust(issuer, asset(1'000), dest, tfSetFreeze | tfSetDeepFreeze));
954 testZeroBrokerID([&]() {
958 amount(vaultInfo.asset(2)));
961 if (asset.holds<
Issue>())
966 amount(vaultInfo.asset(2)),
970 env(
fset(issuer, asfAllowTrustLineClawback | asfNoFreeze));
974 amount(vaultInfo.asset(2)),
982 amount(vaultInfo.asset(2)),
990 Account
const borrower{
"borrower"};
991 env.
fund(
XRP(1'000), borrower);
992 env(
loan::set(borrower, brokerKeylet.key, asset(50).value()),
993 sig(sfCounterpartySignature, alice),
994 fee(env.
current()->fees().base * 2));
997 testZeroBrokerID([&]() {
return del(alice, brokerKeylet.key); });
1003 auto const loanKeylet =
keylet::loan(brokerKeylet.key, 1);
1004 env(
loan::pay(borrower, loanKeylet.key, asset(50).value()));
1007 env(
trust(issuer, asset(0), alice, tfSetFreeze | tfSetDeepFreeze));
1010 env(
trust(issuer, asset(0), alice, tfClearFreeze | tfClearDeepFreeze));
1017 env(
del(alice, brokerKeylet.key));
1020 if (brokerTest ==
Set)
1023 testZeroBrokerID([&]() {
1027 testZeroVaultID([&]() {
1031 if (asset.holds<
Issue>())
1033 env(
fclear(issuer, asfDefaultRipple));
1038 env(
fset(issuer, asfDefaultRipple));
1044 env(
pay(alice, issuer, amt));
1217 testcase(
"Require Auth - Implicit Pseudo-account authorization");
1218 using namespace jtx;
1219 using namespace loanBroker;
1221 Account const issuer{
"issuer"};
1226 env.
fund(
XRP(100'000), issuer, alice);
1233 .flags =
MPTDEXFlags | tfMPTRequireAuth | tfMPTCanClawback | tfMPTCanLock,
1237 env(
pay(issuer, alice, asset(100'000)));
1241 asset.authorize({.account = issuer, .holder = alice, .flags = tfMPTUnauthorize});
1242 auto [tx, vaultKeylet] = vault.create({.owner = alice, .asset = asset});
1246 auto const le = env.
le(vaultKeylet);
1248 if (BEAST_EXPECT(le))
1249 return VaultInfo{asset, vaultKeylet.key, le->at(sfAccount)};
1258 .holder = vaultInfo.pseudoAccount,
1259 .flags = tfMPTUnauthorize,
1262 auto forUnauthAuth = [&](
auto&& doTx) {
1263 for (
auto const flag : {tfMPTUnauthorize, 0u})
1265 asset.authorize({.account = issuer, .holder = alice, .flags = flag});
1275 env(
vault.deposit({.depositor = alice, .id = vaultKeylet.key, .amount = asset(51)}),
1282 env(
vault.withdraw({.depositor = alice, .id = vaultKeylet.key, .amount = asset(1)}),
1288 forUnauthAuth([&](
auto) { env(
set(alice, vaultInfo.vaultID)); });
1290 auto const broker = env.
le(brokerKeylet);
1291 if (!BEAST_EXPECT(broker))
1293 Account brokerPseudo(
"pseudo", broker->at(sfAccount));
1298 .holder = brokerPseudo,
1299 .flags = tfMPTUnauthorize,
1305 env(
coverDeposit(alice, brokerKeylet.key, vaultInfo.asset(10)), err);
1311 env(
coverWithdraw(alice, brokerKeylet.key, vaultInfo.asset(5)), err);
1315 forUnauthAuth([&](
bool) {
1323 testcase(
"testLoanBrokerSetDebtMaximum");
1324 using namespace jtx;
1325 using namespace loanBroker;
1326 Account const issuer{
"issuer"};
1329 Vault const vault{env};
1331 env.
fund(
XRP(100'000), issuer, alice);
1335 MPTTester mptt{env, issuer, mptInitNoFund};
1336 mptt.create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock});
1339 mptt.authorize({.account = alice});
1344 env(pay(issuer, alice, asset(100'000)));
1347 auto [tx, vaultKeylet] = vault.create({.owner = alice, .asset = asset});
1350 auto const le = env.
le(vaultKeylet);
1352 if (BEAST_EXPECT(le))
1353 return VaultInfo{asset, vaultKeylet.key, le->at(sfAccount)};
1359 env(vault.deposit({.depositor = alice, .id = vaultKeylet.key, .amount = asset(50)}));
1363 env(
set(alice, vaultInfo.vaultID));
1366 Account const borrower{
"borrower"};
1367 env.
fund(XRP(1'000), borrower);
1368 env(loan::set(borrower, brokerKeylet.key, asset(50).value()),
1369 sig(sfCounterpartySignature, alice),
1370 fee(env.
current()->fees().base * 2));
1371 auto const broker = env.
le(brokerKeylet);
1372 if (!BEAST_EXPECT(broker))
1375 BEAST_EXPECT(broker->at(sfDebtTotal) == 50);
1376 auto debtTotal = broker->at(sfDebtTotal);
1378 auto tx2 =
set(alice, vaultInfo.vaultID);
1379 tx2[sfLoanBrokerID] =
to_string(brokerKeylet.key);
1380 tx2[sfDebtMaximum] = debtTotal - 1;
1383 tx2[sfDebtMaximum] = debtTotal + 1;
1386 tx2[sfDebtMaximum] = 0;
1393 auto const dm =
power(2, 64) - 1;
1395 tx2[sfDebtMaximum] = dm;
1400 auto const dm =
power(2, 63) - 1;
1402 tx2[sfDebtMaximum] = dm;
1407 auto const dm =
power(2, 63) - 3;
1409 tx2[sfDebtMaximum] = dm;
1414 auto const dm = 2 * (
power(2, 62) - 1) + 1;
1416 tx2[sfDebtMaximum] = dm;
1420 tx2[sfDebtMaximum] =
Number{9223372036854775807, 0};
1529 using namespace jtx;
1533 auto const token = issuer[
"IOU"];
1543 auto test = [&](TrustState trustState) {
1546 testcase <<
"RIPD-4274 IOU with state: " <<
static_cast<int>(trustState);
1548 auto setTrustLine = [&](
Account const& acct, TrustState state) {
1552 env(trust(issuer, token(0), acct, tfSetfAuth));
1555 auto jv = trust(acct, token(0));
1558 jv[sfQualityIn] = 10'000'000;
1562 case ReachedLimit: {
1563 env(trust(acct, token(1'000)));
1564 env(pay(issuer, acct, token(1'000)));
1569 env(trust(acct, token(1'000)));
1570 env(pay(issuer, acct, token(950)));
1578 BEAST_EXPECT(
false);
1583 env.
fund(
XRP(1'000), issuer, broker, dest);
1586 if (trustState == RequireAuth)
1588 env(
fset(issuer, asfRequireAuth));
1591 setTrustLine(broker, RequireAuth);
1594 setTrustLine(dest, trustState);
1596 env(trust(broker, token(2'000), 0));
1597 env(pay(issuer, broker, token(2'000)));
1600 Vault const vault(env);
1601 auto const [tx, keylet] = vault.create({.owner = broker, .asset = token.asset()});
1606 env(vault.deposit({.depositor = broker, .id = keylet.key, .amount = token(1'000)}));
1609 env(vault.withdraw({.depositor = broker, .id = keylet.key, .amount = token(1'000)}),
1610 loanBroker::destination(dest),
1615 env(vault.withdraw({.depositor = broker, .id = keylet.key, .amount = token(1'000)}));
1618 auto const brokerKeylet = keylet::loanbroker(broker, env.
seq(broker));
1620 env(loanBroker::set(broker, keylet.
key));
1623 env(loanBroker::coverDeposit(broker, brokerKeylet.key, token(1'000)));
1626 env(loanBroker::coverWithdraw(broker, brokerKeylet.key, token(100)),
1627 loanBroker::destination(dest),
1633 if (trustState == RequireAuth)
1635 env(
fclear(issuer, asfRequireAuth));
1638 env(loanBroker::coverWithdraw(broker, brokerKeylet.key, token(100)),
1639 loanBroker::destination(dest),
1656 using namespace jtx;
1667 auto test = [&](MPTState MPTState) {
1670 testcase <<
"RIPD-4274 MPT with state: " <<
static_cast<int>(MPTState);
1672 env.
fund(
XRP(1'000), issuer, broker, dest);
1682 .holders = {broker, dest},
1689 {.account = issuer, .holder = dest, .flags = tfMPTUnauthorize});
1696 .holders = {broker, dest},
1700 BEAST_EXPECT(env.
balance(issuer, tester) == tester(-4'000));
1707 .holders = {broker},
1716 if (!BEAST_EXPECT(maybeToken))
1719 auto const& token = *maybeToken;
1721 Vault const vault(env);
1722 auto const [tx, keylet] = vault.create({.owner = broker, .asset = token.asset()});
1727 env(vault.deposit({.depositor = broker, .id = keylet.key, .amount = token(1'000)}));
1730 env(vault.withdraw({.depositor = broker, .id = keylet.key, .amount = token(1'000)}),
1731 loanBroker::destination(dest),
1736 BEAST_EXPECT(env.
ter() == err);
1742 {.depositor = broker, .id = keylet.key, .amount = token(1'000)}));
1746 auto const brokerKeylet = keylet::loanbroker(broker, env.
seq(broker));
1748 env(loanBroker::set(broker, keylet.
key));
1751 env(loanBroker::coverDeposit(broker, brokerKeylet.key, token(1'000)));
1754 env(loanBroker::coverWithdraw(broker, brokerKeylet.key, token(100)),
1755 loanBroker::destination(dest),
1757 BEAST_EXPECT(env.
ter() == err);