Frozen IOUs should still be transferable to/from the issuer - #6113
Frozen IOUs should still be transferable to/from the issuer#6113vlntb wants to merge 641 commits into
Conversation
- Move management fee calculations out of transactors an into the appropriate functions in LendingHelpers.h. - Rewrite how overpayments are handled. May changed based on numerical analysis. - Update, fix, and clean up unit tests. Includes adding tolerances for some checks where an exact match is unlikely. - Add "integral()" function to Asset to simplify a common check.
…5904) * Add unit-test to verify correct behavior on broker deep freeze
- Uses the same name and value as for LoanSet: tfLoanOverpayment. - Untested. - Also create several placeholders for missing test cases.
* XRPLF/develop: Moved fix1513 to retire state (5919)
- Loan scale is completely irrelevant to integral types (XRP, MPT), and the field is "soeDEFAULT", so when set to 0, it won't be stored on ledger, saving a little bit of space.
- Implement a new helper accountCanSend, which is like accountHolds, but returns a meaningful value for issuers, and will include the available credit on the other side of a trust line. (The sfHighLimit or sfLowLimit as appropriate.) - Use this new helper when checking the available balance in LoanPay.
* XRPLF/develop:
refactor: Retire fix1515 amendment (5920)
Use "${ENVVAR}" instead of ${{ env.ENVVAR }} syntax in GitHub Actions (5923)
- Add convenience functions to MPT test-framework.
- Fix LoanSet.calculateBaseFee with multisign.
- Cleanups.
- Add View helper functions for Loan and Vault transactions
- preflightDestinationAndTag
- checkDestinationAndTag
- canSendToAccount
- Used the helpers in appropriate Loan and Vault transactions.
- They could also be used in older transactions, I'll save that for
later.
- Correct interest rounding calculation - Fix some comments - Don't explicitly break out of the multiple payment loop for the final payment. Assert that it will exit by the loop condition.
- canSendToAccount will check if a destination tag is required _before_ checking if the sender is the destination. This is the original VaultWithdraw behavior, and I want to stay consistent.
…nez/lending-XLS-66 * mywork/ximinez/crashed-tests: test: Count crashed test suites
- Renamed canSendToAccount to canWithdraw, because the semantics are a little different from a payment. Notably, if withdrawing to self, you can still include a destination tag. - Simplified the interface to canWithdraw to just pass in the STTx. - preflightDestinationAndTag is pretty pointless now, so removed it.
- Adds a check to the MPToken creation invariant to ensure none are created for the issuer. - `addEmptyHolding()` will return success without doing anything for these scenarios. There is nothing to do, as with XRP. --------- Co-authored-by: Ed Hennis <ed@ripple.com>
- This is an intermediate commit. It leaves the old variables in place, so I can do verifications that the new computations are correct. They will be removed in the next commit. - PaymentComponents is an class used internally to break a payment value into principal, interest, and fees.
* Replace accountHolds with accountSpendable when checking for account funds in VaultDeposit and LoanBrokerCoverDeposit
- Updates or fixes a couple of things I noticed while reviewing changes to the spec. - Rename sfPreviousPaymentDate to sfPreviousPaymentDueDate. - Make the vault asset cap check added in #6124 a little more robust: 1. Check in preflight if the vault is _already_ over the limit. 2. Prevent overflow when checking with the loan value. (Subtract instead of adding, in case the values are near maxint. Both return the same result. Also add a unit test so each case is covered.
ximinez
left a comment
There was a problem hiding this comment.
There are a bunch of unit test failures
| coverDeposit(holder, brokerKeylet.key, USD(10)), | ||
| ter(tecFROZEN)); | ||
|
|
||
| env_post(coverDeposit(issuer, brokerKeylet.key, USD(20))); |
There was a problem hiding this comment.
This doesn't look right. Only the broker owner (owner) should be able to deposit cover. Not because of the freeze, but because of the LP rules. The CI results confirm that - there are many unit test failures.
| // Verify issuer can still receive payments (uses isFrozen internally) | ||
| env(pay(holder, issuer, USD(10))); | ||
| env.close(); | ||
|
|
There was a problem hiding this comment.
Should also verify that the issuer can still send payments.
// Verify issuer can still send payments (uses isFrozen internally) env(pay(issuer, holder, USD(10))); env.close();
I see a lot of changes where the loan broker deposits and withdraws, but I would like to see a simple payment from the issuer here in testIsFrozenDirectly
| void | ||
| testIsFrozenDirectly(FeatureBitset features) |
There was a problem hiding this comment.
should these tests be part of testGlobalFreeze in this same file?
Also, I wonder why those tests did not catch this obvious fault?
| // Check global freeze for IOU payments where sender is the issuer. | ||
| // This is NOT Lending Protocol/Vault specific, so issuers do NOT get | ||
| // exemption from their own global freeze for regular Payment transactions. | ||
| // IMPORTANT: This restriction only applies when featureLendingProtocol is | ||
| // enabled. Before this amendment, issuers were allowed to send under global | ||
| // freeze. | ||
| if (ctx.view.rules().enabled(featureLendingProtocol)) | ||
| { | ||
| STAmount const maxSourceAmount = | ||
| getMaxSourceAmount(ctx.tx[sfAccount], dstAmount, sendMax); | ||
| if (!maxSourceAmount.native() && !maxSourceAmount.holds<MPTIssue>()) | ||
| { | ||
| auto const& issue = maxSourceAmount.get<Issue>(); | ||
| auto const& account = ctx.tx[sfAccount]; | ||
|
|
||
| // If sender is the issuer and global freeze is enabled, payment | ||
| // fails | ||
| if (account == issue.getIssuer() && isGlobalFrozen(ctx.view, issue)) | ||
| return tecPATH_DRY; | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
why? isn't the issuer always allowed to transfer their own asset regardless if the asset is frozen or not?
| asset.value()); | ||
| } | ||
|
|
||
| /** Lending Protocol-specific freeze check with issuer exemption. |
There was a problem hiding this comment.
i'm not sure about these lending specific freeze rules. What's the rationale for this approach compared to the old one, where we added the check directly in the existing freeze checking helper (this seemed to be more elegant and simpler).
also, IIRC, freeze check should always exempt the issuer, not just for lending. so is having lending specific freeze-helpers really necessary?
ximinez
left a comment
There was a problem hiding this comment.
There's no diplomatic way to say this. The changes since my last review
(8011c43..4c8d9b5) are almost entirely the wrong way to go about this.
An not-necessarily-exhaustive list of the problems:
- None of the new functions in
View.h/cppshould have been added.- Refer to
https://xrpl.org/docs/concepts/tokens/fungible-tokens/freezes. We
should not be changing any of those rules for either existing or
new transactions. It's also true for pseudo-accounts - even though
they are not acting on their own, they are still sending directly
to or from the issuer if the issuer is the one acting via
aVaultDeposit, orLoanBrokerCoverWithdraw, etc. - Instead, the existing corresponding functions should be modified to
include changes if the SAV or LP amendments are enabled. They
should not be rewritten, but only add the parameters and checks
needed to determine if either sender or receiver is the issuer. - Modifying the existing functions is not changing the rules - it's
centralizing them.
- Refer to
- I don't think any of the Invariant changes are correct either. We're
not changing the existing freeze rules. Specifically, I don't think
pseudo-accounts should be treated any differently as far as freezes
are concerned. - In
LoanBrokerCoverDeposit:- I don't understand why you moved the
account != sleBroker->at(sfOwner)check to later in the function.
If the account doesn't have permission, we shouldn't waste time
reading the Vault object before returning. - The change from
checkFrozentoisIndividualFrozenskips the
global freeze check, which is only correct if the account is the
issuer. If you make the changes above, then it will automatically
do the right thing. - It's probably correct to change the
accountSpendablecall to
ignore freeze, because with the changes above, any real freezes
will be caught before we get to that point.
- I don't understand why you moved the
- In
LoanBrokerCoverWithdraw:- Again, moving the
account != sleBroker->at(sfOwner)check doesn't
make sense. - If the
dstAcctis not the issuer, then you should absolutely be
checking if the pseudoaccount is frozen. It should not be able to
send funds to anyone except the issuer. - Again, it's probably correct to change the
accountSpendablecall to
ignore freeze, because with the changes above, any freezes that
should cause failure will be caught before we get to that point.
- Again, moving the
LoanSetis fine. It's just part of the project rename.- There is no reason to make any changes to the
Paymenttransaction,
particularly one that takes existing, correct, functionality away
from the issuer. VaultClawbacklooks fine.VaultDepositandVaultWithdrawshould go back to using the
correctedisFrozen(or converted tocheckFrozen). But I am
a little confused why you would need to check if the shares of the
vault (vaultShare) are frozen, because they are issued by the
pseudoaccount, which can't change the MPTIssuance, and I don't think
there's any other mechanism to do that, is there?- Though with the updated
isFrozen/checkFrozen,VaultWithdraw
won't need to check if either account is the issuer.
- Though with the updated
c6fcce0 to
b314566
Compare
|
This PR has conflicts, please resolve them in order for the PR to be reviewed. |
|
We recently merged a refactor to One-time setupIf you don't already have clang-tidy working in your env, on macOS: brew install llvm@21
# Follow brew's hint to put $(brew --prefix llvm@21)/bin on PATH so run-clang-tidy is found.Workflow on your branch (before merging develop)1. Grab the new git remote -v # should show 'upstream' among others; if not:
# git remote set-url upstream git@github.com:XRPLF/rippled.git
git fetch upstream
git checkout upstream/develop -- .clang-tidy2. Reconfigure conan/cmake so 3. Apply renames for the files modified in your PR: git diff --name-only $(git merge-base HEAD upstream/develop) HEAD \
| grep -E '\.(cpp|h|hpp|ipp)$' \
| xargs run-clang-tidy -p build -fix -allow-no-checks
# or -p .build, or whatever your build dir is called4. Build + test, then commit as a single dedicated commit: cmake --build build -j8
git commit -am "refactor: Align identifier naming with develop"5. Now merge develop: git merge upstream/developExtraRun clang-tidy once more after the merge to catch any stragglers introduced from develop's side: run-clang-tidy -p build -fix -allow-no-checks src tests
# or -p .build, or whatever your build dir is called |
High Level Overview of Change
The freeze logic was incorrectly blocking IOU issuers from transacting with their own frozen currency. This violated the XRP Ledger protocol, which specifies that "Counterparties of the frozen issuer can still send and receive payments directly to and from the issuing address."
Context of Change
Three issues were fixed:
isFrozen()function was returning true for issuers checking their own currency during global freeze, causing the issuer to be treated as frozen. The early return prevented reaching the later issuer exemption check.LoanBrokerCoverDeposit::preclaim()was using accountHolds() with FreezeHandling::fhZERO_IF_FROZEN for all accounts, including issuers. Since issuers don't have a "balance" of their own tokens (infinite issuance ability), the balance check would return 0 and fail with tecINSUFFICIENT_FUNDS.VaultWithdraw::preclaim()had checkFrozen() calls that were always executed, even when the destination or submitter was the asset issuer. Now skips freeze checks when either the destination or submitter is the IOU issuer.Type of Change
.gitignore, formatting, dropping support for older tooling)API Impact
libxrplchange (any change that may affectlibxrplor dependents oflibxrpl)