Pieces Protocol

First Flight #32
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: high
Valid

ERC20 token can be minted by anyone

Summary

When the TokenDivider contract divide the ERC721 NFT, it deployed a new ERC20 Token address and then minted to the amount given to the divide function. But the problem is, ERC20 Token contract has vunlerability to be minted by anyone, since its mint function has no check toward who can mint.

Vulnerability Details

function mint(address _to, uint256 _amount) public {
_mint(_to, _amount);
}

as shown above, in the src/token/ERC20ToGenerateNftFraccion.sol the mint function has public modifier which means it can be called by anyone and has no validation through who can call the function, including the attacker.

Impact

this will cause confusion to the holders because there are ERC20 tokens that are registered in this contract and which are not (through self mint).

Tools Used

Foundry

function test_failWhen_reMintTheDividedERC20Token() public {
vm.startPrank(USER);
// approve the NFT to receive the NFT in USER
erc721Mock.approve(address(tokenDivider), TOKEN_ID);
tokenDivider.divideNft(
address(erc721Mock),
TOKEN_ID,
AMOUNT
);
vm.stopPrank();
ERC20Mock erc20Mock = ERC20Mock(
tokenDivider.getErc20InfoFromNft(address(erc721Mock)).erc20Address
);
// assert if USER has the ERC20 token
assertEq(
tokenDivider.getBalanceOf(USER, address(erc20Mock)),
AMOUNT
);
// attacker try to mint the ERC20
vm.startPrank(USER2);
erc20Mock.mint(address(USER2), AMOUNT);
vm.stopPrank();
assertEq(
tokenDivider.getBalanceOf(
USER,
address(erc20Mock)
),
AMOUNT
);
// this return false, because tokenDivider tracks its own minted ERC20
// but this will cause confusion to the holders
assertEq(
tokenDivider.getBalanceOf(
USER2,
address(erc20Mock)
),
erc20Mock.balanceOf(address(USER2))
);
assertEq(
erc20Mock.totalSupply(),
AMOUNT
);
}

Recommendations

Add owner logic to the ERC20ToGenerateNftFraccion to be like such:

contract ERC20ToGenerateNftFraccion is ERC20, ERC20Burnable {
address immutable owner; // we add immutable storage address variable of owner
error ERC20ToGenerateNftFraccion__NotOwner(); // we define the error
constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {
// we assign owner during construction by the sender of the deployer
owner = address(msg.sender);
}
function mint(address _to, uint256 _amount) public {
// we add logic to check msg sender toward owner, if not owner it will revert
if (address(msg.sender) != owner) {
revert ERC20ToGenerateNftFraccion__NotOwner();
}
_mint(_to, _amount);
}
}
Updates

Lead Judging Commences

fishy Lead Judge 9 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Lack of token access control chekcs

Any person can mint the ERC20 token generated in representation of the NFT

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.