pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; import "../../src/GhstERC20.sol"; import "../../src/StinkyERC20.sol"; import "../../src/GhostAuthority.sol"; import "../../src/Staking.sol"; import "./Permit.t.sol"; import "./Allowance.t.sol"; import "./Transfer.t.sol"; import "./Votes.t.sol"; contract GhostTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferTest, ERC20VotesTest { uint256 constant public INITIAL_INDEX = 10819917194513808e56; address constant initializer = 0x0000000000000000000000000000000000000001; address constant alice = 0x0000000000000000000000000000000000000003; address constant bob = 0x0000000000000000000000000000000000000004; address constant treasury = 0x0000000000000000000000000000000000000005; uint256 constant amount = 69; uint256 constant maxAmount = type(uint256).max; Stinky stnk; Ghost ghst; GhostAuthority public authority; GhostStaking public staking; function setUp() public { vm.startPrank(initializer); authority = new GhostAuthority( initializer, initializer, initializer, initializer ); stnk = new Stinky(INITIAL_INDEX); ghst = new Ghost(address(stnk)); staking = new GhostStaking( address(0), address(stnk), address(ghst), 69, 1337, 1337, address(authority) ); stnk.initialize(address(staking), treasury, address(ghst)); ghst.initialize(address(staking)); vm.stopPrank(); initializePermit(address(ghst), amount, maxAmount); initializeAllowance(alice, bob, address(ghst), amount, maxAmount, amount); initializeTransfer(alice, bob, address(ghst), amount, 0); initializeVotes(alice, bob, address(ghst), amount); } function test_isConstructedCorrectly() public view { assertEq(ghst.name(), "Ghost"); assertEq(ghst.symbol(), "GHST"); assertEq(ghst.decimals(), 18); assertEq(ghst.staking(), address(staking)); assertEq(ghst.stnk(), address(stnk)); assertEq(ghst.index(), stnk.index()); } function test_mint_couldBeDoneByStaking() public { assertEq(ghst.totalSupply(), 0); vm.prank(address(staking)); ghst.mint(alice, amount); assertEq(ghst.totalSupply(), amount); assertEq(ghst.balanceOf(alice), amount); } function test_mint_couldNotFromArbitraryAddress(address who) public { vm.assume(who != address(staking)); vm.expectRevert(); vm.prank(who); ghst.mint(alice, amount); assertEq(ghst.totalSupply(), 0); assertEq(ghst.balanceOf(who), 0); } function test_burn_couldBeDoneByOwner() public { _mintTokens(alice, amount); assertEq(ghst.totalSupply(), amount); vm.prank(address(staking)); ghst.burn(alice, amount); assertEq(ghst.totalSupply(), 0); assertEq(ghst.balanceOf(alice), 0); } function test_burn_couldBeDoneByOwnerPartially(uint256 part) public { vm.assume(part <= amount); _mintTokens(alice, amount); assertEq(ghst.totalSupply(), amount); vm.prank(address(staking)); ghst.burn(alice, part); assertEq(ghst.totalSupply(), amount - part); assertEq(ghst.balanceOf(alice), amount - part); } function test_burn_couldNotBurnMoreThanBalance() public { _mintTokens(alice, amount); assertEq(ghst.totalSupply(), amount); vm.expectRevert(); vm.prank(alice); ghst.burn(alice, amount + 1); assertEq(ghst.totalSupply(), amount); assertEq(ghst.balanceOf(alice), amount); } function test_burn_couldNotFromArbitraryAddress(address who) public { vm.assume(who != address(staking)); _mintTokens(alice, amount); vm.expectRevert(); vm.prank(who); ghst.burn(alice, amount); assertEq(ghst.totalSupply(), amount); assertEq(ghst.balanceOf(alice), amount); } function test_balanceToCalculatesCorrectly(uint256 balanceToAmount) public view { vm.assume(balanceToAmount < type(uint128).max - 1); uint256 index = ghst.index(); assertEq(ghst.balanceTo(balanceToAmount), balanceToAmount * 1e18 / index); } function test_balanceFromCalculatesCorrectly(uint256 balanceFromAmount) public view { vm.assume(balanceFromAmount < type(uint128).max - 1); uint256 index = ghst.index(); assertEq(ghst.balanceFrom(balanceFromAmount), balanceFromAmount * index / 1e18); } function _mintTokens(address who, uint256 value) internal { uint256 totalSupply = ghst.totalSupply(); vm.prank(address(staking)); ghst.mint(who, value); assertEq(ghst.totalSupply(), totalSupply + value); } function _mintTransferTokens(address who, uint256 value) internal override { _mintTokens(who, value); } function _mintAllowanceTokens(address who, uint256 value) internal override { _mintTokens(who, value); } function _mintPermitTokens(address who, uint256 value) internal override { _mintTokens(who, value); } function _mintVotesTokens(address who, uint256 value) internal override { _mintTokens(who, value); } function _burnVotesTokens(address who, uint256 value) internal override { vm.prank(address(staking)); ghst.burn(who, value); } }