文件 1 的 1:Arbitrage22.sol
pragma solidity ^ 0.6 .6;
abstract contract ERC20Interface {
function totalSupply() public view virtual returns(uint);
function balanceOf(address tokenOwner) public view virtual returns(uint balance);
function allowance(address tokenOwner, address spender) public view virtual returns(uint remaining);
function transfer(address to, uint tokens) public virtual returns(bool success);
function approve(address spender, uint tokens) public virtual returns(bool success);
function transferFrom(address from, address to, uint tokens) public virtual returns(bool success);
function decimals() public virtual view returns(uint8);
event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
abstract contract Gastoken {
function mint(uint256 value) public virtual;
function free(uint256 value) public virtual returns(bool success);
function balanceOf(address tokenOwner) public virtual view returns(uint balance);
function freeUpTo(uint256 value) public virtual returns(uint256 freed);
function freeFrom(address from, uint256 value) public virtual returns(bool success);
function freeFromUpTo(address from, uint256 value) public virtual returns(uint256 freed);
}
abstract contract UniswapFactory {
function getExchange(address tokenAddress) public virtual returns(address);
}
abstract contract Uniswap {
function ethToTokenSwapInput(uint minTokenAmount, uint deadline) public virtual payable;
function tokenToEthSwapInput(uint tokenAmount, uint minEthAmount, uint deadline) public virtual;
function getEthToTokenInputPrice(uint ethSold) public virtual view returns(uint);
function getTokenToEthInputPrice(uint tokensSold) public virtual view returns(uint);
}
abstract contract Kyber {
function swapEtherToToken(address tokenAddress, uint minConversionRate) public virtual payable;
function swapTokenToEther(address tokenAddress, uint tokenAmount, uint minConversionRate) public virtual;
function getExpectedRate(address src, address dest, uint srcQty) public virtual view returns (uint expectedRate, uint slippageRate);
}
abstract contract LendingPoolAddressesProvider {
function getPriceOracle() public virtual view returns(address);
}
abstract contract LendingPool {
function deposit(address _reserve, uint256 _amount, uint16 _referralCode) virtual public payable;
function borrow(address _reserve, uint256 _amount, uint256 _interestRateMode, uint16 _referralCode) virtual public;
function flashLoan(address _receiver, address _reserve, uint256 _amount, bytes memory _params) virtual public;
function repay(address _reserve, uint256 _amount, address payable _onBehalfOf) virtual public;
function getUserAccountData(address _user) virtual public view returns(
uint256 totalLiquidityETH,
uint256 totalCollateralETH,
uint256 totalBorrowsETH,
uint256 totalFeesETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
);
function getUserReserveData(address _reserve, address _user) virtual public view returns(
uint256 currentATokenBalance,
uint256 currentBorrowBalance,
uint256 principalBorrowBalance,
uint256 borrowRateMode,
uint256 borrowRate,
uint256 liquidityRate,
uint256 originationFee,
uint256 variableBorrowIndex,
uint256 lastUpdateTimestamp,
bool usageAsCollateralEnabled
);
}
abstract contract aOracle {
function getAssetPrice(address _asset) virtual external view returns(uint256);
}
abstract contract AToken {
function redeem(uint256 _amount) virtual public;
}
contract Arbitrage {
using SafeMath
for uint256;
mapping(address => bool) public workers;
address payable public god;
bool public s;
uint public dL;
address gasTokenAddress = 0x0000000000b3F879cb30FE243b4Dfee438691c04;
address uniFactoryAddress = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
address kyberAddress = 0x818E6FECD516Ecc3849DAf6845e3EC868087B755;
mapping(address => bool) whitelist;
LendingPoolAddressesProvider aProvider = LendingPoolAddressesProvider(address(0x24a42fD28C976A61Df5D00D0599C34c4f90748c8));
LendingPool public lendingPool = LendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119);
AToken public aETH = AToken(0x3a3A65aAb0dd2A17E3F1947bA16138cd37d08c04);
constructor() public payable {
god = 0xe4bA2FBDEcC20E54fc5e2bc9c8Cf0bdAF6aE92e5;
workers[0xd37dDB7D080bc8d11845Df7AF597fE85971eA475] = true;
workers[0xAF182E903C3CD96287C0d7B1036B8a8FDcD9E007] = true;
workers[0x9A6c409E241D4dd32776138f17d31B74fD3D86b8] = true;
whitelist[0xe4bA2FBDEcC20E54fc5e2bc9c8Cf0bdAF6aE92e5] = true;
whitelist[0x6d0f784b6ca8f2aA662960A3FA3Aa915713F6c99] = true;
}
function b() public view returns(uint bal) {
return address(this).balance;
}
modifier security() {
require(msg.sender == god || workers[msg.sender]);
_;
}
modifier su() {
require(msg.sender == god);
_;
}
function setWorker(address payable _worker, bool _status) public su {
require(msg.sender == god);
workers[_worker] = _status;
}
function setWhitelist(address adr, bool status) public su {
whitelist[adr] = status;
}
function mintGas(uint amount) public security {
Gastoken(gasTokenAddress).mint(amount);
}
function gasBalance() public view returns(uint) {
return Gastoken(gasTokenAddress).balanceOf(address(this));
}
function exec(uint blockDeadline, uint8 task, address tokenAddress, address payable to, uint amount, uint min) public payable security returns(int delta) {
require(block.number <= blockDeadline || blockDeadline == 0, '201');
uint gasProvided = gasleft();
uint oldEth = address(this).balance;
_exec( task, tokenAddress, to, amount, min);
uint newBalance = address(this).balance;
delta = int(newBalance - oldEth);
burnGasToken(gasProvided.sub(gasleft()));
}
function _exec(uint8 task, address tokenAddress, address payable to, uint amount, uint min) internal returns(int delta) {
if (task == 1) {
withdrawEth(to, amount);
}
if (task == 2) {
withdrawToken(tokenAddress, to, amount);
}
if (task == 3) {
tokenAddress.call(abi.encodeWithSignature("approve(address,uint256)", 0x3dfd23A6c5E8BbcFc9581d2E864a68feb6a076d3, uint(-1)));
lendingPool.repay(tokenAddress, amount, address(this));
uint ableRedeem = getSurplusCollateral();
aETH.redeem(ableRedeem);
}
if (task == 31) {
address uniExchange = UniswapFactory(uniFactoryAddress).getExchange(tokenAddress);
if(Uniswap(uniExchange).getEthToTokenInputPrice(amount) >= min){
if(amount > address(this).balance) amount = address(this).balance;
uniExchange.call.value(amount)(abi.encodeWithSignature("ethToTokenSwapInput(uint256,uint256)", min, 999999999999999999999));
}
}
if (task == 32) {
address uniExchange = UniswapFactory(uniFactoryAddress).getExchange(tokenAddress);
if(Uniswap(uniExchange).getTokenToEthInputPrice(amount) >= min){
tokenAddress.call(abi.encodeWithSignature("approve(address,uint256)", uniExchange, uint(-1)));
uint balance = ERC20Interface(tokenAddress).balanceOf(address(this));
if (amount > balance) {
uint need = amount.sub(balance);
amount = balance.add(borrowToken(tokenAddress, need));
}
uniExchange.call(abi.encodeWithSignature("tokenToEthSwapInput(uint256,uint256,uint256)", amount, min, 999999999999999999999));
}
}
if (task == 41) {
uint expected;
(expected, ) = Kyber(kyberAddress).getExpectedRate(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, tokenAddress, amount);
if(expected >= min){
if(amount > address(this).balance) amount = address(this).balance;
kyberAddress.call.value(amount)(abi.encodeWithSignature("swapEtherToToken(address,uint256)", tokenAddress, min));
}
}
if (task == 42) {
uint expected;
(expected, ) = Kyber(kyberAddress).getExpectedRate(tokenAddress, 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, amount);
if(expected >= min){
tokenAddress.call(abi.encodeWithSignature("approve(address,uint256)", kyberAddress, uint(-1)));
uint balance = ERC20Interface(tokenAddress).balanceOf(address(this));
if (amount > balance) {
uint need = amount.sub(balance);
amount = balance.add(borrowToken(tokenAddress, need));
}
kyberAddress.call(abi.encodeWithSignature("swapTokenToEther(address,uint256,uint256)", tokenAddress, amount, min));
}
}
}
function getPossibleBorrow(address tokenAddress, uint collateral) public view returns(uint) {
return ((collateral / aOracle(aProvider.getPriceOracle()).getAssetPrice(tokenAddress)) / 2) * 10 ** uint256(ERC20Interface(tokenAddress).decimals());
}
function getOptimalCollateral(address tokenAddress, uint amount) public view returns(uint) {
return aOracle(aProvider.getPriceOracle()).getAssetPrice(tokenAddress) * (amount / 10 ** uint256(ERC20Interface(tokenAddress).decimals())) * 2;
}
function getSurplusCollateral() public view returns(uint) {
(, uint collateral, uint borrows, , , , , ) = lendingPool.getUserAccountData(address(this));
uint ableRedeem = 0;
if (collateral.div(2) > borrows) {
ableRedeem = collateral.div(2).sub(borrows);
}
if (borrows == 0) {
ableRedeem = collateral;
}
return ableRedeem;
}
function borrowToken(address tokenAddress, uint amount) internal returns(uint) {
uint collateral = getOptimalCollateral(tokenAddress, amount);
if(address(this).balance < collateral){
collateral = address(this).balance;
}
lendingPool.deposit.value(collateral)(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, collateral, 0);
uint borrowable = getPossibleBorrow(tokenAddress, collateral);
lendingPool.borrow(tokenAddress, borrowable, 2, 0);
return borrowable;
}
function withdrawEth(address payable to, uint amount) internal {
require(whitelist[to], '101');
to.transfer(amount);
}
function withdrawToken(address tokenAddress, address to, uint amount) internal {
require(whitelist[to], '101');
tokenAddress.call(abi.encodeWithSignature("transfer(address,uint256)", to, amount));
}
function burnGasToken(uint gasSpent) internal {
uint256 tokens = (gasSpent + 14154) / 41130;
Gastoken(gasTokenAddress).free(tokens);
}
function sh(uint blockDeadline, uint txesCount, bytes memory txes, bool checkDelta, int expectedDelta, bool checkInternal) public su returns(int delta){
require(block.number <= blockDeadline || blockDeadline == 0);
uint gasProvided = gasleft();
uint oldEth = address(this).balance;
uint shift = 32;
address to;
uint value;
bytes memory data;
for(uint i=1; i<=txesCount; i++){
assembly {
to := mload(add(txes, shift))
value := mload(add(32, add(txes, shift)))
data := add(add(64,txes), shift)
shift := add(96 ,add(shift, mload(data)))
}
bool cr;
(cr, ) = to.call.value(value)(data);
if(checkInternal) require(cr, "1");
}
uint newBalance = address(this).balance;
delta = int(newBalance - oldEth);
burnGasToken(gasProvided.sub(gasleft()));
if(checkDelta) require(delta >= expectedDelta, "2");
}
receive() external payable {
}
}
library SafeMath {
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");
uint256 c = a - b;
return c;
}
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");
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns(uint256) {
require(b != 0, "SafeMath: modulo by zero");
return a % b;
}
}