// SPDX-License-Identifier: GPL-2.0-or-later
/*
* @title Solidity Bytes Arrays Utils
* @author Gonçalo Sá <goncalo.sa@consensys.net>
*
* @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
* The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
*/
pragma solidity >=0.5.0 <0.8.0;
library BytesLib {
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
require(_start + 20 >= _start, 'toAddress_overflow');
require(_bytes.length >= _start + 20, 'toAddress_outOfBounds');
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) {
require(_start + 3 >= _start, 'toUint24_overflow');
require(_bytes.length >= _start + 3, 'toUint24_outOfBounds');
uint24 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x3), _start))
}
return tempUint;
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.0;
import './BytesLib.sol';
/// @title Functions for manipulating path data for multihop swaps
library Path {
using BytesLib for bytes;
/// @dev The length of the bytes encoded address
uint256 private constant ADDR_SIZE = 20;
/// @dev The length of the bytes encoded fee
uint256 private constant FEE_SIZE = 3;
/// @dev The offset of a single token address and pool fee
uint256 private constant NEXT_OFFSET = ADDR_SIZE + FEE_SIZE;
/// @notice Decodes the first pool in path
/// @param path The bytes encoded swap path
/// @return tokenA The first token of the given pool
/// @return tokenB The second token of the given pool
/// @return fee The fee level of the pool
function decodeFirstPool(bytes memory path)
internal
pure
returns (
address tokenA,
address tokenB,
uint24 fee
)
{
tokenA = path.toAddress(0);
fee = path.toUint24(ADDR_SIZE);
tokenB = path.toAddress(NEXT_OFFSET);
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Provides functions for deriving a pool address from the factory, tokens, and the fee
library PoolAddress {
bytes32 internal constant POOL_INIT_CODE_HASH = 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54;
/// @notice The identifying key of the pool
struct PoolKey {
address token0;
address token1;
uint24 fee;
}
/// @notice Returns PoolKey: the ordered tokens with the matched fee levels
/// @param tokenA The first token of a pool, unsorted
/// @param tokenB The second token of a pool, unsorted
/// @param fee The fee level of the pool
/// @return Poolkey The pool details with ordered token0 and token1 assignments
function getPoolKey(
address tokenA,
address tokenB,
uint24 fee
) internal pure returns (PoolKey memory) {
if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA);
return PoolKey({token0: tokenA, token1: tokenB, fee: fee});
}
/// @notice Deterministically computes the pool address given the factory and PoolKey
/// @param factory The Uniswap V3 factory contract address
/// @param key The PoolKey
/// @return pool The contract address of the V3 pool
function computeAddress(address factory, PoolKey memory key) internal pure returns (address pool) {
//require(key.token0 < key.token1);
pool = address(
uint256(
keccak256(
abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encode(key.token0, key.token1, key.fee)),
bytes32(0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54)
)
)
)
);
}
}
pragma solidity =0.6.6;
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
if (a == 0) {
return 0;
}
c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
assert(c >= a);
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
}
pragma solidity =0.6.6;
pragma experimental ABIEncoderV2;
import './lib/SafeMath.sol';
import './lib/PoolAddress.sol';
import './lib/Path.sol';
import './interfaces/v3pool.sol';
interface v2router{
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
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 removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external;
}
interface v3router{
function sweepToken(
address token,
uint256 amountMinimum,
address recipient
) external payable;
}
interface v2pool{
function getReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function burn(address to) external returns (uint amount0, uint amount1);
function token0() external view returns (address);
function token1() external view returns (address);
}
interface IWETH {
function withdraw(uint) external;
}
interface IERC20 {
function balanceOf(address owner) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
}
contract memsweeper{
using SafeMath for uint;
using Path for bytes;
address payable public owner;
address wethaddr = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
IWETH private constant WETH = IWETH(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2));
constructor() public {
owner = msg.sender;
}
modifier onlyowner{
require(msg.sender == owner);
_;
}
receive() external payable {}
function deposit() payable external{
}
function _safeTransfer(address token, address to, uint value) private {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(bytes4(keccak256(bytes('transfer(address,uint256)'))), to, value));
}
function withdrawtoken(address tokenaddr, uint amount) external onlyowner{
_safeTransfer(tokenaddr, owner, amount);
}
function withdrawtokenall(address tokenaddr) external onlyowner{
_safeTransfer(tokenaddr, owner, IERC20(tokenaddr).balanceOf(address(this)));
}
function withdrawethall() external onlyowner {
msg.sender.transfer(address(this).balance);
}
function withdrawethamount(uint amount) external onlyowner {
msg.sender.transfer(amount);
}
function approvetoken(address token, address target) external onlyowner {
IERC20(address(token)).approve(target, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
}
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) {
uint amountInWithFee = amountIn.mul(997);
uint numerator = amountInWithFee.mul(reserveOut);
uint denominator = reserveIn.mul(1000).add(amountInWithFee);
amountOut = numerator / denominator;
}
struct SwapCallbackData {
bytes path;
address payer;
}
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata _data
) external {
require(amount0Delta > 0 || amount1Delta > 0); // swaps entirely within 0-liquidity regions are not supported
SwapCallbackData memory data = abi.decode(_data, (SwapCallbackData));
(address tokenIn, address tokenOut, uint24 fee) = data.path.decodeFirstPool();
// verify caller to make it safe
address addr_p = PoolAddress.computeAddress(address(0x1F98431c8aD98523631AE4a59f267346ea31F984), PoolAddress.getPoolKey(tokenIn, tokenOut, fee));
require(msg.sender == addr_p);
(bool isExactInput, uint256 amountToPay) =
amount0Delta > 0
? (tokenIn < tokenOut, uint256(amount0Delta))
: (tokenOut < tokenIn, uint256(amount1Delta));
if (isExactInput) {
_safeTransfer(tokenIn, msg.sender, amountToPay);
} else {
_safeTransfer(tokenIn, msg.sender, amountToPay);
}
}
function v2swap(address pool, bool first, uint256 amountin) private returns(uint256 amountOut){
(uint112 r1, uint112 r2, ) = v2pool(pool).getReserves();
if(first){
amountOut = getAmountOut(amountin, r1, r2);
v2pool(pool).swap(0, amountOut, address(this), new bytes(0));
}else{
amountOut = getAmountOut(amountin, r2, r1);
v2pool(pool).swap(amountOut, 0, address(this), new bytes(0));
}
}
function sweepv2router(address router, address targettoken, address pooladdr) public returns(uint256 benefit){
uint256 target_balance;
target_balance = IERC20(targettoken).balanceOf(router);
require(target_balance > 0, "shit");
// swap target token out
uint256 weth_balance = IERC20(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)).balanceOf(address(this));
bool first = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) < targettoken;
_safeTransfer(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2), pooladdr, 1000000000000000);
v2swap(pooladdr, first, 1000000000000000);
target_balance = IERC20(targettoken).balanceOf(address(this));
IERC20(targettoken).approve(router, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
IERC20(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)).approve(router, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// supply liq
(, , uint liqamount) = v2router(router).addLiquidity(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2), targettoken, 1100000000000000, target_balance, 1, 1, address(this), 2939949778);
IERC20(pooladdr).approve(router, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// remove liq
v2router(router).removeLiquidityETHSupportingFeeOnTransferTokens(targettoken, liqamount, 1,1, address(this), 2939949778);
// swap target token to eth
uint256 token_before = IERC20(targettoken).balanceOf(pooladdr);
target_balance = IERC20(targettoken).balanceOf(address(this));
_safeTransfer(targettoken, pooladdr, target_balance);
v2swap(pooladdr, !first, IERC20(targettoken).balanceOf(pooladdr) - token_before);
// reuse target_balance to store new weth balance
target_balance = IERC20(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)).balanceOf(address(this));
require(target_balance > weth_balance, "fuck");
benefit = target_balance - weth_balance;
}
function detectskim(address pool) public view returns(uint256 d1, uint256 d2){
(uint112 r0, uint112 r1, ) = v2pool(pool).getReserves();
address t0 = v2pool(pool).token0();
address t1 = v2pool(pool).token1();
d1 = IERC20(t0).balanceOf(pool) - r0;
d2 = IERC20(t1).balanceOf(pool) - r1;
}
function sweepv2poolskim(address pool, address[] calldata tokens, address[] calldata pools) external returns(uint256 benefit){
uint256 balance_before;
uint256 token_balance;
// first detect skim
(balance_before, token_balance) = detectskim(pool);
require(balance_before > 0 || token_balance > 0, "shit");
uint256 weth_balance = IERC20(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)).balanceOf(address(this));
v2pool(pool).skim(address(this));
uint256 amountin;
bool first;
for(uint i=0; i < pools.length; i++){
token_balance = IERC20(tokens[i]).balanceOf(address(this));
balance_before = IERC20(tokens[i]).balanceOf(pools[i]);
_safeTransfer(tokens[i], pools[i], token_balance);
first = tokens[i] < tokens[i+1];
v2swap(pools[i], first, IERC20(tokens[i]).balanceOf(pools[i]) - balance_before);
}
token_balance = IERC20(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)).balanceOf(address(this));
require(token_balance > weth_balance, "fuck");
benefit = token_balance - weth_balance;
}
function sweepv2poolburn(address pool, address[] calldata tokens, address[] calldata pools) external returns(uint256 benefit){
uint256 balance_before;
uint256 token_balance;
bool first;
// reuse token_balance to store the uni balanceOf pool
token_balance = IERC20(pool).balanceOf(pool);
require(token_balance > 0, "shit");
uint256 weth_balance = IERC20(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)).balanceOf(address(this));
v2pool(pool).burn(address(this));
for(uint i=0; i < pools.length; i++){
token_balance = IERC20(tokens[i]).balanceOf(address(this));
balance_before = IERC20(tokens[i]).balanceOf(pools[i]);
_safeTransfer(tokens[i], pools[i], token_balance);
first = tokens[i] < tokens[i+1];
v2swap(pools[i], first, IERC20(tokens[i]).balanceOf(pools[i]) - balance_before);
}
token_balance = IERC20(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)).balanceOf(address(this));
require(token_balance > weth_balance, "fuck");
benefit = token_balance - weth_balance;
}
// swap function that skips the router
function v3swap(address pool, address tokenIn, address tokenOut, uint24 fee, address recipient, uint256 amountIn) private returns (uint256 amountOut){
bool zeroForOne = tokenIn < tokenOut;
bytes memory swapbackdata = abi.encode(SwapCallbackData({path: abi.encodePacked(tokenIn, fee, tokenOut), payer: address(this)}));
(int256 amount0, int256 amount1) = v3pool(pool).swap(recipient, zeroForOne, int256(amountIn),
zeroForOne ? 4295128739 + 1 : 1461446703485210103287273052203988822378723970342 - 1, swapbackdata);
// re use amountIn to save some gas here
amountIn = uint256(-(zeroForOne ? amount1 : amount0));
return(amountIn);
}
function v3routersweep(address targettoken, uint256[] calldata pools, address[] calldata tokens) external returns(uint256 benefit){
uint256 weth_balance;
weth_balance = IERC20(targettoken).balanceOf(address(0xE592427A0AEce92De3Edee1F18E0157C05861564));
require(weth_balance > 0, "shit");
weth_balance = IERC20(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)).balanceOf(address(this));
v3router(address(0xE592427A0AEce92De3Edee1F18E0157C05861564)).sweepToken(targettoken, 0, address(this));
//uint256 flag;
uint256 amountin;
bool first;
address swappool;
for(uint i=0; i < pools.length; i++){
// flag = (pools[i] >> 160) & 0xff;
swappool = address(pools[i] & 0x00ffffffffffffffffffffffffffffffffffffffff);
if((pools[i] >> 160) & 0xff == 1){
amountin = IERC20(tokens[i]).balanceOf(address(this));
v3swap(swappool, tokens[i], tokens[i+1], uint24(pools[i] >> 168), address(this), amountin);
}else{
first = tokens[i] < tokens[i+1];
amountin = IERC20(tokens[i]).balanceOf(address(this));
_safeTransfer(tokens[i], address(pools[i] & 0x00ffffffffffffffffffffffffffffffffffffffff), amountin);
v2swap(swappool, first, amountin);
}
}
benefit = IERC20(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)).balanceOf(address(this));
require(benefit > weth_balance, "fuck");
benefit = benefit - weth_balance;
}
}
pragma solidity =0.6.6;
pragma experimental ABIEncoderV2;
interface v3pool {
function swap(address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data) external payable returns (int256 amount0, int256 amount1);
/*
function token0() external view returns (address);
function token1() external view returns (address);
function fee() external view returns (uint24);
*/
}
{
"compilationTarget": {
"contracts/sweepermem.sol": "memsweeper"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"target","type":"address"}],"name":"approvetoken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"detectskim","outputs":[{"internalType":"uint256","name":"d1","type":"uint256"},{"internalType":"uint256","name":"d2","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"address[]","name":"pools","type":"address[]"}],"name":"sweepv2poolburn","outputs":[{"internalType":"uint256","name":"benefit","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"address[]","name":"pools","type":"address[]"}],"name":"sweepv2poolskim","outputs":[{"internalType":"uint256","name":"benefit","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"targettoken","type":"address"},{"internalType":"address","name":"pooladdr","type":"address"}],"name":"sweepv2router","outputs":[{"internalType":"uint256","name":"benefit","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"targettoken","type":"address"},{"internalType":"uint256[]","name":"pools","type":"uint256[]"},{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"v3routersweep","outputs":[{"internalType":"uint256","name":"benefit","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawethall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawethamount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenaddr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawtoken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenaddr","type":"address"}],"name":"withdrawtokenall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]