ghost-dao-contracts/test/gatekeeper/GatekeeperRecall.t.sol
Uncle Fatso 8d94ab0dd1
implement phantom refund after verification
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2026-09-10 14:16:14 +03:00

172 lines
7.6 KiB
Solidity

pragma solidity 0.8.20;
import {Test} from "forge-std/Test.sol";
import {Fatso} from "../../src/FatsoERC20.sol";
import {Stinky} from "../../src/StinkyERC20.sol";
import {Ghost} from "../../src/GhstERC20.sol";
import {GhostAuthority} from "../../src/GhostAuthority.sol";
import {GhostTreasury} from "../../src/Treasury.sol";
import {GhostStaking} from "../../src/Staking.sol";
import {WETH9} from "../../src/mocks/WETH9.sol";
import {GhostBondingCalculator} from "../../src/StandardBondingCalculator.sol";
import {Gatekeeper} from "../../src/Gatekeeper.sol";
import {ITreasury} from "../../src/interfaces/ITreasury.sol";
contract GatekeeperRecallTest is Test {
uint256 public constant TOTAL_INITIAL_SUPPLY = 5000000000000000;
uint256 public constant LARGE_APPROVAL = 100000000000000000000000000000000;
uint256 public constant INITIAL_INDEX = 10819917194513808e56;
uint48 public constant EPOCH_LENGTH = 2200;
uint48 public constant EPOCH_NUMBER = 1;
uint48 public constant EPOCH_END_TIME = 1337;
uint256 public constant INITIAL_MINT = 1000000000000000000000000;
uint256 public constant CAPACITY = 10000e9;
uint256 public constant INITIAL_PRICE = 400e9;
uint256 public constant BUFFER = 2e5;
address constant INITIALIZER = 0x0000000000000000000000000000000000000001;
address constant GOVERNOR = 0x0000000000000000000000000000000000000003;
address constant GUARDIAN = 0x0000000000000000000000000000000000000004;
address constant POLICY = 0x0000000000000000000000000000000000000005;
address constant VAULT = 0x0000000000000000000000000000000000000006;
address constant ALICE = 0x0000000000000000000000000000000000000007;
address constant BOB = 0x0000000000000000000000000000000000000008;
uint256 public constant VESTING = 100;
uint256 public constant TIME_TO_CONCLUSION = 60 * 60 * 24;
uint256 public constant DEPOSIT_INTERVAL = 60 * 60 * 4;
uint256 public constant TUNE_INTERVAL = 60 * 60;
Fatso ftso;
Stinky stnk;
Ghost ghst;
GhostStaking staking;
GhostTreasury treasury;
GhostAuthority authority;
GhostBondingCalculator calculator;
WETH9 reserve;
function setUp() public {
vm.startPrank(INITIALIZER, INITIALIZER);
reserve = new WETH9();
authority = new GhostAuthority(
GOVERNOR,
GUARDIAN,
POLICY,
VAULT
);
ftso = new Fatso(address(authority), "Fatso", "FTSO");
stnk = new Stinky(INITIAL_INDEX, "Stinky", "STNK");
ghst = new Ghost(address(stnk), "Ghost", "GHST");
staking = new GhostStaking(
address(ftso),
address(stnk),
address(ghst),
EPOCH_LENGTH,
EPOCH_NUMBER,
EPOCH_END_TIME,
address(authority)
);
treasury = new GhostTreasury(address(ftso), address(authority));
calculator = new GhostBondingCalculator(address(ftso), 6000, 3);
stnk.initialize(address(staking), address(treasury), address(ghst));
ghst.initialize(address(staking));
vm.stopPrank();
vm.startPrank(GOVERNOR);
authority.pushVault(address(treasury));
treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, ALICE, address(0));
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
treasury.enable(ITreasury.STATUS.STAKING, address(staking), address(0));
vm.stopPrank();
vm.deal(ALICE, INITIAL_MINT);
vm.startPrank(ALICE);
reserve.deposit{value: INITIAL_MINT}();
reserve.approve(address(treasury), type(uint256).max);
treasury.deposit(address(reserve), INITIAL_MINT, treasury.tokenValue(address(reserve), INITIAL_MINT) / 2);
assertEq(ftso.totalSupply(), treasury.baseSupply());
vm.stopPrank();
}
function test_recallChainWorks() public {
vm.startPrank(INITIALIZER);
Gatekeeper gatekeeper = Gatekeeper(payable(staking.gatekeeper()));
gatekeeper.updatePublicKeyMetadata(0, 0xb5cd0d028a5e1b6a4eecb113b7e49c8176385eb77c8f134bc1db4bddd7654de6, 0);
vm.stopPrank();
vm.startPrank(ALICE);
uint256 aliceBalance = ftso.balanceOf(ALICE);
ftso.approve(address(staking), type(uint256).max);
staking.stake(aliceBalance, ALICE, false, true);
uint256 ghostBalance = ghst.balanceOf(ALICE);
staking.ghost(bytes32(abi.encodePacked(ALICE)), ghostBalance);
vm.stopPrank();
uint256 actualAmount = 105000000000000000;
address actualReceiver = address(0x0000000000000000000000000000000000000002);
uint256 bobGhstBefore = ghst.balanceOf(BOB);
uint256 receiverEthBefore = actualReceiver.balance;
uint256 receiverGhstBefore = ghst.balanceOf(actualReceiver);
uint256 totalReservesBefore = treasury.totalReserves();
uint256 totalSupplyBefore = ftso.totalSupply();
uint256 ghostedSupplyBefore = gatekeeper.ghostedSupply();
vm.txGasPrice(2 gwei);
vm.startPrank(BOB, BOB);
gatekeeper.verify(
hex"bf06188a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000017508f1956a800000000000000000000000000000000000000000020000000000007a6980000000",
0x883302783b7f3d253d5bdeb17f39117641acdf061bf3fe457cb505df6b17dfc1,
0x8c3fc03b5cb738777ceec396ee8647f782d6670992f8f973de2dfc83379978d5
);
vm.stopPrank();
{
uint256 bobGhstAfter = ghst.balanceOf(BOB);
uint256 receiverGhstAfter = ghst.balanceOf(actualReceiver);
assertTrue(
ghst.balanceFrom(bobGhstAfter - bobGhstBefore) * totalReservesBefore / totalSupplyBefore
> gatekeeper.GAS_EXECUTION_BUFFER()
);
assertTrue(bobGhstAfter > bobGhstBefore);
assertApproxEqAbs(receiverGhstAfter - receiverGhstBefore, actualAmount / 2, 1e18);
}
{
uint256 ftsoAmount = ghst.balanceFrom(actualAmount / 2);
uint256 expectedReservesToSend = ftsoAmount * totalReservesBefore / totalSupplyBefore;
uint256 expectedEthRefund = expectedReservesToSend * 1e18 / calculator.fraction();
expectedEthRefund = expectedEthRefund * 1e18 / 1e9;
assertApproxEqAbs(actualReceiver.balance, receiverEthBefore + expectedEthRefund, 1);
}
{
actualAmount = treasury.tokenValue(address(reserve), actualReceiver.balance);
uint256 backingRatioBefore = totalReservesBefore * 1e18 / totalSupplyBefore;
uint256 backingRatioAfter = treasury.totalReserves() * 1e18 / ftso.totalSupply();
uint256 gasFtsoMinted = ghst.balanceFrom(ghst.balanceOf(BOB) - bobGhstBefore);
uint256 expectedDelta = (backingRatioBefore * gasFtsoMinted) / totalSupplyBefore;
assertApproxEqAbs(backingRatioAfter, backingRatioBefore - expectedDelta, 1000);
vm.prank(GOVERNOR);
treasury.auditReserves();
assertApproxEqAbs(treasury.totalReserves() * 1e18 / ftso.totalSupply(), backingRatioBefore - expectedDelta, 2000);
}
{
uint256 receiverGhstAfter = ghst.balanceOf(actualReceiver);
uint256 receiverImbalance = receiverGhstAfter - receiverGhstBefore;
assertEq(ghostedSupplyBefore - receiverImbalance, staking.ghostedSupply());
}
}
}