make the dream a reality; treasury buyBack added

Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
This commit is contained in:
Uncle Fatso 2026-09-06 16:58:29 +03:00
parent 2e35fb24c7
commit fe9f92281b
Signed by: f4ts0
GPG Key ID: 565F4F2860226EBB
20 changed files with 396 additions and 158 deletions

View File

@ -69,9 +69,6 @@ INITIAL_INDEX=
COEFFICIENT_NUMERATOR=
COEFFICIENT_DENOMINATOR=
## Blocks needed for permissions to take place, only needed if timelock enabled
BLOCKS_NEEDED_FOR_TREASURY_QUEUE=
## Multiplier for each native coin where result of multiplication represents amount
## of mint tokens.
RESERVE_MINT_RATE=
@ -105,10 +102,8 @@ GOVERNOR_PROPOSAL_THRESHOLD=
GOVERNOR_QUORUM_FRACTION=
###################### Initial ghosted supply on gatekeeper ###########################
## existential - minimum amount that could be reflected inside other chain ##
## previousWeaver - previous weaver address if any to make linked list of weavers ##
#######################################################################################
INITIAL_EXISTENTIAL_DEPOSIT=
PREVIOUS_WEAVER_ADDRESS=
SEPOLIA_TEST_RPC_URL=

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IWETH9} from "./interfaces/IWETH9.sol";
import {IStaking} from "./interfaces/IStaking.sol";
import {IGatekeeper} from "./interfaces/IGatekeeper.sol";
import {IStorageHistory} from "./interfaces/IStorageHistory.sol";
@ -24,10 +25,13 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
uint256 private constant SECP256K1_Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
uint256 private constant SHIFT_FACTOR = (2**128) % SECP256K1_N;
uint256 public constant GAS_RECALL_SPENDING = 329188;
uint256 public constant EXISTENTIAL_DEPOSIT = 500 * 1e12;
uint256 public constant REGISTRY_INDEX = 0;
address public override staking;
address public override deployer;
address public override storageHistory;
uint256 public override existentialDeposit;
address private _previousAddress;
bool private _initialized;
@ -35,16 +39,14 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
Checkpoints.Trace256 private _aggregatedPublicKeys;
mapping(bytes32 => uint256) private _packedRotationStates;
constructor(
uint256 _existentialDeposit,
address _storageHistory
) {
existentialDeposit = _existentialDeposit;
constructor(address _storageHistory) {
storageHistory = _storageHistory;
staking = msg.sender;
deployer = tx.origin;
}
receive() external payable {}
function initialize(address _previousGatekeeperAddress) external override {
if (_previousGatekeeperAddress != address(0)) {
require(_initialized == false);
@ -124,7 +126,7 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
function ghost(bytes32 receiver, uint256 amount) external override returns (uint256) {
if (msg.sender != staking) revert NotStaking();
if (amount < existentialDeposit) revert NonExistentAmount();
if (amount < EXISTENTIAL_DEPOSIT) revert NonExistentAmount();
IStorageHistory(storageHistory).increaseBridgeIn(amount);
@ -143,25 +145,25 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
if (payload.chainId != block.chainid) revert WrongChainId();
StorageHistory(storageHistory).trySetTransactionExecuted(exodusSession);
IStorageHistory(storageHistory).tryIncreaseBridgeOut(amount);
uint256 bountyAmount = FullMath.mulDiv(amount, uint256(payload.bounty), BOUNTY_DIVISOR);
uint256 bountyAmount = FullMath.mulDiv(amount, BOUNTY_DIVISOR - uint256(payload.bounty), BOUNTY_DIVISOR);
uint256 receiverAmount = amount - bountyAmount;
uint256 bridgeOutImbalance = receiverAmount;
IStaking(staking).recall(payload.receiver, receiverAmount);
if (bountyAmount > 0) {
uint256 totalReserves = IStaking(staking).totalReserves();
uint256 baseSupply = IStaking(staking).baseSupply();
uint256 minimumNativeRequired = FullMath.mulDiv(bountyAmount, totalReserves, baseSupply);
uint256 gasSpent = GAS_RECALL_SPENDING * tx.gasprice;
(address token, uint256 forGas, uint256 sent) = IStaking(staking).recall(bountyAmount, gasSpent, REGISTRY_INDEX);
bridgeOutImbalance += forGas;
if (minimumNativeRequired > msg.value) revert InsufficientValue();
IStaking(staking).recall(tx.origin, bountyAmount);
(bool sentSuccess,) = payload.receiver.call{ value: msg.value }("");
IWETH9(token).withdraw(sent);
(bool sentSuccess,) = payload.receiver.call{ value: sent }("");
if (!sentSuccess) revert SendFailed();
}
IStorageHistory(storageHistory).tryIncreaseBridgeOut(bridgeOutImbalance);
emit Recalled(payload.receiver, amount);
}

View File

@ -9,6 +9,7 @@ import {Gatekeeper} from "./Gatekeeper.sol";
import {StorageHistory} from "./types/StorageHistory.sol";
import {GhostAccessControlled} from "./types/GhostAccessControlled.sol";
import {IFTSO} from "./interfaces/IFTSO.sol";
import {ISTNK} from "./interfaces/ISTNK.sol";
import {IGHST} from "./interfaces/IGHST.sol";
import {IStaking} from "./interfaces/IStaking.sol";
@ -46,8 +47,7 @@ contract GhostStaking is IStaking, GhostAccessControlled {
uint48 _epochLength,
uint48 _firstEpochNumber,
uint48 _firstEpochTime,
address _authority,
uint256 _existentialDeposit
address _authority
) GhostAccessControlled(IGhostAuthority(_authority)) {
ftso = _ftso;
stnk = _stnk;
@ -62,7 +62,7 @@ contract GhostStaking is IStaking, GhostAccessControlled {
GhostWarmup newWarmup = new GhostWarmup(_ghst);
StorageHistory newHistory = new StorageHistory();
Gatekeeper newGatekeeper = new Gatekeeper(_existentialDeposit, address(newHistory));
Gatekeeper newGatekeeper = new Gatekeeper(address(newHistory));
IStorageHistory(newHistory).setOwner(address(newGatekeeper));
IGatekeeper(newGatekeeper).initialize(address(0));
@ -172,6 +172,29 @@ contract GhostStaking is IStaking, GhostAccessControlled {
IGHST(ghst).mint(receiver, amount);
}
function recall(
uint256 amount,
uint256 gasSpent,
uint256 registryIndex
) external override returns (address reserveToken, uint256 gasGhstAmount, uint256 value) {
if (gatekeeper != msg.sender) revert NotGatekeeper();
address treasury = ISTNK(stnk).treasury();
uint256 ftsoAmount = IGHST(ghst).balanceFrom(amount);
uint256 gasFtsoAmount;
(reserveToken, value, gasFtsoAmount) = ITreasury(treasury).buyBack(
msg.sender,
ftsoAmount,
gasSpent,
registryIndex
);
gasGhstAmount = IGHST(ghst).balanceTo(gasFtsoAmount);
IFTSO(ftso).burn(ftsoAmount - gasFtsoAmount);
IGHST(ghst).mint(tx.origin, gasGhstAmount);
}
function rebase() public override returns (uint256 bounty) {
if (epoch.end <= block.timestamp && block.number > _lastRebaseBlock) {
ISTNK(stnk).rebase(epoch.distribute, epoch.number);

View File

@ -4,6 +4,7 @@ pragma solidity ^0.8.20;
import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol";
import {EnumerableSet} from "@openzeppelin-contracts/utils/structs/EnumerableSet.sol";
import {IUniswapV2Factory} from "@uniswap-v2-core-1.0.1/interfaces/IUniswapV2Factory.sol";
import {IUniswapV2Pair} from "@uniswap-v2-core-1.0.1/interfaces/IUniswapV2Pair.sol";
@ -21,25 +22,22 @@ import {IGhostAuthority} from "./interfaces/IGhostAuthority.sol";
contract GhostTreasury is GhostAccessControlled, ITreasury {
using SafeERC20 for IERC20;
using EnumerableSet for EnumerableSet.AddressSet;
address public immutable ftso; // forge-lint: disable-line(screaming-snake-case-immutable)
uint256 public immutable blocksNeededForQueue; // forge-lint: disable-line(screaming-snake-case-immutable)
address public immutable FTSO;
uint256 public totalReserves;
uint256 public totalDebt;
uint256 public ftsoDebt;
mapping(STATUS => address[]) public registry;
mapping(STATUS => mapping(address => bool)) public permissions;
mapping(STATUS => EnumerableSet.AddressSet) private _registry;
mapping(STATUS => mapping(address => bool)) private _permissions;
mapping(address => address) public bondCalculator;
constructor(
address _ftso,
uint256 _timelock,
address _authority
) GhostAccessControlled(IGhostAuthority(_authority)) {
ftso = _ftso;
blocksNeededForQueue = _timelock;
FTSO = _ftso;
}
function deposit(
@ -47,30 +45,30 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
uint256 amount,
uint256 profit
) external override returns (uint256 send) {
if (permissions[STATUS.RESERVETOKEN][token]) {
if (!permissions[STATUS.RESERVEDEPOSITOR][msg.sender]) revert NotApproved();
} else if (permissions[STATUS.LIQUIDITYTOKEN][token]) {
if (!permissions[STATUS.LIQUIDITYDEPOSITOR][msg.sender]) revert NotApproved();
if (_permissions[STATUS.RESERVETOKEN][token]) {
if (!_permissions[STATUS.RESERVEDEPOSITOR][msg.sender]) revert NotApproved();
} else if (_permissions[STATUS.LIQUIDITYTOKEN][token]) {
if (!_permissions[STATUS.LIQUIDITYDEPOSITOR][msg.sender]) revert NotApproved();
} else revert InvalidToken();
IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
uint256 value = tokenValue(token, amount);
send = value - profit;
IFTSO(ftso).mint(msg.sender, send);
IFTSO(FTSO).mint(msg.sender, send);
totalReserves = totalReserves + value;
emit Deposit(token, amount, value);
}
function mint(address recipient, uint256 amount) external override {
if (!permissions[STATUS.REWARDMANAGER][msg.sender]) revert NotApproved();
if (!_permissions[STATUS.REWARDMANAGER][msg.sender]) revert NotApproved();
if (amount > excessReserves()) revert InsufficientReserves();
IFTSO(ftso).mint(recipient, amount);
IFTSO(FTSO).mint(recipient, amount);
emit Minted(msg.sender, recipient, amount);
}
function withdraw(address token, uint256 amount) external onlyGovernor override {
if (!permissions[STATUS.RESERVETOKEN][token]) revert NotAccepted();
if (!_permissions[STATUS.RESERVETOKEN][token]) revert NotAccepted();
uint256 value = tokenValue(token, amount);
totalReserves = totalReserves - value;
@ -79,6 +77,30 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
emit Withdrawal(token, amount, value);
}
function buyBack(
address receiver,
uint256 amount,
uint256 gasSpent,
uint256 index
) external override returns (address reserveToken, uint256 value, uint256 gasValue) {
if (!_permissions[STATUS.STAKING][msg.sender]) revert NotApproved();
reserveToken = _registry[STATUS.RESERVETOKEN].at(index);
if (!_permissions[STATUS.RESERVETOKEN][reserveToken]) revert NotApproved();
uint256 totalSupply = IERC20(FTSO).totalSupply();
gasValue = tokenValue(reserveToken, gasSpent);
gasValue = FullMath.mulDiv(gasValue, totalSupply, totalReserves);
if (amount <= gasValue) revert GasExceedsBounty();
uint256 reservesToSend = FullMath.mulDiv(amount - gasValue, totalReserves, totalSupply);
totalReserves = totalReserves - reservesToSend;
value = FullMath.mulDiv(reservesToSend, 1e18, IBondingCalculator(bondCalculator[reserveToken]).fraction());
value = FullMath.mulDiv(value, 10**IERC20Metadata(reserveToken).decimals(), 1e9);
IERC20(reserveToken).safeTransfer(receiver, value);
}
function auditReserves() external {
if (
msg.sender != authority.governor() &&
@ -86,12 +108,12 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
) revert NotApproved();
uint256 reserves;
address[] memory reserveTokens = registry[STATUS.RESERVETOKEN];
uint256 reserveTokensLength = _registry[STATUS.RESERVETOKEN].length();
uint256 i;
for (; i < reserveTokens.length;) {
address reserveToken = reserveTokens[i];
if (permissions[STATUS.RESERVETOKEN][reserveToken]) {
for (; i < reserveTokensLength;) {
address reserveToken = _registry[STATUS.RESERVETOKEN].at(i);
if (_permissions[STATUS.RESERVETOKEN][reserveToken]) {
reserves = reserves + tokenValue(
reserveToken,
IERC20(reserveToken).balanceOf(address(this))
@ -100,11 +122,12 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
unchecked { ++i; }
}
address[] memory liquidityTokens = registry[STATUS.LIQUIDITYTOKEN];
uint256 liquidityTokensLength = _registry[STATUS.LIQUIDITYTOKEN].length();
i = 0;
for (; i < liquidityTokens.length;) {
address liquidityToken = liquidityTokens[i];
if (permissions[STATUS.LIQUIDITYTOKEN][liquidityToken]) {
for (; i < liquidityTokensLength;) {
address liquidityToken = _registry[STATUS.LIQUIDITYTOKEN].at(i);
if (_permissions[STATUS.LIQUIDITYTOKEN][liquidityToken]) {
reserves = reserves + tokenValue(
liquidityToken,
IERC20(liquidityToken).balanceOf(address(this))
@ -122,11 +145,13 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
address someAddress,
address calculatorAddress
) external onlyGovernor {
permissions[status][someAddress] = true;
(bool registered, ) = indexInRegistry(someAddress, status);
if (!registered && (status == STATUS.LIQUIDITYTOKEN || status == STATUS.RESERVETOKEN)) {
assert(calculatorAddress != address(0));
registry[status].push(someAddress);
_permissions[status][someAddress] = true;
bool alreadyRegistered = _registry[status].contains(someAddress);
if (!alreadyRegistered && (status == STATUS.LIQUIDITYTOKEN || status == STATUS.RESERVETOKEN)) {
if (calculatorAddress == address(0)) revert();
_registry[status].add(someAddress);
bondCalculator[someAddress] = calculatorAddress;
}
emit Permissioned(someAddress, status, true);
@ -137,7 +162,7 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
msg.sender != authority.governor() &&
msg.sender != authority.guardian()
) revert NotApproved();
permissions[status][toDisable] = false;
_permissions[status][toDisable] = false;
emit Permissioned(toDisable, status, false);
}
@ -147,7 +172,7 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
bool destroyerMode
) external onlyGovernor {
address weth = IUniswapV2Router01(router).WETH();
address pair = IUniswapV2Factory(IUniswapV2Router01(router).factory()).getPair(ftso, weth);
address pair = IUniswapV2Factory(IUniswapV2Router01(router).factory()).getPair(FTSO, weth);
IERC20(pair).safeTransfer(pair, liquidity);
(uint256 amount0, uint256 amount1) = IUniswapV2Pair(pair).burn(address(this));
@ -157,15 +182,15 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
address token0 = IUniswapV2Pair(pair).token0();
address token1 = IUniswapV2Pair(pair).token1();
if (token0 == ftso) {
if (token0 == FTSO) {
amountToDestroy = amount0;
}
if (token1 == ftso) {
if (token1 == FTSO) {
amountToDestroy = amount1;
}
IFTSO(ftso).burn(amountToDestroy);
IFTSO(FTSO).burn(amountToDestroy);
}
}
@ -174,16 +199,16 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
uint256 amount
) external onlyGovernor {
address weth = IUniswapV2Router01(router).WETH();
address pair = IUniswapV2Factory(IUniswapV2Router01(router).factory()).getPair(ftso, weth);
address pair = IUniswapV2Factory(IUniswapV2Router01(router).factory()).getPair(FTSO, weth);
IERC20(weth).approve(router, amount);
(uint256 reserve0, uint256 reserve1,) = IUniswapV2Pair(pair).getReserves();
address[] memory path = new address[](2);
path[0] = weth;
path[1] = ftso;
path[1] = FTSO;
if (ftso < weth) {
if (FTSO < weth) {
reserve0 = reserve1 ^ reserve0;
reserve1 = reserve1 ^ reserve0;
reserve0 = reserve1 ^ reserve0;
@ -202,48 +227,41 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
amountIn = amount - amountIn;
IERC20(weth).safeTransfer(pair, amountIn);
IERC20(ftso).safeTransfer(pair, amounts[1]);
IERC20(FTSO).safeTransfer(pair, amounts[1]);
IUniswapV2Pair(pair).mint(address(this));
}
function indexInRegistry(
address someAddress,
STATUS status
) public view override returns (bool, uint256) {
address[] memory entries = registry[status];
uint256 i;
for (; i < entries.length; ) {
if (someAddress == entries[i]) {
return (true, i);
function permissioned(STATUS status, address someAddress) external view returns (bool) {
return _permissions[status][someAddress];
}
unchecked { ++i; }
}
return (false, 0);
function registered(STATUS status, address someAddress) external view returns (bool) {
return _registry[status].contains(someAddress);
}
function originalCoefficient() external view returns (uint256) {
address[] memory reserveTokens = registry[STATUS.RESERVETOKEN];
return IBondingCalculator(bondCalculator[reserveTokens[0]]).fraction();
address reserveToken = _registry[STATUS.RESERVETOKEN].at(0);
return IBondingCalculator(bondCalculator[reserveToken]).fraction();
}
function excessReserves() public view override returns (uint256) {
return totalReserves - (IFTSO(ftso).totalSupply() - totalDebt);
return totalReserves - (IFTSO(FTSO).totalSupply() - totalDebt);
}
function tokenValue(
address token,
uint256 amount
) public view override returns (uint256 value) {
if (permissions[STATUS.LIQUIDITYTOKEN][token]) {
if (_permissions[STATUS.LIQUIDITYTOKEN][token]) {
value = IBondingCalculator(bondCalculator[token]).valuation(token, amount);
} else if (permissions[STATUS.RESERVETOKEN][token]) {
} else if (_permissions[STATUS.RESERVETOKEN][token]) {
value = FullMath.mulDiv(amount, 1e9, 10**IERC20Metadata(token).decimals());
value = FullMath.mulDiv(value, IBondingCalculator(bondCalculator[token]).fraction(), 1e18);
}
}
function baseSupply() external view override returns (uint256) {
return IFTSO(ftso).totalSupply() - ftsoDebt;
return IFTSO(FTSO).totalSupply();
}
function _quantityToBeSwapped(uint256 xa, uint256 x1) internal pure returns (uint256) {

View File

@ -21,7 +21,6 @@ interface IGatekeeper {
function deployer() external view returns (address);
function ghostedSupply() external view returns (uint256);
function storageHistory() external view returns (address);
function existentialDeposit() external view returns (uint256);
function latestPublicKeyInfo() external view returns (bytes32, uint8, uint64);
function getRotationInfoAt(uint256 session) external view returns (bytes32, uint8, uint64);

View File

@ -69,6 +69,7 @@ interface IStaking {
function unwrap(address _to, uint256 _amount) external returns (uint256 sBalance_);
function ghost(bytes32 receiver, uint256 amount) external;
function recall(address receiver, uint256 amount) external;
function recall(uint256 amount, uint256 gasSpent, uint256 registryIndex) external returns (address, uint256, uint256);
function rebase() external returns (uint256);
function index() external view returns (uint256);

View File

@ -5,6 +5,7 @@ interface ITreasury {
error NotApproved();
error NotAccepted();
error InvalidToken();
error GasExceedsBounty();
error InsufficientReserves();
enum STATUS {
@ -12,7 +13,8 @@ interface ITreasury {
RESERVETOKEN,
LIQUIDITYDEPOSITOR,
LIQUIDITYTOKEN,
REWARDMANAGER
REWARDMANAGER,
STAKING
}
event Deposit(address indexed token, uint256 amount, uint256 value);
@ -27,10 +29,10 @@ interface ITreasury {
uint256 _profit
) external returns (uint256);
function buyBack(address receiver, uint256 amount, uint256 gasSpent, uint256 index) external returns (address, uint256, uint256);
function withdraw(address token, uint256 amount) external;
function mint(address _recipient, uint256 _amount) external;
function tokenValue(address _token, uint256 _amount) external view returns (uint256 value_);
function indexInRegistry(address _address, STATUS _status) external view returns (bool, uint256);
function excessReserves() external view returns (uint256);
function baseSupply() external view returns (uint256);
function totalReserves() external view returns (uint256);

View File

@ -75,10 +75,9 @@ contract GhostBondDepositoryTest is Test {
EPOCH_LENGTH,
EPOCH_NUMBER,
EPOCH_END_TIME,
address(authority),
0
address(authority)
);
treasury = new GhostTreasury(address(ftso), 69, address(authority));
treasury = new GhostTreasury(address(ftso), address(authority));
calculator = new GhostBondingCalculator(address(ftso), 1, 1);
stnk.initialize(address(staking), address(treasury), address(ghst));
ghst.initialize(address(staking));

View File

@ -7,6 +7,7 @@ import {FullMath} from "../../src/libraries/FullMath.sol";
import {RequestPacking} from "../../src/libraries/Packing.sol";
import {IStorageHistory} from "../../src/interfaces/IStorageHistory.sol";
import {StorageHistory} from "../../src/types/StorageHistory.sol";
import {WETH9} from "../../src/mocks/WETH9.sol";
contract MockGovernance is Test {
address public immutable GATEKEEPER;
@ -137,12 +138,14 @@ contract MockGovernance is Test {
contract MockStaking is Test {
Gatekeeper public gatekeeper;
WETH9 public mockReserve;
mapping(address => uint256) private _recalledAmounts;
constructor(uint256 existential) {
constructor() {
mockReserve = new WETH9();
StorageHistory history = new StorageHistory();
gatekeeper = new Gatekeeper(existential, address(history));
gatekeeper = new Gatekeeper(address(history));
gatekeeper.initialize(address(0));
history.setOwner(address(gatekeeper));
}
@ -169,6 +172,11 @@ contract MockStaking is Test {
_recalledAmounts[receiver] += amount;
}
function recall(uint256 amount, uint256, uint256) external returns (address, uint256, uint256){
_recalledAmounts[tx.origin] += amount;
return (address(mockReserve), 0, 0);
}
function recalledAmount(address who) external view returns (uint256) {
return _recalledAmounts[who];
}
@ -187,7 +195,6 @@ contract GatekeeperTest is Test {
address constant ALICE = 0x0000000000000000000000000000000000000001;
address constant BOB = 0x0000000000000000000000000000000000000002;
uint256 constant EXISTENTIAL = 1337;
uint256 constant INIT_AMOUNT = 69 * 1e18;
address constant DUMMY_ADDRESS = address(0x0101010101010101010101010101010101010101);
@ -199,7 +206,7 @@ contract GatekeeperTest is Test {
function setUp() public {
vm.prank(ALICE, ALICE);
staking = new MockStaking(EXISTENTIAL);
staking = new MockStaking();
gatekeeper = staking.gatekeeper();
MockGovernance tempGov = new MockGovernance(address(gatekeeper), DUMMY_ADDRESS);
@ -215,7 +222,7 @@ contract GatekeeperTest is Test {
}
function test_ghostTokensWork(uint256 ghostAmount) public {
vm.assume(ghostAmount >= EXISTENTIAL && ghostAmount < type(uint96).max);
vm.assume(ghostAmount >= gatekeeper.EXISTENTIAL_DEPOSIT() && ghostAmount < type(uint96).max);
bytes32 receiver = bytes32(abi.encodePacked(ALICE));
uint256 ghostedSupply = gatekeeper.ghostedSupply();
@ -235,7 +242,7 @@ contract GatekeeperTest is Test {
}
function test_ghostTokensEmitsEvent(uint256 ghostAmount) public {
vm.assume(ghostAmount >= EXISTENTIAL);
vm.assume(ghostAmount >= gatekeeper.EXISTENTIAL_DEPOSIT());
bytes32 receiver = bytes32(abi.encodePacked(ALICE));
vm.expectEmit(true, true, true, false, address(gatekeeper));
@ -245,7 +252,7 @@ contract GatekeeperTest is Test {
}
function test_recallWork(uint256 exodusSession, uint256 bobAmount, uint32 bobCommission) public {
vm.assume(bobAmount > 1337 && bobAmount < 1_000 ether);
vm.assume(bobAmount > gatekeeper.EXISTENTIAL_DEPOSIT() && bobAmount < 1_000 ether);
vm.assume(bobCommission > 0 && bobCommission <= type(uint32).max);
address storageHistory = gatekeeper.storageHistory();
@ -259,19 +266,9 @@ contract GatekeeperTest is Test {
vm.deal(ALICE, nativeNeeded + 1 ether);
assertEq(BOB.balance, 0 ether);
uint256 aliceStartingNative = ALICE.balance;
uint256 previousAliceAmount = staking.recalledAmount(ALICE);
uint256 previousBobAmount = staking.recalledAmount(BOB);
vm.prank(ALICE);
staking.runRecall{value: nativeNeeded}(exodusSession, bobAmount, bobPacked, ALICE);
assertApproxEqAbs(previousAliceAmount + commissionAmount, staking.recalledAmount(ALICE), 1000);
assertApproxEqAbs(previousBobAmount + (bobAmount - commissionAmount), staking.recalledAmount(BOB), 1000);
assertEq(BOB.balance, nativeNeeded);
assertEq(ALICE.balance, aliceStartingNative - nativeNeeded);
staking.runRecall(exodusSession, bobAmount, bobPacked, ALICE);
assert(IStorageHistory(storageHistory).isTransactionExecuted(exodusSession));
}
@ -283,7 +280,7 @@ contract GatekeeperTest is Test {
}
function test_couldNotBridgeBelowExistential(uint256 amount) public {
vm.assume(amount < EXISTENTIAL);
vm.assume(amount < gatekeeper.EXISTENTIAL_DEPOSIT());
bytes32 receiver = bytes32(abi.encodePacked(ALICE));
vm.expectRevert();
@ -363,6 +360,7 @@ contract GatekeeperTest is Test {
// execute bridge out, happened on DKG #0
// amount: 69; commission: 0%; ALICE
// exodus session #1
vm.prank(ALICE, ALICE);
gatekeeper.verify(
hex"bf06188a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000010000000000007a6900000000",
hex"04bccb4cd4633e2c61ca5c65006a6a09baa893be219b21509866123a8d6299f92aefe9c380bd9728dbe0b93a8042f431636d08ed191b5c04062bf14e1347059cb9",
@ -393,10 +391,8 @@ contract GatekeeperTest is Test {
0x772731b359ee7ecac7830438333e4ffb61759b36610f69cef20f66f7a79a405f
);
assertEq(aliceAmountBefore + 210, staking.recalledAmount(ALICE));
assertEq(bobAmountBefore + 210, staking.recalledAmount(BOB));
assertEq(aliceBalanceBefore - buyback, ALICE.balance);
assertEq(bobBalanceBefore + buyback, BOB.balance);
assertApproxEqAbs(aliceAmountBefore + 210, staking.recalledAmount(ALICE), 1);
assertApproxEqAbs(bobAmountBefore + 210, staking.recalledAmount(BOB), 1);
// execute setDistributor, exodusSession: 2
vm.prank(ALICE);

View File

@ -7,21 +7,24 @@ import {IStorageHistory} from "../../src/interfaces/IStorageHistory.sol";
import {IGatekeeper} from "../../src/interfaces/IGatekeeper.sol";
import {RequestPacking} from "../../src/libraries/Packing.sol";
import {StorageHistory} from "../../src/types/StorageHistory.sol";
import {WETH9} from "../../src/mocks/WETH9.sol";
contract MockStaking is Test {
Gatekeeper public gatekeeper;
WETH9 public mockReserve;
mapping(address => uint256) private _recalledAmounts;
constructor(uint256 existential) {
constructor() {
mockReserve = new WETH9();
StorageHistory history = new StorageHistory();
gatekeeper = new Gatekeeper(existential, address(history));
gatekeeper = new Gatekeeper(address(history));
gatekeeper.initialize(address(0));
history.setOwner(address(gatekeeper));
}
function redoGatekeeper(uint256 existential) external {
Gatekeeper newGatekeeper = new Gatekeeper(existential, address(0));
function redoGatekeeper() external {
Gatekeeper newGatekeeper = new Gatekeeper(address(0));
newGatekeeper.initialize(address(gatekeeper));
address storageHistory = IGatekeeper(gatekeeper).storageHistory();
@ -43,6 +46,11 @@ contract MockStaking is Test {
_recalledAmounts[receiver] += amount;
}
function recall(uint256 amount, uint256, uint256) external returns (address, uint256, uint256){
_recalledAmounts[tx.origin] += amount;
return (address(mockReserve), amount, 0);
}
function recalledAmount(address who) external view returns (uint256) {
return _recalledAmounts[who];
}
@ -54,14 +62,13 @@ contract GatekeeperStorageHistoryTest is Test {
address constant ALICE = 0x0000000000000000000000000000000000000001;
address constant BOB = 0x0000000000000000000000000000000000000002;
uint256 constant INIT_AMOUNT = 1337 * 1e18;
uint256 constant EXISTENTIAL = 0;
Gatekeeper gatekeeper;
MockStaking staking;
function setUp() public {
vm.prank(ALICE);
staking = new MockStaking(EXISTENTIAL);
staking = new MockStaking();
staking.runGhost(bytes32(abi.encodePacked(ALICE)), INIT_AMOUNT);
gatekeeper = staking.gatekeeper();
@ -78,7 +85,7 @@ contract GatekeeperStorageHistoryTest is Test {
}
function test_historicalAmountsOnlyIncrease(uint256 ghostAmount, uint64 exodusSession) public {
vm.assume(ghostAmount > 0 && ghostAmount < INIT_AMOUNT);
vm.assume(ghostAmount > gatekeeper.EXISTENTIAL_DEPOSIT() && ghostAmount < INIT_AMOUNT);
uint256 amountToGhost = ghostAmount;
uint256 amountToMaterialize = ghostAmount / 2;
@ -99,6 +106,7 @@ contract GatekeeperStorageHistoryTest is Test {
uint256 packed = RequestPacking.pack(0, uint64(block.chainid), BOB);
uint256 previousAmount = staking.recalledAmount(BOB);
vm.prank(BOB, BOB);
staking.runRecall(exodusSession, amountToMaterialize, packed);
assertEq(previousAmount + amountToMaterialize, staking.recalledAmount(BOB));
@ -121,7 +129,7 @@ contract GatekeeperStorageHistoryTest is Test {
address prevStorageHistory = gatekeeper.storageHistory();
IStorageHistory.DeploymentSnapshot memory prevSnapshot = IStorageHistory(prevStorageHistory).deploymentSnapshot();
staking.redoGatekeeper(EXISTENTIAL + 1);
staking.redoGatekeeper();
assert(gatekeeper != staking.gatekeeper());
address currStorageHistory = gatekeeper.storageHistory();
@ -133,8 +141,5 @@ contract GatekeeperStorageHistoryTest is Test {
assert(IStorageHistory(prevStorageHistory).isTransactionExecuted(exodusSession));
assert(IStorageHistory(currStorageHistory).isTransactionExecuted(exodusSession));
assertEq(gatekeeper.existentialDeposit(), EXISTENTIAL);
assertEq(staking.gatekeeper().existentialDeposit(), EXISTENTIAL + 1);
}
}

View File

@ -0,0 +1,203 @@
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 {GhostBondDepository} from "../../src/BondDepository.sol";
import {ERC20Mock} from "../../src/mocks/ERC20Mock.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";
import {IGatekeeper} from "../../src/interfaces/IGatekeeper.sol";
import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.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, 0x4e8c1fe96d6737cdabbcc96501d6656b9d0b659b3a528ef507f2d52bef29e157, 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 bountyPercent = type(uint32).max / 2;
uint256 amountToBridge = 42 * 1e15;
address evmReceiver = address(0x0000000000000000000000000000000000000002);
uint256 bobGhstBefore = ghst.balanceOf(BOB);
uint256 receiverEthBefore = evmReceiver.balance;
uint256 receiverGhstBefore = ghst.balanceOf(evmReceiver);
uint256 totalReservesBefore = treasury.totalReserves();
uint256 totalSupplyBefore = ftso.totalSupply();
uint256 ghostedSupplyBefore = gatekeeper.ghostedSupply();
vm.txGasPrice(2 gwei);
vm.startPrank(BOB, BOB);
gatekeeper.verify(
hex"bf06188a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000009536c70891000000000000000000000000000000000000000000020000000000007a6980000000",
hex"046566d4b0904bf35afd25dff583d53bd30e50f57cc790ad08377e0b85006b38b85046b527098f3dfdadc30d6623b6b1c4644306dd56d39f7c9d6b3b295d005c33",
0x942fb44ad0422c197f9c3016ff7c7e574a9f86182c5485e39fc9bebf61228ad6
);
vm.stopPrank();
{
uint256 bobEarnedGhst = ghst.balanceOf(BOB) - bobGhstBefore;
assertTrue(bobEarnedGhst > 0);
uint256 bobEarnedFtso = ghst.balanceFrom(bobEarnedGhst);
uint256 totalReservesAfter = treasury.totalReserves();
uint256 totalSupplyAfter = ftso.totalSupply();
uint256 gasUsed = 2 * 1e9 * 329188;
uint256 gasReserveValue = treasury.tokenValue(address(reserve), gasUsed);
uint256 expectedGasFtso = gasReserveValue * totalSupplyAfter / totalReservesAfter;
uint256 simulatedGhst = ghst.balanceTo(expectedGasFtso);
uint256 dynamicGasPriceEstimation = ghst.balanceFrom(simulatedGhst);
assertApproxEqAbs(bobEarnedFtso, dynamicGasPriceEstimation, 1);
}
{
uint256 expectedBounty = amountToBridge * bountyPercent / type(uint32).max;
uint256 expectedMintToReceiver = amountToBridge - expectedBounty;
uint256 actualMintToReceiver = ghst.balanceOf(evmReceiver) - receiverGhstBefore;
assertApproxEqAbs(actualMintToReceiver, expectedMintToReceiver, 1);
}
{
uint256 receiverEthAfter = evmReceiver.balance;
uint256 receivedEth = receiverEthAfter - receiverEthBefore;
assertTrue(receivedEth > 0);
uint256 totalReservesAfter = treasury.totalReserves();
uint256 totalSupplyAfter = ftso.totalSupply();
uint256 expectedBounty = amountToBridge * bountyPercent / type(uint32).max;
uint256 totalBountyFtso = ghst.balanceFrom(expectedBounty);
uint256 totalBountyReserveValue = totalBountyFtso * totalReservesAfter / totalSupplyAfter;
uint256 fraction = calculator.fraction();
uint256 totalBountyInEth = totalBountyReserveValue * 1e18 / fraction;
totalBountyInEth = totalBountyInEth * 1e18 / 1e9;
uint256 physicalGasSpentEth = 2 * 1e9 * 329188; // 2 gwei * gas Used
assertApproxEqAbs(receivedEth, totalBountyInEth - physicalGasSpentEth, 1);
}
{
uint256 totalReservesAfter = treasury.totalReserves();
uint256 totalSupplyAfter = ftso.totalSupply();
uint256 backingRatioBefore = totalReservesBefore * 1e18 / totalSupplyBefore;
uint256 backingRatioAfter = totalReservesAfter * 1e18 / totalSupplyAfter;
uint256 receivedValue = treasury.tokenValue(address(reserve), evmReceiver.balance);
assertEq(backingRatioAfter, backingRatioBefore);
assertApproxEqAbs(totalReservesAfter + receivedValue, totalReservesBefore, 2000); // 2e-16%
vm.prank(GOVERNOR);
treasury.auditReserves();
assertEq(treasury.totalReserves() + receivedValue, totalReservesBefore);
}
{
uint256 expectedMintToReceiver = amountToBridge * (type(uint32).max - bountyPercent) / type(uint32).max;
uint256 bobGhstAfter = ghst.balanceOf(BOB);
assertApproxEqAbs(ghostedSupplyBefore - bobGhstAfter - expectedMintToReceiver, gatekeeper.ghostedSupply(), 1);
}
}
}

View File

@ -13,9 +13,9 @@ contract MockStaking {
GatekeeperWeaver public gatekeeper;
address public governor;
constructor(uint256 existential) {
constructor() {
StorageHistory history = new StorageHistory();
gatekeeper = new GatekeeperWeaver(existential, address(history));
gatekeeper = new GatekeeperWeaver(address(history));
gatekeeper.initialize(address(0));
history.setOwner(address(gatekeeper));
governor = msg.sender;
@ -26,10 +26,10 @@ contract MockStaking {
return gatekeeper.ghost(receiver, amount);
}
function createNewGatekeeper(uint256 existential) external {
function createNewGatekeeper() external {
require(msg.sender == governor);
GatekeeperWeaver newGatekeeper = new GatekeeperWeaver(existential, address(0));
GatekeeperWeaver newGatekeeper = new GatekeeperWeaver(address(0));
newGatekeeper.initialize(address(gatekeeper));
address storageHistory = IGatekeeper(gatekeeper).storageHistory();
@ -43,7 +43,7 @@ contract GatekeeperWeaver is Gatekeeper {
using Checkpoints for Checkpoints.Trace256;
using Checkpoints for Checkpoints.Trace160;
constructor(uint256 existential, address storageHistory) Gatekeeper(existential, storageHistory) {}
constructor(address storageHistory) Gatekeeper(storageHistory) {}
function filledEntries(uint256 session) public view returns (uint256) {
return _filledEntries[session];
@ -115,7 +115,6 @@ contract GatekeeperWeaver is Gatekeeper {
contract GatekeeperWeaverTest is Test {
address constant ALICE = 0x0000000000000000000000000000000000000001;
address constant BOB = 0x0000000000000000000000000000000000000002;
uint256 constant EXISTENTIAL = 1337;
uint256 constant AMOUNT = 1 * 1e7;
MockStaking staking;
@ -123,7 +122,7 @@ contract GatekeeperWeaverTest is Test {
function setUp() public {
vm.prank(ALICE);
staking = new MockStaking(EXISTENTIAL);
staking = new MockStaking();
gatekeeper = staking.gatekeeper();
}
@ -164,7 +163,7 @@ contract GatekeeperWeaverTest is Test {
vm.roll(block.number + 420);
vm.prank(ALICE);
staking.createNewGatekeeper(EXISTENTIAL);
staking.createNewGatekeeper();
gatekeeper = staking.gatekeeper();
uint256 finalSession = gatekeeper.currentWeavingSession();
@ -256,13 +255,15 @@ contract GatekeeperWeaverTest is Test {
}
}
function _prepareArrays(uint256 count) private pure returns (bytes32[] memory, uint256[] memory) {
function _prepareArrays(uint256 count) private view returns (bytes32[] memory, uint256[] memory) {
bytes32[] memory whos = new bytes32[](count);
uint256[] memory amounts = new uint256[](count);
uint256 existential = gatekeeper.EXISTENTIAL_DEPOSIT();
for (uint256 i = 0; i < count; i++) {
whos[i] = keccak256(abi.encodePacked("user", i));
amounts[i] = EXISTENTIAL + 1 + i;
amounts[i] = existential + 1 + i;
}
return (whos, amounts);

View File

@ -106,10 +106,9 @@ contract StakingTest is Test {
EPOCH_LENGTH,
EPOCH_NUMBER,
EPOCH_END_TIME,
address(authority),
0
address(authority)
);
treasury = new GhostTreasury(address(ftso), 69, address(authority));
treasury = new GhostTreasury(address(ftso), address(authority));
stnk.initialize(address(staking), address(treasury), address(ghst));
ghst.initialize(address(staking));
calculator = new GhostBondingCalculator(address(ftso), 1, 1);
@ -596,7 +595,7 @@ contract StakingTest is Test {
vm.prank(address(previousGatekeeper));
IStorageHistory(storageHistory).trySetTransactionExecuted(34);
Gatekeeper newGatekeeper = new Gatekeeper(420, address(0));
Gatekeeper newGatekeeper = new Gatekeeper(address(0));
vm.prank(GOVERNOR);
staking.updateGatekeeperAddress(address(newGatekeeper));

View File

@ -61,10 +61,9 @@ contract StakingDistributorTest is Test {
EPOCH_LENGTH,
EPOCH_NUMBER,
EPOCH_END_TIME,
address(authority),
0
address(authority)
);
treasury = new GhostTreasury(address(ftso), 69, address(authority));
treasury = new GhostTreasury(address(ftso), address(authority));
calculator = new GhostBondingCalculator(address(ftso), 1, 1);
distributor = new GhostDistributor(
address(treasury),

View File

@ -53,8 +53,7 @@ contract GhostTest is
69,
1337,
1337,
address(authority),
0
address(authority)
);
stnk.initialize(address(staking), TREASURY, address(ghst));
ghst.initialize(address(staking));

View File

@ -59,8 +59,7 @@ contract StinkyTest is Test, ERC20PermitTest, ERC20AllowanceTest, ERC20TransferT
69,
1337,
1337,
address(authority),
0
address(authority)
);
ghst.initialize(address(staking));
vm.stopPrank();

View File

@ -37,7 +37,7 @@ contract GhostTreasuryTest is Test {
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));
treasury = new GhostTreasury(address(ftso), address(authority));
calculator = new GhostBondingCalculator(address(ftso), 1, 1);
vm.stopPrank();
@ -109,8 +109,8 @@ contract GhostTreasuryTest is Test {
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.permissioned(ITreasury.STATUS.RESERVETOKEN, address(reserve)), true);
assertEq(treasury.registered(ITreasury.STATUS.RESERVETOKEN, address(reserve)), true);
assertEq(
treasury.tokenValue(address(reserve), reserve.balanceOf(address(treasury))),
treasury.totalReserves());
@ -139,15 +139,13 @@ contract GhostTreasuryTest is Test {
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.registered(ITreasury.STATUS.RESERVETOKEN, address(reserve)), true);
assertEq(treasury.registered(ITreasury.STATUS.LIQUIDITYTOKEN, address(liquidity)), true);
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);
assertEq(treasury.permissioned(ITreasury.STATUS.RESERVETOKEN, address(reserve)), true);
assertEq(treasury.permissioned(ITreasury.STATUS.LIQUIDITYTOKEN, address(liquidity)), true);
assertEq(treasury.permissioned(ITreasury.STATUS.RESERVEDEPOSITOR, msg.sender), true);
}
function test_randomAddressCouldNotDisableStatusByAddress(address who) public {
@ -185,9 +183,9 @@ contract GhostTreasuryTest is Test {
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);
assertEq(treasury.permissioned(ITreasury.STATUS.RESERVETOKEN, address(reserve)), false);
assertEq(treasury.permissioned(ITreasury.STATUS.LIQUIDITYTOKEN, address(liquidity)), false);
assertEq(treasury.permissioned(ITreasury.STATUS.RESERVEDEPOSITOR, msg.sender), false);
}
function test_mainnet_disableReserveAndLiquidity() public {

View File

@ -41,7 +41,7 @@ contract GhostTreasuryCoefficienBiggerTest is Test {
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));
treasury = new GhostTreasury(address(ftso), address(authority));
calculator = new GhostBondingCalculator(address(ftso), 20, 1);
vm.stopPrank();

View File

@ -41,7 +41,7 @@ contract GhostTreasuryCoefficientLesserTest is Test {
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));
treasury = new GhostTreasury(address(ftso), address(authority));
calculator = new GhostBondingCalculator(address(ftso), 1, 20);
vm.stopPrank();

View File

@ -37,7 +37,7 @@ contract GhostTreasuryRedemptionTest is Test {
OWNER,
OWNER
);
treasury = new GhostTreasury(DAI, 69, address(authority));
treasury = new GhostTreasury(DAI, address(authority));
calculator = new GhostBondingCalculator(DAI, 4000, 1);
vm.stopPrank();