ghost-dao-contracts/test/treasury/Treasury.t.sol
Uncle Fatso 8ac8b67767
get rid of annoying foundry warnings
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2026-03-09 00:37:41 +03:00

326 lines
13 KiB
Solidity

pragma solidity 0.8.20;
import {Test} from "forge-std/Test.sol";
import {Fatso} from "../../src/FatsoERC20.sol";
import {GhostAuthority} from "../../src/GhostAuthority.sol";
import {GhostTreasury} from "../../src/Treasury.sol";
import {GhostBondingCalculator} from "../../src/StandardBondingCalculator.sol";
import {ERC20Mock} from "../../src/mocks/ERC20Mock.sol";
import {ITreasury} from "../../src/interfaces/ITreasury.sol";
import {IUniswapV2Pair} from "@uniswap-v2-core/interfaces/IUniswapV2Pair.sol";
contract GhostTreasuryTest is Test {
address public constant OWNER = 0x0000000000000000000000000000000000000001;
address public constant GOVERNOR = 0x0000000000000000000000000000000000000002;
address public constant GUARDIAN = 0x0000000000000000000000000000000000000003;
address public constant ALICE = 0x0000000000000000000000000000000000000004;
uint256 public constant AMOUNT = 69 * 1e18;
Fatso ftso;
ERC20Mock reserve;
ERC20Mock liquidity;
GhostTreasury treasury;
GhostAuthority authority;
GhostBondingCalculator calculator;
function setUp() public {
vm.startPrank(OWNER);
authority = new GhostAuthority(
GOVERNOR,
GUARDIAN,
OWNER,
OWNER
);
reserve = new ERC20Mock("Reserve Token", "RET");
liquidity = new ERC20Mock("Liquidity Token", "LDT");
ftso = new Fatso(address(authority), "Fatso", "FTSO");
treasury = new GhostTreasury(address(ftso), 69, address(authority));
calculator = new GhostBondingCalculator(address(ftso), 1, 1);
vm.stopPrank();
vm.prank(GOVERNOR);
authority.pushVault(address(treasury));
vm.startPrank(ALICE);
reserve.mint(ALICE, AMOUNT);
reserve.approve(address(treasury), type(uint256).max);
ftso.approve(address(treasury), type(uint256).max);
vm.stopPrank();
}
function test_deposit_onlyIfApprovedTokenAndApprovedAddress() public {
vm.expectRevert();
vm.prank(ALICE);
treasury.deposit(address(reserve), AMOUNT, 0);
vm.prank(GOVERNOR);
treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0));
vm.expectRevert();
vm.prank(ALICE);
treasury.deposit(address(reserve), AMOUNT, 0);
vm.prank(GOVERNOR);
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
vm.prank(ALICE);
uint256 send = treasury.deposit(address(reserve), AMOUNT, 0);
assertEq(ftso.balanceOf(ALICE), send);
assertEq(reserve.balanceOf(address(treasury)), AMOUNT);
}
function test_withdraw_onlyIfApprovedTokenAndApprovedAddress() public {
vm.startPrank(GOVERNOR);
treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0));
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
vm.stopPrank();
vm.prank(ALICE);
treasury.deposit(address(reserve), AMOUNT, 0);
vm.expectRevert();
vm.prank(ALICE);
treasury.withdraw(address(reserve), AMOUNT);
vm.prank(GOVERNOR);
treasury.enable(ITreasury.STATUS.RESERVESPENDER, ALICE, address(0));
vm.prank(ALICE);
treasury.withdraw(address(reserve), AMOUNT);
assertEq(ftso.balanceOf(ALICE), 0);
assertEq(reserve.balanceOf(address(treasury)), 0);
}
function test_manage_onlyIfApprovedTokenAndApprovedAddress() public {
vm.startPrank(GOVERNOR);
treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0));
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
vm.stopPrank();
uint256 tokenValue = treasury.tokenValue(address(reserve), AMOUNT);
vm.prank(ALICE);
uint256 send = treasury.deposit(address(reserve), AMOUNT, tokenValue);
vm.expectRevert();
vm.prank(ALICE);
treasury.manage(address(reserve), AMOUNT);
vm.prank(GOVERNOR);
treasury.enable(ITreasury.STATUS.RESERVEMANAGER, ALICE, address(0));
vm.prank(ALICE);
treasury.manage(address(reserve), AMOUNT);
assertEq(ftso.balanceOf(ALICE), send);
assertEq(reserve.balanceOf(ALICE), AMOUNT);
assertEq(reserve.balanceOf(address(treasury)), 0);
}
function test_mint_onlyIfApprovedTokenAndApprovedAddress() public {
vm.startPrank(GOVERNOR);
treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0));
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
vm.stopPrank();
uint256 tokenValue = treasury.tokenValue(address(reserve), AMOUNT);
vm.prank(ALICE);
uint256 send = treasury.deposit(address(reserve), AMOUNT, tokenValue);
vm.expectRevert();
vm.prank(ALICE);
treasury.mint(ALICE, 69);
vm.prank(GOVERNOR);
treasury.enable(ITreasury.STATUS.REWARDMANAGER, ALICE, address(0));
vm.prank(ALICE);
treasury.mint(ALICE, 69);
assertEq(ftso.balanceOf(ALICE), send + 69);
assertEq(reserve.balanceOf(address(treasury)), AMOUNT);
}
function test_auditTreasuryReserves() public {
vm.startPrank(GOVERNOR);
treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0));
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
vm.stopPrank();
uint256 tokenValue = treasury.tokenValue(address(reserve), AMOUNT);
vm.prank(ALICE);
treasury.deposit(address(reserve), AMOUNT, tokenValue);
vm.prank(GOVERNOR);
treasury.auditReserves();
assertEq(treasury.permissions(ITreasury.STATUS.RESERVETOKEN, address(reserve)), true);
assertEq(treasury.registry(ITreasury.STATUS.RESERVETOKEN, 0), address(reserve));
assertEq(
treasury.tokenValue(address(reserve), reserve.balanceOf(address(treasury))),
treasury.totalReserves());
}
function test_randomAddressCouldNotEnableStatusAndCalculator(address who) public {
vm.assume(who != GOVERNOR);
vm.expectRevert();
vm.prank(who);
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(0));
vm.expectRevert();
vm.prank(who);
treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, address(liquidity), address(calculator));
vm.expectRevert();
vm.prank(who);
treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, msg.sender, address(0));
}
function test_enableStatusAndCalculator() public {
vm.startPrank(GOVERNOR);
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, address(liquidity), address(calculator));
treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, msg.sender, address(0));
vm.stopPrank();
assertEq(treasury.registry(ITreasury.STATUS.RESERVETOKEN, 0), address(reserve));
assertEq(treasury.registry(ITreasury.STATUS.LIQUIDITYTOKEN, 0), address(liquidity));
assertEq(treasury.bondCalculator(address(liquidity)), address(calculator));
vm.expectRevert();
treasury.registry(ITreasury.STATUS.RESERVEDEPOSITOR, 0);
assertEq(treasury.permissions(ITreasury.STATUS.RESERVETOKEN, address(reserve)), true);
assertEq(treasury.permissions(ITreasury.STATUS.LIQUIDITYTOKEN, address(liquidity)), true);
assertEq(treasury.permissions(ITreasury.STATUS.RESERVEDEPOSITOR, msg.sender), true);
}
function test_randomAddressCouldNotDisableStatusByAddress(address who) public {
vm.assume(who != GOVERNOR && who != GUARDIAN);
vm.startPrank(GOVERNOR);
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, address(liquidity), address(calculator));
treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, msg.sender, address(0));
vm.stopPrank();
vm.expectRevert();
vm.prank(who);
treasury.disable(ITreasury.STATUS.RESERVETOKEN, address(reserve));
vm.expectRevert();
vm.prank(who);
treasury.disable(ITreasury.STATUS.LIQUIDITYTOKEN, address(liquidity));
vm.expectRevert();
vm.prank(who);
treasury.disable(ITreasury.STATUS.RESERVEDEPOSITOR, msg.sender);
}
function test_disableStatusByAddress() public {
vm.startPrank(GOVERNOR);
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, address(liquidity), address(calculator));
treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, msg.sender, address(0));
vm.stopPrank();
vm.startPrank(GOVERNOR);
treasury.disable(ITreasury.STATUS.RESERVETOKEN, address(reserve));
treasury.disable(ITreasury.STATUS.LIQUIDITYTOKEN, address(liquidity));
treasury.disable(ITreasury.STATUS.RESERVEDEPOSITOR, msg.sender);
vm.stopPrank();
assertEq(treasury.permissions(ITreasury.STATUS.RESERVETOKEN, address(reserve)), false);
assertEq(treasury.permissions(ITreasury.STATUS.LIQUIDITYTOKEN, address(liquidity)), false);
assertEq(treasury.permissions(ITreasury.STATUS.RESERVEDEPOSITOR, msg.sender), false);
}
function test_mainnet_disableReserveAndLiquidity() public {
address realDexPair = 0xB20bd5D04BE54f870D5C0d3cA85d82b34B836405;
vm.startPrank(GOVERNOR);
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, realDexPair, address(calculator));
vm.stopPrank();
assertEq(treasury.tokenValue(address(reserve), 1e18), 1e9);
(uint256 reserve0, uint256 reserve1,) = IUniswapV2Pair(realDexPair).getReserves();
uint256 reserves = reserve0 * reserve1 / 1e6;
uint256 reserveEps = reserves * 1e5 / 1e7; // 1%
uint256 totalSupply = IUniswapV2Pair(realDexPair).totalSupply();
uint256 liquidityValue = (treasury.tokenValue(realDexPair, totalSupply) / 2)**2;
assertEq(liquidityValue + reserveEps >= reserves, true);
assertEq(liquidityValue - reserveEps <= reserves, true);
vm.startPrank(GOVERNOR);
treasury.disable(ITreasury.STATUS.RESERVETOKEN, address(reserve));
treasury.disable(ITreasury.STATUS.LIQUIDITYTOKEN, realDexPair);
vm.stopPrank();
assertEq(treasury.tokenValue(address(reserve), 1e18), 0);
assertEq(treasury.tokenValue(realDexPair, 1e18), 0);
}
function test_mainnet_tokenValueIsCorret() public {
address realDexPair = 0xB20bd5D04BE54f870D5C0d3cA85d82b34B836405;
vm.startPrank(GOVERNOR);
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, realDexPair, address(calculator));
vm.stopPrank();
assertEq(treasury.tokenValue(address(reserve), 1e18), 1e9);
(uint256 reserve0, uint256 reserve1,) = IUniswapV2Pair(realDexPair).getReserves();
uint256 reserves = reserve0 * reserve1 / 1e6;
uint256 reserveEps = reserves * 1e5 / 1e7; // 1%
uint256 totalSupply = IUniswapV2Pair(realDexPair).totalSupply();
uint256 liquidityValue = (treasury.tokenValue(realDexPair, totalSupply) / 2)**2;
assertEq(liquidityValue + reserveEps >= reserves, true);
assertEq(liquidityValue - reserveEps <= reserves, true);
}
function test_randomAddressCouldNotTriggerTimelock(address who) public {
vm.assume(who != GOVERNOR);
vm.expectRevert();
vm.prank(who);
treasury.toggleTimelock();
}
function test_triggerTimelock() public {
assertEq(treasury.timelockEnabled(), false);
assertEq(treasury.onChainGovernanceTimelock(), 0);
vm.prank(GOVERNOR);
treasury.toggleTimelock();
uint256 queuedTime = block.number + 69 * 7;
assertEq(treasury.timelockEnabled(), false);
assertEq(treasury.onChainGovernanceTimelock(), queuedTime);
vm.roll(queuedTime + 1);
vm.prank(GOVERNOR);
treasury.toggleTimelock();
assertEq(treasury.timelockEnabled(), true);
assertEq(treasury.onChainGovernanceTimelock(), 0);
vm.prank(GOVERNOR);
treasury.toggleTimelock();
queuedTime = block.number + 69 * 7;
assertEq(treasury.timelockEnabled(), true);
assertEq(treasury.onChainGovernanceTimelock(), queuedTime);
vm.roll(queuedTime + 1);
vm.prank(GOVERNOR);
treasury.toggleTimelock();
assertEq(treasury.timelockEnabled(), false);
assertEq(treasury.onChainGovernanceTimelock(), 0);
}
}