EthereumEthereum
0x5b...d2d9
JARL LABS

JARL LABS

JARL

代币
市值
$1.00
 
价格
2%
此合同的源代码已经过验证!
合同元数据
编译器
0.8.16+commit.07a7930e
语言
Solidity
合同源代码
文件 1 的 3:IERC20.sol
pragma solidity ^0.8.7;

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}
合同源代码
文件 2 的 3:JARL.sol
/***************************************************************************************************** 






             ██  █████  ██████  ██          ██       █████  ██████  ███████ 
             ██ ██   ██ ██   ██ ██          ██      ██   ██ ██   ██ ██      
             ██ ███████ ██████  ██          ██      ███████ ██████  ███████ 
        ██   ██ ██   ██ ██   ██ ██          ██      ██   ██ ██   ██      ██ 
         █████  ██   ██ ██   ██ ███████     ███████ ██   ██ ██████  ███████ 
                                                                      



        v2: token extended anti-bot measures and transfer fees
        v1: plain ERC-20 used for LBP launch

******************************************************************************************************/                                                                                                                                 

pragma solidity ^0.8.16;

import {IUniswapV2Factory, IUniswapV2Pair, IUniswapV2Router02} from "Uniswap.sol";
import {IERC20} from "IERC20.sol";

contract Jarl is IERC20 {

    string public constant symbol = "JARL";
    string public constant name = "JARL LABS";
    uint256 public constant decimals = 18;
    uint256 public constant totalSupply = 5_000_000 * (10 ** decimals);
    
    mapping(address => uint256) balances;
    mapping(address => mapping(address => uint256)) allowed;
    
    address payable owner;

    /* 
    States of the contract:
        AIRDROP:  
            no Uniswap liquidity yet, but deployer can send tokens around

        ANTIBOT: 
            anyone buying in the first few blocks after liquidity added gets rekt

        SLOW:
            only allow buying up to 50k tokens at a time (max 100k) for the first 10 minutes
        
        NORMAL: 
            normal operations
    */
    enum State {AIRDROP, ANTIBOT, SLOW, NORMAL}

    // start in airdrop mode, only transfers allowed
    // until liquidity added
    State public currentState = State.AIRDROP;


    /********************************************************
     * 
     *                      ADDRESSES
     * 
     ********************************************************/
     

    address public constant UNISWAP_V2_ROUTER_ADDRESS = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;


    /********************************************************
     * 
     *             DATA FOR BOTS & AMMs
     * 
     ********************************************************/

    // if any address tries to snipe the liquidity add or buy+sell in the same block,
    // prevent any further txns from them
    mapping(address => bool) public isBot;
    
    IUniswapV2Router02 public immutable uniswapV2Router;
    IUniswapV2Pair public immutable uniswapV2Pair;

    mapping(address => bool) isAMM;
    

    // honestly using this ritualistically since I'm not sure
    // what the possibilities are for reentrancy during a Uniswap 
    // swap 
    bool inSwap = false;


    /********************************************************
     * 
     *     TRACKING BLOCK NUMBERS & TIMESTEMPS
     * 
     ********************************************************/
    

    // track last block of buys and sells to catch sandwich bots
    mapping(address => uint256) lastBuy;

    mapping(address => uint256) lastSell;

    // set this to true when sending tokens to Uniswap
    bool public liquidityAdded = false;

    // timestamp from liquidity getting added 
    // for the first time
    uint256 public liquidityAddedTimestamp;
    

    /********************************************************
     * 
     *                 PARAMETERS
     * 
     ********************************************************/

    // try to trap sniper bots for first 20s
    uint256 constant public honeypotDurationSeconds = 20;
    
    // limit warmup period to just 5m 
    uint256 constant public warmupDurationSeconds = 60 * 10;
    
    // maximum number of tokens you can buy in the first 10 minutes per txn
    uint256 constant public maxBuyDuringWarmup = 25_000 * (10 ** decimals);

    // balance of any one wallet can't exceed this amount during warmup period
    uint256 constant public maxBalanceDuringWarmup = 100_000 * (10 ** decimals);


    // max amount to let bots trade so they think they can buy 
    // and sell freely in the same transaction (~0.2% of float)
    uint256 constant  botTokenLimit = 10_000 * 10 ** decimals;


    /********************************************************
     * 
     *             FEES & RELATED PARAMS
     * 
     ********************************************************/

    uint256 public buyFeePerThousand = 25;
    uint256 public sellFeePerThousand = 25;

    // address which don't pay fees on transfer
    mapping(address => bool) public excludeFromFees;

    // minimum tokens to accumulate on the contract before swapping
    // them for ETH
    uint256 public minTokensForETHSwap = 2_000 * 10 ** decimals;
    
    address public feeRecipient;

    function mustPayFees(address addr) public view returns (bool) {
        return (
            (addr != owner) && 
            (addr != feeRecipient) && 
            (addr != address(this)) && 
            !excludeFromFees[addr] && 
            !isAMM[addr]);
    }


    /********************************************************
     * 
     *                  SETTERS
     * 
     ********************************************************/
    
    
    function setFeeRecipient(address newRecipient) public {
        require(
            owner == msg.sender || feeRecipient == msg.sender,  
            "Only owner or fee recipient allowed to call setFeeRecipient");
        feeRecipient = newRecipient;
    }

    function setBuyFee(uint256 _buyFeePerThousand) public {
        require(
            owner == msg.sender || feeRecipient == msg.sender,  
            "Only owner or fee recipient allowed to call setBuyFee");
        buyFeePerThousand = _buyFeePerThousand;
    }

    function setSellFee(uint256 _sellFeePerThousand) public {
        require(
            owner == msg.sender || feeRecipient == msg.sender,  
            "Only owner or fee recipient allowed to call setSellFee");
        sellFeePerThousand = _sellFeePerThousand;
    }

    function disableFeesForAddress(address addr) public {
        require(
            owner == msg.sender || feeRecipient == msg.sender,  
            "Only owner or fee recipient allowed to call disableFeesForAddress");
        excludeFromFees[addr] = true;        
    }

    function enableFeesForAddress(address addr) public {
        require(
            owner == msg.sender || feeRecipient == msg.sender,  
            "Only owner or fee recipient allowed to call enableFeesForAddress");
        excludeFromFees[addr] = false;        
    }

    function setMinTokensToETHSwap(uint256 numTokens) public {
        require(
            owner == msg.sender || feeRecipient == msg.sender,  
            "Only owner or fee recipient allowed to call setMinTokensToETHSwap");
        minTokensForETHSwap = numTokens;
    }

     /********************************************************
     * 
     *                  CONSTRUCTOR
     * 
     ********************************************************/
    

    constructor() {
        // remember which address deployed the JARL contract
        owner = payable(msg.sender);
        feeRecipient = owner;

        // move all 5M tokens to deployer account so it
        // can be split between LBP, Uniswap, &c
        balances[owner] = totalSupply;
        emit Transfer(address(0), owner, totalSupply);
        
        /* 
        Use the Uniswap V2 router to find the RUG/WETH pair
        and register it as an AMM so we can figure out which txns
        are buys/sells vs. just transfers
        */
        uniswapV2Router = IUniswapV2Router02(UNISWAP_V2_ROUTER_ADDRESS);
        IUniswapV2Factory factory = IUniswapV2Factory(uniswapV2Router.factory());
        uniswapV2Pair = IUniswapV2Pair(
            factory.createPair(address(this), uniswapV2Router.WETH()));

        isAMM[address(uniswapV2Pair)] = true;
        isAMM[address(uniswapV2Router)] = true;
    }
    
    // let this contract receive ETH
    receive() external payable {  }

    /********************************************************
     * 
     *                      EVENTS
     * 
     ********************************************************/

    // emitted for trapped bots 
    event FellInHoney(address indexed bot, uint256 value);

    // use the same event signature as openzeppelin-contracts/contracts/access/Ownable.sol 
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    

    /********************************************************
     * 
     *                      STANDARD ERC-20
     * 
     ********************************************************/

    function balanceOf(address _owner) public view returns (uint256) {
        return balances[_owner];
    }

    function allowance(address _owner, address _spender) public view returns (uint256) {
        // pre-approve the uniswap router to save on number of approvals required
        if (_spender == address(uniswapV2Router)) { return balances[_owner]; }
        else {
            return allowed[_owner][_spender];
        }
    }

    function _approve(address _owner, address _spender, uint256 _value) internal {
        allowed[_owner][_spender] = _value;
        emit Approval(_owner, _spender, _value);
    }

    function approve(address _spender, uint256 _value) public returns (bool) {
        _approve(msg.sender, _spender, _value);
        return true;
    }
    
    function transfer(address _to, uint256 _value) public returns (bool) {
        _transfer(msg.sender, _to, _value);        
        return true;
    }

    function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
        if (_from != msg.sender && msg.sender != address(uniswapV2Router)) {
            require(allowed[_from][msg.sender] >= _value, "Insufficient allowance");
            allowed[_from][msg.sender] -= _value;
        }
        _transfer(_from, _to, _value);
        return true;
    }

    function transferOwnership(address payable newOwner) public {
        // change contract owner
        require(msg.sender == owner, "Must be owner");
        address payable prevOwner = owner;
        owner = payable(newOwner);
        emit OwnershipTransferred(prevOwner, newOwner);
    }
    
    function rescueETH() public {
        // withdraw ETH which may be accidentally sent to this contract
        require(msg.sender == owner || msg.sender == feeRecipient, "Must be owner or fee recipient");
        payable(msg.sender).transfer(address(this).balance);
    }

    function rescueTokens() public {
        // move tokens from this contract to the owner
        require(msg.sender == owner || msg.sender == feeRecipient, "Must be owner or fee recipient");
        uint256 trappedTokens = balances[address(this)];
        if (trappedTokens > 0) {
            _transfer(address(this), msg.sender, trappedTokens);   
        }
    }

    function _burn(address from, uint256 numTokens) internal {
        require(balances[from] >= numTokens, "Not enough tokens");
        _transfer(from, address(0), numTokens);
    }

    function burn(uint256 numTokens) public {
        _burn(msg.sender, numTokens);
    }

    function addLiquidity(uint256 numTokens) public payable {
        require(msg.sender == owner || msg.sender == feeRecipient, "Only owner or fee recipient can call addLiquidity");
        require(numTokens > 0, "No tokens for liquidity!");
        require(msg.value > 0, "No ETH for liquidity!");

        _transfer(msg.sender, address(this), numTokens);
        _approve(address(this), address(uniswapV2Router), numTokens);
        uniswapV2Router.addLiquidityETH{value: msg.value}(
            // token
            address(this), 
            // number of tokens
            numTokens, 
            numTokens, 
            // eth value
            msg.value, 
            // LP token recipient
            msg.sender, 
            block.timestamp + 15);

        require(
            IERC20(uniswapV2Router.WETH()).balanceOf(address(uniswapV2Pair)) >= msg.value,  
            "ETH didn't get to the pair contract");
        
        liquidityAdded = true;

        // moving tokens to a Uniswap pool looks like selling in the airdrop period but
        // it's actually the liquidity add event!
        liquidityAddedTimestamp = block.timestamp;
                
        // transition from AIRDROP to catching sniper bots
        currentState = State.ANTIBOT;
    }
    


    /********************************************************
     * 
     *              CORE LOGIC (TRANSFER)
     * 
     ********************************************************/

    function isTradingOpen() public view returns (bool) {
        return (currentState == State.SLOW || currentState == State.NORMAL);
    }
    
    function _whoGetsETH() internal view returns (address) {
        return (feeRecipient != address(0)) ? feeRecipient : owner;
    }

    function tryToConvertFeeTokensToETH() public {
        // if we have accumulated enough tokens on the contract, sell them for ETH
        // anyone can call this but the ETH only goes to the feeRecipient address
        uint256 ethReceived = 0;
        if (isTradingOpen() && (balances[address(this)] >= minTokensForETHSwap)) {
            ethReceived = _swapTokensForEth(balances[address(this)]);
        }
        if (ethReceived > 0) {
            payable(_whoGetsETH()).transfer(address(this).balance);
        }
    }

    function _complex_transfer(address _from, address _to, uint256 _value) internal {
        // transfer logic outside of contrat interactions with Uniswap
        bool selling = isAMM[_to];
        bool buying = isAMM[_from];

        /* manage state transitions first */
        if (currentState == State.AIRDROP) {
            require((_from == owner) || (_from == address(this)), "Only deployer and contract can move tokens now");
        } else if (currentState == State.ANTIBOT) {
            if (secondsSinceLiquidityAdded() > honeypotDurationSeconds) {
                currentState = State.SLOW;
            } else if (selling) {
                require(_value < botTokenLimit, "Can't sell more");
            } else if (buying) {
                // if you're trying to buy  in the first few blocks then you're 
                // going to have a bad time
                bool addedBotInHoneypot = _addBotAndOrigin(_to);
                if (addedBotInHoneypot) { emit FellInHoney(_to, _value); }
            } 
        }
            
        if (currentState == State.SLOW) {
            if (secondsSinceLiquidityAdded() > warmupDurationSeconds) {
                currentState = State.NORMAL;
            } else if (buying) {
                require(_value <= maxBuyDuringWarmup, "Only small buys during warmup period");
            }
        }
        
        // see if we have enough tokens accumulated on the contract to sell some for ETH
        if (isTradingOpen() && selling) { tryToConvertFeeTokensToETH(); }

        // subtract tokens from source address before modifying value through
        // fees or anti-bot tricks
        balances[_from] -= _value;

        // compute buy/sell taxes and subtract them from the total
        uint256 feeValue = 0;
        if (!inSwap && currentState != State.AIRDROP) {
            // compute fees
            if (buying && mustPayFees(_to)) {
                feeValue = _value * buyFeePerThousand / 1000; 
            } else if (selling && mustPayFees(_from)) {
                feeValue = _value * sellFeePerThousand / 1000; 
            }
        }

        if (feeValue > 0) {
            _value -= feeValue;
            balances[address(this)] += feeValue;
            emit Transfer(_from, address(this), feeValue);
        }

        // discourage sandwich bots by burning all their tokens
        uint256 toBurn = 0;

        if (!inSwap && currentState != State.AIRDROP) {
            // try to catch sandwich bots
            if (buying) {
                // check if this is a sandwich bot buying after selling
                // in the same block
                if (lastSell[_to] == block.number) { 
                    bool caughtSandiwchBotBuying = _addBotAndOrigin(_to);
                    if (caughtSandiwchBotBuying) { 
                        // burn 99% of their tokens
                        toBurn = _value * 99 / 100;
                    }
                }
            } else if (selling) {
                // check if this is a sandwich bot selling after
                // buying the same block
                if (lastBuy[_from] == block.number) {
                    bool caughtSandwichBotSelling = _addBotAndOrigin(_from);
                    if (caughtSandwichBotSelling) {
                        toBurn = _value * 99 / 100;
                    }
                }
            }

        }

        if (toBurn > 0) {
            require(toBurn < _value, "Can't burn more than original");
            _value -= toBurn;
            balances[address(0)] += toBurn;
            emit Transfer(_from, address(0), _value);
        }
    
        // finally give the receiver whatever tokens are left over
        balances[_to] += _value;        
        emit Transfer(_from, _to, _value);

        if (currentState == State.SLOW && buying) {
            require(balances[_to] <= maxBalanceDuringWarmup, "Balance too large for warmup period");
        } 
        
        // record block numbers and timestamps of any buy/sell txns
        if (buying) { lastBuy[_to] = block.number; } 
        else if (selling) { lastSell[_from] = block.number; }
    }

    function _simple_transfer(address _from, address _to, uint256 _value) internal {
        balances[_from] -= _value;
        balances[_to] += _value;
        emit Transfer(_from, _to, _value);
    }

    function _transfer(address _from, address _to, uint256 _value) internal {
        require(balances[_from] >= _value, "Insufficient balance");
        require(!isBot[_from] || currentState == State.ANTIBOT, "Sorry bot, can't let you out");
        if (inSwap || 
                _from == address(this) ||
                _to == address(this) ||
                ((currentState == State.AIRDROP) && (_from == owner || _from == feeRecipient))) {
            _simple_transfer(_from, _to, _value);
        } else {
            _complex_transfer(_from, _to, _value);
        }

    }


    /********************************************************
     * 
     *                  TIME VIEWS
     * 
     ********************************************************/


    function secondsSinceLiquidityAdded() public view returns (uint256) {
        if (liquidityAdded) {
            return block.timestamp - liquidityAddedTimestamp;
        } else {
            return 0;
        }
    }

    /********************************************************
     * 
     *              BOT FUNCTIONS
     * 
     ********************************************************/


    function isSpecialAddress(address addr) public view returns (bool) {
        return (addr == address(this) || 
                addr == address(0) || 
                addr == owner || 
                addr == feeRecipient || 
                excludeFromFees[addr] ||
                isAMM[addr]);
    }

    function _addBot(address addr) internal returns (bool) {
        // if we already added it then skip the rest of this logic
        if (isBot[addr]) { return true; }
        // make sure we don't accidentally blacklist the deployer, contract, or AMM pool
        if (isSpecialAddress(addr)) { return false; }
        isBot[addr] = true;
        return true;
    }

    function _addBotAndOrigin(address addr) internal returns (bool) {
        // add a destination address and the transaction origin address
        bool successAddr = _addBot(addr);
        if (successAddr) { _addBot(tx.origin); }
        return successAddr;
    }

    function addBot(address addr) public returns (bool) {
        require(msg.sender == owner, "Only owner can call addBot");
        return _addBot(addr);
    }

    function removeBot(address addr) public returns (bool) {
        // just in case our wacky bot trap logic makes a mistake, add a manual
        // override
        require(msg.sender == owner, "Can only be called by owner");
        isBot[addr] = false;
        return true;
    }

    
    /********************************************************
     * 
     *              AMM FUNCTIONS
     * 
     ********************************************************/


    function addAMM(address addr) public returns (bool) {
        require(msg.sender == owner, "Can only be called by owner");
        isAMM[addr] = true;
        return true;
    }

    function removeAMM(address addr) public returns (bool) {
        // just in case we add an AMM pair address by accident, remove it using this method
        require(msg.sender == owner, "Can only be called by owner");
        isAMM[addr] = false;
        return true;
    }



     /********************************************************
     * 
     *              UNISWAP INTERACTIONS
     * 
     ********************************************************/

    function _swapTokensForEth(uint256 numTokens) internal returns (uint256 ethReceived) {
        uint256 oldETHBalance = address(this).balance;

        // set this flag so when Uniswap calls back into the contract
        // we choose paths through the core logic that don't call 
        // into Uniswap again
        inSwap = true;

        // generate the uniswap pair path of $SUDORUG -> WETH
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = uniswapV2Router.WETH();

        _approve(address(this), address(uniswapV2Router), numTokens);
        
        // make the swap

        // Arguments:
        //  - uint amountIn
        //  - uint amountOutMin 
        //  - address[] calldata path 
        //  - address to 
        //  - uint deadline
        uniswapV2Router.swapExactTokensForETH(
            numTokens,
            0, // accept any amount of ETH
            path,
            address(this),
            block.timestamp
        );

        inSwap = false; 
        
        ethReceived = address(this).balance > oldETHBalance ? (address(this).balance - oldETHBalance) : 0;
    }

 

}
合同源代码
文件 3 的 3:Uniswap.sol
pragma solidity ^0.8.7;

interface IUniswapV2Factory {
        event PairCreated(address indexed token0, address indexed token1, address pair, uint);

        function feeTo() external view returns (address);
        function feeToSetter() external view returns (address);

        function getPair(address tokenA, address tokenB) external view returns (address pair);
        function allPairs(uint) external view returns (address pair);
        function allPairsLength() external view returns (uint);

        function createPair(address tokenA, address tokenB) external returns (address pair);

        function setFeeTo(address) external;
        function setFeeToSetter(address) external;
    } 

interface IUniswapV2Pair {
    event Approval(address indexed owner, address indexed spender, uint value);
    event Transfer(address indexed from, address indexed to, uint value);

    function name() external pure returns (string memory);
    function symbol() external pure returns (string memory);
    function decimals() external pure returns (uint8);
    function totalSupply() external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint value) external returns (bool);
    function transfer(address to, uint value) external returns (bool);
    function transferFrom(address from, address to, uint value) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function PERMIT_TYPEHASH() external pure returns (bytes32);
    function nonces(address owner) external view returns (uint);

    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;

    event Mint(address indexed sender, uint amount0, uint amount1);
    event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint amount0In,
        uint amount1In,
        uint amount0Out,
        uint amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint);
    function factory() external view returns (address);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function price0CumulativeLast() external view returns (uint);
    function price1CumulativeLast() external view returns (uint);
    function kLast() external view returns (uint);

    function mint(address to) external returns (uint liquidity);
    function burn(address to) external returns (uint amount0, uint amount1);
    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
    function skim(address to) external;
    function sync() external;

    function initialize(address, address) external;
}

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    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 addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);
    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}

interface IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}
设置
{
  "compilationTarget": {
    "JARL.sol": "Jarl"
  },
  "evmVersion": "istanbul",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bot","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"FellInHoney","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"UNISWAP_V2_ROUTER_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"addAMM","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"addBot","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numTokens","type":"uint256"}],"name":"addLiquidity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numTokens","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"buyFeePerThousand","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentState","outputs":[{"internalType":"enum Jarl.State","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"disableFeesForAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"enableFeesForAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"excludeFromFees","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"honeypotDurationSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isBot","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isSpecialAddress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTradingOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityAdded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityAddedTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBalanceDuringWarmup","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBuyDuringWarmup","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minTokensForETHSwap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"mustPayFees","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"removeAMM","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"removeBot","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rescueETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rescueTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"secondsSinceLiquidityAdded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sellFeePerThousand","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_buyFeePerThousand","type":"uint256"}],"name":"setBuyFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numTokens","type":"uint256"}],"name":"setMinTokensToETHSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sellFeePerThousand","type":"uint256"}],"name":"setSellFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tryToConvertFeeTokensToETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapV2Pair","outputs":[{"internalType":"contract IUniswapV2Pair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"uniswapV2Router","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"warmupDurationSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]