#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include namespace xrpl { /** * View-parameterized wrapper for AccountRoot ledger entries. * * AccountRoot — read-only access to account data * AccountRoot — read-write access, with insert/update/erase * and domain-specific write methods */ template class AccountRoot : public SLEBase { static constexpr bool kIS_WRITABLE = SLEBase::kIS_WRITABLE; AccountID const id_; public: /** Constructor for read-only context */ AccountRoot( AccountID const& id, ReadView const& view, beast::Journal j = beast::Journal{beast::Journal::getNullSink()}) requires(!kIS_WRITABLE) : SLEBase(view.read(keylet::account(id)), view, j), id_(id) { } /** Constructor for writable context */ AccountRoot( AccountID const& id, ApplyView& view, beast::Journal j = beast::Journal{beast::Journal::getNullSink()}) requires kIS_WRITABLE : SLEBase(keylet::account(id), view, j), id_(id) { } /** Converting constructor: writable → read-only. */ template AccountRoot(AccountRoot const& other) requires(!kIS_WRITABLE) : SLEBase(other), id_(other.id()) { } /** Create an AccountRoot backed by a brand-new SLE. */ [[nodiscard]] static AccountRoot makeNew( AccountID const& id, ApplyView& view, beast::Journal j = beast::Journal{beast::Journal::getNullSink()}) requires kIS_WRITABLE { return AccountRoot(id, view, j, std::make_shared(keylet::account(id))); } [[nodiscard]] AccountID const& id() const { return id_; } // --- Read-only domain methods (available on both specializations) --- /** Check if the issuer has the global freeze flag set. @return true if the account has global freeze set */ [[nodiscard]] bool isGlobalFrozen() const; /** Returns IOU issuer transfer fee as Rate. Rate specifies * the fee as fractions of 1 billion. For example, 1% transfer rate * is represented as 1,010,000,000. */ [[nodiscard]] Rate transferRate() const; // Calculate liquid XRP balance for an account. // This function may be used to calculate the amount of XRP that // the holder is able to freely spend. It subtracts reserve requirements. // // ownerCountAdj adjusts the owner count in case the caller calculates // before ledger entries are added or removed. Positive to add, negative // to subtract. // // @param ownerCountAdj positive to add to count, negative to reduce count. [[nodiscard]] XRPAmount xrpLiquid(std::int32_t ownerCountAdj) const; /** Checks the destination and tag. - Checks that the SLE is not null. - If the SLE requires a destination tag, checks that there is a tag. */ [[nodiscard]] TER checkDestinationAndTag(bool hasDestinationTag) const; /** Returns true if and only if sleAcct is a pseudo-account or specific pseudo-accounts in pseudoFieldFilter. Returns false if sleAcct is: - NOT a pseudo-account OR - NOT a ltACCOUNT_ROOT OR - null pointer */ [[nodiscard]] bool isPseudoAccount(std::set const& pseudoFieldFilter = {}) const; [[nodiscard]] bool operator==(AccountRoot const& other) const { return id_ == other.id_; } [[nodiscard]] bool operator==(AccountID const& other) const { return id_ == other; } // --- Write-only domain methods (compile-time gated) --- /** Adjust the owner count up or down. */ void adjustOwnerCount(std::int32_t amount) requires kIS_WRITABLE; private: // Private constructor only used by `makeNew` AccountRoot(AccountID const& id, ApplyView& view, beast::Journal j, std::shared_ptr sle) requires kIS_WRITABLE : SLEBase(std::move(sle), view, j), id_(id) { this->insert(); } }; // CTAD deduction guide — bare AccountRoot(id, view) always deduces read-only. // For writable access, use WAccountRoot(id, applyView) explicitly. AccountRoot(AccountID const&, ReadView const&) -> AccountRoot; AccountRoot(AccountID const&, ReadView const&, beast::Journal) -> AccountRoot; // Backward-compatible aliases using RAccountRoot = AccountRoot; using WAccountRoot = AccountRoot; // Explicit instantiation declarations (definitions in .cpp) extern template class AccountRoot; extern template class AccountRoot; /** Generate a pseudo-account address from a pseudo owner key. @param pseudoOwnerKey The key to generate the address from @return The generated account ID */ [[nodiscard]] AccountID pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey); /** Returns the list of fields that define an ACCOUNT_ROOT as a pseudo-account if set. The list is constructed during initialization and is const after that. Pseudo-account designator fields MUST be maintained by including the SField::sMD_PseudoAccount flag in the SField definition. */ [[nodiscard]] std::vector const& getPseudoAccountFields(); /** * Create pseudo-account, storing pseudoOwnerKey into ownerField. * * The list of valid ownerField is maintained in AccountRootHelpers.cpp and * the caller to this function must perform necessary amendment check(s) * before using a field. The amendment check is **not** performed in * createPseudoAccount. */ [[nodiscard]] Expected, TER> createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const& ownerField); } // namespace xrpl