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
Rank: 20/38
Findings: 3
Award: $382.76
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: hickuphh3
Also found by: 0xDjango, kirk-baird, leastwood, m9800, minhquanym, pedroais
203.7202 USDC - $203.72
ERC721Payable.sol
and thus CoreCollection.sol
contain a function called _handlePayment()
. In this function, funds are transferred via payableToken.transferFrom()
in order to mint an isForSale
token. Many tokens do not revert on transfer failure and instead simply return false. Since payableToken
can be any token used to receive payment, it is possible that users will be able to mint the ERC721 for free if it is set to one that doesn't revert automatically.
If the CoreCollection
is initialized with a payableToken
that does not revert on failure as is very common, the user will be able to call mint()
with less than the necessary mintFee
. Since the transfer of the ERC20 fails but the minting of the ERC721 succeeds, the user gets the NFT for free.
Manual Review
Use SafeERC20.safeTransfer()
whenever transferring ERC20 tokens. This function reverts on failure by default.
#0 - sofianeOuafir
2022-04-14T14:53:00Z
duplicate of #52
🌟 Selected for report: kirk-baird
Also found by: 0xDjango, Dravee, Ruhum, TomFrenchBlockchain, WatchPug, defsec, hubble, hyh, leastwood, minhquanym
85.0569 USDC - $85.06
Owner can arbitrarily set platform fee without validation. If the fee is set too high, all token transfers to splitter will fail. E.g. platformFee > 10000
If the owner sets calls setPlatformFee(10001)
, all calls to sendToSplitter()
will fail due to the following lines:
uint256 platformShare = (balanceOfVault * platformFee) / 10000; uint256 splitterShare = balanceOfVault - platformShare;
Assuming that balanceOfVault
contains even $1 USDC (1e6), the platformShare
will be larger than balanceOfVault
causing the function to revert.
Manual review.
Add checks to ensure that platformFee <= 10000
to ensure continuous functionality. Most likely want this to be less than 1000 or similar.
#0 - sofianeOuafir
2022-04-15T14:23:31Z
duplicate of #9
93.9847 USDC - $93.98
https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/core-contracts/contracts/CoreCollection.sol#L193 https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/splits/contracts/SplitFactory.sol#L60-L61 https://github.com/code-423n4/2022-03-joyn/blob/c9297ccd925ebb2c44dbc6eaa3effd8db5d2368a/royalty-vault/contracts/RoyaltyVault.sol#L76
There are several input addresses that should be verified != address(0). Most notably, the royaltyVault and platformFeeRecipient.
In the event that royaltyAsset
gives control on transfer such as with an ERC777, a malicious platformFeeRecipient
will have the power to stop all executions of sendToSplitter()
The transferSplitAsset()
function contains comments about sending ETH, and the event that is emitted is called TransferETH
despite only ERC20 transfers.
Since attemptETHTransfer()
is private and not used in the contract, it can safely be removed.
Code style best practice.
The function reverts if transfer fails, so bool in event will always be true.
#0 - sofianeOuafir
2022-04-15T16:12:36Z
high quality report