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
Rank: 14/37
Findings: 3
Award: $1,159.94
🌟 Selected for report: 2
🚀 Solo Findings: 2
🌟 Selected for report: gzeon
1139.8542 INSURE - $398.95
692.0543 USDC - $692.05
gzeon
To prevent withdrawal front-running, a lockup period is set between withdrawal request and withdrawal. However, there are no obligation to withdraw after the lockup period and the capital will keep earning premium during lockup. A strategy for underwriter is to keep requesting withdrawal every lockup period
to keep their average lockup to lockup period/2
.
Assuming
lockup period
is set to 86400 (24 hours) in the supplied test cases
It is very likely an underwriter can avoid payout by such strategy since their effective lockup would be 12 hours only. They will continue to earn yield in the pool and only require some extra gas cost for the requestWithdraw
every 24 hours.Extend the lockup period at least by a factor of 2 or force underwriter to withdraw after lockup period.
#0 - oishun1112
2022-01-19T06:22:44Z
Yes, lock up period is going to be like a week~2week in production.
🌟 Selected for report: gzeon
62.2711 INSURE - $21.79
32.6923 USDC - $32.69
gzeon
Use unchecked for safe math to save gas, for example: https://github.com/code-423n4/2022-01-insure/blob/19d1a7819fe7ce795e6d4814e7ddf8b8e1323df3/contracts/PremiumModels/BondingPremium.sol#L176
premiumRate = premiumRate / T_1 / (u1 - u2) / BASE;
Since we have
2.9784 INSURE - $1.04
1.5637 USDC - $1.56
gzeon
> 0
is less gas efficient than != 0
for uint
$ grep "> 0" contracts -R -n contracts/IndexTemplate.sol:133: bytes(_metaData).length > 0 && contracts/IndexTemplate.sol:166: require(_amount > 0, "ERROR: DEPOSIT_ZERO"); contracts/IndexTemplate.sol:172: if (_supply > 0 && _totalLiquidity > 0) { contracts/IndexTemplate.sol:174: } else if (_supply > 0 && _totalLiquidity == 0) { contracts/IndexTemplate.sol:199: require(_amount > 0, "ERROR: REQUEST_ZERO"); contracts/IndexTemplate.sol:231: require(_amount > 0, "ERROR: WITHDRAWAL_ZERO"); contracts/IndexTemplate.sol:246: if (_liquidityAfter > 0) { contracts/IndexTemplate.sol:274: if(_totalLiquidity > 0){ contracts/IndexTemplate.sol:283: if (_allocPoint > 0) { contracts/IndexTemplate.sol:427: allocPoints[msg.sender] > 0, contracts/IndexTemplate.sol:477: require(allocPoints[msg.sender] > 0); contracts/IndexTemplate.sol:493: if (totalLiquidity() > 0) { contracts/IndexTemplate.sol:513: if (totalSupply() > 0) { contracts/IndexTemplate.sol:612: if (totalAllocPoint > 0) { contracts/IndexTemplate.sol:656: if (allocPoints[poolList[i]] > 0) { contracts/Factory.sol:175: if (_references.length > 0) { contracts/Factory.sol:185: if (_conditions.length > 0) { contracts/Factory.sol:187: if (conditionlist[address(_template)][i] > 0) { contracts/Vault.sol:154: attributions[msg.sender] > 0 && contracts/Vault.sol:187: attributions[msg.sender] > 0 && contracts/Vault.sol:220: attributions[msg.sender] > 0 && contracts/Vault.sol:347: if (_amount > 0) { contracts/Vault.sol:388: if (totalAttributions > 0 && _attribution > 0) { contracts/Vault.sol:406: if (attributions[_target] > 0) { contracts/Vault.sol:473: } else if (IERC20(_token).balanceOf(address(this)) > 0) { contracts/CDSTemplate.sol:100: bytes(_metaData).length > 0 && contracts/CDSTemplate.sol:132: require(_amount > 0, "ERROR: DEPOSIT_ZERO"); contracts/CDSTemplate.sol:140: if (_supply > 0 && _liquidity > 0) { contracts/CDSTemplate.sol:142: } else if (_supply > 0 && _liquidity == 0) { contracts/CDSTemplate.sol:191: require(_amount > 0, "ERROR: REQUEST_ZERO"); contracts/CDSTemplate.sol:223: require(_amount > 0, "ERROR: WITHDRAWAL_ZERO"); contracts/CDSTemplate.sol:296: if (totalSupply() > 0) { contracts/PoolTemplate.sol:185: bytes(_metaData).length > 0 && contracts/PoolTemplate.sol:218: if (_conditions[1] > 0) { contracts/PoolTemplate.sol:237: require(_amount > 0, "ERROR: DEPOSIT_ZERO"); contracts/PoolTemplate.sol:263: require(_amount > 0, "ERROR: DEPOSIT_ZERO"); contracts/PoolTemplate.sol:282: require(_amount > 0, "ERROR: REQUEST_ZERO"); contracts/PoolTemplate.sol:321: require(_amount > 0, "ERROR: WITHDRAWAL_ZERO"); contracts/PoolTemplate.sol:391: } else if (_index.credit > 0) { contracts/PoolTemplate.sol:396: if (_pending > 0) { contracts/PoolTemplate.sol:401: if (_credit > 0) { contracts/PoolTemplate.sol:437: if (_credit > 0) { contracts/PoolTemplate.sol:444: if (_pending > 0) { contracts/PoolTemplate.sol:521: if (_totalCredit > 0) { contracts/PoolTemplate.sol:672: if (indicies[indexList[i]].credit > 0) { contracts/PoolTemplate.sol:706: if (_credit > 0) { contracts/PoolTemplate.sol:726: if (_deductionFromPool > 0) { contracts/PoolTemplate.sol:745: if (totalSupply() > 0) { contracts/PoolTemplate.sol:802: if (_supply > 0 && _originalLiquidity > 0) { contracts/PoolTemplate.sol:804: } else if (_supply > 0 && _originalLiquidity == 0) { contracts/PoolTemplate.sol:835: if (totalLiquidity() > 0) { contracts/PoolTemplate.sol:847: if (lockedAmount > 0) { contracts/PoolTemplate.sol:929: require(b > 0);
#0 - oishun1112
2022-01-16T06:16:08Z
#1 - 0xean
2022-01-28T00:09:27Z
dupe of #36
2.4125 INSURE - $0.84
1.2666 USDC - $1.27
gzeon
Cache array length in for loop to save gas
for (uint256 i = 0; i < poolList.length; i++) {
uint _length = poolList.length; for (uint256 i = 0; i < _length; i++) {
#0 - oishun1112
2022-01-17T07:37:56Z
8.1712 INSURE - $2.86
4.2899 USDC - $4.29
gzeon
Use external keyword instead of public for some functions that are not used internally.
For example, the deposit function in PoolTemplate was never used internally. https://github.com/code-423n4/2022-01-insure/blob/19d1a7819fe7ce795e6d4814e7ddf8b8e1323df3/contracts/PoolTemplate.sol#L232
#0 - oishun1112
2022-01-17T08:12:38Z
#1 - 0xean
2022-01-29T01:41:19Z
dupe of #7
🌟 Selected for report: Dravee
Also found by: 0x1f8b, Jujic, TomFrenchBlockchain, csanuragjain, defsec, gzeon, loop, robee
2.9784 INSURE - $1.04
1.5637 USDC - $1.56
gzeon
Some variables could be set immutable to save gas, e.g.
IOwnership public ownership;
that is only set in the constructor
constructor(address _ownership) { ownership = IOwnership(_ownership); }
#0 - oishun1112
2022-01-17T07:43:26Z