From 969d3ee22bbf0a36aa6d44ab9887d1a799d64a81 Mon Sep 17 00:00:00 2001 From: Tanya S <120410716+stubbsta@users.noreply.github.com> Date: Wed, 30 Jul 2025 08:51:26 +0200 Subject: [PATCH] chore: Add new test token with only owner mint (#28) * Add TestStableToken with only owner minting * Add tests for TestStableToken * Formatting * Use 'Ownable' for access control * fix linting --- test/TestStableToken.sol | 21 ++++++++++++++++++++ test/WakuRlnV2.t.sol | 41 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 test/TestStableToken.sol diff --git a/test/TestStableToken.sol b/test/TestStableToken.sol new file mode 100644 index 0000000..c546b4e --- /dev/null +++ b/test/TestStableToken.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.19 <0.9.0; + +import { BaseScript } from "../script/Base.s.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { ERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; +import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; + +contract TestStableToken is ERC20, ERC20Permit, Ownable { + constructor() ERC20("TestStableToken", "TST") ERC20Permit("TestStableToken") Ownable() { } + + function mint(address to, uint256 amount) external onlyOwner { + _mint(to, amount); + } +} + +contract TestStableTokenFactory is BaseScript { + function run() public broadcast returns (address) { + return address(new TestStableToken()); + } +} diff --git a/test/WakuRlnV2.t.sol b/test/WakuRlnV2.t.sol index 70f6927..9c6d7c7 100644 --- a/test/WakuRlnV2.t.sol +++ b/test/WakuRlnV2.t.sol @@ -7,7 +7,7 @@ import "../src/WakuRlnV2.sol"; // solhint-disable-line import "../src/Membership.sol"; // solhint-disable-line import { IPriceCalculator } from "../src/IPriceCalculator.sol"; import { LinearPriceCalculator } from "../src/LinearPriceCalculator.sol"; -import { TestToken } from "./TestToken.sol"; +import { TestStableToken } from "./TestStableToken.sol"; import { PoseidonT3 } from "poseidon-solidity/PoseidonT3.sol"; import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; @@ -16,21 +16,21 @@ import "forge-std/console.sol"; contract WakuRlnV2Test is Test { WakuRlnV2 internal w; - TestToken internal token; + TestStableToken internal token; address internal deployer; uint256[] internal noIdCommitmentsToErase = new uint256[](0); function setUp() public virtual { - token = new TestToken(); + token = new TestStableToken(); IPriceCalculator priceCalculator = (new DeployPriceCalculator()).deploy(address(token)); WakuRlnV2 wakuRlnV2 = (new DeployWakuRlnV2()).deploy(); ERC1967Proxy proxy = (new DeployProxy()).deploy(address(priceCalculator), address(wakuRlnV2)); w = WakuRlnV2(address(proxy)); - // Minting a large number of tokens to not have to worry about + // TestStableTokening a large number of tokens to not have to worry about // Not having enough balance token.mint(address(this), 100_000_000 ether); } @@ -763,6 +763,39 @@ contract WakuRlnV2Test is Test { } } + function test__TestStableToken__OnlyOwnerCanMint() external { + address nonOwner = vm.addr(1); + uint256 mintAmount = 1000 ether; + + vm.prank(nonOwner); + vm.expectRevert("Ownable: caller is not the owner"); + token.mint(nonOwner, mintAmount); + } + + function test__TestStableToken__OwnerMintsTransfersAndRegisters() external { + address recipient = vm.addr(2); + uint256 idCommitment = 3; + uint32 membershipRateLimit = w.minMembershipRateLimit(); + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); + + // Owner (test contract) mints tokens to recipient + token.mint(recipient, price); + assertEq(token.balanceOf(recipient), price); + + // Recipient uses tokens to register + vm.startPrank(recipient); + token.approve(address(w), price); + w.register(idCommitment, membershipRateLimit, noIdCommitmentsToErase); + vm.stopPrank(); + + // Verify registration succeeded + assertTrue(w.isInMembershipSet(idCommitment)); + (,,,, uint32 fetchedMembershipRateLimit, uint32 index, address holder,) = w.memberships(idCommitment); + assertEq(fetchedMembershipRateLimit, membershipRateLimit); + assertEq(holder, recipient); + assertEq(index, 0); + } + function test__Upgrade() external { address testImpl = address(new WakuRlnV2()); bytes memory data = abi.encodeCall(WakuRlnV2.initialize, (address(0), 100, 1, 10, 10 minutes, 4 minutes));