memoscan
← all memos

Memo 0x81f4f525…ce1f67 on Ethereum

data:application/vnd.facet.tx+json;rule=esip6,{"op":"call","data":{"to":"0xf29e6e319ac4ce8c100cfc02b1702eb3d275029e","function":"upgrade","args":{"newHash":"0xd6c73897c5441fa221f1f0ebaee84241099b58f9cf51f6f4bcaf6bac4c29756d","newSource":"pragma(:rubidity, \"1.0.0\")\ncontract(:ERC20, abstract: true) {\n event(:Transfer, { from: :address, to: :address, amount: :uint256 })\n event(:Approval, { owner: :address, spender: :address, amount: :uint256 })\n string(:public, :name)\n string(:public, :symbol)\n uint8(:public, :decimals)\n uint256(:public, :totalSupply)\n mapping(({ address: :uint256 }), :public, :balanceOf)\n mapping(({ address: mapping(address: :uint256) }), :public, :allowance)\n constructor(name: :string, symbol: :string, decimals: :uint8) {\n s.name=name\n s.symbol=symbol\n s.decimals=decimals\n }\n function(:approve, { spender: :address, amount: :uint256 }, :public, :virtual, returns: :bool) {\n s.allowance[msg.sender][spender] = amount\n emit(:Approval, owner: msg.sender, spender: spender, amount: amount)\n return true\n }\n function(:transfer, { to: :address, amount: :uint256 }, :public, :virtual, returns: :bool) {\n require(s.balanceOf[msg.sender] \u003e= amount, \"Insufficient balance\")\n s.balanceOf[msg.sender] -= amount\n s.balanceOf[to] += amount\n emit(:Transfer, from: msg.sender, to: to, amount: amount)\n return true\n }\n function(:transferFrom, { from: :address, to: :address, amount: :uint256 }, :public, :virtual, returns: :bool) {\n allowed = s.allowance[from][msg.sender]\n require(s.balanceOf[from] \u003e= amount, \"Insufficient balance\")\n require(allowed \u003e= amount, \"Insufficient allowance\")\n s.allowance[from][msg.sender] = allowed - amount\n s.balanceOf[from] -= amount\n s.balanceOf[to] += amount\n emit(:Transfer, from: from, to: to, amount: amount)\n return true\n }\n function(:_mint, { to: :address, amount: :uint256 }, :internal, :virtual) {\n s.totalSupply += amount\n s.balanceOf[to] += amount\n emit(:Transfer, from: address(0), to: to, amount: amount)\n }\n function(:_burn, { from: :address, amount: :uint256 }, :internal, :virtual) {\n require(s.balanceOf[from] \u003e= amount, \"Insufficient balance\")\n s.balanceOf[from] -= amount\n s.totalSupply -= amount\n emit(:Transfer, from: from, to: address(0), amount: amount)\n }\n}\ncontract(:FacetSwapV1Callee, abstract: true) {\n function(:facetSwapV1Call, { sender: :address, amount0: :uint256, amount1: :uint256, data: :bytes }, :virtual, :external)\n}\ncontract(:FacetSwapV1ERC20, is: :ERC20, abstract: true) {\n constructor {\n self.ERC20.constructor(name: \"FacetSwap V1 ERC20\", symbol: \"FACET-V1\", decimals: 18)\n }\n}\ncontract(:IFacetSwapV1Factory02, abstract: true) {\n function(:feeTo, :external, :view, returns: :address)\n function(:lpFeeBPS, :external, :view, returns: :uint256)\n}\ncontract(:Upgradeable, abstract: true) {\n address(:public, :upgradeAdmin)\n event(:ContractUpgraded, { oldHash: :bytes32, newHash: :bytes32 })\n event(:UpgradeAdminChanged, { newUpgradeAdmin: :address })\n constructor(upgradeAdmin: :address) {\n s.upgradeAdmin=upgradeAdmin\n }\n function(:setUpgradeAdmin, { newUpgradeAdmin: :address }, :public) {\n require(msg.sender == s.upgradeAdmin, \"NOT_AUTHORIZED\")\n s.upgradeAdmin=newUpgradeAdmin\n emit(:UpgradeAdminChanged, newUpgradeAdmin: newUpgradeAdmin)\n }\n function(:upgradeAndCall, { newHash: :bytes32, newSource: :string, migrationCalldata: :string }, :public) {\n upgrade(newHash: newHash, newSource: newSource)\n (success, data) = address(this).call(migrationCalldata)\n require(success, \"Migration failed\")\n }\n function(:upgrade, { newHash: :bytes32, newSource: :string }, :public) {\n currentHash = this.currentInitCodeHash\n require(msg.sender == s.upgradeAdmin, \"NOT_AUTHORIZED\")\n this.upgradeImplementation(newHash, newSource)\n emit(:ContractUpgraded, oldHash: currentHash, newHash: newHash)\n }\n}\ncontract(:FacetSwapV1Pair02, is: [:FacetSwapV1ERC20, :Upgradeable], upgradeable: true) {\n uint256(:public, :MINIMUM_LIQUIDITY)\n address(:public, :factory)\n address(:public, :token0)\n address(:public, :token1)\n uint112(:private, :reserve0)\n uint112(:private, :reserve1)\n uint32(:private, :blockTimestampLast)\n uint256(:public, :price0CumulativeLast)\n uint256(:public, :price1CumulativeLast)\n uint256(:public, :kLast)\n uint256(:private, :unlocked)\n function(:getReserves, {}, :public, :view, returns: { _reserve0: :uint112, _reserve1: :uint112, _blockTimestampLast: :uint32 }) {\n return { _reserve0: s.reserve0, _reserve1: s.reserve1, _blockTimestampLast: s.blockTimestampLast }\n }\n function(:_safeTransfer, { token: :address, to: :address, value: :uint256 }, :private) {\n result = ERC20(token).transfer(to: to, amount: value)\n require(result, \"FacetSwapV1: TRANSFER_FAILED\")\n }\n event(:Mint, { sender: :address, amount0: :uint256, amount1: :uint256 })\n event(:Burn, { sender: :address, amount0: :uint256, amount1: :uint256, to: :address })\n event(:Swap, { sender: :address, amount0In: :uint256, amount1In: :uint256, amount0Out: :uint256, amount1Out: :uint256, to: :address })\n event(:Sync, { reserve0: :uint112, reserve1: :uint112 })\n event(:PreSwapReserves, { reserve0: :uint112, reserve1: :uint112 })\n constructor {\n self.FacetSwapV1ERC20.constructor\n s.factory=msg.sender\n s.MINIMUM_LIQUIDITY=10 ** 3\n s.unlocked=1\n self.Upgradeable.constructor(upgradeAdmin: msg.sender)\n }\n function(:init, { _token0: :address, _token1: :address }, :external) {\n require(msg.sender == s.factory, \"FacetSwapV1: FORBIDDEN\")\n s.token0=_token0\n s.token1=_token1\n return nil\n }\n function(:_update, { balance0: :uint256, balance1: :uint256, _reserve0: :uint112, _reserve1: :uint112 }, :private) {\n require(balance0 \u003c= (2 ** 112 - 1) \u0026\u0026 balance1 \u003c= (2 ** 112 - 1), \"FacetSwapV1: OVERFLOW\")\n blockTimestamp = uint32(block.timestamp % 2.**(32))\n timeElapsed = blockTimestamp - s.blockTimestampLast\n if timeElapsed \u003e 0 \u0026\u0026 _reserve0 != 0 \u0026\u0026 _reserve1 != 0\n s.price0CumulativeLast += uint256(uqdiv(encode(_reserve1), _reserve0)) * timeElapsed\n s.price1CumulativeLast += uint256(uqdiv(encode(_reserve0), _reserve1)) * timeElapsed\n end\n emit(:PreSwapReserves, reserve0: s.reserve0, reserve1: s.reserve1)\n s.reserve0=uint112(balance0)\n s.reserve1=uint112(balance1)\n s.blockTimestampLast=blockTimestamp\n emit(:Sync, reserve0: s.reserve0, reserve1: s.reserve1)\n }\n function(:encode, { y: :uint112 }, :internal, :pure, returns: :uint224) {\n return uint224(y) * (2 ** 112)\n }\n function(:uqdiv, { x: :uint224, y: :uint112 }, :internal, :pure, returns: :uint224) {\n return x / uint224(y)\n }\n function(:_mintFee, { _reserve0: :uint112, _reserve1: :uint112 }, :private, returns: :bool) {\n feeTo = IFacetSwapV1Factory02(s.factory).feeTo\n feeOn = feeTo != address(0)\n _kLast = s.kLast\n if feeOn\n if _kLast != 0\n rootK = sqrt(_reserve0 * _reserve1)\n rootKLast = sqrt(_kLast)\n if rootK \u003e rootKLast\n numerator = totalSupply * (rootK - rootKLast)\n denominator = rootK * 5 + rootKLast\n liquidity = numerator.div(denominator)\n if liquidity \u003e 0\n _mint(feeTo, liquidity)\n end\n end\n end\n else\n if _kLast != 0\n s.kLast=0\n end\n end\n feeOn\n }\n function(:mint, { to: :address }, :public, returns: :uint256) {\n require(s.unlocked == 1, \"FacetSwapV1: LOCKED\")\n s.unlocked=0\n (_reserve0, _reserve1, _) = getReserves\n balance0 = ERC20(s.token0).balanceOf(address(this))\n balance1 = ERC20(s.token1).balanceOf(address(this))\n amount0 = balance0 - _reserve0\n amount1 = balance1 - _reserve1\n feeOn = _mintFee(_reserve0, _reserve1)\n _totalSupply = s.totalSupply\n if _totalSupply == 0\n liquidity = sqrt(amount0 * amount1) - s.MINIMUM_LIQUIDITY\n _mint(address(0), s.MINIMUM_LIQUIDITY)\n else\n liquidity = [(amount0 * _totalSupply).div(_reserve0), (amount1 * _totalSupply).div(_reserve1)].min\n end\n require(liquidity \u003e 0, \"FacetSwapV1: INSUFFICIENT_LIQUIDITY_MINTED\")\n _mint(to, liquidity)\n _update(balance0, balance1, _reserve0, _reserve1)\n if feeOn\n s.kLast=s.reserve0 * s.reserve1\n end\n emit(:Mint, sender: msg.sender, amount0: amount0, amount1: amount1)\n s.unlocked=1\n return liquidity\n }\n function(:burn, { to: :address }, :external, :lock, returns: { amount0: :uint256, amount1: :uint256 }) {\n require(s.unlocked == 1, \"FacetSwapV1: LOCKED\")\n s.unlocked=0\n (_reserve0, _reserve1, _) = getReserves\n _token0 = s.token0\n _token1 = s.token1\n balance0 = ERC20(_token0).balanceOf(address(this))\n balance1 = ERC20(_token1).balanceOf(address(this))\n liquidity = s.balanceOf[address(this)]\n feeOn = _mintFee(_reserve0, _reserve1)\n _totalSupply = s.totalSupply\n amount0 = (liquidity * balance0).div(_totalSupply)\n amount1 = (liquidity * balance1).div(_totalSupply)\n require(amount0 \u003e 0 \u0026\u0026 amount1 \u003e 0, \"FacetSwapV1: INSUFFICIENT_LIQUIDITY_BURNED\")\n _burn(address(this), liquidity)\n _safeTransfer(_token0, to, amount0)\n _safeTransfer(_token1, to, amount1)\n balance0 = ERC20(_token0).balanceOf(address(this))\n balance1 = ERC20(_token1).balanceOf(address(this))\n _update(balance0, balance1, _reserve0, _reserve1)\n if feeOn\n s.kLast=s.reserve0 * s.reserve1\n end\n emit(:Burn, sender: msg.sender, amount0: amount0, amount1: amount1, to: to)\n s.unlocked=1\n return { amount0: amount0, amount1: amount1 }\n }\n function(:swap, { amount0Out: :uint256, amount1Out: :uint256, to: :address, data: :bytes }, :external) {\n require(s.unlocked == 1, \"FacetSwapV1: LOCKED\")\n s.unlocked=0\n require(amount0Out \u003e 0 || amount1Out \u003e 0, \"FacetSwapV1: INSUFFICIENT_OUTPUT_AMOUNT\")\n (_reserve0, _reserve1, _) = getReserves\n require(amount0Out \u003c _reserve0 \u0026\u0026 amount1Out \u003c _reserve1, \"FacetSwapV1: INSUFFICIENT_LIQUIDITY\")\n balance0 = 0\n balance1 = 0\n _token0 = s.token0\n _token1 = s.token1\n require(to != _token0 \u0026\u0026 to != _token1, \"FacetSwapV1: INVALID_TO\")\n if amount0Out \u003e 0\n _safeTransfer(_token0, to, amount0Out)\n end\n if amount1Out \u003e 0\n _safeTransfer(_token1, to, amount1Out)\n end\n if data.length \u003e 0\n FacetSwapV1Callee(to).facetSwapV1Call(msg.sender, amount0Out, amount1Out, data)\n end\n balance0 = ERC20(_token0).balanceOf(address(this))\n balance1 = ERC20(_token1).balanceOf(address(this))\n amount0In = if balance0 \u003e _reserve0.-(amount0Out)\n balance0 - (_reserve0 - amount0Out)\n else\n 0\n end\n amount1In = if balance1 \u003e _reserve1.-(amount1Out)\n balance1 - (_reserve1 - amount1Out)\n else\n 0\n end\n require(amount0In \u003e 0 || amount1In \u003e 0, \"FacetSwapV1: INSUFFICIENT_INPUT_AMOUNT\")\n lpFeeBPS = IFacetSwapV1Factory02(s.factory).lpFeeBPS\n balance0Adjusted = balance0 * 1000 - (amount0In * lpFeeBPS).div(10)\n balance1Adjusted = balance1 * 1000 - (amount1In * lpFeeBPS).div(10)\n require(balance0Adjusted * balance1Adjusted \u003e= uint256(_reserve0).*(_reserve1).*((1000 ** 2)), \"FacetSwapV1: K\")\n _update(balance0, balance1, _reserve0, _reserve1)\n s.unlocked=1\n emit(:Swap, sender: msg.sender, amount0In: amount0In, amount1In: amount1In, amount0Out: amount0Out, amount1Out: amount1Out, to: to)\n }\n function(:skim, { to: :address }, :external) {\n require(s.unlocked == 1, \"FacetSwapV1: LOCKED\")\n s.unlocked=0\n _token0 = s.token0\n _token1 = s.token1\n _safeTransfer(_token0, to, ERC20(_token0).balanceOf(address(this)) - s.reserve0)\n _safeTransfer(_token1, to, ERC20(_token1).balanceOf(address(this)) - s.reserve1)\n s.unlocked=1\n nil\n }\n function(:sync, {}, :external) {\n require(s.unlocked == 1, \"FacetSwapV1: LOCKED\")\n s.unlocked=0\n _update(ERC20(s.token0).balanceOf(address(this)), ERC20(s.token1).balanceOf(address(this)), s.reserve0, s.reserve1)\n s.unlocked=1\n nil\n }\n}\ncontract(:FacetSwapV1Factory02, is: :Upgradeable, upgradeable: true) {\n address(:public, :feeTo)\n address(:public, :feeToSetter)\n uint256(:public, :lpFeeBPS)\n mapping(({ address: mapping({ address: :address }) }), :public, :getPair)\n array(:address, :public, :allPairs)\n event(:PairCreated, { token0: :address, token1: :address, pair: :address, pairLength: :uint256 })\n constructor(_feeToSetter: :address) {\n s.feeToSetter=_feeToSetter\n self.Upgradeable.constructor(upgradeAdmin: msg.sender)\n }\n function(:setLpFeeBPS, { lpFeeBPS: :uint256 }, :public) {\n require(msg.sender == feeToSetter, \"FacetSwapV1: FORBIDDEN\")\n require(lpFeeBPS \u003c= 10000, \"Fees cannot exceed 100%\")\n s.lpFeeBPS=lpFeeBPS\n return nil\n }\n function(:allPairsLength, :public, :view, returns: :uint256) {\n return s.allPairs.length\n }\n function(:createPair, { tokenA: :address, tokenB: :address }, :public, returns: :address) {\n require(tokenA != tokenB, \"FacetSwapV1: IDENTICAL_ADDRESSES\")\n (token0, token1) = if tokenA.cast(:uint256) \u003c tokenB.cast(:uint256)\n [tokenA, tokenB]\n else\n [tokenB, tokenA]\n end\n require(token0 != address(0), \"FacetSwapV1: ZERO_ADDRESS\")\n require(s.getPair[token0][token1] == address(0), \"FacetSwapV1: PAIR_EXISTS\")\n salt = keccak256(abi.encodePacked(token0, token1))\n pair = new(FacetSwapV1Pair02({ salt: salt }))\n pair.init(token0, token1)\n s.getPair[token0][token1] = pair\n s.getPair[token1][token0] = pair\n s.allPairs.push(pair)\n emit(:PairCreated, { token0: token0, token1: token1, pair: pair, pairLength: s.allPairs.length })\n return pair\n }\n function(:setFeeTo, { _feeTo: :address }, :public) {\n require(msg.sender == feeToSetter, \"FacetSwapV1: FORBIDDEN\")\n s.feeTo=_feeTo\n return nil\n }\n function(:setFeeToSetter, { _feeToSetter: :address }, :public) {\n require(msg.sender == feeToSetter, \"FacetSwapV1: FORBIDDEN\")\n s.feeToSetter=_feeToSetter\n return nil\n }\n function(:upgradePairs, { pairs: [:address], newHash: :bytes32, newSource: :string }, :public) {\n require(msg.sender == s.upgradeAdmin, \"NOT_AUTHORIZED\")\n require(pairs.length \u003c= 10, \"Too many pairs to upgrade at once\")\n forLoop(condition: -\u003e(i) {\n i \u003c pairs.length\n }) { |i|\n pair = pairs[i]\n sourceToUse = if i == 0\n newSource\n else\n \"\"\n end\n upgradePair(pair: pair, newHash: newHash, newSource: sourceToUse)\n }\n }\n function(:upgradePair, { pair: :address, newHash: :bytes32, newSource: :string }, :public) {\n require(msg.sender == s.upgradeAdmin, \"NOT_AUTHORIZED\")\n Upgradeable(pair).upgrade(newHash: newHash, newSource: newSource)\n }\n}\ncontract(:Ownable, abstract: true) {\n address(:public, :owner)\n event(:OwnershipTransferred, { previousOwner: :address, newOwner: :address })\n constructor(owner: :address) {\n s.owner=owner\n }\n function(:transferOwnership, { newOwner: :address }, :public) {\n onlyOwner!\n previousOwner = s.owner\n s.owner=newOwner\n emit(:OwnershipTransferred, previousOwner: previousOwner, newOwner: newOwner)\n }\n function(:onlyOwner!, :internal) {\n require(msg.sender == s.owner, \"msg.sender is not the owner\")\n }\n}\ncontract(:Pausable, abstract: true) {\n bool(:public, :paused)\n event(:Paused, { account: :address })\n event(:Unpaused, { account: :address })\n constructor(initialPauseState: :bool) {\n s.paused=initialPauseState\n }\n function(:_pause, :internal) {\n s.paused=true\n emit(:Paused, account: msg.sender)\n }\n function(:_unpause, :internal) {\n s.paused=false\n emit(:Unpaused, account: msg.sender)\n }\n function(:whenPaused!, :internal) {\n require(s.paused, \"Contract is not paused\")\n }\n function(:whenNotPaused!, :internal) {\n require(!s.paused, \"Contract is paused\")\n }\n}\ncontract(:FacetSwapV1Router03, is: [:Ownable, :Upgradeable, :Pausable], upgradeable: true) {\n address(:public, :factory)\n address(:public, :WETH)\n uint8(:public, :maxPathLength)\n uint256(:public, :protocolFeeBPS)\n event(:FeeAdjustedSwap, { inputToken: :address, outputToken: :address, inputAmount: :uint256, outputAmount: :uint256, feeAmount: :uint256, to: :address })\n constructor(_factory: :address, _WETH: :address, protocolFeeBPS: :uint256, initialPauseState: :bool) {\n s.factory=_factory\n s.WETH=_WETH\n self.Upgradeable.constructor(upgradeAdmin: msg.sender)\n self.Ownable.constructor(owner: msg.sender)\n updateProtocolFee(protocolFeeBPS: protocolFeeBPS)\n self.Pausable.constructor(initialPauseState: initialPauseState)\n s.maxPathLength=3\n }\n function(:onUpgrade, { owner: :address, initialPauseState: :bool }, :public) {\n require(msg.sender == address(this), \"Only the contract itself can upgrade\")\n s.owner=owner\n if initialPauseState\n _pause\n else\n _unpause\n end\n }\n function(:_addLiquidity, { tokenA: :address, tokenB: :address, amountADesired: :uint256, amountBDesired: :uint256, amountAMin: :uint256, amountBMin: :uint256 }, :internal, :virtual, returns: { amountA: :uint256, amountB: :uint256 }) {\n if FacetSwapV1Factory02(factory).getPair(tokenA, tokenB) == address(0)\n FacetSwapV1Factory02(factory).createPair(tokenA, tokenB)\n end\n (reserveA, reserveB) = getReserves(s.factory, tokenA, tokenB)\n if reserveA == 0 \u0026\u0026 reserveB == 0\n return { amountA: amountADesired, amountB: amountBDesired }\n else\n amountBOptimal = quote(amountADesired, reserveA, reserveB)\n if amountBOptimal \u003c= amountBDesired\n require(amountBOptimal \u003e= amountBMin, \"FacetSwapV1Router: INSUFFICIENT_B_AMOUNT\")\n return { amountA: amountADesired, amountB: amountBOptimal }\n else\n amountAOptimal = quote(amountBDesired, reserveB, reserveA)\n require(amountAOptimal \u003c= amountADesired, \"ASSERT\")\n require(amountAOptimal \u003e= amountAMin, \"FacetSwapV1Router: INSUFFICIENT_A_AMOUNT\")\n return { amountA: amountAOptimal, amountB: amountBDesired }\n end\n end\n }\n function(:addLiquidity, { tokenA: :address, tokenB: :address, amountADesired: :uint256, amountBDesired: :uint256, amountAMin: :uint256, amountBMin: :uint256, to: :address, deadline: :uint256 }, :public, :virtual, returns: { amountA: :uint256, amountB: :uint256, liquidity: :uint256 }) {\n whenNotPaused!\n require(deadline \u003e= block.timestamp, \"FacetSwapV1Router: EXPIRED\")\n (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin)\n pair = pairFor(s.factory, tokenA, tokenB)\n _safeTransferFrom(token: tokenA, from: msg.sender, to: pair, value: amountA)\n _safeTransferFrom(token: tokenB, from: msg.sender, to: pair, value: amountB)\n liquidity = FacetSwapV1Pair02(pair).mint(to: to)\n return { amountA: amountA, amountB: amountB, liquidity: liquidity }\n }\n function(:removeLiquidity, { tokenA: :address, tokenB: :address, liquidity: :uint256, amountAMin: :uint256, amountBMin: :uint256, to: :address, deadline: :uint256 }, :public, :virtual, returns: { amountA: :uint256, amountB: :uint256 }) {\n whenNotPaused!\n require(deadline \u003e= block.timestamp, \"FacetSwapV1Router: EXPIRED\")\n pair = pairFor(s.factory, tokenA, tokenB)\n FacetSwapV1Pair02(pair).transferFrom(msg.sender, pair, liquidity)\n (amount0, amount1) = FacetSwapV1Pair02(pair).burn(to)\n (token0, _) = sortTokens(tokenA, tokenB)\n (amountA, amountB) = if tokenA == token0\n [amount0, amount1]\n else\n [amount1, amount0]\n end\n require(amountA \u003e= amountAMin, \"FacetSwapV1Router: INSUFFICIENT_A_AMOUNT\")\n require(amountB \u003e= amountBMin, \"FacetSwapV1Router: INSUFFICIENT_B_AMOUNT\")\n return { amountA: amountA, amountB: amountB }\n }\n function(:swapExactTokensForTokens, { amountIn: :uint256, amountOutMin: :uint256, path: [:address], to: :address, deadline: :uint256 }, :public, :virtual, returns: [:uint256]) {\n whenNotPaused!\n require(path[0] == s.WETH || path[path.length - 1] == s.WETH, \"Must have WETH as either the first or last token in the path\")\n amountInWithFee = if path[0] == s.WETH\n amountIn - calculateFeeAmount(amountIn)\n else\n amountIn\n end\n amounts = _swapExactTokensForTokens(amountIn: amountInWithFee, amountOutMin: amountOutMin, path: path, to: address(this), deadline: deadline)\n amountToChargeFeeOn = if path[0] == s.WETH\n amountIn\n else\n amounts[amounts.length - 1]\n end\n feeAmount = calculateFeeAmount(amountToChargeFeeOn)\n if path[0] == s.WETH\n amounts[0] = amountIn\n ERC20(s.WETH).transferFrom(from: msg.sender, to: address(this), amount: feeAmount)\n else\n amounts[amounts.length - 1] -= feeAmount\n end\n outputToken = ERC20(path[path.length - 1])\n outputToken.transfer(to, amounts[amounts.length - 1])\n emit(:FeeAdjustedSwap, inputToken: path[0], outputToken: path[path.length - 1], inputAmount: amounts[0], outputAmount: amounts[amounts.length - 1], feeAmount: feeAmount, to: to)\n amounts\n }\n function(:_swapExactTokensForTokens, { amountIn: :uint256, amountOutMin: :uint256, path: [:address], to: :address, deadline: :uint256 }, :internal, :virtual, returns: [:uint256]) {\n require(deadline \u003e= block.timestamp, \"FacetSwapV1Router: EXPIRED\")\n amounts = getAmountsOut(factory, amountIn, path)\n require(amounts[amounts.length - 1] \u003e= amountOutMin, \"FacetSwapV1Router: INSUFFICIENT_OUTPUT_AMOUNT\")\n _safeTransferFrom(path[0], msg.sender, pairFor(factory, path[0], path[1]), amounts[0])\n _swap(amounts, path, to)\n return amounts\n }\n function(:swapTokensForExactTokens, { amountOut: :uint256, amountInMax: :uint256, path: [:address], to: :address, deadline: :uint256 }, :public, :virtual, returns: [:uint256]) {\n whenNotPaused!\n require(path[0] == s.WETH || path[path.length - 1] == s.WETH, \"Must have WETH as either the first or last token in the path\")\n amountOutWithFee = if path[path.length - 1] == s.WETH\n amountOut + calculateFeeAmount(amountOut)\n else\n amountOut\n end\n amounts = _swapTokensForExactTokens(amountOut: amountOutWithFee, amountInMax: amountInMax, path: path, to: address(this), deadline: deadline)\n amountToChargeFeeOn = if path[0] == s.WETH\n amounts[0]\n else\n amountOut\n end\n feeAmount = calculateFeeAmount(amountToChargeFeeOn)\n if path[0] == s.WETH\n amounts[0] += feeAmount\n ERC20(s.WETH).transferFrom(from: msg.sender, to: address(this), amount: feeAmount)\n else\n amounts[amounts.length - 1] = amountOut\n end\n outputToken = ERC20(path[path.length - 1])\n outputToken.transfer(to, amounts[amounts.length - 1])\n emit(:FeeAdjustedSwap, inputToken: path[0], outputToken: path[path.length - 1], inputAmount: amounts[0], outputAmount: amounts[amounts.length - 1], feeAmount: feeAmount, to: to)\n amounts\n }\n function(:_swapTokensForExactTokens, { amountOut: :uint256, amountInMax: :uint256, path: [:address], to: :address, deadline: :uint256 }, :internal, :virtual, returns: [:uint256]) {\n require(deadline \u003e= block.timestamp, \"FacetSwapV1Router: EXPIRED\")\n amounts = getAmountsIn(factory, amountOut, path)\n require(amounts[0] \u003c= amountInMax, \"FacetSwapV1Router: EXCESSIVE_INPUT_AMOUNT\")\n _safeTransferFrom(path[0], msg.sender, pairFor(factory, path[0], path[1]), amounts[0])\n _swap(amounts, path, to)\n return amounts\n }\n function(:_swap, { amounts: [:uint256], path: [:address], _to: :address }, :internal, :virtual) {\n require(path.length \u003c= s.maxPathLength, \"Max path length exceeded\")\n forLoop(condition: -\u003e(i) {\n i \u003c path.length.-(1)\n }) { |i|\n (input, output) = [path[i], path[i + 1]]\n (token0, _) = sortTokens(input, output)\n amountOut = amounts[i + 1]\n (amount0Out, amount1Out) = if input == token0\n [0, amountOut]\n else\n [amountOut, 0]\n end\n to = if i \u003c path.length.-(2)\n pairFor(factory, output, path[i + 2])\n else\n _to\n end\n FacetSwapV1Pair02(pairFor(factory, input, output)).swap(amount0Out, amount1Out, to, \"\")\n }\n }\n function(:_safeTransferFrom, { token: :address, from: :address, to: :address, value: :uint256 }, :private) {\n result = ERC20(token).transferFrom(from: from, to: to, amount: value)\n require(result, \"FacetSwapV1: TRANSFER_FAILED\")\n }\n function(:getAmountsOut, { factory: :address, amountIn: :uint256, path: [:address] }, :public, :view, returns: [:uint256]) {\n require(path.length \u003e= 2, \"FacetSwapV1Library: INVALID_PATH\")\n require(path.length \u003c= s.maxPathLength, \"Max path length exceeded\")\n amounts = array(:uint256, path.length)\n amounts[0] = amountIn\n forLoop(condition: -\u003e(i) {\n i \u003c path.length.-(1)\n }) { |i|\n (reserveIn, reserveOut) = getReserves(factory, path[i], path[i + 1])\n amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut)\n }\n return amounts\n }\n function(:getAmountOut, { amountIn: :uint256, reserveIn: :uint256, reserveOut: :uint256 }, :public, :view, returns: :uint256) {\n require(amountIn \u003e 0, \"FacetSwapV1Library: INSUFFICIENT_INPUT_AMOUNT\")\n require(reserveIn \u003e 0 \u0026\u0026 reserveOut \u003e 0, \"FacetSwapV1Library: INSUFFICIENT_LIQUIDITY\")\n lpFeeBPS = FacetSwapV1Factory02(s.factory).lpFeeBPS\n totalFeeFactor = 1000 - lpFeeBPS.div(10)\n amountInWithFee = amountIn * totalFeeFactor\n numerator = amountInWithFee * reserveOut\n denominator = reserveIn * 1000 + amountInWithFee\n amountOut = numerator.div(denominator)\n return amountOut\n }\n function(:getAmountsIn, { factory: :address, amountOut: :uint256, path: [:address] }, :public, :view, returns: [:uint256]) {\n require(path.length \u003e= 2, \"FacetSwapV1Library: INVALID_PATH\")\n require(path.length \u003c= s.maxPathLength, \"Max path length exceeded\")\n amounts = array(:uint256, path.length)\n amounts[amounts.length - 1] = amountOut\n forLoop(start: path.length - 1, condition: -\u003e(i) {\n i \u003e 0\n }, step: -1) { |i|\n (reserveIn, reserveOut) = getReserves(factory, path[i - 1], path[i])\n amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut)\n }\n return amounts\n }\n function(:getAmountIn, { amountOut: :uint256, reserveIn: :uint256, reserveOut: :uint256 }, :public, :view, returns: :uint256) {\n require(amountOut \u003e 0, \"FacetSwapV1Library: INSUFFICIENT_OUTPUT_AMOUNT\")\n require(reserveIn \u003e 0 \u0026\u0026 reserveOut \u003e 0, \"FacetSwapV1Library: INSUFFICIENT_LIQUIDITY\")\n lpFeeBPS = FacetSwapV1Factory02(s.factory).lpFeeBPS\n totalFeeFactor = 1000 - lpFeeBPS.div(10)\n numerator = reserveIn * amountOut * 1000\n denominator = (reserveOut - amountOut) * totalFeeFactor\n amountIn = (numerator.div(denominator)) + 1\n return amountIn\n }\n function(:quote, { amountA: :uint256, reserveA: :uint256, reserveB: :uint256 }, :public, :pure, returns: :uint256) {\n require(amountA \u003e 0, \"FacetSwapV1Library: INSUFFICIENT_AMOUNT\")\n require(reserveA \u003e 0 \u0026\u0026 reserveB \u003e 0, \"FacetSwapV1Library: INSUFFICIENT_LIQUIDITY\")\n return (amountA * reserveB).div(reserveA)\n }\n function(:getReserves, { factory: :address, tokenA: :address, tokenB: :address }, :public, :view, returns: { reserveA: :uint256, reserveB: :uint256 }) {\n (token0, _) = sortTokens(tokenA, tokenB)\n (reserve0, reserve1, _) = FacetSwapV1Pair02(pairFor(factory, tokenA, tokenB)).getReserves\n (reserveA, reserveB) = if tokenA == token0\n [reserve0, reserve1]\n else\n [reserve1, reserve0]\n end\n return { reserveA: reserveA, reserveB: reserveB }\n }\n function(:pairFor, { factory: :address, tokenA: :address, tokenB: :address }, :internal, :view, returns: :address) {\n return FacetSwapV1Factory02(s.factory).getPair(tokenA, tokenB)\n }\n function(:sortTokens, { tokenA: :address, tokenB: :address }, :internal, :pure, returns: { token0: :address, token1: :address }) {\n require(tokenA != tokenB, \"FacetSwapV1Library: IDENTICAL_ADDRESSES\")\n (token0, token1) = if tokenA.cast(:uint256) \u003c tokenB.cast(:uint256)\n [tokenA, tokenB]\n else\n [tokenB, tokenA]\n end\n require(token0 != address(0), \"FacetSwapV1Library: ZERO_ADDRESS\")\n return { token0: token0, token1: token1 }\n }\n function(:calculateFeeAmount, { amount: :uint256 }, :public, :view, returns: :uint256) {\n return (amount * s.protocolFeeBPS).div(10000)\n }\n function(:updateProtocolFee, { protocolFeeBPS: :uint256 }, :public) {\n onlyOwner!\n require(protocolFeeBPS \u003c= 10000, \"Fee cannot be greater than 100%\")\n s.protocolFeeBPS=protocolFeeBPS\n nil\n }\n function(:withdrawFees, { to: :address }, :public, returns: :bool) {\n onlyOwner!\n ERC20(s.WETH).transfer(to: to, amount: ERC20(s.WETH).balanceOf(address(this)))\n }\n function(:pause, :public) {\n onlyOwner!\n _pause\n }\n function(:unpause, :public) {\n onlyOwner!\n _unpause\n }\n function(:userStats, { user: :address, tokenA: :address, tokenB: :address }, :public, :view, returns: { userTokenABalance: :uint256, userTokenBBalance: :uint256, tokenAName: :string, tokenBName: :string, tokenAReserves: :uint256, tokenBReserves: :uint256, userLPBalance: :uint256, pairAddress: :address }) {\n tokenAReserves = 0\n tokenBReserves = 0\n userLPBalance = 0\n if FacetSwapV1Factory02(s.factory).getPair(tokenA, tokenB) != address(0)\n (tokenAReserves, tokenBReserves) = getReserves(s.factory, tokenA, tokenB)\n pair = FacetSwapV1Factory02(s.factory).getPair(tokenA, tokenB)\n userLPBalance = FacetSwapV1ERC20(pair).balanceOf(user)\n end\n return { userTokenABalance: ERC20(tokenA).balanceOf(user), userTokenBBalance: ERC20(tokenB).balanceOf(user), tokenAName: ERC20(tokenA).name, tokenBName: ERC20(tokenB).name, tokenAReserves: tokenAReserves, tokenBReserves: tokenBReserves, userLPBalance: userLPBalance, pairAddress: pair }\n }\n}\n"}}}