Source Code
Overview
MNT Balance
MNT Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 9796947 | 853 days ago | Contract Creation | 0 MNT |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
AlgebraFactory
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)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.20;
import './libraries/Constants.sol';
import './interfaces/IAlgebraFactory.sol';
import './interfaces/IAlgebraPoolDeployer.sol';
import './interfaces/plugin/IAlgebraPluginFactory.sol';
import './AlgebraCommunityVault.sol';
import '@openzeppelin/contracts/access/Ownable2Step.sol';
import '@openzeppelin/contracts/access/AccessControlEnumerable.sol';
/// @title Algebra factory
/// @notice Is used to deploy pools and its plugins
/// @dev Version: Algebra Integral
contract AlgebraFactory is IAlgebraFactory, Ownable2Step, AccessControlEnumerable {
/// @inheritdoc IAlgebraFactory
bytes32 public constant override POOLS_ADMINISTRATOR_ROLE = keccak256('POOLS_ADMINISTRATOR'); // it`s here for the public visibility of the value
/// @inheritdoc IAlgebraFactory
address public immutable override poolDeployer;
/// @inheritdoc IAlgebraFactory
address public immutable override communityVault;
/// @inheritdoc IAlgebraFactory
uint16 public override defaultCommunityFee;
/// @inheritdoc IAlgebraFactory
uint16 public override defaultFee;
/// @inheritdoc IAlgebraFactory
int24 public override defaultTickspacing;
/// @inheritdoc IAlgebraFactory
uint256 public override renounceOwnershipStartTimestamp;
/// @dev time delay before ownership renouncement can be finished
uint256 private constant RENOUNCE_OWNERSHIP_DELAY = 1 days;
/// @inheritdoc IAlgebraFactory
IAlgebraPluginFactory public defaultPluginFactory;
/// @inheritdoc IAlgebraFactory
mapping(address => mapping(address => address)) public override poolByPair;
/// @inheritdoc IAlgebraFactory
/// @dev keccak256 of AlgebraPool init bytecode. Used to compute pool address deterministically
bytes32 public constant POOL_INIT_CODE_HASH = 0x177d5fbf994f4d130c008797563306f1a168dc689f81b2fa23b4396931014d91;
constructor(address _poolDeployer) {
require(_poolDeployer != address(0));
poolDeployer = _poolDeployer;
communityVault = address(new AlgebraCommunityVault(msg.sender));
defaultTickspacing = Constants.INIT_DEFAULT_TICK_SPACING;
defaultFee = Constants.INIT_DEFAULT_FEE;
emit DefaultTickspacing(Constants.INIT_DEFAULT_TICK_SPACING);
emit DefaultFee(Constants.INIT_DEFAULT_FEE);
}
/// @inheritdoc IAlgebraFactory
function owner() public view override(IAlgebraFactory, Ownable) returns (address) {
return super.owner();
}
/// @inheritdoc IAlgebraFactory
function hasRoleOrOwner(bytes32 role, address account) public view override returns (bool) {
return (owner() == account || super.hasRole(role, account));
}
/// @inheritdoc IAlgebraFactory
function defaultConfigurationForPool() external view override returns (uint16 communityFee, int24 tickSpacing, uint16 fee) {
return (defaultCommunityFee, defaultTickspacing, defaultFee);
}
/// @inheritdoc IAlgebraFactory
function computePoolAddress(address token0, address token1) public view override returns (address pool) {
pool = address(uint160(uint256(keccak256(abi.encodePacked(hex'ff', poolDeployer, keccak256(abi.encode(token0, token1)), POOL_INIT_CODE_HASH)))));
}
/// @inheritdoc IAlgebraFactory
function createPool(address tokenA, address tokenB) external override returns (address pool) {
require(tokenA != tokenB);
(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0));
require(poolByPair[token0][token1] == address(0));
address defaultPlugin;
if (address(defaultPluginFactory) != address(0)) {
defaultPlugin = defaultPluginFactory.createPlugin(computePoolAddress(token0, token1));
}
pool = IAlgebraPoolDeployer(poolDeployer).deploy(defaultPlugin, token0, token1);
poolByPair[token0][token1] = pool; // to avoid future addresses comparison we are populating the mapping twice
poolByPair[token1][token0] = pool;
emit Pool(token0, token1, pool);
}
/// @inheritdoc IAlgebraFactory
function setDefaultCommunityFee(uint16 newDefaultCommunityFee) external override onlyOwner {
require(newDefaultCommunityFee <= Constants.MAX_COMMUNITY_FEE);
require(defaultCommunityFee != newDefaultCommunityFee);
defaultCommunityFee = newDefaultCommunityFee;
emit DefaultCommunityFee(newDefaultCommunityFee);
}
/// @inheritdoc IAlgebraFactory
function setDefaultFee(uint16 newDefaultFee) external override onlyOwner {
require(newDefaultFee <= Constants.MAX_DEFAULT_FEE);
require(defaultFee != newDefaultFee);
defaultFee = newDefaultFee;
emit DefaultFee(newDefaultFee);
}
/// @inheritdoc IAlgebraFactory
function setDefaultTickspacing(int24 newDefaultTickspacing) external override onlyOwner {
require(newDefaultTickspacing >= Constants.MIN_TICK_SPACING);
require(newDefaultTickspacing <= Constants.MAX_TICK_SPACING);
require(newDefaultTickspacing != defaultTickspacing);
defaultTickspacing = newDefaultTickspacing;
emit DefaultTickspacing(newDefaultTickspacing);
}
/// @inheritdoc IAlgebraFactory
function setDefaultPluginFactory(address newDefaultPluginFactory) external override onlyOwner {
require(newDefaultPluginFactory != address(defaultPluginFactory));
defaultPluginFactory = IAlgebraPluginFactory(newDefaultPluginFactory);
emit DefaultPluginFactory(newDefaultPluginFactory);
}
/// @inheritdoc IAlgebraFactory
function startRenounceOwnership() external override onlyOwner {
require(renounceOwnershipStartTimestamp == 0);
renounceOwnershipStartTimestamp = block.timestamp;
emit RenounceOwnershipStart(renounceOwnershipStartTimestamp, renounceOwnershipStartTimestamp + RENOUNCE_OWNERSHIP_DELAY);
}
/// @inheritdoc IAlgebraFactory
function stopRenounceOwnership() external override onlyOwner {
require(renounceOwnershipStartTimestamp != 0);
renounceOwnershipStartTimestamp = 0;
emit RenounceOwnershipStop(block.timestamp);
}
/// @dev Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore.
/// Can only be called by the current owner if RENOUNCE_OWNERSHIP_DELAY seconds
/// have passed since the call to the startRenounceOwnership() function.
function renounceOwnership() public override onlyOwner {
require(renounceOwnershipStartTimestamp != 0);
require(block.timestamp - renounceOwnershipStartTimestamp >= RENOUNCE_OWNERSHIP_DELAY);
renounceOwnershipStartTimestamp = 0;
super.renounceOwnership();
emit RenounceOwnershipFinish(block.timestamp);
}
/// @dev Transfers ownership of the contract to a new account (`newOwner`).
/// Modified to fit with the role mechanism.
function _transferOwnership(address newOwner) internal override {
_revokeRole(DEFAULT_ADMIN_ROLE, owner());
super._transferOwnership(newOwner);
if (owner() != address(0)) {
_grantRole(DEFAULT_ADMIN_ROLE, owner());
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)
pragma solidity ^0.8.0;
import "./IAccessControlEnumerable.sol";
import "./AccessControl.sol";
import "../utils/structs/EnumerableSet.sol";
/**
* @dev Extension of {AccessControl} that allows enumerating the members of each role.
*/
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
using EnumerableSet for EnumerableSet.AddressSet;
mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) {
return _roleMembers[role].at(index);
}
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) {
return _roleMembers[role].length();
}
/**
* @dev Overload {_grantRole} to track enumerable memberships
*/
function _grantRole(bytes32 role, address account) internal virtual override {
super._grantRole(role, account);
_roleMembers[role].add(account);
}
/**
* @dev Overload {_revokeRole} to track enumerable memberships
*/
function _revokeRole(bytes32 role, address account) internal virtual override {
super._revokeRole(role, account);
_roleMembers[role].remove(account);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IAccessControlEnumerable is IAccessControl {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.0;
import "./Ownable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.20;
import './libraries/SafeTransfer.sol';
import './libraries/FullMath.sol';
import './interfaces/IAlgebraFactory.sol';
import './interfaces/IAlgebraCommunityVault.sol';
/// @title Algebra community fee vault
/// @notice Community fee from pools is sent here, if it is enabled
/// @dev Role system is used to withdraw tokens
/// @dev Version: Algebra Integral
contract AlgebraCommunityVault is IAlgebraCommunityVault {
/// @dev The role can be granted in AlgebraFactory
bytes32 public constant COMMUNITY_FEE_WITHDRAWER_ROLE = keccak256('COMMUNITY_FEE_WITHDRAWER');
/// @dev The role can be granted in AlgebraFactory
bytes32 public constant COMMUNITY_FEE_VAULT_ADMINISTRATOR = keccak256('COMMUNITY_FEE_VAULT_ADMINISTRATOR');
address private immutable factory;
/// @notice Address to which community fees are sent from vault
address public communityFeeReceiver;
/// @notice The percentage of the protocol fee that Algebra will receive
/// @dev Value in thousandths,i.e. 1e-3
uint16 public algebraFee;
/// @notice Represents whether there is a new Algebra fee proposal or not
bool public hasNewAlgebraFeeProposal;
/// @notice Suggested Algebra fee value
uint16 public proposedNewAlgebraFee;
/// @notice Address of recipient Algebra part of community fee
address public algebraFeeReceiver;
/// @notice Address of Algebra fee manager
address public algebraFeeManager;
address private _pendingAlgebraFeeManager;
uint16 private constant ALGEBRA_FEE_DENOMINATOR = 1000;
modifier onlyAdministrator() {
require(IAlgebraFactory(factory).hasRoleOrOwner(COMMUNITY_FEE_VAULT_ADMINISTRATOR, msg.sender), 'only administrator');
_;
}
modifier onlyWithdrawer() {
require(msg.sender == algebraFeeManager || IAlgebraFactory(factory).hasRoleOrOwner(COMMUNITY_FEE_WITHDRAWER_ROLE, msg.sender), 'only withdrawer');
_;
}
modifier onlyAlgebraFeeManager() {
require(msg.sender == algebraFeeManager, 'only algebra fee manager');
_;
}
constructor(address _algebraFeeManager) {
(factory, algebraFeeManager) = (msg.sender, _algebraFeeManager);
}
/// @inheritdoc IAlgebraCommunityVault
function withdraw(address token, uint256 amount) external override onlyWithdrawer {
(uint16 _algebraFee, address _algebraFeeReceiver, address _communityFeeReceiver) = _readAndVerifyWithdrawSettings();
_withdraw(token, _communityFeeReceiver, amount, _algebraFee, _algebraFeeReceiver);
}
/// @inheritdoc IAlgebraCommunityVault
function withdrawTokens(WithdrawTokensParams[] calldata params) external override onlyWithdrawer {
uint256 paramsLength = params.length;
(uint16 _algebraFee, address _algebraFeeReceiver, address _communityFeeReceiver) = _readAndVerifyWithdrawSettings();
unchecked {
for (uint256 i; i < paramsLength; ++i) _withdraw(params[i].token, _communityFeeReceiver, params[i].amount, _algebraFee, _algebraFeeReceiver);
}
}
function _readAndVerifyWithdrawSettings() private view returns (uint16 _algebraFee, address _algebraFeeReceiver, address _communityFeeReceiver) {
(_algebraFee, _algebraFeeReceiver, _communityFeeReceiver) = (algebraFee, algebraFeeReceiver, communityFeeReceiver);
if (_algebraFee != 0) require(_algebraFeeReceiver != address(0), 'invalid algebra fee receiver');
require(_communityFeeReceiver != address(0), 'invalid receiver');
}
function _withdraw(address token, address to, uint256 amount, uint16 _algebraFee, address _algebraFeeReceiver) private {
uint256 withdrawAmount = amount;
if (_algebraFee != 0) {
uint256 algebraFeeAmount = FullMath.mulDivRoundingUp(withdrawAmount, _algebraFee, ALGEBRA_FEE_DENOMINATOR);
withdrawAmount -= algebraFeeAmount;
SafeTransfer.safeTransfer(token, _algebraFeeReceiver, algebraFeeAmount);
emit AlgebraTokensWithdrawal(token, _algebraFeeReceiver, algebraFeeAmount);
}
SafeTransfer.safeTransfer(token, to, withdrawAmount);
emit TokensWithdrawal(token, to, withdrawAmount);
}
// ### algebra factory owner permissioned actions ###
/// @inheritdoc IAlgebraCommunityVault
function acceptAlgebraFeeChangeProposal(uint16 newAlgebraFee) external override onlyAdministrator {
require(hasNewAlgebraFeeProposal, 'not proposed');
require(newAlgebraFee == proposedNewAlgebraFee, 'invalid new fee');
// note that the new value will be used for previously accumulated tokens that have not yet been withdrawn
algebraFee = newAlgebraFee;
(proposedNewAlgebraFee, hasNewAlgebraFeeProposal) = (0, false);
emit AlgebraFee(newAlgebraFee);
}
/// @inheritdoc IAlgebraCommunityVault
function changeCommunityFeeReceiver(address newCommunityFeeReceiver) external override onlyAdministrator {
require(newCommunityFeeReceiver != address(0));
require(newCommunityFeeReceiver != communityFeeReceiver);
communityFeeReceiver = newCommunityFeeReceiver;
emit CommunityFeeReceiver(newCommunityFeeReceiver);
}
// ### algebra fee manager permissioned actions ###
/// @inheritdoc IAlgebraCommunityVault
function transferAlgebraFeeManagerRole(address _newAlgebraFeeManager) external override onlyAlgebraFeeManager {
_pendingAlgebraFeeManager = _newAlgebraFeeManager;
emit PendingAlgebraFeeManager(_newAlgebraFeeManager);
}
/// @inheritdoc IAlgebraCommunityVault
function acceptAlgebraFeeManagerRole() external override {
require(msg.sender == _pendingAlgebraFeeManager);
(_pendingAlgebraFeeManager, algebraFeeManager) = (address(0), msg.sender);
emit AlgebraFeeManager(msg.sender);
}
/// @inheritdoc IAlgebraCommunityVault
function proposeAlgebraFeeChange(uint16 newAlgebraFee) external override onlyAlgebraFeeManager {
require(newAlgebraFee <= ALGEBRA_FEE_DENOMINATOR);
require(newAlgebraFee != proposedNewAlgebraFee && newAlgebraFee != algebraFee);
(proposedNewAlgebraFee, hasNewAlgebraFeeProposal) = (newAlgebraFee, true);
emit AlgebraFeeProposal(newAlgebraFee);
}
/// @inheritdoc IAlgebraCommunityVault
function cancelAlgebraFeeChangeProposal() external override onlyAlgebraFeeManager {
(proposedNewAlgebraFee, hasNewAlgebraFeeProposal) = (0, false);
emit CancelAlgebraFeeProposal();
}
/// @inheritdoc IAlgebraCommunityVault
function changeAlgebraFeeReceiver(address newAlgebraFeeReceiver) external override onlyAlgebraFeeManager {
require(newAlgebraFeeReceiver != address(0));
require(newAlgebraFeeReceiver != algebraFeeReceiver);
algebraFeeReceiver = newAlgebraFeeReceiver;
emit AlgebraFeeReceiver(newAlgebraFeeReceiver);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title The interface for the Algebra community fee vault
/// @notice Community fee from pools is sent here, if it is enabled
/// @dev Version: Algebra Integral
interface IAlgebraCommunityVault {
/// @notice Event emitted when a fees has been claimed
/// @param token The address of token fee
/// @param to The address where claimed rewards were sent to
/// @param amount The amount of fees tokens claimed by communityFeeReceiver
event TokensWithdrawal(address indexed token, address indexed to, uint256 amount);
/// @notice Event emitted when a fees has been claimed
/// @param token The address of token fee
/// @param to The address where claimed rewards were sent to
/// @param amount The amount of fees tokens claimed by Algebra
event AlgebraTokensWithdrawal(address indexed token, address indexed to, uint256 amount);
/// @notice Emitted when a AlgebraFeeReceiver address changed
/// @param newAlgebraFeeReceiver New Algebra fee receiver address
event AlgebraFeeReceiver(address newAlgebraFeeReceiver);
/// @notice Emitted when a AlgebraFeeManager address change proposed
/// @param pendingAlgebraFeeManager New pending Algebra fee manager address
event PendingAlgebraFeeManager(address pendingAlgebraFeeManager);
/// @notice Emitted when a new Algebra fee value proposed
/// @param proposedNewAlgebraFee The new proposed Algebra fee value
event AlgebraFeeProposal(uint16 proposedNewAlgebraFee);
/// @notice Emitted when a Algebra fee proposal canceled
event CancelAlgebraFeeProposal();
/// @notice Emitted when a AlgebraFeeManager address changed
/// @param newAlgebraFeeManager New Algebra fee manager address
event AlgebraFeeManager(address newAlgebraFeeManager);
/// @notice Emitted when the Algebra fee is changed
/// @param newAlgebraFee The new Algebra fee value
event AlgebraFee(uint16 newAlgebraFee);
/// @notice Emitted when a CommunityFeeReceiver address changed
/// @param newCommunityFeeReceiver New fee receiver address
event CommunityFeeReceiver(address newCommunityFeeReceiver);
/// @notice Withdraw protocol fees from vault
/// @dev Can only be called by algebraFeeManager or communityFeeReceiver
/// @param token The token address
/// @param amount The amount of token
function withdraw(address token, uint256 amount) external;
struct WithdrawTokensParams {
address token;
uint256 amount;
}
/// @notice Withdraw protocol fees from vault. Used to claim fees for multiple tokens
/// @dev Can be called by algebraFeeManager or communityFeeReceiver
/// @param params Array of WithdrawTokensParams objects containing token addresses and amounts to withdraw
function withdrawTokens(WithdrawTokensParams[] calldata params) external;
// ### algebra factory owner permissioned actions ###
/// @notice Accepts the proposed new Algebra fee
/// @dev Can only be called by the factory owner.
/// The new value will also be used for previously accumulated tokens that have not yet been withdrawn
/// @param newAlgebraFee New Algebra fee value
function acceptAlgebraFeeChangeProposal(uint16 newAlgebraFee) external;
/// @notice Change community fee receiver address
/// @dev Can only be called by the factory owner
/// @param newCommunityFeeReceiver New community fee receiver address
function changeCommunityFeeReceiver(address newCommunityFeeReceiver) external;
// ### algebra fee manager permissioned actions ###
/// @notice Transfers Algebra fee manager role
/// @param _newAlgebraFeeManager new Algebra fee manager address
function transferAlgebraFeeManagerRole(address _newAlgebraFeeManager) external;
/// @notice accept Algebra FeeManager role
function acceptAlgebraFeeManagerRole() external;
/// @notice Proposes new Algebra fee value for protocol
/// @dev the new value will also be used for previously accumulated tokens that have not yet been withdrawn
/// @param newAlgebraFee new Algebra fee value
function proposeAlgebraFeeChange(uint16 newAlgebraFee) external;
/// @notice Cancels Algebra fee change proposal
function cancelAlgebraFeeChangeProposal() external;
/// @notice Change Algebra community fee part receiver
/// @param newAlgebraFeeReceiver The address of new Algebra fee receiver
function changeAlgebraFeeReceiver(address newAlgebraFeeReceiver) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
pragma abicoder v2;
import './plugin/IAlgebraPluginFactory.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 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 current communityVaultAddress
/// @return The address to which community fees are transferred
function communityVault() 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
/// @return Algebra plugin factory
function defaultPluginFactory() external view returns (IAlgebraPluginFactory);
/// @notice Returns the default communityFee and tickspacing
/// @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
function defaultConfigurationForPool() external view returns (uint16 communityFee, int24 tickSpacing, uint16 fee);
/// @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;
/// @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;
}// 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 Pools
/// @notice A contract that constructs a pool must implement this to pass arguments to the pool
/// @dev This is used to avoid having constructor arguments in the pool contract, which results in the init code hash
/// of the pool being constant allowing the CREATE2 address of the pool to be cheaply computed on-chain.
/// Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPoolDeployer {
/// @notice Get the parameters to be used in constructing the pool, set transiently during pool creation.
/// @dev Called by the pool constructor to fetch the parameters of the pool
/// @return plugin The pool associated plugin (if any)
/// @return factory The Algebra Factory address
/// @return communityVault The community vault address
/// @return token0 The first token of the pool by address sort order
/// @return token1 The second token of the pool by address sort order
function getDeployParameters() external view returns (address plugin, address factory, address communityVault, address token0, address token1);
/// @dev Deploys a pool with the given parameters by transiently setting the parameters in cache.
/// @param plugin The pool associated plugin (if any)
/// @param token0 The first token of the pool by address sort order
/// @param token1 The second token of the pool by address sort order
/// @return pool The deployed pool's address
function deploy(address plugin, address token0, address token1) external returns (address pool);
}// 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
/// @return New plugin address
function createPlugin(address pool) external returns (address);
}// 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();
}// 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');
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
/// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = a * b
// Compute the product mod 2**256 and mod 2**256 - 1
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2**256 + prod0
uint256 prod0 = a * b; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(a, b, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Make sure the result is less than 2**256.
// Also prevents denominator == 0
require(denominator > prod1);
// Handle non-overflow cases, 256 by 256 division
if (prod1 == 0) {
assembly {
result := div(prod0, denominator)
}
return result;
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0]
// Compute remainder using mulmod
// Subtract 256 bit remainder from 512 bit number
assembly {
let remainder := mulmod(a, b, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator
// Compute largest power of two divisor of denominator.
// Always >= 1.
uint256 twos = (0 - denominator) & denominator;
// Divide denominator by power of two
assembly {
denominator := div(denominator, twos)
}
// Divide [prod1 prod0] by the factors of two
assembly {
prod0 := div(prod0, twos)
}
// Shift in bits from prod1 into prod0. For this we need
// to flip `twos` such that it is 2**256 / twos.
// If twos is zero, then it becomes one
assembly {
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
// Invert denominator mod 2**256
// Now that denominator is an odd number, it has an inverse
// modulo 2**256 such that denominator * inv = 1 mod 2**256.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, denominator * inv = 1 mod 2**4
uint256 inv = (3 * denominator) ^ 2;
// Now use Newton-Raphson iteration to improve the precision.
// Thanks to Hensel's lifting lemma, this also works in modular
// arithmetic, doubling the correct bits in each step.
inv *= 2 - denominator * inv; // inverse mod 2**8
inv *= 2 - denominator * inv; // inverse mod 2**16
inv *= 2 - denominator * inv; // inverse mod 2**32
inv *= 2 - denominator * inv; // inverse mod 2**64
inv *= 2 - denominator * inv; // inverse mod 2**128
inv *= 2 - denominator * inv; // inverse mod 2**256
// Because the division is now exact we can divide by multiplying
// with the modular inverse of denominator. This will give us the
// correct result modulo 2**256. Since the preconditions guarantee
// that the outcome is less than 2**256, this is the final result.
// We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inv;
return result;
}
}
/// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
function mulDivRoundingUp(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
if (a == 0 || ((result = a * b) / a == b)) {
require(denominator > 0);
assembly {
result := add(div(result, denominator), gt(mod(result, denominator), 0))
}
} else {
result = mulDiv(a, b, denominator);
if (mulmod(a, b, denominator) > 0) {
require(result < type(uint256).max);
result++;
}
}
}
}
/// @notice Returns ceil(x / y)
/// @dev division by 0 has unspecified behavior, and must be checked externally
/// @param x The dividend
/// @param y The divisor
/// @return z The quotient, ceil(x / y)
function unsafeDivRoundingUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := add(div(x, y), gt(mod(x, y), 0))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;
import '../interfaces/pool/IAlgebraPoolErrors.sol';
/// @title SafeTransfer
/// @notice Safe ERC20 transfer library that gracefully handles missing return values.
/// @dev Credit to Solmate under MIT license: https://github.com/transmissions11/solmate/blob/ed67feda67b24fdeff8ad1032360f0ee6047ba0a/src/utils/SafeTransferLib.sol
/// @dev Please note that this library does not check if the token has a code! That responsibility is delegated to the caller.
library SafeTransfer {
/// @notice Transfers tokens to a recipient
/// @dev Calls transfer on token contract, errors with transferFailed() if transfer fails
/// @param token The contract address of the token which will be transferred
/// @param to The recipient of the transfer
/// @param amount The amount of the token to transfer
function safeTransfer(address token, address to, uint256 amount) internal {
bool success;
assembly {
let freeMemoryPointer := mload(0x40) // we will need to restore 0x40 slot
mstore(0x00, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) // "transfer(address,uint256)" selector
mstore(0x04, and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // append cleaned "to" address
mstore(0x24, amount)
// now we use 0x00 - 0x44 bytes (68), freeMemoryPointer is dirty
success := call(gas(), token, 0, 0, 0x44, 0, 0x20)
success := and(
// set success to true if call isn't reverted and returned exactly 1 (can't just be non-zero data) or nothing
or(and(eq(mload(0), 1), eq(returndatasize(), 32)), iszero(returndatasize())),
success
)
mstore(0x40, freeMemoryPointer) // restore the freeMemoryPointer
}
if (!success) revert IAlgebraPoolErrors.transferFailed();
}
}{
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 1000000
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_poolDeployer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"newDefaultCommunityFee","type":"uint16"}],"name":"DefaultCommunityFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"newDefaultFee","type":"uint16"}],"name":"DefaultFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"defaultPluginFactoryAddress","type":"address"}],"name":"DefaultPluginFactory","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int24","name":"newDefaultTickspacing","type":"int24"}],"name":"DefaultTickspacing","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token0","type":"address"},{"indexed":true,"internalType":"address","name":"token1","type":"address"},{"indexed":false,"internalType":"address","name":"pool","type":"address"}],"name":"Pool","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RenounceOwnershipFinish","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"finishTimestamp","type":"uint256"}],"name":"RenounceOwnershipStart","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RenounceOwnershipStop","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POOLS_ADMINISTRATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POOL_INIT_CODE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"communityVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"name":"computePoolAddress","outputs":[{"internalType":"address","name":"pool","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"createPool","outputs":[{"internalType":"address","name":"pool","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultCommunityFee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultConfigurationForPool","outputs":[{"internalType":"uint16","name":"communityFee","type":"uint16"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"uint16","name":"fee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultFee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultPluginFactory","outputs":[{"internalType":"contract IAlgebraPluginFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultTickspacing","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRoleOrOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"poolByPair","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolDeployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnershipStartTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newDefaultCommunityFee","type":"uint16"}],"name":"setDefaultCommunityFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newDefaultFee","type":"uint16"}],"name":"setDefaultFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newDefaultPluginFactory","type":"address"}],"name":"setDefaultPluginFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int24","name":"newDefaultTickspacing","type":"int24"}],"name":"setDefaultTickspacing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startRenounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopRenounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60c06040523480156200001157600080fd5b5060405162003bca38038062003bca83398101604081905262000034916200050f565b6200003f3362000131565b6001600160a01b0381166200005357600080fd5b6001600160a01b0381166080526040513390620000709062000501565b6001600160a01b039091168152602001604051809103906000f0801580156200009d573d6000803e3d6000fd5b506001600160a01b031660a0526004805466ffffffffff00001916643c01f40000179055604051603c81527f7d7979096f943139ebee59f01c077a0f0766d06c40c86d596f23ed2561547cce9060200160405180910390a16040516101f481527fddc0c6f0b581e0d51bfe90ff138e4a548f94515c4dbcb12f5e98fdf0f75039839060200160405180910390a1506200058f565b6200015060006200014a6000546001600160a01b031690565b6200018f565b6200015b81620001ba565b6000546001600160a01b0316156200018c576200018c6000620001866000546001600160a01b031690565b620001d5565b50565b6200019b8282620001fb565b6000828152600360205260409020620001b5908262000280565b505050565b600180546001600160a01b03191690556200018c81620002a0565b620001e18282620002f0565b6000828152600360205260409020620001b5908262000394565b60008281526002602090815260408083206001600160a01b038516845290915290205460ff16156200027c5760008281526002602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45b5050565b600062000297836001600160a01b038416620003ab565b90505b92915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008281526002602090815260408083206001600160a01b038516845290915290205460ff166200027c5760008281526002602090815260408083206001600160a01b03851684529091529020805460ff19166001179055620003503390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600062000297836001600160a01b038416620004af565b60008181526001830160205260408120548015620004a4576000620003d260018362000541565b8554909150600090620003e89060019062000541565b9050818114620004545760008660000182815481106200040c576200040c62000563565b906000526020600020015490508087600001848154811062000432576200043262000563565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062000468576200046862000579565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506200029a565b60009150506200029a565b6000818152600183016020526040812054620004f8575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200029a565b5060006200029a565b611784806200244683390190565b6000602082840312156200052257600080fd5b81516001600160a01b03811681146200053a57600080fd5b9392505050565b818103818111156200029a57634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60805160a051611e83620005c360003960006103a701526000818161034001528181610b320152610e950152611e836000f3fe608060405234801561001057600080fd5b50600436106102265760003560e01c80638d5a87111161012a578063d547741f116100bd578063e30c39781161008c578063e8ae2b6911610071578063e8ae2b69146105ab578063f09489ac146105be578063f2fde38b146105d157600080fd5b8063e30c39781461057a578063e34336151461059857600080fd5b8063d547741f146104ec578063d8ed2241146104ff578063d9a641e114610512578063dc6fd8ab1461055357600080fd5b8063a217fddf116100f9578063a217fddf1461048a578063b500a48b14610492578063ca15c873146104b9578063d0ad2792146104cc57600080fd5b80638d5a8711146104005780638da5cb5b146104135780639010d07c1461043157806391d148541461044457600080fd5b80632f8a39dd116101bd57806353e978681161018c578063715018a611610171578063715018a6146103dd57806377326584146103e557806379ba5097146103f857600080fd5b806353e97868146103a25780635a6c72d0146103c957600080fd5b80632f8a39dd1461031a5780633119049a1461033b57806336568abe14610387578063469388c41461039a57600080fd5b806325b355d6116101f957806325b355d6146102975780632939dd97146102cc57806329bc3446146102df5780632f2ff15d1461030757600080fd5b806301ffc9a71461022b578063084bfff914610253578063238a1d741461026a578063248a9ca314610274575b600080fd5b61023e610239366004611ad4565b6105e4565b60405190151581526020015b60405180910390f35b61025c60055481565b60405190815260200161024a565b610272610640565b005b61025c610282366004611b16565b60009081526002602052604090206001015490565b6004546040805161ffff8084168252640100000000840460020b6020830152620100009093049092169082015260600161024a565b6102726102da366004611b51565b610692565b6004546102f490640100000000900460020b81565b60405160029190910b815260200161024a565b610272610315366004611b6e565b61073c565b6004546103289061ffff1681565b60405161ffff909116815260200161024a565b6103627f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161024a565b610272610395366004611b6e565b610766565b61027261081e565b6103627f000000000000000000000000000000000000000000000000000000000000000081565b6004546103289062010000900461ffff1681565b61027261087d565b6102726103f3366004611b9e565b6108ee565b61027261098d565b61027261040e366004611b9e565b610a42565b60005473ffffffffffffffffffffffffffffffffffffffff16610362565b61036261043f366004611bc2565b610ad3565b61023e610452366004611b6e565b600091825260026020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b61025c600081565b61025c7fb73ce166ead2f8e9add217713a7989e4edfba9625f71dfd2516204bb67ad344281565b61025c6104c7366004611b16565b610af2565b6006546103629073ffffffffffffffffffffffffffffffffffffffff1681565b6102726104fa366004611b6e565b610b09565b61036261050d366004611be4565b610b2e565b610362610520366004611be4565b600760209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b61025c7f177d5fbf994f4d130c008797563306f1a168dc689f81b2fa23b4396931014d9181565b60015473ffffffffffffffffffffffffffffffffffffffff16610362565b6103626105a6366004611be4565b610c87565b61023e6105b9366004611b6e565b610fbd565b6102726105cc366004611c12565b61104a565b6102726105df366004611b51565b6110ff565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061063a575061063a826111ae565b92915050565b610648611245565b60055460000361065757600080fd5b60006005556040514281527fa2492902a0a1d28dc73e6ab22e473239ef077bb7bc8174dc7dab9fc0818e7135906020015b60405180910390a1565b61069a611245565b60065473ffffffffffffffffffffffffffffffffffffffff908116908216036106c257600080fd5b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f5e38e259ec1f8a38b98fc65a27e266bb9cc87c76eb8c96c957450d1cff4591ef906020015b60405180910390a150565b600082815260026020526040902060010154610757816112c8565b61076183836112d2565b505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610810576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b61081a82826112f4565b5050565b610826611245565b6005541561083357600080fd5b4260058190557fcd60f5d54996130c21c3f063279b39230bcbafc12f763a1ac1dfaec2e9b61d29906108686201518082611c64565b60408051928352602083019190915201610688565b610885611245565b60055460000361089457600080fd5b62015180600554426108a69190611c77565b10156108b157600080fd5b60006005556108be611316565b6040514281527fa24203c457ce43a097fa0c491fc9cf5e0a893af87a5e0a9785f29491deb11e2390602001610688565b6108f6611245565b61c35061ffff8216111561090957600080fd5b60045461ffff80831662010000909204160361092457600080fd5b600480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff166201000061ffff8416908102919091179091556040519081527fddc0c6f0b581e0d51bfe90ff138e4a548f94515c4dbcb12f5e98fdf0f750398390602001610731565b600154339073ffffffffffffffffffffffffffffffffffffffff168114610a36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152608401610807565b610a3f81611324565b50565b610a4a611245565b6103e861ffff82161115610a5d57600080fd5b60045461ffff808316911603610a7257600080fd5b600480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83169081179091556040519081527f6b5c342391f543846fce47a925e7eba910f7bec232b08633308ca93fdd0fdf0d90602001610731565b6000828152600360205260408120610aeb908361139d565b9392505050565b600081815260036020526040812061063a906113a9565b600082815260026020526040902060010154610b24816112c8565b61076183836112f4565b60007f00000000000000000000000000000000000000000000000000000000000000008383604051602001610b8692919073ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290528051602091820120610c4a939290917f177d5fbf994f4d130c008797563306f1a168dc689f81b2fa23b4396931014d9191017fff00000000000000000000000000000000000000000000000000000000000000815260609390931b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660018401526015830191909152603582015260550190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209392505050565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610cc157600080fd5b6000808373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1610610cfe578385610d01565b84845b909250905073ffffffffffffffffffffffffffffffffffffffff8216610d2657600080fd5b73ffffffffffffffffffffffffffffffffffffffff828116600090815260076020908152604080832085851684529091529020541615610d6557600080fd5b60065460009073ffffffffffffffffffffffffffffffffffffffff1615610e405760065473ffffffffffffffffffffffffffffffffffffffff1663361c0f76610dae8585610b2e565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016020604051808303816000875af1158015610e19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3d9190611c8a565b90505b6040517fd9181cd300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152848116602483015283811660448301527f0000000000000000000000000000000000000000000000000000000000000000169063d9181cd3906064016020604051808303816000875af1158015610ede573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f029190611c8a565b73ffffffffffffffffffffffffffffffffffffffff848116600081815260076020818152604080842089871680865290835281852080549789167fffffffffffffffffffffffff000000000000000000000000000000000000000098891681179091559383528185208686528352938190208054909616831790955593519081529397509290917f91ccaa7a278130b65168c3a0c8d3bcae84cf5e43704342bd3ec0b59e59c036db910160405180910390a350505092915050565b60008173ffffffffffffffffffffffffffffffffffffffff16610ff560005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161480610aeb5750600083815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8616845290915290205460ff16610aeb565b611052611245565b6001600282900b121561106457600080fd5b6101f4600282900b131561107757600080fd5b6004546401000000009004600290810b9082900b0361109557600080fd5b600480547fffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffff1664010000000062ffffff841602179055604051600282900b81527f7d7979096f943139ebee59f01c077a0f0766d06c40c86d596f23ed2561547cce90602001610731565b611107611245565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915561116960005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061063a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461063a565b60005473ffffffffffffffffffffffffffffffffffffffff1633146112c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610807565b565b610a3f81336113b3565b6112dc828261146d565b60008281526003602052604090206107619082611561565b6112fe8282611583565b6000828152600360205260409020610761908261163e565b61131e611245565b6112c660005b61134d600061134860005473ffffffffffffffffffffffffffffffffffffffff1690565b6112f4565b61135681611660565b60005473ffffffffffffffffffffffffffffffffffffffff1615610a3f57610a3f600061139860005473ffffffffffffffffffffffffffffffffffffffff1690565b6112d2565b6000610aeb8383611691565b600061063a825490565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1661081a576113f3816116bb565b6113fe8360206116da565b60405160200161140f929190611ccb565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261080791600401611d4c565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1661081a57600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556115033390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610aeb8373ffffffffffffffffffffffffffffffffffffffff841661191d565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff161561081a57600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610aeb8373ffffffffffffffffffffffffffffffffffffffff841661196c565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055610a3f81611a5f565b60008260000182815481106116a8576116a8611d9d565b9060005260206000200154905092915050565b606061063a73ffffffffffffffffffffffffffffffffffffffff831660145b606060006116e9836002611dcc565b6116f4906002611c64565b67ffffffffffffffff81111561170c5761170c611de3565b6040519080825280601f01601f191660200182016040528015611736576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061176d5761176d611d9d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106117d0576117d0611d9d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600061180c846002611dcc565b611817906001611c64565b90505b60018111156118b4577f303132333435363738396162636465660000000000000000000000000000000085600f166010811061185857611858611d9d565b1a60f81b82828151811061186e5761186e611d9d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c936118ad81611e12565b905061181a565b508315610aeb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610807565b60008181526001830160205260408120546119645750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561063a565b50600061063a565b60008181526001830160205260408120548015611a55576000611990600183611c77565b85549091506000906119a490600190611c77565b9050818114611a095760008660000182815481106119c4576119c4611d9d565b90600052602060002001549050808760000184815481106119e7576119e7611d9d565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611a1a57611a1a611e47565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061063a565b600091505061063a565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600060208284031215611ae657600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610aeb57600080fd5b600060208284031215611b2857600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610a3f57600080fd5b600060208284031215611b6357600080fd5b8135610aeb81611b2f565b60008060408385031215611b8157600080fd5b823591506020830135611b9381611b2f565b809150509250929050565b600060208284031215611bb057600080fd5b813561ffff81168114610aeb57600080fd5b60008060408385031215611bd557600080fd5b50508035926020909101359150565b60008060408385031215611bf757600080fd5b8235611c0281611b2f565b91506020830135611b9381611b2f565b600060208284031215611c2457600080fd5b81358060020b8114610aeb57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561063a5761063a611c35565b8181038181111561063a5761063a611c35565b600060208284031215611c9c57600080fd5b8151610aeb81611b2f565b60005b83811015611cc2578181015183820152602001611caa565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351611d03816017850160208801611ca7565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351611d40816028840160208801611ca7565b01602801949350505050565b6020815260008251806020840152611d6b816040850160208701611ca7565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b808202811582820484141761063a5761063a611c35565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600081611e2157611e21611c35565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000814000a60a060405234801561001057600080fd5b5060405161178438038061178483398101604081905261002f91610058565b600280546001600160a01b0319166001600160a01b039290921691909117905533608052610088565b60006020828403121561006a57600080fd5b81516001600160a01b038116811461008157600080fd5b9392505050565b6080516116cc6100b86000396000818161065601528181610acd01528181610ca60152610e0701526116cc6000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c8063ad6129ac116100b2578063d17bc78311610081578063dfadc79411610066578063dfadc794146102fd578063f3fef3a314610310578063ff3c43e11461032357600080fd5b8063d17bc783146102e2578063d9fb4353146102ea57600080fd5b8063ad6129ac14610269578063b5f680ae14610271578063bbac3b8d14610284578063c53b3fbe146102ab57600080fd5b806350eea0c8116100ee57806350eea0c8146101d457806362744405146101e75780639d754dde146102235780639f856b8d1461024357600080fd5b80631de4161314610120578063371abc951461015a5780634738761c1461019f57806348a50fcf146101bf575b600080fd5b6101477fb77a63f119f4dc2174dc6c76fc1a1565fa4f2b0dde50ed5c0465471cd9b331f681565b6040519081526020015b60405180910390f35b60005461017a9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610151565b60015461017a9073ffffffffffffffffffffffffffffffffffffffff1681565b6101d26101cd366004611521565b610336565b005b6101d26101e2366004611521565b61047e565b6000546102109077010000000000000000000000000000000000000000000000900461ffff1681565b60405161ffff9091168152602001610151565b60025461017a9073ffffffffffffffffffffffffffffffffffffffff1681565b6000546102109074010000000000000000000000000000000000000000900461ffff1681565b6101d2610572565b6101d261027f366004611521565b610602565b6101477f63e58c34d94475ba3fc063e19800b940485850d84d09cd3c1f2c14192c559a6881565b6000546102d290760100000000000000000000000000000000000000000000900460ff1681565b6040519015158152602001610151565b6101d26107f7565b6101d26102f836600461153c565b6108c9565b6101d261030b366004611560565b610a58565b6101d261031e3660046115d5565b610c31565b6101d261033136600461153c565b610db3565b60025473ffffffffffffffffffffffffffffffffffffffff1633146103bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6f6e6c7920616c676562726120666565206d616e61676572000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166103dc57600080fd5b60015473ffffffffffffffffffffffffffffffffffffffff9081169082160361040457600080fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f34d1b5ef1c1c2c03a5000b91bef5c465790244c6751c794e5b45bed7657c38fd906020015b60405180910390a150565b60025473ffffffffffffffffffffffffffffffffffffffff1633146104ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6f6e6c7920616c676562726120666565206d616e61676572000000000000000060448201526064016103b3565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fab6918ba7303f2f81e46e324b5f34af4bda562577c1da710e2034980fee1e82a90602001610473565b60035473ffffffffffffffffffffffffffffffffffffffff16331461059657600080fd5b60028054337fffffffffffffffffffffffff000000000000000000000000000000000000000091821681179092556003805490911690556040519081527fecf97a11fb2f2bcc38d1b6881865ecc04405af2d8b953004c79b3ab398732d029060200160405180910390a1565b6040517fe8ae2b690000000000000000000000000000000000000000000000000000000081527f63e58c34d94475ba3fc063e19800b940485850d84d09cd3c1f2c14192c559a6860048201523360248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e8ae2b6990604401602060405180830381865afa1580156106b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d691906115ff565b61073c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6f6e6c792061646d696e6973747261746f72000000000000000000000000000060448201526064016103b3565b73ffffffffffffffffffffffffffffffffffffffff811661075c57600080fd5b60005473ffffffffffffffffffffffffffffffffffffffff9081169082160361078457600080fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f2f4db788b994a5908051d68a2340153f49870447185a244d2326861e60cc418690602001610473565b60025473ffffffffffffffffffffffffffffffffffffffff163314610878576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6f6e6c7920616c676562726120666565206d616e61676572000000000000000060448201526064016103b3565b600080547fffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffff1681556040517f9f4bbade0736edbd2ec12c598bdac4573af13a3b57820ae4c7da5c61703eaaff9190a1565b60025473ffffffffffffffffffffffffffffffffffffffff16331461094a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6f6e6c7920616c676562726120666565206d616e61676572000000000000000060448201526064016103b3565b6103e861ffff8216111561095d57600080fd5b60005461ffff8281167701000000000000000000000000000000000000000000000090920416148015906109b2575060005461ffff828116740100000000000000000000000000000000000000009092041614155b6109bb57600080fd5b6000805461ffff831677010000000000000000000000000000000000000000000000027fffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffff909116177601000000000000000000000000000000000000000000001790556040517f2d6ac59d6da98f80c7ea481d17c670ea310b000fff5cf1732d94d93652dd25b79061047390839061ffff91909116815260200190565b60025473ffffffffffffffffffffffffffffffffffffffff16331480610b4d57506040517fe8ae2b690000000000000000000000000000000000000000000000000000000081527fb77a63f119f4dc2174dc6c76fc1a1565fa4f2b0dde50ed5c0465471cd9b331f660048201523360248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e8ae2b6990604401602060405180830381865afa158015610b29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4d91906115ff565b610bb3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c792077697468647261776572000000000000000000000000000000000060448201526064016103b3565b8060008080610bc061109d565b92509250925060005b84811015610c2857610c20878783818110610be657610be6611621565b610bfc9260206040909202019081019150611521565b83898985818110610c0f57610c0f611621565b9050604002016020013587876111df565b600101610bc9565b50505050505050565b60025473ffffffffffffffffffffffffffffffffffffffff16331480610d2657506040517fe8ae2b690000000000000000000000000000000000000000000000000000000081527fb77a63f119f4dc2174dc6c76fc1a1565fa4f2b0dde50ed5c0465471cd9b331f660048201523360248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e8ae2b6990604401602060405180830381865afa158015610d02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2691906115ff565b610d8c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c792077697468647261776572000000000000000000000000000000000060448201526064016103b3565b6000806000610d9961109d565b925092509250610dac85828686866111df565b5050505050565b6040517fe8ae2b690000000000000000000000000000000000000000000000000000000081527f63e58c34d94475ba3fc063e19800b940485850d84d09cd3c1f2c14192c559a6860048201523360248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e8ae2b6990604401602060405180830381865afa158015610e63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8791906115ff565b610eed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6f6e6c792061646d696e6973747261746f72000000000000000000000000000060448201526064016103b3565b600054760100000000000000000000000000000000000000000000900460ff16610f73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f6e6f742070726f706f736564000000000000000000000000000000000000000060448201526064016103b3565b60005461ffff828116770100000000000000000000000000000000000000000000009092041614611000576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f696e76616c6964206e657720666565000000000000000000000000000000000060448201526064016103b3565b600080547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000061ffff84169081027fffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffff16919091179091556040519081527fda1e1a9a6410acc0398b3b64e0c0110b8df57e29bfe69a419cdd9ae12718c30790602001610473565b60005460015461ffff740100000000000000000000000000000000000000008304169173ffffffffffffffffffffffffffffffffffffffff9182169116821561115d5773ffffffffffffffffffffffffffffffffffffffff821661115d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f696e76616c696420616c6765627261206665652072656365697665720000000060448201526064016103b3565b73ffffffffffffffffffffffffffffffffffffffff81166111da576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f696e76616c69642072656365697665720000000000000000000000000000000060448201526064016103b3565b909192565b8261ffff83161561127f5760006111fd8261ffff86166103e86112f9565b90506112098183611650565b9150611216878483611398565b8273ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fb7ee7fc9dacb957cfa93faeb8ca1826292de295e18e287a347dddfde7ab48b408360405161127591815260200190565b60405180910390a3505b61128a868683611398565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167f7a629b77ef27ad337abe438773206187960a90abfb43607826bef77d650e84b9836040516112e991815260200190565b60405180910390a3505050505050565b600083158061131a5750508282028284828161131757611317611690565b04145b1561133b576000821161132c57600080fd5b81810490829006151501611391565b611346848484611441565b90506000828061135857611358611690565b8486091115611391577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811061138d57600080fd5b6001015b9392505050565b60006040517fa9059cbb0000000000000000000000000000000000000000000000000000000060005273ffffffffffffffffffffffffffffffffffffffff841660045282602452602060006044600080895af19150813d1560203d14600160005114161716915080604052508061143b576040517fe465903e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b6000838302817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8587098281108382030391505080841161148157600080fd5b8060000361149457508290049050611391565b8385870960008581038616958690049560026003880281188089028203028089028203028089028203028089028203028089028203028089029091030291819003819004600101858411909403939093029190930391909104170290509392505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461151c57600080fd5b919050565b60006020828403121561153357600080fd5b611391826114f8565b60006020828403121561154e57600080fd5b813561ffff8116811461139157600080fd5b6000806020838503121561157357600080fd5b823567ffffffffffffffff8082111561158b57600080fd5b818501915085601f83011261159f57600080fd5b8135818111156115ae57600080fd5b8660208260061b85010111156115c357600080fd5b60209290920196919550909350505050565b600080604083850312156115e857600080fd5b6115f1836114f8565b946020939093013593505050565b60006020828403121561161157600080fd5b8151801515811461139157600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8181038181111561168a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea164736f6c6343000814000a0000000000000000000000009de2dea5c68898eb4cb2deaff357dfb26255a4aa
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102265760003560e01c80638d5a87111161012a578063d547741f116100bd578063e30c39781161008c578063e8ae2b6911610071578063e8ae2b69146105ab578063f09489ac146105be578063f2fde38b146105d157600080fd5b8063e30c39781461057a578063e34336151461059857600080fd5b8063d547741f146104ec578063d8ed2241146104ff578063d9a641e114610512578063dc6fd8ab1461055357600080fd5b8063a217fddf116100f9578063a217fddf1461048a578063b500a48b14610492578063ca15c873146104b9578063d0ad2792146104cc57600080fd5b80638d5a8711146104005780638da5cb5b146104135780639010d07c1461043157806391d148541461044457600080fd5b80632f8a39dd116101bd57806353e978681161018c578063715018a611610171578063715018a6146103dd57806377326584146103e557806379ba5097146103f857600080fd5b806353e97868146103a25780635a6c72d0146103c957600080fd5b80632f8a39dd1461031a5780633119049a1461033b57806336568abe14610387578063469388c41461039a57600080fd5b806325b355d6116101f957806325b355d6146102975780632939dd97146102cc57806329bc3446146102df5780632f2ff15d1461030757600080fd5b806301ffc9a71461022b578063084bfff914610253578063238a1d741461026a578063248a9ca314610274575b600080fd5b61023e610239366004611ad4565b6105e4565b60405190151581526020015b60405180910390f35b61025c60055481565b60405190815260200161024a565b610272610640565b005b61025c610282366004611b16565b60009081526002602052604090206001015490565b6004546040805161ffff8084168252640100000000840460020b6020830152620100009093049092169082015260600161024a565b6102726102da366004611b51565b610692565b6004546102f490640100000000900460020b81565b60405160029190910b815260200161024a565b610272610315366004611b6e565b61073c565b6004546103289061ffff1681565b60405161ffff909116815260200161024a565b6103627f0000000000000000000000009de2dea5c68898eb4cb2deaff357dfb26255a4aa81565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161024a565b610272610395366004611b6e565b610766565b61027261081e565b6103627f000000000000000000000000295ae2f79638198731643ef819d2833d981f189781565b6004546103289062010000900461ffff1681565b61027261087d565b6102726103f3366004611b9e565b6108ee565b61027261098d565b61027261040e366004611b9e565b610a42565b60005473ffffffffffffffffffffffffffffffffffffffff16610362565b61036261043f366004611bc2565b610ad3565b61023e610452366004611b6e565b600091825260026020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b61025c600081565b61025c7fb73ce166ead2f8e9add217713a7989e4edfba9625f71dfd2516204bb67ad344281565b61025c6104c7366004611b16565b610af2565b6006546103629073ffffffffffffffffffffffffffffffffffffffff1681565b6102726104fa366004611b6e565b610b09565b61036261050d366004611be4565b610b2e565b610362610520366004611be4565b600760209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b61025c7f177d5fbf994f4d130c008797563306f1a168dc689f81b2fa23b4396931014d9181565b60015473ffffffffffffffffffffffffffffffffffffffff16610362565b6103626105a6366004611be4565b610c87565b61023e6105b9366004611b6e565b610fbd565b6102726105cc366004611c12565b61104a565b6102726105df366004611b51565b6110ff565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061063a575061063a826111ae565b92915050565b610648611245565b60055460000361065757600080fd5b60006005556040514281527fa2492902a0a1d28dc73e6ab22e473239ef077bb7bc8174dc7dab9fc0818e7135906020015b60405180910390a1565b61069a611245565b60065473ffffffffffffffffffffffffffffffffffffffff908116908216036106c257600080fd5b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f5e38e259ec1f8a38b98fc65a27e266bb9cc87c76eb8c96c957450d1cff4591ef906020015b60405180910390a150565b600082815260026020526040902060010154610757816112c8565b61076183836112d2565b505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610810576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b61081a82826112f4565b5050565b610826611245565b6005541561083357600080fd5b4260058190557fcd60f5d54996130c21c3f063279b39230bcbafc12f763a1ac1dfaec2e9b61d29906108686201518082611c64565b60408051928352602083019190915201610688565b610885611245565b60055460000361089457600080fd5b62015180600554426108a69190611c77565b10156108b157600080fd5b60006005556108be611316565b6040514281527fa24203c457ce43a097fa0c491fc9cf5e0a893af87a5e0a9785f29491deb11e2390602001610688565b6108f6611245565b61c35061ffff8216111561090957600080fd5b60045461ffff80831662010000909204160361092457600080fd5b600480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff166201000061ffff8416908102919091179091556040519081527fddc0c6f0b581e0d51bfe90ff138e4a548f94515c4dbcb12f5e98fdf0f750398390602001610731565b600154339073ffffffffffffffffffffffffffffffffffffffff168114610a36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152608401610807565b610a3f81611324565b50565b610a4a611245565b6103e861ffff82161115610a5d57600080fd5b60045461ffff808316911603610a7257600080fd5b600480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83169081179091556040519081527f6b5c342391f543846fce47a925e7eba910f7bec232b08633308ca93fdd0fdf0d90602001610731565b6000828152600360205260408120610aeb908361139d565b9392505050565b600081815260036020526040812061063a906113a9565b600082815260026020526040902060010154610b24816112c8565b61076183836112f4565b60007f0000000000000000000000009de2dea5c68898eb4cb2deaff357dfb26255a4aa8383604051602001610b8692919073ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290528051602091820120610c4a939290917f177d5fbf994f4d130c008797563306f1a168dc689f81b2fa23b4396931014d9191017fff00000000000000000000000000000000000000000000000000000000000000815260609390931b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660018401526015830191909152603582015260550190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209392505050565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610cc157600080fd5b6000808373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1610610cfe578385610d01565b84845b909250905073ffffffffffffffffffffffffffffffffffffffff8216610d2657600080fd5b73ffffffffffffffffffffffffffffffffffffffff828116600090815260076020908152604080832085851684529091529020541615610d6557600080fd5b60065460009073ffffffffffffffffffffffffffffffffffffffff1615610e405760065473ffffffffffffffffffffffffffffffffffffffff1663361c0f76610dae8585610b2e565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016020604051808303816000875af1158015610e19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3d9190611c8a565b90505b6040517fd9181cd300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152848116602483015283811660448301527f0000000000000000000000009de2dea5c68898eb4cb2deaff357dfb26255a4aa169063d9181cd3906064016020604051808303816000875af1158015610ede573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f029190611c8a565b73ffffffffffffffffffffffffffffffffffffffff848116600081815260076020818152604080842089871680865290835281852080549789167fffffffffffffffffffffffff000000000000000000000000000000000000000098891681179091559383528185208686528352938190208054909616831790955593519081529397509290917f91ccaa7a278130b65168c3a0c8d3bcae84cf5e43704342bd3ec0b59e59c036db910160405180910390a350505092915050565b60008173ffffffffffffffffffffffffffffffffffffffff16610ff560005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161480610aeb5750600083815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8616845290915290205460ff16610aeb565b611052611245565b6001600282900b121561106457600080fd5b6101f4600282900b131561107757600080fd5b6004546401000000009004600290810b9082900b0361109557600080fd5b600480547fffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffff1664010000000062ffffff841602179055604051600282900b81527f7d7979096f943139ebee59f01c077a0f0766d06c40c86d596f23ed2561547cce90602001610731565b611107611245565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915561116960005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061063a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461063a565b60005473ffffffffffffffffffffffffffffffffffffffff1633146112c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610807565b565b610a3f81336113b3565b6112dc828261146d565b60008281526003602052604090206107619082611561565b6112fe8282611583565b6000828152600360205260409020610761908261163e565b61131e611245565b6112c660005b61134d600061134860005473ffffffffffffffffffffffffffffffffffffffff1690565b6112f4565b61135681611660565b60005473ffffffffffffffffffffffffffffffffffffffff1615610a3f57610a3f600061139860005473ffffffffffffffffffffffffffffffffffffffff1690565b6112d2565b6000610aeb8383611691565b600061063a825490565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1661081a576113f3816116bb565b6113fe8360206116da565b60405160200161140f929190611ccb565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261080791600401611d4c565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1661081a57600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556115033390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610aeb8373ffffffffffffffffffffffffffffffffffffffff841661191d565b600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff161561081a57600082815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610aeb8373ffffffffffffffffffffffffffffffffffffffff841661196c565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055610a3f81611a5f565b60008260000182815481106116a8576116a8611d9d565b9060005260206000200154905092915050565b606061063a73ffffffffffffffffffffffffffffffffffffffff831660145b606060006116e9836002611dcc565b6116f4906002611c64565b67ffffffffffffffff81111561170c5761170c611de3565b6040519080825280601f01601f191660200182016040528015611736576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061176d5761176d611d9d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106117d0576117d0611d9d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600061180c846002611dcc565b611817906001611c64565b90505b60018111156118b4577f303132333435363738396162636465660000000000000000000000000000000085600f166010811061185857611858611d9d565b1a60f81b82828151811061186e5761186e611d9d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c936118ad81611e12565b905061181a565b508315610aeb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610807565b60008181526001830160205260408120546119645750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561063a565b50600061063a565b60008181526001830160205260408120548015611a55576000611990600183611c77565b85549091506000906119a490600190611c77565b9050818114611a095760008660000182815481106119c4576119c4611d9d565b90600052602060002001549050808760000184815481106119e7576119e7611d9d565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611a1a57611a1a611e47565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061063a565b600091505061063a565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600060208284031215611ae657600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610aeb57600080fd5b600060208284031215611b2857600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610a3f57600080fd5b600060208284031215611b6357600080fd5b8135610aeb81611b2f565b60008060408385031215611b8157600080fd5b823591506020830135611b9381611b2f565b809150509250929050565b600060208284031215611bb057600080fd5b813561ffff81168114610aeb57600080fd5b60008060408385031215611bd557600080fd5b50508035926020909101359150565b60008060408385031215611bf757600080fd5b8235611c0281611b2f565b91506020830135611b9381611b2f565b600060208284031215611c2457600080fd5b81358060020b8114610aeb57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561063a5761063a611c35565b8181038181111561063a5761063a611c35565b600060208284031215611c9c57600080fd5b8151610aeb81611b2f565b60005b83811015611cc2578181015183820152602001611caa565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351611d03816017850160208801611ca7565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351611d40816028840160208801611ca7565b01602801949350505050565b6020815260008251806020840152611d6b816040850160208701611ca7565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b808202811582820484141761063a5761063a611c35565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600081611e2157611e21611c35565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000814000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000009de2dea5c68898eb4cb2deaff357dfb26255a4aa
-----Decoded View---------------
Arg [0] : _poolDeployer (address): 0x9dE2dEA5c68898eb4cb2DeaFf357DFB26255a4aa
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000009de2dea5c68898eb4cb2deaff357dfb26255a4aa
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in MNT
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.