Nested Finance contest - 0xliumin's results

The one-stop Defi app to build, manage and monetize your portfolio.

General Information

Platform: Code4rena

Start Date: 10/02/2022

Pot Size: $30,000 USDC

Total HM: 5

Participants: 24

Period: 3 days

Judge: harleythedog

Total Solo HM: 3

Id: 86

League: ETH

Nested Finance

Findings Distribution

Researcher Performance

Rank: 1/24

Findings: 3

Award: $7,232.49

🌟 Selected for report: 1

πŸš€ Solo Findings: 1

Findings Information

🌟 Selected for report: 0xliumin

Labels

bug
2 (Med Risk)
disagree with severity

Awards

5623.2427 USDC - $5,623.24

External Links

Lines of code

https://github.com/code-423n4/2022-02-nested/blob/69cf51d8e4eeb8bce3025db7f4f74cc565c9fad3/contracts/NestedFactory.sol#L446

Vulnerability details

Impact

A user can destroy their NFTs and not pay fees on most of their assets.

Proof of concept

Alice has an NFT portfolio with 100 gwei dai and 100 gwei uni. Alice calls destroy on this NFT with buy token marked as dai. We would expect after this destroy step that she would pay 1 gwei dai in fees + 1 gwei uni worth of dai in fees, no matter what orders she selects.

Alice selects the following orders:

[{ operator: ZeroEx, token: uni, calldata: performSwap with a very small amount of uni for dai} { operator: Flat, token: dai, calldata: transfer a very small amount dai for dai}]

This set of orders doesn't violate any of the require statements in the destroy function. Each order will complete successfully given the constraints here: https://github.com/code-423n4/2022-02-nested/blob/69cf51d8e4eeb8bce3025db7f4f74cc565c9fad3/contracts/abstracts/MixinOperatorResolver.sol#L100-L101

Fees aren't collected on the leftover amount from the callOperator step, seen here https://github.com/code-423n4/2022-02-nested/blob/69cf51d8e4eeb8bce3025db7f4f74cc565c9fad3/contracts/NestedFactory.sol#L446

this means that Alice will only pay the fees on the dai that was output from the orders (a very small amount), and the rest of the 100 gwei uni and 100 gwei dai are transferred directly back to the attacker.

Recommended mitigation

Replace the safeTransfer with your safeTransferWithFees function. Or, if you don't want users to have to pay fees on slippage, set a maximum "slippage" amount in the safeSubmitOrder function.

#0 - maximebrugel

2022-02-11T11:13:46Z

Good one

#1 - harleythedogC4

2022-02-27T16:22:50Z

The warden has described a way to avoid fees even when large amounts are being withdrawn. An avoidance of fees more closely fits the criteria of a medium severity issue:

2 β€” Med: Assets not at direct risk, but the function of the protocol or its availability could be impacted, or leak value with a hypothetical attack path with stated assumptions, but external requirements.

This is contrary to the previous audit that awarded a fee avoidance finding as high severity (which I disagree with).

Findings Information

🌟 Selected for report: pauliax

Also found by: 0xliumin, Dravee, GreyArt, IllIllI, Omik, ShippooorDAO, WatchPug, bobi, csanuragjain, gzeon, kenzo, rfa, robee, samruna

Labels

bug
QA (Quality Assurance)
sponsor acknowledged

Awards

90.9726 USDC - $90.97

External Links

Overall the code is high-quality and easy to follow. I did find some low-risk and non-critical findings below.

Low risk findings

areOperatorsImported has incorrect logic

Right now, this function returns false if the implementation AND the selector don't match. It's possible to provide a destination with either a different implementation or selector, and still get a true response.

https://github.com/code-423n4/2022-02-nested/blob/69cf51d8e4eeb8bce3025db7f4f74cc565c9fad3/contracts/OperatorResolver.sol#L42 Mitigation is to change && to ||.

Accidentally calling withdraw twice with the same parameters could withdraw multiple assets

If a user accidentally submits two withdraw transactions from the frontend, they will withdraw the token at that index and the last token in the list originally. Making sure that the user is unable to do this on the frontend will be important.

Non-critical findings

Flat operator doesn't need IERC20 imported from openzeppelin

No nftDestroyed event on destroy call

No nftUpdated event on updateLockTimestamp function

#0 - maximebrugel

2022-02-15T17:38:27Z

"areOperatorsImported has incorrect logic" (Duplicated)

https://github.com/code-423n4/2022-02-nested-findings/issues/17

"Accidentally calling withdraw twice with the same parameters could withdraw multiple assets" (Acknowledged)

"Flat operator doesn't need IERC20 imported from openzeppelin" (Duplicated)

https://github.com/code-423n4/2022-02-nested-findings/issues/52

"No nftDestroyed event on destroy call" (Disputed)

Transfer to address zero event used.

"No nftUpdated event on updateLockTimestamp function" (Disputed)

Specific update, the event LockTimestampIncreased is emitted.

#1 - harleythedogC4

2022-03-03T01:17:36Z

My personal judgements:

    1. "areOperatorsImported has incorrect logic". This has been upgraded to medium severity in #75. Will not contribute to the QA score.
    1. "Accidentally calling withdraw twice with the same parameters could withdraw multiple assets". Not a huge issue and is not really related to the smart contract. Valid and non-critical.
    1. "Flat operator doesn't need IERC20 imported from openzeppelin". Valid and non-critical.
    1. "No nftDestroyed event on destroy call". Agree with sponsor, the _burn will emit a transfer event which is good enough. Invalid.
    1. "No nftUpdated event on updateLockTimestamp function". Agree with sponsor. Invalid.

#2 - harleythedogC4

2022-03-03T02:27:44Z

Now, here is the methodology I used for calculating a score for each QA report. I first assigned each submission to be either non-critical (1 point), very-low-critical (5 points) or low-critical (10 points), depending on how severe/useful the issue is. The score of a QA report is the sum of these points, divided by the maximum number of points achieved by a QA report. This maximum number was 26 points, achieved by https://github.com/code-423n4/2022-02-nested-findings/issues/66.

The number of points achieved by this report is 2 points. Thus the final score of this QA report is (2/26)*100 = 8.

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