// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin-contracts/token/ERC20/extensions/ERC20Permit.sol"; contract Reserve is ERC20Permit { address private immutable _owner; uint256 public accumulatedDonation; uint256 public conversionRate; uint256 public donationRate; error OnlyOwner(); constructor( string memory name, string memory symbol, uint256 rate ) ERC20(name, symbol) ERC20Permit(name) { conversionRate = rate; _owner = msg.sender; } fallback() external payable { _innerMint(msg.sender, msg.value); } receive() external payable { _innerMint(msg.sender, msg.value); } function changeRate(uint256 rate) external { if (msg.sender != _owner) revert OnlyOwner(); conversionRate = rate; } function changeReminder(uint256 reminder) external { if (msg.sender != _owner) revert OnlyOwner(); donationRate = reminder; } function withdraw(address payable receiver) external { if (msg.sender != _owner) revert OnlyOwner(); (bool sent,) = receiver.call{ value: accumulatedDonation }(""); require(sent, "Failed to send Ether"); } function superMint(address account, uint256 value) external { if (msg.sender != _owner) revert OnlyOwner(); _innerMint(account, value); } function mint(address account) external payable { uint256 donation = msg.value * donationRate / 1e5; accumulatedDonation += donation; _mint(account, msg.value * conversionRate); } function burn(uint256 amount) external payable { _burn(msg.sender, amount); uint256 valueDiff = address(this).balance - accumulatedDonation; uint256 valueBack = amount * valueDiff / (amount + totalSupply()); (bool sent,) = msg.sender.call{ value: valueBack }(""); require(sent, "Failed to send Ether"); } function estimateAmount(uint256 amount) external view returns (uint256) { uint256 valueDiff = address(this).balance - accumulatedDonation; return amount * valueDiff / totalSupply(); } }