Joyn contest - TomFrenchBlockchain's results

Launchpad for collaborative web3 media projects with blueprints, building blocks, and community support.

General Information

Platform: Code4rena

Start Date: 30/03/2022

Pot Size: $30,000 USDC

Total HM: 21

Participants: 38

Period: 3 days

Judge: Michael De Luca

Total Solo HM: 10

Id: 104

League: ETH

Joyn

Findings Distribution

Researcher Performance

Rank: 13/38

Findings: 2

Award: $890.06

🌟 Selected for report: 1

🚀 Solo Findings: 1

Findings Information

🌟 Selected for report: kirk-baird

Also found by: 0xDjango, Dravee, Ruhum, TomFrenchBlockchain, WatchPug, defsec, hubble, hyh, leastwood, minhquanym

Labels

bug
duplicate
3 (High Risk)
sponsor confirmed

Awards

85.0569 USDC - $85.06

External Links

Lines of code

https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/royalty-vault/contracts/RoyaltyVaultFactory.sol#L57-L59 https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/royalty-vault/contracts/RoyaltyVault.sol#L67-L70 https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/royalty-vault/contracts/RoyaltyVault.sol#L40 https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/core-contracts/contracts/CoreCollection.sol#L307

Vulnerability details

Impact

A ProxyVault's platformFee may be set to arbitrary values resulting in either a DOS attack or claiming 100% of any royalties received as platform fees. A DOS attack would freeze all affected NFTs as well as the royalties.

Proof of Concept

ProxyVault.sendToSplitter uses the platformFee variable to determine how much of the accrued royalties should be kept as a platform fee and how much to release to the Splitter (the collection's team).

A platformFee of 100% is represented by platformFee = 10000. Clearly if platformFee > 10000 the contract will try to send more platform fees than it has received in royalties, resulting in all calls to ProxyVault.sendToSplitter reverting.

If we look at the functions which allow us to update platformFee we can see there's no input validation preventing someone from giving a value greater than 10000.

https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/royalty-vault/contracts/RoyaltyVaultFactory.sol#L57-L59

https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/royalty-vault/contracts/RoyaltyVault.sol#L67-L70

Notably all transfers of a collection will call ProxyVault.sendToSplitter so as well as preventing the team from collecting royalties, all NFTs in the collection will be frozen.

https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/core-contracts/contracts/CoreCollection.sol#L307

A malicious admin could then DOS a collection completely with a single transaction. They could also simply prevent the team from collecting any royalties at all by reserving it as a platform fee.

Choose a sensible maximum platform fee (well below 100%) and revert someone attempts to set it above that value.

#0 - liveactionllama

2022-03-31T16:56:24Z

Adding note from warden TomFrenchBlockchain:

It seems that RoyaltyVaultFactory in the Joyn contest is actual a test contract despite looking like the main factory for this contract and is out of scope. This impacts one of my findings but the finding is STILL IN SCOPE.

On my finding "Platform fee may be set at or greater than 100% to claim all royalties or DOS a collection" I used RoyaltyVaultFactory as the example to show that the platform fee can be set greater than 100%. It's important to note that the real contract which will be deploying ProxyVaults (SplitFactory) has the same issue and so the finding SHOULD NOT be marked invalid.

#1 - sofianeOuafir

2022-04-14T20:31:17Z

duplicate of #9

Findings Information

🌟 Selected for report: TomFrenchBlockchain

Labels

bug
2 (Med Risk)
sponsor confirmed

Awards

805.0047 USDC - $805.00

External Links

Lines of code

https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/core-contracts/contracts/CoreCollection.sol#L161-L163 https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/core-contracts/contracts/CoreCollection.sol#L307 https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/royalty-vault/contracts/RoyaltyVault.sol#L43-L50 https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/splits/contracts/Splitter.sol#L149-L169

Vulnerability details

Impact

Collection owners will likely lose money by claiming fees unless the fees from a single NFT sale outweighs the cost of claiming it (not guaranteed).

Proof of Concept

Consider a new Collection with a RoyaltyVault and Splitter set and a nonzero mint fee.

When calling mintToken, the _handlePayment function is called https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/core-contracts/contracts/CoreCollection.sol#L161-L163

This will transfer the minting fee to the RoyaltyVault contract.

On each transfer of an NFT within the collection (for instance in the _mint call which occurs directly after calling _handlePayment), the Collection contract will call sendToSplitter on the RoyaltyVault: https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/core-contracts/contracts/CoreCollection.sol#L307

This function will forward the collection owners' portion of the minting on to the Splitter contract but another important thing to note is that we call Splitter.incrementWindow.

https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/royalty-vault/contracts/RoyaltyVault.sol#L43-L50

This results in the fees newly deposited into the Splitter contract being held in a separate "window" to the fees from previous or later mints and need to be claimed separately. Remember that this process happens on every NFT sale so the only funds which will be held in this window will be the minting fees for this particular mint.

https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/splits/contracts/Splitter.sol#L149-L169

From this we can see that the claim function will only claim the fraction of the fees which are owed to the caller from a single NFT mint.

https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/splits/contracts/Splitter.sol#L112-L142

Note that we can attempt to claim from multiple windows in a single transaction using claimForAllWindow but as the name suggests it performs an unbounded loop trying to claim all previous windows (even ones which have already been claimed!) and it is likely that with a new window for every NFT sold this function will exceed the gas limit (consider an 10k token collection resulting in trying to do 10k SSTOREs at 20k gas each.), leaving us to claim each window individually with claim.

https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/splits/contracts/Splitter.sol#L35-L62

We're then forced to claim the royalties from each NFT sold one by one, having to send huge numbers of calls to claim incurring the base transaction cost many times over and performing many ERC20 transfers when we could have just performed one.

Compound on this that this needs to be repeated by everyone included in the split, multiplying the costs of claiming.

Medium risk as it's gas inefficiency to the point of significant value leakage where collection owners will lose a large fraction of their royalties.

It doesn't seem like the "window" mechanism does anything except raise gas costs to the extent that it will be very difficult to withdraw fees so it should be removed.

#0 - sofianeOuafir

2022-04-14T19:26:20Z

This is a very fair point and we'll consider fixing this issue.

#1 - deluca-mike

2022-04-22T04:11:34Z

Aside from the very valid points made by the warden, it seems that the heavy functions called from the _beforeTokenTransfer also create a lot of friction for the NFT owners. Might make more sense to have royalty splitting happen asynchronously from NFT transfers (i.e. let the cost of splitting be the burden of royalty stakeholders, not NFT holders).

If NFT transferring becomes too costly, someone could make a "de-joyn" contract which can "re-tokenize" NFTs sent to it, so that they can be transferred without having to worry about _beforeTokenTransfer (or royalties, for that matter).

See Recommended Mitigation Steps in #37 for more info.

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