From ed36c4b554564dbf20adedb12e57882c2b769272 Mon Sep 17 00:00:00 2001 From: betmoardotfun Date: Fri, 15 Nov 2024 00:15:46 +0800 Subject: [PATCH 1/5] Fix: unintended delegatecall external interestLib on deployment testing observed that when this function is called it reverts as it attempts to delegatecall to a non existent contract to execute this function. fixed by changing it from public to internal. --- src/InterestLib.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/InterestLib.sol b/src/InterestLib.sol index 6131d95..0da3477 100644 --- a/src/InterestLib.sol +++ b/src/InterestLib.sol @@ -7,7 +7,7 @@ library InterestLib { uint256 public constant ONE = 10 ** 18; uint256 public constant ONE_THOUSAND_APY = 76_036_763_191; - function pow(uint256 _base, uint256 _exponent) public pure returns (uint256) { + function pow(uint256 _base, uint256 _exponent) internal pure returns (uint256) { if (_exponent == 0) { return ONE; } else if (_exponent % 2 == 0) { From fb4d29963de79c751d076548f4023c0c949e8ba7 Mon Sep 17 00:00:00 2001 From: betmoardotfun Date: Fri, 15 Nov 2024 00:19:42 +0800 Subject: [PATCH 2/5] vulnerability: early auction calls interest <1 due to the previous method of calculation it leads to value of < InterstLib.ONE when called early on. This results in amountOwed going to 0 over time rather than increasing as intended leading to loss for USDC lender. Fixed by calculating the linear auction rate with a baseline from InterestLib.ONE --- src/PolyLend.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PolyLend.sol b/src/PolyLend.sol index 14dfc32..fbbe2a7 100644 --- a/src/PolyLend.sol +++ b/src/PolyLend.sol @@ -362,7 +362,8 @@ contract PolyLend is PolyLendEE, ERC1155TokenReceiver { revert AuctionHasEnded(); } - uint256 currentInterestRate = (block.timestamp - loans[_loanId].callTime) * MAX_INTEREST / AUCTION_DURATION; + // Fixed bug: add InterestLib.ONE to prevent interest going to 0 for early calls to transfer + uint256 currentInterestRate = InterestLib.ONE + ((block.timestamp - loans[_loanId].callTime) * (MAX_INTEREST - InterestLib.ONE) / AUCTION_DURATION); // _newRate must be less than or equal to the current offered rate if (_newRate > currentInterestRate) { From 481a21b6d247163aa5455fe3ded7bd20b947a3e2 Mon Sep 17 00:00:00 2001 From: betmoardotfun Date: Fri, 15 Nov 2024 00:21:13 +0800 Subject: [PATCH 3/5] fix: _getNewRate calc match vuln fix update for rate calc. --- src/test/PolyLendTestHelper.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/PolyLendTestHelper.sol b/src/test/PolyLendTestHelper.sol index 24f2e25..ed163d8 100644 --- a/src/test/PolyLendTestHelper.sol +++ b/src/test/PolyLendTestHelper.sol @@ -101,6 +101,7 @@ contract PolyLendTestHelper is Test, PolyLendEE { } function _getNewRate(uint256 _callTime) internal view returns (uint256) { - return (block.timestamp - _callTime) * polyLend.MAX_INTEREST() / polyLend.AUCTION_DURATION(); + //return (block.timestamp - _callTime) * polyLend.MAX_INTEREST() / polyLend.AUCTION_DURATION(); + return InterestLib.ONE + ((block.timestamp - _callTime) * (polyLend.MAX_INTEREST() - InterestLib.ONE) / polyLend.AUCTION_DURATION()); } } From 91ef2cb9931be3e0279609f47861357a9cd68d97 Mon Sep 17 00:00:00 2001 From: betmoardotfun Date: Fri, 15 Nov 2024 00:22:00 +0800 Subject: [PATCH 4/5] fix: add lib import. link to prev commit _getNewRateCalc --- src/test/PolyLendTestHelper.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/PolyLendTestHelper.sol b/src/test/PolyLendTestHelper.sol index ed163d8..a233aa9 100644 --- a/src/test/PolyLendTestHelper.sol +++ b/src/test/PolyLendTestHelper.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.15; import {Test, console2 as console, stdStorage, StdStorage, stdError} from "../../lib/forge-std/src/Test.sol"; import {PolyLend, PolyLendEE, Loan, Request, Offer} from "../PolyLend.sol"; +import {InterestLib} from "../InterestLib.sol"; import {USDC} from "../dev/USDC.sol"; import {DeployLib} from "../dev/DeployLib.sol"; import {IConditionalTokens} from "../interfaces/IConditionalTokens.sol"; From 4d0ecf803ace2307bf65be8644ac4d91ddb5b3a5 Mon Sep 17 00:00:00 2001 From: betmoardotfun Date: Fri, 15 Nov 2024 00:24:18 +0800 Subject: [PATCH 5/5] fix: wrong usage of requestId & offerId previous version used offerId for requests and requestId for offers. --- src/PolyLend.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PolyLend.sol b/src/PolyLend.sol index fbbe2a7..080bc53 100644 --- a/src/PolyLend.sol +++ b/src/PolyLend.sol @@ -246,7 +246,7 @@ contract PolyLend is PolyLendEE, ERC1155TokenReceiver { loanAmount: loanAmount, rate: offers[_offerId].rate, startTime: block.timestamp, - minimumDuration: requests[_offerId].minimumDuration, + minimumDuration: requests[requestId].minimumDuration, callTime: 0 }); @@ -254,7 +254,7 @@ contract PolyLend is PolyLendEE, ERC1155TokenReceiver { requests[requestId].borrower = address(0); // invalidate the offer - offers[requestId].lender = address(0); + offers[_offerId].lender = address(0); // transfer the borrowers collateral to address(this) conditionalTokens.safeTransferFrom(msg.sender, address(this), positionId, collateralAmount, "");