POL Price: $0.701444 (-1.33%)
Gas: 30 GWei
 

Overview

POL Balance

Polygon PoS Chain LogoPolygon PoS Chain LogoPolygon PoS Chain Logo0 POL

POL Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BalancerAMM

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 14 : BalancerAMM.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

// ==========================================================
// ====================== BalancerAMM.sol ====================
// ==========================================================

/**
 * @title Balancer AMM
 * @dev Interactions with Balancer Pool
 */

import { ChainlinkLibrary, IPriceFeed } from "../Libraries/Chainlink.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { TransferHelper } from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
import { ISweep } from "../Sweep/ISweep.sol";
import { IAsset, SingleSwap, FundManagement, SwapKind, IBalancerVault, IBalancerPool } from "../Assets/Interfaces/Balancer/IBalancer.sol";
import { StableMath } from "../Libraries/Balancer/StableMath.sol";
import { IMarketMaker } from "../Balancer/IMarketMaker.sol";

contract BalancerAMM {
    using Math for uint256;

    IBalancerVault public vault;
    IBalancerPool public pool;

    IERC20Metadata public immutable base;
    ISweep public immutable sweep;
    IPriceFeed public immutable oracleBase;
    IPriceFeed public immutable sequencer;
    uint256 public immutable oracleBaseUpdateFrequency;
    IMarketMaker public marketMaker;

    uint8 private constant USD_DECIMALS = 6;
    uint16 private constant DEADLINE_GAP = 15 minutes;

    constructor(
        address _sweep,
        address _base,
        address _sequencer,
        address _oracleBase,
        uint256 _oracleBaseUpdateFrequency
    ) {
        sweep = ISweep(_sweep);
        base = IERC20Metadata(_base);
        oracleBase = IPriceFeed(_oracleBase);
        sequencer = IPriceFeed(_sequencer);
        oracleBaseUpdateFrequency = _oracleBaseUpdateFrequency;
    }

    // Events
    event Bought(uint256 usdxAmount);
    event Sold(uint256 sweepAmount);

    // Errors
    error ZeroAmount();
    error BadRate();
    error NotOwnerOrGov();

    modifier onlyOwner () {
        if (msg.sender != sweep.fastMultisig() && msg.sender != sweep.owner())
            revert NotOwnerOrGov();
        _;
    }

    /**
     * @notice Get Price
     * @dev Get the quote for selling 1 unit of a token.
     */
    function getPrice() public view returns (uint256 amountOut) {
        if(address(pool) == address(0)) return 2e6;

        uint8 sweepDecimals = sweep.decimals();
        uint8 baseDecimals = base.decimals();
        uint8 quoteDecimals = sweepDecimals - baseDecimals;

        uint256[] memory factors = pool.getScalingFactors();
        (uint256 amplification, , ) = pool.getAmplificationParameter();
        (IAsset[] memory tokens, uint256[] memory balances,) = IBalancerVault(pool.getVault()).getPoolTokens(pool.getPoolId());

        uint8 tokenIndexIn = findAssetIndex(address(sweep), tokens);
        uint8 tokenIndexOut = findAssetIndex(address(base), tokens);

        uint256[] memory newBalances = new uint256[](2);
        newBalances[0] = balances[tokenIndexIn];
        newBalances[1] = balances[tokenIndexOut] * (10 ** quoteDecimals);

        uint256 invariant = StableMath._calculateInvariant(amplification, newBalances);
        uint256 quote = StableMath._calcOutGivenIn(amplification, newBalances, 0, 1, 1e18, invariant);
        uint8 oracleDecimals = ChainlinkLibrary.getDecimals(oracleBase);
        uint256 price = ChainlinkLibrary.getPrice(
            oracleBase,
            sequencer,
            oracleBaseUpdateFrequency
        );

        amountOut = (quote * factors[tokenIndexIn] * price) / (10 ** (oracleDecimals + sweepDecimals + quoteDecimals));
    }

    /**
     * @notice Get TWA Price
     * @dev Get the quote for selling 1 unit of a token.
     */
    function getTWAPrice() external view returns (uint256 amountOut) {
        return getPrice();
    }

    function getRate() public view returns (uint256 rate) {
        rate = sweep.targetPrice() * 1e12;
    }

    function getPositions(uint256)
        public view
        returns (uint256 usdxAmount, uint256 sweepAmount, uint256 lp)
    {
        (IAsset[] memory tokens, uint256[] memory balances,) = IBalancerVault(pool.getVault()).getPoolTokens(pool.getPoolId());
        uint8 usdxIndex = findAssetIndex(address(base), tokens);
        uint8 sweepIndex = findAssetIndex(address(sweep), tokens);
        uint8 lpIndex = findAssetIndex(address(pool), tokens);

        usdxAmount = balances[usdxIndex];
        sweepAmount = balances[sweepIndex];
        lp = balances[lpIndex];
    }

    /* ========== Actions ========== */

    /**
     * @notice Buy Sweep
     * @param usdxAddress Token Address to use for buying sweep.
     * @param usdxAmount Token Amount.
     * @param amountOutMin Minimum amount out.
     * @dev Increases the sweep balance and decrease collateral balance.
     */
    function buySweep(address usdxAddress, uint256 usdxAmount, uint256 amountOutMin) 
        external returns (uint256 sweepAmount)
    {
        emit Bought(usdxAmount);

        if (address(marketMaker) != address(0) && marketMaker.getBuyPrice() < getPrice()) {
            TransferHelper.safeTransferFrom(address(base), msg.sender, address(this), usdxAmount);
            TransferHelper.safeApprove(address(base), address(marketMaker), usdxAmount);
            sweepAmount = marketMaker.buySweep(usdxAmount);
            TransferHelper.safeTransfer(address(sweep), msg.sender, sweepAmount);
        } else {
            checkRate(usdxAddress, usdxAmount, amountOutMin);
            sweepAmount = swap(usdxAddress, address(sweep), usdxAmount, amountOutMin, address(pool));
        }        
    }

    /**
     * @notice Sell Sweep
     * @param usdxAddress Token Address to return after selling sweep.
     * @param sweepAmount Sweep Amount.
     * @param amountOutMin Minimum amount out.
     * @dev Decreases the sweep balance and increase collateral balance
     */
    function sellSweep(
        address usdxAddress,
        uint256 sweepAmount,
        uint256 amountOutMin
    ) external returns (uint256 tokenAmount) {
        emit Sold(sweepAmount);
        checkRate(usdxAddress, amountOutMin, sweepAmount);
        tokenAmount = swap(address(sweep), usdxAddress, sweepAmount, amountOutMin, address(pool));
    }

    /**
     * @notice Swap tokenIn for tokenOut using balancer exact input swap
     * @param tokenIn Address to in
     * @param tokenOut Address to out
     * @param amountIn Amount of _tokenA
     * @param amountOutMin Minimum amount out.
     */
    function swapExactInput(
        address tokenIn,
        address tokenOut,
        uint24,
        uint256 amountIn,
        uint256 amountOutMin
    ) public returns (uint256 amountOut) {
        return swap(tokenIn, tokenOut, amountIn, amountOutMin, address(pool));
    }

    function setPool(address poolAddress) external {
        require(msg.sender == sweep.owner(), "BalancerAMM: Not Governance");
        pool = IBalancerPool(poolAddress);
    }

    function findAssetIndex(address asset, IAsset[] memory assets) internal pure returns (uint8) {
        for (uint8 i = 0; i < assets.length; i++) {
            if (address(assets[i]) == asset) {
                return i;
            }
        }
        revert("BalancerAMM: Asset not found");
    }

    function checkRate(address token, uint256 tokenAmount, uint256 sweepAmount) internal view {
        if(tokenAmount == 0 || sweepAmount == 0) revert ZeroAmount();
        uint256 tokenFactor = 10 ** IERC20Metadata(token).decimals();
        uint256 sweepFactor = 10 ** sweep.decimals();
        uint256 rate = tokenAmount * sweepFactor * 1e6 / (tokenFactor * sweepAmount);
        if(rate > 16e5 || rate < 6e5) revert BadRate();
    }

    /**
     * @notice Swap tokenIn for tokenOut using balancer exact input swap
     * @param tokenIn Address to in
     * @param tokenOut Address to out
     * @param amountIn Amount of _tokenA
     * @param amountOutMin Minimum amount out.
     * @param poolAddress The pool to execute the swap into
     */
    function swap(address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOutMin, address poolAddress) 
        private returns (uint256 amountOut)
    {
        bytes32 poolId = IBalancerPool(poolAddress).getPoolId();
        address vaultAddress = IBalancerPool(poolAddress).getVault();

        TransferHelper.safeTransferFrom(tokenIn, msg.sender, address(this), amountIn);
        TransferHelper.safeApprove(tokenIn, vaultAddress, amountIn);

        bytes memory userData;
        SingleSwap memory singleSwap = SingleSwap(
            poolId,
            SwapKind.GIVEN_IN,
            IAsset(tokenIn),
            IAsset(tokenOut),
            amountIn,
            userData
        );

        FundManagement memory funds = FundManagement(address(this), false, payable(msg.sender), false);
        uint256 deadline = block.timestamp + DEADLINE_GAP;

        amountOut = IBalancerVault(vaultAddress).swap(singleSwap, funds, amountOutMin, deadline);
    }

    function setMarketMaker(address _marketMaker) external onlyOwner {
        marketMaker = IMarketMaker(_marketMaker);
    }
}

File 2 of 14 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../token/ERC20/extensions/IERC20Metadata.sol";

File 3 of 14 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 4 of 14 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 5 of 14 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10**64) {
                value /= 10**64;
                result += 64;
            }
            if (value >= 10**32) {
                value /= 10**32;
                result += 32;
            }
            if (value >= 10**16) {
                value /= 10**16;
                result += 16;
            }
            if (value >= 10**8) {
                value /= 10**8;
                result += 8;
            }
            if (value >= 10**4) {
                value /= 10**4;
                result += 4;
            }
            if (value >= 10**2) {
                value /= 10**2;
                result += 2;
            }
            if (value >= 10**1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
        }
    }
}

File 6 of 14 : TransferHelper.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.0;

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

library TransferHelper {
    /// @notice Transfers tokens from the targeted address to the given destination
    /// @notice Errors with 'STF' if transfer fails
    /// @param token The contract address of the token to be transferred
    /// @param from The originating address from which the tokens will be transferred
    /// @param to The destination address of the transfer
    /// @param value The amount to be transferred
    function safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) = token.call(
            abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)
        );
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF');
    }

    /// @notice Transfers tokens from msg.sender to a recipient
    /// @dev Errors with ST if transfer fails
    /// @param token The contract address of the token which will be transferred
    /// @param to The recipient of the transfer
    /// @param value The value of the transfer
    function safeTransfer(
        address token,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST');
    }

    /// @notice Approves the stipulated contract to spend the given allowance in the given token
    /// @dev Errors with 'SA' if transfer fails
    /// @param token The contract address of the token to be approved
    /// @param to The target of the approval
    /// @param value The amount of the given token the target will be allowed to spend
    function safeApprove(
        address token,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA');
    }

    /// @notice Transfers ETH to the recipient address
    /// @dev Fails with `STE`
    /// @param to The destination of the transfer
    /// @param value The value to be transferred
    function safeTransferETH(address to, uint256 value) internal {
        (bool success, ) = to.call{value: value}(new bytes(0));
        require(success, 'STE');
    }
}

File 7 of 14 : IBalancer.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

import "@openzeppelin/contracts/interfaces/IERC20Metadata.sol";

interface IBalancerGauge {
    function claim_rewards() external;
    function deposit(uint256 _amount) external;
    function withdraw(uint256 _amount) external;
    function balanceOf(address _address) external view returns(uint256 _balance);
}

interface IBalancerVault {
    struct JoinPoolRequest {
        IAsset[] assets;
        uint256[] maxAmountsIn;
        bytes userData;
        bool fromInternalBalance;
    }

    struct ExitPoolRequest {
        IAsset[] assets;
        uint256[] minAmountsOut;
        bytes userData;
        bool toInternalBalance;
    }

    function joinPool(bytes32 poolId, address sender, address recipient, JoinPoolRequest memory request) external payable;
    function exitPool(bytes32 poolId, address sender, address recipient, ExitPoolRequest memory request) external payable;
    function getPoolTokens(bytes32 poolId) external view returns (IAsset[] memory tokens, uint256[] memory balances, uint256 lastChangeBlock);
    function swap(SingleSwap memory singleSwap, FundManagement memory funds, uint256 limit, uint256 deadline) external returns (uint256 amountOut);
}

interface IAsset {
    // solhint-disable-previous-line no-empty-blocks
}

interface IBalancerPool is IERC20Metadata {
    function getPoolId() external view returns (bytes32);
    function getVault() external view returns (address);
    function getRate() external view returns (uint256);
    function getTokenRate(address) external view returns (uint256);
    function getScalingFactors() external view returns (uint256[] memory);
    function getAmplificationParameter() external view returns (uint256, bool, uint256);
}

struct SingleSwap {
   bytes32 poolId;
   SwapKind kind;
   IAsset assetIn;
   IAsset assetOut;
   uint256 amount;
   bytes userData;
}

struct FundManagement {
    address sender;
    bool fromInternalBalance;
    address payable recipient;
    bool toInternalBalance;
}

interface IComposableStablePoolFactory {
    function create(
        string memory name,
        string memory symbol,
        IERC20[] memory tokens,
        uint256 amplificationParameter,
        IRateProvider[] memory rateProviders,
        uint256[] memory tokenRateCacheDurations,
        bool exemptFromYieldProtocolFeeFlag,
        uint256 swapFeePercentage,
        address owner,
        bytes32 salt
    ) external returns(address poolAddress);
}

interface IRateProvider {
    function getRate() external view returns (uint256);
}

enum JoinKind { INIT, EXACT_TOKENS_IN_FOR_BPT_OUT, TOKEN_IN_FOR_EXACT_BPT_OUT, ALL_TOKENS_IN_FOR_EXACT_BPT_OUT }
enum ExitKind { EXACT_BPT_IN_FOR_ONE_TOKEN_OUT, BPT_IN_FOR_EXACT_TOKENS_OUT, EXACT_BPT_IN_FOR_ALL_TOKENS_OUT }
enum SwapKind { GIVEN_IN, GIVEN_OUT }

File 8 of 14 : IMarketMaker.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

interface IMarketMaker {
    function getBuyPrice() external view returns (uint256 price); 
    function buySweep(uint256 usdxAmount) external returns (uint256 sweepAmount);
}

File 9 of 14 : FixedPoint.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

import "./LogExpMath.sol";

/* solhint-disable private-vars-leading-underscore */
library FixedPoint {
    // solhint-disable no-inline-assembly

    uint256 internal constant ONE = 1e18; // 18 decimal places
    uint256 internal constant TWO = 2 * ONE;
    uint256 internal constant FOUR = 4 * ONE;
    uint256 internal constant MAX_POW_RELATIVE_ERROR = 10000; // 10^(-14)

    // Minimum base for the power function when the exponent is 'free' (larger than ONE).
    uint256 internal constant MIN_POW_BASE_FREE_EXPONENT = 0.7e18;

    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        // Fixed Point addition is the same as regular checked addition

        uint256 c = a + b;
        require(c >= a, "ADD_OVERFLOW");
        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        // Fixed Point addition is the same as regular checked addition

        require(b <= a, "SUB_OVERFLOW");
        uint256 c = a - b;
        return c;
    }

    function mulDown(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 product = a * b;
        require(a == 0 || product / a == b, "MUL_OVERFLOW");

        return product / ONE;
    }

    function mulUp(uint256 a, uint256 b) internal pure returns (uint256 result) {
        uint256 product = a * b;
        require(a == 0 || product / a == b, "MUL_OVERFLOW");

        // The traditional divUp formula is:
        // divUp(x, y) := (x + y - 1) / y
        // To avoid intermediate overflow in the addition, we distribute the division and get:
        // divUp(x, y) := (x - 1) / y + 1
        // Note that this requires x != 0, if x == 0 then the result is zero
        //
        // Equivalent to:
        // result = product == 0 ? 0 : ((product - 1) / FixedPoint.ONE) + 1;
        assembly {
            result := mul(iszero(iszero(product)), add(div(sub(product, 1), ONE), 1))
        }
    }

    function divDown(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "ZERO_DIVISION");

        uint256 aInflated = a * ONE;
        require(a == 0 || aInflated / a == ONE, "DIV_INTERNAL"); // mul overflow

        return aInflated / b;
    }

    function divUp(uint256 a, uint256 b) internal pure returns (uint256 result) {
        require(b != 0, "ZERO_DIVISION");

        uint256 aInflated = a * ONE;
        require(a == 0 || aInflated / a == ONE, "DIV_INTERNAL"); // mul overflow

        // The traditional divUp formula is:
        // divUp(x, y) := (x + y - 1) / y
        // To avoid intermediate overflow in the addition, we distribute the division and get:
        // divUp(x, y) := (x - 1) / y + 1
        // Note that this requires x != 0, if x == 0 then the result is zero
        //
        // Equivalent to:
        // result = a == 0 ? 0 : (a * FixedPoint.ONE - 1) / b + 1;
        assembly {
            result := mul(iszero(iszero(aInflated)), add(div(sub(aInflated, 1), b), 1))
        }
    }

    /**
     * @dev Returns x^y, assuming both are fixed point numbers, rounding down. The result is guaranteed to not be above
     * the true value (that is, the error function expected - actual is always positive).
     */
    function powDown(uint256 x, uint256 y) internal pure returns (uint256) {
        // Optimize for when y equals 1.0, 2.0 or 4.0, as those are very simple to implement and occur often in 50/50
        // and 80/20 Weighted Pools
        if (y == ONE) {
            return x;
        } else if (y == TWO) {
            return mulDown(x, x);
        } else if (y == FOUR) {
            uint256 square = mulDown(x, x);
            return mulDown(square, square);
        } else {
            uint256 raw = LogExpMath.pow(x, y);
            uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1);

            if (raw < maxError) {
                return 0;
            } else {
                return sub(raw, maxError);
            }
        }
    }

    /**
     * @dev Returns x^y, assuming both are fixed point numbers, rounding up. The result is guaranteed to not be below
     * the true value (that is, the error function expected - actual is always negative).
     */
    function powUp(uint256 x, uint256 y) internal pure returns (uint256) {
        // Optimize for when y equals 1.0, 2.0 or 4.0, as those are very simple to implement and occur often in 50/50
        // and 80/20 Weighted Pools
        if (y == ONE) {
            return x;
        } else if (y == TWO) {
            return mulUp(x, x);
        } else if (y == FOUR) {
            uint256 square = mulUp(x, x);
            return mulUp(square, square);
        } else {
            uint256 raw = LogExpMath.pow(x, y);
            uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1);

            return add(raw, maxError);
        }
    }

    /**
     * @dev Returns the complement of a value (1 - x), capped to 0 if x is larger than 1.
     *
     * Useful when computing the complement for values with some level of relative error, as it strips this error and
     * prevents intermediate negative values.
     */
    function complement(uint256 x) internal pure returns (uint256 result) {
        // Equivalent to:
        // result = (x < ONE) ? (ONE - x) : 0;
        assembly {
            result := mul(lt(x, ONE), sub(ONE, x))
        }
    }
}

File 10 of 14 : LogExpMath.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

/* solhint-disable */

/**
 * @dev Exponentiation and logarithm functions for 18 decimal fixed point numbers (both base and exponent/argument).
 *
 * Exponentiation and logarithm with arbitrary bases (x^y and log_x(y)) are implemented by conversion to natural
 * exponentiation and logarithm (where the base is Euler's number).
 *
 * @author Fernando Martinelli - @fernandomartinelli
 * @author Sergio Yuhjtman - @sergioyuhjtman
 * @author Daniel Fernandez - @dmf7z
 */
library LogExpMath {
    // All fixed point multiplications and divisions are inlined. This means we need to divide by ONE when multiplying
    // two numbers, and multiply by ONE when dividing them.

    // All arguments and return values are 18 decimal fixed point numbers.
    int256 constant ONE_18 = 1e18;

    // Internally, intermediate values are computed with higher precision as 20 decimal fixed point numbers, and in the
    // case of ln36, 36 decimals.
    int256 constant ONE_20 = 1e20;
    int256 constant ONE_36 = 1e36;

    // The domain of natural exponentiation is bound by the word size and number of decimals used.
    //
    // Because internally the result will be stored using 20 decimals, the largest possible result is
    // (2^255 - 1) / 10^20, which makes the largest exponent ln((2^255 - 1) / 10^20) = 130.700829182905140221.
    // The smallest possible result is 10^(-18), which makes largest negative argument
    // ln(10^(-18)) = -41.446531673892822312.
    // We use 130.0 and -41.0 to have some safety margin.
    int256 constant MAX_NATURAL_EXPONENT = 130e18;
    int256 constant MIN_NATURAL_EXPONENT = -41e18;

    // Bounds for ln_36's argument. Both ln(0.9) and ln(1.1) can be represented with 36 decimal places in a fixed point
    // 256 bit integer.
    int256 constant LN_36_LOWER_BOUND = ONE_18 - 1e17;
    int256 constant LN_36_UPPER_BOUND = ONE_18 + 1e17;

    uint256 constant MILD_EXPONENT_BOUND = 2**254 / uint256(ONE_20);

    // 18 decimal constants
    int256 constant x0 = 128000000000000000000; // 2ˆ7
    int256 constant a0 = 38877084059945950922200000000000000000000000000000000000; // eˆ(x0) (no decimals)
    int256 constant x1 = 64000000000000000000; // 2ˆ6
    int256 constant a1 = 6235149080811616882910000000; // eˆ(x1) (no decimals)

    // 20 decimal constants
    int256 constant x2 = 3200000000000000000000; // 2ˆ5
    int256 constant a2 = 7896296018268069516100000000000000; // eˆ(x2)
    int256 constant x3 = 1600000000000000000000; // 2ˆ4
    int256 constant a3 = 888611052050787263676000000; // eˆ(x3)
    int256 constant x4 = 800000000000000000000; // 2ˆ3
    int256 constant a4 = 298095798704172827474000; // eˆ(x4)
    int256 constant x5 = 400000000000000000000; // 2ˆ2
    int256 constant a5 = 5459815003314423907810; // eˆ(x5)
    int256 constant x6 = 200000000000000000000; // 2ˆ1
    int256 constant a6 = 738905609893065022723; // eˆ(x6)
    int256 constant x7 = 100000000000000000000; // 2ˆ0
    int256 constant a7 = 271828182845904523536; // eˆ(x7)
    int256 constant x8 = 50000000000000000000; // 2ˆ-1
    int256 constant a8 = 164872127070012814685; // eˆ(x8)
    int256 constant x9 = 25000000000000000000; // 2ˆ-2
    int256 constant a9 = 128402541668774148407; // eˆ(x9)
    int256 constant x10 = 12500000000000000000; // 2ˆ-3
    int256 constant a10 = 113314845306682631683; // eˆ(x10)
    int256 constant x11 = 6250000000000000000; // 2ˆ-4
    int256 constant a11 = 106449445891785942956; // eˆ(x11)

    /**
     * @dev Exponentiation (x^y) with unsigned 18 decimal fixed point base and exponent.
     *
     * Reverts if ln(x) * y is smaller than `MIN_NATURAL_EXPONENT`, or larger than `MAX_NATURAL_EXPONENT`.
     */
    function pow(uint256 x, uint256 y) internal pure returns (uint256) {
        if (y == 0) {
            // We solve the 0^0 indetermination by making it equal one.
            return uint256(ONE_18);
        }

        if (x == 0) {
            return 0;
        }

        // Instead of computing x^y directly, we instead rely on the properties of logarithms and exponentiation to
        // arrive at that result. In particular, exp(ln(x)) = x, and ln(x^y) = y * ln(x). This means
        // x^y = exp(y * ln(x)).

        // The ln function takes a signed value, so we need to make sure x fits in the signed 256 bit range.
        require(x >> 255 == 0, "X_OUT_OF_BOUNDS");
        int256 x_int256 = int256(x);

        // We will compute y * ln(x) in a single step. Depending on the value of x, we can either use ln or ln_36. In
        // both cases, we leave the division by ONE_18 (due to fixed point multiplication) to the end.

        // This prevents y * ln(x) from overflowing, and at the same time guarantees y fits in the signed 256 bit range.
        require(y < MILD_EXPONENT_BOUND, "Y_OUT_OF_BOUNDS");
        int256 y_int256 = int256(y);

        int256 logx_times_y;
        if (LN_36_LOWER_BOUND < x_int256 && x_int256 < LN_36_UPPER_BOUND) {
            int256 ln_36_x = _ln_36(x_int256);

            // ln_36_x has 36 decimal places, so multiplying by y_int256 isn't as straightforward, since we can't just
            // bring y_int256 to 36 decimal places, as it might overflow. Instead, we perform two 18 decimal
            // multiplications and add the results: one with the first 18 decimals of ln_36_x, and one with the
            // (downscaled) last 18 decimals.
            logx_times_y = ((ln_36_x / ONE_18) * y_int256 + ((ln_36_x % ONE_18) * y_int256) / ONE_18);
        } else {
            logx_times_y = _ln(x_int256) * y_int256;
        }
        logx_times_y /= ONE_18;

        // Finally, we compute exp(y * ln(x)) to arrive at x^y
        require(
            MIN_NATURAL_EXPONENT <= logx_times_y && logx_times_y <= MAX_NATURAL_EXPONENT,
            "PRODUCT_OUT_OF_BOUNDS"
        );

        return uint256(exp(logx_times_y));
    }

    /**
     * @dev Natural exponentiation (e^x) with signed 18 decimal fixed point exponent.
     *
     * Reverts if `x` is smaller than MIN_NATURAL_EXPONENT, or larger than `MAX_NATURAL_EXPONENT`.
     */
    function exp(int256 x) internal pure returns (int256) {
        require(x >= MIN_NATURAL_EXPONENT && x <= MAX_NATURAL_EXPONENT, "INVALID_EXPONENT");

        if (x < 0) {
            // We only handle positive exponents: e^(-x) is computed as 1 / e^x. We can safely make x positive since it
            // fits in the signed 256 bit range (as it is larger than MIN_NATURAL_EXPONENT).
            // Fixed point division requires multiplying by ONE_18.
            return ((ONE_18 * ONE_18) / exp(-x));
        }

        // First, we use the fact that e^(x+y) = e^x * e^y to decompose x into a sum of powers of two, which we call x_n,
        // where x_n == 2^(7 - n), and e^x_n = a_n has been precomputed. We choose the first x_n, x0, to equal 2^7
        // because all larger powers are larger than MAX_NATURAL_EXPONENT, and therefore not present in the
        // decomposition.
        // At the end of this process we will have the product of all e^x_n = a_n that apply, and the remainder of this
        // decomposition, which will be lower than the smallest x_n.
        // exp(x) = k_0 * a_0 * k_1 * a_1 * ... + k_n * a_n * exp(remainder), where each k_n equals either 0 or 1.
        // We mutate x by subtracting x_n, making it the remainder of the decomposition.

        // The first two a_n (e^(2^7) and e^(2^6)) are too large if stored as 18 decimal numbers, and could cause
        // intermediate overflows. Instead we store them as plain integers, with 0 decimals.
        // Additionally, x0 + x1 is larger than MAX_NATURAL_EXPONENT, which means they will not both be present in the
        // decomposition.

        // For each x_n, we test if that term is present in the decomposition (if x is larger than it), and if so deduct
        // it and compute the accumulated product.

        int256 firstAN;
        if (x >= x0) {
            x -= x0;
            firstAN = a0;
        } else if (x >= x1) {
            x -= x1;
            firstAN = a1;
        } else {
            firstAN = 1; // One with no decimal places
        }

        // We now transform x into a 20 decimal fixed point number, to have enhanced precision when computing the
        // smaller terms.
        x *= 100;

        // `product` is the accumulated product of all a_n (except a0 and a1), which starts at 20 decimal fixed point
        // one. Recall that fixed point multiplication requires dividing by ONE_20.
        int256 product = ONE_20;

        if (x >= x2) {
            x -= x2;
            product = (product * a2) / ONE_20;
        }
        if (x >= x3) {
            x -= x3;
            product = (product * a3) / ONE_20;
        }
        if (x >= x4) {
            x -= x4;
            product = (product * a4) / ONE_20;
        }
        if (x >= x5) {
            x -= x5;
            product = (product * a5) / ONE_20;
        }
        if (x >= x6) {
            x -= x6;
            product = (product * a6) / ONE_20;
        }
        if (x >= x7) {
            x -= x7;
            product = (product * a7) / ONE_20;
        }
        if (x >= x8) {
            x -= x8;
            product = (product * a8) / ONE_20;
        }
        if (x >= x9) {
            x -= x9;
            product = (product * a9) / ONE_20;
        }

        // x10 and x11 are unnecessary here since we have high enough precision already.

        // Now we need to compute e^x, where x is small (in particular, it is smaller than x9). We use the Taylor series
        // expansion for e^x: 1 + x + (x^2 / 2!) + (x^3 / 3!) + ... + (x^n / n!).

        int256 seriesSum = ONE_20; // The initial one in the sum, with 20 decimal places.
        int256 term; // Each term in the sum, where the nth term is (x^n / n!).

        // The first term is simply x.
        term = x;
        seriesSum += term;

        // Each term (x^n / n!) equals the previous one times x, divided by n. Since x is a fixed point number,
        // multiplying by it requires dividing by ONE_20, but dividing by the non-fixed point n values does not.

        term = ((term * x) / ONE_20) / 2;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 3;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 4;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 5;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 6;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 7;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 8;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 9;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 10;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 11;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 12;
        seriesSum += term;

        // 12 Taylor terms are sufficient for 18 decimal precision.

        // We now have the first a_n (with no decimals), and the product of all other a_n present, and the Taylor
        // approximation of the exponentiation of the remainder (both with 20 decimals). All that remains is to multiply
        // all three (one 20 decimal fixed point multiplication, dividing by ONE_20, and one integer multiplication),
        // and then drop two digits to return an 18 decimal value.

        return (((product * seriesSum) / ONE_20) * firstAN) / 100;
    }

    /**
     * @dev Logarithm (log(arg, base), with signed 18 decimal fixed point base and argument.
     */
    function log(int256 arg, int256 base) internal pure returns (int256) {
        // This performs a simple base change: log(arg, base) = ln(arg) / ln(base).

        // Both logBase and logArg are computed as 36 decimal fixed point numbers, either by using ln_36, or by
        // upscaling.

        int256 logBase;
        if (LN_36_LOWER_BOUND < base && base < LN_36_UPPER_BOUND) {
            logBase = _ln_36(base);
        } else {
            logBase = _ln(base) * ONE_18;
        }

        int256 logArg;
        if (LN_36_LOWER_BOUND < arg && arg < LN_36_UPPER_BOUND) {
            logArg = _ln_36(arg);
        } else {
            logArg = _ln(arg) * ONE_18;
        }

        // When dividing, we multiply by ONE_18 to arrive at a result with 18 decimal places
        return (logArg * ONE_18) / logBase;
    }

    /**
     * @dev Natural logarithm (ln(a)) with signed 18 decimal fixed point argument.
     */
    function ln(int256 a) internal pure returns (int256) {
        // The real natural logarithm is not defined for negative numbers or zero.
        require(a > 0, "OUT_OF_BOUNDS");
        if (LN_36_LOWER_BOUND < a && a < LN_36_UPPER_BOUND) {
            return _ln_36(a) / ONE_18;
        } else {
            return _ln(a);
        }
    }

    /**
     * @dev Internal natural logarithm (ln(a)) with signed 18 decimal fixed point argument.
     */
    function _ln(int256 a) private pure returns (int256) {
        if (a < ONE_18) {
            // Since ln(a^k) = k * ln(a), we can compute ln(a) as ln(a) = ln((1/a)^(-1)) = - ln((1/a)). If a is less
            // than one, 1/a will be greater than one, and this if statement will not be entered in the recursive call.
            // Fixed point division requires multiplying by ONE_18.
            return (-_ln((ONE_18 * ONE_18) / a));
        }

        // First, we use the fact that ln^(a * b) = ln(a) + ln(b) to decompose ln(a) into a sum of powers of two, which
        // we call x_n, where x_n == 2^(7 - n), which are the natural logarithm of precomputed quantities a_n (that is,
        // ln(a_n) = x_n). We choose the first x_n, x0, to equal 2^7 because the exponential of all larger powers cannot
        // be represented as 18 fixed point decimal numbers in 256 bits, and are therefore larger than a.
        // At the end of this process we will have the sum of all x_n = ln(a_n) that apply, and the remainder of this
        // decomposition, which will be lower than the smallest a_n.
        // ln(a) = k_0 * x_0 + k_1 * x_1 + ... + k_n * x_n + ln(remainder), where each k_n equals either 0 or 1.
        // We mutate a by subtracting a_n, making it the remainder of the decomposition.

        // For reasons related to how `exp` works, the first two a_n (e^(2^7) and e^(2^6)) are not stored as fixed point
        // numbers with 18 decimals, but instead as plain integers with 0 decimals, so we need to multiply them by
        // ONE_18 to convert them to fixed point.
        // For each a_n, we test if that term is present in the decomposition (if a is larger than it), and if so divide
        // by it and compute the accumulated sum.

        int256 sum = 0;
        if (a >= a0 * ONE_18) {
            a /= a0; // Integer, not fixed point division
            sum += x0;
        }

        if (a >= a1 * ONE_18) {
            a /= a1; // Integer, not fixed point division
            sum += x1;
        }

        // All other a_n and x_n are stored as 20 digit fixed point numbers, so we convert the sum and a to this format.
        sum *= 100;
        a *= 100;

        // Because further a_n are  20 digit fixed point numbers, we multiply by ONE_20 when dividing by them.

        if (a >= a2) {
            a = (a * ONE_20) / a2;
            sum += x2;
        }

        if (a >= a3) {
            a = (a * ONE_20) / a3;
            sum += x3;
        }

        if (a >= a4) {
            a = (a * ONE_20) / a4;
            sum += x4;
        }

        if (a >= a5) {
            a = (a * ONE_20) / a5;
            sum += x5;
        }

        if (a >= a6) {
            a = (a * ONE_20) / a6;
            sum += x6;
        }

        if (a >= a7) {
            a = (a * ONE_20) / a7;
            sum += x7;
        }

        if (a >= a8) {
            a = (a * ONE_20) / a8;
            sum += x8;
        }

        if (a >= a9) {
            a = (a * ONE_20) / a9;
            sum += x9;
        }

        if (a >= a10) {
            a = (a * ONE_20) / a10;
            sum += x10;
        }

        if (a >= a11) {
            a = (a * ONE_20) / a11;
            sum += x11;
        }

        // a is now a small number (smaller than a_11, which roughly equals 1.06). This means we can use a Taylor series
        // that converges rapidly for values of `a` close to one - the same one used in ln_36.
        // Let z = (a - 1) / (a + 1).
        // ln(a) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))

        // Recall that 20 digit fixed point division requires multiplying by ONE_20, and multiplication requires
        // division by ONE_20.
        int256 z = ((a - ONE_20) * ONE_20) / (a + ONE_20);
        int256 z_squared = (z * z) / ONE_20;

        // num is the numerator of the series: the z^(2 * n + 1) term
        int256 num = z;

        // seriesSum holds the accumulated sum of each term in the series, starting with the initial z
        int256 seriesSum = num;

        // In each step, the numerator is multiplied by z^2
        num = (num * z_squared) / ONE_20;
        seriesSum += num / 3;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 5;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 7;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 9;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 11;

        // 6 Taylor terms are sufficient for 36 decimal precision.

        // Finally, we multiply by 2 (non fixed point) to compute ln(remainder)
        seriesSum *= 2;

        // We now have the sum of all x_n present, and the Taylor approximation of the logarithm of the remainder (both
        // with 20 decimals). All that remains is to sum these two, and then drop two digits to return a 18 decimal
        // value.

        return (sum + seriesSum) / 100;
    }

    /**
     * @dev Intrnal high precision (36 decimal places) natural logarithm (ln(x)) with signed 18 decimal fixed point argument,
     * for x close to one.
     *
     * Should only be used if x is between LN_36_LOWER_BOUND and LN_36_UPPER_BOUND.
     */
    function _ln_36(int256 x) private pure returns (int256) {
        // Since ln(1) = 0, a value of x close to one will yield a very small result, which makes using 36 digits
        // worthwhile.

        // First, we transform x to a 36 digit fixed point value.
        x *= ONE_18;

        // We will use the following Taylor expansion, which converges very rapidly. Let z = (x - 1) / (x + 1).
        // ln(x) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))

        // Recall that 36 digit fixed point division requires multiplying by ONE_36, and multiplication requires
        // division by ONE_36.
        int256 z = ((x - ONE_36) * ONE_36) / (x + ONE_36);
        int256 z_squared = (z * z) / ONE_36;

        // num is the numerator of the series: the z^(2 * n + 1) term
        int256 num = z;

        // seriesSum holds the accumulated sum of each term in the series, starting with the initial z
        int256 seriesSum = num;

        // In each step, the numerator is multiplied by z^2
        num = (num * z_squared) / ONE_36;
        seriesSum += num / 3;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 5;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 7;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 9;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 11;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 13;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 15;

        // 8 Taylor terms are sufficient for 36 decimal precision.

        // All that remains is multiplying by 2 (non fixed point).
        return seriesSum * 2;
    }
}

File 11 of 14 : Math.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow checks.
 * Adapted from OpenZeppelin's SafeMath library.
 */
library BMath {
    // solhint-disable no-inline-assembly

    /**
     * @dev Returns the absolute value of a signed integer.
     */
    function abs(int256 a) internal pure returns (uint256 result) {
        // Equivalent to:
        // result = a > 0 ? uint256(a) : uint256(-a)
        assembly {
            let s := sar(255, a)
            result := sub(xor(a, s), s)
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers of 256 bits, reverting on overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "ADD_OVERFLOW");
        return c;
    }

    /**
     * @dev Returns the addition of two signed integers, reverting on overflow.
     */
    function add(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a + b;
        require((b >= 0 && c >= a) || (b < 0 && c < a), "ADD_OVERFLOW");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers of 256 bits, reverting on overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SUB_OVERFLOW");
        uint256 c = a - b;
        return c;
    }

    /**
     * @dev Returns the subtraction of two signed integers, reverting on overflow.
     */
    function sub(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a - b;
        require((b >= 0 && c <= a) || (b < 0 && c > a), "SUB_OVERFLOW");
        return c;
    }

    /**
     * @dev Returns the largest of two numbers of 256 bits.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256 result) {
        // Equivalent to:
        // result = (a < b) ? b : a;
        assembly {
            result := sub(a, mul(sub(a, b), lt(a, b)))
        }
    }

    /**
     * @dev Returns the smallest of two numbers of 256 bits.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256 result) {
        // Equivalent to `result = (a < b) ? a : b`
        assembly {
            result := sub(a, mul(sub(a, b), gt(a, b)))
        }
    }

    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a * b;
        require(a == 0 || c / a == b, "MUL_OVERFLOW");
        return c;
    }

    function div(
        uint256 a,
        uint256 b,
        bool roundUp
    ) internal pure returns (uint256) {
        return roundUp ? divUp(a, b) : divDown(a, b);
    }

    function divDown(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "ZERO_DIVISION");
        return a / b;
    }

    function divUp(uint256 a, uint256 b) internal pure returns (uint256 result) {
        require(b != 0, "ZERO_DIVISION");

        // Equivalent to:
        // result = a == 0 ? 0 : 1 + (a - 1) / b;
        assembly {
            result := mul(iszero(iszero(a)), add(1, div(sub(a, 1), b)))
        }
    }
}

File 12 of 14 : StableMath.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

import "./FixedPoint.sol";
import "./Math.sol";

library StableMath {
    using FixedPoint for uint256;

    uint256 internal constant _MIN_AMP = 1;
    uint256 internal constant _MAX_AMP = 5000;
    uint256 internal constant _AMP_PRECISION = 1e3;

    uint256 internal constant _MAX_STABLE_TOKENS = 5;

    function _calculateInvariant(uint256 amplificationParameter, uint256[] memory balances)
        internal
        pure
        returns (uint256)
    {
        uint256 sum = 0; // S in the Curve version
        uint256 numTokens = balances.length;
        for (uint256 i = 0; i < numTokens; i++) {
            sum = sum.add(balances[i]);
        }
        if (sum == 0) {
            return 0;
        }

        uint256 prevInvariant; // Dprev in the Curve version
        uint256 invariant = sum; // D in the Curve version
        uint256 ampTimesTotal = amplificationParameter * numTokens; // Ann in the Curve version

        for (uint256 i = 0; i < 255; i++) {
            uint256 D_P = invariant;

            for (uint256 j = 0; j < numTokens; j++) {
                // (D_P * invariant) / (balances[j] * numTokens)
                D_P = BMath.divDown(BMath.mul(D_P, invariant), BMath.mul(balances[j], numTokens));
            }

            prevInvariant = invariant;

            invariant = BMath.divDown(
                BMath.mul(
                    // (ampTimesTotal * sum) / AMP_PRECISION + D_P * numTokens
                    (BMath.divDown(BMath.mul(ampTimesTotal, sum), _AMP_PRECISION).add(BMath.mul(D_P, numTokens))),
                    invariant
                ),
                // ((ampTimesTotal - _AMP_PRECISION) * invariant) / _AMP_PRECISION + (numTokens + 1) * D_P
                (
                    BMath.divDown(BMath.mul((ampTimesTotal - _AMP_PRECISION), invariant), _AMP_PRECISION).add(
                        BMath.mul((numTokens + 1), D_P)
                    )
                )
            );

            if (invariant > prevInvariant) {
                if (invariant - prevInvariant <= 1) {
                    return invariant;
                }
            } else if (prevInvariant - invariant <= 1) {
                return invariant;
            }
        }

        revert("STABLE_INVARIANT_DIDNT_CONVERGE");
    }

    function _calcOutGivenIn(
        uint256 amplificationParameter,
        uint256[] memory balances,
        uint256 tokenIndexIn,
        uint256 tokenIndexOut,
        uint256 tokenAmountIn,
        uint256 invariant
    ) internal pure returns (uint256) {

        balances[tokenIndexIn] = balances[tokenIndexIn].add(tokenAmountIn);

        uint256 finalBalanceOut = _getTokenBalanceGivenInvariantAndAllOtherBalances(
            amplificationParameter,
            balances,
            invariant,
            tokenIndexOut
        );

        balances[tokenIndexIn] = balances[tokenIndexIn] - tokenAmountIn;

        return balances[tokenIndexOut].sub(finalBalanceOut).sub(1);
    }

    function _calcInGivenOut(
        uint256 amplificationParameter,
        uint256[] memory balances,
        uint256 tokenIndexIn,
        uint256 tokenIndexOut,
        uint256 tokenAmountOut,
        uint256 invariant
    ) internal pure returns (uint256) {

        balances[tokenIndexOut] = balances[tokenIndexOut].sub(tokenAmountOut);

        uint256 finalBalanceIn = _getTokenBalanceGivenInvariantAndAllOtherBalances(
            amplificationParameter,
            balances,
            invariant,
            tokenIndexIn
        );

        balances[tokenIndexOut] = balances[tokenIndexOut] + tokenAmountOut;

        return finalBalanceIn.sub(balances[tokenIndexIn]).add(1);
    }

    function _calcBptOutGivenExactTokensIn(
        uint256 amp,
        uint256[] memory balances,
        uint256[] memory amountsIn,
        uint256 bptTotalSupply,
        uint256 currentInvariant,
        uint256 swapFeePercentage
    ) internal pure returns (uint256) {
        uint256 sumBalances = 0;
        for (uint256 i = 0; i < balances.length; i++) {
            sumBalances = sumBalances.add(balances[i]);
        }

        // Calculate the weighted balance ratio without considering fees
        uint256[] memory balanceRatiosWithFee = new uint256[](amountsIn.length);
        // The weighted sum of token balance ratios with fee
        uint256 invariantRatioWithFees = 0;
        for (uint256 i = 0; i < balances.length; i++) {
            uint256 currentWeight = balances[i].divDown(sumBalances);
            balanceRatiosWithFee[i] = balances[i].add(amountsIn[i]).divDown(balances[i]);
            invariantRatioWithFees = invariantRatioWithFees.add(balanceRatiosWithFee[i].mulDown(currentWeight));
        }

        // Second loop calculates new amounts in, taking into account the fee on the percentage excess
        uint256[] memory newBalances = new uint256[](balances.length);
        for (uint256 i = 0; i < balances.length; i++) {
            uint256 amountInWithoutFee;

            // Check if the balance ratio is greater than the ideal ratio to charge fees or not
            if (balanceRatiosWithFee[i] > invariantRatioWithFees) {
                uint256 nonTaxableAmount = balances[i].mulDown(invariantRatioWithFees.sub(FixedPoint.ONE));
                uint256 taxableAmount = amountsIn[i].sub(nonTaxableAmount);
                // No need to use checked arithmetic for the swap fee, it is guaranteed to be lower than 50%
                amountInWithoutFee = nonTaxableAmount.add(taxableAmount.mulDown(FixedPoint.ONE - swapFeePercentage));
            } else {
                amountInWithoutFee = amountsIn[i];
            }

            newBalances[i] = balances[i].add(amountInWithoutFee);
        }

        uint256 newInvariant = _calculateInvariant(amp, newBalances);
        uint256 invariantRatio = newInvariant.divDown(currentInvariant);

        // If the invariant didn't increase for any reason, we simply don't mint BPT
        if (invariantRatio > FixedPoint.ONE) {
            return bptTotalSupply.mulDown(invariantRatio - FixedPoint.ONE);
        } else {
            return 0;
        }
    }

    function _calcTokenInGivenExactBptOut(
        uint256 amp,
        uint256[] memory balances,
        uint256 tokenIndex,
        uint256 bptAmountOut,
        uint256 bptTotalSupply,
        uint256 currentInvariant,
        uint256 swapFeePercentage
    ) internal pure returns (uint256) {
        // Token in, so we round up overall.

        uint256 newInvariant = bptTotalSupply.add(bptAmountOut).divUp(bptTotalSupply).mulUp(currentInvariant);

        // Calculate amount in without fee.
        uint256 newBalanceTokenIndex = _getTokenBalanceGivenInvariantAndAllOtherBalances(
            amp,
            balances,
            newInvariant,
            tokenIndex
        );
        uint256 amountInWithoutFee = newBalanceTokenIndex.sub(balances[tokenIndex]);

        // First calculate the sum of all token balances, which will be used to calculate
        // the current weight of each token
        uint256 sumBalances = 0;
        for (uint256 i = 0; i < balances.length; i++) {
            sumBalances = sumBalances.add(balances[i]);
        }

        // We can now compute how much extra balance is being deposited and used in virtual swaps, and charge swap fees
        // accordingly.
        uint256 currentWeight = balances[tokenIndex].divDown(sumBalances);
        uint256 taxablePercentage = currentWeight.complement();
        uint256 taxableAmount = amountInWithoutFee.mulUp(taxablePercentage);
        uint256 nonTaxableAmount = amountInWithoutFee.sub(taxableAmount);

        // No need to use checked arithmetic for the swap fee, it is guaranteed to be lower than 50%
        return nonTaxableAmount.add(taxableAmount.divUp(FixedPoint.ONE - swapFeePercentage));
    }

    /*
    Flow of calculations:
    amountsTokenOut -> amountsOutProportional ->
    amountOutPercentageExcess -> amountOutBeforeFee -> newInvariant -> amountBPTIn
    */
    function _calcBptInGivenExactTokensOut(
        uint256 amp,
        uint256[] memory balances,
        uint256[] memory amountsOut,
        uint256 bptTotalSupply,
        uint256 currentInvariant,
        uint256 swapFeePercentage
    ) internal pure returns (uint256) {
        // BPT in, so we round up overall.

        // First loop calculates the sum of all token balances, which will be used to calculate
        // the current weights of each token relative to this sum
        uint256 sumBalances = 0;
        for (uint256 i = 0; i < balances.length; i++) {
            sumBalances = sumBalances.add(balances[i]);
        }

        // Calculate the weighted balance ratio without considering fees
        uint256[] memory balanceRatiosWithoutFee = new uint256[](amountsOut.length);
        uint256 invariantRatioWithoutFees = 0;
        for (uint256 i = 0; i < balances.length; i++) {
            uint256 currentWeight = balances[i].divUp(sumBalances);
            balanceRatiosWithoutFee[i] = balances[i].sub(amountsOut[i]).divUp(balances[i]);
            invariantRatioWithoutFees = invariantRatioWithoutFees.add(balanceRatiosWithoutFee[i].mulUp(currentWeight));
        }

        // Second loop calculates new amounts in, taking into account the fee on the percentage excess
        uint256[] memory newBalances = new uint256[](balances.length);
        for (uint256 i = 0; i < balances.length; i++) {
            // Swap fees are typically charged on 'token in', but there is no 'token in' here, so we apply it to
            // 'token out'. This results in slightly larger price impact.

            uint256 amountOutWithFee;
            if (invariantRatioWithoutFees > balanceRatiosWithoutFee[i]) {
                uint256 nonTaxableAmount = balances[i].mulDown(invariantRatioWithoutFees.complement());
                uint256 taxableAmount = amountsOut[i].sub(nonTaxableAmount);
                // No need to use checked arithmetic for the swap fee, it is guaranteed to be lower than 50%
                amountOutWithFee = nonTaxableAmount.add(taxableAmount.divUp(FixedPoint.ONE - swapFeePercentage));
            } else {
                amountOutWithFee = amountsOut[i];
            }

            newBalances[i] = balances[i].sub(amountOutWithFee);
        }

        uint256 newInvariant = _calculateInvariant(amp, newBalances);
        uint256 invariantRatio = newInvariant.divDown(currentInvariant);

        // return amountBPTIn
        return bptTotalSupply.mulUp(invariantRatio.complement());
    }

    function _calcTokenOutGivenExactBptIn(
        uint256 amp,
        uint256[] memory balances,
        uint256 tokenIndex,
        uint256 bptAmountIn,
        uint256 bptTotalSupply,
        uint256 currentInvariant,
        uint256 swapFeePercentage
    ) internal pure returns (uint256) {
        // Token out, so we round down overall.

        uint256 newInvariant = bptTotalSupply.sub(bptAmountIn).divUp(bptTotalSupply).mulUp(currentInvariant);

        // Calculate amount out without fee
        uint256 newBalanceTokenIndex = _getTokenBalanceGivenInvariantAndAllOtherBalances(
            amp,
            balances,
            newInvariant,
            tokenIndex
        );
        uint256 amountOutWithoutFee = balances[tokenIndex].sub(newBalanceTokenIndex);

        // First calculate the sum of all token balances, which will be used to calculate
        // the current weight of each token
        uint256 sumBalances = 0;
        for (uint256 i = 0; i < balances.length; i++) {
            sumBalances = sumBalances.add(balances[i]);
        }

        // We can now compute how much excess balance is being withdrawn as a result of the virtual swaps, which result
        // in swap fees.
        uint256 currentWeight = balances[tokenIndex].divDown(sumBalances);
        uint256 taxablePercentage = currentWeight.complement();

        // Swap fees are typically charged on 'token in', but there is no 'token in' here, so we apply it
        // to 'token out'. This results in slightly larger price impact. Fees are rounded up.
        uint256 taxableAmount = amountOutWithoutFee.mulUp(taxablePercentage);
        uint256 nonTaxableAmount = amountOutWithoutFee.sub(taxableAmount);

        // No need to use checked arithmetic for the swap fee, it is guaranteed to be lower than 50%
        return nonTaxableAmount.add(taxableAmount.mulDown(FixedPoint.ONE - swapFeePercentage));
    }

    // This function calculates the balance of a given token (tokenIndex)
    // given all the other balances and the invariant
    function _getTokenBalanceGivenInvariantAndAllOtherBalances(
        uint256 amplificationParameter,
        uint256[] memory balances,
        uint256 invariant,
        uint256 tokenIndex
    ) internal pure returns (uint256) {
        // Rounds result up overall

        uint256 ampTimesTotal = amplificationParameter * balances.length;
        uint256 sum = balances[0];
        uint256 P_D = balances[0] * balances.length;
        for (uint256 j = 1; j < balances.length; j++) {
            P_D = BMath.divDown(BMath.mul(BMath.mul(P_D, balances[j]), balances.length), invariant);
            sum = sum.add(balances[j]);
        }
        // No need to use safe Bmath, based on the loop above `sum` is greater than or equal to `balances[tokenIndex]`
        sum = sum - balances[tokenIndex];

        uint256 inv2 = BMath.mul(invariant, invariant);
        // We remove the balance from c by multiplying it
        uint256 c = BMath.mul(
            BMath.mul(BMath.divUp(inv2, BMath.mul(ampTimesTotal, P_D)), _AMP_PRECISION),
            balances[tokenIndex]
        );
        uint256 b = sum.add(BMath.mul(BMath.divDown(invariant, ampTimesTotal), _AMP_PRECISION));

        // We iterate to find the balance
        uint256 prevTokenBalance = 0;
        // We multiply the first iteration outside the loop with the invariant to set the value of the
        // initial approximation.
        uint256 tokenBalance = BMath.divUp(inv2.add(c), invariant.add(b));

        for (uint256 i = 0; i < 255; i++) {
            prevTokenBalance = tokenBalance;

            tokenBalance = BMath.divUp(
                BMath.mul(tokenBalance, tokenBalance).add(c),
                BMath.mul(tokenBalance, 2).add(b).sub(invariant)
            );

            if (tokenBalance > prevTokenBalance) {
                if (tokenBalance - prevTokenBalance <= 1) {
                    return tokenBalance;
                }
            } else if (prevTokenBalance - tokenBalance <= 1) {
                return tokenBalance;
            }
        }

        revert("STABLE_GET_BALANCE_DIDNT_CONVERGE");
    }
}

File 13 of 14 : Chainlink.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

interface IPriceFeed {
    function latestAnswer() external view returns (int256);

    function latestTimestamp() external view returns (uint256);

    function latestRound() external view returns (uint256);

    function getAnswer(uint256 roundId) external view returns (int256);

    function getTimestamp(uint256 roundId) external view returns (uint256);

    function decimals() external view returns (uint8);

    function description() external view returns (string memory);

    function version() external view returns (uint256);

    function getRoundData(
        uint80 _roundId
    )
        external
        view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        );

    function latestRoundData()
        external
        view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        );
}

library ChainlinkLibrary {
    uint8 constant USD_DECIMALS = 6;

    function getDecimals(IPriceFeed oracle) internal view returns (uint8) {
        return oracle.decimals();
    }

    function getPrice(IPriceFeed oracle) internal view returns (uint256) {
        (
            uint80 roundID,
            int256 price,
            ,
            uint256 timeStamp,
            uint80 answeredInRound
        ) = oracle.latestRoundData();
        require(answeredInRound >= roundID, "Old data");
        require(timeStamp > 0, "Round not complete");

        return uint256(price);
    }

    function getPrice(
        IPriceFeed oracle,
        IPriceFeed sequencerOracle,
        uint256 frequency
    ) internal view returns (uint256) {
        if (address(sequencerOracle) != address(0))
            checkUptime(sequencerOracle);

        (uint256 roundId, int256 price, , uint256 updatedAt, ) = oracle
            .latestRoundData();
        require(price > 0 && roundId != 0 && updatedAt != 0, "Invalid Price");
        if (frequency > 0)
            require(block.timestamp - updatedAt <= frequency, "Stale Price");

        return uint256(price);
    }

    function checkUptime(IPriceFeed sequencerOracle) internal view {
        (, int256 answer, uint256 startedAt, , ) = sequencerOracle
            .latestRoundData();
        require(answer <= 0, "Sequencer Down"); // 0: Sequencer is up, 1: Sequencer is down
        require(block.timestamp - startedAt > 1 hours, "Grace Period Not Over");
    }

    function convertTokenToToken(
        uint256 amount0,
        uint8 token0Decimals,
        uint8 token1Decimals,
        IPriceFeed oracle0,
        IPriceFeed oracle1
    ) internal view returns (uint256 amount1) {
        uint256 price0 = getPrice(oracle0);
        uint256 price1 = getPrice(oracle1);
        amount1 =
            (amount0 * price0 * (10 ** token1Decimals)) /
            (price1 * (10 ** token0Decimals));
    }

    function convertTokenToUsd(
        uint256 amount,
        uint8 tokenDecimals,
        IPriceFeed oracle
    ) internal view returns (uint256 amountUsd) {
        uint8 decimals = getDecimals(oracle);
        uint256 price = getPrice(oracle);

        amountUsd =
            (amount * price * (10 ** USD_DECIMALS)) /
            10 ** (decimals + tokenDecimals);
    }

    function convertUsdToToken(
        uint256 amountUsd,
        uint256 tokenDecimals,
        IPriceFeed oracle
    ) internal view returns (uint256 amount) {
        uint8 decimals = getDecimals(oracle);
        uint256 price = getPrice(oracle);

        amount =
            (amountUsd * 10 ** (decimals + tokenDecimals)) /
            (price * (10 ** USD_DECIMALS));
    }
}

File 14 of 14 : ISweep.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

interface ISweep {
    struct Minter {
        uint256 maxAmount;
        uint256 mintedAmount;
        bool isListed;
        bool isEnabled;
    }

    function isMintingAllowed() external view returns (bool);

    function DEFAULT_ADMIN_ADDRESS() external view returns (address);

    function balancer() external view returns (address);

    function treasury() external view returns (address);

    function allowance(
        address holder,
        address spender
    ) external view returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    function balanceOf(address account) external view returns (uint256);

    function decimals() external view returns (uint8);

    function decreaseAllowance(
        address spender,
        uint256 subtractedValue
    ) external returns (bool);

    function isValidMinter(address) external view returns (bool);

    function amm() external view returns (address);

    function ammPrice() external view returns (uint256);

    function twaPrice() external view returns (uint256);

    function increaseAllowance(
        address spender,
        uint256 addedValue
    ) external returns (bool);

    function name() external view returns (string memory);

    function owner() external view returns (address);

    function fastMultisig() external view returns (address);

    function burn(uint256 amount) external;

    function mint(uint256 amount) external;

    function minters(address minterAaddress) external returns (Minter memory);

    function minterAddresses(uint256 index) external view returns (address);

    function getMinters() external view returns (address[] memory);

    function targetPrice() external view returns (uint256);

    function interestRate() external view returns (int256);

    function periodStart() external view returns (uint256);

    function stepValue() external view returns (int256);

    function arbSpread() external view returns (uint256);

    function refreshInterestRate(int256 newInterestRate, uint256 newPeriodStart) external;

    function setTargetPrice(
        uint256 currentTargetPrice,
        uint256 nextTargetPrice
    ) external;

    function setInterestRate(
        int256 currentInterestRate,
        int256 nextInterestRate
    ) external;

    function setPeriodStart(
        uint256 currentPeriodStart,
        uint256 nextPeriodStart
    ) external;

    function startNewPeriod() external;

    function symbol() external view returns (string memory);

    function totalSupply() external view returns (uint256);

    function convertToUSD(uint256 amount) external view returns (uint256);

    function convertToSWEEP(uint256 amount) external view returns (uint256);

    function transfer(
        address recipient,
        uint256 amount
    ) external returns (bool);

    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_sweep","type":"address"},{"internalType":"address","name":"_base","type":"address"},{"internalType":"address","name":"_sequencer","type":"address"},{"internalType":"address","name":"_oracleBase","type":"address"},{"internalType":"uint256","name":"_oracleBaseUpdateFrequency","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadRate","type":"error"},{"inputs":[],"name":"NotOwnerOrGov","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"usdxAmount","type":"uint256"}],"name":"Bought","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"name":"Sold","type":"event"},{"inputs":[],"name":"base","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"usdxAddress","type":"address"},{"internalType":"uint256","name":"usdxAmount","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"buySweep","outputs":[{"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getPositions","outputs":[{"internalType":"uint256","name":"usdxAmount","type":"uint256"},{"internalType":"uint256","name":"sweepAmount","type":"uint256"},{"internalType":"uint256","name":"lp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPrice","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRate","outputs":[{"internalType":"uint256","name":"rate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTWAPrice","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketMaker","outputs":[{"internalType":"contract IMarketMaker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleBase","outputs":[{"internalType":"contract IPriceFeed","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleBaseUpdateFrequency","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pool","outputs":[{"internalType":"contract IBalancerPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"usdxAddress","type":"address"},{"internalType":"uint256","name":"sweepAmount","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"sellSweep","outputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sequencer","outputs":[{"internalType":"contract IPriceFeed","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_marketMaker","type":"address"}],"name":"setMarketMaker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"poolAddress","type":"address"}],"name":"setPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"","type":"uint24"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"swapExactInput","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sweep","outputs":[{"internalType":"contract ISweep","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract IBalancerVault","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

6101206040523480156200001257600080fd5b5060405162002ad138038062002ad183398101604081905262000035916200007b565b6001600160a01b0394851660a052928416608052831660c05290911660e05261010052620000e2565b80516001600160a01b03811681146200007657600080fd5b919050565b600080600080600060a086880312156200009457600080fd5b6200009f866200005e565b9450620000af602087016200005e565b9350620000bf604087016200005e565b9250620000cf606087016200005e565b9150608086015190509295509295909350565b60805160a05160c05160e0516101005161291e620001b3600039600081816102680152610ecf0152600081816102390152610eae0152600081816101e301528181610e600152610e8d0152600081816101860152818161047f0152818161057a015281816105b8015281816106d20152818161091101528181610952015281816109aa01528181610d2a01528181610f910152818161102f015261125001526000818161020a015281816104510152818161083c0152818161086c01528181610a300152610d58015261291e6000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c806359879099116100a25780638c60c71c116100715780638c60c71c1461028a57806398d5fdca1461029d578063eda28b11146102a5578063f54c42d7146102b8578063fbfa77cf146102cb57600080fd5b8063598790991461022c5780635c1bba3814610234578063679aefce1461025b57806375cdf6491461026357600080fd5b806338da412e116100de57806338da412e146101a85780634437152a146101c95780634562aee3146101de5780635001f3b51461020557600080fd5b806316f0115b146101105780631f21f9af1461014057806330e005961461015357806335faa41614610181575b600080fd5b600154610123906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b600254610123906001600160a01b031681565b6101666101613660046121b9565b6102de565b60408051938452602084019290925290820152606001610137565b6101237f000000000000000000000000000000000000000000000000000000000000000081565b6101bb6101b63660046121ea565b61052b565b604051908152602001610137565b6101dc6101d736600461221f565b6105b6565b005b6101237f000000000000000000000000000000000000000000000000000000000000000081565b6101237f000000000000000000000000000000000000000000000000000000000000000081565b6101bb6106bf565b6101237f000000000000000000000000000000000000000000000000000000000000000081565b6101bb6106ce565b6101bb7f000000000000000000000000000000000000000000000000000000000000000081565b6101bb6102983660046121ea565b610761565b6101bb61098b565b6101bb6102b336600461223c565b610f65565b6101dc6102c636600461221f565b610f8f565b600054610123906001600160a01b031681565b6000806000806000600160009054906101000a90046001600160a01b03166001600160a01b0316638d928af86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610339573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061035d919061229f565b6001600160a01b031663f94d4668600160009054906101000a90046001600160a01b03166001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e291906122bc565b6040518263ffffffff1660e01b815260040161040091815260200190565b600060405180830381865afa15801561041d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261044591908101906123ab565b509150915060006104767f000000000000000000000000000000000000000000000000000000000000000084611105565b905060006104a47f000000000000000000000000000000000000000000000000000000000000000085611105565b6001549091506000906104c0906001600160a01b031686611105565b9050838360ff16815181106104d7576104d7612479565b60200260200101519750838260ff16815181106104f6576104f6612479565b60200260200101519650838160ff168151811061051557610515612479565b6020026020010151955050505050509193909250565b60007f92f64ca637d023f354075a4be751b169c1a8a9ccb6d33cdd0cb35205439957278360405161055e91815260200190565b60405180910390a16105718483856111b2565b6001546105ae907f0000000000000000000000000000000000000000000000000000000000000000908690869086906001600160a01b0316611345565b949350505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610614573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610638919061229f565b6001600160a01b0316336001600160a01b03161461069d5760405162461bcd60e51b815260206004820152601b60248201527f42616c616e636572414d4d3a204e6f7420476f7665726e616e6365000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60006106c961098b565b905090565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dc38679c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561072e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075291906122bc565b6106c99064e8d4a510006124a5565b60007f4e08ba899977cf7d4c2964bce71c6b9a7ef76ee5166a4c1249a1e08016e33ef18360405161079491815260200190565b60405180910390a16002546001600160a01b03161580159061083257506107b961098b565b600260009054906101000a90046001600160a01b03166001600160a01b031663018a25e86040518163ffffffff1660e01b8152600401602060405180830381865afa15801561080c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061083091906122bc565b105b1561093c576108637f0000000000000000000000000000000000000000000000000000000000000000333086611559565b60025461089b907f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b03168561165b565b6002546040516369ae990b60e01b8152600481018590526001600160a01b03909116906369ae990b906024016020604051808303816000875af11580156108e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090a91906122bc565b90506109377f0000000000000000000000000000000000000000000000000000000000000000338361175b565b610984565b6109478484846111b2565b6001546105ae9085907f000000000000000000000000000000000000000000000000000000000000000090869086906001600160a01b0316611345565b9392505050565b6001546000906001600160a01b03166109a65750621e848090565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2a91906124bc565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab091906124bc565b90506000610abe82846124df565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316631dd746ea6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610b15573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b3d91908101906124f8565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316636daccffa6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610b94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb89190612542565b50509050600080600160009054906101000a90046001600160a01b03166001600160a01b0316638d928af86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c36919061229f565b6001600160a01b031663f94d4668600160009054906101000a90046001600160a01b03166001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cbb91906122bc565b6040518263ffffffff1660e01b8152600401610cd991815260200190565b600060405180830381865afa158015610cf6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d1e91908101906123ab565b50915091506000610d4f7f000000000000000000000000000000000000000000000000000000000000000084611105565b90506000610d7d7f000000000000000000000000000000000000000000000000000000000000000085611105565b6040805160028082526060820183529293506000929091602083019080368337019050509050838360ff1681518110610db857610db8612479565b602002602001015181600081518110610dd357610dd3612479565b6020908102919091010152610de988600a61265b565b848360ff1681518110610dfe57610dfe612479565b6020026020010151610e1091906124a5565b81600181518110610e2357610e23612479565b6020026020010181815250506000610e3b8783611854565b90506000610e57888460006001670de0b6b3a764000087611a3c565b90506000610e847f0000000000000000000000000000000000000000000000000000000000000000611b1e565b90506000610ef37f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000611b82565b90508b610f008f8461266a565b610f0a919061266a565b610f1590600a61265b565b818c8960ff1681518110610f2b57610f2b612479565b602002602001015185610f3e91906124a5565b610f4891906124a5565b610f529190612683565b9e50505050505050505050505050505090565b600154600090610f859087908790869086906001600160a01b0316611345565b9695505050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663baf4a3126040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611011919061229f565b6001600160a01b0316336001600160a01b0316141580156110c557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561108b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110af919061229f565b6001600160a01b0316336001600160a01b031614155b156110e3576040516338ae11af60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000805b82518160ff16101561116357836001600160a01b0316838260ff168151811061113457611134612479565b60200260200101516001600160a01b0316036111515790506111ac565b8061115b816126a5565b915050611109565b5060405162461bcd60e51b815260206004820152601c60248201527f42616c616e636572414d4d3a204173736574206e6f7420666f756e64000000006044820152606401610694565b92915050565b8115806111bd575080155b156111db57604051631f2a200560e01b815260040160405180910390fd5b6000836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561121b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123f91906124bc565b61124a90600a61265b565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d091906124bc565b6112db90600a61265b565b905060006112e984846124a5565b6112f383876124a5565b61130090620f42406124a5565b61130a9190612683565b905062186a0081118061131f5750620927c081105b1561133d5760405163491dee2160e01b815260040160405180910390fd5b505050505050565b600080826001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611386573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113aa91906122bc565b90506000836001600160a01b0316638d928af86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611410919061229f565b905061141e88333089611559565b61142988828861165b565b606060006040518060c0016040528085815260200160006001811115611451576114516126c4565b81526020018b6001600160a01b031681526020018a6001600160a01b0316815260200189815260200183815250905060006040518060800160405280306001600160a01b03168152602001600015158152602001336001600160a01b03168152602001600015158152509050600061038461ffff16426114d191906126da565b6040516352bbbe2960e01b81529091506001600160a01b038616906352bbbe299061150690869086908e90879060040161273d565b6020604051808303816000875af1158015611525573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154991906122bc565b9c9b505050505050505050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916115bd919061281b565b6000604051808303816000865af19150503d80600081146115fa576040519150601f19603f3d011682016040523d82523d6000602084013e6115ff565b606091505b50915091508180156116295750805115806116295750808060200190518101906116299190612837565b61133d5760405162461bcd60e51b815260206004820152600360248201526229aa2360e91b6044820152606401610694565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b17905291516000928392908716916116b7919061281b565b6000604051808303816000865af19150503d80600081146116f4576040519150601f19603f3d011682016040523d82523d6000602084013e6116f9565b606091505b50915091508180156117235750805115806117235750808060200190518101906117239190612837565b6117545760405162461bcd60e51b8152602060048201526002602482015261534160f01b6044820152606401610694565b5050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916117b7919061281b565b6000604051808303816000865af19150503d80600081146117f4576040519150601f19603f3d011682016040523d82523d6000602084013e6117f9565b606091505b50915091508180156118235750805115806118235750808060200190518101906118239190612837565b6117545760405162461bcd60e51b815260206004820152600260248201526114d560f21b6044820152606401610694565b80516000908190815b818110156118a55761189185828151811061187a5761187a612479565b602002602001015184611cc490919063ffffffff16565b92508061189d81612852565b91505061185d565b50816000036118b9576000925050506111ac565b600082816118c784896124a5565b905060005b60ff8110156119f3578260005b8681101561192a576119166118ee8387611d12565b6119118c848151811061190357611903612479565b60200260200101518a611d12565b611d71565b91508061192281612852565b9150506118d9565b5083945061199161196261195c611941848a611d12565b61195661194e888d611d12565b6103e8611d71565b90611cc4565b86611d12565b6119116119796119738a60016126da565b85611d12565b61195661194e61198b6103e88a61286b565b8a611d12565b9350848411156119c05760016119a7868661286b565b116119bb57839750505050505050506111ac565b6119e0565b60016119cc858761286b565b116119e057839750505050505050506111ac565b50806119eb81612852565b9150506118cc565b5060405162461bcd60e51b815260206004820152601f60248201527f535441424c455f494e56415249414e545f4449444e545f434f4e5645524745006044820152606401610694565b6000611a6a83878781518110611a5457611a54612479565b6020026020010151611cc490919063ffffffff16565b868681518110611a7c57611a7c612479565b6020026020010181815250506000611a9688888588611dbd565b905083878781518110611aab57611aab612479565b6020026020010151611abd919061286b565b878781518110611acf57611acf612479565b602002602001018181525050611b126001611b0c838a8981518110611af657611af6612479565b602002602001015161201390919063ffffffff16565b90612013565b98975050505050505050565b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b5e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ac91906124bc565b60006001600160a01b03831615611b9c57611b9c83612060565b6000806000866001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611bdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c039190612898565b50935050925069ffffffffffffffffffff169250600082138015611c2657508215155b8015611c3157508015155b611c6d5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420507269636560981b6044820152606401610694565b8415611cba5784611c7e824261286b565b1115611cba5760405162461bcd60e51b815260206004820152600b60248201526a5374616c6520507269636560a81b6044820152606401610694565b5095945050505050565b600080611cd183856126da565b9050838110156109845760405162461bcd60e51b815260206004820152600c60248201526b4144445f4f564552464c4f5760a01b6044820152606401610694565b600080611d1f83856124a5565b9050831580611d36575082611d348583612683565b145b6109845760405162461bcd60e51b815260206004820152600c60248201526b4d554c5f4f564552464c4f5760a01b6044820152606401610694565b600081600003611db35760405162461bcd60e51b815260206004820152600d60248201526c2d22a927afa224ab24a9a4a7a760991b6044820152606401610694565b6109848284612683565b600080845186611dcd91906124a5565b9050600085600081518110611de457611de4612479565b602002602001015190506000865187600081518110611e0557611e05612479565b6020026020010151611e1791906124a5565b905060015b8751811015611e8657611e5b611e55611e4e848b8581518110611e4157611e41612479565b6020026020010151611d12565b8a51611d12565b88611d71565b9150611e7288828151811061187a5761187a612479565b925080611e7e81612852565b915050611e1c565b50868581518110611e9957611e99612479565b602002602001015182611eac919061286b565b91506000611eba8788611d12565b90506000611ef1611edf611ed784611ed28988611d12565b612165565b6103e8611d12565b8a8981518110611e4157611e41612479565b90506000611f0c611f05611ed78b89611d71565b8690611cc4565b9050600080611f28611f1e8686611cc4565b611ed28d86611cc4565b905060005b60ff811015611fc057819250611f5d611f4a866119568586611d12565b611ed28e611b0c88611956886002611d12565b915082821115611f8d576001611f73848461286b565b11611f88575097506105ae9650505050505050565b611fae565b6001611f99838561286b565b11611fae575097506105ae9650505050505050565b80611fb881612852565b915050611f2d565b5060405162461bcd60e51b815260206004820152602160248201527f535441424c455f4745545f42414c414e43455f4449444e545f434f4e564552476044820152604560f81b6064820152608401610694565b6000828211156120545760405162461bcd60e51b815260206004820152600c60248201526b5355425f4f564552464c4f5760a01b6044820152606401610694565b60006105ae838561286b565b600080826001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156120a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c59190612898565b50509250925050600082131561210e5760405162461bcd60e51b815260206004820152600e60248201526d29b2b8bab2b731b2b9102237bbb760911b6044820152606401610694565b610e1061211b824261286b565b116121605760405162461bcd60e51b815260206004820152601560248201527423b930b1b2902832b934b7b2102737ba1027bb32b960591b6044820152606401610694565b505050565b6000816000036121a75760405162461bcd60e51b815260206004820152600d60248201526c2d22a927afa224ab24a9a4a7a760991b6044820152606401610694565b50811515600019909201046001010290565b6000602082840312156121cb57600080fd5b5035919050565b6001600160a01b03811681146121e757600080fd5b50565b6000806000606084860312156121ff57600080fd5b833561220a816121d2565b95602085013595506040909401359392505050565b60006020828403121561223157600080fd5b8135610984816121d2565b600080600080600060a0868803121561225457600080fd5b853561225f816121d2565b9450602086013561226f816121d2565b9350604086013562ffffff8116811461228757600080fd5b94979396509394606081013594506080013592915050565b6000602082840312156122b157600080fd5b8151610984816121d2565b6000602082840312156122ce57600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612314576123146122d5565b604052919050565b600067ffffffffffffffff821115612336576123366122d5565b5060051b60200190565b600082601f83011261235157600080fd5b815160206123666123618361231c565b6122eb565b82815260059290921b8401810191818101908684111561238557600080fd5b8286015b848110156123a05780518352918301918301612389565b509695505050505050565b6000806000606084860312156123c057600080fd5b835167ffffffffffffffff808211156123d857600080fd5b818601915086601f8301126123ec57600080fd5b815160206123fc6123618361231c565b82815260059290921b8401810191818101908a84111561241b57600080fd5b948201945b83861015612442578551612433816121d2565b82529482019490820190612420565b9189015191975090935050508082111561245b57600080fd5b5061246886828701612340565b925050604084015190509250925092565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176111ac576111ac61248f565b6000602082840312156124ce57600080fd5b815160ff8116811461098457600080fd5b60ff82811682821603908111156111ac576111ac61248f565b60006020828403121561250a57600080fd5b815167ffffffffffffffff81111561252157600080fd5b6105ae84828501612340565b8051801515811461253d57600080fd5b919050565b60008060006060848603121561255757600080fd5b835192506125676020850161252d565b9150604084015190509250925092565b600181815b808511156125b25781600019048211156125985761259861248f565b808516156125a557918102915b93841c939080029061257c565b509250929050565b6000826125c9575060016111ac565b816125d6575060006111ac565b81600181146125ec57600281146125f657612612565b60019150506111ac565b60ff8411156126075761260761248f565b50506001821b6111ac565b5060208310610133831016604e8410600b8410161715612635575081810a6111ac565b61263f8383612577565b80600019048211156126535761265361248f565b029392505050565b600061098460ff8416836125ba565b60ff81811683821601908111156111ac576111ac61248f565b6000826126a057634e487b7160e01b600052601260045260246000fd5b500490565b600060ff821660ff81036126bb576126bb61248f565b60010192915050565b634e487b7160e01b600052602160045260246000fd5b808201808211156111ac576111ac61248f565b60005b838110156127085781810151838201526020016126f0565b50506000910152565b600081518084526127298160208601602086016126ed565b601f01601f19169290920160200192915050565b60e08152845160e0820152600060208601516002811061276d57634e487b7160e01b600052602160045260246000fd5b61010083015260408601516001600160a01b031661012083015260608601516127a26101408401826001600160a01b03169052565b50608086015161016083015260a086015160c06101808401526127c96101a0840182612711565b915050612809602083018680516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b60a082019390935260c0015292915050565b6000825161282d8184602087016126ed565b9190910192915050565b60006020828403121561284957600080fd5b6109848261252d565b6000600182016128645761286461248f565b5060010190565b818103818111156111ac576111ac61248f565b805169ffffffffffffffffffff8116811461253d57600080fd5b600080600080600060a086880312156128b057600080fd5b6128b98661287e565b94506020860151935060408601519250606086015191506128dc6080870161287e565b9050929550929590935056fea264697066735822122034d6076b22da7cecbf8a6b93581d263c4fcee103111e1a043ce67842daccaaa964736f6c63430008130033000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435740000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe4a8cc5b5b2366c1b58bea3858e81843581b2f70000000000000000000000000000000000000000000000000000000000015180

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061010b5760003560e01c806359879099116100a25780638c60c71c116100715780638c60c71c1461028a57806398d5fdca1461029d578063eda28b11146102a5578063f54c42d7146102b8578063fbfa77cf146102cb57600080fd5b8063598790991461022c5780635c1bba3814610234578063679aefce1461025b57806375cdf6491461026357600080fd5b806338da412e116100de57806338da412e146101a85780634437152a146101c95780634562aee3146101de5780635001f3b51461020557600080fd5b806316f0115b146101105780631f21f9af1461014057806330e005961461015357806335faa41614610181575b600080fd5b600154610123906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b600254610123906001600160a01b031681565b6101666101613660046121b9565b6102de565b60408051938452602084019290925290820152606001610137565b6101237f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d4357481565b6101bb6101b63660046121ea565b61052b565b604051908152602001610137565b6101dc6101d736600461221f565b6105b6565b005b6101237f000000000000000000000000fe4a8cc5b5b2366c1b58bea3858e81843581b2f781565b6101237f0000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c335981565b6101bb6106bf565b6101237f000000000000000000000000000000000000000000000000000000000000000081565b6101bb6106ce565b6101bb7f000000000000000000000000000000000000000000000000000000000001518081565b6101bb6102983660046121ea565b610761565b6101bb61098b565b6101bb6102b336600461223c565b610f65565b6101dc6102c636600461221f565b610f8f565b600054610123906001600160a01b031681565b6000806000806000600160009054906101000a90046001600160a01b03166001600160a01b0316638d928af86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610339573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061035d919061229f565b6001600160a01b031663f94d4668600160009054906101000a90046001600160a01b03166001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e291906122bc565b6040518263ffffffff1660e01b815260040161040091815260200190565b600060405180830381865afa15801561041d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261044591908101906123ab565b509150915060006104767f0000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c335984611105565b905060006104a47f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d4357485611105565b6001549091506000906104c0906001600160a01b031686611105565b9050838360ff16815181106104d7576104d7612479565b60200260200101519750838260ff16815181106104f6576104f6612479565b60200260200101519650838160ff168151811061051557610515612479565b6020026020010151955050505050509193909250565b60007f92f64ca637d023f354075a4be751b169c1a8a9ccb6d33cdd0cb35205439957278360405161055e91815260200190565b60405180910390a16105718483856111b2565b6001546105ae907f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d43574908690869086906001600160a01b0316611345565b949350505050565b7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610614573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610638919061229f565b6001600160a01b0316336001600160a01b03161461069d5760405162461bcd60e51b815260206004820152601b60248201527f42616c616e636572414d4d3a204e6f7420476f7665726e616e6365000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60006106c961098b565b905090565b60007f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663dc38679c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561072e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075291906122bc565b6106c99064e8d4a510006124a5565b60007f4e08ba899977cf7d4c2964bce71c6b9a7ef76ee5166a4c1249a1e08016e33ef18360405161079491815260200190565b60405180910390a16002546001600160a01b03161580159061083257506107b961098b565b600260009054906101000a90046001600160a01b03166001600160a01b031663018a25e86040518163ffffffff1660e01b8152600401602060405180830381865afa15801561080c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061083091906122bc565b105b1561093c576108637f0000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c3359333086611559565b60025461089b907f0000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c3359906001600160a01b03168561165b565b6002546040516369ae990b60e01b8152600481018590526001600160a01b03909116906369ae990b906024016020604051808303816000875af11580156108e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090a91906122bc565b90506109377f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d43574338361175b565b610984565b6109478484846111b2565b6001546105ae9085907f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d4357490869086906001600160a01b0316611345565b9392505050565b6001546000906001600160a01b03166109a65750621e848090565b60007f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2a91906124bc565b905060007f0000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c33596001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab091906124bc565b90506000610abe82846124df565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316631dd746ea6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610b15573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b3d91908101906124f8565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316636daccffa6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610b94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb89190612542565b50509050600080600160009054906101000a90046001600160a01b03166001600160a01b0316638d928af86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c36919061229f565b6001600160a01b031663f94d4668600160009054906101000a90046001600160a01b03166001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cbb91906122bc565b6040518263ffffffff1660e01b8152600401610cd991815260200190565b600060405180830381865afa158015610cf6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d1e91908101906123ab565b50915091506000610d4f7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d4357484611105565b90506000610d7d7f0000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c335985611105565b6040805160028082526060820183529293506000929091602083019080368337019050509050838360ff1681518110610db857610db8612479565b602002602001015181600081518110610dd357610dd3612479565b6020908102919091010152610de988600a61265b565b848360ff1681518110610dfe57610dfe612479565b6020026020010151610e1091906124a5565b81600181518110610e2357610e23612479565b6020026020010181815250506000610e3b8783611854565b90506000610e57888460006001670de0b6b3a764000087611a3c565b90506000610e847f000000000000000000000000fe4a8cc5b5b2366c1b58bea3858e81843581b2f7611b1e565b90506000610ef37f000000000000000000000000fe4a8cc5b5b2366c1b58bea3858e81843581b2f77f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000015180611b82565b90508b610f008f8461266a565b610f0a919061266a565b610f1590600a61265b565b818c8960ff1681518110610f2b57610f2b612479565b602002602001015185610f3e91906124a5565b610f4891906124a5565b610f529190612683565b9e50505050505050505050505050505090565b600154600090610f859087908790869086906001600160a01b0316611345565b9695505050505050565b7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663baf4a3126040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611011919061229f565b6001600160a01b0316336001600160a01b0316141580156110c557507f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561108b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110af919061229f565b6001600160a01b0316336001600160a01b031614155b156110e3576040516338ae11af60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000805b82518160ff16101561116357836001600160a01b0316838260ff168151811061113457611134612479565b60200260200101516001600160a01b0316036111515790506111ac565b8061115b816126a5565b915050611109565b5060405162461bcd60e51b815260206004820152601c60248201527f42616c616e636572414d4d3a204173736574206e6f7420666f756e64000000006044820152606401610694565b92915050565b8115806111bd575080155b156111db57604051631f2a200560e01b815260040160405180910390fd5b6000836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561121b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123f91906124bc565b61124a90600a61265b565b905060007f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d091906124bc565b6112db90600a61265b565b905060006112e984846124a5565b6112f383876124a5565b61130090620f42406124a5565b61130a9190612683565b905062186a0081118061131f5750620927c081105b1561133d5760405163491dee2160e01b815260040160405180910390fd5b505050505050565b600080826001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611386573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113aa91906122bc565b90506000836001600160a01b0316638d928af86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611410919061229f565b905061141e88333089611559565b61142988828861165b565b606060006040518060c0016040528085815260200160006001811115611451576114516126c4565b81526020018b6001600160a01b031681526020018a6001600160a01b0316815260200189815260200183815250905060006040518060800160405280306001600160a01b03168152602001600015158152602001336001600160a01b03168152602001600015158152509050600061038461ffff16426114d191906126da565b6040516352bbbe2960e01b81529091506001600160a01b038616906352bbbe299061150690869086908e90879060040161273d565b6020604051808303816000875af1158015611525573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154991906122bc565b9c9b505050505050505050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916115bd919061281b565b6000604051808303816000865af19150503d80600081146115fa576040519150601f19603f3d011682016040523d82523d6000602084013e6115ff565b606091505b50915091508180156116295750805115806116295750808060200190518101906116299190612837565b61133d5760405162461bcd60e51b815260206004820152600360248201526229aa2360e91b6044820152606401610694565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b17905291516000928392908716916116b7919061281b565b6000604051808303816000865af19150503d80600081146116f4576040519150601f19603f3d011682016040523d82523d6000602084013e6116f9565b606091505b50915091508180156117235750805115806117235750808060200190518101906117239190612837565b6117545760405162461bcd60e51b8152602060048201526002602482015261534160f01b6044820152606401610694565b5050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916117b7919061281b565b6000604051808303816000865af19150503d80600081146117f4576040519150601f19603f3d011682016040523d82523d6000602084013e6117f9565b606091505b50915091508180156118235750805115806118235750808060200190518101906118239190612837565b6117545760405162461bcd60e51b815260206004820152600260248201526114d560f21b6044820152606401610694565b80516000908190815b818110156118a55761189185828151811061187a5761187a612479565b602002602001015184611cc490919063ffffffff16565b92508061189d81612852565b91505061185d565b50816000036118b9576000925050506111ac565b600082816118c784896124a5565b905060005b60ff8110156119f3578260005b8681101561192a576119166118ee8387611d12565b6119118c848151811061190357611903612479565b60200260200101518a611d12565b611d71565b91508061192281612852565b9150506118d9565b5083945061199161196261195c611941848a611d12565b61195661194e888d611d12565b6103e8611d71565b90611cc4565b86611d12565b6119116119796119738a60016126da565b85611d12565b61195661194e61198b6103e88a61286b565b8a611d12565b9350848411156119c05760016119a7868661286b565b116119bb57839750505050505050506111ac565b6119e0565b60016119cc858761286b565b116119e057839750505050505050506111ac565b50806119eb81612852565b9150506118cc565b5060405162461bcd60e51b815260206004820152601f60248201527f535441424c455f494e56415249414e545f4449444e545f434f4e5645524745006044820152606401610694565b6000611a6a83878781518110611a5457611a54612479565b6020026020010151611cc490919063ffffffff16565b868681518110611a7c57611a7c612479565b6020026020010181815250506000611a9688888588611dbd565b905083878781518110611aab57611aab612479565b6020026020010151611abd919061286b565b878781518110611acf57611acf612479565b602002602001018181525050611b126001611b0c838a8981518110611af657611af6612479565b602002602001015161201390919063ffffffff16565b90612013565b98975050505050505050565b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b5e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ac91906124bc565b60006001600160a01b03831615611b9c57611b9c83612060565b6000806000866001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611bdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c039190612898565b50935050925069ffffffffffffffffffff169250600082138015611c2657508215155b8015611c3157508015155b611c6d5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420507269636560981b6044820152606401610694565b8415611cba5784611c7e824261286b565b1115611cba5760405162461bcd60e51b815260206004820152600b60248201526a5374616c6520507269636560a81b6044820152606401610694565b5095945050505050565b600080611cd183856126da565b9050838110156109845760405162461bcd60e51b815260206004820152600c60248201526b4144445f4f564552464c4f5760a01b6044820152606401610694565b600080611d1f83856124a5565b9050831580611d36575082611d348583612683565b145b6109845760405162461bcd60e51b815260206004820152600c60248201526b4d554c5f4f564552464c4f5760a01b6044820152606401610694565b600081600003611db35760405162461bcd60e51b815260206004820152600d60248201526c2d22a927afa224ab24a9a4a7a760991b6044820152606401610694565b6109848284612683565b600080845186611dcd91906124a5565b9050600085600081518110611de457611de4612479565b602002602001015190506000865187600081518110611e0557611e05612479565b6020026020010151611e1791906124a5565b905060015b8751811015611e8657611e5b611e55611e4e848b8581518110611e4157611e41612479565b6020026020010151611d12565b8a51611d12565b88611d71565b9150611e7288828151811061187a5761187a612479565b925080611e7e81612852565b915050611e1c565b50868581518110611e9957611e99612479565b602002602001015182611eac919061286b565b91506000611eba8788611d12565b90506000611ef1611edf611ed784611ed28988611d12565b612165565b6103e8611d12565b8a8981518110611e4157611e41612479565b90506000611f0c611f05611ed78b89611d71565b8690611cc4565b9050600080611f28611f1e8686611cc4565b611ed28d86611cc4565b905060005b60ff811015611fc057819250611f5d611f4a866119568586611d12565b611ed28e611b0c88611956886002611d12565b915082821115611f8d576001611f73848461286b565b11611f88575097506105ae9650505050505050565b611fae565b6001611f99838561286b565b11611fae575097506105ae9650505050505050565b80611fb881612852565b915050611f2d565b5060405162461bcd60e51b815260206004820152602160248201527f535441424c455f4745545f42414c414e43455f4449444e545f434f4e564552476044820152604560f81b6064820152608401610694565b6000828211156120545760405162461bcd60e51b815260206004820152600c60248201526b5355425f4f564552464c4f5760a01b6044820152606401610694565b60006105ae838561286b565b600080826001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156120a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c59190612898565b50509250925050600082131561210e5760405162461bcd60e51b815260206004820152600e60248201526d29b2b8bab2b731b2b9102237bbb760911b6044820152606401610694565b610e1061211b824261286b565b116121605760405162461bcd60e51b815260206004820152601560248201527423b930b1b2902832b934b7b2102737ba1027bb32b960591b6044820152606401610694565b505050565b6000816000036121a75760405162461bcd60e51b815260206004820152600d60248201526c2d22a927afa224ab24a9a4a7a760991b6044820152606401610694565b50811515600019909201046001010290565b6000602082840312156121cb57600080fd5b5035919050565b6001600160a01b03811681146121e757600080fd5b50565b6000806000606084860312156121ff57600080fd5b833561220a816121d2565b95602085013595506040909401359392505050565b60006020828403121561223157600080fd5b8135610984816121d2565b600080600080600060a0868803121561225457600080fd5b853561225f816121d2565b9450602086013561226f816121d2565b9350604086013562ffffff8116811461228757600080fd5b94979396509394606081013594506080013592915050565b6000602082840312156122b157600080fd5b8151610984816121d2565b6000602082840312156122ce57600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612314576123146122d5565b604052919050565b600067ffffffffffffffff821115612336576123366122d5565b5060051b60200190565b600082601f83011261235157600080fd5b815160206123666123618361231c565b6122eb565b82815260059290921b8401810191818101908684111561238557600080fd5b8286015b848110156123a05780518352918301918301612389565b509695505050505050565b6000806000606084860312156123c057600080fd5b835167ffffffffffffffff808211156123d857600080fd5b818601915086601f8301126123ec57600080fd5b815160206123fc6123618361231c565b82815260059290921b8401810191818101908a84111561241b57600080fd5b948201945b83861015612442578551612433816121d2565b82529482019490820190612420565b9189015191975090935050508082111561245b57600080fd5b5061246886828701612340565b925050604084015190509250925092565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176111ac576111ac61248f565b6000602082840312156124ce57600080fd5b815160ff8116811461098457600080fd5b60ff82811682821603908111156111ac576111ac61248f565b60006020828403121561250a57600080fd5b815167ffffffffffffffff81111561252157600080fd5b6105ae84828501612340565b8051801515811461253d57600080fd5b919050565b60008060006060848603121561255757600080fd5b835192506125676020850161252d565b9150604084015190509250925092565b600181815b808511156125b25781600019048211156125985761259861248f565b808516156125a557918102915b93841c939080029061257c565b509250929050565b6000826125c9575060016111ac565b816125d6575060006111ac565b81600181146125ec57600281146125f657612612565b60019150506111ac565b60ff8411156126075761260761248f565b50506001821b6111ac565b5060208310610133831016604e8410600b8410161715612635575081810a6111ac565b61263f8383612577565b80600019048211156126535761265361248f565b029392505050565b600061098460ff8416836125ba565b60ff81811683821601908111156111ac576111ac61248f565b6000826126a057634e487b7160e01b600052601260045260246000fd5b500490565b600060ff821660ff81036126bb576126bb61248f565b60010192915050565b634e487b7160e01b600052602160045260246000fd5b808201808211156111ac576111ac61248f565b60005b838110156127085781810151838201526020016126f0565b50506000910152565b600081518084526127298160208601602086016126ed565b601f01601f19169290920160200192915050565b60e08152845160e0820152600060208601516002811061276d57634e487b7160e01b600052602160045260246000fd5b61010083015260408601516001600160a01b031661012083015260608601516127a26101408401826001600160a01b03169052565b50608086015161016083015260a086015160c06101808401526127c96101a0840182612711565b915050612809602083018680516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b60a082019390935260c0015292915050565b6000825161282d8184602087016126ed565b9190910192915050565b60006020828403121561284957600080fd5b6109848261252d565b6000600182016128645761286461248f565b5060010190565b818103818111156111ac576111ac61248f565b805169ffffffffffffffffffff8116811461253d57600080fd5b600080600080600060a086880312156128b057600080fd5b6128b98661287e565b94506020860151935060408601519250606086015191506128dc6080870161287e565b9050929550929590935056fea264697066735822122034d6076b22da7cecbf8a6b93581d263c4fcee103111e1a043ce67842daccaaa964736f6c63430008130033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435740000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe4a8cc5b5b2366c1b58bea3858e81843581b2f70000000000000000000000000000000000000000000000000000000000015180

-----Decoded View---------------
Arg [0] : _sweep (address): 0xB88a5Ac00917a02d82c7cd6CEBd73E2852d43574
Arg [1] : _base (address): 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359
Arg [2] : _sequencer (address): 0x0000000000000000000000000000000000000000
Arg [3] : _oracleBase (address): 0xfE4A8cc5b5B2366C1B58Bea3858e81843581b2F7
Arg [4] : _oracleBaseUpdateFrequency (uint256): 86400

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d43574
Arg [1] : 0000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c3359
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [3] : 000000000000000000000000fe4a8cc5b5b2366c1b58bea3858e81843581b2f7
Arg [4] : 0000000000000000000000000000000000000000000000000000000000015180


Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.