Platform: Code4rena
Start Date: 07/07/2022
Pot Size: $75,000 USDC
Total HM: 32
Participants: 141
Period: 7 days
Judge: HardlyDifficult
Total Solo HM: 4
Id: 144
League: ETH
Rank: 49/141
Findings: 2
Award: $194.14
🌟 Selected for report: 0
🚀 Solo Findings: 0
https://github.com/code-423n4/2022-07-fractional/blob/e2c5a962a94106f9495eb96769d7f60f7d5b14c9/src/FERC1155.sol#L247 https://github.com/code-423n4/2022-07-fractional/blob/e2c5a962a94106f9495eb96769d7f60f7d5b14c9/src/FERC1155.sol#L222
Function setRoyalties does not check that the value of _percentage is less or equal to 100. Function royaltyInfo in L247 could return a royaltyAmount greater than _salePrice.
This simple test shows how the controller can set a value of percentage greater than 100%:
// SPDX-License-Identifier: Unlicense pragma solidity 0.8.13; import "./TestUtil.sol"; contract FERC1155Test is TestUtil { string tokenURI = "token uri"; string contractURI = "contract uri"; event URI(string value, uint256 indexed id); /// ================= /// ===== SETUP ===== /// ================= function setUp() public { setUpContract(); alice = setUpUser(111, 1); bob = setUpUser(222, 2); setUpCreateFor(alice); setUpMetadata(alice); vm.label(address(this), "FERC1155Test"); vm.label(alice.addr, "Alice"); vm.label(bob.addr, "Bob"); } /// ============================ /// ===== SET ROYALTIES ===== /// ============================ function testSetRoyalties() public { uint256 _id = 1; // We set a percentage of 150% uint256 _percentage = 150; uint256 _salePrice = 10000; // We expect a royalty amount greater that sale price (50% greater) uint256 _expectedRoyaltyAmount = 15000; (address receiver, uint256 royaltyAmount) = fERC1155.royaltyInfo(_id, _salePrice); // assert royalty amount is 0 before setting royalties assertEq(royaltyAmount, uint256(0)); // set royalties for token id 1 to 150% (beneficiary of royalties being Bob) fERC1155.setRoyalties(_id, bob.addr, _percentage); (receiver, royaltyAmount) = fERC1155.royaltyInfo(_id, _salePrice); // assert royalty amount is the expected amount assertEq(royaltyAmount, uint256(_expectedRoyaltyAmount)); } }
Forge
Consider adding a check in FERC1155.sol just before L222, in function setRoyalties, to check that _percentage <= 100. Some example implementations like this do exactly this.
#0 - 0x0aa0
2022-07-18T18:41:03Z
Duplicate of #166
🌟 Selected for report: xiaoming90
Also found by: 0x1f8b, 0x29A, 0x52, 0xA5DF, 0xDjango, 0xNazgul, 0xNineDec, 0xf15ers, 0xsanson, 0xsolstars, 242, 8olidity, Amithuddar, Aymen0909, Bnke0x0, BowTiedWardens, David_, Deivitto, ElKu, Funen, Hawkeye, IllIllI, JC, Kaiziron, Keen_Sheen, Kthere, Kulk0, Kumpa, Lambda, MEP, ReyAdmirado, Rohan16, Ruhum, Sm4rty, TomJ, Tomio, Treasure-Seeker, TrungOre, Tutturu, Viksaa39, Waze, _Adam, __141345__, ak1, apostle0x01, asutorufos, async, ayeslick, aysha, bbrho, benbaessler, berndartmueller, c3phas, cccz, chatch, cloudjunky, codexploder, cryptphi, delfin454000, dipp, durianSausage, dy, exd0tpy, fatherOfBlocks, hake, hansfriese, horsefacts, hubble, joestakey, jonatascm, kebabsec, kenzo, kyteg, mektigboy, neumo, oyc_109, pashov, pedr02b2, peritoflores, rajatbeladiya, rbserver, robee, rokinot, s3cunda, sach1r0, sahar, sashik_eth, scaraven, shenwilly, simon135, sorrynotsorry, sseefried, svskaushik, unforgiven, z3s, zzzitron
61.9379 USDC - $61.94
Changing critical addresses in contracts should be a two-step process where the first transaction (from the old/current address) registers the new address (i.e. grants ownership) and the second transaction (from the new address) replaces the old address with the new one (i.e. claims ownership). This gives an opportunity to recover from incorrect addresses mistakenly used in the first step. If not, contract functionality might become inaccessible:
Bad natspec comment @notice in FERC1155.sol L238
Bad natspec comment @param in FERC1155.sol L239
Missing @return natspec for values returned by functions:
Consider adding a check in FERC1155.sol just before L222, in function setRoyalties, to check that _receiver != address(0) if _percentage > 0
Missing zero address validation: transferOwnership (L95) in Vault.sol does not check if new owner is different from address(0). Setters of address type parameters should include a zero-address check otherwise contract functionality may become inaccessible.
In Vault.sol function install does not check that a selector is already present in the methods mapping. This could cause that, after calling install, some of the selectors of a preexisting plugin point to another plugin (the newly installed) while others still point to the correct plugin. This could lead to confusion. Consider reverting if trying to install a selector that is already pointing to a plugin (L79), so the only way to install it would be to first uninstall the plugin that causes the collision. There could also exist the option of redeploy the plugin that the user is trying to install but changing the colliding selectors to others that don't exist in the methods mapping.