mirror of
https://github.com/logos-messaging/logos-messaging-rlnv2-contract.git
synced 2026-02-19 21:33:09 +00:00
Add mintWithEth function to TST to burn Eth
This commit is contained in:
parent
9be52113b8
commit
0ea8e1d7a9
@ -12,6 +12,8 @@ import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils
|
||||
error AccountNotMinter();
|
||||
error AccountAlreadyMinter();
|
||||
error AccountNotInMinterList();
|
||||
error InsufficientETH();
|
||||
error ETHTransferFailed();
|
||||
|
||||
contract TestStableToken is
|
||||
Initializable,
|
||||
@ -24,6 +26,7 @@ contract TestStableToken is
|
||||
|
||||
event MinterAdded(address indexed account);
|
||||
event MinterRemoved(address indexed account);
|
||||
event ETHBurned(uint256 amount, address indexed minter, address indexed to, uint256 tokensMinted);
|
||||
|
||||
modifier onlyOwnerOrMinter() {
|
||||
if (msg.sender != owner() && !isMinter[msg.sender]) revert AccountNotMinter();
|
||||
@ -58,6 +61,18 @@ contract TestStableToken is
|
||||
function mint(address to, uint256 amount) external onlyOwnerOrMinter {
|
||||
_mint(to, amount);
|
||||
}
|
||||
|
||||
function mintWithETH(address to, uint256 amount) external payable {
|
||||
if (msg.value == 0) revert InsufficientETH();
|
||||
|
||||
// Burn ETH by sending to zero address
|
||||
(bool success,) = payable(address(0)).call{ value: msg.value }("");
|
||||
if (!success) revert ETHTransferFailed();
|
||||
|
||||
_mint(to, amount);
|
||||
|
||||
emit ETHBurned(msg.value, msg.sender, to, amount);
|
||||
}
|
||||
}
|
||||
|
||||
contract TestStableTokenFactory is BaseScript {
|
||||
|
||||
@ -2,7 +2,14 @@
|
||||
pragma solidity >=0.8.19 <0.9.0;
|
||||
|
||||
import { Test } from "forge-std/Test.sol";
|
||||
import { TestStableToken, AccountNotMinter, AccountAlreadyMinter, AccountNotInMinterList } from "./TestStableToken.sol";
|
||||
import {
|
||||
TestStableToken,
|
||||
AccountNotMinter,
|
||||
AccountAlreadyMinter,
|
||||
AccountNotInMinterList,
|
||||
InsufficientETH,
|
||||
ETHTransferFailed
|
||||
} from "./TestStableToken.sol";
|
||||
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
|
||||
import { DeployTokenWithProxy } from "../script/DeployTokenWithProxy.s.sol";
|
||||
|
||||
@ -51,6 +58,9 @@ contract TestStableTokenTest is Test {
|
||||
function test__OwnerCanMintWithoutMinterRole() external {
|
||||
uint256 mintAmount = 1000 ether;
|
||||
|
||||
// Owner is not in minter role but should still be able to mint
|
||||
assertFalse(token.isMinter(owner));
|
||||
|
||||
vm.prank(owner);
|
||||
token.mint(user1, mintAmount);
|
||||
|
||||
@ -134,16 +144,6 @@ contract TestStableTokenTest is Test {
|
||||
token.mint(user2, mintAmount);
|
||||
}
|
||||
|
||||
function test__OwnerCanAlwaysMintEvenWithoutMinterRole() external {
|
||||
uint256 mintAmount = 500 ether;
|
||||
|
||||
// Owner is not in minter role but should still be able to mint
|
||||
assertFalse(token.isMinter(owner));
|
||||
vm.prank(owner);
|
||||
token.mint(user1, mintAmount);
|
||||
assertEq(token.balanceOf(user1), mintAmount);
|
||||
}
|
||||
|
||||
function test__CheckMinterRoleMapping() external {
|
||||
assertFalse(token.isMinter(user1));
|
||||
assertFalse(token.isMinter(user2));
|
||||
@ -164,24 +164,6 @@ contract TestStableTokenTest is Test {
|
||||
assertTrue(token.isMinter(user2));
|
||||
}
|
||||
|
||||
function test__ERC20BasicFunctionality() external {
|
||||
vm.prank(owner);
|
||||
token.addMinter(user1);
|
||||
uint256 mintAmount = 1000 ether;
|
||||
|
||||
vm.prank(user1);
|
||||
token.mint(user2, mintAmount);
|
||||
|
||||
assertEq(token.balanceOf(user2), mintAmount);
|
||||
assertEq(token.totalSupply(), mintAmount);
|
||||
|
||||
vm.prank(user2);
|
||||
assertTrue(token.transfer(owner, 200 ether));
|
||||
|
||||
assertEq(token.balanceOf(user2), 800 ether);
|
||||
assertEq(token.balanceOf(owner), 200 ether);
|
||||
}
|
||||
|
||||
function test__MinterAddedEventEmitted() external {
|
||||
vm.expectEmit(true, true, false, false);
|
||||
emit MinterAdded(user1);
|
||||
@ -203,4 +185,104 @@ contract TestStableTokenTest is Test {
|
||||
|
||||
event MinterAdded(address indexed account);
|
||||
event MinterRemoved(address indexed account);
|
||||
event ETHBurned(uint256 amount, address indexed minter, address indexed to, uint256 tokensMinted);
|
||||
|
||||
// New tests for ETH burning functionality
|
||||
function test__MintRequiresETH() external {
|
||||
uint256 mintAmount = 1000 ether;
|
||||
|
||||
vm.prank(owner);
|
||||
vm.expectRevert(abi.encodeWithSelector(InsufficientETH.selector));
|
||||
token.mintWithETH(user1, mintAmount);
|
||||
}
|
||||
|
||||
function test__ERC20BasicFunctionality() external {
|
||||
uint256 mintAmount = 1000 ether;
|
||||
uint256 ethAmount = 0.1 ether;
|
||||
|
||||
vm.deal(user1, ethAmount);
|
||||
vm.prank(user1);
|
||||
token.mintWithETH{ value: ethAmount }(user2, mintAmount);
|
||||
|
||||
assertEq(token.balanceOf(user2), mintAmount);
|
||||
assertEq(token.totalSupply(), mintAmount);
|
||||
|
||||
vm.prank(user2);
|
||||
assertTrue(token.transfer(owner, 200 ether));
|
||||
|
||||
assertEq(token.balanceOf(user2), 800 ether);
|
||||
assertEq(token.balanceOf(owner), 200 ether);
|
||||
}
|
||||
|
||||
function test__ETHBurnedEventEmitted() external {
|
||||
uint256 mintAmount = 1000 ether;
|
||||
uint256 ethAmount = 0.1 ether;
|
||||
|
||||
vm.deal(owner, ethAmount);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit ETHBurned(ethAmount, owner, user1, mintAmount);
|
||||
|
||||
vm.prank(owner);
|
||||
token.mintWithETH{ value: ethAmount }(user1, mintAmount);
|
||||
}
|
||||
|
||||
function test__ETHIsBurnedToZeroAddress() external {
|
||||
uint256 mintAmount = 1000 ether;
|
||||
uint256 ethAmount = 0.1 ether;
|
||||
address zeroAddress = address(0);
|
||||
|
||||
uint256 zeroBalanceBefore = zeroAddress.balance;
|
||||
|
||||
vm.deal(owner, ethAmount);
|
||||
vm.prank(owner);
|
||||
token.mintWithETH{ value: ethAmount }(user1, mintAmount);
|
||||
|
||||
// ETH should be burned to zero address
|
||||
assertEq(zeroAddress.balance, zeroBalanceBefore + ethAmount);
|
||||
}
|
||||
|
||||
function test__ContractDoesNotHoldETHAfterMint() external {
|
||||
uint256 mintAmount = 1000 ether;
|
||||
uint256 ethAmount = 0.1 ether;
|
||||
|
||||
uint256 contractBalanceBefore = address(token).balance;
|
||||
|
||||
vm.deal(owner, ethAmount);
|
||||
vm.prank(owner);
|
||||
token.mintWithETH{ value: ethAmount }(user1, mintAmount);
|
||||
|
||||
// Contract should not hold any ETH after mint
|
||||
assertEq(address(token).balance, contractBalanceBefore);
|
||||
}
|
||||
|
||||
function test__MintWithDifferentETHAmounts() external {
|
||||
uint256 mintAmount = 1000 ether;
|
||||
uint256[] memory ethAmounts = new uint256[](3);
|
||||
ethAmounts[0] = 0.01 ether;
|
||||
ethAmounts[1] = 1 ether;
|
||||
ethAmounts[2] = 10 ether;
|
||||
|
||||
for (uint256 i = 0; i < ethAmounts.length; i++) {
|
||||
address user = vm.addr(i + 10);
|
||||
vm.deal(owner, ethAmounts[i]);
|
||||
|
||||
vm.expectEmit(true, true, true, true);
|
||||
emit ETHBurned(ethAmounts[i], owner, user, mintAmount);
|
||||
|
||||
vm.prank(owner);
|
||||
token.mintWithETH{ value: ethAmounts[i] }(user, mintAmount);
|
||||
|
||||
assertEq(token.balanceOf(user), mintAmount);
|
||||
}
|
||||
}
|
||||
|
||||
function test__CannotMintWithZeroETH() external {
|
||||
uint256 mintAmount = 1000 ether;
|
||||
|
||||
// Anyone can call mintWithETH (public function), but it requires ETH
|
||||
vm.prank(user1);
|
||||
vm.expectRevert(abi.encodeWithSelector(InsufficientETH.selector));
|
||||
token.mintWithETH{ value: 0 }(user2, mintAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@ -634,6 +634,48 @@ contract WakuRlnV2Test is Test {
|
||||
}
|
||||
}
|
||||
|
||||
function test__NonMinterCanMintWithETHAndRegister() external {
|
||||
uint256 idCommitment = 123;
|
||||
uint32 membershipRateLimit = w.minMembershipRateLimit();
|
||||
address nonMinter = vm.addr(999);
|
||||
|
||||
// Calculate required token amount for membership
|
||||
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
|
||||
uint256 ethAmount = price; // Use same amount of ETH as token price needed
|
||||
|
||||
// Verify nonMinter is not a minter
|
||||
assertFalse(token.isMinter(nonMinter));
|
||||
|
||||
// Non-minter uses mintWithETH to get tokens needed for membership
|
||||
vm.deal(nonMinter, ethAmount);
|
||||
vm.prank(nonMinter);
|
||||
token.mintWithETH{ value: ethAmount }(nonMinter, price);
|
||||
|
||||
// Verify tokens were minted
|
||||
assertEq(token.balanceOf(nonMinter), price);
|
||||
|
||||
// Non-minter approves and registers for membership
|
||||
vm.startPrank(nonMinter);
|
||||
token.approve(address(w), price);
|
||||
w.register(idCommitment, membershipRateLimit, noIdCommitmentsToErase);
|
||||
vm.stopPrank();
|
||||
|
||||
// Verify successful registration
|
||||
assertTrue(w.isInMembershipSet(idCommitment));
|
||||
(uint32 fetchedRateLimit, uint32 index, uint256 rateCommitment) = w.getMembershipInfo(idCommitment);
|
||||
assertEq(fetchedRateLimit, membershipRateLimit);
|
||||
assertEq(index, 0);
|
||||
assertNotEq(rateCommitment, 0);
|
||||
|
||||
// Verify membership holder is the non-minter
|
||||
(,,,,,, address holder,) = w.memberships(idCommitment);
|
||||
assertEq(holder, nonMinter);
|
||||
|
||||
// Verify tokens were transferred to membership contract
|
||||
assertEq(token.balanceOf(address(w)), price);
|
||||
assertEq(token.balanceOf(nonMinter), 0);
|
||||
}
|
||||
|
||||
function test__WithdrawToken(uint32 membershipRateLimit) external {
|
||||
vm.pauseGasMetering();
|
||||
uint256 idCommitment = 2;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user