// SPDX-License-Identifier: MIT pragma solidity 0.8.36; import {IFluxFactory} from "../interfaces/IFluxFactory.sol"; import {IFluxPair} from "../interfaces/IFluxPair.sol"; /// @title Pricing and reserve helpers shared by the router. library FluxLibrary { function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { require(tokenA != tokenB, "FluxLibrary: IDENTICAL_ADDRESSES"); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), "FluxLibrary: ZERO_ADDRESS"); } function pairFor(address factory, address tokenA, address tokenB) internal view returns (address pair) { pair = IFluxFactory(factory).getPair(tokenA, tokenB); require(pair != address(0), "FluxLibrary: PAIR_NOT_FOUND"); } function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint256 reserveA, uint256 reserveB) { (address token0,) = sortTokens(tokenA, tokenB); (uint112 reserve0, uint112 reserve1,) = IFluxPair(pairFor(factory, tokenA, tokenB)).getReserves(); (reserveA, reserveB) = tokenA == token0 ? (uint256(reserve0), uint256(reserve1)) : (uint256(reserve1), uint256(reserve0)); } /// @notice Equal-value counterpart amount given current reserves. function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) internal pure returns (uint256 amountB) { require(amountA > 0, "FluxLibrary: INSUFFICIENT_AMOUNT"); require(reserveA > 0 && reserveB > 0, "FluxLibrary: INSUFFICIENT_LIQUIDITY"); amountB = amountA * reserveB / reserveA; } /// @notice Output for an exact input, 0.3% fee applied to the input. function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut) internal pure returns (uint256 amountOut) { require(amountIn > 0, "FluxLibrary: INSUFFICIENT_INPUT_AMOUNT"); require(reserveIn > 0 && reserveOut > 0, "FluxLibrary: INSUFFICIENT_LIQUIDITY"); uint256 amountInWithFee = amountIn * 997; uint256 numerator = amountInWithFee * reserveOut; uint256 denominator = reserveIn * 1000 + amountInWithFee; amountOut = numerator / denominator; } /// @notice Input required for an exact output, 0.3% fee applied to the input. function getAmountIn(uint256 amountOut, uint256 reserveIn, uint256 reserveOut) internal pure returns (uint256 amountIn) { require(amountOut > 0, "FluxLibrary: INSUFFICIENT_OUTPUT_AMOUNT"); require(reserveIn > 0 && reserveOut > 0, "FluxLibrary: INSUFFICIENT_LIQUIDITY"); uint256 numerator = reserveIn * amountOut * 1000; uint256 denominator = (reserveOut - amountOut) * 997; amountIn = numerator / denominator + 1; } function getAmountsOut(address factory, uint256 amountIn, address[] memory path) internal view returns (uint256[] memory amounts) { require(path.length >= 2, "FluxLibrary: INVALID_PATH"); amounts = new uint256[](path.length); amounts[0] = amountIn; for (uint256 i; i < path.length - 1; i++) { (uint256 reserveIn, uint256 reserveOut) = getReserves(factory, path[i], path[i + 1]); amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); } } function getAmountsIn(address factory, uint256 amountOut, address[] memory path) internal view returns (uint256[] memory amounts) { require(path.length >= 2, "FluxLibrary: INVALID_PATH"); amounts = new uint256[](path.length); amounts[amounts.length - 1] = amountOut; for (uint256 i = path.length - 1; i > 0; i--) { (uint256 reserveIn, uint256 reserveOut) = getReserves(factory, path[i - 1], path[i]); amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); } } }