A pseudo-account that holds vault shares but not the underlying asset fails
requireAuth's recursive share->underlying check, which left an AMM unable to
read its own vault-share balance (read as zero via accountHolds) and blocked
the MPToken transfer invariant on AMM create.
Exempt pseudo-accounts before the recursive check in requireAuth, gated by
fixCleanup3_3_0 to preserve pre-amendment consensus, and treat them as
authorized in the MPToken transfer invariant (fork-safe: that invariant is
enforced only under MPTokensV2). Create and withdraw of AMM-held vault shares
now succeed once fixCleanup3_3_0 is enabled.
Add AMM/vault-share coverage and side-specific AMM_WITHDRAW freeze invariant
tests, and correct the pre-amendment test expectations: pre-fixCleanup3_3_0
the shares remain inaccessible to the pseudo-account, so the withdraw fails
with tecAMM_FAILED.
- Move amendmentCombinations algorithm to jtx::amendmentCombinations in
test/jtx/utility.h+cpp; it was copy-pasted into both AMM_test and
AMMMPT_test. AMM_test retains a one-liner wrapper that seeds from its
local testableAmendments() (strips SAV/Lending).
- Document the isVaultPseudoAccountFrozen sub-step in the Doxygen for
checkWithdrawFreeze and checkDepositFreeze; the MPT-only transitive
freeze check occurs between the listed steps 1 and 2 in each function.
- Expand the IgnoreFreeze comment in VaultWithdraw::doApply to explain
why preclaim validation makes the flag safe to use post-fix330.
Adds testAMMWithVaultShares to AMMMPT_test verifying that underlying-asset
freeze propagates to vault shares in AMM deposit/withdraw, pre- and
post-fixCleanup3_3_0.
Prerequisite fixes that unblocked the test:
- MPTokenHelpers: move pseudo-account exemption before the recursive
vault-underlying check in requireAuth so AMM pseudo-accounts are not
rejected when holding vault shares whose underlying needs auth.
- MPTInvariant: gate isVaultPseudoAccountFrozen on fixCleanup3_3_0;
pre-amendment AMM withdrawals of vault shares are permitted even when
the underlying is individually frozen.
- TokenHelpers: remove dead checkIndividualDeepFrozen and forward decl
for isLPTokenFrozen (both unused after earlier refactor).
Add a test to testMPT() in Invariants_test.cpp that verifies the
ValidMPTTransfer invariant correctly gates isVaultPseudoAccountFrozen
on fixCleanup3_3_0.
The test creates an IOU vault whose shares are held by two accounts,
then freezes the underlying IOU for one account (a1). It simulates a
vault-share transfer by directly modifying the MPToken SLEs:
- post-fixCleanup3_3_0: isVaultPseudoAccountFrozen finds a1's underlying
IOU frozen → invalidTransfer → "invalid MPToken transfer between
holders" → tecINVARIANT_FAILED.
- pre-fixCleanup3_3_0: the vault-underlying check is not called;
the transfer is allowed even though the underlying IOU is frozen
→ tesSUCCESS.
Restore unconditional IgnoreFreeze in VaultWithdraw::doApply when
fixCleanup3_3_0 is enabled. That accountHolds reads the submitter's
share balance, which recurses into the underlying asset, so freeze
gating must stay in preclaim; a dstAcct==issuer guard there wrongly
blocked self-withdrawal under a regular freeze.
Apply issuer-aware freeze handling to LoanBrokerCoverWithdraw::preclaim
so the issuer can redeem their own token from the broker pseudo-account
even under a global freeze, matching AMM and Vault. Here accountHolds
reads the pseudo-account's holdings, so the issuer-only IgnoreFreeze is
both necessary and sufficient.
Rename the checkWithdrawFreeze source parameter to srcAcct to match its
definition, drop a misleading comment, and hoist the fixCleanup feature
flags into named locals.
Migrate AMMDeposit and AMMWithdraw to use the unified freeze helpers
introduced for Vault and LoanBroker, gated on fixCleanup3_3_0.
AMMDeposit: checkDepositFreeze for both pool assets replaces the
two-layer checkAsset + checkAmount freeze logic. If either pool asset
is frozen (depositor or AMM account), all deposits are blocked.
AMMWithdraw: checkWithdrawFreeze per withdrawn amount replaces
checkFrozen(AMM) + checkIndividualFrozen(user). Regular IOU freeze
no longer blocks self-withdrawal; only deep freeze does. The issuer
exemption allows the token issuer to withdraw from a frozen pool;
issuerFreezeHandling() ensures doApply uses IgnoreFreeze so pool
math does not divide by zero.
Rename checkWithdrawFreezes -> checkWithdrawFreeze (singular) and
update all callers. Document both helpers with full freeze semantics.
Extract all IOU freeze and MPT lock tests from testWithIOU and
testWithMPT into two focused test functions covering VaultDeposit
and VaultWithdraw respectively.
Each function tests both IOU (global, depositor regular/deep,
vault-account regular/deep) and MPT (global lock, depositor lock,
vault-account lock) for both pre- and post-fixCleanup3_3_0, plus
clawback-while-frozen assertions.