177 lines
5.9 KiB
Solidity
177 lines
5.9 KiB
Solidity
pragma solidity 0.8.20;
|
|
|
|
import {Test} from "forge-std/Test.sol";
|
|
|
|
import {Ghost} from "../../src/GhstERC20.sol";
|
|
import {Stinky} from "../../src/StinkyERC20.sol";
|
|
import {GhostAuthority} from "../../src/GhostAuthority.sol";
|
|
import {GhostStaking} from "../../src/Staking.sol";
|
|
|
|
import {ERC20PermitTest} from "./Permit.t.sol";
|
|
import {ERC20AllowanceTest} from "./Allowance.t.sol";
|
|
import {ERC20TransferTest} from "./Transfer.t.sol";
|
|
import {ERC20VotesTest} from "./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 MAX_AMOUNT = type(uint256).max;
|
|
|
|
string constant NAME = "Ghost Test Name";
|
|
string constant SYMBOL = "GHSTTST";
|
|
|
|
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, "Stinky", "STNK");
|
|
ghst = new Ghost(address(stnk), NAME, SYMBOL);
|
|
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, MAX_AMOUNT);
|
|
initializeAllowance(ALICE, BOB, address(ghst), AMOUNT, MAX_AMOUNT, AMOUNT);
|
|
initializeTransfer(ALICE, BOB, address(ghst), AMOUNT, MAX_AMOUNT);
|
|
initializeVotes(ALICE, BOB, address(ghst), AMOUNT);
|
|
}
|
|
|
|
function test_isConstructedCorrectly() public view {
|
|
assertEq(ghst.name(), NAME);
|
|
assertEq(ghst.symbol(), SYMBOL);
|
|
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);
|
|
}
|
|
|
|
function _getCurrentTotalSupply() internal override view returns (uint256) {
|
|
return ghst.totalSupply();
|
|
}
|
|
}
|