287 lines
11 KiB
Solidity
287 lines
11 KiB
Solidity
pragma solidity 0.8.20;
|
|
|
|
import {Test} from "forge-std/Test.sol";
|
|
|
|
import "../../src/FatsoERC20.sol";
|
|
import "../../src/GhostAuthority.sol";
|
|
import "../../src/Treasury.sol";
|
|
import "../../src/StandardBondingCalculator.sol";
|
|
import "../../src/mocks/ERC20Mock.sol";
|
|
|
|
contract GhostTreasuryTest is Test {
|
|
address public constant owner = 0x0000000000000000000000000000000000000001;
|
|
address public constant governor = 0x0000000000000000000000000000000000000002;
|
|
address public constant guardian = 0x0000000000000000000000000000000000000003;
|
|
address public constant other = 0x0000000000000000000000000000000000000004;
|
|
address public constant alice = 0x0000000000000000000000000000000000000005;
|
|
address public constant bob = 0x0000000000000000000000000000000000000006;
|
|
|
|
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));
|
|
treasury = new GhostTreasury(address(ftso), 69, address(authority));
|
|
calculator = new GhostBondingCalculator(address(ftso));
|
|
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(0));
|
|
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(0));
|
|
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(0));
|
|
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(0));
|
|
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(0));
|
|
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(0));
|
|
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(0));
|
|
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(0));
|
|
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_tokenValueIsCorret() public {
|
|
vm.startPrank(governor);
|
|
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(0));
|
|
treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, 0xB20bd5D04BE54f870D5C0d3cA85d82b34B836405, address(calculator));
|
|
vm.stopPrank();
|
|
|
|
assertEq(treasury.tokenValue(address(reserve), 1e18), 1e9);
|
|
assertEq(treasury.tokenValue(address(liquidity), 1e18), 1e9);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|