Area
Investment Vault / Security
Complexity
Medium-hard
File(s)
investment_vault/src/lib.rs:1451-1482 (specifically line 1478); tests at investment_vault/src/test.rs:2627-2729
Problem
After client.flash_loan_callback(...) returns, the vault calls Base::transfer(&env, &borrower, &MuxedAddress::from(&vault), amount + fee). Base::transfer calls from.require_auth() on borrower — but borrower is a contract address whose authorization window was tied to its own flash_loan_callback invocation, which has already returned by this point. A contract cannot pre-authorize a debit the vault initiates against it after the fact unless it implements a custom account/auth contract. All existing flash-loan tests pass only because env.mock_all_auths() is set globally, masking that this would fail real signature verification on any live network.
Scope
In:
- Redesign so the borrower repays by calling into the vault/transfer from within its own callback frame (the standard flash-loan repayment pattern), rather than the vault debiting the borrower afterward.
Out:
Acceptance Criteria
Area
Investment Vault / Security
Complexity
Medium-hard
File(s)
investment_vault/src/lib.rs:1451-1482 (specifically line 1478); tests at investment_vault/src/test.rs:2627-2729
Problem
After
client.flash_loan_callback(...)returns, the vault callsBase::transfer(&env, &borrower, &MuxedAddress::from(&vault), amount + fee).Base::transfercallsfrom.require_auth()onborrower— butborroweris a contract address whose authorization window was tied to its ownflash_loan_callbackinvocation, which has already returned by this point. A contract cannot pre-authorize a debit the vault initiates against it after the fact unless it implements a custom account/auth contract. All existing flash-loan tests pass only becauseenv.mock_all_auths()is set globally, masking that this would fail real signature verification on any live network.Scope
In:
Out:
Acceptance Criteria