编译器
0.6.10+commit.00c0fcaf
文件 1 的 15:Address.sol
pragma solidity >=0.6.2 <0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 15:AddressArrayUtils.sol
pragma solidity 0.6.10;
library AddressArrayUtils {
function indexOf(address[] memory A, address a) internal pure returns (uint256, bool) {
uint256 length = A.length;
for (uint256 i = 0; i < length; i++) {
if (A[i] == a) {
return (i, true);
}
}
return (uint256(-1), false);
}
function contains(address[] memory A, address a) internal pure returns (bool) {
(, bool isIn) = indexOf(A, a);
return isIn;
}
function hasDuplicate(address[] memory A) internal pure returns(bool) {
require(A.length > 0, "A is empty");
for (uint256 i = 0; i < A.length - 1; i++) {
address current = A[i];
for (uint256 j = i + 1; j < A.length; j++) {
if (current == A[j]) {
return true;
}
}
}
return false;
}
function remove(address[] memory A, address a)
internal
pure
returns (address[] memory)
{
(uint256 index, bool isIn) = indexOf(A, a);
if (!isIn) {
revert("Address not in array.");
} else {
(address[] memory _A,) = pop(A, index);
return _A;
}
}
function removeStorage(address[] storage A, address a)
internal
{
(uint256 index, bool isIn) = indexOf(A, a);
if (!isIn) {
revert("Address not in array.");
} else {
uint256 lastIndex = A.length - 1;
if (index != lastIndex) { A[index] = A[lastIndex]; }
A.pop();
}
}
function pop(address[] memory A, uint256 index)
internal
pure
returns (address[] memory, address)
{
uint256 length = A.length;
require(index < A.length, "Index must be < A length");
address[] memory newAddresses = new address[](length - 1);
for (uint256 i = 0; i < index; i++) {
newAddresses[i] = A[i];
}
for (uint256 j = index + 1; j < length; j++) {
newAddresses[j - 1] = A[j];
}
return (newAddresses, A[index]);
}
function extend(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
uint256 aLength = A.length;
uint256 bLength = B.length;
address[] memory newAddresses = new address[](aLength + bLength);
for (uint256 i = 0; i < aLength; i++) {
newAddresses[i] = A[i];
}
for (uint256 j = 0; j < bLength; j++) {
newAddresses[aLength + j] = B[j];
}
return newAddresses;
}
function validatePairsWithArray(address[] memory A, uint[] memory B) internal pure {
require(A.length == B.length, "Array length mismatch");
_validateLengthAndUniqueness(A);
}
function validatePairsWithArray(address[] memory A, bool[] memory B) internal pure {
require(A.length == B.length, "Array length mismatch");
_validateLengthAndUniqueness(A);
}
function validatePairsWithArray(address[] memory A, string[] memory B) internal pure {
require(A.length == B.length, "Array length mismatch");
_validateLengthAndUniqueness(A);
}
function validatePairsWithArray(address[] memory A, address[] memory B) internal pure {
require(A.length == B.length, "Array length mismatch");
_validateLengthAndUniqueness(A);
}
function validatePairsWithArray(address[] memory A, bytes[] memory B) internal pure {
require(A.length == B.length, "Array length mismatch");
_validateLengthAndUniqueness(A);
}
function _validateLengthAndUniqueness(address[] memory A) internal pure {
require(A.length > 0, "Array length must be > 0");
require(!hasDuplicate(A), "Cannot duplicate addresses");
}
}
文件 3 的 15:Context.sol
pragma solidity >=0.6.0 <0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
文件 4 的 15:IERC20.sol
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);
}
文件 5 的 15:IUniswapV2Factory.sol
pragma solidity >=0.5.0;
interface IUniswapV2Factory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}
文件 6 的 15:IUniswapV2Pair.sol
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;
}
文件 7 的 15:IUniswapV2Router01.sol
pragma solidity >=0.6.2;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
文件 8 的 15:IUniswapV2Router02.sol
pragma solidity >=0.6.2;
import './IUniswapV2Router01.sol';
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}
文件 9 的 15:IWETH.sol
pragma solidity 0.6.10;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH is IERC20{
function deposit()
external
payable;
function withdraw(
uint256 wad
)
external;
}
文件 10 的 15:Math.sol
pragma solidity >=0.6.0 <0.8.0;
library Math {
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
}
文件 11 的 15:Ownable.sol
pragma solidity >=0.6.0 <0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
文件 12 的 15:SOFIProxy.sol
pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IUniswapV2Factory } from "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import { IUniswapV2Router02 } from "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import { Math } from "@openzeppelin/contracts/math/Math.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { UniSushiV2Library } from "./lib/UniSushiV2Library.sol";
import { AddressArrayUtils } from "./lib/AddressArrayUtils.sol";
import { IWETH } from "./interfaces/IWETH.sol";
contract SOFIProxy is Ownable {
using AddressArrayUtils for address[];
using Address for address payable;
using SafeMath for uint256;
using SafeERC20 for IERC20;
uint256 constant private MAX_UINT96 = 2**96 - 1;
address public WETH;
address[] public RouterList;
mapping(address => bool) public isRouter;
event TradeInfo(
address indexed _router,
address indexed _sender,
address _tokenIn,
address _tokenOut,
uint256 _amountIn,
uint256 _amountOut,
address indexed _to
);
constructor(
address _weth
)
public
{
WETH = _weth;
}
receive() external payable {
require(msg.sender == WETH, "SOFIProxy: Direct deposits not allowed");
}
function _safeApprove(IERC20 _token, address _spender, uint256 _requiredAllowance) internal {
uint256 allowance = _token.allowance(address(this), _spender);
if (allowance < _requiredAllowance) {
_token.safeIncreaseAllowance(_spender, MAX_UINT96 - allowance);
}
}
function _swapExactTokensForTokens(address _router, address _tokenIn, address _tokenOut, uint256 _amountIn, uint256 _amountOutMin) internal returns (uint256) {
if (_tokenIn == _tokenOut) {
return _amountIn;
}
address[] memory path = new address[](2);
path[0] = _tokenIn;
path[1] = _tokenOut;
return IUniswapV2Router02(_router).swapExactTokensForTokens(_amountIn, _amountOutMin, path, address(this), block.timestamp)[1];
}
function tradeTokenByExactETH(address _router, address _tokenOut, uint256 _amountOutMin, address _to) external payable returns (uint256) {
require(isRouter[_router], "Router does not exist");
require(msg.value > 0 && _amountOutMin >= 0, "INVALID INPUTS");
uint256 _amountOut;
IWETH(WETH).deposit{value: msg.value}();
if (_tokenOut == WETH) {
_amountOut = msg.value;
} else {
_safeApprove(IERC20(WETH), _router, msg.value);
_amountOut = _swapExactTokensForTokens(_router, WETH, _tokenOut, msg.value, _amountOutMin);
}
IERC20(_tokenOut).safeTransfer(_to, _amountOut);
emit TradeInfo(_router, msg.sender, address(0), _tokenOut, msg.value, _amountOut, _to);
return _amountOut;
}
function tradeETHByExactToken(address _router, address _tokenIn, uint256 _amountIn, uint256 _amountOutMin, address _to) external payable returns (uint256) {
require(isRouter[_router], "Router does not exist");
require(_amountIn > 0 && _amountOutMin >= 0, "INVALID INPUTSS");
uint256 _amountOut;
IERC20(_tokenIn).safeTransferFrom(msg.sender, address(this), _amountIn);
if (_tokenIn == WETH) {
_amountOut = _amountIn;
} else {
_safeApprove(IERC20(_tokenIn), _router, _amountIn);
_amountOut = _swapExactTokensForTokens(_router, _tokenIn, WETH, _amountIn, _amountOutMin);
}
IWETH(WETH).withdraw(_amountOut);
(payable(_to)).sendValue(_amountOut);
emit TradeInfo(_router, msg.sender, _tokenIn, address(0), _amountIn, _amountOut, _to);
return _amountOut;
}
function tradeTokenByExactToken(address _router, address _tokenIn, address _tokenOut, uint256 _amountIn, uint256 _amountOutMin,address _to) external returns (uint256) {
require(isRouter[_router], "Router does not exist");
require(_tokenIn != _tokenOut && _amountOutMin >= 0, "INVALID INPUTS");
IERC20(_tokenIn).safeTransferFrom(msg.sender, address(this), _amountIn);
_safeApprove(IERC20(_tokenIn), _router, _amountIn);
uint256 _amountOut = _swapExactTokensForTokens(_router, _tokenIn, _tokenOut, _amountIn, _amountOutMin);
IERC20(_tokenOut).safeTransfer(_to, _amountOut);
emit TradeInfo(_router, msg.sender, _tokenIn, _tokenOut, _amountIn, _amountOut, _to);
return _amountOut;
}
function _swapTokensForExactTokens(address _router, address _tokenIn, address _tokenOut, uint256 _amountOut, uint256 _amountInMax) internal returns (uint256) {
if (_tokenIn == _tokenOut) {
return _amountOut;
}
address[] memory path = new address[](2);
path[0] = _tokenIn;
path[1] = _tokenOut;
return IUniswapV2Router02(_router).swapTokensForExactTokens(_amountOut, _amountInMax, path, address(this), block.timestamp)[0];
}
function tradeExactTokenByToken(address _router, address _tokenIn, address _tokenOut, uint256 _amountOut, uint256 _amountInMax, address _to) external returns (uint256) {
require(isRouter[_router], "Router does not exist");
require(_tokenIn != _tokenOut, "Same token In && Out");
IERC20(_tokenIn).safeTransferFrom(msg.sender, address(this), _amountInMax);
_safeApprove(IERC20(_tokenIn), _router, _amountInMax);
uint256 _amountInSpent = _swapTokensForExactTokens(_router, _tokenIn, _tokenOut, _amountOut, _amountInMax);
IERC20(_tokenOut).safeTransfer(_to, _amountOut);
uint256 _amountInReturn = _amountInMax.sub(_amountInSpent);
if (_amountInReturn > 0) {
IERC20(_tokenIn).safeTransfer(msg.sender, _amountInReturn);
}
emit TradeInfo(_router, msg.sender, _tokenIn, _tokenOut, _amountInSpent, _amountOut, _to);
return _amountInSpent;
}
function addRouter(address _routerAddress) external onlyOwner {
require(!isRouter[_routerAddress], "Router already exists");
isRouter[_routerAddress] = true;
RouterList.push(_routerAddress);
}
function removeRouter(address _routerAddress) external onlyOwner {
require(isRouter[_routerAddress], "Router does not exist");
RouterList = RouterList.remove(_routerAddress);
isRouter[_routerAddress] = false;
}
function getRouters() external view returns (address[] memory) {
return RouterList;
}
function getUniV2Routers(uint256 _amountIn, address _tokenIn, address _tokenOut) public view returns (address[] memory, uint256[] memory) {
require(_tokenIn != _tokenOut, '_tokenIn should not equal _tokenOut');
require(_amountIn > 0, '_amountIn should > 0');
uint256 routerCount = RouterList.length;
uint256[] memory amountOutList = new uint256[](routerCount);
for (uint i = 0; i < routerCount; i++) {
address _pair = _getPair(RouterList[i], _tokenIn, _tokenOut);
if(_pair != address(0)) {
(uint256 _reserveIn, uint256 _reserveOut) = UniSushiV2Library.getReserves(_pair, _tokenIn, _tokenOut);
uint256 _amountOut = UniSushiV2Library.getAmountOut(_amountIn, _reserveIn, _reserveOut);
amountOutList[i] = _amountOut;
}
}
return (RouterList, amountOutList);
}
function getMaxAmountOut(uint256 _amountIn, address _tokenIn, address _tokenOut) external view returns (uint256, address, address) {
require(_amountIn > 0, '_amountIn should > 0');
if (_tokenIn == _tokenOut) {
return (_amountIn, address(0), address(0));
}
uint256 _maxAmountOut = 0;
address _maxRouter = address(0);
address _maxPair = address(0);
uint256 routerCount = RouterList.length;
for (uint i = 0; i < routerCount; i++) {
address _pair = _getPair(RouterList[i] , _tokenIn, _tokenOut);
if(_pair != address(0)) {
(uint256 _reserveIn, uint256 _reserveOut) = UniSushiV2Library.getReserves(_pair, _tokenIn, _tokenOut);
uint256 _amountOut = UniSushiV2Library.getAmountOut(_amountIn, _reserveIn, _reserveOut);
_maxRouter = (_amountOut > _maxAmountOut) ? RouterList[i] : _maxRouter;
_maxPair = (_amountOut > _maxAmountOut) ? _pair : _maxPair;
_maxAmountOut = (_amountOut > _maxAmountOut) ? _amountOut : _maxAmountOut;
}
}
return (_maxAmountOut, _maxRouter, _maxPair);
}
function getMinAmountIn(uint256 _amountOut, address _tokenIn, address _tokenOut) external view returns (uint256, address, address) {
require(_amountOut > 0, '_amountOut should > 0');
if (_tokenIn == _tokenOut) {
return (_amountOut, address(0), address(0));
}
uint256 _minAmountIn = MAX_UINT96;
address _minRouter = address(0);
address _minPair = address(0);
uint256 routerCount = RouterList.length;
for (uint i = 0; i < routerCount; i++) {
address _pair = _getPair(RouterList[i] , _tokenIn, _tokenOut);
if(_pair != address(0)) {
(uint256 _reserveIn, uint256 _reserveOut) = UniSushiV2Library.getReserves(_pair, _tokenIn, _tokenOut);
if (_reserveOut > _amountOut) {
uint256 _amountIn = UniSushiV2Library.getAmountIn(_amountOut, _reserveIn, _reserveOut);
_minRouter = (_amountIn < _minAmountIn) ? RouterList[i] : _minRouter;
_minPair = (_amountIn < _minAmountIn) ? _pair : _minPair;
_minAmountIn = (_amountIn < _minAmountIn) ? _amountIn : _minAmountIn;
}
}
}
require(_minAmountIn < MAX_UINT96 && _minAmountIn > 0, "SOFIProxy: LIQUID_INVALID");
return (_minAmountIn, _minRouter, _minPair);
}
function _getPair(address _router, address _tokenIn, address _tokenOut) internal view returns (address) {
address _factory = IUniswapV2Router02(_router).factory();
return IUniswapV2Factory(_factory).getPair(_tokenIn, _tokenOut);
}
}
文件 13 的 15:SafeERC20.sol
pragma solidity >=0.6.0 <0.8.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 14 的 15:SafeMath.sol
pragma solidity >=0.6.0 <0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
文件 15 的 15:UniSushiV2Library.sol
pragma solidity >=0.5.0;
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
library UniSushiV2Library {
using SafeMath for uint;
function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES');
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS');
}
function getReserves(address pair, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) {
(address token0,) = sortTokens(tokenA, tokenB);
(uint reserve0, uint reserve1,) = IUniswapV2Pair(pair).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) {
require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT');
require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
amountB = amountA.mul(reserveB) / reserveA;
}
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) {
require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT');
require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
uint amountInWithFee = amountIn.mul(997);
uint numerator = amountInWithFee.mul(reserveOut);
uint denominator = reserveIn.mul(1000).add(amountInWithFee);
amountOut = numerator / denominator;
}
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) {
require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT');
require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
uint numerator = reserveIn.mul(amountOut).mul(1000);
uint denominator = reserveOut.sub(amountOut).mul(997);
amountIn = (numerator / denominator).add(1);
}
function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) {
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');
amounts = new uint[](path.length);
amounts[0] = amountIn;
for (uint i; i < path.length - 1; i++) {
(uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]);
amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
}
}
function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) {
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');
amounts = new uint[](path.length);
amounts[amounts.length - 1] = amountOut;
for (uint i = path.length - 1; i > 0; i--) {
(uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]);
amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
}
}
}
{
"compilationTarget": {
"contracts/SOFIProxy.sol": "SOFIProxy"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_router","type":"address"},{"indexed":true,"internalType":"address","name":"_sender","type":"address"},{"indexed":false,"internalType":"address","name":"_tokenIn","type":"address"},{"indexed":false,"internalType":"address","name":"_tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amountOut","type":"uint256"},{"indexed":true,"internalType":"address","name":"_to","type":"address"}],"name":"TradeInfo","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"RouterList","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_routerAddress","type":"address"}],"name":"addRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"}],"name":"getMaxAmountOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"}],"name":"getMinAmountIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRouters","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"}],"name":"getUniV2Routers","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isRouter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_routerAddress","type":"address"}],"name":"removeRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_router","type":"address"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"tradeETHByExactToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_router","type":"address"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"uint256","name":"_amountOut","type":"uint256"},{"internalType":"uint256","name":"_amountInMax","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"tradeExactTokenByToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_router","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"tradeTokenByExactETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_router","type":"address"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"tradeTokenByExactToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]