code4rena-2022-08-nounsdao-g11

[G‑11] ++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for- and while-loops

보고서

Summary

오버플로우 날 가능성이 없는 반복문 인덱스 연산은 unchecked 하여 가스를 줄일 수 있다 제안했다.

Keyword

gas optimization, safemath, unchecked

Vulnerability

File: contracts/governance/NounsDAOLogicV1.sol
 
281:          for (uint256 i = 0; i < proposal.targets.length; i++) {
 
319:          for (uint256 i = 0; i < proposal.targets.length; i++) {
 
346:          for (uint256 i = 0; i < proposal.targets.length; i++) {
 
371:          for (uint256 i = 0; i < proposal.targets.length; i++) {
 
File: contracts/governance/NounsDAOLogicV2.sol
 
292:          for (uint256 i = 0; i < proposal.targets.length; i++) {
 
330:          for (uint256 i = 0; i < proposal.targets.length; i++) {
 
357:          for (uint256 i = 0; i < proposal.targets.length; i++) {
 
382:          for (uint256 i = 0; i < proposal.targets.length; i++) {

일반적으로 반복문은 for (uint256 i = 0; i < length; i++) 와 같이 이용된다. length의 타입이 동일하거나 i보다 작다면 i는 length보다 항상 작다. 따라서 대부분의 상황에서 i++++i 연산 시 오버플로우가 발생하지 않는다.

solidity 0.8.0 부터는 기본적으로 연산에 safeMath가 적용된다. 이는 30~40 gas를 추가로 소모한다. 이는 unchecked를 이용하여 해제할 수 있다.

다음과 같이 unchecked로 인덱스를 업데이트 하면 가스를 절약할 수 있다. 아직 루프문에 바로 unchecked 문을 사용할 수 없어 함수로 빼거나 다음과 같이 해야 한다.

for (uint i ; i < length;) {
    // do something that doesn't change the value of i
    unchecked{
      ++i;
    }
}

Impact

for 루프를 돌 때마다 SafeMath를 체크하느라 30~40 gas가 낭비된다.

Mitigation

unchecked 를 이용하여 인덱스를 업데이트 한다.


tags: bughunting, nouns dao, smart contract, solidity, gas optimization, gas, solidity unchecked, solidity safemath, severity gas