Summary
Due to missing restriction on ERC20ToGenerateNftFraccion.sol
, anyone can mint from the deployed ERC20 when an NFT is divided causing the ERC20 to not have value and initial owner of the NFT to can't claim the NFT even though if he didn't intend to sell/transfer it's ERC20.
Vulnerability Details
When TokenDivider::divideNft
is used, a new ERC20 token is created
function divideNft(
address nftAddress,
uint256 tokenId,
uint256 amount
)
external
onlyNftOwner(nftAddress, tokenId)
onlyNftOwner(nftAddress, tokenId)
{
[...]
ERC20ToGenerateNftFraccion erc20Contract = new ERC20ToGenerateNftFraccion(
string(abi.encodePacked(ERC721(nftAddress).name(), "Fraccion")),
string(abi.encodePacked("F", ERC721(nftAddress).symbol()))
);
This token represents the shares of the Nft.
Though anyone can use the mint function in the newly created ERC20 and then get a share of the NFT as there is no restriction
function mint(address _to, uint256 _amount) public {
_mint(_to, _amount);
}
POC
function testAnyoneCanMintFromDeployedERC20(
address randomUser,
uint256 amount
) public nftDivided {
vm.assume(randomUser != USER && randomUser != address(0));
vm.assume(amount <= type(uint256).max - AMOUNT);
ERC20ToGenerateNftFraccion fraccionERC20 = ERC20ToGenerateNftFraccion(
tokenDivider.getErc20InfoFromNft(address(erc721Mock)).erc20Address
);
assertEq(
tokenDivider.getErc20TotalMintedAmount(address(fraccionERC20)),
AMOUNT
);
vm.prank(randomUser);
fraccionERC20.mint(randomUser, amount);
assertEq(fraccionERC20.balanceOf(randomUser), amount);
}
Impact
The user calling TokenDivider::divideNft
can instantly loose the ability to claim back its Nft even though he didn't intend to transfer or sell it's ERC20 shares
Anyone can sell ERC20 shares even without buying any share
Recommendations
Inherit from openzeppelin Ownable
and restrict the mint with onlyOwner
modifier
-contract ERC20ToGenerateNftFraccion is ERC20, ERC20Burnable {
+contract ERC20ToGenerateNftFraccion is ERC20, ERC20Burnable, Ownable {
constructor(
string memory _name,
string memory _symbol
- ) ERC20(_name, _symbol) {}
+ ) ERC20(_name, _symbol) Ownable{msg.sender}
- function mint(address _to, uint256 _amount) public {
+ function mint(address _to, uint256 _amount) public onlyOwner {
_mint(_to, _amount);
}
}