creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/core/interfaces/ISCRYCallee.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.5.0;\n\ninterface ISCRYCallee {\n    function SCRYCall(address sender, uint amount0, uint amount1, bytes calldata data) external;\n}\n"
      },
      "contracts/core/interfaces/ISCRYERC20.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.5.0;\n\ninterface ISCRYERC20 {\n    // event Approval(address indexed owner, address indexed spender, uint value);\n    // event Transfer(address indexed from, address indexed to, uint value);\n\n    function name() external view returns (string memory);\n    function symbol() external view returns (string memory);\n    function decimals() external view returns (uint8);\n    function totalSupply() external view returns (uint);\n    function balanceOf(address owner) external view returns (uint);\n    function allowance(address owner, address spender) external view returns (uint);\n\n    function approve(address spender, uint value) external returns (bool);\n    function transfer(address to, uint value) external returns (bool);\n    function transferFrom(address from, address to, uint value) external returns (bool);\n}\n"
      },
      "contracts/core/interfaces/ISCRYERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.5.0;\n\nimport './ISCRYERC20.sol';\n\ninterface ISCRYERC20Permit is ISCRYERC20 {\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n    function PERMIT_TYPEHASH() external pure returns (bytes32);\n    function nonces(address owner) external view returns (uint);\n\n    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;\n}"
      },
      "contracts/core/interfaces/ISCRYFactory.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.5.0;\n\ninterface ISCRYFactory {\n    event PairCreated(address indexed token0, address indexed token1, address pair, uint);\n\n    function getPair(address tokenA, address tokenB) external view returns (address pair);\n    function allPairs(uint) external view returns (address pair);\n    function allPairsLength() external view returns (uint);\n    function lpTokens(address) external view returns (bool);\n\n    function createPair(address tokenA, address tokenB) external returns (address pair, address stashTokenA, address stashTokenB);\n    function oldMajor() external view returns (address);\n    function tokenFactory() external view returns (address);\n    function stashETH() external view returns (address);\n}\n"
      },
      "contracts/core/interfaces/ISCRYPair.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.5.0;\n\nimport './ISCRYERC20Permit.sol';\n\ninterface ISCRYPair is ISCRYERC20Permit {\n    // event Mint(address indexed sender, uint amount0, uint amount1);\n    // event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);\n    // event Swap(\n    //     address indexed sender,\n    //     uint amount0In,\n    //     uint amount1In,\n    //     uint amount0Out,\n    //     uint amount1Out,\n    //     address indexed to\n    // );\n    // event Sync(uint128 reserve0, uint128 reserve1);\n\n    function MINIMUM_LIQUIDITY() external pure returns (uint);\n    function factory() external view returns (address);\n    function token0() external view returns (address);\n    function token1() external view returns (address);\n    function getReserves() external view returns (uint128 reserve0, uint128 reserve1);\n\n    function mint(address to) external returns (uint liquidity);\n    function burn(address to) external returns (uint amount0, uint amount1);\n    function burnUnbalanced(address to, uint token0Min, uint token1Min) external returns (uint amount0, uint amount1);\n    function burnUnbalancedForExactToken(address to, address exactToken, uint amountExactOut) external returns (uint, uint);\n    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;\n    function sync() external;\n\n    function setIsFlashSwapEnabled(bool _isFlashSwapEnabled) external;\n    function setFeeToAddresses(address _feeTo0, address _feeTo1) external;\n    function setRouter(address _router) external;\n    function getBurnFee() external view returns (uint256);\n}\n"
      },
      "contracts/core/interfaces/ISCRYPairDelegate.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.5.0;\n\ninterface ISCRYPairDelegate {\n    function updatePoolFeeAmount(address tokenA, address tokenB, uint256 feeAmountA, uint256 feeAmountB) external;\n    function feeToAddresses(address tokenA, address tokenB) external view returns (address feeToA, address feeToB);\n    function swapFee(address lpToken) external view returns (uint256);\n    function router() external view returns (address);\n    function isFlashSwapEnabled() external view returns (bool);\n}\n"
      },
      "contracts/core/interfaces/ISCRYPairTransferable.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.5.0;\n\ninterface ISCRYPairTransferable {\n    function transferFromPool(address to, uint value) external returns (bool);\n    // function balanceOf(address owner) external returns (uint);\n}\n"
      },
      "contracts/core/interfaces/ISCRYTokenFactory.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.5.0;\n\ninterface ISCRYTokenFactory {\n    event TokenCreated(address indexed nativeToken, address indexed stashToken);\n\n    function isStashed(address token) external view returns (bool);\n    function nativeToStash(address token) external view returns (address);\n    function stashTokensLength() external view returns (uint);\n    function stashTokens(uint index) external view returns (address);\n    function getStashAddress(address nativeToken) external view returns (address);\n    function getOrCreateStashToken(address nativeToken) external returns (address stashToken);\n    function stashETH() external view returns (address);\n}"
      },
      "contracts/core/interfaces/IStashETH.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.5.0;\n\nimport './ISCRYPairTransferable.sol';\n\ninterface IStashETH is ISCRYPairTransferable {\n    function deposit() external payable returns (uint256);\n    function depositFor(address to) external payable returns (bool);\n    function withdraw(uint amount) external returns (bool);\n    function withdrawTo(address account, uint amount) external returns (bool);\n}"
      },
      "contracts/core/interfaces/IStashToken.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.5.0;\n\nimport './ISCRYERC20.sol';\nimport './ISCRYPairTransferable.sol';\n\ninterface IStashToken is ISCRYPairTransferable {\n    // needs permit\n    function underlying() external returns (ISCRYERC20);\n    function depositFor(address to, uint256 amount) external returns (bool);\n    function depositForWithPermit(address to, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external returns (bool);\n    function deposit() external returns (uint256);\n    function depositTo(address to) external returns (uint256);\n    function withdrawTo(address account, uint amount) external returns (bool);\n    function withdrawFrom(address from, address to, uint amount) external returns (bool);\n}"
      },
      "contracts/core/libraries/Math.sol": {
        "content": "pragma solidity >=0.5.0;\n\n// a library for performing various math operations\n\nlibrary Math {\n    function min(uint x, uint y) internal pure returns (uint z) {\n        z = x < y ? x : y;\n    }\n\n    // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)\n    function sqrt(uint y) internal pure returns (uint z) {\n        if (y > 3) {\n            z = y;\n            uint x = y / 2 + 1;\n            while (x < z) {\n                z = x;\n                x = (y / x + x) / 2;\n            }\n        } else if (y != 0) {\n            z = 1;\n        }\n    }\n}\n"
      },
      "contracts/core/libraries/SafeMath.sol": {
        "content": "pragma solidity >=0.5.0;\n\n// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)\n\nlibrary SafeMath {\n    function add(uint x, uint y) internal pure returns (uint z) {\n        require((z = x + y) >= x, 'ds-math-add-overflow');\n    }\n\n    function sub(uint x, uint y) internal pure returns (uint z) {\n        require((z = x - y) <= x, 'ds-math-sub-underflow');\n    }\n\n    function mul(uint x, uint y) internal pure returns (uint z) {\n        require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');\n    }\n}\n"
      },
      "contracts/core/SCRYFactory.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity =0.6.12;\n\nimport './interfaces/ISCRYFactory.sol';\nimport './interfaces/ISCRYTokenFactory.sol';\nimport './interfaces/IStashToken.sol';\nimport './SCRYPair.sol';\nimport './SCRYTokenFactory.sol';\n\ncontract SCRYFactory is ISCRYFactory {\n    address override public immutable oldMajor;\n    address override public immutable tokenFactory;\n\n    mapping(address => mapping(address => address)) override public getPair;\n    address[] override public allPairs;\n    mapping(address => bool) override public lpTokens;\n\n    constructor(address _oldMajor) public {\n        oldMajor = _oldMajor;\n        tokenFactory = address(new SCRYTokenFactory());\n    }\n\n    function allPairsLength() external override view returns (uint) {\n        return allPairs.length;\n    }\n\n    function createPair(address tokenA, address tokenB) external override returns (address pair, address stashTokenA, address stashTokenB) {\n        require(tokenA != tokenB, 'SCRY: IDENTICAL_ADDRESSES');\n\n        stashTokenA = ISCRYTokenFactory(tokenFactory).getOrCreateStashToken(tokenA);\n        stashTokenB = ISCRYTokenFactory(tokenFactory).getOrCreateStashToken(tokenB);\n\n        (address token0, address token1) = stashTokenA < stashTokenB ? (stashTokenA, stashTokenB) : (stashTokenB, stashTokenA);\n        require(getPair[token0][token1] == address(0), 'SCRY: PAIR_EXISTS');\n        bytes32 salt = keccak256(abi.encodePacked(token0, token1));\n        pair = address(new SCRYPair{salt: salt}(token0, token1, oldMajor));\n        getPair[token0][token1] = pair;\n        getPair[token1][token0] = pair;\n        allPairs.push(pair);\n        lpTokens[pair] = true;\n        emit PairCreated(token0, token1, pair, allPairs.length);\n    }\n\n    function stashETH() external override view returns (address) {\n      return ISCRYTokenFactory(tokenFactory).stashETH();\n    }\n}\n"
      },
      "contracts/core/SCRYLPToken.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.6.12;\n\nimport './SLOWERC20.sol';\n\ncontract SCRYLPToken is SLOWERC20 {\n    constructor(address _factory) public SLOWERC20(5) {\n    }\n\n    function name() public view override returns (string memory) {\n        return 'ScurrySwap LP';\n    }\n\n    function symbol() external view override returns (string memory) {\n        return 'SCRY-LP';\n    }\n\n    function _mint(address to, uint value) internal override {\n        // delay after minting to address\n        if (to != address(0)) {\n            lastReceivedBlock[to] = block.number;\n        }\n        super._mint(to, value);\n    }\n}\n "
      },
      "contracts/core/SCRYPair.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity =0.6.12;\n\nimport './interfaces/ISCRYPair.sol';\nimport './SCRYLPToken.sol';\nimport './libraries/Math.sol';\nimport './interfaces/ISCRYERC20.sol';\nimport './interfaces/ISCRYPairTransferable.sol';\nimport './interfaces/ISCRYPairDelegate.sol';\nimport './interfaces/ISCRYCallee.sol';\n\ncontract SCRYPair is ISCRYPair, SCRYLPToken {\n    using SafeMath for uint;\n\n    uint public override constant MINIMUM_LIQUIDITY = 10**3;\n    uint internal constant DEFAULT_BURN_FEE = 100; /* 1.0% */\n    bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));\n    uint256 internal constant MAX_FEE = 10000;\n\n    address public immutable override factory;\n    address private immutable pairDelegate;\n    address public immutable override token0;\n    address public immutable override token1;\n \n    uint128 private reserve0;           // uses single storage slot, accessible via getReserves\n    uint128 private reserve1;           // uses single storage slot, accessible via getReserves\n    uint public kLast;\n\n    address private feeTo0;\n    address private feeTo1;\n    address private router;\n\n    bool private isFlashSwapEnabled;\n\n    // used to ensure that a contract can only swap once per block. \n    mapping (address => uint) lastSwapMap;\n    modifier oncePerBlock() {\n      if (router == address(0) || msg.sender == router) {\n        _;\n      } else {\n        require(lastSwapMap[tx.origin] != block.number, 'SCRY: LOCKED');\n        lastSwapMap[tx.origin] = block.number;\n        _;\n      }\n    }\n\n    function getReserves() public override view returns (uint128 _reserve0, uint128 _reserve1) {\n        _reserve0 = reserve0;\n        _reserve1 = reserve1;\n    }\n\n    function _safeTransfer(address token, address to, uint value) private {\n        assert(ISCRYPairTransferable(token).transferFromPool(to, value));\n    }\n\n    // event Mint(address indexed sender, uint amount0, uint amount1);\n    // event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);\n    // event Swap(\n    //     address indexed sender,\n    //     uint amount0In,\n    //     uint amount1In,\n    //     uint amount0Out,\n    //     uint amount1Out,\n    //     address indexed to\n    // );\n    // event Sync(uint128 reserve0, uint128 reserve1);\n\n    constructor(address _token0, address _token1, address _pairDelegate) public SCRYLPToken(msg.sender) {\n        factory = msg.sender;\n        token0 = _token0;\n        token1 = _token1;\n        pairDelegate = _pairDelegate;\n        if (_pairDelegate != address(0)) {\n          (feeTo0, feeTo1) = ISCRYPairDelegate(_pairDelegate).feeToAddresses(_token0, _token1);\n          router = ISCRYPairDelegate(_pairDelegate).router();\n          isFlashSwapEnabled = ISCRYPairDelegate(_pairDelegate).isFlashSwapEnabled();\n        }\n    }\n\n    // update reserves and, on the first call per block, price accumulators\n    function _update(uint balance0, uint balance1) private {\n        require(balance0 <= uint128(-1) && balance1 <= uint128(-1), 'SCRY: OVERFLOW');\n        reserve0 = uint128(balance0);\n        reserve1 = uint128(balance1);\n        // emit Sync(uint128(balance0), uint128(balance1));\n    }\n\n    function _updateSwapVolume(uint _reserve0, uint _reserve1) private returns (bool feeOn){\n        uint _kLast = kLast; // gas savings\n        (address _feeTo0, address _feeTo1) = (feeTo0, feeTo1);\n\n        if (_feeTo0 != address(0) || _feeTo1 != address(0)) {\n          feeOn = true;\n          if (_kLast != 0) {\n            uint kNow = uint(_reserve0).mul(_reserve1);\n            if (kNow > _kLast) {\n              uint amount0Vol;\n              uint amount1Vol;\n              if (_feeTo0 != address(0)) {\n                uint first = (kNow.mul(_reserve0) / _kLast).sub(_reserve0);\n                amount0Vol = Math.sqrt(first.mul(_reserve0));\n              }\n              if (_feeTo1 != address(0)) {\n                uint first = (kNow.mul(_reserve1) / _kLast).sub(_reserve1);\n                amount1Vol = Math.sqrt(first.mul(_reserve1));\n              }\n\n              ISCRYPairDelegate(pairDelegate).updatePoolFeeAmount(token0, token1, amount0Vol, amount1Vol);\n            }\n          }\n        } else if (_kLast != 0) {\n          kLast = 0;\n        }\n    }\n\n    // this low-level function should be called from a contract which performs important safety checks\n    function mint(address to) external override oncePerBlock returns (uint liquidity) {\n        (uint128 _reserve0, uint128 _reserve1) = getReserves(); // gas savings\n        uint balance0 = ISCRYERC20(token0).balanceOf(address(this));\n        uint balance1 = ISCRYERC20(token1).balanceOf(address(this));\n\n        bool feeOn = _updateSwapVolume(_reserve0, _reserve1);\n        uint _tS = _totalSupply; // gas savings, must be defined here since _totalSupply can update in _mintFee\n\n        if (_tS == 0) {\n            liquidity = Math.sqrt(balance0.sub(_reserve0).mul(balance1.sub(_reserve1))).sub(MINIMUM_LIQUIDITY);\n            _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens\n            _update(balance0, balance1);\n        } else {\n          if (balance1.sub(_reserve1).mul(balance0) < balance0.sub(_reserve0).mul(balance1)) {\n            // case: swapping token0 for token1            \n            uint numerator = balance0.sub(_reserve0).mul(balance1).sub(balance1.sub(_reserve1).mul(balance0));\n            uint amt0In = numerator / balance1.mul(2);\n            uint amt1Out = numerator / balance0.mul(2);\n            liquidity = Math.min(\n              (_tS).mul(balance0.sub(_reserve0).sub(amt0In)) / amt0In.add(_reserve0),\n              (_tS).mul(balance1.add(amt1Out).sub(_reserve1)) / uint(_reserve1).sub(amt1Out));\n            _update(balance0, balance1);\n          } else {\n            // case: swapping token1 for token0\n            uint numerator = balance1.sub(_reserve1).mul(balance0).sub(balance0.sub(_reserve0).mul(balance1));\n            uint amt1In = numerator / balance0.mul(2);\n            uint amt0Out = numerator / balance1.mul(2);\n            liquidity = Math.min(\n              (_tS).mul(balance1.sub(_reserve1).sub(amt1In)) / amt1In.add(_reserve1),\n              (_tS).mul(balance0.add(amt0Out).sub(_reserve0)) / uint(_reserve0).sub(amt0Out));\n             _update(balance0, balance1);\n          }\n        }\n        require(liquidity > 0, 'SCRY: INSUFFICIENT_LIQUIDITY_MINTED');\n        _mint(to, liquidity);\n        if (feeOn) kLast = uint(balance0).mul(balance1);\n        // mint event needs to emit after _mint for subgraph to work properly\n        // emit Mint(msg.sender, balance0.sub(_reserve0), balance1.sub(_reserve1));\n    }\n\n    function burnTransferAndUpdate(address to, address _token0, address _token1, uint amount0, uint amount1, bool feeOn) private {\n        if (amount0 > 0) { _safeTransfer(_token0, to, amount0); }\n        if (amount1 > 0) { _safeTransfer(_token1, to, amount1); }\n        uint balance0 = ISCRYERC20(_token0).balanceOf(address(this));\n        uint balance1 = ISCRYERC20(_token1).balanceOf(address(this));\n        _update(balance0, balance1);\n        if (feeOn) { kLast = balance0.mul(balance1); }\n        // emit Burn(msg.sender, amount0, amount1, to);\n    }\n\n    // this low-level function should be called from a contract which performs important safety checks\n    // this burns the deposited lp tokens and returns equal amounts of each token\n    function burn(address to) external override oncePerBlock returns (uint amount0, uint amount1) {\n        address _token0 = token0; // gas savings\n        address _token1 = token1; // gas savings\n        uint balance0 = ISCRYERC20(_token0).balanceOf(address(this));\n        uint balance1 = ISCRYERC20(_token1).balanceOf(address(this));\n        uint liquidity = balanceOf[address(this)];\n\n        bool feeOn = _updateSwapVolume(balance0, balance1);\n        uint _tS = _totalSupply; // gas savings\n        amount0 = liquidity.mul(balance0) / _tS; // using balances ensures pro-rata distribution\n        amount1 = liquidity.mul(balance1) / _tS; // using balances ensures pro-rata distribution\n        require(amount0 > 0 && amount1 > 0, 'SCRY: INSUFFICIENT_LIQUIDITY');\n        _burn(address(this), liquidity);\n        (amount0, amount1) = calculateAndTransferFees(_token0, _token1, amount0, amount1, amount0, amount1);\n\n        burnTransferAndUpdate(to, _token0, _token1, amount0, amount1, feeOn);\n    }\n\n    // After burning lp tokens, swaps one token for the other to get the exact amount out\n    function burnUnbalancedForExactToken(address to, address exactToken, uint amountExactOut) external override oncePerBlock returns (uint amount0, uint amount1) {\n        address _token0 = token0; // gas savings\n        address _token1 = token1; // gas savings\n        uint balance0 = ISCRYERC20(_token0).balanceOf(address(this));\n        uint balance1 = ISCRYERC20(_token1).balanceOf(address(this));\n\n        {\n          uint liquidity = balanceOf[address(this)];\n          uint _tS = _totalSupply;                        // gas savings\n          uint amount0LV = liquidity.mul(balance0) / _tS; // using balances ensures pro-rata distribution\n          uint amount1LV = liquidity.mul(balance1) / _tS; // using balances ensures pro-rata distribution\n          require(amount0LV > 0 && amount1LV > 0, 'SCRY: INSUFFICIENT_LIQUIDITY');\n          _burn(address(this), liquidity);\n\n          if (exactToken == _token0) {\n            amount0 = amountExactOut;\n            amount1 = burnUnbalancedAmountOtherOut(amount0, amount0LV, balance0, balance1, liquidity, _tS, 0);\n          } else if (exactToken == _token1) {\n            amount1 = amountExactOut;\n            amount0 = burnUnbalancedAmountOtherOut(amount1, amount1LV, balance1, balance0, liquidity, _tS, 0);\n          } else {\n            require(false, 'SCRY: INVALID_TOKEN');\n          }\n\n          (amount0, amount1) = calculateAndTransferFees(_token0, _token1, amount0LV, amount1LV, amount0, amount1);\n        }\n        burnTransferAndUpdate(to, _token0, _token1, amount0, amount1, _updateSwapVolume(balance0, balance1));\n    }\n\n    // helper for burnUnbalancedForExactToken\n    function burnUnbalancedAmountOtherOut(uint amountExactOut, uint exactTokenLV, uint exactTokenBalance, uint otherTokenBalance, uint liquidity, uint _tS, uint burnFee) \n      private pure returns (uint amountOtherOut) {\n        exactTokenLV = exactTokenLV.mul(MAX_FEE - burnFee) / MAX_FEE;\n        liquidity = liquidity.mul(MAX_FEE - burnFee) / MAX_FEE;\n\n        if (amountExactOut <= exactTokenLV) {\n          // swap excess exactToken for otherToken\n          amountOtherOut = otherTokenBalance.mul(exactTokenBalance.mul(liquidity).mul(2).sub(amountExactOut.mul(liquidity.add(_tS)))) / \n            exactTokenBalance.mul(_tS.add(liquidity)).sub(amountExactOut.mul(_tS).mul(2));\n        } else {\n          // swap otherToken for exactToken\n          amountOtherOut = otherTokenBalance.mul(exactTokenBalance.mul(liquidity).mul(2).sub(amountExactOut.mul(_tS.add(liquidity)))) / \n            exactTokenBalance.mul(liquidity.add(_tS)).sub(amountExactOut.mul(_tS).mul(2));\n        }\n    }\n\n    // Burns lp tokens and minimizes slippage given minimum token conditions\n    function burnUnbalanced(address to, uint token0Min, uint token1Min) external override oncePerBlock returns (uint, uint) {\n        // address _token0 = token0;\n        // address _token1 = token1;\n        uint balance0 = ISCRYERC20(token0).balanceOf(address(this));\n        uint balance1 = ISCRYERC20(token1).balanceOf(address(this));\n\n        uint amount0Out;\n        uint amount1Out;\n        {\n          uint liquidity = balanceOf[address(this)];\n          uint _tS = _totalSupply;                    // gas savings\n          amount0Out = liquidity.mul(balance0) / _tS; // using balances ensures pro-rata distribution\n          amount1Out = liquidity.mul(balance1) / _tS; // using balances ensures pro-rata distribution\n          require(amount0Out > 0 && amount1Out > 0, 'SCRY: INSUFFICIENT_LIQUIDITY');\n          _burn(address(this), liquidity);\n          (amount0Out, amount1Out) = burnSwapAmount(balance0, balance1, amount0Out, amount1Out, token0Min, token1Min);\n          // recalc amount0LV due to stack too deep\n          (amount0Out, amount1Out) = calculateAndTransferFees(token0, token1, liquidity.mul(balance0) / _tS, liquidity.mul(balance1) / _tS, amount0Out, amount1Out);\n        }\n\n        burnTransferAndUpdate(to, token0, token1, amount0Out, amount1Out, _updateSwapVolume(balance0, balance1));\n        return (amount0Out, amount1Out);\n    }\n\n    // Helper for burnUnbalanced\n    // returns amount of each token the LP should receive\n    function burnSwapAmount(uint balance0, uint balance1, uint amount0, uint amount1, uint token0Min, uint token1Min) private pure \n      returns (uint, uint) {\n        if (amount0 < token0Min && amount1 < token1Min) {\n          require(false, 'SCRY: INSUFFICIENT_LIQUIDITY');\n        } \n        \n        // check to see if one of the amounts if less than minimum, if so, we need to swap\n        if (amount0 < token0Min) {\n          // swap token1 for token0\n          // uint swapAmt0Out = token0Min.sub(amount0);\n          uint swapAmt1In = token0Min.sub(amount0).mul(balance1.sub(amount1)) / balance0.sub(amount0).sub(token0Min.sub(amount0).mul(2));\n          //  add 1 for rounding\n          swapAmt1In = swapAmt1In.add(1);\n          // amount1Out = amount1.sub(swapAmt1In);\n          require(amount1.sub(swapAmt1In) >= token0Min, 'SCRY: INSUFFICIENT_TOKEN0');\n          // amount0Out = token0Min;\n          return (token0Min, amount1.sub(swapAmt1In));\n        } else if (amount1 < token1Min) {\n          // swap token0 for token1\n          // uint swapAmt1Out = token1Min.sub(amount1);\n          uint swapAmt0In = token1Min.sub(amount1).mul(balance0.sub(amount0)) / balance1.sub(amount1).sub(token1Min.sub(amount1).mul(2));\n          swapAmt0In = swapAmt0In.add(1);\n          // amount0Out = amount0.sub(swapAmt0In);\n          require(amount0.sub(swapAmt0In) >= token0Min, 'SCRY: INSUFFICIENT_TOKEN1');\n          // amount1Out = token1Min;\n          return (amount0.sub(swapAmt0In), token1Min);\n        } else {\n          // no swapping required\n          return (amount0, amount1);\n        }\n    }\n\n    // this low-level function should be called from a contract which performs important safety checks\n    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external override oncePerBlock {\n        require(amount0Out > 0 || amount1Out > 0, 'SCRY: INSUFFICIENT_OUTPUT');\n        (uint128 _reserve0, uint128 _reserve1) = getReserves(); // gas savings\n        require(amount0Out < _reserve0 && amount1Out < _reserve1, 'SCRY: INSUFFICIENT_LIQUIDITY');\n\n        uint balance0;\n        uint balance1;\n        uint amount0In;\n        uint amount1In;\n\n        { // scope for _token{0,1}, avoids stack too deep errors\n        address _token0 = token0;\n        address _token1 = token1;\n        require(to != _token0 && to != _token1, 'SCRY: INVALID_TO');\n        if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens\n        if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens\n        if (data.length > 0 && isFlashSwapEnabled) ISCRYCallee(to).SCRYCall(msg.sender, amount0Out, amount1Out, data);\n        balance0 = ISCRYERC20(_token0).balanceOf(address(this));\n        balance1 = ISCRYERC20(_token1).balanceOf(address(this));\n        // already checked for overflow\n        amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;\n        amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;\n        require(amount0In > 0 || amount1In > 0, 'SCRY: INSUFFICIENT_INPUT');\n        _update(balance0, balance1);\n        }\n        {\n        // derivation requires some algebra, basically ensures swap is profitable for LPs. check whitepaper for details\n        require((balance0.mul(2)).sub(uint(_reserve0))\n          .mul((balance1.mul(2)).sub(uint(_reserve1))) >=\n          uint(_reserve0).mul(_reserve1), 'SCRY: INVALID_SWAP');\n        }\n\n        // emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);\n    }\n\n    // tokenA, tokenB should always be token0, token1 respectively\n    function calculateAndTransferFees(address tokenA, address tokenB, uint amountALV, uint amountBLV, uint amountAOut, uint amountBOut) private returns(uint, uint) {\n      uint BURN_FEE = getBurnFee();\n\n      address _feeToA = feeTo0; // gas savings\n      address _feeToB = feeTo1;\n      if (_feeToA != address(0) && _feeToB != address(0)) {\n        // if both tokens have fee addresses, we just take fee from both inputs\n        uint feeAmountA = amountALV.mul(BURN_FEE) / MAX_FEE;\n        uint feeAmountB = amountBLV.mul(BURN_FEE) / MAX_FEE;\n        if (feeAmountA > 0) { _safeTransfer(tokenA, _feeToA, feeAmountA); }\n        if (feeAmountB > 0) { _safeTransfer(tokenB, _feeToB, feeAmountB); }\n        return (amountAOut.sub(feeAmountA), amountBOut.sub(feeAmountB));\n      } else if (_feeToA != address(0)) {\n        // multiplied by 2 since only taken from one side\n        uint feeAmountA = amountALV.mul(2 * BURN_FEE) / (MAX_FEE);\n        if (feeAmountA > 0) { _safeTransfer(tokenA, _feeToA, feeAmountA); }\n        return (amountAOut.sub(feeAmountA), amountBOut);\n      } else if (_feeToB != address(0)) {\n        uint feeAmountB = amountBLV.mul(2 * BURN_FEE) / (MAX_FEE);\n        if (feeAmountB > 0) { _safeTransfer(tokenB, _feeToB, feeAmountB); }\n        return (amountAOut, amountBOut.sub(feeAmountB));\n      }\n      return (amountAOut, amountBOut);\n    }\n\n    // force reserves to match balances\n    function sync() external override {\n        _update(ISCRYERC20(token0).balanceOf(address(this)), ISCRYERC20(token1).balanceOf(address(this)));\n    }\n\n    function getBurnFee() public view override returns (uint256 burnFee) {\n      if (pairDelegate == address(0)) { \n        return DEFAULT_BURN_FEE;\n      }\n      burnFee = ISCRYPairDelegate(pairDelegate).swapFee(address(this));\n      // 5% max fee\n      require(burnFee <= 500, \"SCRY: INVALID_FEE\");\n    }\n\n    function setFeeToAddresses(address _feeTo0, address _feeTo1) external override {\n      require(msg.sender == pairDelegate, 'SCRY: FORBIDDEN');\n      feeTo0 = _feeTo0;\n      feeTo1 = _feeTo1;\n    }\n\n    function setRouter(address _router) external override {\n      require(msg.sender == pairDelegate, 'SCRY: FORBIDDEN');\n      router = _router;\n    }\n\n    function setIsFlashSwapEnabled(bool _isFlashSwapEnabled) external override {\n      require(msg.sender == pairDelegate, 'SCRY: FORBIDDEN');\n      isFlashSwapEnabled = _isFlashSwapEnabled;\n    }\n}"
      },
      "contracts/core/SCRYTokenFactory.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity =0.6.12;\n\nimport './interfaces/ISCRYTokenFactory.sol';\nimport './StashToken.sol';\nimport './StashETH.sol';\n\ncontract SCRYTokenFactory is ISCRYTokenFactory {\n    mapping(address => address) public override nativeToStash;\n    mapping(address => bool) public override isStashed;\n    address[] public override stashTokens;\n    address private immutable factory;\n    address public override immutable stashETH;\n\n    constructor() public {\n        factory = msg.sender;\n        stashETH = createStashETH(msg.sender);\n    }\n\n    function stashTokensLength() external override view returns (uint) {\n        return stashTokens.length;\n    }\n\n    function createStashETH(address _factory) private returns (address _stashETH) {\n        _stashETH = address(new StashETH(_factory));\n        // circular so that we don't accidentally wrap stashETH\n        nativeToStash[_stashETH] = _stashETH;\n        isStashed[_stashETH] = true;\n    }\n\n    function getOrCreateStashToken(address nativeToken) external override returns (address stashToken) {\n        require(msg.sender == factory, 'SCRYTokenFactory: FORBIDDEN');\n        require(nativeToken != address(0), 'SCRYTokenFactory: INVALID_ADDRESS');\n        stashToken = nativeToStash[nativeToken];\n\n        if (stashToken == address(0)) {\n            bytes32 salt = keccak256(abi.encodePacked(nativeToken));\n            stashToken = address(new StashToken{salt: salt}(factory, nativeToken));\n            nativeToStash[nativeToken] = stashToken;\n            isStashed[stashToken] = true;\n            stashTokens.push(stashToken);\n            emit TokenCreated(nativeToken, stashToken);\n        }\n    }\n\n    // will always return a stashedAddress even if you give a stashToken address\n    function getStashAddress(address nativeToken) public view override returns (address) {\n        return address(uint160(uint(keccak256(abi.encodePacked(\n            bytes1(0xff),\n            address(this),\n            keccak256(abi.encodePacked(nativeToken)),\n            keccak256(abi.encodePacked(\n                type(StashToken).creationCode,\n                abi.encode(factory, nativeToken)\n            ))\n        )))));\n    }\n}\n"
      },
      "contracts/core/SLOWERC20.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity =0.6.12;\n\nimport './interfaces/ISCRYERC20Permit.sol';\nimport './interfaces/ISCRYFactory.sol';\nimport './libraries/SafeMath.sol';\n\nabstract contract SLOWERC20 is ISCRYERC20Permit {\n    using SafeMath for uint;\n\n    uint internal _totalSupply;\n    mapping(address => uint) public override balanceOf;\n    mapping(address => mapping(address => uint)) public override allowance;\n\n    bytes32 public override immutable DOMAIN_SEPARATOR;\n    // keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n    bytes32 public override constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;\n    mapping(address => uint) public override nonces;\n\n    mapping (address => uint) internal lastReceivedBlock;\n    uint internal immutable BLOCK_HOLDING_PERIOD;\n\n    constructor(uint blockHoldingPeriod) public {\n        uint chainId;\n        assembly {\n            chainId := chainid()\n        }\n        DOMAIN_SEPARATOR = keccak256(\n            abi.encode(\n                keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),\n                keccak256(bytes(name())),\n                keccak256(bytes('1')),\n                chainId,\n                address(this)\n            )  \n        );\n        BLOCK_HOLDING_PERIOD = blockHoldingPeriod;\n    }\n\n    function name() public view override virtual returns (string memory);\n\n    function symbol() external view override virtual returns (string memory);\n\n    function decimals() external view override virtual returns (uint8) {\n        return 18;\n    }\n\n    function _mint(address to, uint value) internal virtual {\n        _totalSupply = _totalSupply.add(value);\n        balanceOf[to] = balanceOf[to].add(value);\n        // emit Transfer(address(0), to, value);\n    }\n\n    function _burn(address from, uint value) internal {\n        require(block.number.sub(lastReceivedBlock[from]) >= BLOCK_HOLDING_PERIOD, 'SLOWERC20: BLOCKED');\n\n        balanceOf[from] = balanceOf[from].sub(value);\n        _totalSupply = _totalSupply.sub(value);\n        // emit Transfer(from, address(0), value);\n    }\n\n    function _approve(address owner, address spender, uint value) private {\n        allowance[owner][spender] = value;\n        // emit Approval(owner, spender, value);\n    }\n\n    function _transfer(address from, address to, uint value) internal {\n        require(block.number.sub(lastReceivedBlock[from]) >= BLOCK_HOLDING_PERIOD, 'SLOWERC20: BLOCKED');\n        balanceOf[from] = balanceOf[from].sub(value);\n        balanceOf[to] = balanceOf[to].add(value);\n        // emit Transfer(from, to, value);\n    }\n\n    function approve(address spender, uint value) external override returns (bool) {\n        _approve(msg.sender, spender, value);\n        return true;\n    }\n\n    function transfer(address to, uint value) external override returns (bool) {\n        _transfer(msg.sender, to, value);\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint value) public override returns (bool) {\n        if (allowance[from][msg.sender] != 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) {\n            allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);\n        }\n        _transfer(from, to, value);\n        return true;\n    }\n\n    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external override {\n        require(deadline >= block.timestamp, 'SLOWERC20: EXPIRED');\n        bytes32 digest = keccak256(\n            abi.encodePacked(\n                '\\x19\\x01',\n                DOMAIN_SEPARATOR,\n                keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))\n            )\n        );\n        address recoveredAddress = ecrecover(digest, v, r, s);\n        require(recoveredAddress != address(0) && recoveredAddress == owner, 'SLOWERC20: INVALID_SIGNATURE');\n        _approve(owner, spender, value);\n    }\n\n    function totalSupply() external view override virtual returns (uint) {\n        return _totalSupply;\n    }\n}\n"
      },
      "contracts/core/StashETH.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity =0.6.12;\n\nimport './SLOWERC20.sol';\nimport './interfaces/IStashETH.sol';\n\ncontract StashETH is IStashETH, SLOWERC20 {\n    address immutable private factory;\n\n    // event Deposit(address indexed dst, uint wad);\n    // event DepositFor(address indexed src, address indexed dst, uint wad);\n    // event Withdrawal(address indexed src, uint wad);\n    // event WithdrawalTo(address indexed src, address indexed to, uint wad);    \n\n    constructor(address _factory) public SLOWERC20(5) {\n        factory = _factory;\n    }\n\n    receive() payable external {\n        deposit();\n    }\n\n    function name() public view override returns (string memory) {\n        return 'ScurrySwap Stash Ether';\n    }\n\n    function symbol() external view override returns (string memory) {\n        return 'stash-ETH';\n    }\n\n    function deposit() public payable override returns (uint256) {\n        balanceOf[msg.sender] = balanceOf[msg.sender].add(msg.value);\n        // emit Deposit(msg.sender, msg.value);\n        return msg.value;\n    }\n\n    function depositFor(address to) external payable override returns (bool) {\n        balanceOf[to] = balanceOf[to].add(msg.value);\n        // emit DepositFor(msg.sender, to, msg.value);\n        return true;\n    }\n\n    function withdraw(uint wad) external override returns (bool) {\n        require(block.number.sub(lastReceivedBlock[msg.sender]) >= BLOCK_HOLDING_PERIOD, 'StashETH: BLOCKED');\n        balanceOf[msg.sender] = balanceOf[msg.sender].sub(wad);\n        payable(msg.sender).transfer(wad);\n        // emit Withdrawal(msg.sender, wad);\n        return true;\n    }\n\n    function withdrawTo(address account, uint wad) external override returns (bool) {\n        require(block.number.sub(lastReceivedBlock[msg.sender]) >= BLOCK_HOLDING_PERIOD, 'StashETH: BLOCKED');\n        balanceOf[msg.sender] = balanceOf[msg.sender].sub(wad);\n        payable(account).transfer(wad);\n        // emit WithdrawalTo(msg.sender, account, wad);\n        return true;   \n    }\n\n    function totalSupply() external view override returns (uint) {\n        return address(this).balance;\n    }\n\n    function transferFromPool(address to, uint256 value) external override returns (bool) {\n        require(ISCRYFactory(factory).lpTokens(msg.sender), 'StashETH: FORBIDDEN');\n        _transfer(msg.sender, to, value);\n        if (!ISCRYFactory(factory).lpTokens(to) ) {\n            lastReceivedBlock[to] = block.number;\n        }\n        return true;\n    }\n}\n"
      },
      "contracts/core/StashToken.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity =0.6.12;\n\nimport './SLOWERC20.sol';\nimport './interfaces/IStashToken.sol';\nimport './interfaces/ISCRYERC20.sol';\nimport '../solidity-lib/libraries/TransferHelper.sol';\n\ncontract StashToken is IStashToken, SLOWERC20 {\n    ISCRYERC20 public override immutable underlying;\n    address private immutable factory;\n\n    // event Deposit(address indexed dst, uint wad);\n    // event DepositTo(address indexed src, address indexed dst, uint wad);\n    // event DepositFor(address indexed src, address indexed dst, uint wad);\n    // event WithdrawalTo(address indexed src, address indexed to, uint wad);    \n    // event WithdrawalFrom(address indexed src, address indexed to, uint wad);    \n\n    constructor(address _factory, address _underlying) public SLOWERC20(5) {\n        underlying = ISCRYERC20(_underlying);\n        factory = _factory;\n    }\n\n    function name() public view virtual override returns (string memory) {\n        return 'ScurrySwap Stash Token';\n    }\n\n    function symbol() external view virtual override returns (string memory) {\n        return string(abi.encodePacked('stash-', ISCRYERC20(underlying).symbol()));\n    }\n\n    function decimals() external view override returns (uint8) {\n        return underlying.decimals();\n    }\n\n    function depositFor(address to, uint256 amount) external virtual override returns (bool) {\n        // for fee-on-transfer, need to use balanceOf\n        TransferHelper.safeTransferFrom(address(underlying), msg.sender, address(this), amount);\n        _mint(to, underlying.balanceOf(address(this)).sub(_totalSupply));\n        // emit DepositFor(msg.sender, to, amount);\n\n        return true;\n    }\n\n    function depositForWithPermit(address to, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external override returns (bool) {\n        ISCRYERC20Permit(address(underlying))\n          .permit(msg.sender, address(this), amount, deadline, v, r, s);\n        TransferHelper.safeTransferFrom(address(underlying), msg.sender, address(this), amount);\n        _mint(to, underlying.balanceOf(address(this)).sub(_totalSupply));\n        // emit DepositFor(msg.sender, to, amount);\n\n        return true;\n    }\n\n    function deposit() external virtual override returns (uint256) {\n        uint256 value = underlying.balanceOf(address(this)).sub(_totalSupply);\n        _mint(msg.sender, value);\n        // emit Deposit(msg.sender, value);\n\n        return value;\n    }\n\n    function depositTo(address to) external virtual override returns (uint256) {\n        uint256 value = underlying.balanceOf(address(this)).sub(_totalSupply);\n        _mint(to, value);\n        // emit DepositTo(msg.sender, to, value);\n\n        return value;\n    }\n\n    // adds hold time if transferring from pool unless `to` is another pair token\n    function transferFromPool(address to, uint256 value) external override returns (bool) {\n        require(ISCRYFactory(factory).lpTokens(msg.sender), 'StashToken: FORBIDDEN');\n        _transfer(msg.sender, to, value);\n        if (!ISCRYFactory(factory).lpTokens(to) ) {\n            lastReceivedBlock[to] = block.number;\n        }\n        return true;\n    }\n\n    function withdrawTo(address account, uint amount) external virtual override returns (bool) {\n        _burn(msg.sender, amount);\n        TransferHelper.safeTransfer(address(underlying), account, amount);\n        // emit WithdrawalTo(msg.sender, account, amount);\n        return true;\n    }\n\n    function withdrawFrom(address from, address to, uint amount) external virtual override returns (bool) {\n        address sender = msg.sender;\n        if (allowance[from][sender] != 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) {\n            allowance[from][sender] = allowance[from][sender].sub(amount);\n        }\n        _burn(from, amount);\n        TransferHelper.safeTransfer(address(underlying), to, amount);\n        // emit WithdrawalFrom(from, to, amount);\n\n        return true;\n    }\n}\n"
      },
      "contracts/solidity-lib/libraries/TransferHelper.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.6.0;\n\n// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false\nlibrary TransferHelper {\n    function safeApprove(\n        address token,\n        address to,\n        uint256 value\n    ) internal {\n        // bytes4(keccak256(bytes('approve(address,uint256)')));\n        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));\n        require(\n            success && (data.length == 0 || abi.decode(data, (bool))),\n            'TransferHelper::safeApprove: approve failed'\n        );\n    }\n\n    function safeTransfer(\n        address token,\n        address to,\n        uint256 value\n    ) internal {\n        // bytes4(keccak256(bytes('transfer(address,uint256)')));\n        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));\n        require(\n            success && (data.length == 0 || abi.decode(data, (bool))),\n            'TransferHelper::safeTransfer: transfer failed'\n        );\n    }\n\n    function safeTransferFrom(\n        address token,\n        address from,\n        address to,\n        uint256 value\n    ) internal {\n        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));\n        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));\n        require(\n            success && (data.length == 0 || abi.decode(data, (bool))),\n            'TransferHelper::transferFrom: transferFrom failed'\n        );\n    }\n\n    function safeTransferETH(address to, uint256 value) internal {\n        (bool success, ) = to.call{value: value}(new bytes(0));\n        require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 999999
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}