diff --git a/contracts/Pool.sol b/contracts/Pool.sol index 32968159..4dcc26d1 100644 --- a/contracts/Pool.sol +++ b/contracts/Pool.sol @@ -251,6 +251,8 @@ contract Pool is IPool, ERC20Upgradeable, BeaconImplementation { onlyPoolController onlyCrankedPool { + require(!_fundedLoans[addr], "Pool: already funded"); + _fundedLoans[addr] = true; ILoan loan = ILoan(addr); uint256 principal = loan.principal(); @@ -260,7 +262,6 @@ contract Pool is IPool, ERC20Upgradeable, BeaconImplementation { loan.fund(); _accountings.outstandingLoanPrincipals += principal; - _fundedLoans[addr] = true; emit LoanFunded(addr, principal); } diff --git a/test/controllers/PoolController.test.ts b/test/controllers/PoolController.test.ts index 1b52113c..25f01deb 100644 --- a/test/controllers/PoolController.test.ts +++ b/test/controllers/PoolController.test.ts @@ -969,6 +969,35 @@ describe("PoolController", () => { poolController.connect(otherAccount).fundLoan(otherAccount.address) ).to.be.revertedWith("Pool: caller is not admin"); }); + + it("reverts if trying to fund the same loan again", async () => { + const { + pool, + liquidityAsset, + otherAccount, + borrower, + poolAdmin, + loan, + poolController + } = await loadFixture(loadPoolFixture); + + await activatePool(pool, poolAdmin, liquidityAsset); + await collateralizeLoan(loan, borrower, liquidityAsset); + await depositToPool( + pool, + otherAccount, + liquidityAsset, + DEFAULT_LOAN_SETTINGS.principal * 3 + ); + + // fund loan 1 time + await fundLoan(loan, poolController, poolAdmin); + + // Try again, even though there's technically enough money to cover the loan + await expect( + poolController.connect(poolAdmin).fundLoan(loan.address) + ).to.be.revertedWith("Pool: already funded"); + }); }); describe("defaultLoan()", () => {