PangolinLibrary.sol
1 pragma solidity >=0.5.0; 2 3 import "./SafeMath.sol"; 4 import "@pangolindex/exchange-contracts/contracts/pangolin-core/interfaces/IPangolinPair.sol"; 5 6 library PangolinLibrary { 7 using SafeMath for uint; 8 9 // returns sorted token addresses, used to handle return values from pairs sorted in this order 10 function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { 11 require(tokenA != tokenB, 'PangolinLibrary: IDENTICAL_ADDRESSES'); 12 (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); 13 require(token0 != address(0), 'PangolinLibrary: ZERO_ADDRESS'); 14 } 15 16 // calculates the CREATE2 address for a pair without making any external calls 17 function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) { 18 (address token0, address token1) = sortTokens(tokenA, tokenB); 19 pair = address(uint(keccak256(abi.encodePacked( 20 hex'ff', 21 factory, 22 keccak256(abi.encodePacked(token0, token1)), 23 hex'40231f6b438bce0797c9ada29b718a87ea0a5cea3fe9a771abdd76bd41a3e545' // init code hash 24 )))); 25 } 26 27 // fetches and sorts the reserves for a pair 28 function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) { 29 (address token0,) = sortTokens(tokenA, tokenB); 30 (uint reserve0, uint reserve1,) = IPangolinPair(pairFor(factory, tokenA, tokenB)).getReserves(); 31 (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); 32 } 33 34 // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset 35 function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) { 36 require(amountA > 0, 'PangolinLibrary: INSUFFICIENT_AMOUNT'); 37 require(reserveA > 0 && reserveB > 0, 'PangolinLibrary: INSUFFICIENT_LIQUIDITY'); 38 amountB = amountA.mul(reserveB) / reserveA; 39 } 40 41 // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset 42 function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) { 43 require(amountIn > 0, 'PangolinLibrary: INSUFFICIENT_INPUT_AMOUNT'); 44 require(reserveIn > 0 && reserveOut > 0, 'PangolinLibrary: INSUFFICIENT_LIQUIDITY'); 45 uint amountInWithFee = amountIn.mul(997); 46 uint numerator = amountInWithFee.mul(reserveOut); 47 uint denominator = reserveIn.mul(1000).add(amountInWithFee); 48 amountOut = numerator / denominator; 49 } 50 51 // given an output amount of an asset and pair reserves, returns a required input amount of the other asset 52 function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) { 53 require(amountOut > 0, 'PangolinLibrary: INSUFFICIENT_OUTPUT_AMOUNT'); 54 require(reserveIn > 0 && reserveOut > 0, 'PangolinLibrary: INSUFFICIENT_LIQUIDITY'); 55 uint numerator = reserveIn.mul(amountOut).mul(1000); 56 uint denominator = reserveOut.sub(amountOut).mul(997); 57 amountIn = (numerator / denominator).add(1); 58 } 59 60 // performs chained getAmountOut calculations on any number of pairs 61 function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) { 62 require(path.length >= 2, 'PangolinLibrary: INVALID_PATH'); 63 amounts = new uint[](path.length); 64 amounts[0] = amountIn; 65 for (uint i; i < path.length - 1; i++) { 66 (uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]); 67 amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); 68 } 69 } 70 71 // performs chained getAmountIn calculations on any number of pairs 72 function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) { 73 require(path.length >= 2, 'PangolinLibrary: INVALID_PATH'); 74 amounts = new uint[](path.length); 75 amounts[amounts.length - 1] = amountOut; 76 for (uint i = path.length - 1; i > 0; i--) { 77 (uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]); 78 amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); 79 } 80 } 81 }