文件 1 的 1:UniswapV3Router.sol
pragma solidity >=0.6.0;
library TransferHelper {
function safeApprove(address token, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
}
function safeTransfer(address token, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
}
function safeTransferFrom(address token, address from, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
}
function safeTransferETH(address to, uint value) internal {
(bool success,) = to.call{value:value}(new bytes(0));
require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
}
}
pragma solidity >=0.5.0;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
pragma solidity >=0.5.0;
library SafeMath {
function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x + y) >= x, "ds-math-add-overflow");
}
function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x - y) <= x, "ds-math-sub-underflow");
}
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
}
}
library UniswapV3Lib {
using SafeMath for uint256;
function checkAndConvertETHToWETH(address token) internal pure returns(address) {
if(token == address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)) {
return address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
}
return token;
}
function sortTokens(address tokenA, address tokenB) internal pure returns (address, address) {
return(tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA));
}
function pairFor(address factory, address tokenA, address tokenB, bytes32 initCode) internal pure returns (address) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
return(address(uint(keccak256(abi.encodePacked(
hex"ff",
factory,
keccak256(abi.encodePacked(token0, token1)),
initCode
)))));
}
function getReservesByPair(address pair, address tokenA, address tokenB) internal view returns (uint256 reserveA, uint256 reserveB) {
(address token0,) = sortTokens(tokenA, tokenB);
(uint256 reserve0, uint256 reserve1,) = IUniswapV2Pair(pair).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut) internal pure returns (uint256 amountOut) {
require(amountIn > 0, "UniswapV3Library: INSUFFICIENT_INPUT_AMOUNT");
uint256 amountInWithFee = amountIn.mul(997);
uint256 numerator = amountInWithFee.mul(reserveOut);
uint256 denominator = reserveIn.mul(1000).add(amountInWithFee);
amountOut = uint256(numerator / denominator);
}
function getAmountInAndPair(address factory, uint amountOut, address tokenA, address tokenB, bytes32 initCode) internal view returns (uint256 amountIn, address pair) {
tokenA = checkAndConvertETHToWETH(tokenA);
tokenB = checkAndConvertETHToWETH(tokenB);
pair = pairFor(factory, tokenA, tokenB, initCode);
(uint256 reserveIn, uint256 reserveOut) = getReservesByPair(pair, tokenA, tokenB);
require(amountOut > 0, "UniswapV3Library: INSUFFICIENT_OUTPUT_AMOUNT");
require(reserveOut > amountOut, "UniswapV3Library: reserveOut should be greater than amountOut");
uint numerator = reserveIn.mul(amountOut).mul(1000);
uint denominator = reserveOut.sub(amountOut).mul(997);
amountIn = (numerator / denominator).add(1);
}
function getAmountOutByPair(uint256 amountIn, address pair, address tokenA, address tokenB) internal view returns(uint256 amountOut) {
(uint256 reserveIn, uint256 reserveOut) = getReservesByPair(pair, tokenA, tokenB);
return (getAmountOut(amountIn, reserveIn, reserveOut));
}
}
pragma solidity >=0.6.0 <0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
pragma solidity 0.7.5;
abstract contract IWETH is IERC20 {
function deposit() external virtual payable;
function withdraw(uint256 amount) external virtual;
}
pragma solidity =0.7.5;
contract UniswapV3Router {
using SafeMath for uint;
address public immutable factory;
address public immutable WETH;
address public constant ETH_IDENTIFIER = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
bytes32 public initCode;
constructor(address _factory, address _WETH, bytes32 _initCode) public {
factory = _factory;
WETH = _WETH;
initCode = _initCode;
}
receive() external payable {
}
function swap(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path
)
external
payable
returns (uint256 tokensBought)
{
require(path.length > 1, "More than 1 token required");
uint8 pairs = uint8(path.length - 1);
bool tokensBoughtEth;
tokensBought = amountIn;
address receiver;
for(uint8 i = 0; i < pairs; i++) {
address tokenSold = path[i];
address tokenBought = path[i+1];
address currentPair = receiver;
if (i == pairs - 1) {
if (tokenBought == ETH_IDENTIFIER) {
tokenBought = WETH;
tokensBoughtEth = true;
}
}
if (i == 0) {
if (tokenSold == ETH_IDENTIFIER) {
tokenSold = WETH;
currentPair = UniswapV3Lib.pairFor(factory, tokenSold, tokenBought, initCode);
uint256 amount = msg.value;
IWETH(WETH).deposit{value: amount}();
assert(IWETH(WETH).transfer(currentPair, amount));
}
else {
currentPair = UniswapV3Lib.pairFor(factory, tokenSold, tokenBought, initCode);
TransferHelper.safeTransferFrom(
tokenSold, msg.sender, currentPair, amountIn
);
}
}
tokensBought = UniswapV3Lib.getAmountOutByPair(tokensBought, currentPair, tokenSold, tokenBought);
if ((i + 1) == pairs) {
if ( tokensBoughtEth ) {
receiver = address(this);
}
else {
receiver = msg.sender;
}
}
else {
receiver = UniswapV3Lib.pairFor(factory, tokenBought, path[i+2] == ETH_IDENTIFIER ? WETH : path[i+2], initCode);
}
(address token0,) = UniswapV3Lib.sortTokens(tokenSold, tokenBought);
(uint256 amount0Out, uint256 amount1Out) = tokenSold == token0 ? (uint256(0), tokensBought) : (tokensBought, uint256(0));
IUniswapV2Pair(currentPair).swap(
amount0Out, amount1Out, receiver, new bytes(0)
);
}
if (tokensBoughtEth) {
IWETH(WETH).withdraw(tokensBought);
TransferHelper.safeTransferETH(msg.sender, tokensBought);
}
require(tokensBought >= amountOutMin, "UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT");
}
function buy(
uint256 amountInMax,
uint256 amountOut,
address[] calldata path
)
external
payable
returns (uint256 tokensSold)
{
require(path.length > 1, "More than 1 token required");
bool tokensBoughtEth;
uint8 length = uint8(path.length);
uint256[] memory amounts = new uint256[](length);
address[] memory pairs = new address[](length - 1);
amounts[length - 1] = amountOut;
for (uint8 i = length - 1; i > 0; i--) {
(amounts[i - 1], pairs[i - 1]) = UniswapV3Lib.getAmountInAndPair(
factory,
amounts[i],
path[i-1],
path[i],
initCode
);
}
tokensSold = amounts[0];
require(tokensSold <= amountInMax, "UniswapV3Router: INSUFFICIENT_INPUT_AMOUNT");
for(uint8 i = 0; i < length - 1; i++) {
address tokenSold = path[i];
address tokenBought = path[i+1];
if (i == length - 2) {
if (tokenBought == ETH_IDENTIFIER) {
tokenBought = WETH;
tokensBoughtEth = true;
}
}
if (i == 0) {
if (tokenSold == ETH_IDENTIFIER) {
tokenSold = WETH;
TransferHelper.safeTransferETH(msg.sender, msg.value.sub(tokensSold));
IWETH(WETH).deposit{value: tokensSold}();
assert(IWETH(WETH).transfer(pairs[i], tokensSold));
}
else {
TransferHelper.safeTransferFrom(
tokenSold, msg.sender, pairs[i], tokensSold
);
}
}
address receiver;
if (i == length - 2) {
if (tokensBoughtEth) {
receiver = address(this);
}
else {
receiver = msg.sender;
}
}
else {
receiver = pairs[i+1];
}
(address token0,) = UniswapV3Lib.sortTokens(tokenSold, tokenBought);
(uint256 amount0Out, uint256 amount1Out) = tokenSold == token0 ? (uint256(0), amounts[i+1]) : (amounts[i+1], uint256(0));
IUniswapV2Pair(pairs[i]).swap(
amount0Out, amount1Out, receiver, new bytes(0)
);
}
if (tokensBoughtEth) {
IWETH(WETH).withdraw(amountOut);
TransferHelper.safeTransferETH(msg.sender, amountOut);
}
}
}