文件 1 的 4:PoolAddress.sol
pragma solidity >=0.5.0;
library PoolAddress {
bytes32 internal constant POOL_INIT_CODE_HASH = 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54;
struct PoolKey {
address token0;
address token1;
uint24 fee;
}
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});
}
function computeAddress(address factory, PoolKey memory key) internal pure returns (address pool) {
pool = address(
uint256(
keccak256(
abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encode(key.token0, key.token1, key.fee)),
POOL_INIT_CODE_HASH
)
)
)
);
}
}
文件 3 的 4:admevarbp3.sol
pragma solidity =0.6.6;
pragma experimental ABIEncoderV2;
import './interfaces/v3pool.sol';
import './lib/SafeMath.sol';
import './lib/PoolAddress.sol';
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);
}
interface chitoken {
function freeUpTo(uint256 value) external returns (uint256 freed);
}
interface v3quoter{
function quoteExactInputSingle(
address tokenIn,
address tokenOut,
uint24 fee,
uint256 amountIn,
uint160 sqrtPriceLimitX96
) external returns (uint256 amountOut);
}
interface v2pool{
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
}
contract mevarbp3 {
using SafeMath for uint;
address payable public owner;
uint160 internal constant MIN_SQRT_RATIO = 4295128739;
uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
address wethaddr = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
IWETH private constant WETH = IWETH(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2));
address factory = address(0x1F98431c8aD98523631AE4a59f267346ea31F984);
address quoter_addr = address(0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6);
chitoken chi = chitoken(address(0x0000000000004946c0e9F43F4Dee607b0eF1fA1c));
v3quoter quoter = v3quoter(quoter_addr);
constructor() public {
owner = msg.sender;
}
modifier onlyowner{
require(msg.sender == owner);
_;
}
modifier discountCHI {
uint256 gasStart = gasleft();
_;
uint256 gasSpent = 21000 + gasStart - gasleft() + 16 * msg.data.length;
chi.freeUpTo((gasSpent + 14154) / 41947);
}
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(SELECTOR, 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);
}
struct SwapInfo {
uint256[] poolinfo;
address[] tokens;
uint256[] amounts;
uint256 param;
uint256 cur;
}
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata _data
) external {
SwapInfo memory data = abi.decode(_data, (SwapInfo));
uint256[] memory local_poolinfo = data.poolinfo;
address[] memory local_tokens = data.tokens;
uint256 local_cur = data.cur;
uint256 cur_pool_info = local_poolinfo[local_cur];
uint256 token_in_index = (cur_pool_info >> 168) & 0x000000ff;
uint256 token_out_index = (cur_pool_info >> 160) & 0x00000000ff;
uint256 v3num = (cur_pool_info >> 176) & 0x00ffff;
address receiver;
address addr_p = PoolAddress.computeAddress(factory, PoolAddress.getPoolKey(local_tokens[token_in_index], local_tokens[token_out_index], uint24(v3num)));
require(msg.sender == addr_p);
v3num = data.param >> 248;
if(local_cur + 1 == v3num){
_safeTransfer(wethaddr, address(local_poolinfo[(data.param >> 240) & 0x00ff] & 0x00ffffffffffffffffffffffffffffffffffffffff), (data.param >> 120) & 0x0000ffffffffffffffffffffffffffffff );
if(v3num == local_poolinfo.length){
return;
}else{
for(uint i = local_cur + 1; i < local_poolinfo.length; i++){
token_in_index = local_poolinfo[i] >> 168;
addr_p = address(local_poolinfo[i] & 0x00ffffffffffffffffffffffffffffffffffffffff);
if(token_in_index == local_poolinfo.length){
receiver = address(this);
}else{
receiver = address(local_poolinfo[token_in_index] & 0x00ffffffffffffffffffffffffffffffffffffffff);
}
if(i % 2 == 1){
v3num = data.amounts[i/2] >> 128;
}else{
v3num = data.amounts[i/2] & 0xffffffffffffffffffffffffffffffff;
}
if((local_poolinfo[i] >> 160 & 0x00ff) == 1 ){
v2pool(addr_p).swap(0, v3num, receiver, new bytes(0));
}else{
v2pool(addr_p).swap(v3num, 0, receiver, new bytes(0));
}
}
}
return;
}
local_cur = local_cur + 1;
data.cur = local_cur;
cur_pool_info = local_poolinfo[local_cur];
token_out_index = cur_pool_info >> 192;
bytes memory callbackdata = abi.encode(data);
if(token_out_index == local_poolinfo.length){
receiver = address(this);
}else{
receiver = address(local_poolinfo[token_out_index] & 0x00ffffffffffffffffffffffffffffffffffffffff);
}
token_in_index = (cur_pool_info >> 168) & 0x000000ff;
token_out_index = (cur_pool_info >> 160) & 0x00000000ff;
bool zeroForOne = local_tokens[token_in_index] < local_tokens[token_out_index];
addr_p = address(cur_pool_info & 0x00ffffffffffffffffffffffffffffffffffffffff);
if(local_cur % 2 == 1){
v3num = data.amounts[local_cur / 2] >> 128;
}else{
v3num = data.amounts[local_cur / 2] & 0xffffffffffffffffffffffffffffffff;
}
v3pool(addr_p).swap(receiver, zeroForOne, int256(v3num),
zeroForOne ? MIN_SQRT_RATIO + 1 : MAX_SQRT_RATIO - 1, callbackdata);
}
function arbswap(uint256[] memory poolinfo, address[] memory tokens, uint256[] memory amounts, uint256 param) public discountCHI{
if(block.number > (param >> 96) & 0xffffff){
return;
}
uint256 gasstart = gasleft();
uint256 balance;
balance = IERC20(wethaddr).balanceOf(address(this)) + address(this).balance;
uint256 firstpoolinfo = poolinfo[0];
uint256 rc_index = firstpoolinfo >> 192;
address pool_addr = address(firstpoolinfo & 0x00ffffffffffffffffffffffffffffffffffffffff);
bool zeroForOne = tokens[(firstpoolinfo >> 168) & 0x000000ff] < tokens[(firstpoolinfo >> 160) & 0x00000000ff];
address receiver;
if(rc_index == poolinfo.length){
receiver = address(this);
}else{
receiver = address(poolinfo[rc_index] & 0x00ffffffffffffffffffffffffffffffffffffffff);
}
bytes memory callbackdata = abi.encode(SwapInfo({poolinfo: poolinfo, tokens: tokens, amounts: amounts, param: param, cur:0}));
int256 firstsend = int256(amounts[0] & 0xffffffffffffffffffffffffffffffff);
v3pool(pool_addr).swap(receiver, zeroForOne, firstsend,
zeroForOne ? MIN_SQRT_RATIO + 1 : MAX_SQRT_RATIO - 1, callbackdata);
block.coinbase.call{value: (param & 0xffffffffffffffffffffffff)}(new bytes(0));
param = IERC20(wethaddr).balanceOf(address(this)) + address(this).balance;
require(param > balance + (tx.gasprice * (gasstart - gasleft())), "i");
}
function arbswapn(uint256[] memory poolinfo, address[] memory tokens, uint256[] memory amounts, uint256 param) public{
if(block.number > (param >> 96) & 0xffffff){
return;
}
uint256 gasstart = gasleft();
uint256 balance;
balance = IERC20(wethaddr).balanceOf(address(this)) + address(this).balance;
uint256 firstpoolinfo = poolinfo[0];
uint256 rc_index = firstpoolinfo >> 192;
address pool_addr = address(firstpoolinfo & 0x00ffffffffffffffffffffffffffffffffffffffff);
bool zeroForOne = tokens[(firstpoolinfo >> 168) & 0x000000ff] < tokens[(firstpoolinfo >> 160) & 0x00000000ff];
address receiver;
if(rc_index == poolinfo.length){
receiver = address(this);
}else{
receiver = address(poolinfo[rc_index] & 0x00ffffffffffffffffffffffffffffffffffffffff);
}
bytes memory callbackdata = abi.encode(SwapInfo({poolinfo: poolinfo, tokens: tokens, amounts: amounts, param: param, cur:0}));
int256 firstsend = int256(amounts[0] & 0xffffffffffffffffffffffffffffffff);
v3pool(pool_addr).swap(receiver, zeroForOne, firstsend,
zeroForOne ? MIN_SQRT_RATIO + 1 : MAX_SQRT_RATIO - 1, callbackdata);
block.coinbase.call{value: (param & 0xffffffffffffffffffffffff)}(new bytes(0));
param = IERC20(wethaddr).balanceOf(address(this)) + address(this).balance;
require(param > balance + (tx.gasprice * (gasstart - gasleft())), "i");
}
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) {
require(amountIn > 0, 'AMOUNT');
require(reserveIn > 0 && reserveOut > 0, 'LIQUIDITY');
uint amountInWithFee = amountIn.mul(997);
uint numerator = amountInWithFee.mul(reserveOut);
uint denominator = reserveIn.mul(1000).add(amountInWithFee);
amountOut = numerator / denominator;
}
function v2out(address pool, bool first, uint256 amountIn) private returns (uint256 amountOut){
bytes memory returnData;
(, returnData) = pool.staticcall(abi.encodeWithSelector(0x0902f1ac));
(uint reserve0,uint reserve1, ) = abi.decode(returnData, (uint,uint,uint));
(uint reserveInput, uint reserveOutput) = (first) ? (reserve0, reserve1) : (reserve1, reserve0);
amountOut = getAmountOut(amountIn, reserveInput, reserveOutput);
return(amountOut);
}
function v3out(address tokenIn, address tokenOut, uint24 fee, uint256 amountIn) private returns (uint256 amountOut) {
amountOut = quoter.quoteExactInputSingle(tokenIn, tokenOut, fee, amountIn, 0);
}
function simulateoutput(uint256 amountin, address[] memory pools, address[] memory tokens, uint256[] memory flags) public returns(uint256[] memory amounts){
amounts = new uint256[](pools.length);
for(uint i = 0; i < flags.length; i++){
if((flags[i] >> 128) == 0){
amountin = v2out(pools[i], tokens[i] < tokens[i+1], amountin);
amounts[i] = amountin;
} else{
amountin = v3out(tokens[i], tokens[i+1], uint24(flags[i] & 0x00ffffffffffffffffffffffffffffffff), amountin);
amounts[i] = amountin;
}
}
}
function unwrapweth(uint256 amount) public onlyowner {
WETH.withdraw(amount);
}
}