InsureDAO contest - Dravee's results

Anyone can create an insurance pool like Uniswap.

General Information

Platform: Code4rena

Start Date: 07/01/2022

Pot Size: $80,000 USDC

Total HM: 21

Participants: 37

Period: 7 days

Judge: 0xean

Total Solo HM: 14

Id: 71

League: ETH

InsureDAO

Findings Distribution

Researcher Performance

Rank: 6/37

Findings: 6

Award: $3,600.54

🌟 Selected for report: 37

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: WatchPug

Also found by: Dravee, Ruhum, cmichel, pmerkleplant

Labels

bug
duplicate
2 (Med Risk)

Awards

149.5717 INSURE - $52.35

90.8114 USDC - $90.81

External Links

Handle

Dravee

Vulnerability details

Impact

Bad accounting in case of non-standard ERC20 tokens

Proof of Concept

Vault.sol 105: IERC20(token).safeTransferFrom(_from, address(this), _amount); 106: 107: balance += _amount; Vault.sol 136: IERC20(token).safeTransferFrom(_from, address(this), _amount); 137: balance += _amount; Vault.sol 250: function repayDebt(uint256 _amount, address _target) external override { 251: uint256 _debt = debts[_target]; 252: if (_debt >= _amount) { 253: debts[_target] -= _amount; 254: totalDebt -= _amount; 255: IERC20(token).safeTransferFrom(msg.sender, address(this), _amount); 256: } else { 257: debts[_target] = 0; 258: totalDebt -= _debt; 259: IERC20(token).safeTransferFrom(msg.sender, address(this), _debt); 260: } 261: } Vault.sol 171: balance -= _amount; 172: IERC20(token).safeTransfer(_to, _amount); Vault.sol 201: function borrowValue(uint256 _amount, address _to) external onlyMarket override { 202: debts[msg.sender] += _amount; 203: totalDebt += _amount; 204: 205: IERC20(token).safeTransfer(_to, _amount); 206: } Vault.sol 314: balance -= _retVal; 315: IERC20(token).safeTransfer(_to, _retVal); Vault.sol 348: IERC20(token).safeTransfer(address(controller), _amount); 349: balance -= _amount;

Tools Used

VS Code

The balance should be saved before and after the transfer. The difference between those 2 values should then be calculated and added / substracted in the accounting variables.

Findings Information

🌟 Selected for report: Dravee

Also found by: Fitraldys, Ruhum, WatchPug, danb, egjlmn1, robee

Labels

bug
2 (Med Risk)
sponsor confirmed

Awards

86.5379 INSURE - $30.29

52.5409 USDC - $52.54

External Links

Handle

Dravee

Vulnerability details

Impact

The transactions could fail if the array get too big and the transaction would consume more gas than the block limit. This will then result in a denial of service for the desired functionality and break core functionality.

Proof of Concept

https://github.com/code-423n4/2022-01-insure/blob/main/contracts/PoolTemplate.sol#L703

Tools Used

VS Code

Keep the array size small.

#0 - oishun1112

2022-01-19T04:54:29Z

@kohshiba I think we need to set this

#1 - takadr

2022-01-22T04:34:22Z

@oishun1112 Does this mean for each pool the number of indices that can add the pool should be limited? Like the limitation on the number of pools each index can add. https://github.com/code-423n4/2022-01-insure/blob/main/contracts/IndexTemplate.sol#L593

#2 - oishun1112

2022-01-22T06:18:24Z

@takadr Yes, we need to limit the number of PoolTemplates indexed by IndexTemplate. This indexList issue is little bit complicated (have to change multiple places), so I'm going to do myself. Thank you!

#3 - 0xean

2022-01-27T21:15:35Z

Upgrading to sev-2 as this will eventually affect the availability of the protocol as transactions revert.

Findings Information

🌟 Selected for report: 0x1f8b

Also found by: Dravee, Meta0xNull, hyh, ospwner, robee

Labels

bug
duplicate
1 (Low Risk)
sponsor confirmed

Awards

37.3929 INSURE - $13.09

22.7028 USDC - $22.70

External Links

Handle

Dravee

Vulnerability details

Impact

As mistakes happen, address(0) checks should be made to avoid having to redeploy contracts

Proof of Concept

Here, registry can't be updated after deployment: https://github.com/code-423n4/2022-01-insure/blob/19d1a7819fe7ce795e6d4814e7ddf8b8e1323df3/contracts/Factory.sol#L82

Tools Used

VS Code

Add the address(0) check

#1 - 0xean

2022-01-27T22:40:09Z

dupe of #120

Findings Information

🌟 Selected for report: robee

Also found by: 0xngndev, Dravee, WatchPug, defsec, hyh

Labels

bug
duplicate
1 (Low Risk)

Awards

37.3929 INSURE - $13.09

22.7028 USDC - $22.70

External Links

Handle

Dravee

Vulnerability details

require() should be used for checking error conditions on inputs and return values while assert() should be used for invariant checking (properly functioning code should never reach a failing assert statement, unless there is a bug in your contract you should fix).

Here, I believe the assert should be a require or a revert:

contracts\Vault.sol:168: assert(available() >= _amount);

As the Solidity version is > 0.8.0, the remaining gas would still be refunded in case of failure, so I'll just flag this issue as Non-critical

#1 - 0xean

2022-01-27T23:27:03Z

#234

#2 - 0xean

2022-02-22T13:59:12Z

Moving these to dupe of #21

Findings Information

🌟 Selected for report: defsec

Also found by: Dravee, pauliax

Labels

bug
duplicate
1 (Low Risk)

Awards

102.5869 INSURE - $35.91

62.2849 USDC - $62.28

External Links

Handle

Dravee

Vulnerability details

In Parameters.sol:setFeeRate, the fee rate isn't bounded. It could get troublesome for users in the case of malicious/faulty governor contract :

172: /** 173: * @notice set the contract address of fee model 174: * @param _address address to set the fee model 175: * @param _target fee rate 176: */ 177: function setFeeRate(address _address, uint256 _target) 178: external 179: override 180: onlyOwner 181: { 182: _fee[_address] = _target; 183: emit FeeRateSet(_address, _target); 184: }

Set a max fee

Findings Information

🌟 Selected for report: Dravee

Labels

bug
1 (Low Risk)
resolved
sponsor confirmed

Awards

379.9514 INSURE - $132.98

230.6848 USDC - $230.68

External Links

Handle

Dravee

Vulnerability details

Impact

A division by 0 could occur

Proof of Concept

While at some places, a check is made to make sure that totalSupply() > 0, it's not consistently the case, such as in the following places:

contracts\CDSTemplate.sol:235: _retVal = (vault.attributionValue(crowdPool) * _amount) / totalSupply(); contracts\CDSTemplate.sol:318: _balance * vault.attributionValue(crowdPool) / totalSupply(); contracts\IndexTemplate.sol:216: _retVal = (_liquidty * _amount) / totalSupply(); contracts\IndexTemplate.sol:530: return (_balance * totalLiquidity()) / totalSupply(); contracts\PoolTemplate.sol:768: return (_balance * originalLiquidity()) / totalSupply();

At the following places, the check is indeed made:

contracts\IndexTemplate.sol:514: return (totalLiquidity() * MAGIC_SCALE_1E6) / totalSupply(); contracts\PoolTemplate.sol:747: return (originalLiquidity() * MAGIC_SCALE_1E6) / totalSupply();

Tools Used

VS Code

If this check is at least made at some places, this means that totalSupply() can indeed take a value of 0. Therefore, a check should always be made to prevent the div by 0

Findings Information

🌟 Selected for report: Dravee

Labels

bug
1 (Low Risk)
resolved
sponsor confirmed

Awards

379.9514 INSURE - $132.98

230.6848 USDC - $230.68

External Links

Handle

Dravee

Vulnerability details

The spec doesn't match with the comments in the code here:

Code: https://github.com/code-423n4/2022-01-insure/blob/main/contracts/Factory.sol#L90-L91 Spec: https://insuredao.gitbook.io/developers/market/factory#approvetemplate

Here, the spec doesn't mention _isOpen and seem to confuse the _approval description with what _isOpen should be.

Tools Used

VS Code

My guess is that the spec should be corrected

Findings Information

🌟 Selected for report: Dravee

Labels

bug
1 (Low Risk)
resolved
sponsor confirmed

Awards

379.9514 INSURE - $132.98

230.6848 USDC - $230.68

External Links

Handle

Dravee

Vulnerability details

The spec says the function should be called approveCondition() instead of setCondition: https://insuredao.gitbook.io/developers/market/factory#approvecondition

While this might still be understood nonetheless as setCondition is also mentioned, the spec says that the parameter _slot is the index of the reference array, whereas the code comment says it's the index within condition array: https://github.com/code-423n4/2022-01-insure/blob/main/contracts/Factory.sol#L133

Tools Used

VS Code

My guess is that the spec should be corrected

#0 - adust09

2022-01-26T12:00:10Z

@oishun1112 In this issue, should I change spec(Gitbook or something) ? if so, could you tell me how to

Findings Information

🌟 Selected for report: Dravee

Labels

bug
1 (Low Risk)
resolved
sponsor confirmed

Awards

379.9514 INSURE - $132.98

230.6848 USDC - $230.68

External Links

Handle

Dravee

Vulnerability details

Impact

Division by 0 or functionally incorrect targetLev

POC

A division by targetLev is made here : https://github.com/code-423n4/2022-01-insure/blob/main/contracts/IndexTemplate.sol#L306 and targetLev can be set to 0 : https://github.com/code-423n4/2022-01-insure/blob/main/contracts/IndexTemplate.sol#L575

Tools Used

VS Code

Either make a check on targetLev before setting it here: https://github.com/code-423n4/2022-01-insure/blob/main/contracts/IndexTemplate.sol#L575 or make a check before the division here: https://github.com/code-423n4/2022-01-insure/blob/main/contracts/IndexTemplate.sol#L306

#0 - oishun1112

2022-01-19T06:19:26Z

should be equal or higher than 1e6 (x1 leverage)

#1 - takadr

2022-01-22T04:08:36Z

@oishun1112 Looks like there is 0 check in current withdrawable() code. https://github.com/InsureDAO/pool-contracts/blob/audit/code4rena/contracts/IndexTemplate.sol#L275

As for setLeverage, should I change like this

function setLeverage(uint256 _target) external override onlyOwner {
    targetLev = _target;
    adjustAlloc();
    emit LeverageSet(_target);
}

to

function setLeverage(uint256 _target) external override onlyOwner {
    require(_target >= MAGIC_SCALE_1E6, "ERROR")
    targetLev = _target;
    adjustAlloc();
    emit LeverageSet(_target);
}

? What error message should it show?

#2 - oishun1112

2022-01-22T06:13:23Z

@takadr code like this would be fine

require(_target >= MAGIC_SCALE_1E6, "leverage must be x1 or higher");

Findings Information

🌟 Selected for report: Dravee

Labels

bug
1 (Low Risk)
sponsor acknowledged

Awards

379.9514 INSURE - $132.98

230.6848 USDC - $230.68

External Links

Handle

Dravee

Vulnerability details

Impact

To give more trust to users: functions that set key/critical variables should be put behind a timelock.

Proof of Concept

https://github.com/code-423n4/2022-01-insure/blob/main/contracts/Parameters.sol#L177-L184

Tools Used

VS Code

Add a timelock to setter functions of key/critical variables.

#0 - oishun1112

2022-01-19T05:45:22Z

from user experience, the amount of money user has to pay doesn't change by the feeRate. User pays premium. feeRate is ratio how much of premium goes to governance instead of insurance sellers.

#1 - oishun1112

2022-01-19T05:46:11Z

So yes, maybe we need to set timelock for changing InsureDAO's premium model

#2 - oishun1112

2022-01-19T05:46:49Z

I'll put this as acknowledge

#3 - 0xean

2022-01-27T21:57:52Z

going to downgrade this to low severity as I don't see this as a way of compromising assets immediately.

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

It's possible to save gas by optimizing the checks in conditional statements (if, else if and else). This would save a few opcodes and avoid redundant checks.

Proof of Concept

In CDSTemplate.sol:deposit(), the code is as follows:

140: if (_supply > 0 && _liquidity > 0) { 141: _mintAmount = (_amount * _supply) / _liquidity; 142: } else if (_supply > 0 && _liquidity == 0) { 143: //when vault lose all underwritten asset = 144: _mintAmount = _amount * _supply; //dilute LP token value af. Start CDS again. 145: } else { 146: //when _supply == 0, 147: _mintAmount = _amount; 148: }

The conditions checks can be optimized with the following (read the @audit-info comments for futher information):

if (_supply == 0) { _mintAmount = _amount; } else if (_liquidity == 0) { // @audit-info : implicit _supply > 0 as above condition is false //when vault lose all underwritten asset = _mintAmount = _amount * _supply; //dilute LP token value af. Start CDS again. } else { // @audit-info : implicit _supply > 0 and _liquidity > 0 as both the previous conditions are false _mintAmount = (_amount * _supply) / _liquidity; }

Tools Used

VS Code

Compact conditions in mentioned logic statements

#0 - oishun1112

2022-01-17T07:37:19Z

most of the case will be _supply > 0 && _liquidity > 0 so, it is cheaper to keep this order of validations

#1 - oishun1112

2022-01-17T09:38:00Z

I performed experiment and confirmed that even above premise, this impl reduce gas

https://github.com/code-423n4/2022-01-insure-findings/issues/355

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

Increased gas cost as SSTOREs are very expensive

Proof of Concept

The code is as follows :

094: function approveTemplate( 095: IUniversalMarket _template, 096: bool _approval, 097: bool _isOpen, 098: bool _duplicate 099: ) external override onlyOwner { 100: require(address(_template) != address(0)); 101: templates[address(_template)].approval = _approval; //@audit-info SSTORE 102: templates[address(_template)].isOpen = _isOpen; //@audit-info SSTORE 103: templates[address(_template)].allowDuplicate = _duplicate; //@audit-info SSTORE 104: emit TemplateApproval(_template, _approval, _isOpen, _duplicate); 105: }

As we can see, it's making 3 SSTORE operations, one for each boolean. The code could be optimized as follows to save gas :

function approveTemplate( IUniversalMarket _template, bool _approval, bool _isOpen, bool _duplicate ) external override onlyOwner { require(address(_template) != address(0)); Template memory approvedTemplate = new Template(_isOpen, _approval, _duplicate); templates[address(_template)] = approvedTemplate; //@audit-info only one SSTORE emit TemplateApproval(_template, _approval, _isOpen, _duplicate); }

Tools Used

VS Code

Use a memory Template struct and write in storage only once

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

Reducing from public to private will save gas

Proof of Concept

PremiumModels\BondingPremium.sol:26: //constants PremiumModels\BondingPremium.sol:27: uint256 public constant DECIMAL = uint256(1e6); //Decimals of USDC PremiumModels\BondingPremium.sol:28: uint256 public constant BASE = uint256(1e6); //bonding curve graph takes 1e6 as 100.0000% PremiumModels\BondingPremium.sol:29: uint256 public constant BASE_x2 = uint256(1e12); //BASE^2 PremiumModels\BondingPremium.sol:30: uint256 public constant ADJUSTER = uint256(10); //adjuster of 1e6 to 1e5 (100.0000% to 100.000%) CDSTemplate.sol:55: uint256 public constant MAGIC_SCALE_1E6 = 1e6; //internal multiplication scale 1e6 to reduce decimal truncation IndexTemplate.sol:95: uint256 public constant MAGIC_SCALE_1E6 = 1e6; //internal multiplication scale 1e6 to reduce decimal truncation PoolTemplate.sol:146: uint256 public constant MAGIC_SCALE_1E6 = 1e6; //internal multiplication scale 1e6 to reduce decimal truncation Vault.sol:38: uint256 public constant MAGIC_SCALE_1E6 = 1e6; //internal multiplication scale 1e6 to reduce decimal truncation

Tools Used

VS Code

Theses constants can simply be read from the verified contract, i.e., it is unnecessary to expose it with a public function. Also, constants having "1E6" in their name aren't even "nice to have public constants", as their value is obvious.

#0 - oishun1112

2022-01-12T07:13:28Z

sponsor confirmed

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

It's possible to save gas by optimizing the checks in conditional statements (if, else if and else). This would save a few opcodes and avoid redundant checks.

Proof of Concept

In IndexTemplate.sol:deposit(), the code is as follows:

172: if (_supply > 0 && _totalLiquidity > 0) { 173: _mintAmount = (_amount * _supply) / _totalLiquidity; 174: } else if (_supply > 0 && _totalLiquidity == 0) { 175: //when 176: _mintAmount = _amount * _supply; 177: } else { 178: _mintAmount = _amount; 179: }

The conditions checks can be optimized with the following (read the @audit-info comments for further information):

if (_supply == 0) { _mintAmount = _amount; } else if (_totalLiquidity == 0) { // @audit-info : implicit _supply > 0 as above condition is false _mintAmount = _amount * _supply; } else { // @audit-info : implicit _supply > 0 and _totalLiquidity > 0 as both the previous conditions are false _mintAmount = (_amount * _supply) / _totalLiquidity; }

Tools Used

VS Code

Compact conditions in mentioned logic statements

#0 - oishun1112

2022-01-17T07:40:43Z

#1 - oishun1112

2022-01-17T09:38:27Z

I performed experiment and confirmed that even above premise, this impl reduce gas

#355

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

SLOADs are expensive

Proof of Concept

Here, totalLiquidity() is loaded twice from storage

491: function leverage() public view returns (uint256 _rate) { 492: //check current leverage rate 493: if (totalLiquidity() > 0) { 494: return (totalAllocatedCredit * MAGIC_SCALE_1E6) / totalLiquidity(); 495: } else { 496: return 0; 497: } 498: }

Tools Used

VS Code

Cache totalLiquidity() in a variable

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

SLOADs are expensive

Proof of Concept

Here, _fee[_target] can be loaded twice from storage:

271: function getFeeRate(address _target) 272: external 273: view 274: override 275: returns (uint256) 276: { 277: if (_fee[_target] == 0) { 278: return _fee[address(0)]; 279: } else { 280: return _fee[_target]; 281: } 282: }

Tools Used

VS Code

Cache the storage reading in a memory variable

#0 - oishun1112

2022-01-17T08:29:57Z

I've confirmed that this implementation

  • increase gas around 30 when called the default value
  • reduce gas around 200 when called the set value

most of the cases, this tends to return the default value, so we want to keep the current implementation

#1 - oishun1112

2022-01-25T06:53:31Z

we confirm this issue to reduce gas cost in the future

#2 - oishun1112

2022-01-25T06:57:06Z

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

SLOADs are expensive

Proof of Concept

Here, attributions[_target] can be loaded twice from storage:

Vault.sol 400: function underlyingValue(address _target) 401: public 402: view 403: override 404: returns (uint256) 405: { 406: if (attributions[_target] > 0) { 407: return (valueAll() * attributions[_target]) / totalAttributions; 408: } else { 409: return 0; 410: } 411: }

Tools Used

VS Code

Cache the loaded storage value in a memory variable

#0 - oishun1112

2022-01-17T08:40:44Z

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

Checking if the value is 0 before returning 0 is less expensive than returning a calculation that's equal to 0

Proof of Concept

In Vault.sol:underlyingValue(), the code is as follows:

Vault.sol 400: function underlyingValue(address _target) 401: public 402: view 403: override 404: returns (uint256) 405: { 406: if (attributions[_target] > 0) { 407: return (valueAll() * attributions[_target]) / totalAttributions; 408: } else { 409: return 0; 410: } 411: }

It can be optimized as such:

406: uint256 valueAll = valueAll(); 407: if (valueAll != 0 && attributions[_target] > 0) { 408: return (valueAll * attributions[_target]) / totalAttributions; 409: } else { 410: return 0; 411: }

Tools Used

VS Code

Cache the loaded storage value in a memory variable and make the 0 checks to avoid unnecessary calculations if valueAll() == 0

#0 - oishun1112

2022-01-17T08:40:28Z

Findings Information

🌟 Selected for report: Dravee

Also found by: Dravee

Labels

bug
G (Gas Optimization)
sponsor acknowledged

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

Fixed arrays are less expensive than dynamic arrays and would implicitely add the array.length check

Proof of Concept

https://github.com/code-423n4/2022-01-insure/blob/main/contracts/PoolTemplate.sol#L180

Tools Used

VS Code

Make _conditions a fixed array of size 2

#0 - oishun1112

2022-01-17T08:51:57Z

true, but we keep the current implementation to leave some rooms for future upgrade. This is only one time function at deploy, so not going to be a problem in terms of user experience.

Findings Information

🌟 Selected for report: Dravee

Also found by: Dravee

Labels

bug
duplicate
G (Gas Optimization)
sponsor acknowledged

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

Fixed arrays are less expensive than dynamic arrays and would implicitely add the array.length check

Proof of Concept

https://github.com/code-423n4/2022-01-insure/blob/main/contracts/PoolTemplate.sol#L181

Tools Used

VS Code

Make _references a fixed array of size 5. I submitted a similar finding for _conditions. While the initialize function is indeed inherited from IUniversalMarket, this is in PoolTemplate that these arrays are the largest. Their bounds should then respectively be 5 and 2.

#0 - oishun1112

2022-01-17T08:52:30Z

#1 - 0xean

2022-01-28T00:05:15Z

dupe of #345

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

Increased gas cost (1 MSTORE and 1 MLOAD)

Proof of Concept

https://github.com/code-423n4/2022-01-insure/blob/main/contracts/PoolTemplate.sol#L552 There's no readability or gas gain from copying incident.payoutNumerator to a variable as it's used only once in the method.

Tools Used

VS Code

Do not store this data in a variable

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

Increased gas cost (1 MSTORE and 1 MLOAD)

Proof of Concept

https://github.com/code-423n4/2022-01-insure/blob/main/contracts/PoolTemplate.sol#L553 There's no readability or gas gain from copying incident.payoutDenominator to a variable as it's used only once in the method.

Tools Used

VS Code

Do not store this data in a variable

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

It's possible to save gas by optimizing the checks in conditional statements (if, else if and else). This would save a few opcodes and avoid redundant checks.

Proof of Concept

In PoolTemplate.sol:worth(), the code is as follows:

799: function worth(uint256 _value) public view returns (uint256 _amount) { 800: uint256 _supply = totalSupply(); 801: uint256 _originalLiquidity = originalLiquidity(); 802: if (_supply > 0 && _originalLiquidity > 0) { 803: _amount = (_value * _supply) / _originalLiquidity; 804: } else if (_supply > 0 && _originalLiquidity == 0) { 805: _amount = _value * _supply; 806: } else { 807: _amount = _value; 808: } 809: }

The conditions checks can be optimized with the following (read the @audit-info comments for further information):

function worth(uint256 _value) public view returns (uint256 _amount) { uint256 _supply = totalSupply(); uint256 _originalLiquidity = originalLiquidity(); if (_supply == 0) { _amount = _value; } else if (_originalLiquidity == 0) { _amount = _value * _supply; } else { _amount = (_value * _supply) / _originalLiquidity; } }

Tools Used

VS Code

Compact conditions in mentioned logic statements

#0 - oishun1112

2022-01-17T09:31:20Z

//new one function worth_1() public pure returns (uint256) { uint256 _value = 100; uint256 _supply = 1; uint256 _originalLiquidity = 1; uint256 _amount; if (_supply == 0) { _amount = _value; } else if (_originalLiquidity == 0) { _amount = _value * _supply; } else { _amount = (_value * _supply) / _originalLiquidity; } return _amount; } //current one function worth_2() public pure returns (uint256) { uint256 _value = 100; uint256 _supply = 1; uint256 _originalLiquidity = 1; uint256 _amount; if (_supply > 0 && _originalLiquidity > 0) { _amount = (_value * _supply) / _originalLiquidity; } else if (_supply > 0 && _originalLiquidity == 0) { _amount = _value * _supply; } else { _amount = _value; } return _amount; } //little bit of gas opt from worth_2 function worth_3() public pure returns (uint256) { uint256 _value = 100; uint256 _supply = 1; uint256 _originalLiquidity = 1; uint256 _amount; if (_supply != 0 && _originalLiquidity != 0) { _amount = (_value * _supply) / _originalLiquidity; } else if (_supply != 0 && _originalLiquidity == 0) { _amount = _value * _supply; } else { _amount = _value; } return _amount; }

worth_1 => 21876 gas worth_2 => 21934 gas worth_3 => 21918 gas

Findings Information

🌟 Selected for report: Dravee

Also found by: 0x0x0x, 0xngndev, Jujic, Ruhum, WatchPug, defsec, gzeon, solgryn

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

2.9784 INSURE - $1.04

1.5637 USDC - $1.56

External Links

Handle

Dravee

Vulnerability details

Impact

!= 0 costs less gas compared to > 0 for unsigned integer

Proof of Concept

> 0 is used in the following location(s):

CDSTemplate.sol:100: bytes(_metaData).length > 0 && CDSTemplate.sol:132: require(_amount > 0, "ERROR: DEPOSIT_ZERO"); CDSTemplate.sol:140: if (_supply > 0 && _liquidity > 0) { CDSTemplate.sol:142: } else if (_supply > 0 && _liquidity == 0) { CDSTemplate.sol:191: require(_amount > 0, "ERROR: REQUEST_ZERO"); CDSTemplate.sol:223: require(_amount > 0, "ERROR: WITHDRAWAL_ZERO"); CDSTemplate.sol:296: if (totalSupply() > 0) { Factory.sol:175: if (_references.length > 0) { Factory.sol:185: if (_conditions.length > 0) { Factory.sol:187: if (conditionlist[address(_template)][i] > 0) { IndexTemplate.sol:133: bytes(_metaData).length > 0 && IndexTemplate.sol:166: require(_amount > 0, "ERROR: DEPOSIT_ZERO"); IndexTemplate.sol:172: if (_supply > 0 && _totalLiquidity > 0) { IndexTemplate.sol:174: } else if (_supply > 0 && _totalLiquidity == 0) { IndexTemplate.sol:199: require(_amount > 0, "ERROR: REQUEST_ZERO"); IndexTemplate.sol:231: require(_amount > 0, "ERROR: WITHDRAWAL_ZERO"); IndexTemplate.sol:246: if (_liquidityAfter > 0) { IndexTemplate.sol:274: if(_totalLiquidity > 0){ IndexTemplate.sol:283: if (_allocPoint > 0) { IndexTemplate.sol:391: if (_current > _target && _available != 0) { IndexTemplate.sol:427: allocPoints[msg.sender] > 0, IndexTemplate.sol:477: require(allocPoints[msg.sender] > 0); IndexTemplate.sol:493: if (totalLiquidity() > 0) { IndexTemplate.sol:513: if (totalSupply() > 0) { IndexTemplate.sol:612: if (totalAllocPoint > 0) { IndexTemplate.sol:656: if (allocPoints[poolList[i]] > 0) { InsureDAOERC20.sol:302: require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); Parameters.sol:31: mapping(address => uint256) private _fee; //fee rate in 1e6 (100% = 1e6) PoolTemplate.sol:185: bytes(_metaData).length > 0 && PoolTemplate.sol:218: if (_conditions[1] > 0) { PoolTemplate.sol:237: require(_amount > 0, "ERROR: DEPOSIT_ZERO"); PoolTemplate.sol:263: require(_amount > 0, "ERROR: DEPOSIT_ZERO"); PoolTemplate.sol:282: require(_amount > 0, "ERROR: REQUEST_ZERO"); PoolTemplate.sol:321: require(_amount > 0, "ERROR: WITHDRAWAL_ZERO"); PoolTemplate.sol:391: } else if (_index.credit > 0) { PoolTemplate.sol:396: if (_pending > 0) { PoolTemplate.sol:401: if (_credit > 0) { PoolTemplate.sol:437: if (_credit > 0) { PoolTemplate.sol:444: if (_pending > 0) { PoolTemplate.sol:521: if (_totalCredit > 0) { PoolTemplate.sol:672: if (indicies[indexList[i]].credit > 0) { PoolTemplate.sol:706: if (_credit > 0) { PoolTemplate.sol:726: if (_deductionFromPool > 0) { PoolTemplate.sol:745: if (totalSupply() > 0) { PoolTemplate.sol:802: if (_supply > 0 && _originalLiquidity > 0) { PoolTemplate.sol:804: } else if (_supply > 0 && _originalLiquidity == 0) { PoolTemplate.sol:835: if (totalLiquidity() > 0) { PoolTemplate.sol:847: if (lockedAmount > 0) { PoolTemplate.sol:929: require(b > 0); Vault.sol:154: attributions[msg.sender] > 0 && Vault.sol:187: attributions[msg.sender] > 0 && Vault.sol:220: attributions[msg.sender] > 0 && Vault.sol:347: if (_amount > 0) { Vault.sol:388: if (totalAttributions > 0 && _attribution > 0) { Vault.sol:406: if (attributions[_target] > 0) { Vault.sol:473: } else if (IERC20(_token).balanceOf(address(this)) > 0) {

Tools Used

VS Code

Change > 0 with != 0.

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

Checking if the value is 0 before returning 0 is less expensive than returning a calculation that's equal to 0

Proof of Concept

In PoolTemplate.sol:rate(), the code is as follows:

File: PoolTemplate.sol 744: function rate() external view returns (uint256) { 745: if (totalSupply() > 0) { 746: return (originalLiquidity() * MAGIC_SCALE_1E6) / totalSupply(); 747: } else { 748: return 0; 749: } 750: }

It can be optimized as such:

744: function rate() external view returns (uint256) { 745: uint256 originalLiquidity = originalLiquidity(); 746: if (originalLiquidity != 0 && totalSupply() > 0) { 747: return (originalLiquidity * MAGIC_SCALE_1E6) / totalSupply(); 748: } else { 749: return 0; 750: } 751: }

Tools Used

VS Code

Cache the loaded storage value in a memory variable and make the 0 checks to avoid unnecessary calculations if originalLiquidity() == 0

Findings Information

🌟 Selected for report: Dravee

Also found by: Jujic, defsec

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

16.8132 INSURE - $5.88

8.8269 USDC - $8.83

External Links

Handle

Dravee

Vulnerability details

Impact

Increased gas cost

Proof of Concept

Solidity version 0.8.* already implements overflow and underflow checks by default. Using the SafeMath library from OpenZeppelin (which is more gas expensive than the 0.8.* overflow checks) is therefore redundant.

Instances include:

mocks\ERC20.sol:4:import "@openzeppelin/contracts/utils/math/SafeMath.sol"; mocks\ERC20.sol:30: using SafeMath for uint256; mocks\TestPremiumModel.sol:3:import "@openzeppelin/contracts/utils/math/SafeMath.sol"; mocks\TestPremiumModel.sol:7: using SafeMath for uint256; PremiumModels\BondingPremium.sol:10:import "@openzeppelin/contracts/utils/math/SafeMath.sol";

Tools Used

VS Code

Use the built-in checks instead of SafeMath and remove SafeMath from the dependencies

Findings Information

🌟 Selected for report: Dravee

Also found by: Jujic, Meta0xNull, Tomio, defsec, egjlmn1, robee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

2.4125 INSURE - $0.84

1.2666 USDC - $1.27

External Links

Handle

Dravee

Vulnerability details

Impact

If a variable is not set/initialized, it is assumed to have the default value (0, false, 0x0 etc depending on the data type). Explicitly initializing it with its default value is an anti-pattern and wastes gas.

Proof of Concept

Instances include:

Factory.sol:176: for (uint256 i = 0; i < _references.length; i++) { Factory.sol:186: for (uint256 i = 0; i < _conditions.length; i++) { IndexTemplate.sol:280: for (uint256 i = 0; i < _length; i++) { IndexTemplate.sol:348: for (uint256 i = 0; i < _length; i++) { IndexTemplate.sol:381: for (uint256 i = 0; i < _length; i++) { IndexTemplate.sol:462: for (uint256 i = 0; i < _poolLength; i++) { IndexTemplate.sol:655: for (uint256 i = 0; i < poolList.length; i++) { PoolTemplate.sol:343: for (uint256 i = 0; i < _ids.length; i++) { PoolTemplate.sol:671: for (uint256 i = 0; i < indexList.length; i++) { PoolTemplate.sol:703: for (uint256 i = 0; i < indexList.length; i++) { Vault.sol:109: for (uint128 i = 0; i < 2; i++) {

Tools Used

Manual Analysis

Remove explicit initialization for default values.

Findings Information

🌟 Selected for report: Dravee

Also found by: 0x0x0x, Jujic, WatchPug, defsec, egjlmn1, gzeon, robee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

Reading array length at each iteration of the loop takes 6 gas (3 for mload and 3 to place memory_offset) in the stack.

Caching the array length in the stack saves around 3 gas per iteration.

Proof of Concept

Factory.sol:176: for (uint256 i = 0; i < _references.length; i++) { Factory.sol:186: for (uint256 i = 0; i < _conditions.length; i++) { IndexTemplate.sol:655: for (uint256 i = 0; i < poolList.length; i++) { PoolTemplate.sol:343: for (uint256 i = 0; i < _ids.length; i++) { PoolTemplate.sol:671: for (uint256 i = 0; i < indexList.length; i++) { PoolTemplate.sol:703: for (uint256 i = 0; i < indexList.length; i++) {

Tools Used

VS Code

Store the array's length in a variable before the for-loop, and use it instead.

Findings Information

🌟 Selected for report: Dravee

Also found by: Jujic, robee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

16.8132 INSURE - $5.88

8.8269 USDC - $8.83

External Links

Handle

Dravee

Vulnerability details

Impact

Due to how the EVM natively works on 256 bit numbers, using a 8 bit number in for-loops introduces additional costs as the EVM has to properly enforce the limits of this smaller type.

See the warning at this link: https://docs.soliditylang.org/en/v0.8.0/internals/layout_in_storage.html#layout-of-state-variables-in-storage :

When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size. It is only beneficial to use reduced-size arguments if you are dealing with storage values because the compiler will pack multiple elements into one storage slot, and thus, combine multiple reads or writes into a single operation. When dealing with function arguments or memory values, there is no inherent benefit because the compiler does not pack these values.

Proof of Concept

Vault.sol:109: for (uint128 i = 0; i < 2; i++) {

Tools Used

VS Code

Use uint256 as a counter in for-loops.

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

Using both named returns and a return statement isn't necessary. Removing unused named return variables can reduce gas usage and improve code clarity. To save gas and improve code quality: consider using only one of those.

Proof of Concept

Instances include:

CDSTemplate.sol:287: function totalLiquidity() public view returns (uint256 _balance) { IndexTemplate.sol:491: function leverage() public view returns (uint256 _rate) { IndexTemplate.sol:504: function totalLiquidity() public view returns (uint256 _balance) { PoolTemplate.sol:628: returns (uint256 premium) PoolTemplate.sol:833: returns (uint256 _balance) PoolTemplate.sol:846: function utilizationRate() public view override returns (uint256 _rate) { PoolTemplate.sol:858: function totalLiquidity() public view override returns (uint256 _balance) { PoolTemplate.sol:866: function originalLiquidity() public view returns (uint256 _balance) {

Tools Used

VS Code

Remove the unused named returns

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

On external functions, when using the memory keyword with a function argument, what's happening is that a memory acts as an intermediate.

Reading directly from calldata using calldataload instead of going via memory saves the gas from the intermediate memory operations that carry the values.

As an extract from https://ethereum.stackexchange.com/questions/74442/when-should-i-use-calldata-and-when-should-i-use-memory :

memory and calldata (as well as storage) are keywords that define the data area where a variable is stored. To answer your question directly, memory should be used when declaring variables (both function parameters as well as inside the logic of a function) that you want stored in memory (temporary), and calldata must be used when declaring an external function's dynamic parameters. The easiest way to think about the difference is that calldata is a non-modifiable, non-persistent area where function arguments are stored, and behaves mostly like memory.

Proof of Concept

Vault.sol:92: address[2] memory _beneficiaries, Vault.sol:93: uint256[2] memory _shares

Tools Used

VS Code

Use calldata instead of memory for external functions where the function argument is read-only.

Findings Information

🌟 Selected for report: Dravee

Also found by: Jujic, WatchPug, defsec, hyh, sirhashalot

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

6.1284 INSURE - $2.14

3.2174 USDC - $3.22

External Links

Handle

Dravee

Vulnerability details

Impact

Increased gas cost.

Proof of Concept

Solidity version 0.8+ comes with implicit overflow and underflow checks on unsigned integers.

When an overflow or an underflow isn't possible (as an example, when a comparison is made before the arithmetic operation, or the operation doesn't depend on user input), some gas can be saved by using an unchecked block.

https://docs.soliditylang.org/en/v0.8.10/control-structures.html#checked-or-unchecked-arithmetic

These lines are the obvious ones that can't underflow or overflow (operations on constants or checks already made before the operations with require statements or if statements):

PremiumModels\BondingPremium.sol:47: T_1 = 1000000 * DECIMAL; PremiumModels\BondingPremium.sol:130: uint256 u1 = BASE - ((_lockedAmount * BASE) / _totalLiquidity); //util rate before. 1000000 = 100.000% PremiumModels\BondingPremium.sol:132: (((_lockedAmount + _amount) * BASE) / _totalLiquidity); //util rate after. 1000000 = 100.000% IndexTemplate.sol:292: uint256 _lockedCredit = _allocated - _availableBalance; PoolTemplate.sol:942: return a - b; IndexTemplate.sol:308: _retVal = _totalLiquidity - _necessaryAmount; IndexTemplate.sol:393: uint256 _decrease = _current - _target; IndexTemplate.sol:399: uint256 _allocate = _target - _current; IndexTemplate.sol:441: _shortage = _amount - _value; InsureDAOERC20.sol:255: _balances[sender] = senderBalance - amount; InsureDAOERC20.sol:303: _balances[account] = accountBalance - amount; Vault.sol:165: uint256 _shortage = _amount - available(); Vault.sol:310: uint256 _shortage = _retVal - available();

Tools Used

VS Code

Uncheck arithmetic operations when the risk of underflow or overflow is already contained.

#0 - oishun1112

2022-01-16T07:09:21Z

contract Storage { uint256 num; function test_1(uint256 a, uint256 b)external pure returns(uint256){ require(a > b); uint256 c; c = a - b; return c; } function test_2(uint256 a, uint256 b)external pure returns(uint256){ require(a > b); uint256 c = a - b; return c; } function test_3(uint256 a, uint256 b)external pure returns(uint256){ require(a > b); uint256 c; unchecked{ c = a - b; } return c; } }

test_1 => 22365 gas test_2 => 22343 gas test_3 => 22139 gas

226~204 gas reduction confirmed

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

Increased gas cost (1 slot)

Proof of Concept

IndexTemplate.pendingEnd (contracts/IndexTemplate.sol#62) should be deleted as it's never used by the contract

Tools Used

Slither

Delete the variable IndexTemplate.pendingEnd

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

Repetitive and expensive SSTORE opcode operations inside loops

Proof of Concept

totalAllocatedCredit -= _available (contracts/IndexTemplate.sol#368) totalAllocatedCredit -= _decrease (contracts/IndexTemplate.sol#395) totalAllocatedCredit += _allocate (contracts/IndexTemplate.sol#401)

Tools Used

Slither

Create a memory variable which will be used to compute a _totalAllocatedCredit that will get added to totalAllocatedCredit storage variable outside the loop. As an idea, you could create 1 such int variable and use it's value after the for-loop, or you could create 2 uint variables where 1 would store the _totalDecrease and 1 would store the _totalAllocate, and respectively substract and add them.

Findings Information

🌟 Selected for report: robee

Also found by: Dravee, Fitraldys, defsec, gzeon

Labels

bug
duplicate
G (Gas Optimization)

Awards

8.1712 INSURE - $2.86

4.2899 USDC - $4.29

External Links

Handle

Dravee

Vulnerability details

Impact

Public functions that are never called by the contract should be declared external to save gas.

Proof of Concept

- CDSTemplate.totalLiquidity() (contracts/CDSTemplate.sol#287-289) - CDSTemplate.valueOfUnderlying(address) (contracts/CDSTemplate.sol#310-318) - IndexTemplate.deposit(uint256) (contracts/IndexTemplate.sol#164-190) - IndexTemplate.leverage() (contracts/IndexTemplate.sol#491-498) - IndexTemplate.valueOfUnderlying(address) (contracts/IndexTemplate.sol#525-532) - IndexTemplate.set(uint256,address,uint256) (contracts/IndexTemplate.sol#586-623) - InsureDAOERC20.name() (contracts/InsureDAOERC20.sol#42-44) - InsureDAOERC20.symbol() (contracts/InsureDAOERC20.sol#50-52) - InsureDAOERC20.decimals() (contracts/InsureDAOERC20.sol#67-69) - InsureDAOERC20.transfer(address,uint256) (contracts/InsureDAOERC20.sol#99-107) - InsureDAOERC20.allowance(address,address) (contracts/InsureDAOERC20.sol#112-120) - InsureDAOERC20.approve(address,uint256) (contracts/InsureDAOERC20.sol#129-137) - InsureDAOERC20.transferFrom(address,address,uint256) (contracts/InsureDAOERC20.sol#152-168) - InsureDAOERC20.increaseAllowance(address,uint256) (contracts/InsureDAOERC20.sol#182-193) - InsureDAOERC20.decreaseAllowance(address,uint256) (contracts/InsureDAOERC20.sol#209-223) - Parameters.getOwner() (contracts/Parameters.sol#218-220) - PoolTemplate.deposit(uint256) (contracts/PoolTemplate.sol#232-247) - IPoolTemplate.valueOfUnderlying(address) (contracts/interfaces/IPoolTemplate.sol#27-31) - PoolTemplate.valueOfUnderlying(address) (contracts/PoolTemplate.sol#757-769) - PoolTemplate.allocatedCredit(address) (contracts/PoolTemplate.sol#816-823) - IPoolTemplate.utilizationRate() (contracts/interfaces/IPoolTemplate.sol#22) - PoolTemplate.utilizationRate() (contracts/PoolTemplate.sol#846-852) - BondingPremium.getCurrentPremiumRate(uint256,uint256) (contracts/PremiumModels/BondingPremium.sol#61-102) - Vault.getPricePerFullShare() (contracts/Vault.sol#448-450) - Vault.setController(address) (contracts/Vault.sol#485-496)

Tools Used

Slither

Change the visibility to external

Findings Information

🌟 Selected for report: Dravee

Also found by: 0x1f8b, Jujic, TomFrenchBlockchain, csanuragjain, defsec, gzeon, loop, robee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

2.9784 INSURE - $1.04

1.5637 USDC - $1.56

External Links

Handle

Dravee

Vulnerability details

Impact

The compiler won't reserve a storage slot for immutable variables

Proof of Concept

The following variables are initialized in the contract's constructor and can't get updated after:

Factory.sol:registry Factory.sol:ownership Parameters:ownership BondingPremium:ownership Registry:ownership Vault:ownership

Tools Used

VS Code

Make these variables immutable

#0 - oishun1112

2022-01-13T14:34:46Z

address token can be immutable as well #34

Findings Information

🌟 Selected for report: egjlmn1

Also found by: 0x0x0x, Dravee, Jujic, OriDabush, WatchPug, defsec, robee, tqts

Labels

bug
duplicate
G (Gas Optimization)

Awards

2.9784 INSURE - $1.04

1.5637 USDC - $1.56

External Links

Handle

Dravee

Vulnerability details

Impact

++i costs less gas compared to i++ for unsigned integer, as pre-increment is cheaper (about 5 gas per iteration)

Proof of Concept

i++ increments i and returns the initial value of i. Which means:

uint i = 1; i++; // == 1 but i == 2

But ++i returns the actual incremented value:

uint i = 1; ++i; // == 2 and i == 2 too, so no need for a temporary variable

In the first case, the compiler has to create a temporary variable (when used) for returning 1 instead of 2

Instances include:

Factory.sol:176: for (uint256 i = 0; i < _references.length; i++) { Factory.sol:186: for (uint256 i = 0; i < _conditions.length; i++) { IndexTemplate.sol:280: for (uint256 i = 0; i < _length; i++) { IndexTemplate.sol:348: for (uint256 i = 0; i < _length; i++) { IndexTemplate.sol:381: for (uint256 i = 0; i < _length; i++) { IndexTemplate.sol:462: for (uint256 i = 0; i < _poolLength; i++) { IndexTemplate.sol:655: for (uint256 i = 0; i < poolList.length; i++) { PoolTemplate.sol:343: for (uint256 i = 0; i < _ids.length; i++) { PoolTemplate.sol:671: for (uint256 i = 0; i < indexList.length; i++) { PoolTemplate.sol:703: for (uint256 i = 0; i < indexList.length; i++) { Vault.sol:109: for (uint128 i = 0; i < 2; i++) {

Tools Used

VS Code

Use ++i instead of i++ to increment the value of an uint variable.

#0 - oishun1112

2022-01-12T06:34:28Z

sponsor confirmed

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

When a contract imports and implements an interface or another contracts, it doesn't need to import the libraries that were already imported there.

Removing these imports will save gas.

Proof of Concept

InsureDAOERC20 imports the following:

5: import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

The following contracts inherit InsureDAOERC20 and also make those imports: CDSTemplate, IndexTemplate, PoolTemplate

Tools Used

VS Code

Remove the unused imports to reduce the size of the contract and save some deployment gas.

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

Duplicated code, loss of maintainability, increased contract size which leads to increased gas cost

Proof of Concept

The following can be simplified:

260: if (_available >= _amount) { 261: _compensated = _amount; 262: _attributionLoss = vault.transferValue(_amount, msg.sender); 263: emit Compensated(msg.sender, _amount); 264: } else { 265: //when CDS cannot afford, pay as much as possible 266: _compensated = _available; 267: _attributionLoss = vault.transferValue(_available, msg.sender); 268: emit Compensated(msg.sender, _available); 269: }

to

260: _compensated = _available >= _amount ? _amount : _available; //when CDS cannot afford, pay as much as possible 261: _attributionLoss = vault.transferValue(_compensated, msg.sender); 262: emit Compensated(msg.sender, _compensated);

Tools Used

VS Code

Apply the refacto and look out for duplicated code

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

Increased gas cost

Proof of Concept

The variable T_0 can go through 2 assignments in a row: Here:

75: uint256 T_0 = _totalLiquidity; 76: if (T_0 > T_1) { 77: T_0 = T_1; 78: }

And here:

134: uint256 T_0 = _totalLiquidity; 135: if (T_0 > T_1) { 136: T_0 = T_1; 137: }

The code can be optimized as such to save some gas:

uint256 T_0 = _totalLiquidity > T_1 ? _totalLiquidity : T_1;

Tools Used

VS Code

Apply the refacto

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

Increased gas cost

Proof of Concept

In Factory.sol, the following > 0 checks are redundant with the for-loop condition, because if _references.length == 0 or _conditions.length == 0, the condition uint256 i = 0; i <(_conditions)|(_references).length will never be satisfied and the for-loop won't iterate:

175: if (_references.length > 0) { 176: for (uint256 i = 0; i < _references.length; i++) { 177: require( 178: reflist[address(_template)][i][_references[i]] == true || 179: reflist[address(_template)][i][address(0)] == true, 180: "ERROR: UNAUTHORIZED_REFERENCE" 181: ); 182: } 183: } 184: 185: if (_conditions.length > 0) { 186: for (uint256 i = 0; i < _conditions.length; i++) { 187: if (conditionlist[address(_template)][i] > 0) { 188: _conditions[i] = conditionlist[address(_template)][i]; 189: } 190: } 191: }

Tools Used

VS Code

Remove these 2 if-statements

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

Impact

The operators “||” and “&&” apply the common short-circuiting rules. This means that in the expression “f(x) || g(y)”, if “f(x)” evaluates to true, “g(y)” will not be evaluated even if it may have side-effects.

Source: https://docs.soliditylang.org/en/v0.5.4/types.html#booleans

Proof of Concept

In IndexTemplate.sol:withdrawable(), there's an if-statement as such:

293: if (i == 0 || _availableRate < _lowestAvailableRate) {

Here, the condition i == 0 is always evaluated and is always equal to false when i > 0, meaning here a total of poolList.length - 1 evaluations are always evaluated to false.

It's best to reorder the conditions such as this condition doesn't get evaluated if _availableRate < _lowestAvailableRate is satisfied:

293: if (_availableRate < _lowestAvailableRate || i == 0 ) {

Tools Used

VS Code

Apply the refacto

Findings Information

🌟 Selected for report: Dravee

Also found by: p4st13r4

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

28.022 INSURE - $9.81

14.7115 USDC - $14.71

External Links

Handle

Dravee

Vulnerability details

Impact

Increased gas cost

Proof of Concept

In IndexTemplate.sol:_adjustAlloc(), the 3 following conditions are always evaluated:

//Withdraw or Deposit credit if (_current > _target && _available != 0) { //if allocated credit is higher than the target, try to decrease uint256 _decrease = _current - _target; IPoolTemplate(_poolList[i].addr).withdrawCredit(_decrease); totalAllocatedCredit -= _decrease; } if (_current < _target) { uint256 _allocate = _target - _current; IPoolTemplate(_poolList[i].addr).allocateCredit(_allocate); totalAllocatedCredit += _allocate; } if (_current == _target) { IPoolTemplate(_poolList[i].addr).allocateCredit(0); }

The code can be optimized to save some gas:

if (_current == _target) { IPoolTemplate(_poolList[i].addr).allocateCredit(0); } else if (_current < _target) { uint256 _allocate = _target - _current; IPoolTemplate(_poolList[i].addr).allocateCredit(_allocate); totalAllocatedCredit += _allocate; } else if (_current > _target && _available != 0) { //Withdraw or Deposit credit //if allocated credit is higher than the target, try to decrease uint256 _decrease = _current - _target; IPoolTemplate(_poolList[i].addr).withdrawCredit(_decrease); totalAllocatedCredit -= _decrease; }

Tools Used

VS Code

Apply the refacto

Findings Information

🌟 Selected for report: Dravee

Labels

bug
G (Gas Optimization)
resolved
sponsor confirmed

Awards

62.2711 INSURE - $21.79

32.6923 USDC - $32.69

External Links

Handle

Dravee

Vulnerability details

In IndexTemplate.sol:withdrawable(), the following can be optimized to save gas and avoid a loss of precision, from:

uint256 _necessaryAmount = _targetLockedCreditScore * totalAllocPoint / _targetAllocPoint; _necessaryAmount = _necessaryAmount * MAGIC_SCALE_1E6 / targetLev;

to

uint256 _necessaryAmount = _targetLockedCreditScore * totalAllocPoint * MAGIC_SCALE_1E6 / (_targetAllocPoint * targetLev);

#0 - 0xHaku

2022-01-26T10:40:44Z

@oishun1112 already fixed.

Findings Information

🌟 Selected for report: 0xngndev

Also found by: Dravee, Jujic, Meta0xNull, defsec, p4st13r4, robee, sirhashalot, tqts

Labels

bug
duplicate
G (Gas Optimization)

Awards

2.9784 INSURE - $1.04

1.5637 USDC - $1.56

External Links

Handle

Dravee

Vulnerability details

Impact

Shortening revert strings to fit in 32 bytes will decrease deployment time gas and will decrease runtime gas when the revert condition is met.

Revert strings that are longer than 32 bytes require at least one additional mstore, along with additional overhead for computing memory offset, etc.

Proof of Concept

Revert strings > 32 bytes are here:

PremiumModels\BondingPremium.sol:35: "Restricted: caller is not allowed to operate" PremiumModels\BondingPremium.sol:67: "ERROR: _lockedAmount > _totalLiquidity" CDSTemplate.sol:104: "ERROR: INITIALIZATION_BAD_CONDITIONS" CDSTemplate.sol:217: "ERROR: WITHDRAWAL_NO_ACTIVE_REQUEST" CDSTemplate.sol:221: "ERROR: WITHDRAWAL_EXCEEDED_REQUEST" Factory.sol:76: "Restricted: caller is not allowed to operate" IndexTemplate.sol:103: "Restricted: caller is not allowed to operate" IndexTemplate.sol:137: "ERROR: INITIALIZATION_BAD_CONDITIONS" IndexTemplate.sol:225: "ERROR: WITHDRAWAL_NO_ACTIVE_REQUEST" IndexTemplate.sol:229: "ERROR: WITHDRAWAL_EXCEEDED_REQUEST" IndexTemplate.sol:235: "ERROR: WITHDRAW_INSUFFICIENT_LIQUIDITY" IndexTemplate.sol:428: "ERROR_COMPENSATE_UNAUTHORIZED_CALLER" InsureDAOERC20.sol:162: "ERC20: transfer amount exceeds allowance" InsureDAOERC20.sol:217: "ERC20: decreased allowance below zero" InsureDAOERC20.sol:252: "ERC20: transfer amount exceeds balance" Ownership.sol:39: "Restricted: caller is not allowed to operate" Ownership.sol:47: "Restricted: caller is not allowed to operate" Parameters.sol:52: "Restricted: caller is not allowed to operate" PoolTemplate.sol:151: "Restricted: caller is not allowed to operate" PoolTemplate.sol:192: "ERROR: INITIALIZATION_BAD_CONDITIONS" PoolTemplate.sol:315: "ERROR: WITHDRAWAL_NO_ACTIVE_REQUEST" PoolTemplate.sol:319: "ERROR: WITHDRAWAL_EXCEEDED_REQUEST" PoolTemplate.sol:324: "ERROR: WITHDRAW_INSUFFICIENT_LIQUIDITY" PoolTemplate.sol:384: "ERROR: ALLOCATE_CREDIT_BAD_CONDITIONS" PoolTemplate.sol:427: "ERROR: WITHDRAW_CREDIT_BAD_CONDITIONS" PoolTemplate.sol:478: "ERROR: INSURE_EXCEEDED_AVAILABLE_BALANCE" PoolTemplate.sol:613: "ERROR: INSURANCE_TRANSFER_BAD_CONDITIONS" Registry.sol:25: "Restricted: caller is not allowed to operate" Vault.sol:47: "Restricted: caller is not allowed to operate" Vault.sol:156: "ERROR_WITHDRAW-VALUE_BADCONDITOONS" Vault.sol:189: "ERROR_TRANSFER-VALUE_BADCONDITOONS" Vault.sol:302: "ERROR_WITHDRAW-ATTRIBUTION_BADCONDITOONS" Vault.sol:331: "ERROR_TRANSFER-ATTRIBUTION_BADCONDITOONS"

Tools Used

Visual Studio Code

Shorten the revert strings to fit in 32 bytes.

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter