账户
0x1e...3f44
0x1E...3f44

0x1E...3f44

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.6.6+commit.6c089d02
语言
Solidity
合同源代码
文件 1 的 4:PoolAddress.sol
// 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)),
                        POOL_INIT_CODE_HASH
                    )
                )
            )
        );
    }
}
合同源代码
文件 2 的 4:SafeMath.sol
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;
  }  
  
}
合同源代码
文件 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)')));
    
    // ropsten
    /*
    address wethaddr = address(0xc778417E063141139Fce010982780140Aa0cD5Ab);
    IWETH private constant WETH = IWETH(address(0xc778417E063141139Fce010982780140Aa0cD5Ab));
    */
    
    // goerli
    
    /*
    address wethaddr = address(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6);
    IWETH private constant WETH = IWETH(address(0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6));
    */
    
    // main net
    
    address wethaddr = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
    IWETH private constant WETH = IWETH(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2));
    
    
    address factory = address(0x1F98431c8aD98523631AE4a59f267346ea31F984);
    address quoter_addr = address(0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6);
    
    
    
    // chi
    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; // point to the current swap pool, plus one after every swap
    }



    function uniswapV3SwapCallback(
        int256 amount0Delta,
        int256 amount1Delta,
        bytes calldata _data
    ) external {
        /// require(amount0Delta > 0 || amount1Delta > 0); // swaps entirely within 0-liquidity regions are not supported
        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 rc_index = cur_pool_info >> 192;
        //uint256 v3num = data.param >> 248;
        // uint24 fee = uint24((cur_pool_info  >> 176) & 0x00ffff);
        // v3num first stores the fee, then v3num 
        uint256 v3num = (cur_pool_info  >> 176) & 0x00ffff;
        address receiver;
        
        
        
        // verify caller to make it safe
        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 last v3 swap, send weth to the first pool
        // and do all the v2 swaps
        if(local_cur + 1 == v3num){
            _safeTransfer(wethaddr, address(local_poolinfo[(data.param >> 240) & 0x00ff] & 0x00ffffffffffffffffffffffffffffffffffffffff), (data.param >> 120) & 0x0000ffffffffffffffffffffffffffffff );
            
            // do the v2 swaps
            if(v3num == local_poolinfo.length){
                return;
            }else{
                // the pools after data.cur is all v2 pools
                for(uint i = local_cur + 1; i < local_poolinfo.length; i++){
                    // reuse the token_in_index to save some gas
                    token_in_index = local_poolinfo[i] >> 168;
                    
                    //reuse the addr_p as the new v2 pool to save some gas
                    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);
                    }                 
            
                    // reuse v3num here to save some gas
                    if(i % 2 == 1){
                        // the left 128 bits contains the amount 
                        v3num = data.amounts[i/2] >> 128;
                    }else{
                        // the right 128bits contains the first amount
                        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;

        }
        
        // not the last v3 swap, so swap v3 again
        local_cur = local_cur + 1;
        data.cur = local_cur;
        // reuse cur_pool_info to save some gas
        cur_pool_info = local_poolinfo[local_cur];
        // uint256 rc_index = cur_pool_info >> 192;
        // reuse the token_out_index instead of the rc_index to save some gas
        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);
        
        // reuse v3num to store the amount
        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{
      
        // check the blknum to avoid the uncle blk pack
        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}));
        // amounts occupys 16bytes
        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{
      
        // check the blknum to avoid the uncle blk pack
        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}));
        // amounts occupys 16bytes
        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;
    } 


    // the first flag indicts whether the token transferred to the pool is the token0
    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)); // getreserve
        
        (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);
    }
    
    // simulate a swap and returns the exact output amount through trace_call
    function simulateoutput(uint256 amountin,  address[] memory pools, address[] memory tokens, uint256[] memory flags) public returns(uint256[] memory amounts){
 
        amounts = new uint256[](pools.length);
        // loop all the pools and do the swap
        for(uint i = 0; i < flags.length; i++){
            // the pool going to swap is v2 pool
            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);
    }
    

}
合同源代码
文件 4 的 4:v3pool.sol
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);
}
设置
{
  "compilationTarget": {
    "contracts/admevarbp3.sol": "mevarbp3"
  },
  "evmVersion": "istanbul",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256[]","name":"poolinfo","type":"uint256[]"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"param","type":"uint256"}],"name":"arbswap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"poolinfo","type":"uint256[]"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"param","type":"uint256"}],"name":"arbswapn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountin","type":"uint256"},{"internalType":"address[]","name":"pools","type":"address[]"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"flags","type":"uint256[]"}],"name":"simulateoutput","outputs":[{"internalType":"uint256[]","name":"amounts","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":"uint256","name":"amount","type":"uint256"}],"name":"unwrapweth","outputs":[],"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"}]