Severity: Critical
The flash loan function transfers tokens to the borrower but does not verify repayment before returning. An attacker can borrow the entire pool and never repay, draining the contract.
- Attacker calls
flash_loan(attacker, pool_balance). - Contract transfers tokens to attacker.
- Attacker does not repay; contract returns without checking the balance was restored.
- Attacker keeps the tokens.
pub fn flash_loan(env: Env, borrower: Address, amount: i128) {
transfer_out(&env, &borrower, amount);
// ❌ Missing repayment check
}pub fn flash_loan(env: Env, borrower: Address, amount: i128) {
let balance_before = get_pool_balance(&env);
transfer_out(&env, &borrower, amount);
// borrower executes their logic here (via callback or same tx)
let balance_after = get_pool_balance(&env);
assert!(balance_after >= balance_before, "flash loan not repaid"); // ✅
}See the inline secure.rs module inside this crate for the full corrected implementation.