github.com/cwntr/go-defi@v0.0.0-20210629134751-07f9ec2f7e66/contracts/handlers/sushiswap/libraries/UniswapV2Library.sol (about) 1 pragma solidity >=0.5.0; 2 3 import "@openzeppelin/contracts/math/SafeMath.sol"; 4 import "../IUniswapV2Pair.sol"; 5 6 7 library UniswapV2Library { 8 using SafeMath for uint256; 9 10 // returns sorted token addresses, used to handle return values from pairs sorted in this order 11 function sortTokens(address tokenA, address tokenB) 12 internal 13 pure 14 returns (address token0, address token1) 15 { 16 require(tokenA != tokenB, "UniswapV2Library: IDENTICAL_ADDRESSES"); 17 (token0, token1) = tokenA < tokenB 18 ? (tokenA, tokenB) 19 : (tokenB, tokenA); 20 require(token0 != address(0), "UniswapV2Library: ZERO_ADDRESS"); 21 } 22 23 // calculates the CREATE2 address for a pair without making any external calls 24 function pairFor( 25 address factory, 26 address tokenA, 27 address tokenB 28 ) internal pure returns (address pair) { 29 (address token0, address token1) = sortTokens(tokenA, tokenB); 30 31 pair = address( 32 uint256( 33 keccak256( 34 abi.encodePacked( 35 hex"ff", 36 factory, 37 keccak256(abi.encodePacked(token0, token1)), 38 hex"96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f" // init code hash 39 ) 40 ) 41 ) 42 ); 43 } 44 45 // fetches and sorts the reserves for a pair 46 function getReserves( 47 address factory, 48 address tokenA, 49 address tokenB 50 ) internal view returns (uint256 reserveA, uint256 reserveB) { 51 (address token0, ) = sortTokens(tokenA, tokenB); 52 (uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair( 53 pairFor(factory, tokenA, tokenB) 54 ) 55 .getReserves(); 56 (reserveA, reserveB) = tokenA == token0 57 ? (reserve0, reserve1) 58 : (reserve1, reserve0); 59 } 60 61 // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset 62 function quote( 63 uint256 amountA, 64 uint256 reserveA, 65 uint256 reserveB 66 ) internal pure returns (uint256 amountB) { 67 require(amountA > 0, "UniswapV2Library: INSUFFICIENT_AMOUNT"); 68 require( 69 reserveA > 0 && reserveB > 0, 70 "UniswapV2Library: INSUFFICIENT_LIQUIDITY" 71 ); 72 amountB = amountA.mul(reserveB) / reserveA; 73 } 74 75 // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset 76 function getAmountOut( 77 uint256 amountIn, 78 uint256 reserveIn, 79 uint256 reserveOut 80 ) internal pure returns (uint256 amountOut) { 81 require(amountIn > 0, "UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT"); 82 require( 83 reserveIn > 0 && reserveOut > 0, 84 "UniswapV2Library: INSUFFICIENT_LIQUIDITY" 85 ); 86 uint256 amountInWithFee = amountIn.mul(997); 87 uint256 numerator = amountInWithFee.mul(reserveOut); 88 uint256 denominator = reserveIn.mul(1000).add(amountInWithFee); 89 amountOut = numerator / denominator; 90 } 91 92 // given an output amount of an asset and pair reserves, returns a required input amount of the other asset 93 function getAmountIn( 94 uint256 amountOut, 95 uint256 reserveIn, 96 uint256 reserveOut 97 ) internal pure returns (uint256 amountIn) { 98 require(amountOut > 0, "UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT"); 99 require( 100 reserveIn > 0 && reserveOut > 0, 101 "UniswapV2Library: INSUFFICIENT_LIQUIDITY" 102 ); 103 uint256 numerator = reserveIn.mul(amountOut).mul(1000); 104 uint256 denominator = reserveOut.sub(amountOut).mul(997); 105 amountIn = (numerator / denominator).add(1); 106 } 107 108 // performs chained getAmountOut calculations on any number of pairs 109 function getAmountsOut( 110 address factory, 111 uint256 amountIn, 112 address[] memory path 113 ) internal view returns (uint256[] memory amounts) { 114 require(path.length >= 2, "UniswapV2Library: INVALID_PATH"); 115 amounts = new uint256[](path.length); 116 amounts[0] = amountIn; 117 for (uint256 i; i < path.length - 1; i++) { 118 (uint256 reserveIn, uint256 reserveOut) = getReserves( 119 factory, 120 path[i], 121 path[i + 1] 122 ); 123 amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); 124 } 125 } 126 127 // performs chained getAmountIn calculations on any number of pairs 128 function getAmountsIn( 129 address factory, 130 uint256 amountOut, 131 address[] memory path 132 ) internal view returns (uint256[] memory amounts) { 133 require(path.length >= 2, "UniswapV2Library: INVALID_PATH"); 134 amounts = new uint256[](path.length); 135 amounts[amounts.length - 1] = amountOut; 136 for (uint256 i = path.length - 1; i > 0; i--) { 137 (uint256 reserveIn, uint256 reserveOut) = getReserves( 138 factory, 139 path[i - 1], 140 path[i] 141 ); 142 amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); 143 } 144 } 145 }