20,000 USDC
View results
Submission Details
Severity: gas
Valid

Perform updates in memory, write to storage at once.

Summary

Instead of updating struct fields individually by reading the struct each time from memory, its better to create the updated struct in memory the write it to storage once.

Vulnerability Details

Consider the following snippet from Lender.buyLoan() :

...snip
// update the loan with the new info
loans[loanId].lender = msg.sender;
loans[loanId].interestRate = pools[poolId].interestRate;
loans[loanId].startTimestamp = block.timestamp;
loans[loanId].auctionStartTimestamp = type(uint256).max;
loans[loanId].debt = totalDebt;
emit Borrowed(
loan.borrower,
msg.sender,
loanId,
loans[loanId].debt,
loans[loanId].collateral,
pools[poolId].interestRate,
block.timestamp
);
emit LoanBought(loanId);

In order to update the loan variable, there are 7 reads being performed from the storage. We can save on a lot of gas by first creating the updated loan struct, then overwriting the old one with it:

// Created updated loan struct
Loan memory updatedLoan;
updatedLoan.lender = msg.sender;
updatedLoan.interestRate = pools[poolId].interestRate;
updatedLoan.startTimestamp = block.timestamp;
updatedLoan.auctionStartTimestamp = type(uint256).max;
updatedLoan.debt = totalDebt;
// Overwrite existing one with it
loans[loanId] = updatedLoan;
emit Borrowed(
loan.borrower,
msg.sender,
loanId,
updatedLoan.debt,
updatedLoan.collateral,
updatedLoan.interestRate,
block.timestamp
);
emit LoanBought(loanId);

With this simple change, major gas saving of 99630 and 99238 gas were observed in the test_buyLoan() and test_giveLoan() tests respectively, totalling a total gas saving of 198868 gas. The same optimization could be applied to other places where many storage reads are made.

Impact

Gas

Tools Used

Foundry, Forge

Recommendation

Perform updates in memory, then write to storage at once.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.