expose coefficient from treasury

Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
This commit is contained in:
Uncle Fatso 2025-10-07 18:22:58 +03:00
parent fe9cf0a00c
commit 02c0d51335
Signed by: f4ts0
GPG Key ID: 565F4F2860226EBB
5 changed files with 254 additions and 5 deletions

View File

@ -345,6 +345,11 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
}
}
function originalCoefficient() external view returns (uint256) {
address[] memory reserveTokens = registry[STATUS.RESERVETOKEN];
return IBondingCalculator(bondCalculator[reserveTokens[0]]).fraction();
}
function excessReserves() public view override returns (uint256) {
return totalReserves - (IFTSO(ftso).totalSupply() - totalDebt);
}
@ -355,7 +360,7 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
) public view override returns (uint256 value) {
if (permissions[STATUS.LIQUIDITYTOKEN][token]) {
value = IBondingCalculator(bondCalculator[token]).valuation(token, amount);
} else {
} else if (permissions[STATUS.RESERVETOKEN][token]) {
value = amount * 1e9 / (10**IERC20Metadata(token).decimals());
value = value * IBondingCalculator(bondCalculator[token]).fraction() / 1e18;
}

View File

@ -239,7 +239,7 @@ contract GhostTreasuryTest is Test {
assertEq(treasury.permissions(ITreasury.STATUS.RESERVEDEPOSITOR, msg.sender), false);
}
function test_tokenValueIsCorret() public {
function test_mainnet_disableReserveAndLiquidity() public {
address realDexPair = 0xB20bd5D04BE54f870D5C0d3cA85d82b34B836405;
vm.startPrank(governor);
@ -247,12 +247,40 @@ contract GhostTreasuryTest is Test {
treasury.enable(ITreasury.STATUS.LIQUIDITYTOKEN, realDexPair, address(calculator));
vm.stopPrank();
uint256 totalSupply = IUniswapV2Pair(realDexPair).totalSupply();
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);

View File

@ -0,0 +1,95 @@
pragma solidity 0.8.20;
import {Test} from "forge-std/Test.sol";
import {StdChains} from "forge-std/StdChains.sol";
import "../../src/FatsoERC20.sol";
import "../../src/GhostAuthority.sol";
import "../../src/Treasury.sol";
import "../../src/StandardBondingCalculator.sol";
import "../../src/mocks/ERC20Mock.sol";
contract GhostTreasuryCoefficienBiggerTest 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), "Fatso", "FTSO");
treasury = new GhostTreasury(address(ftso), 69, address(authority));
calculator = new GhostBondingCalculator(address(ftso), 20, 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_auditTreasuryReservesWithCoefficient() public {
vm.startPrank(governor);
treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0));
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
vm.stopPrank();
assertEq(treasury.totalReserves(), 0);
uint256 tokenValue = treasury.tokenValue(address(reserve), amount);
vm.prank(alice);
IERC20(reserve).transfer(address(treasury), amount);
assertEq(treasury.totalReserves(), 0);
vm.prank(governor);
treasury.auditReserves();
assertEq(treasury.totalReserves(), tokenValue);
uint256 coefficient = treasury.originalCoefficient();
uint256 decimals = IERC20Metadata(address(reserve)).decimals() + 9;
uint256 convertedReserves = treasury.totalReserves() * 10**decimals / coefficient;
uint256 convertedEps = convertedReserves * 1e5 / 1e12; // .000001%
assertEq(convertedReserves + convertedEps >= convertedReserves, true);
assertEq(convertedReserves - convertedEps <= convertedReserves, true);
assertEq(treasury.excessReserves(), tokenValue);
}
function test_originalCoefficientCorrect() public {
vm.startPrank(governor);
treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0));
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
vm.stopPrank();
uint256 estimation = 20 * 1e18;
uint256 estimationEps = estimation * 1e5 / 1e12; // .000001%
assertEq(estimation + estimationEps >= treasury.originalCoefficient(), true);
assertEq(estimation - estimationEps <= treasury.originalCoefficient(), true);
}
}

View File

@ -0,0 +1,121 @@
pragma solidity 0.8.20;
import {Test} from "forge-std/Test.sol";
import {StdChains} from "forge-std/StdChains.sol";
import "../../src/FatsoERC20.sol";
import "../../src/GhostAuthority.sol";
import "../../src/Treasury.sol";
import "../../src/StandardBondingCalculator.sol";
import "../../src/mocks/ERC20Mock.sol";
contract GhostTreasuryCoefficientLesserTest 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), "Fatso", "FTSO");
treasury = new GhostTreasury(address(ftso), 69, address(authority));
calculator = new GhostBondingCalculator(address(ftso), 1, 20);
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);
vm.startPrank(governor);
treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0));
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
vm.stopPrank();
}
function test_auditTreasuryReservesWithCoefficient() public {
vm.startPrank(governor);
treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0));
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
vm.stopPrank();
assertEq(treasury.totalReserves(), 0);
uint256 tokenValue = treasury.tokenValue(address(reserve), amount);
vm.prank(alice);
IERC20(reserve).transfer(address(treasury), amount);
assertEq(treasury.totalReserves(), 0);
vm.prank(governor);
treasury.auditReserves();
assertEq(treasury.totalReserves(), tokenValue);
uint256 coefficient = treasury.originalCoefficient();
uint256 decimals = IERC20Metadata(address(reserve)).decimals() + 9;
uint256 convertedReserves = treasury.totalReserves() * 10**decimals / coefficient;
uint256 convertedEps = convertedReserves * 1e5 / 1e12; // .000001%
assertEq(convertedReserves + convertedEps >= convertedReserves, true);
assertEq(convertedReserves - convertedEps <= convertedReserves, true);
assertEq(treasury.excessReserves(), tokenValue);
}
function test_originalCoefficientCorrect() public {
vm.startPrank(governor);
treasury.enable(ITreasury.STATUS.RESERVEDEPOSITOR, alice, address(0));
treasury.enable(ITreasury.STATUS.RESERVETOKEN, address(reserve), address(calculator));
vm.stopPrank();
uint256 estimation = 1e18 / 20;
uint256 estimationEps = estimation * 1e5 / 1e12; // .000001%
assertEq(estimation + estimationEps >= treasury.originalCoefficient(), true);
assertEq(estimation - estimationEps <= treasury.originalCoefficient(), true);
}
}

View File

@ -1,5 +1,5 @@
# exclude all tests dependant on rpc
forge test --no-match-test test_tokenValueIsCorret
forge test --no-match-test test_mainnet_
echo ""
echo "#####################################"
@ -11,4 +11,4 @@ echo ""
FORK_URL="${1:-https://eth-mainnet.alchemyapi.io/v2/pwc5rmJhrdoaSEfimoKEmsvOjKSmPDrP}"
# run tests where rpc to the mainnet is needed
forge test --match-test test_tokenValueIsCorret --fork-url $FORK_URL
forge test --match-test test_mainnet_ --fork-url $FORK_URL