draft fixes for native-only support; tests broken

Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
This commit is contained in:
Uncle Fatso 2025-10-06 15:34:25 +03:00
parent 8746bc747a
commit 9dfd10aff7
Signed by: f4ts0
GPG Key ID: 565F4F2860226EBB
4 changed files with 81 additions and 10 deletions

View File

@ -16,27 +16,33 @@ import "./interfaces/IBondingCalculator.sol";
contract GhostBondingCalculator is IBondingCalculator { contract GhostBondingCalculator is IBondingCalculator {
using FixedPoint for *; using FixedPoint for *;
uint256 public override immutable fraction;
address internal immutable ftso; address internal immutable ftso;
constructor(address _ftso) { constructor(address _ftso, uint256 _numerator, uint256 _denominator) {
ftso = _ftso; ftso = _ftso;
fraction = FixedPoint.fraction(_numerator, _denominator).decode112with18();
} }
function getKValue(address pair) public view returns (uint256 k) { function getKValue(address pair, bool isCoefficient) public view returns (uint256 k) {
uint256 token0 = IERC20Metadata(IUniswapV2Pair(pair).token0()).decimals(); uint256 token0 = IERC20Metadata(IUniswapV2Pair(pair).token0()).decimals();
uint256 token1 = IERC20Metadata(IUniswapV2Pair(pair).token1()).decimals(); uint256 token1 = IERC20Metadata(IUniswapV2Pair(pair).token1()).decimals();
uint256 decimals = token0 + token1 - IERC20Metadata(pair).decimals(); uint256 decimals = token0 + token1 - IERC20Metadata(pair).decimals();
(uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(pair).getReserves(); (uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(pair).getReserves();
k = reserve0 * reserve1 / (10**decimals); k = reserve0 * reserve1 / (10**decimals);
if (isCoefficient) {
k = k * 1e18 / fraction;
}
} }
function getTotalValue(address pair) public view returns (uint256 value) { function getTotalValue(address pair, bool isCoefficient) public view returns (uint256) {
return _sqrt(getKValue(pair)) * 2; return _sqrt(getKValue(pair, isCoefficient)) * 2;
} }
function valuation(address pair, uint256 amount) external view override returns (uint256 value) { function valuation(address pair, uint256 amount) external view override returns (uint256 value) {
uint256 totalValue = getTotalValue(pair); uint256 totalValue = getTotalValue(pair, true);
uint256 totalSupply = IUniswapV2Pair(pair).totalSupply(); uint256 totalSupply = IUniswapV2Pair(pair).totalSupply();
value = totalValue * FixedPoint.fraction(amount, totalSupply).decode112with18() / 1e18; value = totalValue * FixedPoint.fraction(amount, totalSupply).decode112with18() / 1e18;
@ -52,7 +58,8 @@ contract GhostBondingCalculator is IBondingCalculator {
reserve = reserve0; reserve = reserve0;
} }
reserve = reserve * (2 * 1e9) / getTotalValue(pair); reserve = reserve * (2 * 1e9) / getTotalValue(pair, false);
reserve = reserve * _sqrt(fraction) / 1e9;
} }
function _sqrt(uint256 a) private pure returns (uint256 c) { function _sqrt(uint256 a) private pure returns (uint256 c) {

View File

@ -190,7 +190,7 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
stnk = someAddress; stnk = someAddress;
} else { } else {
permissions[status][someAddress] = true; permissions[status][someAddress] = true;
if (status == STATUS.LIQUIDITYTOKEN) { if (status == STATUS.LIQUIDITYTOKEN || status == STATUS.RESERVETOKEN) {
bondCalculator[someAddress] = calculatorAddress; bondCalculator[someAddress] = calculatorAddress;
} }
@ -211,6 +211,66 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
emit Permissioned(toDisable, status, false); emit Permissioned(toDisable, status, false);
} }
// function redeemReserve(
// address router,
// address token,
// uint256 amountIn
// ) external onlyGovernor {
// uint256 balance;
// uint256 amountOutMin;
// uint256 deadline = block.timestamp; // No delays in timestamp
// address weth = IUniswapV2Router(router).WETH();
//
// // Reconstruct path based on token address.
// // Avoid user's input error.
// address[2] memory path = [token, weth];
// if (token >= weth) {
// path[0] = weth;
// path[1] = token;
// }
//
// for (uint256 i; i < path.length;) {
// if (path[i] != WETH) {
// balance = IERC20(path[i]).balanceOf(address(this));
// // amountOutMin = ...
// // put big sqrt formula here
// }
// unchecked { ++i; }
// }
//
// // Approve amountIn for swap only.
// if (IERC20(token).allowance(router) <= amountIn) {
// IERC20(token).approve(router, 1e64);
// }
//
// (amountIn, amountOut) = IUniswapV2Router(router).swapExactTokensForTokens(
// amountIn,
// amountOutMin,
// path,
// address(this),
// deadline
// );
//
// if (IERC20(token).allowance(router) <= desiredA) {
// IERC20(token).approve(router, 1e64);
// }
//
// if (IERC20(weth).allowance(router) <= desiredB) {
// IERC20(token).approve(router, 1e64);
// }
//
// IUniswapV2Router(router).addLiquidity(
// path[0],
// path[1],
// desiredA, // could be calculated with sqrt formula
// desiredB, // same as above
// minA, // zeroed or calculated or precomputed?
// minB, // zeroed or calculated or precomputed?
// address(this),
// deadline
// );
// }
function indexInRegistry( function indexInRegistry(
address someAddress, address someAddress,
STATUS status STATUS status
@ -266,7 +326,7 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
} else { } else {
permissions[info.managing][info.toPermit] = true; permissions[info.managing][info.toPermit] = true;
if (info.managing == STATUS.LIQUIDITYTOKEN) { if (info.managing == STATUS.LIQUIDITYTOKEN || info.managing == STATUS.RESERVETOKEN) {
bondCalculator[info.toPermit] = info.calculator; bondCalculator[info.toPermit] = info.calculator;
} }
@ -301,10 +361,13 @@ contract GhostTreasury is GhostAccessControlled, ITreasury {
address token, address token,
uint256 amount uint256 amount
) public view override returns (uint256 value) { ) public view override returns (uint256 value) {
value = amount * 1e9 / (10**IERC20Metadata(token).decimals()); address currentBondCalculator = bondCalculator[token];
if (permissions[STATUS.LIQUIDITYTOKEN][token]) { if (permissions[STATUS.LIQUIDITYTOKEN][token]) {
value = IBondingCalculator(bondCalculator[token]).valuation(token, amount); value = IBondingCalculator(bondCalculator[token]).valuation(token, amount);
} else {
value = amount * 1e9 / (10**IERC20Metadata(token).decimals());
value = value * IBondingCalculator(currentBondCalculator).fraction() / 1e18;
} }
} }

View File

@ -3,6 +3,7 @@ pragma solidity ^0.8.20;
interface IBondingCalculator { interface IBondingCalculator {
error InvalidPair(); error InvalidPair();
function fraction() external view returns (uint256);
function markdown(address _lp) external view returns (uint256); function markdown(address _lp) external view returns (uint256);
function valuation(address pair_, uint256 amount_) external view returns (uint256 _value); function valuation(address pair_, uint256 amount_) external view returns (uint256 _value);
} }

View File

@ -37,7 +37,7 @@ contract GhostTreasuryTest is Test {
liquidity = new ERC20Mock("Liquidity Token", "LDT"); liquidity = new ERC20Mock("Liquidity Token", "LDT");
ftso = new Fatso(address(authority), "Fatso", "FTSO"); ftso = new Fatso(address(authority), "Fatso", "FTSO");
treasury = new GhostTreasury(address(ftso), 69, address(authority)); treasury = new GhostTreasury(address(ftso), 69, address(authority));
calculator = new GhostBondingCalculator(address(ftso)); calculator = new GhostBondingCalculator(address(ftso), 1, 1);
vm.stopPrank(); vm.stopPrank();
vm.prank(governor); vm.prank(governor);