Skip to content

Commit

Permalink
feat: disable flash loan when nft in auction (#114)
Browse files Browse the repository at this point in the history
* disable flash loan when nft in auction

* deploy new pool loan impl on goerli

* deploy new pool loan impl on mainnet
  • Loading branch information
thorseldon committed Jul 11, 2023
1 parent a027918 commit 8a0eb21
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 15 deletions.
23 changes: 20 additions & 3 deletions contracts/protocol/LendPoolLoan.sol
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ contract LendPoolLoan is Initializable, ILendPoolLoan, ContextUpgradeable, IERC7
loan.state = DataTypes.LoanState.Auction;
loan.bidStartTimestamp = block.timestamp;
loan.firstBidderAddress = onBehalfOf;

_setFlashLoanLocking(loan.nftAsset, loan.nftTokenId, address(this), true);
} else {
require(loan.state == DataTypes.LoanState.Auction, Errors.LPL_INVALID_LOAN_STATE);

Expand Down Expand Up @@ -285,6 +287,9 @@ contract LendPoolLoan is Initializable, ILendPoolLoan, ContextUpgradeable, IERC7
loan.bidPrice = 0;
loan.firstBidderAddress = address(0);

// clear flash loan lock when exit auction
_setFlashLoanLocking(loan.nftAsset, loan.nftTokenId, address(this), false);

emit LoanRedeemed(initiator, loanId, loan.nftAsset, loan.nftTokenId, loan.reserveAsset, amountTaken, borrowIndex);
}

Expand Down Expand Up @@ -319,6 +324,9 @@ contract LendPoolLoan is Initializable, ILendPoolLoan, ContextUpgradeable, IERC7
require(_nftTotalCollateral[loan.nftAsset] >= 1, Errors.LP_INVALIED_NFT_AMOUNT);
_nftTotalCollateral[loan.nftAsset] -= 1;

// clear flash loan lock when exit auction
_setFlashLoanLocking(loan.nftAsset, loan.nftTokenId, address(this), false);

// burn bNFT and transfer underlying NFT asset to user
IBNFT(bNftAddress).burn(loan.nftTokenId);

Expand Down Expand Up @@ -413,9 +421,7 @@ contract LendPoolLoan is Initializable, ILendPoolLoan, ContextUpgradeable, IERC7
uint256 tokenId,
bool locked
) public override onlyFlashLoanLocker {
(address bnftProxy, ) = IBNFTRegistry(_addressesProvider.getBNFTRegistry()).getBNFTAddresses(nftAsset);

IBNFT(bnftProxy).setFlashLoanLocking(tokenId, _msgSender(), locked);
_setFlashLoanLocking(nftAsset, tokenId, _msgSender(), locked);
}

function purgeFlashLoanLocking(
Expand Down Expand Up @@ -543,4 +549,15 @@ contract LendPoolLoan is Initializable, ILendPoolLoan, ContextUpgradeable, IERC7
require(checkHandle, "BNFT: call interceptor after token burn failed");
}
}

function _setFlashLoanLocking(
address nftAsset,
uint256 tokenId,
address operator,
bool locked
) internal {
(address bnftProxy, ) = IBNFTRegistry(_addressesProvider.getBNFTRegistry()).getBNFTAddresses(nftAsset);

IBNFT(bnftProxy).setFlashLoanLocking(tokenId, operator, locked);
}
}
2 changes: 1 addition & 1 deletion deployments/deployed-contracts-goerli.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"address": "0x84a47EaEca69f8B521C21739224251c8c4566Bbc"
},
"LendPoolLoanImpl": {
"address": "0x2d86983f13e166451B9928b036C7cAf3F8Da4bF7"
"address": "0xE55870eBB007a50B0dfAbAdB1a21e4bFcee5299b"
},
"LendPoolLoan": {
"address": "0x7F64c32a3c13Bd245a7141a607A7E60DA585BA86"
Expand Down
4 changes: 2 additions & 2 deletions deployments/deployed-contracts-main.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"address": "0x70b97A0da65C15dfb0FFA02aEE6FA36e507C2762"
},
"LendPoolLoanImpl": {
"address": "0x71Bf09450De6327Aba596d921A549b71D0D8E990"
"address": "0x64e7A0969d57C69d81237172D3cDf1f8C342d080"
},
"LendPoolLoan": {
"address": "0x5f6ac80CdB9E87f3Cfa6a90E5140B9a16A361d5C"
Expand Down Expand Up @@ -135,4 +135,4 @@
"address": "0x56ECe8EDba529943b9A8ED966253b1F5ac54BF55",
"deployer": "0x868964fa49a6fd6e116FE82c8f4165904406f479"
}
}
}
20 changes: 16 additions & 4 deletions test/liquidate-redeem.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ makeSuite("LendPool: Redeem", (testEnv) => {
});

it("WETH - Auctions the borrow", async () => {
const { weth, bayc, bBAYC, users, pool, dataProvider } = testEnv;
const { weth, bayc, bBAYC, users, pool, dataProvider, loan } = testEnv;
const liquidator = users[3];
const borrower = users[1];

Expand Down Expand Up @@ -126,10 +126,13 @@ makeSuite("LendPool: Redeem", (testEnv) => {

const tokenOwner = await bayc.ownerOf("101");
expect(tokenOwner).to.be.equal(bBAYC.address, "Invalid token owner after redeem");

const checkFlashLoanLocked = await bBAYC.isFlashLoanLocked("101", loan.address, loan.address);
expect(checkFlashLoanLocked).to.be.equal(true);
});

it("WETH - Redeems the borrow", async () => {
const { weth, bayc, bBAYC, users, pool, dataProvider } = testEnv;
const { weth, bayc, bBAYC, users, pool, dataProvider, loan } = testEnv;
const liquidator = users[3];
const borrower = users[1];

Expand Down Expand Up @@ -201,6 +204,9 @@ makeSuite("LendPool: Redeem", (testEnv) => {
new BigNumber(ethReserveDataBefore.availableLiquidity.toString()).plus(repayDebtAmount).toFixed(0),
"Invalid principal available liquidity"
);

const checkFlashLoanLocked = await bBAYC.isFlashLoanLocked("101", loan.address, loan.address);
expect(checkFlashLoanLocked).to.be.equal(false);
});

it("WETH - Repays the borrow", async () => {
Expand Down Expand Up @@ -283,7 +289,7 @@ makeSuite("LendPool: Redeem", (testEnv) => {
});

it("USDC - Auctions the borrow", async () => {
const { usdc, bayc, bBAYC, users, pool, dataProvider } = testEnv;
const { usdc, bayc, bBAYC, users, pool, dataProvider, loan } = testEnv;
const liquidator = users[3];
const borrower = users[1];

Expand Down Expand Up @@ -326,10 +332,13 @@ makeSuite("LendPool: Redeem", (testEnv) => {
);
console.log("simpleLoansData:", simpleLoansData);
*/

const checkFlashLoanLocked = await bBAYC.isFlashLoanLocked("102", loan.address, loan.address);
expect(checkFlashLoanLocked).to.be.equal(true);
});

it("USDC - Redeems the borrow", async () => {
const { usdc, bayc, bBAYC, users, pool, dataProvider } = testEnv;
const { usdc, bayc, bBAYC, users, pool, dataProvider, loan } = testEnv;
const liquidator = users[3];
const borrower = users[1];

Expand Down Expand Up @@ -403,6 +412,9 @@ makeSuite("LendPool: Redeem", (testEnv) => {
new BigNumber(usdcReserveDataBefore.availableLiquidity.toString()).plus(repayDebtAmount).toFixed(0),
"Invalid principal available liquidity"
);

const checkFlashLoanLocked = await bBAYC.isFlashLoanLocked("102", loan.address, loan.address);
expect(checkFlashLoanLocked).to.be.equal(false);
});

it("USDC - Repays the borrow", async () => {
Expand Down
25 changes: 20 additions & 5 deletions test/liquidate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ makeSuite("LendPool: Liquidation", (testEnv) => {
});

it("WETH - Auctions the borrow", async () => {
const { weth, bayc, bBAYC, users, pool, dataProvider } = testEnv;
const { weth, bayc, bBAYC, users, pool, dataProvider, loan } = testEnv;
const liquidator = users[3];
const borrower = users[1];

Expand Down Expand Up @@ -130,6 +130,9 @@ makeSuite("LendPool: Liquidation", (testEnv) => {

const loanDataAfter = await dataProvider.getLoanDataByLoanId(loanDataBefore.loanId);
expect(loanDataAfter.state).to.be.equal(ProtocolLoanState.Auction, "Invalid loan state after acution");

const checkFlashLoanLocked = await bBAYC.isFlashLoanLocked("101", loan.address, loan.address);
expect(checkFlashLoanLocked).to.be.equal(true);
});

it("WETH - Check auction end time", async () => {
Expand All @@ -149,7 +152,7 @@ makeSuite("LendPool: Liquidation", (testEnv) => {
});

it("WETH - Liquidates the borrow", async () => {
const { weth, bayc, users, pool, dataProvider } = testEnv;
const { weth, bayc, bBAYC, users, pool, dataProvider, loan } = testEnv;
const liquidator = users[3];
const borrower = users[1];

Expand Down Expand Up @@ -209,6 +212,9 @@ makeSuite("LendPool: Liquidation", (testEnv) => {
new BigNumber(ethReserveDataBefore.availableLiquidity.toString()).plus(expectedLiquidateAmount).toFixed(0),
"Invalid principal available liquidity"
);

const checkFlashLoanLocked = await bBAYC.isFlashLoanLocked("101", loan.address, loan.address);
expect(checkFlashLoanLocked).to.be.equal(false);
});

it("USDC - Borrows USDC", async () => {
Expand Down Expand Up @@ -278,7 +284,7 @@ makeSuite("LendPool: Liquidation", (testEnv) => {
});

it("USDC - Auctions the borrow at first time", async () => {
const { usdc, bayc, bBAYC, users, pool, dataProvider } = testEnv;
const { usdc, bayc, bBAYC, users, pool, dataProvider, loan } = testEnv;
const liquidator = users[3];
const borrower = users[1];

Expand Down Expand Up @@ -314,10 +320,13 @@ makeSuite("LendPool: Liquidation", (testEnv) => {

const loanDataAfter = await dataProvider.getLoanDataByCollateral(bayc.address, "102");
expect(loanDataAfter.state).to.be.equal(ProtocolLoanState.Auction, "Invalid loan state after acution");

const checkFlashLoanLocked = await bBAYC.isFlashLoanLocked("102", loan.address, loan.address);
expect(checkFlashLoanLocked).to.be.equal(true);
});

it("USDC - Auctions the borrow at second time with higher price", async () => {
const { usdc, bayc, bBAYC, users, pool, dataProvider } = testEnv;
const { usdc, bayc, bBAYC, users, pool, dataProvider, loan } = testEnv;
const liquidator3 = users[3];
const liquidator4 = users[4];

Expand Down Expand Up @@ -350,10 +359,13 @@ makeSuite("LendPool: Liquidation", (testEnv) => {

const loanDataAfter = await dataProvider.getLoanDataByCollateral(bayc.address, "102");
expect(loanDataAfter.state).to.be.equal(ProtocolLoanState.Auction, "Invalid loan state after acution");

const checkFlashLoanLocked = await bBAYC.isFlashLoanLocked("102", loan.address, loan.address);
expect(checkFlashLoanLocked).to.be.equal(true);
});

it("USDC - Liquidates the borrow", async () => {
const { usdc, bayc, users, pool, dataProvider } = testEnv;
const { usdc, bayc, bBAYC, users, pool, dataProvider, loan } = testEnv;
const liquidator = users[4];
const borrower = users[1];

Expand Down Expand Up @@ -415,5 +427,8 @@ makeSuite("LendPool: Liquidation", (testEnv) => {
new BigNumber(usdcReserveDataBefore.availableLiquidity.toString()).plus(expectedLiquidateAmount).toFixed(0),
"Invalid principal available liquidity"
);

const checkFlashLoanLocked = await bBAYC.isFlashLoanLocked("102", loan.address, loan.address);
expect(checkFlashLoanLocked).to.be.equal(false);
});
});

0 comments on commit 8a0eb21

Please sign in to comment.