143 bool const enforce = view.
rules().
enabled(featureSingleAssetVault);
153 "Invariant failed: vault operation succeeded without modifying "
155 XRPL_ASSERT(enforce,
"xrpl::ValidVault::finalize : vault noop invariant");
164 "Invariant failed: vault updated by a wrong transaction type";
167 "xrpl::ValidVault::finalize : illegal vault transaction "
175 "Invariant failed: vault operation updated more than single vault";
176 XRPL_ASSERT(enforce,
"xrpl::ValidVault::finalize : single vault invariant");
186 if (txnType != ttVAULT_DELETE)
189 "Invariant failed: vault deleted by a wrong transaction type";
192 "xrpl::ValidVault::finalize : illegal vault deletion "
207 if (e.share.getMptID() == beforeVault.shareMPTID)
215 JLOG(j.
fatal()) <<
"Invariant failed: deleted vault must also "
217 XRPL_ASSERT(enforce,
"xrpl::ValidVault::finalize : shares deletion invariant");
222 if (deletedShares->sharesTotal != 0)
224 JLOG(j.
fatal()) <<
"Invariant failed: deleted vault must have no "
225 "shares outstanding";
228 if (beforeVault.assetsTotal !=
zero)
230 JLOG(j.
fatal()) <<
"Invariant failed: deleted vault must have no "
231 "assets outstanding";
234 if (beforeVault.assetsAvailable !=
zero)
236 JLOG(j.
fatal()) <<
"Invariant failed: deleted vault must have no "
243 if (txnType == ttVAULT_DELETE)
245 JLOG(j.
fatal()) <<
"Invariant failed: vault deletion succeeded without "
247 XRPL_ASSERT(enforce,
"xrpl::ValidVault::finalize : vault deletion invariant");
255 "xrpl::ValidVault::finalize : single vault operation");
265 if (e.share.getMptID() == afterVault.shareMPTID)
280 if (afterVault.asset != beforeVault.asset || afterVault.pseudoId != beforeVault.pseudoId ||
281 afterVault.shareMPTID != beforeVault.shareMPTID)
283 JLOG(j.
fatal()) <<
"Invariant failed: violation of vault immutable data";
290 JLOG(j.
fatal()) <<
"Invariant failed: updated vault must have shares";
291 XRPL_ASSERT(enforce,
"xrpl::ValidVault::finalize : vault has shares invariant");
295 if (updatedShares->sharesTotal == 0)
297 if (afterVault.assetsTotal !=
zero)
299 JLOG(j.
fatal()) <<
"Invariant failed: updated zero sized "
300 "vault must have no assets outstanding";
303 if (afterVault.assetsAvailable !=
zero)
305 JLOG(j.
fatal()) <<
"Invariant failed: updated zero sized "
306 "vault must have no assets available";
310 else if (updatedShares->sharesTotal > updatedShares->sharesMaximum)
313 <<
"Invariant failed: updated shares must not exceed maximum "
314 << updatedShares->sharesMaximum;
318 if (afterVault.assetsAvailable <
zero)
320 JLOG(j.
fatal()) <<
"Invariant failed: assets available must be positive";
324 if (afterVault.assetsAvailable > afterVault.assetsTotal)
326 JLOG(j.
fatal()) <<
"Invariant failed: assets available must "
327 "not be greater than assets outstanding";
330 else if (afterVault.lossUnrealized > afterVault.assetsTotal - afterVault.assetsAvailable)
333 <<
"Invariant failed: loss unrealized must not exceed "
334 "the difference between assets outstanding and available";
338 if (afterVault.assetsTotal <
zero)
340 JLOG(j.
fatal()) <<
"Invariant failed: assets outstanding must be positive";
344 if (afterVault.assetsMaximum <
zero)
346 JLOG(j.
fatal()) <<
"Invariant failed: assets maximum must be positive";
355 "Invariant failed: vault created by a wrong transaction type";
356 XRPL_ASSERT(enforce,
"xrpl::ValidVault::finalize : vault creation invariant");
361 txnType != ttLOAN_MANAGE && txnType != ttLOAN_PAY)
364 "Invariant failed: vault transaction must not change loss "
376 if (e.share.getMptID() == beforeVault.shareMPTID)
387 JLOG(j.
fatal()) <<
"Invariant failed: vault operation succeeded "
388 "without updating shares";
389 XRPL_ASSERT(enforce,
"xrpl::ValidVault::finalize : shares noop invariant");
393 auto const& vaultAsset = afterVault.asset;
400 return it->second *
sign;
404 [&]<
typename TIss>(TIss
const& issue) {
420 auto ret = deltaAssets(tx[sfAccount]);
422 if (!ret.has_value() || !vaultAsset.native())
426 if (
auto const delegate = tx[~sfDelegate];
427 delegate.has_value() && *delegate != tx[sfAccount])
437 auto const it = [&]() {
438 if (
id == afterVault.pseudoId)
446 auto const vaultHoldsNoAssets = [&](
Vault const& vault) {
447 return vault.assetsAvailable == 0 && vault.assetsTotal == 0;
457 case ttVAULT_CREATE: {
463 <<
"Invariant failed: create operation must not have "
468 if (afterVault.assetsAvailable !=
zero || afterVault.assetsTotal !=
zero ||
469 afterVault.lossUnrealized !=
zero || updatedShares->sharesTotal != 0)
472 <<
"Invariant failed: created vault must be empty";
476 if (afterVault.pseudoId != updatedShares->share.getIssuer())
479 <<
"Invariant failed: shares issuer and vault "
480 "pseudo-account must be the same";
484 auto const sleSharesIssuer =
486 if (!sleSharesIssuer)
489 <<
"Invariant failed: shares issuer must exist";
496 <<
"Invariant failed: shares issuer must be a "
501 if (
auto const vaultId = (*sleSharesIssuer)[~sfVaultID];
502 !vaultId || *vaultId != afterVault.key)
505 <<
"Invariant failed: shares issuer pseudo-account "
506 "must point back to the vault";
516 !
beforeVault_.empty(),
"xrpl::ValidVault::finalize : set updated a vault");
519 auto const vaultDeltaAssets = deltaAssets(afterVault.pseudoId);
520 if (vaultDeltaAssets)
523 "Invariant failed: set must not change vault balance";
527 if (beforeVault.assetsTotal != afterVault.assetsTotal)
530 "Invariant failed: set must not change assets "
535 if (afterVault.assetsMaximum >
zero &&
536 afterVault.assetsTotal > afterVault.assetsMaximum)
539 "Invariant failed: set assets outstanding must not "
540 "exceed assets maximum";
544 if (beforeVault.assetsAvailable != afterVault.assetsAvailable)
547 "Invariant failed: set must not change assets "
552 if (beforeShares && updatedShares &&
553 beforeShares->sharesTotal != updatedShares->sharesTotal)
556 "Invariant failed: set must not change shares "
563 case ttVAULT_DEPOSIT: {
567 !
beforeVault_.empty(),
"xrpl::ValidVault::finalize : deposit updated a vault");
570 auto const vaultDeltaAssets = deltaAssets(afterVault.pseudoId);
572 if (!vaultDeltaAssets)
575 "Invariant failed: deposit must change vault balance";
579 if (*vaultDeltaAssets > tx[sfAmount])
582 "Invariant failed: deposit must not change vault "
583 "balance by more than deposited amount";
587 if (*vaultDeltaAssets <=
zero)
590 "Invariant failed: deposit must increase vault balance";
596 bool const issuerDeposit = [&]() ->
bool {
597 if (vaultAsset.native())
599 return tx[sfAccount] == vaultAsset.getIssuer();
604 auto const accountDeltaAssets = deltaAssetsTxAccount();
605 if (!accountDeltaAssets)
608 "Invariant failed: deposit must change depositor "
613 if (*accountDeltaAssets >=
zero)
616 "Invariant failed: deposit must decrease depositor "
621 if (*accountDeltaAssets * -1 != *vaultDeltaAssets)
624 "Invariant failed: deposit must change vault and "
625 "depositor balance by equal amount";
630 if (afterVault.assetsMaximum >
zero &&
631 afterVault.assetsTotal > afterVault.assetsMaximum)
634 "Invariant failed: deposit assets outstanding must not "
635 "exceed assets maximum";
639 auto const accountDeltaShares = deltaShares(tx[sfAccount]);
640 if (!accountDeltaShares)
643 "Invariant failed: deposit must change depositor "
648 if (*accountDeltaShares <=
zero)
651 "Invariant failed: deposit must increase depositor "
656 auto const vaultDeltaShares = deltaShares(afterVault.pseudoId);
657 if (!vaultDeltaShares || *vaultDeltaShares ==
zero)
660 "Invariant failed: deposit must change vault shares";
664 if (*vaultDeltaShares * -1 != *accountDeltaShares)
667 "Invariant failed: deposit must change depositor and "
668 "vault shares by equal amount";
672 if (beforeVault.assetsTotal + *vaultDeltaAssets != afterVault.assetsTotal)
674 JLOG(j.
fatal()) <<
"Invariant failed: deposit and assets "
675 "outstanding must add up";
678 if (beforeVault.assetsAvailable + *vaultDeltaAssets != afterVault.assetsAvailable)
680 JLOG(j.
fatal()) <<
"Invariant failed: deposit and assets "
681 "available must add up";
687 case ttVAULT_WITHDRAW: {
692 "xrpl::ValidVault::finalize : withdrawal updated a "
696 auto const vaultDeltaAssets = deltaAssets(afterVault.pseudoId);
698 if (!vaultDeltaAssets)
700 JLOG(j.
fatal()) <<
"Invariant failed: withdrawal must "
701 "change vault balance";
705 if (*vaultDeltaAssets >=
zero)
707 JLOG(j.
fatal()) <<
"Invariant failed: withdrawal must "
708 "decrease vault balance";
714 bool const issuerWithdrawal = [&]() ->
bool {
715 if (vaultAsset.native())
717 auto const destination = tx[~sfDestination].value_or(tx[sfAccount]);
718 return destination == vaultAsset.getIssuer();
721 if (!issuerWithdrawal)
723 auto const accountDeltaAssets = deltaAssetsTxAccount();
725 if (
auto const destination = tx[~sfDestination];
726 destination && *destination != tx[sfAccount])
727 return deltaAssets(*destination);
731 if (accountDeltaAssets.has_value() == otherAccountDelta.has_value())
734 "Invariant failed: withdrawal must change one "
735 "destination balance";
739 auto const destinationDelta =
740 accountDeltaAssets ? *accountDeltaAssets : *otherAccountDelta;
742 if (destinationDelta <=
zero)
745 "Invariant failed: withdrawal must increase "
746 "destination balance";
750 if (*vaultDeltaAssets * -1 != destinationDelta)
753 "Invariant failed: withdrawal must change vault "
754 "and destination balance by equal amount";
759 auto const accountDeltaShares = deltaShares(tx[sfAccount]);
760 if (!accountDeltaShares)
763 "Invariant failed: withdrawal must change depositor "
768 if (*accountDeltaShares >=
zero)
771 "Invariant failed: withdrawal must decrease depositor "
776 auto const vaultDeltaShares = deltaShares(afterVault.pseudoId);
777 if (!vaultDeltaShares || *vaultDeltaShares ==
zero)
780 "Invariant failed: withdrawal must change vault shares";
784 if (*vaultDeltaShares * -1 != *accountDeltaShares)
787 "Invariant failed: withdrawal must change depositor "
788 "and vault shares by equal amount";
793 if (beforeVault.assetsTotal + *vaultDeltaAssets != afterVault.assetsTotal)
795 JLOG(j.
fatal()) <<
"Invariant failed: withdrawal and "
796 "assets outstanding must add up";
800 if (beforeVault.assetsAvailable + *vaultDeltaAssets != afterVault.assetsAvailable)
802 JLOG(j.
fatal()) <<
"Invariant failed: withdrawal and "
803 "assets available must add up";
809 case ttVAULT_CLAWBACK: {
813 !
beforeVault_.empty(),
"xrpl::ValidVault::finalize : clawback updated a vault");
816 if (vaultAsset.native() || vaultAsset.getIssuer() != tx[sfAccount])
820 if (!(beforeShares && beforeShares->sharesTotal > 0 &&
821 vaultHoldsNoAssets(beforeVault) && beforeVault.owner == tx[sfAccount]))
824 "Invariant failed: clawback may only be performed "
825 "by the asset issuer, or by the vault owner of an "
831 auto const vaultDeltaAssets = deltaAssets(afterVault.pseudoId);
832 if (vaultDeltaAssets)
834 if (*vaultDeltaAssets >=
zero)
837 "Invariant failed: clawback must decrease vault "
842 if (beforeVault.assetsTotal + *vaultDeltaAssets != afterVault.assetsTotal)
845 "Invariant failed: clawback and assets outstanding "
850 if (beforeVault.assetsAvailable + *vaultDeltaAssets !=
851 afterVault.assetsAvailable)
854 "Invariant failed: clawback and assets available "
859 else if (!vaultHoldsNoAssets(beforeVault))
862 "Invariant failed: clawback must change vault balance";
866 auto const accountDeltaShares = deltaShares(tx[sfHolder]);
867 if (!accountDeltaShares)
870 "Invariant failed: clawback must change holder shares";
874 if (*accountDeltaShares >=
zero)
877 "Invariant failed: clawback must decrease holder "
882 auto const vaultDeltaShares = deltaShares(afterVault.pseudoId);
883 if (!vaultDeltaShares || *vaultDeltaShares ==
zero)
886 "Invariant failed: clawback must change vault shares";
890 if (*vaultDeltaShares * -1 != *accountDeltaShares)
893 "Invariant failed: clawback must change holder and "
894 "vault shares by equal amount";
910 UNREACHABLE(
"xrpl::ValidVault::finalize : unknown transaction type");
920 XRPL_ASSERT(enforce,
"xrpl::ValidVault::finalize : vault invariants");
uint256 const & key() const
Returns the 'key' (or 'index') of this item.