Concur Finance contest - 0x1f8b's results

Incentives vote-and-rewards sharing protocol

General Information

Platform: Code4rena

Start Date: 03/02/2022

Pot Size: $75,000 USDC

Total HM: 42

Participants: 52

Period: 7 days

Judge: GalloDaSballo

Total Solo HM: 21

Id: 83

League: ETH

Concur Finance

Findings Distribution

Researcher Performance

Rank: 13/52

Findings: 4

Award: $1,515.05

🌟 Selected for report: 1

🚀 Solo Findings: 1

Findings Information

Awards

31.0722 USDC - $31.07

Labels

bug
duplicate
3 (High Risk)

External Links

Lines of code

https://github.com/code-423n4/2022-02-concur/blob/72b5216bfeaa7c52983060ebfc56e72e0aa8e3b0/contracts/Shelter.sol#L52-L57

Vulnerability details

Impact

The user can drain the contract.

Proof of Concept

The withdraw method does not check that the user has called this method before, there is also no tracking of how many tokens the user donates, so the calls client.shareOf(_token, msg.sender) / client.totalShare(_token ) are not related to how many tokens this user deposited, it is about how much balance was deposited.

This method does not subtract transferred tokens from savedTokens[_token], and also does not use the flag claimed[_token][_to] = true; so there is no restriction on a user calling this method multiple times until drain the contract.

Steps:

  • User call withdraw multiple times
  • Use claimed[_token][_to] to avoid duplicate calls to withdraw

#0 - GalloDaSballo

2022-04-12T23:29:01Z

Duplicate of #246

Findings Information

🌟 Selected for report: 0x1f8b

Labels

bug
2 (Med Risk)

Awards

1179.9976 USDC - $1,180.00

External Links

Lines of code

https://github.com/code-423n4/2022-02-concur/blob/72b5216bfeaa7c52983060ebfc56e72e0aa8e3b0/contracts/Shelter.sol#L38-L42

Vulnerability details

Impact

Shelter contract can steal user tokens.

Proof of Concept

Shelter client can call activate on an already activated token, this will reset its start time, so if the client activate a token when it GRACE_PERIOD is almost finished, it will reset this time. This will prevent the user to call withdraw because the condition activated[_token] + GRACE_PERIOD < block.timestamp but will allow the client to call deactivate and receive all funds from the users because it will satisfy the condition activated[_token] + GRACE_PERIOD > block.timestamp.

Steps:

  • client activate tokenA.
  • Users deposit tokenA using donate.
  • client activate tokenA again until they has enough tokens.
  • More users use donate.
  • client deactivate tokenA and receive all tokens.
  • Avoid activate twice for the same token
  • donate only after the GRACE_PERIOD

#0 - GalloDaSballo

2022-04-15T22:58:26Z

I believe the finding to be valid, the warden has shown how the Shelter design allows the client to repeatedly call activate to prevent anyone from withdrawing the tokens.

Because this is contingent on a malicious admin, I believe Medium Severity to be more appropraite

Awards

163.9289 USDC - $163.93

Labels

bug
QA (Quality Assurance)
sponsor confirmed

External Links

Non critical

Lack of events

The method ConcurRewardPool.pushReward should emit an event in order to be detectable by the _recipient.

Non exploitable reentrancy

The method ConcurRewardPool.claimRewards allow the reentrancy, it seems that it's not vulnerable but it should be protected in order to be resilient.

Low

Contract management risks

The following contracts are Ownable and Pausable, so the owner could resign while the contract is paused, causing a Denial of Service. Owner resignation while paused should be avoided:

contracts\ConvexStakingWrapper.sol

  1. It was found some transfer, approve or transferFrom without checking the boolean result, ERC20 standard specify that the token can return false if this call was not made, so it's mandatory to check the result of these methods.

As following you can see the affected locations:

  1. There are a lack of checks in the method requestWithdraw that allow to create a request for _amount=0 it should be denied in order to avoid possible errors.

#0 - GalloDaSballo

2022-04-21T16:54:25Z

Events -> Informational

Reentrancy -> Valid (no POC so low)

Contract management risks Withdrawal are not paused so technically it should be fine, but interesting finding

Lack of check Valid

0 check in requestWithdraw Personally don't think it would make any differnce

#1 - GalloDaSballo

2022-04-27T14:54:38Z

2+++

Awards

140.0476 USDC - $140.05

Labels

bug
G (Gas Optimization)

External Links

General issues

  1. Change the incremental logic from i++ to ++i in order to save some opcodes:
  1. Use delete instead of set to default value (false or 0)

Contracts specific

Contract contracts\MasterChef.sol

  1. The following variables could be declared as constant:
  • concurPerBlock
  • _concurShareMultiplier
  • _perMille
  1. The following variables could be declared as immutable:
  • startBlock
  • endBlock
  • concur
  1. There was an empty pool in lines L63-L70, pushed during the constructor that never is used.

  2. The following struct could be optimized moving depositFeeBP close to depositToken in order to save one storage slot:

struct PoolInfo { IERC20 depositToken; // <- Move here uint allocPoint; uint lastRewardBlock; uint accConcurPerShare; uint16 depositFeeBP; // <- Move this }
  1. On line 204, the transferSuccess variable is init false, it is better to create the variable with the return to avoid this initialization.

Contract contracts\VoteProxy.sol

  1. In line 21 it could be removed the == true in order to save some opcodes.

Contract contracts\USDMPegRecovery.sol

  1. The variable startLiquidity is never used and can be removed or changed to immutable.
  2. The variable step coud be constant.
  3. On lines 74-76 usdm.balanceOf(address(this)) was called twice without any change of balance, it's cheaper to cache it.

Contract contracts\ConvexStakingWrapper.sol

  1. In line 235 it's better to move the asignation of deposits[_pid][msg.sender].amount inside the if if (_amount > 0) {
deposits[_pid][msg.sender].amount -= uint192(_amount); if (_amount > 0) {

#0 - GalloDaSballo

2022-03-25T17:23:35Z

  1. 9 gas
  2. Would like to see proof that it actually saves gas, per the docs this won't save gas

MastChef.sol

  1. -> 2.1k per variable per read -> 6.1k
  2. -> 2.1k per variable per read -> 6.1k
  3. Not sure if we can remove this as the sponsor may want to always use non-zero indexes
  4. Saves a SLOT, let's say 2k gas (one less Cold Slot)
  5. Disagree as syntactic sugar won't save gas

VoteProxy.sol

  1. Would like to see proof but I agree, will give it an ISZERO, 3 gas

USDMPegRecovery.sol

  1. Agree, 2.1k
  2. Agree, 2.1k
  3. Agree, 200 gas (STATICCALL + Hot Slot Read)

ConvexStakingWrapper.sol

  1. Would save 200 gas (Hot SLOAD + Same Value SSTORE)

18812 Gas Saved by implementing these findings

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