// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "./libraries/FixedPoint.sol"; import "@openzeppelin-contracts/utils/Address.sol"; import "@openzeppelin-contracts/token/ERC20/IERC20.sol"; import "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "@uniswap-v2-core/interfaces/IUniswapV2ERC20.sol"; import "@uniswap-v2-core/interfaces/IUniswapV2Pair.sol"; import "./interfaces/IBondingCalculator.sol"; contract GhostBondingCalculator is IBondingCalculator { using FixedPoint for *; uint256 public override immutable fraction; address internal immutable ftso; constructor(address _ftso, uint256 _numerator, uint256 _denominator) { ftso = _ftso; fraction = FixedPoint.fraction(_numerator, _denominator).decode112with18(); } function getKValue(address pair, bool isCoefficient) public view returns (uint256 k) { uint256 token0 = IERC20Metadata(IUniswapV2Pair(pair).token0()).decimals(); uint256 token1 = IERC20Metadata(IUniswapV2Pair(pair).token1()).decimals(); uint256 decimals = token0 + token1 - IERC20Metadata(pair).decimals(); (uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(pair).getReserves(); k = reserve0 * reserve1 / (10**decimals); if (isCoefficient) { k = k * 1e18 / fraction; } } function getTotalValue(address pair, bool isCoefficient) public view returns (uint256) { return _sqrt(getKValue(pair, isCoefficient)) * 2; } function valuation(address pair, uint256 amount) external view override returns (uint256 value) { uint256 totalValue = getTotalValue(pair, true); uint256 totalSupply = IUniswapV2Pair(pair).totalSupply(); value = totalValue * FixedPoint.fraction(amount, totalSupply).decode112with18() / 1e18; } function markdown(address pair) external view override returns (uint256 reserve) { (uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(pair).getReserves(); if (IUniswapV2Pair(pair).token0() == ftso) { reserve = reserve1; } else { if (IUniswapV2Pair(pair).token1() != ftso) revert InvalidPair(); reserve = reserve0; } reserve = reserve * (2 * 1e9) / getTotalValue(pair, false); reserve = reserve * _sqrt(fraction) / 1e9; } function _sqrt(uint256 a) private pure returns (uint256 c) { if (a > 3) { c = a; uint256 b = (a / 2) + 1; while (b < c) { c = b; b = ((a / b) + b) / 2; } } else if (a != 0) { c = 1; } } }