#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace xrpl { namespace detail { // VFALCO TODO Inline this implementation // into the PaymentSandbox class itself class DeferredCredits { private: using KeyIOU = std::tuple; struct ValueIOU { explicit ValueIOU() = default; STAmount lowAcctDebits; STAmount highAcctDebits; STAmount lowAcctOrigBalance; }; struct HolderValueMPT { HolderValueMPT() = default; // Debit to issuer std::uint64_t debit = 0; std::uint64_t origBalance = 0; }; struct IssuerValueMPT { IssuerValueMPT() = default; std::map holders; // Credit to holder std::uint64_t credit = 0; // OutstandingAmount might overflow when MPTs are credited to a holder. // Consider A1 paying 100MPT to A2 and A1 already having maximum MPTs. // Since the payment engine executes a payment in revers, A2 is // credited first and OutstandingAmount is going to be equal // to MaximumAmount + 100MPT. In the next step A1 redeems 100MPT // to the issuer and OutstandingAmount balances out. std::int64_t origBalance = 0; // Self debit on offer selling MPT. Since the payment engine executes // a payment in reverse, a crediting/buying step may overflow // OutstandingAmount. A sell MPT offer owned by a holder can redeem any // amount up to the offer's amount and holder's available funds, // balancing out OutstandingAmount. But if the offer's owner is issuer // then it issues more MPT. In this case the available amount to issue // is the initial issuer's available amount less all offer sell amounts // by the issuer. This is self-debit, where the offer's owner, // issuer in this case, debits to self. std::uint64_t selfDebit = 0; }; using AdjustmentMPT = IssuerValueMPT; public: struct AdjustmentIOU { AdjustmentIOU(STAmount d, STAmount c, STAmount b) : debits(std::move(d)), credits(std::move(c)), origBalance(std::move(b)) { } STAmount debits; STAmount credits; STAmount origBalance; }; // Get the adjustments for the balance between main and other. // Returns the debits, credits and the original balance [[nodiscard]] std::optional adjustmentsIOU(AccountID const& main, AccountID const& other, Currency const& currency) const; [[nodiscard]] std::optional adjustmentsMPT(MPTID const& mptID) const; void creditIOU( AccountID const& sender, AccountID const& receiver, STAmount const& amount, STAmount const& preCreditSenderBalance); void creditMPT( AccountID const& sender, AccountID const& receiver, STAmount const& amount, std::uint64_t preCreditBalanceHolder, std::int64_t preCreditBalanceIssuer); void issuerSelfDebitMPT(MPTIssue const& issue, std::uint64_t amount, std::int64_t origBalance); void ownerCount(AccountID const& id, OwnerCounts const& cur, OwnerCounts const& next); // Get the adjusted owner count. Since DeferredCredits is meant to be used // in payments, and payments only decrease owner counts, return the max // remembered owner count. [[nodiscard]] std::optional ownerCount(AccountID const& id) const; void apply(DeferredCredits& to); private: static KeyIOU makeKeyIOU(AccountID const& a1, AccountID const& a2, Currency const& currency); std::map creditsIOU_; std::map creditsMPT_; std::map ownerCounts_; }; } // namespace detail //------------------------------------------------------------------------------ /** * A wrapper which makes credits unavailable to balances. * * This is used for payments and pathfinding, so that consuming * liquidity from a path never causes portions of that path or * other paths to gain liquidity. * * The behavior of certain free functions in the ApplyView API * will change via the balanceHook and creditHook overrides * of PaymentSandbox. * * @note Presented as ApplyView to clients */ class PaymentSandbox final : public detail::ApplyViewBase { public: PaymentSandbox() = delete; PaymentSandbox(PaymentSandbox const&) = delete; PaymentSandbox& operator=(PaymentSandbox&&) = delete; PaymentSandbox& operator=(PaymentSandbox const&) = delete; PaymentSandbox(PaymentSandbox&&) = default; PaymentSandbox(ReadView const* base, ApplyFlags flags) : ApplyViewBase(base, flags) { } PaymentSandbox(ApplyView const* base) : ApplyViewBase(base, base->flags()) { } /** * Construct on top of existing PaymentSandbox. * * The changes are pushed to the parent when * apply() is called. * * @param parent A non-null pointer to the parent. * * @note A pointer is used to prevent confusion * with copy construction. */ // VFALCO If we are constructing on top of a PaymentSandbox, // or a PaymentSandbox-derived class, we MUST go through // one of these constructors or invariants will be broken. /** @{ */ explicit PaymentSandbox(PaymentSandbox const* base) : ApplyViewBase(base, base->flags()), ps_(base) { } explicit PaymentSandbox(PaymentSandbox* base) : ApplyViewBase(base, base->flags()), ps_(base) { } /** @} */ [[nodiscard]] STAmount balanceHookIOU(AccountID const& account, AccountID const& issuer, STAmount const& amount) const override; [[nodiscard]] STAmount balanceHookMPT(AccountID const& account, MPTIssue const& issue, std::int64_t amount) const override; [[nodiscard]] STAmount balanceHookSelfIssueMPT(MPTIssue const& issue, std::int64_t amount) const override; void creditHookIOU( AccountID const& from, AccountID const& to, STAmount const& amount, STAmount const& preCreditBalance) override; void creditHookMPT( AccountID const& from, AccountID const& to, STAmount const& amount, std::uint64_t preCreditBalanceHolder, std::int64_t preCreditBalanceIssuer) override; void issuerSelfDebitHookMPT(MPTIssue const& issue, std::uint64_t amount, std::int64_t origBalance) override; void adjustOwnerCountHook(AccountID const& account, OwnerCounts const& cur, OwnerCounts const& next) override; [[nodiscard]] OwnerCounts ownerCountHook(AccountID const& account, OwnerCounts const& count) const override; /** * Apply changes to base view. * * `to` must contain contents identical to the parent * view passed upon construction, else undefined * behavior will result. */ /** @{ */ void apply(RawView& to); void apply(PaymentSandbox& to); /** @} */ [[nodiscard]] XRPAmount xrpDestroyed() const; private: detail::DeferredCredits tab_; PaymentSandbox const* ps_ = nullptr; }; } // namespace xrpl