-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG] _refund function can drain the contract #13
Comments
Thanks for raising the issue. Originally the contract calculates the refundable amount from On the implementation contract, you should pass the pricePaid per token each time. I will try to reproduce the issue you have. Thanks again :) |
Hi @ramyhhh , Could you post the implementation contract snippet ? I'd like to see how it's call the mint function. Will |
Hi @0xwil contract TEST721RA is ERC721RA {
uint256 private constant _mintPrice = 1 ether;
constructor() ERC721RA("TEST", "TST",block.timestamp + (1 days)) {}
function mint(uint256 amount) external payable {
require(msg.value >= _mintPrice,"PAY_MINT_PRICE");
_safeMint(msg.sender, amount, msg.value);
}
function withdraw() public onlyOwner {
_withdraw(msg.sender);
}
function refund(uint256 tokenId) public {
_refund(msg.sender,tokenId);
}
function tvl() external view returns (uint256) {
return address(this).balance;
}
} |
Hi @ramyhhh , I see the problem.
Try the following:
|
I see your point, however I still think that it's pretty risky not to check the refund value and protect against over refund. |
Reproduce scenario
The bug can be repreduced by following the steps:
A
mints10
tokens (sendingx
amount to the contract and owing0
to9
ids)V
also mints10
tokensA
can_refund
for token0
and gets the amountx
transferred backA
can_refund
for token1
and also gets the amountx
transferred (out of whatV
sent)A
keep calling_refund
as long as they have tokens in their balance and the contract has ethers.This screenshot shows how I got more than the original 100 ethers in the first address draining the contract.
The problem
The problem is complex, it starts from the fact that
pricePaid
function is returning the whole value sent in transaction regardless of the amount of tokens minted while it should returnmsg.value / amount
(per slot).Also
_refund
is not checking against the amount refunded (which should always be 100% the same as paid price). Therefore,_refund
should track amount of refunded per token and compare against the total refunded amount.Solution
Edit ONE
Fix
_safeMint
to return the amount sent per token. ex:Edit TWO
Currently
_refund
tracks token by boolean flag like:It should instead track by setting the
refundAmount
and check for amount like
Notes
I haven't put more thoughts in the solutions, but at least bringing the issue onto the radar for now.
The text was updated successfully, but these errors were encountered: