S Price: $0.461493 (+2.31%)
    /

    Contract Diff Checker

    Contract Name:
    Pair

    Contract Source Code:

    // SPDX-License-Identifier: GPL-3.0
    pragma solidity =0.6.12;
    
    import "./interfaces/IPair.sol";
    import "./PairERC20.sol";
    import "./libraries/Math.sol";
    import "./libraries/UQ112x112.sol";
    import "./interfaces/IERC20.sol";
    import "./interfaces/IFactory.sol";
    import "./interfaces/ICallee.sol";
    
    contract Pair is PairERC20 {
        using SafeMath for uint256;
        using UQ112x112 for uint224;
    
        uint256 public constant MINIMUM_LIQUIDITY = 10**3;
        bytes4 private constant SELECTOR = bytes4(keccak256(bytes("transfer(address,uint256)")));
    
        address public factory;
        address public token0;
        address public token1;
    
        uint256 public constant FEE_DENOMINATOR = 100000;
        uint256 public constant MAX_FEE_AMOUNT = 3000; // = 3%
        uint256 public constant MIN_FEE_AMOUNT = 10; // = 0.01%
        uint256 public feeAmount = 300; // default = 0.3%
    
        uint112 private reserve0; // uses single storage slot, accessible via getReserves
        uint112 private reserve1; // uses single storage slot, accessible via getReserves
        uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves
    
        uint256 public price0CumulativeLast;
        uint256 public price1CumulativeLast;
        uint256 public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event
    
        uint256 private unlocked = 1;
    
        uint256 public constant PRECISION_FACTOR = 1e4;
    
        modifier lock() {
            require(unlocked == 1, "Pair: LOCKED");
            unlocked = 0;
            _;
            unlocked = 1;
        }
    
        function getReserves()
            public
            view
            returns (
                uint112 _reserve0,
                uint112 _reserve1,
                uint32 _blockTimestampLast
            )
        {
            _reserve0 = reserve0;
            _reserve1 = reserve1;
            _blockTimestampLast = blockTimestampLast;
        }
    
        function _safeTransfer(
            address token,
            address to,
            uint256 value
        ) private {
            (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
            require(success && (data.length == 0 || abi.decode(data, (bool))), "Pair: TRANSFER_FAILED");
        }
    
        event FeeAmountUpdated(uint256 prevFeeAmount, uint256 feeAmount);
        event Mint(address indexed sender, uint256 amount0, uint256 amount1);
        event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
        event Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to);
        event Sync(uint112 reserve0, uint112 reserve1);
    
        constructor() public {
            factory = msg.sender;
        }
    
        // called once by the factory at time of deployment
        function initialize(address _token0, address _token1) external {
            require(msg.sender == factory, "Pair: FORBIDDEN"); // sufficient check
            token0 = _token0;
            token1 = _token1;
        }
    
        /**
         * @dev Updates the swap fees amount
         *
         * Can only be called by the factory's owner
         */
        function setFeeAmount(uint256 newFeeAmount) external {
            require(msg.sender == IFactory(factory).feeToSetter(), "Pair: only factory's feeToSetter");
            require(newFeeAmount <= MAX_FEE_AMOUNT, "Pair: feeAmount mustn't exceed the maximum");
            require(newFeeAmount >= MIN_FEE_AMOUNT, "Pair: feeAmount mustn't exceed the minimum");
            uint256 prevFeeAmount = feeAmount;
            feeAmount = newFeeAmount;
            emit FeeAmountUpdated(prevFeeAmount, newFeeAmount);
        }
    
        // update reserves and, on the first call per block, price accumulators
        function _update(
            uint256 balance0,
            uint256 balance1,
            uint112 _reserve0,
            uint112 _reserve1
        ) private {
            require(balance0 <= uint112(-1) && balance1 <= uint112(-1), "Pair: OVERFLOW");
            uint32 blockTimestamp = uint32(block.timestamp % 2**32);
            uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
            if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {
                // * never overflows, and + overflow is desired
                price0CumulativeLast += uint256(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed;
                price1CumulativeLast += uint256(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed;
            }
            reserve0 = uint112(balance0);
            reserve1 = uint112(balance1);
            blockTimestampLast = blockTimestamp;
            emit Sync(reserve0, reserve1);
        }
    
        // if fee is on, mint liquidity equivalent to 1/2th of the growth in sqrt(k)
        function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) {
            address feeTo = IFactory(factory).feeTo();
            feeOn = feeTo != address(0);
            uint256 _kLast = kLast; // gas savings
            if (feeOn) {
                if (_kLast != 0) {
                    uint256 rootK = Math.sqrt(uint256(_reserve0).mul(_reserve1));
                    uint256 rootKLast = Math.sqrt(_kLast);
                    if (rootK > rootKLast) {
                        uint256 d = ((FEE_DENOMINATOR.mul(PRECISION_FACTOR) / IFactory(factory).ownerFeeShare()).sub( uint256(1).mul(PRECISION_FACTOR)));
                        uint256 numerator = totalSupply.mul(rootK.sub(rootKLast));
                        uint256 denominator = ((rootK.mul(d)) / PRECISION_FACTOR).add(rootKLast);
                        uint256 liquidity = numerator / denominator;
                        if (liquidity > 0) _mint(feeTo, liquidity);
                    }
                }
            } else if (_kLast != 0) {
                kLast = 0;
            }
        }
    
        // this low-level function should be called from a contract which performs important safety checks
        function mint(address to) external lock returns (uint256 liquidity) {
            (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings
            uint256 balance0 = IERC20(token0).balanceOf(address(this));
            uint256 balance1 = IERC20(token1).balanceOf(address(this));
            uint256 amount0 = balance0.sub(_reserve0);
            uint256 amount1 = balance1.sub(_reserve1);
    
            bool feeOn = _mintFee(_reserve0, _reserve1);
            uint256 _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
            if (_totalSupply == 0) {
                liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
                _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
            } else {
                liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
            }
            require(liquidity > 0, "Pair: INSUFFICIENT_LIQUIDITY_MINTED");
            _mint(to, liquidity);
    
            _update(balance0, balance1, _reserve0, _reserve1);
            if (feeOn) kLast = uint256(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
            emit Mint(msg.sender, amount0, amount1);
        }
    
        // this low-level function should be called from a contract which performs important safety checks
        function burn(address to) external lock returns (uint256 amount0, uint256 amount1) {
            (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings
            address _token0 = token0; // gas savings
            address _token1 = token1; // gas savings
            uint256 balance0 = IERC20(_token0).balanceOf(address(this));
            uint256 balance1 = IERC20(_token1).balanceOf(address(this));
            uint256 liquidity = balanceOf[address(this)];
    
            bool feeOn = _mintFee(_reserve0, _reserve1);
            uint256 _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
            amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution
            amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution
            // we change from AND to OR that in case of extreme pair collapses the user is still able to burn
            require(amount0 > 0 || amount1 > 0, "Pair: INSUFFICIENT_LIQUIDITY_BURNED");
            _burn(address(this), liquidity);
            _safeTransfer(_token0, to, amount0);
            _safeTransfer(_token1, to, amount1);
            balance0 = IERC20(_token0).balanceOf(address(this));
            balance1 = IERC20(_token1).balanceOf(address(this));
    
            _update(balance0, balance1, _reserve0, _reserve1);
            if (feeOn) kLast = uint256(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
            emit Burn(msg.sender, amount0, amount1, to);
        }
    
        // this low-level function should be called from a contract which performs important safety checks
        function swap(
            uint256 amount0Out,
            uint256 amount1Out,
            address to,
            bytes calldata data
        ) external lock {
            require(amount0Out > 0 || amount1Out > 0, "Pair: INSUFFICIENT_OUTPUT_AMOUNT");
            (uint112 _reserve0, uint112 _reserve1, ) = getReserves(); // gas savings
            require(amount0Out < _reserve0 && amount1Out < _reserve1, "Pair: INSUFFICIENT_LIQUIDITY");
    
            uint256 balance0;
            uint256 balance1;
    
            {
                // scope for _token{0,1}, avoids stack too deep errors
                address _token0 = token0;
                address _token1 = token1;
                require(to != _token0 && to != _token1, "Pair: INVALID_TO");
                if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
                if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
                if (data.length > 0) ICallee(to).doCall(msg.sender, amount0Out, amount1Out, data);
                balance0 = IERC20(_token0).balanceOf(address(this));
                balance1 = IERC20(_token1).balanceOf(address(this));
            }
            uint256 amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
            uint256 amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
            require(amount0In > 0 || amount1In > 0, "Pair: INSUFFICIENT_INPUT_AMOUNT");
            {
                uint256 _feeAmount = feeAmount;
                uint256 feeDenominator = FEE_DENOMINATOR;
                // scope for reserve{0,1}Adjusted, avoids stack too deep errors
                uint256 balance0Adjusted = balance0.mul(feeDenominator).sub(amount0In.mul(_feeAmount));
                uint256 balance1Adjusted = balance1.mul(feeDenominator).sub(amount1In.mul(_feeAmount));
                require(balance0Adjusted.mul(balance1Adjusted) >= uint256(_reserve0).mul(_reserve1).mul(feeDenominator**2), "Pair: K");
            }
    
            _update(balance0, balance1, _reserve0, _reserve1);
            emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
        }
    
        // force balances to match reserves
        function skim(address to) external lock {
            address _token0 = token0; // gas savings
            address _token1 = token1; // gas savings
            _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0));
            _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1));
        }
    
        // force reserves to match balances
        function sync() external lock {
            _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1);
        }
    }

    // SPDX-License-Identifier: GPL-3.0
    
    pragma solidity =0.6.12;
    
    // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))
    
    // range: [0, 2**112 - 1]
    // resolution: 1 / 2**112
    
    library UQ112x112 {
        uint224 constant Q112 = 2**112;
    
        // encode a uint112 as a UQ112x112
        function encode(uint112 y) internal pure returns (uint224 z) {
            z = uint224(y) * Q112; // never overflows
        }
    
        // divide a UQ112x112 by a uint112, returning a UQ112x112
        function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) {
            z = x / uint224(y);
        }
    }

    // SPDX-License-Identifier: GPL-3.0
    pragma solidity =0.6.12;
    
    // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)
    
    library SafeMath {
        function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
            require((z = x + y) >= x, "ds-math-add-overflow");
        }
    
        function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
            require((z = x - y) <= x, "ds-math-sub-underflow");
        }
    
        function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
            require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
        }
    }

    // SPDX-License-Identifier: GPL-3.0
    pragma solidity =0.6.12;
    
    // a library for performing various math operations
    
    library Math {
        function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
            z = x < y ? x : y;
        }
    
        // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
        function sqrt(uint256 y) internal pure returns (uint256 z) {
            if (y > 3) {
                z = y;
                uint256 x = y / 2 + 1;
                while (x < z) {
                    z = x;
                    x = (y / x + x) / 2;
                }
            } else if (y != 0) {
                z = 1;
            }
        }
    }

    // SPDX-License-Identifier: GPL-3.0
    
    pragma solidity >=0.5.0;
    
    interface IPair {
        event Approval(address indexed owner, address indexed spender, uint256 value);
        event Transfer(address indexed from, address indexed to, uint256 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 (uint256);
    
        function balanceOf(address owner) external view returns (uint256);
    
        function allowance(address owner, address spender) external view returns (uint256);
    
        function approve(address spender, uint256 value) external returns (bool);
    
        function transfer(address to, uint256 value) external returns (bool);
    
        function transferFrom(
            address from,
            address to,
            uint256 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 (uint256);
    
        function permit(
            address owner,
            address spender,
            uint256 value,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) external;
    
        event FeeAmountUpdated(uint256 prevFeeAmount, uint256 feeAmount);
        event Mint(address indexed sender, uint256 amount0, uint256 amount1);
        event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
        event Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to);
        event Sync(uint112 reserve0, uint112 reserve1);
    
        function MINIMUM_LIQUIDITY() external pure returns (uint256);
    
        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 (uint256);
    
        function price1CumulativeLast() external view returns (uint256);
    
        function kLast() external view returns (uint256);
    
        function mint(address to) external returns (uint256 liquidity);
    
        function burn(address to) external returns (uint256 amount0, uint256 amount1);
    
        function swap(
            uint256 amount0Out,
            uint256 amount1Out,
            address to,
            bytes calldata data
        ) external;
    
        function skim(address to) external;
    
        function sync() external;
    
        function initialize(address, address) external;
    
        function feeAmount() external view returns (uint256);
    }

    // SPDX-License-Identifier: GPL-3.0
    
    pragma solidity >=0.5.0;
    
    interface IFactory {
        event PairCreated(address indexed token0, address indexed token1, address pair, uint256);
    
        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(uint256) external view returns (address pair);
    
        function allPairsLength() external view returns (uint256);
    
        function createPair(address tokenA, address tokenB) external returns (address pair);
    
        function setFeeTo(address) external;
    
        function setFeeToSetter(address) external;
    
        function ownerFeeShare() external view returns (uint256);
    }

    // SPDX-License-Identifier: GPL-3.0
    pragma solidity >=0.5.0;
    
    interface IERC20 {
        event Approval(address indexed owner, address indexed spender, uint256 value);
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        function name() external view returns (string memory);
    
        function symbol() external view returns (string memory);
    
        function decimals() external view returns (uint8);
    
        function totalSupply() external view returns (uint256);
    
        function balanceOf(address owner) external view returns (uint256);
    
        function allowance(address owner, address spender) external view returns (uint256);
    
        function approve(address spender, uint256 value) external returns (bool);
    
        function transfer(address to, uint256 value) external returns (bool);
    
        function transferFrom(
            address from,
            address to,
            uint256 value
        ) external returns (bool);
    }

    // SPDX-License-Identifier: GPL-3.0
    pragma solidity >=0.5.0;
    
    interface ICallee {
        function doCall(
            address sender,
            uint256 amount0,
            uint256 amount1,
            bytes calldata data
        ) external;
    }

    // SPDX-License-Identifier: GPL-3.0
    pragma solidity >=0.6.12;
    
    import "./libraries/SafeMath.sol";
    
    contract PairERC20 {
        using SafeMath for uint256;
    
        string public constant name = "Pair LPs";
        string public constant symbol = "Pair-LP";
        uint8 public constant decimals = 18;
        uint256 public totalSupply;
        mapping(address => uint256) public balanceOf;
        mapping(address => mapping(address => uint256)) public allowance;
    
        // bytes32 public DOMAIN_SEPARATOR;
        // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
        bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
        mapping(address => uint256) public nonces;
    
        event Approval(address indexed owner, address indexed spender, uint256 value);
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        address private immutable _CACHED_THIS;
        uint256 private immutable _CACHED_CHAIN_ID;
        bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
    
        constructor() public {
            uint256 chainId;
            assembly {
                chainId := chainid()
            }
    
            _CACHED_DOMAIN_SEPARATOR = _buildDomainSeperator(chainId);
    
            // DOMAIN_SEPARATOR = keccak256(
            //     abi.encode(
            //         keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
            //         keccak256(bytes(name)),
            //         keccak256(bytes("1")),
            //         chainId,
            //         address(this)
            //     )
            // );
    
            _CACHED_CHAIN_ID = chainId;
            _CACHED_THIS = address(this);
        }
    
    
        function domainSeparator() public view returns (bytes32) {
            uint256 chainId;
            assembly {
                chainId := chainid()
            }
            
            if (_CACHED_THIS == address(this) && _CACHED_CHAIN_ID == chainId) {
                return _CACHED_DOMAIN_SEPARATOR;
            } else {
                return _buildDomainSeperator(chainId);
            }
        }
    
        function _buildDomainSeperator(uint256 _chainId) private view returns (bytes32) {
            return keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256(bytes("1")),
                    _chainId,
                    address(this)
                ));
        }
    
        function _mint(address to, uint256 value) internal {
            totalSupply = totalSupply.add(value);
            balanceOf[to] = balanceOf[to].add(value);
            emit Transfer(address(0), to, value);
        }
    
        function _burn(address from, uint256 value) internal {
            balanceOf[from] = balanceOf[from].sub(value);
            totalSupply = totalSupply.sub(value);
            emit Transfer(from, address(0), value);
        }
    
        function _approve(
            address owner,
            address spender,
            uint256 value
        ) private {
            allowance[owner][spender] = value;
            emit Approval(owner, spender, value);
        }
    
        function _transfer(
            address from,
            address to,
            uint256 value
        ) private {
            balanceOf[from] = balanceOf[from].sub(value);
            balanceOf[to] = balanceOf[to].add(value);
            emit Transfer(from, to, value);
        }
    
        function approve(address spender, uint256 value) external returns (bool) {
            _approve(msg.sender, spender, value);
            return true;
        }
    
        function transfer(address to, uint256 value) external returns (bool) {
            _transfer(msg.sender, to, value);
            return true;
        }
    
        function transferFrom(
            address from,
            address to,
            uint256 value
        ) external returns (bool) {
            if (allowance[from][msg.sender] != uint256(-1)) {
                // allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
                _approve(from, msg.sender, allowance[from][msg.sender].sub(value));
            }
            _transfer(from, to, value);
            return true;
        }
    
        function permit(
            address owner,
            address spender,
            uint256 value,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) external {
            require(deadline >= block.timestamp, "Pair: EXPIRED");
            bytes32 digest = keccak256(
                abi.encodePacked("\x19\x01", domainSeparator(), keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)))
            );
            address recoveredAddress = ecrecover(digest, v, r, s);
            require(recoveredAddress != address(0) && recoveredAddress == owner, "Pair: INVALID_SIGNATURE");
            _approve(owner, spender, value);
        }
    }

    Please enter a contract address above to load the contract details and source code.

    Context size (optional):