Stable Midnight Canary
Medium
Transactions are published to Ethereum typically within 5-10 minutes, up to 24 hours based on the Blast docs. This means that the newly created loan may initially have loanId = X, but due to reorg it loanId may be different when transaction is finalized. Load ids are incremented sequentially and users expect that their loan id remains unchanged. In case a transaction which creates a new load is not included in the final state all sequentially created loans will have id = initial id - 1
. This can lead to unexpected result for the users when calling
repay()
, call()
, auction()
and seize()
.
Using only loanId as identifier in repay()
, call()
, auction()
and seize()
functions.
https://github.com/sherlock-audit/2024-09-predict-fun/blob/41e70f9eed3f00dd29aba4038544150f5b35dccb/predict-dot-loan/contracts/PredictDotLoan.sol#L454 https://github.com/sherlock-audit/2024-09-predict-fun/blob/41e70f9eed3f00dd29aba4038544150f5b35dccb/predict-dot-loan/contracts/PredictDotLoan.sol#L534 https://github.com/sherlock-audit/2024-09-predict-fun/blob/41e70f9eed3f00dd29aba4038544150f5b35dccb/predict-dot-loan/contracts/PredictDotLoan.sol#L561 https://github.com/sherlock-audit/2024-09-predict-fun/blob/41e70f9eed3f00dd29aba4038544150f5b35dccb/predict-dot-loan/contracts/PredictDotLoan.sol#L610
User repay()
, call()
, auction()
and seize()
with a loanId which wont correspond to the intended loan because of reorg.
Blockchain reorg. Blast is an optimistic rollup, just like Arbritrum, Base, Optimism, etc and Optimistic rollups are known for having re-org issues.
Depending on the called function and checks implemented in it there are two options :
- The provided loanId will make the transaction revert due to internal checks.
- The provided loanId will be a valid one and will lead to unexpected result for users.
- Loans are created via accept offers, match proposal, refinance.
- User send a transaction to one of the problematic functions
- Reorg happens
- Loan Id will be different from the moment the user submitted his transaction
- User transaction will be executed against a loan different than the intended one.
Possible attack on Ethereum mainnet:
- Loan with id = X is called shortly after it was created.
- User calls
auction()
to bid for loadId = X - reorg happens
- Attacker frontrun the loan creation with id = X and creates unfavorable loan which will have id = X now, because ids are incremented sequentially.
- Attacker call the newly created loan.
- User will bid for the attacker's loan instead of the desired one.
Unexpected results for users.
N/A
Provide additional identifiers for the loan apart from the id and verify they match the Loan storage loan = loans[loanId];
properties.
Another approach would be instead of using a number for the loanId, to use an identifier which is constructed from the number of the loan, lender and lets say block.timestamp. This will prevent the issue which comes from reorgs.