文件 1 的 8:Arbitrageur.sol
pragma solidity 0.6.6;
pragma experimental ABIEncoderV2;
import "./IUniswapV2Route.sol";
import "./IUniswapV2Factory.sol";
import "./IUniswapV2Pair.sol";
import "./IUniswapV1Factory.sol";
import "./IUniswapV1Exchange.sol";
import "./IERC20.sol";
import "./IWBNB.sol";
contract Arbitrageur{
address private owner;
IWBNB private constant WBNB = IWBNB(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
constructor() public{
owner = msg.sender;
}
receive() external payable {}
modifier onlyOwner {
require(
msg.sender == owner,
"Only owner can call this function."
);
_;
}
struct Exchange{
address[] pair;
address route;
int version;
}
struct Factory{
address factory;
int version;
}
function makeArbitrage(Exchange[] memory exchanges, uint amountIn, uint expectedAmountOut) public {
require(checkArbitrageStillExists(exchanges, amountIn) > expectedAmountOut, "X Y Z");
uint baseTokenInitialBalance = getBalanceToken(exchanges[0].pair[0]);
require(baseTokenInitialBalance >= amountIn, "Insufficient balance!");
uint amountToSwap = amountIn;
uint deadline = getDeadline();
for(uint i = 0; i < exchanges.length; i++){
if(exchanges[i].version == 2){
IERC20 token = IERC20(exchanges[i].pair[0]);
require(
token.approve(exchanges[i].route, amountToSwap),
"Could not approve token!"
);
uint[] memory amountReceived = IUniswapV2Route(exchanges[i].route).swapExactTokensForTokens(
amountToSwap,
1,
exchanges[i].pair,
address(this),
deadline
);
amountToSwap = amountReceived[amountReceived.length-1];
}
else{
IUniswapV1Factory factoryV1 = IUniswapV1Factory(exchanges[i].route);
if(isWBNB(exchanges[i].pair[0])){
IUniswapV1Exchange exchangeV1 = IUniswapV1Exchange(factoryV1.getExchange(exchanges[i].pair[1]));
WBNB.withdraw(amountToSwap);
uint amountReceived = exchangeV1.ethToTokenSwapInput{value: amountToSwap}(1, deadline);
amountToSwap = amountReceived;
}
else{
IUniswapV1Exchange exchangeV1 = IUniswapV1Exchange(factoryV1.getExchange(exchanges[i].pair[0]));
IERC20 token = IERC20(exchanges[i].pair[0]);
require(
token.approve(address(exchangeV1), amountToSwap),
"Could not approve token!"
);
uint amountReceived = exchangeV1.tokenToEthSwapInput(amountToSwap, 1, deadline);
WBNB.deposit{value: amountReceived}();
amountToSwap = amountReceived;
}
}
}
uint baseTokenFinalBalance = getBalanceToken(exchanges[0].pair[0]);
require(baseTokenFinalBalance > baseTokenInitialBalance, "XYZ");
}
function checkArbitrageStillExists(Exchange[] memory exchanges, uint amountIn) public view returns (uint) {
uint amountToSwap = amountIn;
for(uint i = 0; i < exchanges.length; i++){
if(exchanges[i].version == 2){
uint[] memory amountOutMin = IUniswapV2Route(exchanges[i].route).getAmountsOut(
amountToSwap,
exchanges[i].pair);
amountToSwap = amountOutMin[amountOutMin.length-1];
}
else{
IUniswapV1Factory factoryV1 = IUniswapV1Factory(exchanges[i].route);
if(isWBNB(exchanges[i].pair[0])){
IUniswapV1Exchange exchangeV1 = IUniswapV1Exchange(factoryV1.getExchange(exchanges[i].pair[1]));
uint amountOutMin = exchangeV1.getEthToTokenInputPrice(amountToSwap);
amountToSwap = amountOutMin;
}
else{
IUniswapV1Exchange exchangeV1 = IUniswapV1Exchange(factoryV1.getExchange(exchanges[i].pair[0]));
uint amountOutMin = exchangeV1.getTokenToEthInputPrice(amountToSwap);
amountToSwap = amountOutMin;
}
}
}
return amountToSwap;
}
function getAllReserves(address tokenA, address tokenB, Factory[] memory factories) public view returns (uint[][] memory){
uint[][] memory allReserves = new uint[][](factories.length);
for(uint i = 0; i < allReserves.length; i++){
if(factories[i].version == 2){
try this.getReserves(factories[i].factory, tokenA, tokenB) returns (uint reserveA, uint reserveB) {
uint [] memory reserves = new uint[](3);
reserves[0] = i;
reserves[1] = reserveA;
reserves[2] = reserveB;
allReserves[i] = reserves;
} catch (bytes memory) {
}
}
else{
try this.getV1Reserves(factories[i].factory, tokenA, tokenB) returns (uint reserveA, uint reserveB) {
uint [] memory reserves = new uint[](3);
reserves[0] = i;
reserves[1] = reserveA;
reserves[2] = reserveB;
allReserves[i] = reserves;
} catch (bytes memory) {
}
}
}
return allReserves;
}
function getReservesPack(address[][] memory tokens, Factory[] memory factories) public view returns (uint[][][] memory){
uint[][][] memory reservesPack = new uint[][][](tokens.length);
for(uint i = 0; i < reservesPack.length; i++){
address tokenA = tokens[i][0];
address tokenB = tokens[i][1];
try this.getAllReserves(tokenA, tokenB, factories) returns (uint[][] memory allReserves) {
reservesPack[i] = allReserves;
} catch (bytes memory) {
}
}
return reservesPack;
}
function getReserves(address factory, address tokenA, address tokenB) external view returns (uint reserveA, uint reserveB) {
(address token0,) = sortTokens(tokenA, tokenB);
(uint reserve0, uint reserve1,) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
function getV1Reserves(address factory, address tokenA, address tokenB) external view returns (uint reserveA, uint reserveB) {
require(isWBNB(tokenA) || isWBNB(tokenB), 'Pair does not exist');
IUniswapV1Factory factoryV1 = IUniswapV1Factory(factory);
reserveA = 0;
reserveB = 0;
if(isWBNB(tokenA)){
IUniswapV1Exchange pair = IUniswapV1Exchange(factoryV1.getExchange(tokenB));
reserveA = getPairBalanceBNB(address(pair));
reserveB = getPairBalanceToken(tokenB, address(pair));
}
else{
IUniswapV1Exchange pair = IUniswapV1Exchange(factoryV1.getExchange(tokenA));
reserveA = getPairBalanceToken(tokenA, address(pair));
reserveB = getPairBalanceBNB(address(pair));
}
}
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 pairFor(address factoryAddress, address tokenA, address tokenB) internal view returns (address pair) {
IUniswapV2Factory factory = IUniswapV2Factory(factoryAddress);
address pairAddress = factory.getPair(tokenA, tokenB);
return pairAddress;
}
function getBalanceToken(address tokenAddress) public view returns(uint){
IERC20 token = IERC20(tokenAddress);
return token.balanceOf(address(this));
}
function getPairBalanceBNB(address pair) internal view returns(uint){
return pair.balance;
}
function getPairBalanceToken(address tokenAddress, address pair) internal view returns(uint){
IERC20 token = IERC20(tokenAddress);
return token.balanceOf(pair);
}
function withdrawToken(address tokenAddress, uint value) external onlyOwner {
IERC20 token = IERC20(tokenAddress);
bool success = token.transfer(msg.sender, value);
require(success, "Could not transfer token amount!");
}
function withdrawWrappedBNB(uint value, address payable to) external onlyOwner{
WBNB.withdraw(value);
to.transfer(value);
}
function withdrawBNB(uint value) external onlyOwner{
msg.sender.transfer(value);
}
function isWBNB(address token) internal pure returns(bool) {
return (token == address(WBNB));
}
function getDeadline() internal view returns (uint) {
return block.timestamp + 900;
}
}
文件 2 的 8:IERC20.sol
pragma solidity >=0.5.0;
interface IERC20 {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function balanceOf(address owner) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
}
文件 3 的 8:IUniswapV1Exchange.sol
pragma solidity >=0.5.0;
interface IUniswapV1Exchange {
function getEthToTokenInputPrice(uint256 eth_sold) external view returns (uint256 tokens_bought);
function getTokenToEthInputPrice(uint256 tokens_sold) external view returns (uint256 eth_bought);
function tokenToEthSwapInput(uint, uint, uint) external returns (uint);
function ethToTokenSwapInput(uint, uint) external payable returns (uint);
}
文件 7 的 8:IUniswapV2Route.sol
pragma solidity 0.6.6;
interface IUniswapV2Route{
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
}
{
"compilationTarget": {
"ethereum/Arbitrageur.sol": "Arbitrageur"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}