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.