Sonic Blaze Testnet

Contract

0x520341700b76c30089E0a14Bf6CF78716Da39AC6

Overview

S Balance

Sonic Blaze LogoSonic Blaze LogoSonic Blaze Logo0 S

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Modify Liqui...50861042024-12-18 15:02:082 days ago1734534128IN
0x52034170...16Da39AC6
0 S0.000039331.1
Set Modify Liqui...50405232024-12-18 10:44:212 days ago1734518661IN
0x52034170...16Da39AC6
0 S0.000039331.1
Set Modify Liqui...29418212024-12-10 17:23:0510 days ago1733851385IN
0x52034170...16Da39AC6
0 S0.000055641.1
Set Farming Addr...29393422024-12-10 17:10:2910 days ago1733850629IN
0x52034170...16Da39AC6
0 S0.00005571.1

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
50861042024-12-18 15:02:082 days ago1734534128
0x52034170...16Da39AC6
0 S
50405232024-12-18 10:44:212 days ago1734518661
0x52034170...16Da39AC6
0 S
50246752024-12-18 9:18:582 days ago1734513538
0x52034170...16Da39AC6
0 S
50246752024-12-18 9:18:582 days ago1734513538
0x52034170...16Da39AC6
 Contract Creation0 S
50246752024-12-18 9:18:582 days ago1734513538
0x52034170...16Da39AC6
0 S
48123132024-12-17 13:17:313 days ago1734441451
0x52034170...16Da39AC6
0 S
48113942024-12-17 13:12:203 days ago1734441140
0x52034170...16Da39AC6
0 S
48103962024-12-17 13:06:393 days ago1734440799
0x52034170...16Da39AC6
0 S
48001692024-12-17 12:11:253 days ago1734437485
0x52034170...16Da39AC6
0 S
47999702024-12-17 12:10:213 days ago1734437421
0x52034170...16Da39AC6
0 S
47991682024-12-17 12:06:103 days ago1734437170
0x52034170...16Da39AC6
0 S
47990862024-12-17 12:05:433 days ago1734437143
0x52034170...16Da39AC6
0 S
47990022024-12-17 12:05:153 days ago1734437115
0x52034170...16Da39AC6
0 S
47988882024-12-17 12:04:373 days ago1734437077
0x52034170...16Da39AC6
0 S
34974572024-12-12 16:08:168 days ago1734019696
0x52034170...16Da39AC6
0 S
34974572024-12-12 16:08:168 days ago1734019696
0x52034170...16Da39AC6
0 S
34963342024-12-12 16:02:288 days ago1734019348
0x52034170...16Da39AC6
0 S
34963342024-12-12 16:02:288 days ago1734019348
0x52034170...16Da39AC6
0 S
34949472024-12-12 15:55:288 days ago1734018928
0x52034170...16Da39AC6
0 S
34877262024-12-12 15:17:388 days ago1734016658
0x52034170...16Da39AC6
0 S
34863222024-12-12 15:10:068 days ago1734016206
0x52034170...16Da39AC6
0 S
32124232024-12-11 16:04:309 days ago1733933070
0x52034170...16Da39AC6
0 S
32124232024-12-11 16:04:309 days ago1733933070
0x52034170...16Da39AC6
 Contract Creation0 S
32124232024-12-11 16:04:309 days ago1733933070
0x52034170...16Da39AC6
0 S
29418212024-12-10 17:23:0510 days ago1733851385
0x52034170...16Da39AC6
0 S
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BasePluginV1Factory

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 27 : BasePluginV1Factory.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.20;

import './interfaces/IBasePluginV1Factory.sol';
import './libraries/AdaptiveFee.sol';
import './AlgebraBasePluginV1.sol';

/// @title Algebra Integral 1.0 default plugin factory
/// @notice This contract creates Algebra default plugins for Algebra liquidity pools
contract BasePluginV1Factory is IBasePluginV1Factory {
  /// @inheritdoc IBasePluginV1Factory
  bytes32 public constant override ALGEBRA_BASE_PLUGIN_FACTORY_ADMINISTRATOR = keccak256('ALGEBRA_BASE_PLUGIN_FACTORY_ADMINISTRATOR');

  /// @inheritdoc IBasePluginV1Factory
  address public immutable override algebraFactory;

  /// @inheritdoc IBasePluginV1Factory
  AlgebraFeeConfiguration public override defaultFeeConfiguration; // values of constants for sigmoids in fee calculation formula

  /// @inheritdoc IBasePluginV1Factory
  address public override farmingAddress;

  address public override modifyLiquidityEntrypoint;

  /// @inheritdoc IBasePluginV1Factory
  mapping(address poolAddress => address pluginAddress) public override pluginByPool;

  modifier onlyAdministrator() {
    require(IAlgebraFactory(algebraFactory).hasRoleOrOwner(ALGEBRA_BASE_PLUGIN_FACTORY_ADMINISTRATOR, msg.sender), 'Only administrator');
    _;
  }

  constructor(address _algebraFactory) {
    algebraFactory = _algebraFactory;
    defaultFeeConfiguration = AdaptiveFee.initialFeeConfiguration();
    emit DefaultFeeConfiguration(defaultFeeConfiguration);
  }

  /// @inheritdoc IAlgebraPluginFactory
  function createPlugin(address pool, address, address) external override returns (address) {
    require(msg.sender == algebraFactory);
    return _createPlugin(pool);
  }

  /// @inheritdoc IBasePluginV1Factory
  function createPluginForExistingPool(address token0, address token1) external override returns (address) {
    IAlgebraFactory factory = IAlgebraFactory(algebraFactory);
    require(factory.hasRoleOrOwner(factory.POOLS_ADMINISTRATOR_ROLE(), msg.sender));

    address pool = factory.poolByPair(token0, token1);
    require(pool != address(0), 'Pool not exist');

    return _createPlugin(pool);
  }

  function _createPlugin(address pool) internal returns (address) {
    require(pluginByPool[pool] == address(0), 'Already created');
    IAlgebraBasePluginV1 volatilityOracle = new AlgebraBasePluginV1(pool, algebraFactory, address(this));
    volatilityOracle.changeFeeConfiguration(defaultFeeConfiguration);
    pluginByPool[pool] = address(volatilityOracle);
    return address(volatilityOracle);
  }

  /// @inheritdoc IBasePluginV1Factory
  function setDefaultFeeConfiguration(AlgebraFeeConfiguration calldata newConfig) external override onlyAdministrator {
    AdaptiveFee.validateFeeConfiguration(newConfig);
    defaultFeeConfiguration = newConfig;
    emit DefaultFeeConfiguration(newConfig);
  }

  /// @inheritdoc IBasePluginV1Factory
  function setFarmingAddress(address newFarmingAddress) external override onlyAdministrator {
    require(farmingAddress != newFarmingAddress);
    farmingAddress = newFarmingAddress;
    emit FarmingAddress(newFarmingAddress);
  }

  function setModifyLiquidityEntrypoint(address newWithDrawalFeePlugin) external override onlyAdministrator {
    require(modifyLiquidityEntrypoint != newWithDrawalFeePlugin);
    modifyLiquidityEntrypoint = newWithDrawalFeePlugin;
    emit ModifyLiquidityEntrypoint(newWithDrawalFeePlugin);
  }
}

File 2 of 27 : Timestamp.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.20;

/// @title Abstract contract with modified blockTimestamp functionality
/// @notice Allows the pool and other contracts to get a timestamp truncated to 32 bits
/// @dev Can be overridden in tests to make testing easier
abstract contract Timestamp {
  /// @dev This function is created for testing by overriding it.
  /// @return A timestamp converted to uint32
  function _blockTimestamp() internal view virtual returns (uint32) {
    return uint32(block.timestamp); // truncation is desired
  }
}

File 3 of 27 : IAlgebraFactory.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
pragma abicoder v2;

import './plugin/IAlgebraPluginFactory.sol';
import './vault/IAlgebraVaultFactory.sol';

/// @title The interface for the Algebra Factory
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraFactory {
  /// @notice Emitted when a process of ownership renounce is started
  /// @param timestamp The timestamp of event
  /// @param finishTimestamp The timestamp when ownership renounce will be possible to finish
  event RenounceOwnershipStart(uint256 timestamp, uint256 finishTimestamp);

  /// @notice Emitted when a process of ownership renounce cancelled
  /// @param timestamp The timestamp of event
  event RenounceOwnershipStop(uint256 timestamp);

  /// @notice Emitted when a process of ownership renounce finished
  /// @param timestamp The timestamp of ownership renouncement
  event RenounceOwnershipFinish(uint256 timestamp);

  /// @notice Emitted when a pool is created
  /// @param token0 The first token of the pool by address sort order
  /// @param token1 The second token of the pool by address sort order
  /// @param pool The address of the created pool
  event Pool(address indexed token0, address indexed token1, address pool);

  /// @notice Emitted when the default community fee is changed
  /// @param newDefaultCommunityFee The new default community fee value
  event DefaultCommunityFee(uint16 newDefaultCommunityFee);

  /// @notice Emitted when the default tickspacing is changed
  /// @param newDefaultTickspacing The new default tickspacing value
  event DefaultTickspacing(int24 newDefaultTickspacing);

  /// @notice Emitted when the default fee is changed
  /// @param newDefaultFee The new default fee value
  event DefaultFee(uint16 newDefaultFee);

  /// @notice Emitted when the defaultPluginFactory address is changed
  /// @param defaultPluginFactoryAddress The new defaultPluginFactory address
  event DefaultPluginFactory(address defaultPluginFactoryAddress);

  /// @notice Emitted when the vaultFactory address is changed
  /// @param newVaultFactory The new vaultFactory address
  event VaultFactory(address newVaultFactory);

  /// @notice role that can change communityFee and tickspacing in pools
  /// @return The hash corresponding to this role
  function POOLS_ADMINISTRATOR_ROLE() external view returns (bytes32);

  /// @notice Returns `true` if `account` has been granted `role` or `account` is owner.
  /// @param role The hash corresponding to the role
  /// @param account The address for which the role is checked
  /// @return bool Whether the address has this role or the owner role or not
  function hasRoleOrOwner(bytes32 role, address account) external view returns (bool);

  /// @notice Returns the current owner of the factory
  /// @dev Can be changed by the current owner via transferOwnership(address newOwner)
  /// @return The address of the factory owner
  function owner() external view returns (address);

  /// @notice Returns the current poolDeployerAddress
  /// @return The address of the poolDeployer
  function poolDeployer() external view returns (address);

  /// @notice Returns the default community fee
  /// @return Fee which will be set at the creation of the pool
  function defaultCommunityFee() external view returns (uint16);

  /// @notice Returns the default fee
  /// @return Fee which will be set at the creation of the pool
  function defaultFee() external view returns (uint16);

  /// @notice Returns the default tickspacing
  /// @return Tickspacing which will be set at the creation of the pool
  function defaultTickspacing() external view returns (int24);

  /// @notice Return the current pluginFactory address
  /// @dev This contract is used to automatically set a plugin address in new liquidity pools
  /// @return Algebra plugin factory
  function defaultPluginFactory() external view returns (IAlgebraPluginFactory);

  /// @notice Return the current vaultFactory address
  /// @dev This contract is used to automatically set a vault address in new liquidity pools
  /// @return Algebra vault factory
  function vaultFactory() external view returns (IAlgebraVaultFactory);

  /// @notice Returns the default communityFee, tickspacing, fee and communityFeeVault for pool
  /// @param pool the address of liquidity pool
  /// @return communityFee which will be set at the creation of the pool
  /// @return tickSpacing which will be set at the creation of the pool
  /// @return fee which will be set at the creation of the pool
  /// @return communityFeeVault the address of communityFeeVault
  function defaultConfigurationForPool(
    address pool
  ) external view returns (uint16 communityFee, int24 tickSpacing, uint16 fee, address communityFeeVault);

  /// @notice Deterministically computes the pool address given the token0 and token1
  /// @dev The method does not check if such a pool has been created
  /// @param token0 first token
  /// @param token1 second token
  /// @return pool The contract address of the Algebra pool
  function computePoolAddress(address token0, address token1) external view returns (address pool);

  /// @notice Returns the pool address for a given pair of tokens, or address 0 if it does not exist
  /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order
  /// @param tokenA The contract address of either token0 or token1
  /// @param tokenB The contract address of the other token
  /// @return pool The pool address
  function poolByPair(address tokenA, address tokenB) external view returns (address pool);

  /// @notice returns keccak256 of AlgebraPool init bytecode.
  /// @dev the hash value changes with any change in the pool bytecode
  /// @return Keccak256 hash of AlgebraPool contract init bytecode
  function POOL_INIT_CODE_HASH() external view returns (bytes32);

  /// @return timestamp The timestamp of the beginning of the renounceOwnership process
  function renounceOwnershipStartTimestamp() external view returns (uint256 timestamp);

  /// @notice Creates a pool for the given two tokens
  /// @param tokenA One of the two tokens in the desired pool
  /// @param tokenB The other of the two tokens in the desired pool
  /// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0.
  /// The call will revert if the pool already exists or the token arguments are invalid.
  /// @return pool The address of the newly created pool
  function createPool(address tokenA, address tokenB) external returns (address pool);

  /// @dev updates default community fee for new pools
  /// @param newDefaultCommunityFee The new community fee, _must_ be <= MAX_COMMUNITY_FEE
  function setDefaultCommunityFee(uint16 newDefaultCommunityFee) external;

  /// @dev updates default fee for new pools
  /// @param newDefaultFee The new  fee, _must_ be <= MAX_DEFAULT_FEE
  function setDefaultFee(uint16 newDefaultFee) external;

  /// @dev updates default tickspacing for new pools
  /// @param newDefaultTickspacing The new tickspacing, _must_ be <= MAX_TICK_SPACING and >= MIN_TICK_SPACING
  function setDefaultTickspacing(int24 newDefaultTickspacing) external;

  /// @dev updates pluginFactory address
  /// @param newDefaultPluginFactory address of new plugin factory
  function setDefaultPluginFactory(address newDefaultPluginFactory) external;

  /// @dev updates vaultFactory address
  /// @param newVaultFactory address of new vault factory
  function setVaultFactory(address newVaultFactory) external;

  /// @notice Starts process of renounceOwnership. After that, a certain period
  /// of time must pass before the ownership renounce can be completed.
  function startRenounceOwnership() external;

  /// @notice Stops process of renounceOwnership and removes timer.
  function stopRenounceOwnership() external;
}

File 4 of 27 : IAlgebraPool.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.4;

import './pool/IAlgebraPoolImmutables.sol';
import './pool/IAlgebraPoolState.sol';
import './pool/IAlgebraPoolActions.sol';
import './pool/IAlgebraPoolPermissionedActions.sol';
import './pool/IAlgebraPoolEvents.sol';
import './pool/IAlgebraPoolErrors.sol';

/// @title The interface for a Algebra Pool
/// @dev The pool interface is broken up into many smaller pieces.
/// This interface includes custom error definitions and cannot be used in older versions of Solidity.
/// For older versions of Solidity use #IAlgebraPoolLegacy
/// Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPool is
  IAlgebraPoolImmutables,
  IAlgebraPoolState,
  IAlgebraPoolActions,
  IAlgebraPoolPermissionedActions,
  IAlgebraPoolEvents,
  IAlgebraPoolErrors
{
  // used only for combining interfaces
}

File 5 of 27 : IAlgebraDynamicFeePlugin.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title The interface for the Algebra plugin with dynamic fee logic
/// @dev A plugin with a dynamic fee must implement this interface so that the current fee can be known through the pool
/// If the dynamic fee logic does not allow the fee to be calculated without additional data, the method should revert with the appropriate message
interface IAlgebraDynamicFeePlugin {
  /// @notice Returns fee from plugin
  /// @return fee The pool fee value in hundredths of a bip, i.e. 1e-6
  function getCurrentFee() external view returns (uint16 fee);
}

File 6 of 27 : IAlgebraPlugin.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title The Algebra plugin interface
/// @dev The plugin will be called by the pool using hook methods depending on the current pool settings
interface IAlgebraPlugin {
  /// @notice Returns plugin config
  /// @return config Each bit of the config is responsible for enabling/disabling the hooks.
  /// The last bit indicates whether the plugin contains dynamic fees logic
  function defaultPluginConfig() external view returns (uint8);

  /// @notice The hook called before the state of a pool is initialized
  /// @param sender The initial msg.sender for the initialize call
  /// @param sqrtPriceX96 The sqrt(price) of the pool as a Q64.96
  /// @return bytes4 The function selector for the hook
  function beforeInitialize(address sender, uint160 sqrtPriceX96) external returns (bytes4);

  /// @notice The hook called after the state of a pool is initialized
  /// @param sender The initial msg.sender for the initialize call
  /// @param sqrtPriceX96 The sqrt(price) of the pool as a Q64.96
  /// @param tick The current tick after the state of a pool is initialized
  /// @return bytes4 The function selector for the hook
  function afterInitialize(address sender, uint160 sqrtPriceX96, int24 tick) external returns (bytes4);

  /// @notice The hook called before a position is modified
  /// @param sender The initial msg.sender for the modify position call
  /// @param recipient Address to which the liquidity will be assigned in case of a mint or
  /// to which tokens will be sent in case of a burn
  /// @param bottomTick The lower tick of the position
  /// @param topTick The upper tick of the position
  /// @param desiredLiquidityDelta The desired amount of liquidity to mint/burn
  /// @param data Data that passed through the callback
  /// @return bytes4 The function selector for the hook
  function beforeModifyPosition(
    address sender,
    address recipient,
    int24 bottomTick,
    int24 topTick,
    int128 desiredLiquidityDelta,
    bytes calldata data
  ) external returns (bytes4);

  /// @notice The hook called after a position is modified
  /// @param sender The initial msg.sender for the modify position call
  /// @param recipient Address to which the liquidity will be assigned in case of a mint or
  /// to which tokens will be sent in case of a burn
  /// @param bottomTick The lower tick of the position
  /// @param topTick The upper tick of the position
  /// @param desiredLiquidityDelta The desired amount of liquidity to mint/burn
  /// @param amount0 The amount of token0 sent to the recipient or was paid to mint
  /// @param amount1 The amount of token0 sent to the recipient or was paid to mint
  /// @param data Data that passed through the callback
  /// @return bytes4 The function selector for the hook
  function afterModifyPosition(
    address sender,
    address recipient,
    int24 bottomTick,
    int24 topTick,
    int128 desiredLiquidityDelta,
    uint256 amount0,
    uint256 amount1,
    bytes calldata data
  ) external returns (bytes4);

  /// @notice The hook called before a swap
  /// @param sender The initial msg.sender for the swap call
  /// @param recipient The address to receive the output of the swap
  /// @param zeroToOne The direction of the swap, true for token0 to token1, false for token1 to token0
  /// @param amountRequired The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
  /// @param limitSqrtPrice The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
  /// value after the swap. If one for zero, the price cannot be greater than this value after the swap
  /// @param withPaymentInAdvance The flag indicating whether the `swapWithPaymentInAdvance` method was called
  /// @param data Data that passed through the callback
  /// @return bytes4 The function selector for the hook
  function beforeSwap(
    address sender,
    address recipient,
    bool zeroToOne,
    int256 amountRequired,
    uint160 limitSqrtPrice,
    bool withPaymentInAdvance,
    bytes calldata data
  ) external returns (bytes4);

  /// @notice The hook called after a swap
  /// @param sender The initial msg.sender for the swap call
  /// @param recipient The address to receive the output of the swap
  /// @param zeroToOne The direction of the swap, true for token0 to token1, false for token1 to token0
  /// @param amountRequired The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
  /// @param limitSqrtPrice The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
  /// value after the swap. If one for zero, the price cannot be greater than this value after the swap
  /// @param amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
  /// @param amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
  /// @param data Data that passed through the callback
  /// @return bytes4 The function selector for the hook
  function afterSwap(
    address sender,
    address recipient,
    bool zeroToOne,
    int256 amountRequired,
    uint160 limitSqrtPrice,
    int256 amount0,
    int256 amount1,
    bytes calldata data
  ) external returns (bytes4);

  /// @notice The hook called before flash
  /// @param sender The initial msg.sender for the flash call
  /// @param recipient The address which will receive the token0 and token1 amounts
  /// @param amount0 The amount of token0 being requested for flash
  /// @param amount1 The amount of token1 being requested for flash
  /// @param data Data that passed through the callback
  /// @return bytes4 The function selector for the hook
  function beforeFlash(address sender, address recipient, uint256 amount0, uint256 amount1, bytes calldata data) external returns (bytes4);

  /// @notice The hook called after flash
  /// @param sender The initial msg.sender for the flash call
  /// @param recipient The address which will receive the token0 and token1 amounts
  /// @param amount0 The amount of token0 being requested for flash
  /// @param amount1 The amount of token1 being requested for flash
  /// @param paid0 The amount of token0 being paid for flash
  /// @param paid1 The amount of token1 being paid for flash
  /// @param data Data that passed through the callback
  /// @return bytes4 The function selector for the hook
  function afterFlash(
    address sender,
    address recipient,
    uint256 amount0,
    uint256 amount1,
    uint256 paid0,
    uint256 paid1,
    bytes calldata data
  ) external returns (bytes4);
}

File 7 of 27 : IAlgebraPluginFactory.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title An interface for a contract that is capable of deploying Algebra plugins
/// @dev Such a factory is needed if the plugin should be automatically created and connected to each new pool
interface IAlgebraPluginFactory {
  /// @notice Deploys new plugin contract for pool
  /// @param pool The address of the pool for which the new plugin will be created
  /// @param token0 First token of the pool
  /// @param token1 Second token of the pool
  /// @return New plugin address
  function createPlugin(address pool, address token0, address token1) external returns (address);
}

File 8 of 27 : IAlgebraPoolActions.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Permissionless pool actions
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPoolActions {
  /// @notice Sets the initial price for the pool
  /// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value
  /// @dev Initialization should be done in one transaction with pool creation to avoid front-running
  /// @param initialPrice The initial sqrt price of the pool as a Q64.96
  function initialize(uint160 initialPrice) external;

  /// @notice Adds liquidity for the given recipient/bottomTick/topTick position
  /// @dev The caller of this method receives a callback in the form of IAlgebraMintCallback#algebraMintCallback
  /// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends
  /// on bottomTick, topTick, the amount of liquidity, and the current price.
  /// @param leftoversRecipient The address which will receive potential surplus of paid tokens
  /// @param recipient The address for which the liquidity will be created
  /// @param bottomTick The lower tick of the position in which to add liquidity
  /// @param topTick The upper tick of the position in which to add liquidity
  /// @param liquidityDesired The desired amount of liquidity to mint
  /// @param data Any data that should be passed through to the callback
  /// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback
  /// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback
  /// @return liquidityActual The actual minted amount of liquidity
  function mint(
    address leftoversRecipient,
    address recipient,
    int24 bottomTick,
    int24 topTick,
    uint128 liquidityDesired,
    bytes calldata data
  ) external returns (uint256 amount0, uint256 amount1, uint128 liquidityActual);

  /// @notice Collects tokens owed to a position
  /// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.
  /// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or
  /// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the
  /// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.
  /// @param recipient The address which should receive the fees collected
  /// @param bottomTick The lower tick of the position for which to collect fees
  /// @param topTick The upper tick of the position for which to collect fees
  /// @param amount0Requested How much token0 should be withdrawn from the fees owed
  /// @param amount1Requested How much token1 should be withdrawn from the fees owed
  /// @return amount0 The amount of fees collected in token0
  /// @return amount1 The amount of fees collected in token1
  function collect(
    address recipient,
    int24 bottomTick,
    int24 topTick,
    uint128 amount0Requested,
    uint128 amount1Requested
  ) external returns (uint128 amount0, uint128 amount1);

  /// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position
  /// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0
  /// @dev Fees must be collected separately via a call to #collect
  /// @param bottomTick The lower tick of the position for which to burn liquidity
  /// @param topTick The upper tick of the position for which to burn liquidity
  /// @param amount How much liquidity to burn
  /// @param data Any data that should be passed through to the plugin
  /// @return amount0 The amount of token0 sent to the recipient
  /// @return amount1 The amount of token1 sent to the recipient
  function burn(int24 bottomTick, int24 topTick, uint128 amount, bytes calldata data) external returns (uint256 amount0, uint256 amount1);

  /// @notice Swap token0 for token1, or token1 for token0
  /// @dev The caller of this method receives a callback in the form of IAlgebraSwapCallback#algebraSwapCallback
  /// @param recipient The address to receive the output of the swap
  /// @param zeroToOne The direction of the swap, true for token0 to token1, false for token1 to token0
  /// @param amountRequired The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
  /// @param limitSqrtPrice The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
  /// value after the swap. If one for zero, the price cannot be greater than this value after the swap
  /// @param data Any data to be passed through to the callback. If using the Router it should contain SwapRouter#SwapCallbackData
  /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
  /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
  function swap(
    address recipient,
    bool zeroToOne,
    int256 amountRequired,
    uint160 limitSqrtPrice,
    bytes calldata data
  ) external returns (int256 amount0, int256 amount1);

  /// @notice Swap token0 for token1, or token1 for token0 with prepayment
  /// @dev The caller of this method receives a callback in the form of IAlgebraSwapCallback#algebraSwapCallback
  /// caller must send tokens in callback before swap calculation
  /// the actually sent amount of tokens is used for further calculations
  /// @param leftoversRecipient The address which will receive potential surplus of paid tokens
  /// @param recipient The address to receive the output of the swap
  /// @param zeroToOne The direction of the swap, true for token0 to token1, false for token1 to token0
  /// @param amountToSell The amount of the swap, only positive (exact input) amount allowed
  /// @param limitSqrtPrice The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
  /// value after the swap. If one for zero, the price cannot be greater than this value after the swap
  /// @param data Any data to be passed through to the callback. If using the Router it should contain SwapRouter#SwapCallbackData
  /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
  /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
  function swapWithPaymentInAdvance(
    address leftoversRecipient,
    address recipient,
    bool zeroToOne,
    int256 amountToSell,
    uint160 limitSqrtPrice,
    bytes calldata data
  ) external returns (int256 amount0, int256 amount1);

  /// @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback
  /// @dev The caller of this method receives a callback in the form of IAlgebraFlashCallback#algebraFlashCallback
  /// @dev All excess tokens paid in the callback are distributed to currently in-range liquidity providers as an additional fee.
  /// If there are no in-range liquidity providers, the fee will be transferred to the first active provider in the future
  /// @param recipient The address which will receive the token0 and token1 amounts
  /// @param amount0 The amount of token0 to send
  /// @param amount1 The amount of token1 to send
  /// @param data Any data to be passed through to the callback
  function flash(address recipient, uint256 amount0, uint256 amount1, bytes calldata data) external;
}

File 9 of 27 : IAlgebraPoolErrors.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.4;

/// @title Errors emitted by a pool
/// @notice Contains custom errors emitted by the pool
/// @dev Custom errors are separated from the common pool interface for compatibility with older versions of Solidity
interface IAlgebraPoolErrors {
  // ####  pool errors  ####

  /// @notice Emitted by the reentrancy guard
  error locked();

  /// @notice Emitted if arithmetic error occurred
  error arithmeticError();

  /// @notice Emitted if an attempt is made to initialize the pool twice
  error alreadyInitialized();

  /// @notice Emitted if an attempt is made to mint or swap in uninitialized pool
  error notInitialized();

  /// @notice Emitted if 0 is passed as amountRequired to swap function
  error zeroAmountRequired();

  /// @notice Emitted if invalid amount is passed as amountRequired to swap function
  error invalidAmountRequired();

  /// @notice Emitted if the pool received fewer tokens than it should have
  error insufficientInputAmount();

  /// @notice Emitted if there was an attempt to mint zero liquidity
  error zeroLiquidityDesired();
  /// @notice Emitted if actual amount of liquidity is zero (due to insufficient amount of tokens received)
  error zeroLiquidityActual();

  /// @notice Emitted if the pool received fewer tokens0 after flash than it should have
  error flashInsufficientPaid0();
  /// @notice Emitted if the pool received fewer tokens1 after flash than it should have
  error flashInsufficientPaid1();

  /// @notice Emitted if limitSqrtPrice param is incorrect
  error invalidLimitSqrtPrice();

  /// @notice Tick must be divisible by tickspacing
  error tickIsNotSpaced();

  /// @notice Emitted if a method is called that is accessible only to the factory owner or dedicated role
  error notAllowed();

  /// @notice Emitted if new tick spacing exceeds max allowed value
  error invalidNewTickSpacing();
  /// @notice Emitted if new community fee exceeds max allowed value
  error invalidNewCommunityFee();

  /// @notice Emitted if an attempt is made to manually change the fee value, but dynamic fee is enabled
  error dynamicFeeActive();
  /// @notice Emitted if an attempt is made by plugin to change the fee value, but dynamic fee is disabled
  error dynamicFeeDisabled();
  /// @notice Emitted if an attempt is made to change the plugin configuration, but the plugin is not connected
  error pluginIsNotConnected();
  /// @notice Emitted if a plugin returns invalid selector after hook call
  /// @param expectedSelector The expected selector
  error invalidHookResponse(bytes4 expectedSelector);

  // ####  LiquidityMath errors  ####

  /// @notice Emitted if liquidity underflows
  error liquiditySub();
  /// @notice Emitted if liquidity overflows
  error liquidityAdd();

  // ####  TickManagement errors  ####

  /// @notice Emitted if the topTick param not greater then the bottomTick param
  error topTickLowerOrEqBottomTick();
  /// @notice Emitted if the bottomTick param is lower than min allowed value
  error bottomTickLowerThanMIN();
  /// @notice Emitted if the topTick param is greater than max allowed value
  error topTickAboveMAX();
  /// @notice Emitted if the liquidity value associated with the tick exceeds MAX_LIQUIDITY_PER_TICK
  error liquidityOverflow();
  /// @notice Emitted if an attempt is made to interact with an uninitialized tick
  error tickIsNotInitialized();
  /// @notice Emitted if there is an attempt to insert a new tick into the list of ticks with incorrect indexes of the previous and next ticks
  error tickInvalidLinks();

  // ####  SafeTransfer errors  ####

  /// @notice Emitted if token transfer failed internally
  error transferFailed();

  // ####  TickMath errors  ####

  /// @notice Emitted if tick is greater than the maximum or less than the minimum allowed value
  error tickOutOfRange();
  /// @notice Emitted if price is greater than the maximum or less than the minimum allowed value
  error priceOutOfRange();
}

File 10 of 27 : IAlgebraPoolEvents.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Events emitted by a pool
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPoolEvents {
  /// @notice Emitted exactly once by a pool when #initialize is first called on the pool
  /// @dev Mint/Burn/Swaps cannot be emitted by the pool before Initialize
  /// @param price The initial sqrt price of the pool, as a Q64.96
  /// @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool
  event Initialize(uint160 price, int24 tick);

  /// @notice Emitted when liquidity is minted for a given position
  /// @param sender The address that minted the liquidity
  /// @param owner The owner of the position and recipient of any minted liquidity
  /// @param bottomTick The lower tick of the position
  /// @param topTick The upper tick of the position
  /// @param liquidityAmount The amount of liquidity minted to the position range
  /// @param amount0 How much token0 was required for the minted liquidity
  /// @param amount1 How much token1 was required for the minted liquidity
  event Mint(
    address sender,
    address indexed owner,
    int24 indexed bottomTick,
    int24 indexed topTick,
    uint128 liquidityAmount,
    uint256 amount0,
    uint256 amount1
  );

  /// @notice Emitted when fees are collected by the owner of a position
  /// @param owner The owner of the position for which fees are collected
  /// @param recipient The address that received fees
  /// @param bottomTick The lower tick of the position
  /// @param topTick The upper tick of the position
  /// @param amount0 The amount of token0 fees collected
  /// @param amount1 The amount of token1 fees collected
  event Collect(address indexed owner, address recipient, int24 indexed bottomTick, int24 indexed topTick, uint128 amount0, uint128 amount1);

  /// @notice Emitted when a position's liquidity is removed
  /// @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect
  /// @param owner The owner of the position for which liquidity is removed
  /// @param bottomTick The lower tick of the position
  /// @param topTick The upper tick of the position
  /// @param liquidityAmount The amount of liquidity to remove
  /// @param amount0 The amount of token0 withdrawn
  /// @param amount1 The amount of token1 withdrawn
  event Burn(address indexed owner, int24 indexed bottomTick, int24 indexed topTick, uint128 liquidityAmount, uint256 amount0, uint256 amount1);

  /// @notice Emitted by the pool for any swaps between token0 and token1
  /// @param sender The address that initiated the swap call, and that received the callback
  /// @param recipient The address that received the output of the swap
  /// @param amount0 The delta of the token0 balance of the pool
  /// @param amount1 The delta of the token1 balance of the pool
  /// @param price The sqrt(price) of the pool after the swap, as a Q64.96
  /// @param liquidity The liquidity of the pool after the swap
  /// @param tick The log base 1.0001 of price of the pool after the swap
  event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 price, uint128 liquidity, int24 tick);

  /// @notice Emitted by the pool for any flashes of token0/token1
  /// @param sender The address that initiated the swap call, and that received the callback
  /// @param recipient The address that received the tokens from flash
  /// @param amount0 The amount of token0 that was flashed
  /// @param amount1 The amount of token1 that was flashed
  /// @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee
  /// @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee
  event Flash(address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1, uint256 paid0, uint256 paid1);

  /// @notice Emitted when the community fee is changed by the pool
  /// @param communityFeeNew The updated value of the community fee in thousandths (1e-3)
  event CommunityFee(uint16 communityFeeNew);

  /// @notice Emitted when the tick spacing changes
  /// @param newTickSpacing The updated value of the new tick spacing
  event TickSpacing(int24 newTickSpacing);

  /// @notice Emitted when the plugin address changes
  /// @param newPluginAddress New plugin address
  event Plugin(address newPluginAddress);

  /// @notice Emitted when the plugin config changes
  /// @param newPluginConfig New plugin config
  event PluginConfig(uint8 newPluginConfig);

  /// @notice Emitted when the fee changes inside the pool
  /// @param fee The current fee in hundredths of a bip, i.e. 1e-6
  event Fee(uint16 fee);

  event CommunityVault(address newCommunityVault);
}

File 11 of 27 : IAlgebraPoolImmutables.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Pool state that never changes
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPoolImmutables {
  /// @notice The Algebra factory contract, which must adhere to the IAlgebraFactory interface
  /// @return The contract address
  function factory() external view returns (address);

  /// @notice The first of the two tokens of the pool, sorted by address
  /// @return The token contract address
  function token0() external view returns (address);

  /// @notice The second of the two tokens of the pool, sorted by address
  /// @return The token contract address
  function token1() external view returns (address);

  /// @notice The maximum amount of position liquidity that can use any tick in the range
  /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and
  /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool
  /// @return The max amount of liquidity per tick
  function maxLiquidityPerTick() external view returns (uint128);
}

File 12 of 27 : IAlgebraPoolPermissionedActions.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Permissioned pool actions
/// @notice Contains pool methods that may only be called by permissioned addresses
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPoolPermissionedActions {
  /// @notice Set the community's % share of the fees. Only factory owner or POOLS_ADMINISTRATOR_ROLE role
  /// @param newCommunityFee The new community fee percent in thousandths (1e-3)
  function setCommunityFee(uint16 newCommunityFee) external;

  /// @notice Set the new tick spacing values. Only factory owner or POOLS_ADMINISTRATOR_ROLE role
  /// @param newTickSpacing The new tick spacing value
  function setTickSpacing(int24 newTickSpacing) external;

  /// @notice Set the new plugin address. Only factory owner or POOLS_ADMINISTRATOR_ROLE role
  /// @param newPluginAddress The new plugin address
  function setPlugin(address newPluginAddress) external;

  /// @notice Set new plugin config. Only factory owner or POOLS_ADMINISTRATOR_ROLE role
  /// @param newConfig In the new configuration of the plugin,
  /// each bit of which is responsible for a particular hook.
  function setPluginConfig(uint8 newConfig) external;

  /// @notice Set new community fee vault address. Only factory owner or POOLS_ADMINISTRATOR_ROLE role
  /// @dev Community fee vault receives collected community fees.
  /// **accumulated but not yet sent to the vault community fees once will be sent to the `newCommunityVault` address**
  /// @param newCommunityVault The address of new community fee vault
  function setCommunityVault(address newCommunityVault) external;

  /// @notice Set new pool fee. Can be called by owner if dynamic fee is disabled.
  /// Called by the plugin if dynamic fee is enabled
  /// @param newFee The new fee value
  function setFee(uint16 newFee) external;
}

File 13 of 27 : IAlgebraPoolState.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Pool state that can change
/// @dev Important security note: when using this data by external contracts, it is necessary to take into account the possibility
/// of manipulation (including read-only reentrancy).
/// This interface is based on the UniswapV3 interface, credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPoolState {
  /// @notice Safely get most important state values of Algebra Integral AMM
  /// @dev Several values exposed as a single method to save gas when accessed externally.
  /// **Important security note: this method checks reentrancy lock and should be preferred in most cases**.
  /// @return sqrtPrice The current price of the pool as a sqrt(dToken1/dToken0) Q64.96 value
  /// @return tick The current global tick of the pool. May not always be equal to SqrtTickMath.getTickAtSqrtRatio(price) if the price is on a tick boundary
  /// @return lastFee The current (last known) pool fee value in hundredths of a bip, i.e. 1e-6 (so '100' is '0.01%'). May be obsolete if using dynamic fee plugin
  /// @return pluginConfig The current plugin config as bitmap. Each bit is responsible for enabling/disabling the hooks, the last bit turns on/off dynamic fees logic
  /// @return activeLiquidity  The currently in-range liquidity available to the pool
  /// @return nextTick The next initialized tick after current global tick
  /// @return previousTick The previous initialized tick before (or at) current global tick
  function safelyGetStateOfAMM()
    external
    view
    returns (uint160 sqrtPrice, int24 tick, uint16 lastFee, uint8 pluginConfig, uint128 activeLiquidity, int24 nextTick, int24 previousTick);

  /// @notice Allows to easily get current reentrancy lock status
  /// @dev can be used to prevent read-only reentrancy.
  /// This method just returns `globalState.unlocked` value
  /// @return unlocked Reentrancy lock flag, true if the pool currently is unlocked, otherwise - false
  function isUnlocked() external view returns (bool unlocked);

  // ! IMPORTANT security note: the pool state can be manipulated.
  // ! The following methods do not check reentrancy lock themselves.

  /// @notice The globalState structure in the pool stores many values but requires only one slot
  /// and is exposed as a single method to save gas when accessed externally.
  /// @dev **important security note: caller should check `unlocked` flag to prevent read-only reentrancy**
  /// @return price The current price of the pool as a sqrt(dToken1/dToken0) Q64.96 value
  /// @return tick The current tick of the pool, i.e. according to the last tick transition that was run
  /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(price) if the price is on a tick boundary
  /// @return lastFee The current (last known) pool fee value in hundredths of a bip, i.e. 1e-6 (so '100' is '0.01%'). May be obsolete if using dynamic fee plugin
  /// @return pluginConfig The current plugin config as bitmap. Each bit is responsible for enabling/disabling the hooks, the last bit turns on/off dynamic fees logic
  /// @return communityFee The community fee represented as a percent of all collected fee in thousandths, i.e. 1e-3 (so 100 is 10%)
  /// @return unlocked Reentrancy lock flag, true if the pool currently is unlocked, otherwise - false
  function globalState() external view returns (uint160 price, int24 tick, uint16 lastFee, uint8 pluginConfig, uint16 communityFee, bool unlocked);

  /// @notice Look up information about a specific tick in the pool
  /// @dev **important security note: caller should check reentrancy lock to prevent read-only reentrancy**
  /// @param tick The tick to look up
  /// @return liquidityTotal The total amount of position liquidity that uses the pool either as tick lower or tick upper
  /// @return liquidityDelta How much liquidity changes when the pool price crosses the tick
  /// @return prevTick The previous tick in tick list
  /// @return nextTick The next tick in tick list
  /// @return outerFeeGrowth0Token The fee growth on the other side of the tick from the current tick in token0
  /// @return outerFeeGrowth1Token The fee growth on the other side of the tick from the current tick in token1
  /// In addition, these values are only relative and must be used only in comparison to previous snapshots for
  /// a specific position.
  function ticks(
    int24 tick
  )
    external
    view
    returns (
      uint256 liquidityTotal,
      int128 liquidityDelta,
      int24 prevTick,
      int24 nextTick,
      uint256 outerFeeGrowth0Token,
      uint256 outerFeeGrowth1Token
    );

  /// @notice The timestamp of the last sending of tokens to community vault
  /// @return The timestamp truncated to 32 bits
  function communityFeeLastTimestamp() external view returns (uint32);

  /// @notice The amounts of token0 and token1 that will be sent to the vault
  /// @dev Will be sent COMMUNITY_FEE_TRANSFER_FREQUENCY after communityFeeLastTimestamp
  /// @return communityFeePending0 The amount of token0 that will be sent to the vault
  /// @return communityFeePending1 The amount of token1 that will be sent to the vault
  function getCommunityFeePending() external view returns (uint128 communityFeePending0, uint128 communityFeePending1);

  /// @notice Returns the address of currently used plugin
  /// @dev The plugin is subject to change
  /// @return pluginAddress The address of currently used plugin
  function plugin() external view returns (address pluginAddress);

  /// @notice The contract to which community fees are transferred
  /// @return communityVaultAddress The communityVault address
  function communityVault() external view returns (address communityVaultAddress);

  /// @notice Returns 256 packed tick initialized boolean values. See TickTree for more information
  /// @param wordPosition Index of 256-bits word with ticks
  /// @return The 256-bits word with packed ticks info
  function tickTable(int16 wordPosition) external view returns (uint256);

  /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool
  /// @dev This value can overflow the uint256
  /// @return The fee growth accumulator for token0
  function totalFeeGrowth0Token() external view returns (uint256);

  /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool
  /// @dev This value can overflow the uint256
  /// @return The fee growth accumulator for token1
  function totalFeeGrowth1Token() external view returns (uint256);

  /// @notice The current pool fee value
  /// @dev In case dynamic fee is enabled in the pool, this method will call the plugin to get the current fee.
  /// If the plugin implements complex fee logic, this method may return an incorrect value or revert.
  /// In this case, see the plugin implementation and related documentation.
  /// @dev **important security note: caller should check reentrancy lock to prevent read-only reentrancy**
  /// @return currentFee The current pool fee value in hundredths of a bip, i.e. 1e-6
  function fee() external view returns (uint16 currentFee);

  /// @notice The tracked token0 and token1 reserves of pool
  /// @dev If at any time the real balance is larger, the excess will be transferred to liquidity providers as additional fee.
  /// If the balance exceeds uint128, the excess will be sent to the communityVault.
  /// @return reserve0 The last known reserve of token0
  /// @return reserve1 The last known reserve of token1
  function getReserves() external view returns (uint128 reserve0, uint128 reserve1);

  /// @notice Returns the information about a position by the position's key
  /// @dev **important security note: caller should check reentrancy lock to prevent read-only reentrancy**
  /// @param key The position's key is a packed concatenation of the owner address, bottomTick and topTick indexes
  /// @return liquidity The amount of liquidity in the position
  /// @return innerFeeGrowth0Token Fee growth of token0 inside the tick range as of the last mint/burn/poke
  /// @return innerFeeGrowth1Token Fee growth of token1 inside the tick range as of the last mint/burn/poke
  /// @return fees0 The computed amount of token0 owed to the position as of the last mint/burn/poke
  /// @return fees1 The computed amount of token1 owed to the position as of the last mint/burn/poke
  function positions(
    bytes32 key
  ) external view returns (uint256 liquidity, uint256 innerFeeGrowth0Token, uint256 innerFeeGrowth1Token, uint128 fees0, uint128 fees1);

  /// @notice The currently in range liquidity available to the pool
  /// @dev This value has no relationship to the total liquidity across all ticks.
  /// Returned value cannot exceed type(uint128).max
  /// @dev **important security note: caller should check reentrancy lock to prevent read-only reentrancy**
  /// @return The current in range liquidity
  function liquidity() external view returns (uint128);

  /// @notice The current tick spacing
  /// @dev Ticks can only be initialized by new mints at multiples of this value
  /// e.g.: a tickSpacing of 60 means ticks can be initialized every 60th tick, i.e., ..., -120, -60, 0, 60, 120, ...
  /// However, tickspacing can be changed after the ticks have been initialized.
  /// This value is an int24 to avoid casting even though it is always positive.
  /// @return The current tick spacing
  function tickSpacing() external view returns (int24);

  /// @notice The previous initialized tick before (or at) current global tick
  /// @dev **important security note: caller should check reentrancy lock to prevent read-only reentrancy**
  /// @return The previous initialized tick
  function prevTickGlobal() external view returns (int24);

  /// @notice The next initialized tick after current global tick
  /// @dev **important security note: caller should check reentrancy lock to prevent read-only reentrancy**
  /// @return The next initialized tick
  function nextTickGlobal() external view returns (int24);

  /// @notice The root of tick search tree
  /// @dev Each bit corresponds to one node in the second layer of tick tree: '1' if node has at least one active bit.
  /// **important security note: caller should check reentrancy lock to prevent read-only reentrancy**
  /// @return The root of tick search tree as bitmap
  function tickTreeRoot() external view returns (uint32);

  /// @notice The second layer of tick search tree
  /// @dev Each bit in node corresponds to one node in the leafs layer (`tickTable`) of tick tree: '1' if leaf has at least one active bit.
  /// **important security note: caller should check reentrancy lock to prevent read-only reentrancy**
  /// @return The node of tick search tree second layer
  function tickTreeSecondLayer(int16) external view returns (uint256);
}

File 14 of 27 : IAlgebraVaultFactory.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title The interface for the Algebra Vault Factory
/// @notice This contract can be used for automatic vaults creation
/// @dev Version: Algebra Integral
interface IAlgebraVaultFactory {
  /// @notice returns address of the community fee vault for the pool
  /// @param pool the address of Algebra Integral pool
  /// @return communityFeeVault the address of community fee vault
  function getVaultForPool(address pool) external view returns (address communityFeeVault);

  /// @notice creates the community fee vault for the pool if needed
  /// @param pool the address of Algebra Integral pool
  /// @return communityFeeVault the address of community fee vault
  function createVaultForPool(address pool) external returns (address communityFeeVault);
}

File 15 of 27 : Constants.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0 <0.9.0;

/// @title Contains common constants for Algebra contracts
/// @dev Constants moved to the library, not the base contract, to further emphasize their constant nature
library Constants {
  uint8 internal constant RESOLUTION = 96;
  uint256 internal constant Q96 = 1 << 96;
  uint256 internal constant Q128 = 1 << 128;

  uint24 internal constant FEE_DENOMINATOR = 1e6;
  uint16 internal constant FLASH_FEE = 0.01e4; // fee for flash loan in hundredths of a bip (0.01%)
  uint16 internal constant INIT_DEFAULT_FEE = 0.05e4; // init default fee value in hundredths of a bip (0.05%)
  uint16 internal constant MAX_DEFAULT_FEE = 5e4; // max default fee value in hundredths of a bip (5%)

  int24 internal constant INIT_DEFAULT_TICK_SPACING = 60;
  int24 internal constant MAX_TICK_SPACING = 500;
  int24 internal constant MIN_TICK_SPACING = 1;

  // the frequency with which the accumulated community fees are sent to the vault
  uint32 internal constant COMMUNITY_FEE_TRANSFER_FREQUENCY = 8 hours;

  // max(uint128) / (MAX_TICK - MIN_TICK)
  uint128 internal constant MAX_LIQUIDITY_PER_TICK = 191757638537527648490752896198553;

  uint16 internal constant MAX_COMMUNITY_FEE = 1e3; // 100%
  uint256 internal constant COMMUNITY_FEE_DENOMINATOR = 1e3;
  // role that can change settings in pools
  bytes32 internal constant POOLS_ADMINISTRATOR_ROLE = keccak256('POOLS_ADMINISTRATOR');
}

File 16 of 27 : Plugins.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.4 <0.9.0;

import '../interfaces/pool/IAlgebraPoolErrors.sol';

/// @title Contains logic and constants for interacting with the plugin through hooks
/// @dev Allows pool to check which hooks are enabled, as well as control the return selector
library Plugins {
  function hasFlag(uint8 pluginConfig, uint256 flag) internal pure returns (bool res) {
    assembly {
      res := gt(and(pluginConfig, flag), 0)
    }
  }

  function shouldReturn(bytes4 selector, bytes4 expectedSelector) internal pure {
    if (selector != expectedSelector) revert IAlgebraPoolErrors.invalidHookResponse(expectedSelector);
  }

  uint256 internal constant BEFORE_SWAP_FLAG = 1;
  uint256 internal constant AFTER_SWAP_FLAG = 1 << 1;
  uint256 internal constant BEFORE_POSITION_MODIFY_FLAG = 1 << 2;
  uint256 internal constant AFTER_POSITION_MODIFY_FLAG = 1 << 3;
  uint256 internal constant BEFORE_FLASH_FLAG = 1 << 4;
  uint256 internal constant AFTER_FLASH_FLAG = 1 << 5;
  uint256 internal constant AFTER_INIT_FLAG = 1 << 6;
  uint256 internal constant DYNAMIC_FEE = 1 << 7;
}

File 17 of 27 : AlgebraBasePluginV1.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.20;

import '@cryptoalgebra/integral-core/contracts/base/common/Timestamp.sol';
import '@cryptoalgebra/integral-core/contracts/libraries/Plugins.sol';

import '@cryptoalgebra/integral-core/contracts/interfaces/IAlgebraFactory.sol';
import '@cryptoalgebra/integral-core/contracts/interfaces/plugin/IAlgebraPlugin.sol';
import '@cryptoalgebra/integral-core/contracts/interfaces/pool/IAlgebraPoolState.sol';
import '@cryptoalgebra/integral-core/contracts/interfaces/IAlgebraPool.sol';

import './interfaces/IAlgebraBasePluginV1.sol';
import './interfaces/IBasePluginV1Factory.sol';
import './interfaces/IAlgebraVirtualPool.sol';

import './libraries/VolatilityOracle.sol';
import './libraries/AdaptiveFee.sol';
import './types/AlgebraFeeConfigurationU144.sol';

/// @title Algebra Integral 1.0 default plugin
/// @notice This contract stores timepoints and calculates adaptive fee and statistical averages
contract AlgebraBasePluginV1 is IAlgebraBasePluginV1, Timestamp, IAlgebraPlugin {
  using Plugins for uint8;
  using AlgebraFeeConfigurationU144Lib for AlgebraFeeConfiguration;

  uint256 internal constant UINT16_MODULO = 65536;
  using VolatilityOracle for VolatilityOracle.Timepoint[UINT16_MODULO];

  /// @dev The role can be granted in AlgebraFactory
  bytes32 public constant ALGEBRA_BASE_PLUGIN_MANAGER = keccak256('ALGEBRA_BASE_PLUGIN_MANAGER');

  /// @inheritdoc IAlgebraPlugin
  uint8 public constant override defaultPluginConfig =
    uint8(Plugins.AFTER_INIT_FLAG | Plugins.BEFORE_SWAP_FLAG | Plugins.DYNAMIC_FEE | Plugins.BEFORE_POSITION_MODIFY_FLAG);

  /// @inheritdoc IFarmingPlugin
  address public immutable override pool;
  address private immutable factory;
  address private immutable pluginFactory;

  /// @inheritdoc IVolatilityOracle
  VolatilityOracle.Timepoint[UINT16_MODULO] public override timepoints;

  /// @inheritdoc IVolatilityOracle
  uint16 public override timepointIndex;

  /// @inheritdoc IVolatilityOracle
  uint32 public override lastTimepointTimestamp;

  /// @inheritdoc IVolatilityOracle
  bool public override isInitialized;

  /// @dev AlgebraFeeConfiguration struct packed in uint144
  AlgebraFeeConfigurationU144 private _feeConfig;

  address public override modifyLiquidityEntrypoint;

  /// @inheritdoc IFarmingPlugin
  address public override incentive;

  /// @dev the address which connected the last incentive. Needed so that he can disconnect it
  address private _lastIncentiveOwner;

  modifier onlyPool() {
    _checkIfFromPool();
    _;
  }

  constructor(address _pool, address _factory, address _pluginFactory) {
    (factory, pool, pluginFactory) = (_factory, _pool, _pluginFactory);
  }

  /// @inheritdoc IDynamicFeeManager
  function feeConfig()
    external
    view
    override
    returns (uint16 alpha1, uint16 alpha2, uint32 beta1, uint32 beta2, uint16 gamma1, uint16 gamma2, uint16 baseFee)
  {
    (alpha1, alpha2) = (_feeConfig.alpha1(), _feeConfig.alpha2());
    (beta1, beta2) = (_feeConfig.beta1(), _feeConfig.beta2());
    (gamma1, gamma2) = (_feeConfig.gamma1(), _feeConfig.gamma2());
    baseFee = _feeConfig.baseFee();
  }

  function _checkIfFromPool() internal view {
    require(msg.sender == pool, 'Only pool can call this');
  }

  function _getPoolState() internal view returns (uint160 price, int24 tick, uint16 fee, uint8 pluginConfig) {
    (price, tick, fee, pluginConfig, , ) = IAlgebraPoolState(pool).globalState();
  }

  function _getPluginInPool() internal view returns (address plugin) {
    return IAlgebraPool(pool).plugin();
  }

  /// @inheritdoc IAlgebraBasePluginV1
  function initialize() external override {
    require(!isInitialized, 'Already initialized');
    require(_getPluginInPool() == address(this), 'Plugin not attached');
    (uint160 price, int24 tick, , ) = _getPoolState();
    require(price != 0, 'Pool is not initialized');

    uint32 time = _blockTimestamp();
    modifyLiquidityEntrypoint = IBasePluginV1Factory(pluginFactory).modifyLiquidityEntrypoint();
    timepoints.initialize(time, tick);
    lastTimepointTimestamp = time;
    isInitialized = true;

    _updatePluginConfigInPool();
  }

  // ###### Volatility and TWAP oracle ######

  /// @inheritdoc IVolatilityOracle
  function getSingleTimepoint(uint32 secondsAgo) external view override returns (int56 tickCumulative, uint88 volatilityCumulative) {
    // `volatilityCumulative` values for timestamps after the last timepoint _should not_ be compared: they may differ due to interpolation errors
    (, int24 tick, , ) = _getPoolState();
    uint16 lastTimepointIndex = timepointIndex;
    uint16 oldestIndex = timepoints.getOldestIndex(lastTimepointIndex);
    VolatilityOracle.Timepoint memory result = timepoints.getSingleTimepoint(_blockTimestamp(), secondsAgo, tick, lastTimepointIndex, oldestIndex);
    (tickCumulative, volatilityCumulative) = (result.tickCumulative, result.volatilityCumulative);
  }

  /// @inheritdoc IVolatilityOracle
  function getTimepoints(
    uint32[] memory secondsAgos
  ) external view override returns (int56[] memory tickCumulatives, uint88[] memory volatilityCumulatives) {
    // `volatilityCumulative` values for timestamps after the last timepoint _should not_ be compared: they may differ due to interpolation errors
    (, int24 tick, , ) = _getPoolState();
    return timepoints.getTimepoints(_blockTimestamp(), secondsAgos, tick, timepointIndex);
  }

  /// @inheritdoc IVolatilityOracle
  function prepayTimepointsStorageSlots(uint16 startIndex, uint16 amount) external override {
    require(!timepoints[startIndex].initialized); // if not initialized, then all subsequent ones too
    require(amount > 0 && type(uint16).max - startIndex >= amount);

    unchecked {
      for (uint256 i = startIndex; i < startIndex + amount; ++i) {
        timepoints[i].blockTimestamp = 1; // will be overwritten
      }
    }
  }

  // ###### Fee manager ######

  /// @inheritdoc IDynamicFeeManager
  function changeFeeConfiguration(AlgebraFeeConfiguration calldata _config) external override {
    require(msg.sender == pluginFactory || IAlgebraFactory(factory).hasRoleOrOwner(ALGEBRA_BASE_PLUGIN_MANAGER, msg.sender));
    AdaptiveFee.validateFeeConfiguration(_config);

    _feeConfig = _config.pack(); // pack struct to uint144 and write in storage
    emit FeeConfiguration(_config);
  }

  /// @inheritdoc IAlgebraDynamicFeePlugin
  function getCurrentFee() external view override returns (uint16 fee) {
    uint16 lastIndex = timepointIndex;
    AlgebraFeeConfigurationU144 feeConfig_ = _feeConfig;
    if (feeConfig_.alpha1() | feeConfig_.alpha2() == 0) return feeConfig_.baseFee();

    uint16 oldestIndex = timepoints.getOldestIndex(lastIndex);
    (, int24 tick, , ) = _getPoolState();

    uint88 volatilityAverage = timepoints.getAverageVolatility(_blockTimestamp(), tick, lastIndex, oldestIndex);
    return AdaptiveFee.getFee(volatilityAverage, feeConfig_);
  }

  function _getFeeAtLastTimepoint(
    uint16 lastTimepointIndex,
    uint16 oldestTimepointIndex,
    int24 currentTick,
    AlgebraFeeConfigurationU144 feeConfig_
  ) internal view returns (uint16 fee) {
    if (feeConfig_.alpha1() | feeConfig_.alpha2() == 0) return feeConfig_.baseFee();

    uint88 volatilityAverage = timepoints.getAverageVolatility(_blockTimestamp(), currentTick, lastTimepointIndex, oldestTimepointIndex);
    return AdaptiveFee.getFee(volatilityAverage, feeConfig_);
  }

  // ###### Farming plugin ######

  /// @inheritdoc IFarmingPlugin
  function setIncentive(address newIncentive) external override {
    bool toConnect = newIncentive != address(0);
    bool accessAllowed;
    if (toConnect) {
      accessAllowed = msg.sender == IBasePluginV1Factory(pluginFactory).farmingAddress();
    } else {
      // we allow the one who connected the incentive to disconnect it,
      // even if he no longer has the rights to connect incentives
      if (_lastIncentiveOwner != address(0)) accessAllowed = msg.sender == _lastIncentiveOwner;
      if (!accessAllowed) accessAllowed = msg.sender == IBasePluginV1Factory(pluginFactory).farmingAddress();
    }
    require(accessAllowed, 'Not allowed to set incentive');

    bool isPluginConnected = _getPluginInPool() == address(this);
    if (toConnect) require(isPluginConnected, 'Plugin not attached');

    address currentIncentive = incentive;
    require(currentIncentive != newIncentive, 'Already active');
    if (toConnect) require(currentIncentive == address(0), 'Has active incentive');

    incentive = newIncentive;
    emit Incentive(newIncentive);

    if (toConnect) {
      _lastIncentiveOwner = msg.sender; // write creator of this incentive
    } else {
      _lastIncentiveOwner = address(0);
    }

    if (isPluginConnected) {
      _updatePluginConfigInPool();
    }
  }

  /// @inheritdoc IFarmingPlugin
  function isIncentiveConnected(address targetIncentive) external view override returns (bool) {
    if (incentive != targetIncentive) return false;
    if (_getPluginInPool() != address(this)) return false;
    (, , , uint8 pluginConfig) = _getPoolState();
    if (!pluginConfig.hasFlag(Plugins.AFTER_SWAP_FLAG)) return false;

    return true;
  }

  // ###### withdrawalFeePlugin ######

  function setModifyLiquidityEntrypoint(address newModifyLiquidityEntrypoint) external override {
    require(IAlgebraFactory(factory).hasRoleOrOwner(ALGEBRA_BASE_PLUGIN_MANAGER, msg.sender));
    modifyLiquidityEntrypoint = newModifyLiquidityEntrypoint;
  }

  // ###### HOOKS ######

  function beforeInitialize(address, uint160) external override onlyPool returns (bytes4) {
    _updatePluginConfigInPool();
    return IAlgebraPlugin.beforeInitialize.selector;
  }

  function afterInitialize(address, uint160, int24 tick) external override onlyPool returns (bytes4) {
    uint32 _timestamp = _blockTimestamp();
    timepoints.initialize(_timestamp, tick);

    lastTimepointTimestamp = _timestamp;
    isInitialized = true;

    IAlgebraPool(pool).setFee(_feeConfig.baseFee());
    return IAlgebraPlugin.afterInitialize.selector;
  }

  function beforeModifyPosition(address caller, address, int24, int24, int128, bytes calldata) external override onlyPool returns (bytes4) {
    if (modifyLiquidityEntrypoint != address(0)) {
      require(caller == modifyLiquidityEntrypoint, 'only modifyLiquidityEntrypoint');
    }
    return IAlgebraPlugin.beforeModifyPosition.selector;
  }

  /// @dev unused
  function afterModifyPosition(address, address, int24, int24, int128, uint256, uint256, bytes calldata) external override onlyPool returns (bytes4) {
    _updatePluginConfigInPool(); // should not be called, reset config
    return IAlgebraPlugin.afterModifyPosition.selector;
  }

  function beforeSwap(address, address, bool, int256, uint160, bool, bytes calldata) external override onlyPool returns (bytes4) {
    _writeTimepointAndUpdateFee();
    return IAlgebraPlugin.beforeSwap.selector;
  }

  function afterSwap(address, address, bool zeroToOne, int256, uint160, int256, int256, bytes calldata) external override onlyPool returns (bytes4) {
    address _incentive = incentive;
    if (_incentive != address(0)) {
      (, int24 tick, , ) = _getPoolState();
      IAlgebraVirtualPool(_incentive).crossTo(tick, zeroToOne);
    } else {
      _updatePluginConfigInPool(); // should not be called, reset config
    }

    return IAlgebraPlugin.afterSwap.selector;
  }

  /// @dev unused
  function beforeFlash(address, address, uint256, uint256, bytes calldata) external override onlyPool returns (bytes4) {
    _updatePluginConfigInPool(); // should not be called, reset config
    return IAlgebraPlugin.beforeFlash.selector;
  }

  /// @dev unused
  function afterFlash(address, address, uint256, uint256, uint256, uint256, bytes calldata) external override onlyPool returns (bytes4) {
    _updatePluginConfigInPool(); // should not be called, reset config
    return IAlgebraPlugin.afterFlash.selector;
  }

  function _updatePluginConfigInPool() internal {
    uint8 newPluginConfig = defaultPluginConfig;
    if (incentive != address(0)) {
      newPluginConfig |= uint8(Plugins.AFTER_SWAP_FLAG);
    }

    (, , , uint8 currentPluginConfig) = _getPoolState();
    if (currentPluginConfig != newPluginConfig) {
      IAlgebraPool(pool).setPluginConfig(newPluginConfig);
    }
  }

  function _writeTimepointAndUpdateFee() internal {
    // single SLOAD
    uint16 _lastIndex = timepointIndex;
    uint32 _lastTimepointTimestamp = lastTimepointTimestamp;
    AlgebraFeeConfigurationU144 feeConfig_ = _feeConfig; // struct packed in uint144
    bool _isInitialized = isInitialized;
    require(_isInitialized, 'Not initialized');

    uint32 currentTimestamp = _blockTimestamp();

    if (_lastTimepointTimestamp == currentTimestamp) return;

    (, int24 tick, uint16 fee, ) = _getPoolState();
    (uint16 newLastIndex, uint16 newOldestIndex) = timepoints.write(_lastIndex, currentTimestamp, tick);

    timepointIndex = newLastIndex;
    lastTimepointTimestamp = currentTimestamp;

    uint16 newFee = _getFeeAtLastTimepoint(newLastIndex, newOldestIndex, tick, feeConfig_);
    if (newFee != fee) {
      IAlgebraPool(pool).setFee(newFee);
    }
  }
}

File 18 of 27 : AlgebraFeeConfiguration.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @notice coefficients for sigmoids: α / (1 + e^( (β-x) / γ))
/// @dev alpha1 + alpha2 + baseFee must be <= type(uint16).max
struct AlgebraFeeConfiguration {
  uint16 alpha1; // max value of the first sigmoid
  uint16 alpha2; // max value of the second sigmoid
  uint32 beta1; // shift along the x-axis for the first sigmoid
  uint32 beta2; // shift along the x-axis for the second sigmoid
  uint16 gamma1; // horizontal stretch factor for the first sigmoid
  uint16 gamma2; // horizontal stretch factor for the second sigmoid
  uint16 baseFee; // minimum possible fee
}

File 19 of 27 : IAlgebraBasePluginV1.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
pragma abicoder v2;

import './plugins/IVolatilityOracle.sol';
import './plugins/IDynamicFeeManager.sol';
import './plugins/IFarmingPlugin.sol';

/// @title The interface for the AlgebraBasePluginV1
/// @notice This contract combines the standard implementations of the volatility oracle and the dynamic fee manager
/// @dev This contract stores timepoints and calculates adaptive fee and statistical averages
interface IAlgebraBasePluginV1 is IVolatilityOracle, IDynamicFeeManager, IFarmingPlugin {
  /// @notice Initialize the plugin externally
  /// @dev This function allows to initialize the plugin if it was created after the pool was created
  function initialize() external;

  /// @notice Set the entrypoint address
  /// @param newModifyLiquidityEntrypoint New entrypoint address
  function setModifyLiquidityEntrypoint(address newModifyLiquidityEntrypoint) external;

  /// @notice Returns the address of entrypoint
  /// @return The modifyLiquidityEntrypoint contract address
  function modifyLiquidityEntrypoint() external view returns (address);
}

File 20 of 27 : IAlgebraVirtualPool.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title The interface for the virtual pool
/// @dev Used to calculate active liquidity in farmings
interface IAlgebraVirtualPool {
  /// @dev This function is called by the main pool if an initialized ticks are crossed by swap.
  /// If any one of crossed ticks is also initialized in a virtual pool it should be crossed too
  /// @param targetTick The target tick up to which we need to cross all active ticks
  /// @param zeroToOne Swap direction
  function crossTo(int24 targetTick, bool zeroToOne) external returns (bool success);
}

File 21 of 27 : IBasePluginV1Factory.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
pragma abicoder v2;

import '@cryptoalgebra/integral-core/contracts/interfaces/plugin/IAlgebraPluginFactory.sol';

import '../base/AlgebraFeeConfiguration.sol';

/// @title The interface for the BasePluginV1Factory
/// @notice This contract creates Algebra default plugins for Algebra liquidity pools
interface IBasePluginV1Factory is IAlgebraPluginFactory {
  /// @notice Emitted when the default fee configuration is changed
  /// @param newConfig The structure with dynamic fee parameters
  /// @dev See the AdaptiveFee library for more details
  event DefaultFeeConfiguration(AlgebraFeeConfiguration newConfig);

  /// @notice Emitted when the farming address is changed
  /// @param newFarmingAddress The farming address after the address was changed
  event FarmingAddress(address newFarmingAddress);

  /// @notice Emitted when the entrypoint address is changed
  /// @param newModifyLiquidityEntrypoint The entrypoint address after the address was changed
  event ModifyLiquidityEntrypoint(address newModifyLiquidityEntrypoint);

  /// @notice The hash of 'ALGEBRA_BASE_PLUGIN_FACTORY_ADMINISTRATOR' used as role
  /// @dev allows to change settings of BasePluginV1Factory
  function ALGEBRA_BASE_PLUGIN_FACTORY_ADMINISTRATOR() external pure returns (bytes32);

  /// @notice Returns the address of AlgebraFactory
  /// @return The AlgebraFactory contract address
  function algebraFactory() external view returns (address);

  /// @notice Returns the address of entrypoint contract
  /// @return The modifyLiquidityEntrypoint contract address
  function modifyLiquidityEntrypoint() external view returns (address);

  /// @notice Current default dynamic fee configuration
  /// @dev See the AdaptiveFee struct for more details about params.
  /// This value is set by default in new plugins
  function defaultFeeConfiguration()
    external
    view
    returns (uint16 alpha1, uint16 alpha2, uint32 beta1, uint32 beta2, uint16 gamma1, uint16 gamma2, uint16 baseFee);

  /// @notice Returns current farming address
  /// @return The farming contract address
  function farmingAddress() external view returns (address);

  /// @notice Returns address of plugin created for given AlgebraPool
  /// @param pool The address of AlgebraPool
  /// @return The address of corresponding plugin
  function pluginByPool(address pool) external view returns (address);

  /// @notice Create plugin for already existing pool
  /// @param token0 The address of first token in pool
  /// @param token1 The address of second token in pool
  /// @return The address of created plugin
  function createPluginForExistingPool(address token0, address token1) external returns (address);

  /// @notice Changes initial fee configuration for new pools
  /// @dev changes coefficients for sigmoids: α / (1 + e^( (β-x) / γ))
  /// alpha1 + alpha2 + baseFee (max possible fee) must be <= type(uint16).max and gammas must be > 0
  /// @param newConfig new default fee configuration. See the #AdaptiveFee.sol library for details
  function setDefaultFeeConfiguration(AlgebraFeeConfiguration calldata newConfig) external;

  /// @dev updates farmings manager address on the factory
  /// @param newFarmingAddress The new tokenomics contract address
  function setFarmingAddress(address newFarmingAddress) external;

  /// @dev updates entrypoint address on the plugin factory
  /// @param newModifyLiquidityEntrypoint The new entrypoint address
  function setModifyLiquidityEntrypoint(address newModifyLiquidityEntrypoint) external;
}

File 22 of 27 : IDynamicFeeManager.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
pragma abicoder v2;

import '@cryptoalgebra/integral-core/contracts/interfaces/plugin/IAlgebraDynamicFeePlugin.sol';
import '../../base/AlgebraFeeConfiguration.sol';

/// @title The interface for the Algebra dynamic fee manager
/// @dev This contract calculates adaptive fee
interface IDynamicFeeManager is IAlgebraDynamicFeePlugin {
  /// @notice Emitted when the fee configuration is changed
  /// @param feeConfig The structure with dynamic fee parameters
  /// @dev See the AdaptiveFee struct for more details
  event FeeConfiguration(AlgebraFeeConfiguration feeConfig);

  /// @notice Current dynamic fee configuration
  /// @dev See the AdaptiveFee struct for more details
  function feeConfig() external view returns (uint16 alpha1, uint16 alpha2, uint32 beta1, uint32 beta2, uint16 gamma1, uint16 gamma2, uint16 baseFee);

  /// @notice Changes fee configuration for the pool
  function changeFeeConfiguration(AlgebraFeeConfiguration calldata feeConfig) external;
}

File 23 of 27 : IFarmingPlugin.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title The interface for the Algebra farming plugin
/// @dev This contract used for virtual pools in farms
interface IFarmingPlugin {
  /// @notice Emitted when new activeIncentive is set
  /// @param newIncentive The address of the new incentive
  event Incentive(address newIncentive);

  /// @notice Returns the address of the pool the plugin is created for
  /// @return address of the pool
  function pool() external view returns (address);

  /// @notice Connects or disconnects an incentive.
  /// @dev Only farming can connect incentives.
  /// The one who connected it and the current farming has the right to disconnect the incentive.
  /// @param newIncentive The address associated with the incentive or zero address
  function setIncentive(address newIncentive) external;

  /// @notice Checks if the incentive is connected to pool
  /// @dev Returns false if the plugin has a different incentive set, the plugin is not connected to the pool,
  /// or the plugin configuration is incorrect.
  /// @param targetIncentive The address of the incentive to be checked
  /// @return Indicates whether the target incentive is active
  function isIncentiveConnected(address targetIncentive) external view returns (bool);

  /// @notice Returns the address of active incentive
  /// @dev if there is no active incentive at the moment, incentiveAddress would be equal to address(0)
  /// @return  The address associated with the current active incentive
  function incentive() external view returns (address);
}

File 24 of 27 : IVolatilityOracle.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title The interface for the Algebra volatility oracle
/// @dev This contract stores timepoints and calculates statistical averages
interface IVolatilityOracle {
  /// @notice Returns data belonging to a certain timepoint
  /// @param index The index of timepoint in the array
  /// @dev There is more convenient function to fetch a timepoint: getTimepoints(). Which requires not an index but seconds
  /// @return initialized Whether the timepoint has been initialized and the values are safe to use
  /// @return blockTimestamp The timestamp of the timepoint
  /// @return tickCumulative The tick multiplied by seconds elapsed for the life of the pool as of the timepoint timestamp
  /// @return volatilityCumulative Cumulative standard deviation for the life of the pool as of the timepoint timestamp
  /// @return tick The tick at blockTimestamp
  /// @return averageTick Time-weighted average tick
  /// @return windowStartIndex Index of closest timepoint >= WINDOW seconds ago
  function timepoints(
    uint256 index
  )
    external
    view
    returns (
      bool initialized,
      uint32 blockTimestamp,
      int56 tickCumulative,
      uint88 volatilityCumulative,
      int24 tick,
      int24 averageTick,
      uint16 windowStartIndex
    );

  /// @notice Returns the index of the last timepoint that was written.
  /// @return index of the last timepoint written
  function timepointIndex() external view returns (uint16);

  /// @notice Returns the timestamp of the last timepoint that was written.
  /// @return timestamp of the last timepoint
  function lastTimepointTimestamp() external view returns (uint32);

  /// @notice Returns information about whether oracle is initialized
  /// @return true if oracle is initialized, otherwise false
  function isInitialized() external view returns (bool);

  /// @dev Reverts if a timepoint at or before the desired timepoint timestamp does not exist.
  /// 0 may be passed as `secondsAgo' to return the current cumulative values.
  /// If called with a timestamp falling between two timepoints, returns the counterfactual accumulator values
  /// at exactly the timestamp between the two timepoints.
  /// @dev `volatilityCumulative` values for timestamps after the last timepoint _should not_ be compared because they may differ due to interpolation errors
  /// @param secondsAgo The amount of time to look back, in seconds, at which point to return a timepoint
  /// @return tickCumulative The cumulative tick since the pool was first initialized, as of `secondsAgo`
  /// @return volatilityCumulative The cumulative volatility value since the pool was first initialized, as of `secondsAgo`
  function getSingleTimepoint(uint32 secondsAgo) external view returns (int56 tickCumulative, uint88 volatilityCumulative);

  /// @notice Returns the accumulator values as of each time seconds ago from the given time in the array of `secondsAgos`
  /// @dev Reverts if `secondsAgos` > oldest timepoint
  /// @dev `volatilityCumulative` values for timestamps after the last timepoint _should not_ be compared because they may differ due to interpolation errors
  /// @param secondsAgos Each amount of time to look back, in seconds, at which point to return a timepoint
  /// @return tickCumulatives The cumulative tick since the pool was first initialized, as of each `secondsAgo`
  /// @return volatilityCumulatives The cumulative volatility values since the pool was first initialized, as of each `secondsAgo`
  function getTimepoints(uint32[] memory secondsAgos) external view returns (int56[] memory tickCumulatives, uint88[] memory volatilityCumulatives);

  /// @notice Fills uninitialized timepoints with nonzero value
  /// @dev Can be used to reduce the gas cost of future swaps
  /// @param startIndex The start index, must be not initialized
  /// @param amount of slots to fill, startIndex + amount must be <= type(uint16).max
  function prepayTimepointsStorageSlots(uint16 startIndex, uint16 amount) external;
}

File 25 of 27 : AdaptiveFee.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.20;

import '@cryptoalgebra/integral-core/contracts/libraries/Constants.sol';
import '../base/AlgebraFeeConfiguration.sol';
import '../types/AlgebraFeeConfigurationU144.sol';

/// @title AdaptiveFee
/// @notice Calculates fee based on combination of sigmoids
/// @dev Version for AlgebraBasePluginV1
library AdaptiveFee {
  uint16 internal constant INITIAL_MIN_FEE = 0.01e4; // 0.01%

  /// @notice Returns default initial fee configuration
  function initialFeeConfiguration() internal pure returns (AlgebraFeeConfiguration memory) {
    return
      AlgebraFeeConfiguration({
        alpha1: 3000 - INITIAL_MIN_FEE, // max value of the first sigmoid in hundredths of a bip, i.e. 1e-6
        alpha2: 15000 - 3000, // max value of the second sigmoid in hundredths of a bip, i.e. 1e-6
        beta1: 360, // shift along the x-axis (volatility) for the first sigmoid
        beta2: 60000, // shift along the x-axis (volatility) for the second sigmoid
        gamma1: 59, // horizontal stretch factor for the first sigmoid
        gamma2: 8500, // horizontal stretch factor for the second sigmoid
        baseFee: INITIAL_MIN_FEE // in hundredths of a bip, i.e. 1e-6
      });
  }

  /// @notice Validates fee configuration.
  /// @dev Maximum fee value capped by baseFee + alpha1 + alpha2 must be <= type(uint16).max
  /// gammas must be > 0
  function validateFeeConfiguration(AlgebraFeeConfiguration memory _config) internal pure {
    require(uint256(_config.alpha1) + uint256(_config.alpha2) + uint256(_config.baseFee) <= type(uint16).max, 'Max fee exceeded');
    require(_config.gamma1 != 0 && _config.gamma2 != 0, 'Gammas must be > 0');
  }

  /// @notice Calculates fee based on formula:
  /// baseFee + sigmoid1(volatility) + sigmoid2(volatility)
  /// maximum value capped by baseFee + alpha1 + alpha2
  function getFee(uint88 volatility, AlgebraFeeConfigurationU144 config) internal pure returns (uint16 fee) {
    unchecked {
      volatility /= 15; // normalize for 15 sec interval
      uint256 sumOfSigmoids = sigmoid(volatility, config.gamma1(), config.alpha1(), config.beta1()) +
        sigmoid(volatility, config.gamma2(), config.alpha2(), config.beta2());

      uint256 result = uint256(config.baseFee()) + sumOfSigmoids;
      assert(result <= type(uint16).max); // should always be true

      return uint16(result); // safe since alpha1 + alpha2 + baseFee _must_ be <= type(uint16).max
    }
  }

  /// @notice calculates α / (1 + e^( (β-x) / γ))
  /// that is a sigmoid with a maximum value of α, x-shifted by β, and stretched by γ
  /// @dev returns uint256 for fuzzy testing. Guaranteed that the result is not greater than alpha
  function sigmoid(uint256 x, uint16 g, uint16 alpha, uint256 beta) internal pure returns (uint256 res) {
    unchecked {
      if (x > beta) {
        x = x - beta;
        if (x >= 6 * uint256(g)) return alpha; // so x < 19 bits
        uint256 g4 = uint256(g) ** 4; // < 64 bits (4*16)
        uint256 ex = expXg4(x, g, g4); // < 155 bits
        res = (alpha * ex) / (g4 + ex); // in worst case: (16 + 155 bits) / 155 bits
        // so res <= alpha
      } else {
        x = beta - x;
        if (x >= 6 * uint256(g)) return 0; // so x < 19 bits
        uint256 g4 = uint256(g) ** 4; // < 64 bits (4*16)
        uint256 ex = g4 + expXg4(x, g, g4); // < 156 bits
        res = (alpha * g4) / ex; // in worst case: (16 + 128 bits) / 156 bits
        // g8 <= ex, so res <= alpha
      }
    }
  }

  /// @notice calculates e^(x/g) * g^4 in a series, since (around zero):
  /// e^x = 1 + x + x^2/2 + ... + x^n/n! + ...
  /// e^(x/g) = 1 + x/g + x^2/(2*g^2) + ... + x^(n)/(g^n * n!) + ...
  /// @dev has good accuracy only if x/g < 6
  function expXg4(uint256 x, uint16 g, uint256 gHighestDegree) internal pure returns (uint256 res) {
    uint256 closestValue; // nearest 'table' value of e^(x/g), multiplied by 10^20
    assembly {
      let xdg := div(x, g)
      switch xdg
      case 0 {
        closestValue := 100000000000000000000 // 1
      }
      case 1 {
        closestValue := 271828182845904523536 // ~= e
      }
      case 2 {
        closestValue := 738905609893065022723 // ~= e^2
      }
      case 3 {
        closestValue := 2008553692318766774092 // ~= e^3
      }
      case 4 {
        closestValue := 5459815003314423907811 // ~= e^4
      }
      default {
        closestValue := 14841315910257660342111 // ~= e^5
      }

      x := mod(x, g)
    }

    unchecked {
      if (x >= g / 2) {
        // (x - closestValue) >= 0.5, so closestValue := closestValue * e^0.5
        x -= g / 2;
        closestValue = (closestValue * 164872127070012814684) / 1e20;
      }

      // After calculating the closestValue x/g is <= 0.5, so that the series in the neighborhood of zero converges with sufficient speed
      uint256 xLowestDegree = x;
      res = gHighestDegree; // g**4, res < 64 bits

      gHighestDegree /= g; // g**3
      res += xLowestDegree * gHighestDegree; // g**4 + x*g**3, res < 68

      gHighestDegree /= g; // g**2
      xLowestDegree *= x; // x**2
      // g**4 + x * g**3 + (x**2 * g**2) / 2, res < 71
      res += (xLowestDegree * gHighestDegree) / 2;

      gHighestDegree /= g; // g
      xLowestDegree *= x; // x**3
      // g^4 + x * g^3 + (x^2 * g^2)/2 + x^3(g*4 + x)/24, res < 73
      res += (xLowestDegree * g * 4 + xLowestDegree * x) / 24;

      // res = g^4 * (1 + x/g + x^2/(2*g^2) + x^3/(6*g^3) + x^4/(24*g^4)) * closestValue / 10^20, closestValue < 75 bits, res < 155
      res = (res * closestValue) / (1e20);
    }
  }
}

File 26 of 27 : VolatilityOracle.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.20;

/// @title VolatilityOracle
/// @notice Provides price and volatility data useful for a wide variety of system designs
/// @dev Instances of stored oracle data, "timepoints", are collected in the oracle array
/// Timepoints are overwritten when the full length of the timepoints array is populated.
/// The most recent timepoint is available by passing 0 to getSingleTimepoint().
/// Version for AlgebraBasePluginV1
library VolatilityOracle {
  /// @notice `target` timestamp is older than oldest timepoint
  error targetIsTooOld();

  /// @notice oracle is initialized already
  error volatilityOracleAlreadyInitialized();

  uint32 internal constant WINDOW = 1 days;
  uint256 private constant UINT16_MODULO = 65536;

  struct Timepoint {
    bool initialized; // whether or not the timepoint is initialized
    uint32 blockTimestamp; // the block timestamp of the timepoint
    int56 tickCumulative; // the tick accumulator, i.e. tick * time elapsed since the pool was first initialized
    uint88 volatilityCumulative; // the volatility accumulator; overflow after ~34800 years is desired :)
    int24 tick; // tick at this blockTimestamp
    int24 averageTick; // average tick at this blockTimestamp (for WINDOW seconds)
    uint16 windowStartIndex; // closest timepoint lte WINDOW seconds ago (or oldest timepoint), _should be used only from last timepoint_!
  }

  /// @notice Initialize the timepoints array by writing the first slot. Called once for the lifecycle of the timepoints array
  /// @param self The stored timepoints array
  /// @param time The time of the oracle initialization, via block.timestamp truncated to uint32
  /// @param tick Initial tick
  function initialize(Timepoint[UINT16_MODULO] storage self, uint32 time, int24 tick) internal {
    Timepoint storage _zero = self[0];
    if (_zero.initialized) revert volatilityOracleAlreadyInitialized();
    (_zero.initialized, _zero.blockTimestamp, _zero.tick, _zero.averageTick) = (true, time, tick, tick);
  }

  /// @notice Writes a timepoint to the array
  /// @dev Writable at most once per block. `lastIndex` must be tracked externally.
  /// @param self The stored timepoints array
  /// @param lastIndex The index of the timepoint that was most recently written to the timepoints array
  /// @param blockTimestamp The timestamp of the new timepoint
  /// @param tick The active tick at the time of the new timepoint
  /// @return indexUpdated The new index of the most recently written element in the timepoints array
  /// @return oldestIndex The new index of the oldest timepoint
  function write(
    Timepoint[UINT16_MODULO] storage self,
    uint16 lastIndex,
    uint32 blockTimestamp,
    int24 tick
  ) internal returns (uint16 indexUpdated, uint16 oldestIndex) {
    Timepoint memory last = self[lastIndex];
    // early return if we've already written a timepoint this block
    if (last.blockTimestamp == blockTimestamp) return (lastIndex, 0);

    // get next index considering overflow
    unchecked {
      indexUpdated = lastIndex + 1;
    }

    // check if we have overflow in the past
    if (self[indexUpdated].initialized) oldestIndex = indexUpdated;

    (int24 avgTick, uint16 windowStartIndex) = _getAverageTickCasted(
      self,
      blockTimestamp,
      tick,
      lastIndex,
      oldestIndex,
      last.blockTimestamp,
      last.tickCumulative
    );
    unchecked {
      // overflow of indexes is desired
      if (windowStartIndex == indexUpdated) windowStartIndex++; // important, since this value can be used to narrow the search
      self[indexUpdated] = _createNewTimepoint(last, blockTimestamp, tick, avgTick, windowStartIndex);
      if (oldestIndex == indexUpdated) oldestIndex++; // previous oldest index has been overwritten
    }
  }

  /// @dev Reverts if a timepoint at or before the desired timepoint timestamp does not exist.
  /// 0 may be passed as `secondsAgo' to return the current cumulative values.
  /// If called with a timestamp falling between two timepoints, returns the counterfactual accumulator values
  /// at exactly the timestamp between the two timepoints.
  /// @dev `volatilityCumulative` values for timestamps after the last timepoint _should not_ be compared because they may differ due to interpolation errors
  /// @param self The stored timepoints array
  /// @param time The current block timestamp
  /// @param secondsAgo The amount of time to look back, in seconds, at which point to return a timepoint
  /// @param tick The current tick
  /// @param lastIndex The index of the timepoint that was most recently written to the timepoints array
  /// @param oldestIndex The index of the oldest timepoint
  /// @return targetTimepoint desired timepoint or it's interpolation
  function getSingleTimepoint(
    Timepoint[UINT16_MODULO] storage self,
    uint32 time,
    uint32 secondsAgo,
    int24 tick,
    uint16 lastIndex,
    uint16 oldestIndex
  ) internal view returns (Timepoint memory targetTimepoint) {
    unchecked {
      uint32 target = time - secondsAgo;
      (Timepoint storage beforeOrAt, Timepoint storage atOrAfter, bool samePoint, ) = _getTimepointsAt(self, time, target, lastIndex, oldestIndex);

      targetTimepoint = beforeOrAt;
      if (target == targetTimepoint.blockTimestamp) return targetTimepoint; // we're at the left boundary
      if (samePoint) {
        // if target is newer than last timepoint
        (int24 avgTick, uint16 windowStartIndex) = _getAverageTickCasted(
          self,
          target,
          tick,
          lastIndex,
          oldestIndex,
          targetTimepoint.blockTimestamp,
          targetTimepoint.tickCumulative
        );
        return _createNewTimepoint(targetTimepoint, target, tick, avgTick, windowStartIndex);
      }

      (uint32 timestampAfter, int56 tickCumulativeAfter) = (atOrAfter.blockTimestamp, atOrAfter.tickCumulative);
      if (target == timestampAfter) return atOrAfter; // we're at the right boundary

      // we're in the middle
      (uint32 timepointTimeDelta, uint32 targetDelta) = (timestampAfter - targetTimepoint.blockTimestamp, target - targetTimepoint.blockTimestamp);

      targetTimepoint.tickCumulative +=
        ((tickCumulativeAfter - targetTimepoint.tickCumulative) / int56(uint56(timepointTimeDelta))) *
        int56(uint56(targetDelta));
      targetTimepoint.volatilityCumulative +=
        ((atOrAfter.volatilityCumulative - targetTimepoint.volatilityCumulative) / timepointTimeDelta) *
        targetDelta;
    }
  }

  /// @notice Returns the accumulator values as of each time seconds ago from the given time in the array of `secondsAgos`
  /// @dev Reverts if `secondsAgos` > oldest timepoint
  /// @dev `volatilityCumulative` values for timestamps after the last timepoint _should not_ be compared because they may differ due to interpolation errors
  /// @param self The stored timepoints array
  /// @param currentTime The current block.timestamp
  /// @param secondsAgos Each amount of time to look back, in seconds, at which point to return a timepoint
  /// @param tick The current tick
  /// @param lastIndex The index of the timepoint that was most recently written to the timepoints array
  /// @return tickCumulatives The cumulative time-weighted tick since the pool was first initialized, as of each `secondsAgo`
  /// @return volatilityCumulatives The cumulative volatility values since the pool was first initialized, as of each `secondsAgo`
  function getTimepoints(
    Timepoint[UINT16_MODULO] storage self,
    uint32 currentTime,
    uint32[] memory secondsAgos,
    int24 tick,
    uint16 lastIndex
  ) internal view returns (int56[] memory tickCumulatives, uint88[] memory volatilityCumulatives) {
    uint256 secondsLength = secondsAgos.length;
    tickCumulatives = new int56[](secondsLength);
    volatilityCumulatives = new uint88[](secondsLength);

    uint16 oldestIndex = getOldestIndex(self, lastIndex);
    Timepoint memory current;
    unchecked {
      for (uint256 i; i < secondsLength; ++i) {
        current = getSingleTimepoint(self, currentTime, secondsAgos[i], tick, lastIndex, oldestIndex);
        (tickCumulatives[i], volatilityCumulatives[i]) = (current.tickCumulative, current.volatilityCumulative);
      }
    }
  }

  /// @notice Returns the index of the oldest timepoint
  /// @param self The stored timepoints array
  /// @param lastIndex The index of the timepoint that was most recently written to the timepoints array
  /// @return oldestIndex The index of the oldest timepoint
  function getOldestIndex(Timepoint[UINT16_MODULO] storage self, uint16 lastIndex) internal view returns (uint16 oldestIndex) {
    unchecked {
      uint16 nextIndex = lastIndex + 1; // considering overflow
      if (self[nextIndex].initialized) oldestIndex = nextIndex; // check if we have overflow in the past
    }
  }

  /// @notice Returns average volatility in the range from currentTime-WINDOW to currentTime
  /// @param self The stored timepoints array
  /// @param currentTime The current block.timestamp
  /// @param tick The current tick
  /// @param lastIndex The index of the timepoint that was most recently written to the timepoints array
  /// @param oldestIndex The index of the oldest timepoint
  /// @return volatilityAverage The average volatility in the recent range
  function getAverageVolatility(
    Timepoint[UINT16_MODULO] storage self,
    uint32 currentTime,
    int24 tick,
    uint16 lastIndex,
    uint16 oldestIndex
  ) internal view returns (uint88 volatilityAverage) {
    unchecked {
      Timepoint storage lastTimepoint = self[lastIndex];
      bool timeAtLastTimepoint = lastTimepoint.blockTimestamp == currentTime;
      uint88 lastCumulativeVolatility = lastTimepoint.volatilityCumulative;
      uint16 windowStartIndex = lastTimepoint.windowStartIndex; // index of timepoint before of at lastTimepoint.blockTimestamp - WINDOW

      if (!timeAtLastTimepoint) {
        lastCumulativeVolatility = _getVolatilityCumulativeAt(self, currentTime, 0, tick, lastIndex, oldestIndex);
      }

      uint32 oldestTimestamp = self[oldestIndex].blockTimestamp;
      if (_lteConsideringOverflow(oldestTimestamp, currentTime - WINDOW, currentTime)) {
        // oldest timepoint is earlier than 24 hours ago
        uint88 cumulativeVolatilityAtStart;
        if (timeAtLastTimepoint) {
          // interpolate cumulative volatility to avoid search. Since the last timepoint has _just_ been written, we know for sure
          // that the start of the window is between windowStartIndex and windowStartIndex + 1
          (oldestTimestamp, cumulativeVolatilityAtStart) = (self[windowStartIndex].blockTimestamp, self[windowStartIndex].volatilityCumulative);

          uint32 timeDeltaBetweenPoints = self[windowStartIndex + 1].blockTimestamp - oldestTimestamp;

          cumulativeVolatilityAtStart +=
            ((self[windowStartIndex + 1].volatilityCumulative - cumulativeVolatilityAtStart) * (currentTime - WINDOW - oldestTimestamp)) /
            timeDeltaBetweenPoints;
        } else {
          cumulativeVolatilityAtStart = _getVolatilityCumulativeAt(self, currentTime, WINDOW, tick, lastIndex, oldestIndex);
        }

        return ((lastCumulativeVolatility - cumulativeVolatilityAtStart) / WINDOW); // sample is big enough to ignore bias of variance
      } else if (currentTime != oldestTimestamp) {
        // recorded timepoints are not enough, so we will extrapolate
        uint88 _oldestVolatilityCumulative = self[oldestIndex].volatilityCumulative;
        uint32 unbiasedDenominator = currentTime - oldestTimestamp;
        if (unbiasedDenominator > 1) unbiasedDenominator--; // Bessel's correction for "small" sample
        return ((lastCumulativeVolatility - _oldestVolatilityCumulative) / unbiasedDenominator);
      }
    }
  }

  // ##### further functions are private to the library, but some are made internal for fuzzy testing #####

  /// @notice Transforms a previous timepoint into a new timepoint, given the passage of time and the current tick and liquidity values
  /// @dev blockTimestamp _must_ be chronologically equal to or greater than last.blockTimestamp, safe for 0 or 1 overflows
  /// @dev The function changes the structure given to the input, and does not create a new one
  /// @param last The specified timepoint to be used in creation of new timepoint
  /// @param blockTimestamp The timestamp of the new timepoint
  /// @param tick The active tick at the time of the new timepoint
  /// @param averageTick The average tick at the time of the new timepoint
  /// @param windowStartIndex The index of closest timepoint >= WINDOW seconds ago
  /// @return Timepoint The newly populated timepoint
  function _createNewTimepoint(
    Timepoint memory last,
    uint32 blockTimestamp,
    int24 tick,
    int24 averageTick,
    uint16 windowStartIndex
  ) internal pure returns (Timepoint memory) {
    unchecked {
      uint32 delta = blockTimestamp - last.blockTimestamp; // overflow is desired
      // We don't create a new structure in memory to save gas. Therefore, the function changes the old structure
      last.initialized = true;
      last.blockTimestamp = blockTimestamp;
      last.tickCumulative += int56(tick) * int56(uint56(delta));
      last.volatilityCumulative += uint88(_volatilityOnRange(int256(uint256(delta)), tick, tick, last.averageTick, averageTick)); // always fits 88 bits
      last.tick = tick;
      last.averageTick = averageTick;
      last.windowStartIndex = windowStartIndex;
      return last;
    }
  }

  /// @notice Calculates volatility between two sequential timepoints with resampling to 1 sec frequency
  /// @param dt Timedelta between timepoints, must be within uint32 range
  /// @param tick0 The tick after the left timepoint, must be within int24 range
  /// @param tick1 The tick at the right timepoint, must be within int24 range
  /// @param avgTick0 The average tick at the left timepoint, must be within int24 range
  /// @param avgTick1 The average tick at the right timepoint, must be within int24 range
  /// @return volatility The volatility between two sequential timepoints
  /// If the requirements for the parameters are met, it always fits 88 bits
  function _volatilityOnRange(int256 dt, int256 tick0, int256 tick1, int256 avgTick0, int256 avgTick1) internal pure returns (uint256 volatility) {
    // On the time interval from the previous timepoint to the current
    // we can represent tick and average tick change as two straight lines:
    // tick = k*t + b, where k and b are some constants
    // avgTick = p*t + q, where p and q are some constants
    // we want to get sum of (tick(t) - avgTick(t))^2 for every t in the interval (0; dt]
    // so: (tick(t) - avgTick(t))^2 = ((k*t + b) - (p*t + q))^2 = (k-p)^2 * t^2 + 2(k-p)(b-q)t + (b-q)^2
    // since everything except t is a constant, we need to use progressions for t and t^2:
    // sum(t) for t from 1 to dt = dt*(dt + 1)/2 = sumOfSequence
    // sum(t^2) for t from 1 to dt = dt*(dt+1)*(2dt + 1)/6 = sumOfSquares
    // so result will be: (k-p)^2 * sumOfSquares + 2(k-p)(b-q)*sumOfSequence + dt*(b-q)^2
    unchecked {
      int256 k = (tick1 - tick0) - (avgTick1 - avgTick0); // (k - p)*dt
      int256 b = (tick0 - avgTick0) * dt; // (b - q)*dt
      int256 sumOfSequence = dt * (dt + 1); // sumOfSequence * 2
      int256 sumOfSquares = sumOfSequence * (2 * dt + 1); // sumOfSquares * 6
      volatility = uint256((k ** 2 * sumOfSquares + 6 * b * k * sumOfSequence + 6 * dt * b ** 2) / (6 * dt ** 2));
    }
  }

  /// @notice Calculates average tick for WINDOW seconds at the moment of `time`
  /// @dev Guaranteed that the result is within the bounds of int24
  /// @return avgTick The average tick
  /// @return windowStartIndex The index of closest timepoint <= WINDOW seconds ago
  function _getAverageTickCasted(
    Timepoint[UINT16_MODULO] storage self,
    uint32 time,
    int24 tick,
    uint16 lastIndex,
    uint16 oldestIndex,
    uint32 lastTimestamp,
    int56 lastTickCumulative
  ) internal view returns (int24 avgTick, uint16 windowStartIndex) {
    (int256 _avgTick, uint256 _windowStartIndex) = _getAverageTick(self, time, tick, lastIndex, oldestIndex, lastTimestamp, lastTickCumulative);
    unchecked {
      (avgTick, windowStartIndex) = (int24(_avgTick), uint16(_windowStartIndex)); // overflow in uint16(_windowStartIndex) is desired
    }
  }

  /// @notice Calculates average tick for WINDOW seconds at the moment of `currentTime`
  /// @dev Guaranteed that the result is within the bounds of int24, but result is not casted
  /// @return avgTick int256 for fuzzy tests
  /// @return windowStartIndex The index of closest timepoint <= WINDOW seconds ago
  function _getAverageTick(
    Timepoint[UINT16_MODULO] storage self,
    uint32 currentTime,
    int24 tick,
    uint16 lastIndex,
    uint16 oldestIndex,
    uint32 lastTimestamp,
    int56 lastTickCumulative
  ) internal view returns (int256 avgTick, uint256 windowStartIndex) {
    (uint32 oldestTimestamp, int56 oldestTickCumulative) = (self[oldestIndex].blockTimestamp, self[oldestIndex].tickCumulative);

    unchecked {
      int56 currentTickCumulative = lastTickCumulative + int56(tick) * int56(uint56(currentTime - lastTimestamp)); // update with new data
      if (!_lteConsideringOverflow(oldestTimestamp, currentTime - WINDOW, currentTime)) {
        // if oldest is newer than WINDOW ago
        if (currentTime == oldestTimestamp) return (tick, oldestIndex);
        return ((currentTickCumulative - oldestTickCumulative) / int56(uint56(currentTime - oldestTimestamp)), oldestIndex);
      }

      if (_lteConsideringOverflow(lastTimestamp, currentTime - WINDOW, currentTime)) {
        // if last timepoint is older or equal than WINDOW ago
        return (tick, lastIndex);
      } else {
        int56 tickCumulativeAtStart;
        (tickCumulativeAtStart, windowStartIndex) = _getTickCumulativeAt(self, currentTime, WINDOW, tick, lastIndex, oldestIndex);

        //    current-WINDOW  last   current
        // _________*____________*_______*_
        //          ||||||||||||||||||||||
        avgTick = (currentTickCumulative - tickCumulativeAtStart) / int56(uint56(WINDOW));
      }
    }
  }

  /// @notice comparator for 32-bit timestamps
  /// @dev safe for 0 or 1 overflows, a and b _must_ be chronologically before or equal to currentTime
  /// @param a A comparison timestamp from which to determine the relative position of `currentTime`
  /// @param b From which to determine the relative position of `currentTime`
  /// @param currentTime A timestamp truncated to 32 bits
  /// @return res Whether `a` is chronologically <= `b`
  function _lteConsideringOverflow(uint32 a, uint32 b, uint32 currentTime) internal pure returns (bool res) {
    res = a > currentTime;
    if (res == b > currentTime) res = a <= b; // if both are on the same side
  }

  /// @notice Calculates cumulative volatility at the moment of `time` - `secondsAgo`
  /// @dev More optimal than via `getSingleTimepoint`
  /// @return volatilityCumulative The cumulative volatility
  function _getVolatilityCumulativeAt(
    Timepoint[UINT16_MODULO] storage self,
    uint32 time,
    uint32 secondsAgo,
    int24 tick,
    uint16 lastIndex,
    uint16 oldestIndex
  ) internal view returns (uint88 volatilityCumulative) {
    unchecked {
      uint32 target = time - secondsAgo;
      (Timepoint storage beforeOrAt, Timepoint storage atOrAfter, bool samePoint, ) = _getTimepointsAt(self, time, target, lastIndex, oldestIndex);

      (uint32 timestampBefore, uint88 volatilityCumulativeBefore) = (beforeOrAt.blockTimestamp, beforeOrAt.volatilityCumulative);
      if (target == timestampBefore) return volatilityCumulativeBefore; // we're at the left boundary
      if (samePoint) {
        // since target != beforeOrAt.blockTimestamp, `samePoint` means that target is newer than last timepoint
        (int24 avgTick, ) = _getAverageTickCasted(self, target, tick, lastIndex, oldestIndex, timestampBefore, beforeOrAt.tickCumulative);

        return (volatilityCumulativeBefore +
          uint88(_volatilityOnRange(int256(uint256(target - timestampBefore)), tick, tick, beforeOrAt.averageTick, avgTick)));
      }

      (uint32 timestampAfter, uint88 volatilityCumulativeAfter) = (atOrAfter.blockTimestamp, atOrAfter.volatilityCumulative);
      if (target == timestampAfter) return volatilityCumulativeAfter; // we're at the right boundary

      // we're in the middle
      (uint32 timepointTimeDelta, uint32 targetDelta) = (timestampAfter - timestampBefore, target - timestampBefore);
      return volatilityCumulativeBefore + ((volatilityCumulativeAfter - volatilityCumulativeBefore) / timepointTimeDelta) * targetDelta;
    }
  }

  /// @notice Calculates cumulative tick at the moment of `time` - `secondsAgo`
  /// @dev More optimal than via `getSingleTimepoint`
  /// @return tickCumulative The cumulative tick
  /// @return indexBeforeOrAt The index of closest timepoint before or at the moment of `time` - `secondsAgo`
  function _getTickCumulativeAt(
    Timepoint[UINT16_MODULO] storage self,
    uint32 time,
    uint32 secondsAgo,
    int24 tick,
    uint16 lastIndex,
    uint16 oldestIndex
  ) internal view returns (int56 tickCumulative, uint256 indexBeforeOrAt) {
    unchecked {
      uint32 target = time - secondsAgo;
      (Timepoint storage beforeOrAt, Timepoint storage atOrAfter, bool samePoint, uint256 _indexBeforeOrAt) = _getTimepointsAt(
        self,
        time,
        target,
        lastIndex,
        oldestIndex
      );

      (uint32 timestampBefore, int56 tickCumulativeBefore) = (beforeOrAt.blockTimestamp, beforeOrAt.tickCumulative);
      if (target == timestampBefore) return (tickCumulativeBefore, _indexBeforeOrAt); // we're at the left boundary
      // since target != timestampBefore, `samePoint` means that target is newer than last timepoint
      if (samePoint) return ((tickCumulativeBefore + int56(tick) * int56(uint56(target - timestampBefore))), _indexBeforeOrAt); // if target is newer than last timepoint

      (uint32 timestampAfter, int56 tickCumulativeAfter) = (atOrAfter.blockTimestamp, atOrAfter.tickCumulative);
      if (target == timestampAfter) return (tickCumulativeAfter, uint16(_indexBeforeOrAt + 1)); // we're at the right boundary

      // we're in the middle
      (uint32 timepointTimeDelta, uint32 targetDelta) = (timestampAfter - timestampBefore, target - timestampBefore);
      return (
        tickCumulativeBefore + ((tickCumulativeAfter - tickCumulativeBefore) / int56(uint56(timepointTimeDelta))) * int56(uint56(targetDelta)),
        _indexBeforeOrAt
      );
    }
  }

  /// @notice Returns closest timepoint or timepoints to the moment of `target`
  /// @return beforeOrAt The timepoint recorded before, or at, the target
  /// @return atOrAfter The timepoint recorded at, or after, the target
  /// @return samePoint Are `beforeOrAt` and `atOrAfter` the same or not
  /// @return indexBeforeOrAt The index of closest timepoint before or at the moment of `target`
  function _getTimepointsAt(
    Timepoint[UINT16_MODULO] storage self,
    uint32 currentTime,
    uint32 target,
    uint16 lastIndex,
    uint16 oldestIndex
  ) private view returns (Timepoint storage beforeOrAt, Timepoint storage atOrAfter, bool samePoint, uint256 indexBeforeOrAt) {
    Timepoint storage lastTimepoint = self[lastIndex];
    uint32 lastTimepointTimestamp = lastTimepoint.blockTimestamp;
    uint16 windowStartIndex = lastTimepoint.windowStartIndex;

    // if target is newer than last timepoint
    if (target == currentTime || _lteConsideringOverflow(lastTimepointTimestamp, target, currentTime)) {
      return (lastTimepoint, lastTimepoint, true, lastIndex);
    }

    bool useHeuristic;
    unchecked {
      if (lastTimepointTimestamp - target <= WINDOW) {
        // We can limit the scope of the search. It is safe because when the array overflows,
        // `windowsStartIndex` cannot point to the overwritten timepoint (check at `write(...)`)
        oldestIndex = windowStartIndex;
        useHeuristic = target == currentTime - WINDOW; // heuristic will optimize search for timepoints close to `currentTime - WINDOW`
      }
      uint32 oldestTimestamp = self[oldestIndex].blockTimestamp;

      if (!_lteConsideringOverflow(oldestTimestamp, target, currentTime)) revert targetIsTooOld();
      if (oldestTimestamp == target) return (self[oldestIndex], self[oldestIndex], true, oldestIndex);

      // no need to search if we already know the answer
      if (lastIndex == oldestIndex + 1) return (self[oldestIndex], lastTimepoint, false, oldestIndex);
    }

    (beforeOrAt, atOrAfter, indexBeforeOrAt) = _binarySearch(self, currentTime, target, lastIndex, oldestIndex, useHeuristic);
    return (beforeOrAt, atOrAfter, false, indexBeforeOrAt);
  }

  /// @notice Fetches the timepoints beforeOrAt and atOrAfter a target, i.e. where [beforeOrAt, atOrAfter] is satisfied.
  /// The result may be the same timepoint, or adjacent timepoints.
  /// @dev The answer must be older than the most recent timepoint and younger, or the same age as, the oldest timepoint
  /// @param self The stored timepoints array
  /// @param currentTime The current block.timestamp
  /// @param target The timestamp at which the timepoint should be
  /// @param upperIndex The index of the upper border of search range
  /// @param lowerIndex The index of the lower border of search range
  /// @param withHeuristic Use heuristic for first guess or not (optimize for targets close to `lowerIndex`)
  /// @return beforeOrAt The timepoint recorded before, or at, the target
  /// @return atOrAfter The timepoint recorded at, or after, the target
  function _binarySearch(
    Timepoint[UINT16_MODULO] storage self,
    uint32 currentTime,
    uint32 target,
    uint16 upperIndex,
    uint16 lowerIndex,
    bool withHeuristic
  ) private view returns (Timepoint storage beforeOrAt, Timepoint storage atOrAfter, uint256 indexBeforeOrAt) {
    unchecked {
      uint256 left = lowerIndex; // oldest timepoint
      uint256 right = upperIndex < lowerIndex ? upperIndex + UINT16_MODULO : upperIndex; // newest timepoint considering one index overflow
      (beforeOrAt, atOrAfter, indexBeforeOrAt) = _binarySearchInternal(self, currentTime, target, left, right, withHeuristic);
    }
  }

  function _binarySearchInternal(
    Timepoint[UINT16_MODULO] storage self,
    uint32 currentTime,
    uint32 target,
    uint256 left,
    uint256 right,
    bool withHeuristic
  ) private view returns (Timepoint storage beforeOrAt, Timepoint storage atOrAfter, uint256 indexBeforeOrAt) {
    unchecked {
      if (withHeuristic && right - left > 2) {
        indexBeforeOrAt = left + 1; // heuristic for first guess
      } else {
        indexBeforeOrAt = (left + right) >> 1; // "middle" point between the boundaries
      }
      beforeOrAt = self[uint16(indexBeforeOrAt)]; // checking the "middle" point between the boundaries
      atOrAfter = beforeOrAt; // to suppress compiler warning; will be overridden
      bool firstIteration = true;
      do {
        (bool initializedBefore, uint32 timestampBefore) = (beforeOrAt.initialized, beforeOrAt.blockTimestamp);
        if (initializedBefore) {
          if (_lteConsideringOverflow(timestampBefore, target, currentTime)) {
            // is current point before or at `target`?
            atOrAfter = self[uint16(indexBeforeOrAt + 1)]; // checking the next point after "middle"
            (bool initializedAfter, uint32 timestampAfter) = (atOrAfter.initialized, atOrAfter.blockTimestamp);
            if (initializedAfter) {
              if (_lteConsideringOverflow(target, timestampAfter, currentTime)) {
                // is the "next" point after or at `target`?
                return (beforeOrAt, atOrAfter, indexBeforeOrAt); // the only fully correct way to finish
              }
              left = indexBeforeOrAt + 1; // "next" point is before the `target`, so looking in the right half
            } else {
              // beforeOrAt is initialized and <= target, and next timepoint is uninitialized
              // should be impossible if initial boundaries and `target` are correct
              return (beforeOrAt, beforeOrAt, indexBeforeOrAt);
            }
          } else {
            right = indexBeforeOrAt - 1; // current point is after the `target`, so looking in the left half
          }
        } else {
          // we've landed on an uninitialized timepoint, keep searching higher
          // should be impossible if initial boundaries and `target` are correct
          left = indexBeforeOrAt + 1;
        }
        // use heuristic if looking in the right half after first iteration
        bool useHeuristic = firstIteration && withHeuristic && left == indexBeforeOrAt + 1;
        if (useHeuristic && right - left > 16) {
          indexBeforeOrAt = left + 8;
        } else {
          indexBeforeOrAt = (left + right) >> 1; // calculating the new "middle" point index after updating the bounds
        }
        beforeOrAt = self[uint16(indexBeforeOrAt)]; // update the "middle" point pointer
        firstIteration = false;
      } while (true);
    }
  }
}

File 27 of 27 : AlgebraFeeConfigurationU144.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.20;

import '../base/AlgebraFeeConfiguration.sol';

type AlgebraFeeConfigurationU144 is uint144;
using AlgebraFeeConfigurationU144Lib for AlgebraFeeConfigurationU144 global;

/// @title AdaptiveFee packed configuration library
/// @notice Used to interact with uint144-packed fee config
/// @dev Structs are not packed in storage with neighboring values, but uint144 can be packed
library AlgebraFeeConfigurationU144Lib {
  uint256 private constant UINT16_MASK = 0xFFFF;
  uint256 private constant UINT32_MASK = 0xFFFFFFFF;

  // alpha1 offset is 0
  uint256 private constant ALPHA2_OFFSET = 16;
  uint256 private constant BETA1_OFFSET = 32;
  uint256 private constant BETA2_OFFSET = 64;
  uint256 private constant GAMMA1_OFFSET = 96;
  uint256 private constant GAMMA2_OFFSET = 112;
  uint256 private constant BASE_FEE_OFFSET = 128;

  function pack(AlgebraFeeConfiguration memory config) internal pure returns (AlgebraFeeConfigurationU144) {
    uint144 _config = uint144(
      (uint256(config.baseFee) << BASE_FEE_OFFSET) |
        (uint256(config.gamma2) << GAMMA2_OFFSET) |
        (uint256(config.gamma1) << GAMMA1_OFFSET) |
        (uint256(config.beta2) << BETA2_OFFSET) |
        (uint256(config.beta1) << BETA1_OFFSET) |
        (uint256(config.alpha2) << ALPHA2_OFFSET) |
        uint256(config.alpha1)
    );

    return AlgebraFeeConfigurationU144.wrap(_config);
  }

  function alpha1(AlgebraFeeConfigurationU144 config) internal pure returns (uint16 _alpha1) {
    assembly {
      _alpha1 := and(UINT16_MASK, config)
    }
  }

  function alpha2(AlgebraFeeConfigurationU144 config) internal pure returns (uint16 _alpha2) {
    assembly {
      _alpha2 := and(UINT16_MASK, shr(ALPHA2_OFFSET, config))
    }
  }

  function beta1(AlgebraFeeConfigurationU144 config) internal pure returns (uint32 _beta1) {
    assembly {
      _beta1 := and(UINT32_MASK, shr(BETA1_OFFSET, config))
    }
  }

  function beta2(AlgebraFeeConfigurationU144 config) internal pure returns (uint32 _beta2) {
    assembly {
      _beta2 := and(UINT32_MASK, shr(BETA2_OFFSET, config))
    }
  }

  function gamma1(AlgebraFeeConfigurationU144 config) internal pure returns (uint16 _gamma1) {
    assembly {
      _gamma1 := and(UINT16_MASK, shr(GAMMA1_OFFSET, config))
    }
  }

  function gamma2(AlgebraFeeConfigurationU144 config) internal pure returns (uint16 _gamma2) {
    assembly {
      _gamma2 := and(UINT16_MASK, shr(GAMMA2_OFFSET, config))
    }
  }

  function baseFee(AlgebraFeeConfigurationU144 config) internal pure returns (uint16 _baseFee) {
    assembly {
      _baseFee := and(UINT16_MASK, shr(BASE_FEE_OFFSET, config))
    }
  }
}

Settings
{
  "evmVersion": "paris",
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "metadata": {
    "bytecodeHash": "none"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"_algebraFactory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint16","name":"alpha1","type":"uint16"},{"internalType":"uint16","name":"alpha2","type":"uint16"},{"internalType":"uint32","name":"beta1","type":"uint32"},{"internalType":"uint32","name":"beta2","type":"uint32"},{"internalType":"uint16","name":"gamma1","type":"uint16"},{"internalType":"uint16","name":"gamma2","type":"uint16"},{"internalType":"uint16","name":"baseFee","type":"uint16"}],"indexed":false,"internalType":"struct AlgebraFeeConfiguration","name":"newConfig","type":"tuple"}],"name":"DefaultFeeConfiguration","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newFarmingAddress","type":"address"}],"name":"FarmingAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newModifyLiquidityEntrypoint","type":"address"}],"name":"ModifyLiquidityEntrypoint","type":"event"},{"inputs":[],"name":"ALGEBRA_BASE_PLUGIN_FACTORY_ADMINISTRATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"algebraFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"createPlugin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"name":"createPluginForExistingPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultFeeConfiguration","outputs":[{"internalType":"uint16","name":"alpha1","type":"uint16"},{"internalType":"uint16","name":"alpha2","type":"uint16"},{"internalType":"uint32","name":"beta1","type":"uint32"},{"internalType":"uint32","name":"beta2","type":"uint32"},{"internalType":"uint16","name":"gamma1","type":"uint16"},{"internalType":"uint16","name":"gamma2","type":"uint16"},{"internalType":"uint16","name":"baseFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"farmingAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"modifyLiquidityEntrypoint","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"poolAddress","type":"address"}],"name":"pluginByPool","outputs":[{"internalType":"address","name":"pluginAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"alpha1","type":"uint16"},{"internalType":"uint16","name":"alpha2","type":"uint16"},{"internalType":"uint32","name":"beta1","type":"uint32"},{"internalType":"uint32","name":"beta2","type":"uint32"},{"internalType":"uint16","name":"gamma1","type":"uint16"},{"internalType":"uint16","name":"gamma2","type":"uint16"},{"internalType":"uint16","name":"baseFee","type":"uint16"}],"internalType":"struct AlgebraFeeConfiguration","name":"newConfig","type":"tuple"}],"name":"setDefaultFeeConfiguration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFarmingAddress","type":"address"}],"name":"setFarmingAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newWithDrawalFeePlugin","type":"address"}],"name":"setModifyLiquidityEntrypoint","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a060405234801561001057600080fd5b50604051620058da380380620058da83398101604081905261003191610240565b6001600160a01b0381166080526100466101b8565b80516000805460208401516040808601516060870151608088015160a089015160c09099015161ffff908116600160801b0261ffff60801b199a8216600160701b0261ffff60701b199383166c01000000000000000000000000029390931663ffffffff60601b1963ffffffff958616680100000000000000000263ffffffff60401b19969097166401000000000295909516600160201b600160601b0319988416620100000263ffffffff19909a1693909b16929092179790971795909516979097179190911716919091179390931793909316929092178255517fe04232512a5cb82c08e0f9b1f51432930cd7a0b7ea9f9f916f080cb0b4ac644b916101aa91600060e082019050825461ffff8082168452808260101c16602085015263ffffffff808360201c166040860152808360401c16606086015250808260601c166080850152808260701c1660a0850152808260801c1660c0850152505092915050565b60405180910390a1506102a0565b6040805160e08082018352600080835260208301819052828401819052606083018190526080830181905260a0830181905260c0830152825190810190925290806102066064610bb8610270565b61ffff168152612ee06020820152610168604082015261ea606060820152603b608082015261213460a0820152606460c090910152919050565b60006020828403121561025257600080fd5b81516001600160a01b038116811461026957600080fd5b9392505050565b61ffff82811682821603908082111561029957634e487b7160e01b600052601160045260246000fd5b5092915050565b6080516155f4620002e660003960008181610238015281816102f0015281816105ab0152818161074c015281816107db015281816109af0152610b8101526155f46000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80639b27d43211610081578063cddff2691161005b578063cddff2691461026d578063cdef16f6146102a2578063f718949a146102d857600080fd5b80639b27d43214610213578063a7b64b0414610233578063b001f6181461025a57600080fd5b8063692afddf116100b2578063692afddf146101cb5780638a2ade58146101e05780639533ff101461020057600080fd5b806327733026146100ce5780634e09a96a1461010b575b600080fd5b6100e16100dc366004610e70565b6102eb565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6000546101839061ffff8082169162010000810482169163ffffffff6401000000008304811692680100000000000000008104909116916c0100000000000000000000000082048116916e01000000000000000000000000000081048216917001000000000000000000000000000000009091041687565b6040805161ffff9889168152968816602088015263ffffffff9586169087015293909216606085015284166080840152831660a08301529190911660c082015260e001610102565b6101de6101d9366004610ea9565b610557565b005b6001546100e19073ffffffffffffffffffffffffffffffffffffffff1681565b6100e161020e366004610ecd565b610732565b6002546100e19073ffffffffffffffffffffffffffffffffffffffff1681565b6100e17f000000000000000000000000000000000000000000000000000000000000000081565b6101de610268366004610ea9565b610787565b6102947f267da724c255813ae00f4522fe843cb70148a4b8099cbc5af64f9a4151e55ed681565b604051908152602001610102565b6100e16102b0366004610ea9565b60036020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6101de6102e6366004610f18565b61095b565b6000807f000000000000000000000000000000000000000000000000000000000000000090508073ffffffffffffffffffffffffffffffffffffffff1663e8ae2b698273ffffffffffffffffffffffffffffffffffffffff1663b500a48b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610378573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061039c9190610f30565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526004810191909152336024820152604401602060405180830381865afa1580156103f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041a9190610f49565b61042357600080fd5b6040517fd9a641e100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015284811660248301526000919083169063d9a641e190604401602060405180830381865afa15801561049b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104bf9190610f6b565b905073ffffffffffffffffffffffffffffffffffffffff8116610543576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f506f6f6c206e6f7420657869737400000000000000000000000000000000000060448201526064015b60405180910390fd5b61054c81610aeb565b925050505b92915050565b6040517fe8ae2b690000000000000000000000000000000000000000000000000000000081527f267da724c255813ae00f4522fe843cb70148a4b8099cbc5af64f9a4151e55ed660048201523360248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e8ae2b6990604401602060405180830381865afa158015610607573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062b9190610f49565b610691576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4f6e6c792061646d696e6973747261746f720000000000000000000000000000604482015260640161053a565b60025473ffffffffffffffffffffffffffffffffffffffff8083169116036106b857600080fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f8abb9ad4b75fd2e4ce33e4cdab5ecb4fe75b728b2bd17c31dd0a049723d39663906020015b60405180910390a150565b60003373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461077657600080fd5b61077f84610aeb565b949350505050565b6040517fe8ae2b690000000000000000000000000000000000000000000000000000000081527f267da724c255813ae00f4522fe843cb70148a4b8099cbc5af64f9a4151e55ed660048201523360248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e8ae2b6990604401602060405180830381865afa158015610837573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085b9190610f49565b6108c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4f6e6c792061646d696e6973747261746f720000000000000000000000000000604482015260640161053a565b60015473ffffffffffffffffffffffffffffffffffffffff8083169116036108e857600080fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f56b9e8342f530796ceed0d5529abdcdeae6e4f2ac1dc456ceb73bbda898e0cd390602001610727565b6040517fe8ae2b690000000000000000000000000000000000000000000000000000000081527f267da724c255813ae00f4522fe843cb70148a4b8099cbc5af64f9a4151e55ed660048201523360248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e8ae2b6990604401602060405180830381865afa158015610a0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2f9190610f49565b610a95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4f6e6c792061646d696e6973747261746f720000000000000000000000000000604482015260640161053a565b610aac610aa736839003830183610fc5565b610d26565b806000610ab982826110b6565b9050507fe04232512a5cb82c08e0f9b1f51432930cd7a0b7ea9f9f916f080cb0b4ac644b8160405161072791906112be565b73ffffffffffffffffffffffffffffffffffffffff81811660009081526003602052604081205490911615610b7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920637265617465640000000000000000000000000000000000604482015260640161053a565b6000827f000000000000000000000000000000000000000000000000000000000000000030604051610bad90610e41565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f080158015610bf6573d6000803e3d6000fd5b50604080517f1d39215e00000000000000000000000000000000000000000000000000000000815260005461ffff8082166004840152601082901c8116602484015263ffffffff602083901c811660448501529382901c9093166064830152606081901c83166084830152607081901c831660a483015260801c90911660c482015290915073ffffffffffffffffffffffffffffffffffffffff821690631d39215e9060e401600060405180830381600087803b158015610cb657600080fd5b505af1158015610cca573d6000803e3d6000fd5b5050505073ffffffffffffffffffffffffffffffffffffffff928316600090815260036020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016938216939093179092555090565b60c08101516020820151825161ffff92831691610d4891908416908416611367565b610d529190611367565b1115610dba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4d61782066656520657863656564656400000000000000000000000000000000604482015260640161053a565b608081015161ffff1615801590610dd8575060a081015161ffff1615155b610e3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f47616d6d6173206d757374206265203e20300000000000000000000000000000604482015260640161053a565b50565b614246806113a283390190565b73ffffffffffffffffffffffffffffffffffffffff81168114610e3e57600080fd5b60008060408385031215610e8357600080fd5b8235610e8e81610e4e565b91506020830135610e9e81610e4e565b809150509250929050565b600060208284031215610ebb57600080fd5b8135610ec681610e4e565b9392505050565b600080600060608486031215610ee257600080fd5b8335610eed81610e4e565b92506020840135610efd81610e4e565b91506040840135610f0d81610e4e565b809150509250925092565b600060e08284031215610f2a57600080fd5b50919050565b600060208284031215610f4257600080fd5b5051919050565b600060208284031215610f5b57600080fd5b81518015158114610ec657600080fd5b600060208284031215610f7d57600080fd5b8151610ec681610e4e565b61ffff81168114610e3e57600080fd5b8035610fa381610f88565b919050565b63ffffffff81168114610e3e57600080fd5b8035610fa381610fa8565b600060e08284031215610fd757600080fd5b60405160e0810181811067ffffffffffffffff82111715611021577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405261102d83610f98565b815261103b60208401610f98565b602082015261104c60408401610fba565b604082015261105d60608401610fba565b606082015261106e60808401610f98565b608082015261107f60a08401610f98565b60a082015261109060c08401610f98565b60c08201529392505050565b6000813561055181610f88565b6000813561055181610fa8565b81356110c181610f88565b61ffff811690508154817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000821617835560208401356110ff81610f88565b63ffff00008160101b16905080837fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000841617178455604085013561114281610fa8565b67ffffffff000000008160201b16847fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008516178317178555505050506111ca61118d606084016110a9565b82547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff1660409190911b6bffffffff000000000000000016178255565b6112186111d96080840161109c565b82547fffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffff1660609190911b6dffff00000000000000000000000016178255565b61126861122760a0840161109c565b82547fffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffff1660709190911b6fffff000000000000000000000000000016178255565b6112ba61127760c0840161109c565b82547fffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffff1660809190911b71ffff0000000000000000000000000000000016178255565b5050565b60e0810182356112cd81610f88565b61ffff90811683526020840135906112e482610f88565b90811660208401526040840135906112fb82610fa8565b63ffffffff918216604085015260608501359161131783610fa8565b91909116606084015260808401359061132f82610f88565b16608083015261134160a08401610f98565b61ffff1660a083015261135660c08401610f98565b61ffff811660c08401525092915050565b80820180821115610551577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfe60e06040523480156200001157600080fd5b50604051620042463803806200424683398101604081905262000034916200006f565b6001600160a01b0390811660c0529182166080521660a052620000b9565b80516001600160a01b03811681146200006a57600080fd5b919050565b6000806000606084860312156200008557600080fd5b620000908462000052565b9250620000a06020850162000052565b9150620000b06040850162000052565b90509250925092565b60805160a05160c0516141176200012f6000396000818161060a01528181610b8101528181610c8901526111d101526000818161068501526109cf01526000818161022f0152818161139b015281816118ac01528181611aaa01528181611cb701528181611d310152611dcb01526141176000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c806374eceae6116100f95780639cb5a96311610097578063da70523511610071578063da7052351461055a578063e63015f01461056d578063f5985d3514610580578063f70d9362146105aa57600080fd5b80639cb5a963146105135780639d3a524114610526578063d68520101461054757600080fd5b806382dd6522116100d357806382dd65221461049257806388f2e862146104a55780638de0a8ee146104de5780639b27d432146104f157600080fd5b806374eceae6146104095780637c1fe0c8146104775780638129fc1c1461048a57600080fd5b806331b25d1a116101665780635e2411b2116101405780635e2411b2146103b6578063636fd804146103c9578063689ea370146103dc578063692afddf146103f657600080fd5b806331b25d1a14610345578063343d37ff1461037a578063392e53cd1461038d57600080fd5b80631d39215e116101975780631d39215e146102765780631d4632ac1461028b5780631e5eb1d0146102ad57600080fd5b8063029c1cb7146101be5780630786feb61461020757806316f0115b1461022a575b600080fd5b6101d16101cc36600461378c565b6105b2565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b62010000546102179061ffff1681565b60405161ffff90911681526020016101fe565b6102517f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101fe565b610289610284366004613836565b6105f2565b005b62010002546102519073ffffffffffffffffffffffffffffffffffffffff1681565b6102fd620100005461ffff67010000000000000090910481811692601082901c83169263ffffffff602084901c811693604081901c90911692606082901c831692607083901c81169260801c1690565b6040805161ffff9889168152968816602088015263ffffffff9586169087015293909216606085015284166080840152831660a08301529190911660c082015260e0016101fe565b61036c7f8e8000aba5b365c0be9685da1153f7f096e76d1ecfb42c050ae1e387aa65b4f581565b6040519081526020016101fe565b6101d161038836600461384e565b61081e565b62010000546103a6906601000000000000900460ff1681565b60405190151581526020016101fe565b6101d16103c43660046138e3565b61085e565b6101d16103d7366004613982565b610940565b6103e460c581565b60405160ff90911681526020016101fe565b6102896104043660046139bb565b61097b565b61041c6104173660046139d8565b610aa1565b60408051971515885263ffffffff909616602088015260069490940b948601949094526affffffffffffffffffffff9091166060850152600290810b60808501529190910b60a083015261ffff1660c082015260e0016101fe565b6102896104853660046139bb565b610b5d565b61028961103a565b6101d16104a03660046139f1565b61131f565b6104b86104b3366004613a50565b611481565b6040805160069390930b83526affffffffffffffffffffff9091166020830152016101fe565b6101d16104ec366004613a6b565b6114d5565b62010001546102519073ffffffffffffffffffffffffffffffffffffffff1681565b6101d1610521366004613ae7565b611514565b610539610534366004613c13565b61162a565b6040516101fe929190613cc0565b6101d1610555366004613d4b565b611666565b610289610568366004613dce565b6116a7565b6103a661057b3660046139bb565b61176e565b6201000080546105959163ffffffff91041681565b60405163ffffffff90911681526020016101fe565b6102176117f2565b60006105bc611894565b6105c4611935565b507f029c1cb70000000000000000000000000000000000000000000000000000000098975050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016148061070557506040517fe8ae2b690000000000000000000000000000000000000000000000000000000081527f8e8000aba5b365c0be9685da1153f7f096e76d1ecfb42c050ae1e387aa65b4f560048201523360248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e8ae2b6990604401602060405180830381865afa1580156106e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107059190613dfc565b61070e57600080fd5b61072561072036839003830183613e19565b611b28565b6107a661073736839003830183613e19565b600080826000015161ffff166010846020015161ffff16901b6020856040015163ffffffff16901b6040866060015163ffffffff16901b6060876080015161ffff16901b60708860a0015161ffff16901b60808960c0015161ffff16901b171717171717905080915050919050565b6201000060076101000a81548171ffffffffffffffffffffffffffffffffffff021916908371ffffffffffffffffffffffffffffffffffff1602179055507f348d1d6a31fa4a2a3ef887c493549a9500fbb77b5218be0c81a71c553364305a816040516108139190613ed1565b60405180910390a150565b6000610828611894565b610830611c43565b507f343d37ff0000000000000000000000000000000000000000000000000000000098975050505050505050565b6000610868611894565b620100015473ffffffffffffffffffffffffffffffffffffffff161561091357620100015473ffffffffffffffffffffffffffffffffffffffff898116911614610913576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f6f6e6c79206d6f646966794c6971756964697479456e747279706f696e74000060448201526064015b60405180910390fd5b507f5e2411b200000000000000000000000000000000000000000000000000000000979650505050505050565b600061094a611894565b610952611c43565b507f636fd804000000000000000000000000000000000000000000000000000000005b92915050565b6040517fe8ae2b690000000000000000000000000000000000000000000000000000000081527f8e8000aba5b365c0be9685da1153f7f096e76d1ecfb42c050ae1e387aa65b4f560048201523360248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e8ae2b6990604401602060405180830381865afa158015610a2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4f9190613dfc565b610a5857600080fd5b6201000180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600081620100008110610ab357600080fd5b015460ff81169150610100810463ffffffff169065010000000000810460060b906c0100000000000000000000000081046affffffffffffffffffffff1690770100000000000000000000000000000000000000000000008104600290810b917a010000000000000000000000000000000000000000000000000000810490910b907d010000000000000000000000000000000000000000000000000000000000900461ffff1687565b73ffffffffffffffffffffffffffffffffffffffff811615801590600090610c43577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16638a2ade586040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0e9190613f76565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16149050610d47565b620100035473ffffffffffffffffffffffffffffffffffffffff1615610c825750620100035473ffffffffffffffffffffffffffffffffffffffff1633145b80610d47577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16638a2ade586040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d169190613f76565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161490505b80610dae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4e6f7420616c6c6f77656420746f2073657420696e63656e7469766500000000604482015260640161090a565b600030610db9611d2d565b73ffffffffffffffffffffffffffffffffffffffff161490508215610e3f5780610e3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f506c7567696e206e6f7420617474616368656400000000000000000000000000604482015260640161090a565b620100025473ffffffffffffffffffffffffffffffffffffffff9081169085168103610ec7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f416c726561647920616374697665000000000000000000000000000000000000604482015260640161090a565b8315610f4b5773ffffffffffffffffffffffffffffffffffffffff811615610f4b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4861732061637469766520696e63656e74697665000000000000000000000000604482015260640161090a565b6201000280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87169081179091556040519081527f915c5369e6580733735d1c2e30ca20dcaa395697a041033c9f35f80f53525e849060200160405180910390a18315610ffa576201000380547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055611025565b6201000380547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b811561103357611033611c43565b5050505050565b62010000546601000000000000900460ff16156110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920696e697469616c697a656400000000000000000000000000604482015260640161090a565b306110bc611d2d565b73ffffffffffffffffffffffffffffffffffffffff1614611139576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f506c7567696e206e6f7420617474616368656400000000000000000000000000604482015260640161090a565b600080611144611dc3565b5050915091508173ffffffffffffffffffffffffffffffffffffffff166000036111ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f506f6f6c206973206e6f7420696e697469616c697a6564000000000000000000604482015260640161090a565b60004290507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639b27d4326040518163ffffffff1660e01b8152600401602060405180830381865afa15801561123a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061125e9190613f76565b6201000180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790556112b160008284611e68565b6201000080547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff63ffffffff84168302167fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffff90911617660100000000000017905561131a611c43565b505050565b6000611329611894565b4261133660008285611e68565b62010000805466010000000000007fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffff90911663ffffffff841683027fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff161717908190557f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690638e00555390670100000000000000900460801c61ffff166040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815261ffff9091166004820152602401600060405180830381600087803b15801561143d57600080fd5b505af1158015611451573d6000803e3d6000fd5b507f82dd6522000000000000000000000000000000000000000000000000000000009450505050505b9392505050565b600080600061148e611dc3565b5050620100005490925061ffff16905060006114aa8183611f97565b905060006114bc814289878787611fca565b6040810151606090910151909890975095505050505050565b60006114df611894565b6114e7611c43565b507f8de0a8ee000000000000000000000000000000000000000000000000000000005b9695505050505050565b600061151e611894565b620100025473ffffffffffffffffffffffffffffffffffffffff1680156115f2576000611549611dc3565b50506040517f34d33590000000000000000000000000000000000000000000000000000000008152600282900b60048201528c1515602482015290925073ffffffffffffffffffffffffffffffffffffffff841691506334d33590906044016020604051808303816000875af11580156115c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115eb9190613dfc565b50506115fa565b6115fa611c43565b507f9cb5a963000000000000000000000000000000000000000000000000000000009a9950505050505050505050565b6060806000611637611dc3565b505091505061165c6116464290565b6201000054600091908790859061ffff16612300565b9250925050915091565b6000611670611894565b611678611c43565b507fd6852010000000000000000000000000000000000000000000000000000000009998505050505050505050565b60008261ffff166201000081106116c0576116c0613f93565b015460ff16156116cf57600080fd5b60008161ffff161180156116f857508061ffff168261ffff6116f19190613ff1565b61ffff1610155b61170157600080fd5b61ffff82165b81830161ffff1681101561131a57600160008262010000811061172c5761172c613f93565b01805463ffffffff92909216610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff909216919091179055600101611707565b620100025460009073ffffffffffffffffffffffffffffffffffffffff83811691161461179d57506000919050565b306117a6611d2d565b73ffffffffffffffffffffffffffffffffffffffff16146117c957506000919050565b60006117d3611dc3565b9350505050600281166117e95750600092915050565b50600192915050565b620100005460009061ffff80821691670100000000000000900471ffffffffffffffffffffffffffffffffffff81169160109190911c1661ffff82161761ffff1660000361184a57608081901c61ffff169250505090565b60006118568184611f97565b90506000611862611dc3565b5050915050600061187e6118734290565b600090848887612489565b905061188a8185612792565b9550505050505090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611933576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4f6e6c7920706f6f6c2063616e2063616c6c2074686973000000000000000000604482015260640161090a565b565b62010000805461ffff811691810463ffffffff1690670100000000000000810471ffffffffffffffffffffffffffffffffffff16906601000000000000900460ff16806119de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4e6f7420696e697469616c697a65640000000000000000000000000000000000604482015260640161090a565b4263ffffffff808216908516036119f6575050505050565b600080611a01611dc3565b5090935091506000905080611a18818a8787612839565b62010000805463ffffffff891682027fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000090911661ffff85161717905590925090506000611a678383878b612bc0565b90508361ffff168161ffff1614611b1c576040517f8e00555300000000000000000000000000000000000000000000000000000000815261ffff821660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690638e00555390602401600060405180830381600087803b158015611b0357600080fd5b505af1158015611b17573d6000803e3d6000fd5b505050505b50505050505050505050565b60c08101516020820151825161ffff92831691611b4a9190841690841661400c565b611b54919061400c565b1115611bbc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4d61782066656520657863656564656400000000000000000000000000000000604482015260640161090a565b608081015161ffff1615801590611bda575060a081015161ffff1615155b611c40576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f47616d6d6173206d757374206265203e20300000000000000000000000000000604482015260640161090a565b50565b620100025460c59073ffffffffffffffffffffffffffffffffffffffff1615611c6a576002175b6000611c74611dc3565b93505050508160ff168160ff1614611d29576040517fbca57f8100000000000000000000000000000000000000000000000000000000815260ff831660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063bca57f8190602401600060405180830381600087803b158015611d1057600080fd5b505af1158015611d24573d6000803e3d6000fd5b505050505b5050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663ef01df4f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbe9190613f76565b905090565b6000806000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e76c01e46040518163ffffffff1660e01b815260040160c060405180830381865afa158015611e34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e58919061401f565b5093989297509095509350915050565b8254839060ff1615611ea6576040517f1156234600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805460017fffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffff9091167a01000000000000000000000000000000000000000000000000000062ffffff949094169384027fffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffff16177701000000000000000000000000000000000000000000000093909302929092177fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000001661010063ffffffff94909416939093027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169290921717905550565b6000600182018361ffff8216620100008110611fb557611fb5613f93565b015460ff1615611fc3578091505b5092915050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152848603600080806120178b8b868a8a612c06565b506040805160e081018252845460ff811615158252610100810463ffffffff9081166020840181905265010000000000830460060b948401949094526c0100000000000000000000000082046affffffffffffffffffffff166060840152770100000000000000000000000000000000000000000000008204600290810b60808501527a0100000000000000000000000000000000000000000000000000008304900b60a08401527d01000000000000000000000000000000000000000000000000000000000090910461ffff1660c0830152909950939650919450925090851603612106575050505061150a565b8015612144576000806121268d878c8c8c8c602001518d60400151612dfc565b9150915061213787878c8585612e23565b965050505050505061150a565b815463ffffffff610100820481169165010000000000900460060b9086168290036122435750506040805160e081018252925460ff811615158452610100810463ffffffff16602085015265010000000000810460060b918401919091526c0100000000000000000000000081046affffffffffffffffffffff166060840152770100000000000000000000000000000000000000000000008104600290810b60808501527a0100000000000000000000000000000000000000000000000000008204900b60a08401527d010000000000000000000000000000000000000000000000000000000000900461ffff1660c083015250925061150a915050565b602087015160408801518184039188039063ffffffff80831691908416600690810b918603900b81612277576122776140ac565b60408c01805192909105929092020160060b90526060890151865463ffffffff80841692908516916affffffffffffffffffffff6c0100000000000000000000000090910481169190910316816122d0576122d06140ac565b60608c0180516affffffffffffffffffffff93909204939093020116905250505050505050509695505050505050565b825160609081908067ffffffffffffffff81111561232057612320613b95565b604051908082528060200260200182016040528015612349578160200160208202803683370190505b5092508067ffffffffffffffff81111561236557612365613b95565b60405190808252806020026020018201604052801561238e578160200160208202803683370190505b509150600061239d8986611f97565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290529192505b8381101561247b576124088b8b8b84815181106123f8576123f8613f93565b60200260200101518b8b88611fca565b91508160400151826060015187838151811061242657612426613f93565b6020026020010187848151811061243f5761243f613f93565b60200260200101826affffffffffffffffffffff166affffffffffffffffffffff168152508260060b60060b81525050508060010190506123d9565b505050509550959350505050565b600080868461ffff166201000081106124a4576124a4613f93565b018054909150610100810463ffffffff90811690881614906affffffffffffffffffffff6c010000000000000000000000008204169061ffff7d0100000000000000000000000000000000000000000000000000000000009091041682612517576125148a8a60008b8b8b612edf565b91505b60008a8761ffff1662010000811061253157612531613f93565b0154610100900463ffffffff16905061256d817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeae808c018c61304d565b156126cd5760008415612697578b8361ffff1662010000811061259257612592613f93565b0154610100900463ffffffff168c61ffff85166201000081106125b7576125b7613f93565b01549092506c0100000000000000000000000090046affffffffffffffffffffff1690506000828d6001860161ffff166201000081106125f9576125f9613f93565b015463ffffffff610100909104811691909103915081811690848e037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeae800116838f61ffff600189011662010000811061265457612654613f93565b01600001600c9054906101000a90046affffffffffffffffffffff1603026affffffffffffffffffffff168161268c5761268c6140ac565b0482019150506126ab565b6126a88c8c620151808d8d8d612edf565b90505b620151806affffffffffffffffffffff82860316049650505050505050612789565b8063ffffffff168a63ffffffff16146127835760008b8861ffff166201000081106126fa576126fa613f93565b01546c0100000000000000000000000090046affffffffffffffffffffff169050818b03600163ffffffff82161115612750577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b8063ffffffff168286036affffffffffffffffffffff1681612774576127746140ac565b04975050505050505050612789565b50505050505b95945050505050565b6000600f6affffffffffffffffffffff841604925060006127e36affffffffffffffffffffff8516607085901c61ffff16601086901c61ffff16604087901c63ffffffff165b63ffffffff16613075565b6128126affffffffffffffffffffff8616606086901c61ffff1661ffff8716602088901c63ffffffff166127d8565b01905061ffff608084901c8116820190811115612831576128316140db565b949350505050565b6000806000868661ffff1662010000811061285657612856613f93565b6040805160e081018252919092015460ff811615158252610100810463ffffffff9081166020840181905265010000000000830460060b948401949094526c0100000000000000000000000082046affffffffffffffffffffff166060840152770100000000000000000000000000000000000000000000008204600290810b60808501527a0100000000000000000000000000000000000000000000000000008304900b60a08401527d01000000000000000000000000000000000000000000000000000000000090910461ffff1660c083015290925086169003612943578560009250925050612bb7565b856001019250868361ffff1662010000811061296157612961613f93565b015460ff161561296f578291505b6000806129898988888b8888602001518960400151612dfc565b915091508461ffff168161ffff16036129a0576001015b6129ad8388888585612e23565b898661ffff166201000081106129c5576129c5613f93565b825191018054602084015160408501516060860151608087015160a088015160c0909801517fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009095169615157fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff169690961761010063ffffffff90941693909302929092177fffffffffffffffffff000000000000000000000000000000000000ffffffffff166501000000000066ffffffffffffff909216919091027fffffffffffffffffff0000000000000000000000ffffffffffffffffffffffff16176c010000000000000000000000006affffffffffffffffffffff90921691909102177fffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffff167701000000000000000000000000000000000000000000000062ffffff948516027fffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffff16177a0100000000000000000000000000000000000000000000000000009390941692909202929092177fff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d01000000000000000000000000000000000000000000000000000000000061ffff928316021790915585811690851603612bb3576001909301925b5050505b94509492505050565b6000601082901c61ffff1661ffff83161761ffff16600003612beb575061ffff608082901c16612831565b6000612bfa8142868989612489565b905061150a8184612792565b6000806000806000898761ffff16620100008110612c2657612c26613f93565b01805490915063ffffffff610100820481169161ffff7d01000000000000000000000000000000000000000000000000000000000090910416908a8116908c161480612c785750612c78828b8d61304d565b15612c94575090945084935060019250505061ffff8516612df0565b6000620151808b840363ffffffff1611612cc257819850620151808c0363ffffffff168b63ffffffff161490505b60008d8a61ffff16620100008110612cdc57612cdc613f93565b0154610100900463ffffffff169050612cf6818d8f61304d565b612d2c576040517f0bc60f1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8b63ffffffff168163ffffffff1603612d8c578d8a61ffff16620100008110612d5757612d57613f93565b018e8b61ffff16620100008110612d7057612d70613f93565b919a50019750600196505061ffff89169450612df09350505050565b8960010161ffff168b61ffff1603612dd1578d8a61ffff16620100008110612db657612db6613f93565b019850939650600095505061ffff88169350612df092505050565b50612de08d8d8d8d8d86613129565b9199509750600096509450505050505b95509550955095915050565b600080600080612e118b8b8b8b8b8b8b613177565b909c909b509950505050505050505050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091526020860180516001885263ffffffff878116909252604088018051918803928316600288810b82810290940160060b90925260a08a0151612ea69391928291810b9089900b6132ce565b606088018051919091016affffffffffffffffffffff1690525050600292830b6080860152910b60a084015261ffff1660c08301525090565b6000848603818080612ef48b8b868a8a612c06565b508254929550909350915063ffffffff61010082048116916affffffffffffffffffffff6c0100000000000000000000000090910416908616829003612f4157955061150a945050505050565b8215612fbf576000612f698e888d8d8d888c60000160059054906101000a900460060b612dfc565b508654909150612faf9063ffffffff858a03169060028e810b9182917a010000000000000000000000000000000000000000000000000000909104810b9086900b6132ce565b820197505050505050505061150a565b835463ffffffff61010082048116916affffffffffffffffffffff6c010000000000000000000000009091041690881682900361300557975061150a9650505050505050565b83820384890363ffffffff8082169083166affffffffffffffffffffff8786031681613033576130336140ac565b040285019a50505050505050505050509695505050505050565b63ffffffff808216848216811091841611810361147a57505063ffffffff9081169116111590565b6000818511156130d55781850394508361ffff16600602851061309d575061ffff8216612831565b600461ffff85160a60006130b2878784613329565b9050808201818661ffff1602816130cb576130cb6140ac565b0492505050612831565b93810393600661ffff85160285106130ef57506000612831565b600461ffff85160a6000613104878784613329565b8201905080828661ffff16028161311d5761311d6140ac565b04979650505050505050565b6000808061ffff80861690829088168211613148578761ffff16613153565b620100008861ffff16015b90506131638b8b8b85858b61349f565b919d909c50909a5098505050505050505050565b6000806000808a8761ffff1662010000811061319557613195613f93565b0154610100900463ffffffff168b61ffff89166201000081106131ba576131ba613f93565b015490925065010000000000900460060b9050600289900b63ffffffff878c031602850161320b837ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeae808d018d61304d565b61326c578263ffffffff168b63ffffffff160361323757505050600287900b91505061ffff84166132c2565b828b0363ffffffff1660060b82820360060b81613256576132566140ac565b0560060b94505061ffff871692506132c2915050565b61327c87620151808d038d61304d565b1561329657505050600287900b91505061ffff85166132c2565b60006132a98d8d620151808e8e8e613610565b955090506201518081830360060b0560060b9550505050505b97509795505050505050565b600082820385850303838603870260018089018902906002808b029091018202906006818c0a81029180870a8402868802860283020190860a8d02909102018161331a5761331a6140ac565b059a9950505050505050505050565b6000808385048080156133685760018114613379576002811461338a576003811461339b57600481146133ac576903248ca20bb7b5032f5f92506133ba565b68056bc75e2d6310000092506133ba565b680ebc5fb4174612111092506133ba565b68280e60114edb805d0392506133ba565b686ce2482d63ef54b74c92506133ba565b690127fa27722cc06cc5e392505b50509383900693600261ffff85160461ffff16851061340a57600261ffff85160461ffff168503945068056bc75e2d63100000816808f00f760a4b2db55c0281613406576134066140ac565b0490505b8291508461ffff85168381613421576134216140ac565b049350838102830192508461ffff16848161343e5761343e6140ac565b0493508502600281850204830192508461ffff168481613460576134606140ac565b04935085026018600461ffff871683020282880201048301925068056bc75e2d6310000082840281613494576134946140ac565b049695505050505050565b60008060008380156134b357506002868603115b156134c25750600185016134ca565b5084840160011c5b888161ffff166201000081106134e2576134e2613f93565b01925082915060015b835460ff811690610100900463ffffffff16811561358f5761350e818b8d61304d565b15613584578b8460010161ffff1662010000811061352e5761352e613f93565b01805490955060ff811690610100900463ffffffff16811561356f576135558c828f61304d565b15613564575050505050613604565b856001019a5061357d565b508695506136049350505050565b5050613596565b600184039750613596565b8360010198505b60008380156135a25750875b80156135b05750846001018a145b90508080156135c1575060108a8a03115b156135d1578960080194506135da565b89890160011c94505b8c8561ffff166201000081106135f2576135f2613f93565b0196506000935050505060016134eb57505b96509650969350505050565b600080858703818080806136278d8d878c8c612c06565b83549397509195509350915063ffffffff610100820481169165010000000000900460060b908716829003613666579750909550613708945050505050565b831561368d5781870363ffffffff168c60020b028101839850985050505050505050613708565b845463ffffffff610100820481169165010000000000900460060b9089168290036136ca57995050505060010161ffff1694506137089350505050565b838203848a0363ffffffff808216908316600690810b90878603900b816136f3576136f36140ac565b05028501879c509c5050505050505050505050505b965096945050505050565b73ffffffffffffffffffffffffffffffffffffffff81168114611c4057600080fd5b8015158114611c4057600080fd5b60008083601f84011261375557600080fd5b50813567ffffffffffffffff81111561376d57600080fd5b60208301915083602082850101111561378557600080fd5b9250929050565b60008060008060008060008060e0898b0312156137a857600080fd5b88356137b381613713565b975060208901356137c381613713565b965060408901356137d381613735565b95506060890135945060808901356137ea81613713565b935060a08901356137fa81613735565b925060c089013567ffffffffffffffff81111561381657600080fd5b6138228b828c01613743565b999c989b5096995094979396929594505050565b600060e0828403121561384857600080fd5b50919050565b60008060008060008060008060e0898b03121561386a57600080fd5b883561387581613713565b9750602089013561388581613713565b965060408901359550606089013594506080890135935060a0890135925060c089013567ffffffffffffffff81111561381657600080fd5b8060020b8114611c4057600080fd5b8035600f81900b81146138de57600080fd5b919050565b600080600080600080600060c0888a0312156138fe57600080fd5b873561390981613713565b9650602088013561391981613713565b95506040880135613929816138bd565b94506060880135613939816138bd565b9350613947608089016138cc565b925060a088013567ffffffffffffffff81111561396357600080fd5b61396f8a828b01613743565b989b979a50959850939692959293505050565b6000806040838503121561399557600080fd5b82356139a081613713565b915060208301356139b081613713565b809150509250929050565b6000602082840312156139cd57600080fd5b813561147a81613713565b6000602082840312156139ea57600080fd5b5035919050565b600080600060608486031215613a0657600080fd5b8335613a1181613713565b92506020840135613a2181613713565b91506040840135613a31816138bd565b809150509250925092565b803563ffffffff811681146138de57600080fd5b600060208284031215613a6257600080fd5b61147a82613a3c565b60008060008060008060a08789031215613a8457600080fd5b8635613a8f81613713565b95506020870135613a9f81613713565b94506040870135935060608701359250608087013567ffffffffffffffff811115613ac957600080fd5b613ad589828a01613743565b979a9699509497509295939492505050565b60008060008060008060008060006101008a8c031215613b0657600080fd5b8935613b1181613713565b985060208a0135613b2181613713565b975060408a0135613b3181613735565b965060608a0135955060808a0135613b4881613713565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff811115613b7257600080fd5b613b7e8c828d01613743565b915080935050809150509295985092959850929598565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613c0b57613c0b613b95565b604052919050565b60006020808385031215613c2657600080fd5b823567ffffffffffffffff80821115613c3e57600080fd5b818501915085601f830112613c5257600080fd5b813581811115613c6457613c64613b95565b8060051b9150613c75848301613bc4565b8181529183018401918481019088841115613c8f57600080fd5b938501935b83851015613cb457613ca585613a3c565b82529385019390850190613c94565b98975050505050505050565b604080825283519082018190526000906020906060840190828701845b82811015613cfc57815160060b84529284019290840190600101613cdd565b5050508381038285015284518082528583019183019060005b81811015613d3e5783516affffffffffffffffffffff1683529284019291840191600101613d15565b5090979650505050505050565b60008060008060008060008060006101008a8c031215613d6a57600080fd5b8935613d7581613713565b985060208a0135613d8581613713565b975060408a0135613d95816138bd565b965060608a0135613da5816138bd565b9550613b4860808b016138cc565b61ffff81168114611c4057600080fd5b80356138de81613db3565b60008060408385031215613de157600080fd5b8235613dec81613db3565b915060208301356139b081613db3565b600060208284031215613e0e57600080fd5b815161147a81613735565b600060e08284031215613e2b57600080fd5b60405160e0810181811067ffffffffffffffff82111715613e4e57613e4e613b95565b6040528235613e5c81613db3565b81526020830135613e6c81613db3565b6020820152613e7d60408401613a3c565b6040820152613e8e60608401613a3c565b60608201526080830135613ea181613db3565b608082015260a0830135613eb481613db3565b60a0820152613ec560c08401613dc3565b60c08201529392505050565b60e081018235613ee081613db3565b61ffff9081168352602084013590613ef782613db3565b8082166020850152613f0b60408601613a3c565b915063ffffffff808316604086015280613f2760608801613a3c565b1660608601525060808501359150613f3e82613db3565b908116608084015260a084013590613f5582613db3565b1660a0830152613f6760c08401613dc3565b61ffff811660c0840152611fc3565b600060208284031215613f8857600080fd5b815161147a81613713565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b61ffff828116828216039080821115611fc357611fc3613fc2565b8082018082111561097557610975613fc2565b60008060008060008060c0878903121561403857600080fd5b865161404381613713565b6020880151909650614054816138bd565b604088015190955061406581613db3565b606088015190945060ff8116811461407c57600080fd5b608088015190935061408d81613db3565b60a088015190925061409e81613735565b809150509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fdfea164736f6c6343000814000aa164736f6c6343000814000a0000000000000000000000004eb881885fe22d895ff299f6cda6e0a8e00e66a0

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100c95760003560e01c80639b27d43211610081578063cddff2691161005b578063cddff2691461026d578063cdef16f6146102a2578063f718949a146102d857600080fd5b80639b27d43214610213578063a7b64b0414610233578063b001f6181461025a57600080fd5b8063692afddf116100b2578063692afddf146101cb5780638a2ade58146101e05780639533ff101461020057600080fd5b806327733026146100ce5780634e09a96a1461010b575b600080fd5b6100e16100dc366004610e70565b6102eb565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6000546101839061ffff8082169162010000810482169163ffffffff6401000000008304811692680100000000000000008104909116916c0100000000000000000000000082048116916e01000000000000000000000000000081048216917001000000000000000000000000000000009091041687565b6040805161ffff9889168152968816602088015263ffffffff9586169087015293909216606085015284166080840152831660a08301529190911660c082015260e001610102565b6101de6101d9366004610ea9565b610557565b005b6001546100e19073ffffffffffffffffffffffffffffffffffffffff1681565b6100e161020e366004610ecd565b610732565b6002546100e19073ffffffffffffffffffffffffffffffffffffffff1681565b6100e17f0000000000000000000000004eb881885fe22d895ff299f6cda6e0a8e00e66a081565b6101de610268366004610ea9565b610787565b6102947f267da724c255813ae00f4522fe843cb70148a4b8099cbc5af64f9a4151e55ed681565b604051908152602001610102565b6100e16102b0366004610ea9565b60036020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6101de6102e6366004610f18565b61095b565b6000807f0000000000000000000000004eb881885fe22d895ff299f6cda6e0a8e00e66a090508073ffffffffffffffffffffffffffffffffffffffff1663e8ae2b698273ffffffffffffffffffffffffffffffffffffffff1663b500a48b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610378573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061039c9190610f30565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526004810191909152336024820152604401602060405180830381865afa1580156103f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041a9190610f49565b61042357600080fd5b6040517fd9a641e100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015284811660248301526000919083169063d9a641e190604401602060405180830381865afa15801561049b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104bf9190610f6b565b905073ffffffffffffffffffffffffffffffffffffffff8116610543576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f506f6f6c206e6f7420657869737400000000000000000000000000000000000060448201526064015b60405180910390fd5b61054c81610aeb565b925050505b92915050565b6040517fe8ae2b690000000000000000000000000000000000000000000000000000000081527f267da724c255813ae00f4522fe843cb70148a4b8099cbc5af64f9a4151e55ed660048201523360248201527f0000000000000000000000004eb881885fe22d895ff299f6cda6e0a8e00e66a073ffffffffffffffffffffffffffffffffffffffff169063e8ae2b6990604401602060405180830381865afa158015610607573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062b9190610f49565b610691576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4f6e6c792061646d696e6973747261746f720000000000000000000000000000604482015260640161053a565b60025473ffffffffffffffffffffffffffffffffffffffff8083169116036106b857600080fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f8abb9ad4b75fd2e4ce33e4cdab5ecb4fe75b728b2bd17c31dd0a049723d39663906020015b60405180910390a150565b60003373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004eb881885fe22d895ff299f6cda6e0a8e00e66a0161461077657600080fd5b61077f84610aeb565b949350505050565b6040517fe8ae2b690000000000000000000000000000000000000000000000000000000081527f267da724c255813ae00f4522fe843cb70148a4b8099cbc5af64f9a4151e55ed660048201523360248201527f0000000000000000000000004eb881885fe22d895ff299f6cda6e0a8e00e66a073ffffffffffffffffffffffffffffffffffffffff169063e8ae2b6990604401602060405180830381865afa158015610837573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085b9190610f49565b6108c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4f6e6c792061646d696e6973747261746f720000000000000000000000000000604482015260640161053a565b60015473ffffffffffffffffffffffffffffffffffffffff8083169116036108e857600080fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f56b9e8342f530796ceed0d5529abdcdeae6e4f2ac1dc456ceb73bbda898e0cd390602001610727565b6040517fe8ae2b690000000000000000000000000000000000000000000000000000000081527f267da724c255813ae00f4522fe843cb70148a4b8099cbc5af64f9a4151e55ed660048201523360248201527f0000000000000000000000004eb881885fe22d895ff299f6cda6e0a8e00e66a073ffffffffffffffffffffffffffffffffffffffff169063e8ae2b6990604401602060405180830381865afa158015610a0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2f9190610f49565b610a95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4f6e6c792061646d696e6973747261746f720000000000000000000000000000604482015260640161053a565b610aac610aa736839003830183610fc5565b610d26565b806000610ab982826110b6565b9050507fe04232512a5cb82c08e0f9b1f51432930cd7a0b7ea9f9f916f080cb0b4ac644b8160405161072791906112be565b73ffffffffffffffffffffffffffffffffffffffff81811660009081526003602052604081205490911615610b7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920637265617465640000000000000000000000000000000000604482015260640161053a565b6000827f0000000000000000000000004eb881885fe22d895ff299f6cda6e0a8e00e66a030604051610bad90610e41565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f080158015610bf6573d6000803e3d6000fd5b50604080517f1d39215e00000000000000000000000000000000000000000000000000000000815260005461ffff8082166004840152601082901c8116602484015263ffffffff602083901c811660448501529382901c9093166064830152606081901c83166084830152607081901c831660a483015260801c90911660c482015290915073ffffffffffffffffffffffffffffffffffffffff821690631d39215e9060e401600060405180830381600087803b158015610cb657600080fd5b505af1158015610cca573d6000803e3d6000fd5b5050505073ffffffffffffffffffffffffffffffffffffffff928316600090815260036020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016938216939093179092555090565b60c08101516020820151825161ffff92831691610d4891908416908416611367565b610d529190611367565b1115610dba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4d61782066656520657863656564656400000000000000000000000000000000604482015260640161053a565b608081015161ffff1615801590610dd8575060a081015161ffff1615155b610e3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f47616d6d6173206d757374206265203e20300000000000000000000000000000604482015260640161053a565b50565b614246806113a283390190565b73ffffffffffffffffffffffffffffffffffffffff81168114610e3e57600080fd5b60008060408385031215610e8357600080fd5b8235610e8e81610e4e565b91506020830135610e9e81610e4e565b809150509250929050565b600060208284031215610ebb57600080fd5b8135610ec681610e4e565b9392505050565b600080600060608486031215610ee257600080fd5b8335610eed81610e4e565b92506020840135610efd81610e4e565b91506040840135610f0d81610e4e565b809150509250925092565b600060e08284031215610f2a57600080fd5b50919050565b600060208284031215610f4257600080fd5b5051919050565b600060208284031215610f5b57600080fd5b81518015158114610ec657600080fd5b600060208284031215610f7d57600080fd5b8151610ec681610e4e565b61ffff81168114610e3e57600080fd5b8035610fa381610f88565b919050565b63ffffffff81168114610e3e57600080fd5b8035610fa381610fa8565b600060e08284031215610fd757600080fd5b60405160e0810181811067ffffffffffffffff82111715611021577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405261102d83610f98565b815261103b60208401610f98565b602082015261104c60408401610fba565b604082015261105d60608401610fba565b606082015261106e60808401610f98565b608082015261107f60a08401610f98565b60a082015261109060c08401610f98565b60c08201529392505050565b6000813561055181610f88565b6000813561055181610fa8565b81356110c181610f88565b61ffff811690508154817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000821617835560208401356110ff81610f88565b63ffff00008160101b16905080837fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000841617178455604085013561114281610fa8565b67ffffffff000000008160201b16847fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008516178317178555505050506111ca61118d606084016110a9565b82547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff1660409190911b6bffffffff000000000000000016178255565b6112186111d96080840161109c565b82547fffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffff1660609190911b6dffff00000000000000000000000016178255565b61126861122760a0840161109c565b82547fffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffff1660709190911b6fffff000000000000000000000000000016178255565b6112ba61127760c0840161109c565b82547fffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffff1660809190911b71ffff0000000000000000000000000000000016178255565b5050565b60e0810182356112cd81610f88565b61ffff90811683526020840135906112e482610f88565b90811660208401526040840135906112fb82610fa8565b63ffffffff918216604085015260608501359161131783610fa8565b91909116606084015260808401359061132f82610f88565b16608083015261134160a08401610f98565b61ffff1660a083015261135660c08401610f98565b61ffff811660c08401525092915050565b80820180821115610551577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfe60e06040523480156200001157600080fd5b50604051620042463803806200424683398101604081905262000034916200006f565b6001600160a01b0390811660c0529182166080521660a052620000b9565b80516001600160a01b03811681146200006a57600080fd5b919050565b6000806000606084860312156200008557600080fd5b620000908462000052565b9250620000a06020850162000052565b9150620000b06040850162000052565b90509250925092565b60805160a05160c0516141176200012f6000396000818161060a01528181610b8101528181610c8901526111d101526000818161068501526109cf01526000818161022f0152818161139b015281816118ac01528181611aaa01528181611cb701528181611d310152611dcb01526141176000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c806374eceae6116100f95780639cb5a96311610097578063da70523511610071578063da7052351461055a578063e63015f01461056d578063f5985d3514610580578063f70d9362146105aa57600080fd5b80639cb5a963146105135780639d3a524114610526578063d68520101461054757600080fd5b806382dd6522116100d357806382dd65221461049257806388f2e862146104a55780638de0a8ee146104de5780639b27d432146104f157600080fd5b806374eceae6146104095780637c1fe0c8146104775780638129fc1c1461048a57600080fd5b806331b25d1a116101665780635e2411b2116101405780635e2411b2146103b6578063636fd804146103c9578063689ea370146103dc578063692afddf146103f657600080fd5b806331b25d1a14610345578063343d37ff1461037a578063392e53cd1461038d57600080fd5b80631d39215e116101975780631d39215e146102765780631d4632ac1461028b5780631e5eb1d0146102ad57600080fd5b8063029c1cb7146101be5780630786feb61461020757806316f0115b1461022a575b600080fd5b6101d16101cc36600461378c565b6105b2565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b62010000546102179061ffff1681565b60405161ffff90911681526020016101fe565b6102517f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101fe565b610289610284366004613836565b6105f2565b005b62010002546102519073ffffffffffffffffffffffffffffffffffffffff1681565b6102fd620100005461ffff67010000000000000090910481811692601082901c83169263ffffffff602084901c811693604081901c90911692606082901c831692607083901c81169260801c1690565b6040805161ffff9889168152968816602088015263ffffffff9586169087015293909216606085015284166080840152831660a08301529190911660c082015260e0016101fe565b61036c7f8e8000aba5b365c0be9685da1153f7f096e76d1ecfb42c050ae1e387aa65b4f581565b6040519081526020016101fe565b6101d161038836600461384e565b61081e565b62010000546103a6906601000000000000900460ff1681565b60405190151581526020016101fe565b6101d16103c43660046138e3565b61085e565b6101d16103d7366004613982565b610940565b6103e460c581565b60405160ff90911681526020016101fe565b6102896104043660046139bb565b61097b565b61041c6104173660046139d8565b610aa1565b60408051971515885263ffffffff909616602088015260069490940b948601949094526affffffffffffffffffffff9091166060850152600290810b60808501529190910b60a083015261ffff1660c082015260e0016101fe565b6102896104853660046139bb565b610b5d565b61028961103a565b6101d16104a03660046139f1565b61131f565b6104b86104b3366004613a50565b611481565b6040805160069390930b83526affffffffffffffffffffff9091166020830152016101fe565b6101d16104ec366004613a6b565b6114d5565b62010001546102519073ffffffffffffffffffffffffffffffffffffffff1681565b6101d1610521366004613ae7565b611514565b610539610534366004613c13565b61162a565b6040516101fe929190613cc0565b6101d1610555366004613d4b565b611666565b610289610568366004613dce565b6116a7565b6103a661057b3660046139bb565b61176e565b6201000080546105959163ffffffff91041681565b60405163ffffffff90911681526020016101fe565b6102176117f2565b60006105bc611894565b6105c4611935565b507f029c1cb70000000000000000000000000000000000000000000000000000000098975050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016148061070557506040517fe8ae2b690000000000000000000000000000000000000000000000000000000081527f8e8000aba5b365c0be9685da1153f7f096e76d1ecfb42c050ae1e387aa65b4f560048201523360248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e8ae2b6990604401602060405180830381865afa1580156106e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107059190613dfc565b61070e57600080fd5b61072561072036839003830183613e19565b611b28565b6107a661073736839003830183613e19565b600080826000015161ffff166010846020015161ffff16901b6020856040015163ffffffff16901b6040866060015163ffffffff16901b6060876080015161ffff16901b60708860a0015161ffff16901b60808960c0015161ffff16901b171717171717905080915050919050565b6201000060076101000a81548171ffffffffffffffffffffffffffffffffffff021916908371ffffffffffffffffffffffffffffffffffff1602179055507f348d1d6a31fa4a2a3ef887c493549a9500fbb77b5218be0c81a71c553364305a816040516108139190613ed1565b60405180910390a150565b6000610828611894565b610830611c43565b507f343d37ff0000000000000000000000000000000000000000000000000000000098975050505050505050565b6000610868611894565b620100015473ffffffffffffffffffffffffffffffffffffffff161561091357620100015473ffffffffffffffffffffffffffffffffffffffff898116911614610913576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f6f6e6c79206d6f646966794c6971756964697479456e747279706f696e74000060448201526064015b60405180910390fd5b507f5e2411b200000000000000000000000000000000000000000000000000000000979650505050505050565b600061094a611894565b610952611c43565b507f636fd804000000000000000000000000000000000000000000000000000000005b92915050565b6040517fe8ae2b690000000000000000000000000000000000000000000000000000000081527f8e8000aba5b365c0be9685da1153f7f096e76d1ecfb42c050ae1e387aa65b4f560048201523360248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e8ae2b6990604401602060405180830381865afa158015610a2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4f9190613dfc565b610a5857600080fd5b6201000180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600081620100008110610ab357600080fd5b015460ff81169150610100810463ffffffff169065010000000000810460060b906c0100000000000000000000000081046affffffffffffffffffffff1690770100000000000000000000000000000000000000000000008104600290810b917a010000000000000000000000000000000000000000000000000000810490910b907d010000000000000000000000000000000000000000000000000000000000900461ffff1687565b73ffffffffffffffffffffffffffffffffffffffff811615801590600090610c43577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16638a2ade586040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0e9190613f76565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16149050610d47565b620100035473ffffffffffffffffffffffffffffffffffffffff1615610c825750620100035473ffffffffffffffffffffffffffffffffffffffff1633145b80610d47577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16638a2ade586040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d169190613f76565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161490505b80610dae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4e6f7420616c6c6f77656420746f2073657420696e63656e7469766500000000604482015260640161090a565b600030610db9611d2d565b73ffffffffffffffffffffffffffffffffffffffff161490508215610e3f5780610e3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f506c7567696e206e6f7420617474616368656400000000000000000000000000604482015260640161090a565b620100025473ffffffffffffffffffffffffffffffffffffffff9081169085168103610ec7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f416c726561647920616374697665000000000000000000000000000000000000604482015260640161090a565b8315610f4b5773ffffffffffffffffffffffffffffffffffffffff811615610f4b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4861732061637469766520696e63656e74697665000000000000000000000000604482015260640161090a565b6201000280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87169081179091556040519081527f915c5369e6580733735d1c2e30ca20dcaa395697a041033c9f35f80f53525e849060200160405180910390a18315610ffa576201000380547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055611025565b6201000380547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b811561103357611033611c43565b5050505050565b62010000546601000000000000900460ff16156110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920696e697469616c697a656400000000000000000000000000604482015260640161090a565b306110bc611d2d565b73ffffffffffffffffffffffffffffffffffffffff1614611139576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f506c7567696e206e6f7420617474616368656400000000000000000000000000604482015260640161090a565b600080611144611dc3565b5050915091508173ffffffffffffffffffffffffffffffffffffffff166000036111ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f506f6f6c206973206e6f7420696e697469616c697a6564000000000000000000604482015260640161090a565b60004290507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639b27d4326040518163ffffffff1660e01b8152600401602060405180830381865afa15801561123a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061125e9190613f76565b6201000180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790556112b160008284611e68565b6201000080547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff63ffffffff84168302167fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffff90911617660100000000000017905561131a611c43565b505050565b6000611329611894565b4261133660008285611e68565b62010000805466010000000000007fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffff90911663ffffffff841683027fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff161717908190557f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690638e00555390670100000000000000900460801c61ffff166040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815261ffff9091166004820152602401600060405180830381600087803b15801561143d57600080fd5b505af1158015611451573d6000803e3d6000fd5b507f82dd6522000000000000000000000000000000000000000000000000000000009450505050505b9392505050565b600080600061148e611dc3565b5050620100005490925061ffff16905060006114aa8183611f97565b905060006114bc814289878787611fca565b6040810151606090910151909890975095505050505050565b60006114df611894565b6114e7611c43565b507f8de0a8ee000000000000000000000000000000000000000000000000000000005b9695505050505050565b600061151e611894565b620100025473ffffffffffffffffffffffffffffffffffffffff1680156115f2576000611549611dc3565b50506040517f34d33590000000000000000000000000000000000000000000000000000000008152600282900b60048201528c1515602482015290925073ffffffffffffffffffffffffffffffffffffffff841691506334d33590906044016020604051808303816000875af11580156115c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115eb9190613dfc565b50506115fa565b6115fa611c43565b507f9cb5a963000000000000000000000000000000000000000000000000000000009a9950505050505050505050565b6060806000611637611dc3565b505091505061165c6116464290565b6201000054600091908790859061ffff16612300565b9250925050915091565b6000611670611894565b611678611c43565b507fd6852010000000000000000000000000000000000000000000000000000000009998505050505050505050565b60008261ffff166201000081106116c0576116c0613f93565b015460ff16156116cf57600080fd5b60008161ffff161180156116f857508061ffff168261ffff6116f19190613ff1565b61ffff1610155b61170157600080fd5b61ffff82165b81830161ffff1681101561131a57600160008262010000811061172c5761172c613f93565b01805463ffffffff92909216610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff909216919091179055600101611707565b620100025460009073ffffffffffffffffffffffffffffffffffffffff83811691161461179d57506000919050565b306117a6611d2d565b73ffffffffffffffffffffffffffffffffffffffff16146117c957506000919050565b60006117d3611dc3565b9350505050600281166117e95750600092915050565b50600192915050565b620100005460009061ffff80821691670100000000000000900471ffffffffffffffffffffffffffffffffffff81169160109190911c1661ffff82161761ffff1660000361184a57608081901c61ffff169250505090565b60006118568184611f97565b90506000611862611dc3565b5050915050600061187e6118734290565b600090848887612489565b905061188a8185612792565b9550505050505090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611933576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4f6e6c7920706f6f6c2063616e2063616c6c2074686973000000000000000000604482015260640161090a565b565b62010000805461ffff811691810463ffffffff1690670100000000000000810471ffffffffffffffffffffffffffffffffffff16906601000000000000900460ff16806119de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4e6f7420696e697469616c697a65640000000000000000000000000000000000604482015260640161090a565b4263ffffffff808216908516036119f6575050505050565b600080611a01611dc3565b5090935091506000905080611a18818a8787612839565b62010000805463ffffffff891682027fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000090911661ffff85161717905590925090506000611a678383878b612bc0565b90508361ffff168161ffff1614611b1c576040517f8e00555300000000000000000000000000000000000000000000000000000000815261ffff821660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690638e00555390602401600060405180830381600087803b158015611b0357600080fd5b505af1158015611b17573d6000803e3d6000fd5b505050505b50505050505050505050565b60c08101516020820151825161ffff92831691611b4a9190841690841661400c565b611b54919061400c565b1115611bbc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4d61782066656520657863656564656400000000000000000000000000000000604482015260640161090a565b608081015161ffff1615801590611bda575060a081015161ffff1615155b611c40576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f47616d6d6173206d757374206265203e20300000000000000000000000000000604482015260640161090a565b50565b620100025460c59073ffffffffffffffffffffffffffffffffffffffff1615611c6a576002175b6000611c74611dc3565b93505050508160ff168160ff1614611d29576040517fbca57f8100000000000000000000000000000000000000000000000000000000815260ff831660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063bca57f8190602401600060405180830381600087803b158015611d1057600080fd5b505af1158015611d24573d6000803e3d6000fd5b505050505b5050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663ef01df4f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbe9190613f76565b905090565b6000806000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e76c01e46040518163ffffffff1660e01b815260040160c060405180830381865afa158015611e34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e58919061401f565b5093989297509095509350915050565b8254839060ff1615611ea6576040517f1156234600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805460017fffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffff9091167a01000000000000000000000000000000000000000000000000000062ffffff949094169384027fffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffff16177701000000000000000000000000000000000000000000000093909302929092177fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000001661010063ffffffff94909416939093027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169290921717905550565b6000600182018361ffff8216620100008110611fb557611fb5613f93565b015460ff1615611fc3578091505b5092915050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152848603600080806120178b8b868a8a612c06565b506040805160e081018252845460ff811615158252610100810463ffffffff9081166020840181905265010000000000830460060b948401949094526c0100000000000000000000000082046affffffffffffffffffffff166060840152770100000000000000000000000000000000000000000000008204600290810b60808501527a0100000000000000000000000000000000000000000000000000008304900b60a08401527d01000000000000000000000000000000000000000000000000000000000090910461ffff1660c0830152909950939650919450925090851603612106575050505061150a565b8015612144576000806121268d878c8c8c8c602001518d60400151612dfc565b9150915061213787878c8585612e23565b965050505050505061150a565b815463ffffffff610100820481169165010000000000900460060b9086168290036122435750506040805160e081018252925460ff811615158452610100810463ffffffff16602085015265010000000000810460060b918401919091526c0100000000000000000000000081046affffffffffffffffffffff166060840152770100000000000000000000000000000000000000000000008104600290810b60808501527a0100000000000000000000000000000000000000000000000000008204900b60a08401527d010000000000000000000000000000000000000000000000000000000000900461ffff1660c083015250925061150a915050565b602087015160408801518184039188039063ffffffff80831691908416600690810b918603900b81612277576122776140ac565b60408c01805192909105929092020160060b90526060890151865463ffffffff80841692908516916affffffffffffffffffffff6c0100000000000000000000000090910481169190910316816122d0576122d06140ac565b60608c0180516affffffffffffffffffffff93909204939093020116905250505050505050509695505050505050565b825160609081908067ffffffffffffffff81111561232057612320613b95565b604051908082528060200260200182016040528015612349578160200160208202803683370190505b5092508067ffffffffffffffff81111561236557612365613b95565b60405190808252806020026020018201604052801561238e578160200160208202803683370190505b509150600061239d8986611f97565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290529192505b8381101561247b576124088b8b8b84815181106123f8576123f8613f93565b60200260200101518b8b88611fca565b91508160400151826060015187838151811061242657612426613f93565b6020026020010187848151811061243f5761243f613f93565b60200260200101826affffffffffffffffffffff166affffffffffffffffffffff168152508260060b60060b81525050508060010190506123d9565b505050509550959350505050565b600080868461ffff166201000081106124a4576124a4613f93565b018054909150610100810463ffffffff90811690881614906affffffffffffffffffffff6c010000000000000000000000008204169061ffff7d0100000000000000000000000000000000000000000000000000000000009091041682612517576125148a8a60008b8b8b612edf565b91505b60008a8761ffff1662010000811061253157612531613f93565b0154610100900463ffffffff16905061256d817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeae808c018c61304d565b156126cd5760008415612697578b8361ffff1662010000811061259257612592613f93565b0154610100900463ffffffff168c61ffff85166201000081106125b7576125b7613f93565b01549092506c0100000000000000000000000090046affffffffffffffffffffff1690506000828d6001860161ffff166201000081106125f9576125f9613f93565b015463ffffffff610100909104811691909103915081811690848e037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeae800116838f61ffff600189011662010000811061265457612654613f93565b01600001600c9054906101000a90046affffffffffffffffffffff1603026affffffffffffffffffffff168161268c5761268c6140ac565b0482019150506126ab565b6126a88c8c620151808d8d8d612edf565b90505b620151806affffffffffffffffffffff82860316049650505050505050612789565b8063ffffffff168a63ffffffff16146127835760008b8861ffff166201000081106126fa576126fa613f93565b01546c0100000000000000000000000090046affffffffffffffffffffff169050818b03600163ffffffff82161115612750577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b8063ffffffff168286036affffffffffffffffffffff1681612774576127746140ac565b04975050505050505050612789565b50505050505b95945050505050565b6000600f6affffffffffffffffffffff841604925060006127e36affffffffffffffffffffff8516607085901c61ffff16601086901c61ffff16604087901c63ffffffff165b63ffffffff16613075565b6128126affffffffffffffffffffff8616606086901c61ffff1661ffff8716602088901c63ffffffff166127d8565b01905061ffff608084901c8116820190811115612831576128316140db565b949350505050565b6000806000868661ffff1662010000811061285657612856613f93565b6040805160e081018252919092015460ff811615158252610100810463ffffffff9081166020840181905265010000000000830460060b948401949094526c0100000000000000000000000082046affffffffffffffffffffff166060840152770100000000000000000000000000000000000000000000008204600290810b60808501527a0100000000000000000000000000000000000000000000000000008304900b60a08401527d01000000000000000000000000000000000000000000000000000000000090910461ffff1660c083015290925086169003612943578560009250925050612bb7565b856001019250868361ffff1662010000811061296157612961613f93565b015460ff161561296f578291505b6000806129898988888b8888602001518960400151612dfc565b915091508461ffff168161ffff16036129a0576001015b6129ad8388888585612e23565b898661ffff166201000081106129c5576129c5613f93565b825191018054602084015160408501516060860151608087015160a088015160c0909801517fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009095169615157fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff169690961761010063ffffffff90941693909302929092177fffffffffffffffffff000000000000000000000000000000000000ffffffffff166501000000000066ffffffffffffff909216919091027fffffffffffffffffff0000000000000000000000ffffffffffffffffffffffff16176c010000000000000000000000006affffffffffffffffffffff90921691909102177fffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffff167701000000000000000000000000000000000000000000000062ffffff948516027fffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffff16177a0100000000000000000000000000000000000000000000000000009390941692909202929092177fff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d01000000000000000000000000000000000000000000000000000000000061ffff928316021790915585811690851603612bb3576001909301925b5050505b94509492505050565b6000601082901c61ffff1661ffff83161761ffff16600003612beb575061ffff608082901c16612831565b6000612bfa8142868989612489565b905061150a8184612792565b6000806000806000898761ffff16620100008110612c2657612c26613f93565b01805490915063ffffffff610100820481169161ffff7d01000000000000000000000000000000000000000000000000000000000090910416908a8116908c161480612c785750612c78828b8d61304d565b15612c94575090945084935060019250505061ffff8516612df0565b6000620151808b840363ffffffff1611612cc257819850620151808c0363ffffffff168b63ffffffff161490505b60008d8a61ffff16620100008110612cdc57612cdc613f93565b0154610100900463ffffffff169050612cf6818d8f61304d565b612d2c576040517f0bc60f1000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8b63ffffffff168163ffffffff1603612d8c578d8a61ffff16620100008110612d5757612d57613f93565b018e8b61ffff16620100008110612d7057612d70613f93565b919a50019750600196505061ffff89169450612df09350505050565b8960010161ffff168b61ffff1603612dd1578d8a61ffff16620100008110612db657612db6613f93565b019850939650600095505061ffff88169350612df092505050565b50612de08d8d8d8d8d86613129565b9199509750600096509450505050505b95509550955095915050565b600080600080612e118b8b8b8b8b8b8b613177565b909c909b509950505050505050505050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091526020860180516001885263ffffffff878116909252604088018051918803928316600288810b82810290940160060b90925260a08a0151612ea69391928291810b9089900b6132ce565b606088018051919091016affffffffffffffffffffff1690525050600292830b6080860152910b60a084015261ffff1660c08301525090565b6000848603818080612ef48b8b868a8a612c06565b508254929550909350915063ffffffff61010082048116916affffffffffffffffffffff6c0100000000000000000000000090910416908616829003612f4157955061150a945050505050565b8215612fbf576000612f698e888d8d8d888c60000160059054906101000a900460060b612dfc565b508654909150612faf9063ffffffff858a03169060028e810b9182917a010000000000000000000000000000000000000000000000000000909104810b9086900b6132ce565b820197505050505050505061150a565b835463ffffffff61010082048116916affffffffffffffffffffff6c010000000000000000000000009091041690881682900361300557975061150a9650505050505050565b83820384890363ffffffff8082169083166affffffffffffffffffffff8786031681613033576130336140ac565b040285019a50505050505050505050509695505050505050565b63ffffffff808216848216811091841611810361147a57505063ffffffff9081169116111590565b6000818511156130d55781850394508361ffff16600602851061309d575061ffff8216612831565b600461ffff85160a60006130b2878784613329565b9050808201818661ffff1602816130cb576130cb6140ac565b0492505050612831565b93810393600661ffff85160285106130ef57506000612831565b600461ffff85160a6000613104878784613329565b8201905080828661ffff16028161311d5761311d6140ac565b04979650505050505050565b6000808061ffff80861690829088168211613148578761ffff16613153565b620100008861ffff16015b90506131638b8b8b85858b61349f565b919d909c50909a5098505050505050505050565b6000806000808a8761ffff1662010000811061319557613195613f93565b0154610100900463ffffffff168b61ffff89166201000081106131ba576131ba613f93565b015490925065010000000000900460060b9050600289900b63ffffffff878c031602850161320b837ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeae808d018d61304d565b61326c578263ffffffff168b63ffffffff160361323757505050600287900b91505061ffff84166132c2565b828b0363ffffffff1660060b82820360060b81613256576132566140ac565b0560060b94505061ffff871692506132c2915050565b61327c87620151808d038d61304d565b1561329657505050600287900b91505061ffff85166132c2565b60006132a98d8d620151808e8e8e613610565b955090506201518081830360060b0560060b9550505050505b97509795505050505050565b600082820385850303838603870260018089018902906002808b029091018202906006818c0a81029180870a8402868802860283020190860a8d02909102018161331a5761331a6140ac565b059a9950505050505050505050565b6000808385048080156133685760018114613379576002811461338a576003811461339b57600481146133ac576903248ca20bb7b5032f5f92506133ba565b68056bc75e2d6310000092506133ba565b680ebc5fb4174612111092506133ba565b68280e60114edb805d0392506133ba565b686ce2482d63ef54b74c92506133ba565b690127fa27722cc06cc5e392505b50509383900693600261ffff85160461ffff16851061340a57600261ffff85160461ffff168503945068056bc75e2d63100000816808f00f760a4b2db55c0281613406576134066140ac565b0490505b8291508461ffff85168381613421576134216140ac565b049350838102830192508461ffff16848161343e5761343e6140ac565b0493508502600281850204830192508461ffff168481613460576134606140ac565b04935085026018600461ffff871683020282880201048301925068056bc75e2d6310000082840281613494576134946140ac565b049695505050505050565b60008060008380156134b357506002868603115b156134c25750600185016134ca565b5084840160011c5b888161ffff166201000081106134e2576134e2613f93565b01925082915060015b835460ff811690610100900463ffffffff16811561358f5761350e818b8d61304d565b15613584578b8460010161ffff1662010000811061352e5761352e613f93565b01805490955060ff811690610100900463ffffffff16811561356f576135558c828f61304d565b15613564575050505050613604565b856001019a5061357d565b508695506136049350505050565b5050613596565b600184039750613596565b8360010198505b60008380156135a25750875b80156135b05750846001018a145b90508080156135c1575060108a8a03115b156135d1578960080194506135da565b89890160011c94505b8c8561ffff166201000081106135f2576135f2613f93565b0196506000935050505060016134eb57505b96509650969350505050565b600080858703818080806136278d8d878c8c612c06565b83549397509195509350915063ffffffff610100820481169165010000000000900460060b908716829003613666579750909550613708945050505050565b831561368d5781870363ffffffff168c60020b028101839850985050505050505050613708565b845463ffffffff610100820481169165010000000000900460060b9089168290036136ca57995050505060010161ffff1694506137089350505050565b838203848a0363ffffffff808216908316600690810b90878603900b816136f3576136f36140ac565b05028501879c509c5050505050505050505050505b965096945050505050565b73ffffffffffffffffffffffffffffffffffffffff81168114611c4057600080fd5b8015158114611c4057600080fd5b60008083601f84011261375557600080fd5b50813567ffffffffffffffff81111561376d57600080fd5b60208301915083602082850101111561378557600080fd5b9250929050565b60008060008060008060008060e0898b0312156137a857600080fd5b88356137b381613713565b975060208901356137c381613713565b965060408901356137d381613735565b95506060890135945060808901356137ea81613713565b935060a08901356137fa81613735565b925060c089013567ffffffffffffffff81111561381657600080fd5b6138228b828c01613743565b999c989b5096995094979396929594505050565b600060e0828403121561384857600080fd5b50919050565b60008060008060008060008060e0898b03121561386a57600080fd5b883561387581613713565b9750602089013561388581613713565b965060408901359550606089013594506080890135935060a0890135925060c089013567ffffffffffffffff81111561381657600080fd5b8060020b8114611c4057600080fd5b8035600f81900b81146138de57600080fd5b919050565b600080600080600080600060c0888a0312156138fe57600080fd5b873561390981613713565b9650602088013561391981613713565b95506040880135613929816138bd565b94506060880135613939816138bd565b9350613947608089016138cc565b925060a088013567ffffffffffffffff81111561396357600080fd5b61396f8a828b01613743565b989b979a50959850939692959293505050565b6000806040838503121561399557600080fd5b82356139a081613713565b915060208301356139b081613713565b809150509250929050565b6000602082840312156139cd57600080fd5b813561147a81613713565b6000602082840312156139ea57600080fd5b5035919050565b600080600060608486031215613a0657600080fd5b8335613a1181613713565b92506020840135613a2181613713565b91506040840135613a31816138bd565b809150509250925092565b803563ffffffff811681146138de57600080fd5b600060208284031215613a6257600080fd5b61147a82613a3c565b60008060008060008060a08789031215613a8457600080fd5b8635613a8f81613713565b95506020870135613a9f81613713565b94506040870135935060608701359250608087013567ffffffffffffffff811115613ac957600080fd5b613ad589828a01613743565b979a9699509497509295939492505050565b60008060008060008060008060006101008a8c031215613b0657600080fd5b8935613b1181613713565b985060208a0135613b2181613713565b975060408a0135613b3181613735565b965060608a0135955060808a0135613b4881613713565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff811115613b7257600080fd5b613b7e8c828d01613743565b915080935050809150509295985092959850929598565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613c0b57613c0b613b95565b604052919050565b60006020808385031215613c2657600080fd5b823567ffffffffffffffff80821115613c3e57600080fd5b818501915085601f830112613c5257600080fd5b813581811115613c6457613c64613b95565b8060051b9150613c75848301613bc4565b8181529183018401918481019088841115613c8f57600080fd5b938501935b83851015613cb457613ca585613a3c565b82529385019390850190613c94565b98975050505050505050565b604080825283519082018190526000906020906060840190828701845b82811015613cfc57815160060b84529284019290840190600101613cdd565b5050508381038285015284518082528583019183019060005b81811015613d3e5783516affffffffffffffffffffff1683529284019291840191600101613d15565b5090979650505050505050565b60008060008060008060008060006101008a8c031215613d6a57600080fd5b8935613d7581613713565b985060208a0135613d8581613713565b975060408a0135613d95816138bd565b965060608a0135613da5816138bd565b9550613b4860808b016138cc565b61ffff81168114611c4057600080fd5b80356138de81613db3565b60008060408385031215613de157600080fd5b8235613dec81613db3565b915060208301356139b081613db3565b600060208284031215613e0e57600080fd5b815161147a81613735565b600060e08284031215613e2b57600080fd5b60405160e0810181811067ffffffffffffffff82111715613e4e57613e4e613b95565b6040528235613e5c81613db3565b81526020830135613e6c81613db3565b6020820152613e7d60408401613a3c565b6040820152613e8e60608401613a3c565b60608201526080830135613ea181613db3565b608082015260a0830135613eb481613db3565b60a0820152613ec560c08401613dc3565b60c08201529392505050565b60e081018235613ee081613db3565b61ffff9081168352602084013590613ef782613db3565b8082166020850152613f0b60408601613a3c565b915063ffffffff808316604086015280613f2760608801613a3c565b1660608601525060808501359150613f3e82613db3565b908116608084015260a084013590613f5582613db3565b1660a0830152613f6760c08401613dc3565b61ffff811660c0840152611fc3565b600060208284031215613f8857600080fd5b815161147a81613713565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b61ffff828116828216039080821115611fc357611fc3613fc2565b8082018082111561097557610975613fc2565b60008060008060008060c0878903121561403857600080fd5b865161404381613713565b6020880151909650614054816138bd565b604088015190955061406581613db3565b606088015190945060ff8116811461407c57600080fd5b608088015190935061408d81613db3565b60a088015190925061409e81613735565b809150509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fdfea164736f6c6343000814000aa164736f6c6343000814000a

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

0000000000000000000000004eb881885fe22d895ff299f6cda6e0a8e00e66a0

-----Decoded View---------------
Arg [0] : _algebraFactory (address): 0x4Eb881885FE22D895Ff299f6cdA6e0A8E00E66A0

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000004eb881885fe22d895ff299f6cda6e0a8e00e66a0


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
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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.