Sherlock contest - hyh's results

Decentralized exploit protection.

General Information

Platform: Code4rena

Start Date: 20/01/2022

Pot Size: $80,000 USDC

Total HM: 5

Participants: 37

Period: 7 days

Judge: Jack the Pug

Total Solo HM: 1

Id: 76

League: ETH

Sherlock

Findings Distribution

Researcher Performance

Rank: 6/37

Findings: 3

Award: $3,303.57

🌟 Selected for report: 2

πŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: hyh

Also found by: GreyArt, hack3r-0m

Labels

bug
2 (Med Risk)
resolved
sponsor confirmed

Awards

1972.2849 USDC - $1,972.28

External Links

Handle

hyh

Vulnerability details

Impact

Sucessfull arbRestake performs _redeemShares for arbRewardShares amount to extract the arbitrager reward. This effectively reduces shares accounted for an NFT, but leaves untouched the addressShares of an nftOwner.

As a result the tokenBalanceOfAddress function will report an old balance that existed before arbitrager reward was slashed away. This will persist if the owner will transfer the NFT to someone else as its new reduced shares value will be subtracted from addressShares in _beforeTokenTransfer, leaving the arbitrage removed shares permanently in addressShares of the NFT owner, essentially making all further reporting of his balance incorrectly inflated by the cumulative arbitrage reward shares from all arbRestakes happened to the owner's NFTs.

Proof of Concept

arbRestake redeems arbRewardShares, which are a part of total shares of an NFT:

https://github.com/code-423n4/2022-01-sherlock/blob/main/contracts/Sherlock.sol#L673

This will effectively reduce the stakeShares:

https://github.com/code-423n4/2022-01-sherlock/blob/main/contracts/Sherlock.sol#L491

But there is no mechanics in place to reduce addressShares of the owner apart from mint/burn/transfer, so addressShares will still correspond to NFT shares before arbitrage. This discrepancy will be accumulated further with arbitrage restakes.

Add a flag to _redeemShares indicating that it was called for a partial shares decrease, say isPartialRedeem, and do addressShares[nftOwner] -= _stakeShares when isPartialRedeem == true.

Another option is to do bigger refactoring, making stakeShares and addressShares always change simultaneously.

#0 - Evert0x

2022-02-09T17:29:46Z

This is a legit issue and needs to be addressed. I think we choose to delete this functionality all together.

The function has some potential future benefit but it might be too little benefit to make these relatively complex changes that make the code harder to understand.

Dups

Findings Information

🌟 Selected for report: hyh

Also found by: GreyArt, harleythedog, pauliax

Labels

bug
enhancement
2 (Med Risk)
disagree with severity

Awards

1331.2923 USDC - $1,331.29

External Links

Handle

hyh

Vulnerability details

Impact

Part of the funds held with the strategy can be frozen if the current strategy has tight liquidity when updateYieldStrategy is run as this function makes an attempt to withdraw all the funds and then unconditionally removes the strategy.

The Sherlock to YieldStrategy link will be broken as a result: Sherlock points to the new Strategy, while old Strategy still allows only this Sherlock contract to withdraw.

This way back and forth switches will be required in the future to return the funds: withdraw all from new strategy and switch to old, withdraw all from old and point to new one again, reinvest there.

Proof of Concept

In peer-to-peer lending protocols it is not always possible for the token supplier to withdraw all what's due. This happens on high utilization of the market (when it has a kind of liquidity crunch).

This way yieldStrategy.withdrawAll is not guaranteed to obtain all the funds held with the strategy:

https://github.com/code-423n4/2022-01-sherlock/blob/main/contracts/Sherlock.sol#L286

The worst case scenario here seems to be the remainder funds to be left frozen within the strategy.

For example, AaveV2Strategy withdraw and withdrawAll have onlySherlockCore modifier:

https://github.com/code-423n4/2022-01-sherlock/blob/main/contracts/managers/AaveV2Strategy.sol#L78-100

While Sherlock core is immutable for the Strategy by default:

https://github.com/code-423n4/2022-01-sherlock/blob/main/contracts/managers/Manager.sol#L26-41

Consider implementing a new method that fails whenever a strategy cannot withdraw all what's due now, and rename current implementation to, for example, forceUpdateYieldStrategy, to have a degree of flexibility around liquidity issues.

Also, to avoid back and forth switching, a strategy argument can be introduced to yieldStrategyWithdrawAll to allow withdrawals from any (not only current) yieldStrategy:

https://github.com/code-423n4/2022-01-sherlock/blob/main/contracts/Sherlock.sol#L322

Now:

function yieldStrategyWithdrawAll() external override onlyOwner {

To be (if _yieldStrategy is zero then utilize current):

function yieldStrategyWithdrawAll(IStrategyManager _yieldStrategy) external override onlyOwner {

#0 - Evert0x

2022-02-09T17:13:08Z

I think this should be low risk but it's an interesting feature to add

#2 - jack-the-pug

2022-03-26T16:10:50Z

I think this worths a Med, the scenario is not impossible to happen, and the handling in the current implementation is quite rough.

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