APE Price: $1.18 (+6.69%)

Contract

0x96A60961230406025a9D4e4BE077841A87b176DA

Overview

APE Balance

Apechain LogoApechain LogoApechain Logo0 APE

APE Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x6080604046033282024-11-18 19:15:462 days ago1731957346IN
 Create: GNSFeeTiers
0 APE0.0559412525.42069

Parent Transaction Hash Block From To
View All Internal Transactions

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
GNSFeeTiers

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 800 runs

Other Settings:
paris EvmVersion
File 1 of 16 : GNSFeeTiers.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import "../abstract/GNSAddressStore.sol";

import "../../interfaces/libraries/IFeeTiersUtils.sol";

import "../../libraries/FeeTiersUtils.sol";
import "../../libraries/PairsStorageUtils.sol";

/**
 * @dev Facet #3: Fee tiers
 */
contract GNSFeeTiers is GNSAddressStore, IFeeTiersUtils {
    // Initialization

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    /// @inheritdoc IFeeTiersUtils
    function initializeFeeTiers(
        uint256[] calldata _groupIndices,
        uint256[] calldata _groupVolumeMultipliers,
        uint256[] calldata _feeTiersIndices,
        IFeeTiersUtils.FeeTier[] calldata _feeTiers
    ) external reinitializer(4) {
        FeeTiersUtils.initializeFeeTiers(_groupIndices, _groupVolumeMultipliers, _feeTiersIndices, _feeTiers);
    }

    // Management Setters

    /// @inheritdoc IFeeTiersUtils
    function setGroupVolumeMultipliers(
        uint256[] calldata _groupIndices,
        uint256[] calldata _groupVolumeMultipliers
    ) external onlyRole(Role.GOV) {
        FeeTiersUtils.setGroupVolumeMultipliers(_groupIndices, _groupVolumeMultipliers);
    }

    /// @inheritdoc IFeeTiersUtils
    function setFeeTiers(
        uint256[] calldata _feeTiersIndices,
        IFeeTiersUtils.FeeTier[] calldata _feeTiers
    ) external onlyRole(Role.GOV) {
        FeeTiersUtils.setFeeTiers(_feeTiersIndices, _feeTiers);
    }

    /// @inheritdoc IFeeTiersUtils
    function setTradersFeeTiersEnrollment(
        address[] calldata _traders,
        IFeeTiersUtils.TraderEnrollment[] calldata _values
    ) external onlyRoles(Role.GOV, Role.GOV_EMERGENCY) {
        FeeTiersUtils.setTradersFeeTiersEnrollment(_traders, _values);
    }

    /// @inheritdoc IFeeTiersUtils
    function addTradersUnclaimedPoints(
        address[] calldata _traders,
        IFeeTiersUtils.CreditType[] calldata _creditTypes,
        uint224[] calldata _points
    ) external onlyRole(Role.GOV) {
        FeeTiersUtils.addTradersUnclaimedPoints(_traders, _creditTypes, _points);
    }

    // Interactions

    /// @inheritdoc IFeeTiersUtils
    function updateTraderPoints(address _trader, uint256 _volumeUsd, uint256 _pairIndex) external virtual onlySelf {
        FeeTiersUtils.updateTraderPoints(_trader, _volumeUsd, PairsStorageUtils.pairFeeIndex(_pairIndex));
    }

    // Getters

    /// @inheritdoc IFeeTiersUtils
    function calculateFeeAmount(address _trader, uint256 _normalFeeAmountCollateral) external view returns (uint256) {
        return FeeTiersUtils.calculateFeeAmount(_trader, _normalFeeAmountCollateral);
    }

    /// @inheritdoc IFeeTiersUtils
    function getFeeTiersCount() external view returns (uint256) {
        return FeeTiersUtils.getFeeTiersCount();
    }

    /// @inheritdoc IFeeTiersUtils
    function getFeeTier(uint256 _feeTierIndex) external view returns (IFeeTiersUtils.FeeTier memory) {
        return FeeTiersUtils.getFeeTier(_feeTierIndex);
    }

    /// @inheritdoc IFeeTiersUtils
    function getGroupVolumeMultiplier(uint256 _groupIndex) external view returns (uint256) {
        return FeeTiersUtils.getGroupVolumeMultiplier(_groupIndex);
    }

    /// @inheritdoc IFeeTiersUtils
    function getFeeTiersTraderInfo(address _trader) external view returns (IFeeTiersUtils.TraderInfo memory) {
        return FeeTiersUtils.getFeeTiersTraderInfo(_trader);
    }

    /// @inheritdoc IFeeTiersUtils
    function getFeeTiersTraderDailyInfo(
        address _trader,
        uint32 _day
    ) external view returns (IFeeTiersUtils.TraderDailyInfo memory) {
        return FeeTiersUtils.getFeeTiersTraderDailyInfo(_trader, _day);
    }

    /// @inheritdoc IFeeTiersUtils
    function getTraderFeeTiersEnrollment(
        address _trader
    ) external view returns (IFeeTiersUtils.TraderEnrollment memory) {
        return FeeTiersUtils.getTraderFeeTiersEnrollment(_trader);
    }

    /// @inheritdoc IFeeTiersUtils
    function getTraderUnclaimedPoints(address _trader) external view returns (uint224) {
        return FeeTiersUtils.getTraderUnclaimedPoints(_trader);
    }
}

File 2 of 16 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized != type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

File 3 of 16 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 4 of 16 : GNSAddressStore.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

import "../../interfaces/IGNSAddressStore.sol";

/**
 * @dev Proxy base for the diamond and its facet contracts to store addresses and manage access control
 */
abstract contract GNSAddressStore is Initializable, IGNSAddressStore {
    AddressStore private addressStore;

    /// @inheritdoc IGNSAddressStore
    function initialize(address _govTimelock) external initializer {
        if (_govTimelock == address(0)) {
            revert IGeneralErrors.InitError();
        }

        _setRole(_govTimelock, Role.GOV_TIMELOCK, true);
    }

    // Addresses

    /// @inheritdoc IGNSAddressStore
    function getAddresses() external view returns (Addresses memory) {
        return addressStore.globalAddresses;
    }

    // Roles

    /// @inheritdoc IGNSAddressStore
    function hasRole(address _account, Role _role) public view returns (bool) {
        return addressStore.accessControl[_account][_role];
    }

    /// @inheritdoc IGNSAddressStore
    function hasRoles(address _account, Role _roleA, Role _roleB) public view returns (bool) {
        return addressStore.accessControl[_account][_roleA] || addressStore.accessControl[_account][_roleB];
    }

    /**
     * @dev Update role for account
     * @param _account account to update
     * @param _role role to set
     * @param _value true if allowed, false if not
     */
    function _setRole(address _account, Role _role, bool _value) internal {
        addressStore.accessControl[_account][_role] = _value;
        emit AccessControlUpdated(_account, _role, _value);
    }

    /// @inheritdoc IGNSAddressStore
    function setRoles(
        address[] calldata _accounts,
        Role[] calldata _roles,
        bool[] calldata _values
    ) external onlyRole(Role.GOV_TIMELOCK) {
        if (_accounts.length != _roles.length || _accounts.length != _values.length) {
            revert IGeneralErrors.InvalidInputLength();
        }

        for (uint256 i = 0; i < _accounts.length; ++i) {
            if (_roles[i] == Role.GOV_TIMELOCK && _accounts[i] == msg.sender) {
                revert NotAllowed();
            }

            _setRole(_accounts[i], _roles[i], _values[i]);
        }
    }

    /**
     * @dev Reverts if caller does not have role
     * @param _role role to enforce
     */
    function _enforceRole(Role _role) internal view {
        if (!hasRole(msg.sender, _role)) {
            revert WrongAccess();
        }
    }

    /**
     * @dev Reverts if caller does not have at least one of the two roles
     * @param _roleA role to enforce
     * @param _roleB role to enforce
     */
    function _enforceRoles(Role _roleA, Role _roleB) internal view {
        if (!hasRoles(msg.sender, _roleA, _roleB)) {
            revert WrongAccess();
        }
    }

    /**
     * @dev Reverts if caller does not have role
     */
    modifier onlyRole(Role _role) {
        _enforceRole(_role);
        _;
    }

    /**
     * @dev Reverts if caller does not have either of the roles
     */
    modifier onlyRoles(Role _roleA, Role _roleB) {
        _enforceRoles(_roleA, _roleB);
        _;
    }

    /**
     * @dev Reverts if caller isn't this same contract (facets calling other facets)
     */
    modifier onlySelf() {
        if (msg.sender != address(this)) {
            revert WrongAccess();
        }
        _;
    }
}

File 5 of 16 : IGeneralErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

/**
 * @dev Interface for errors potentially used in all libraries (general names)
 */
interface IGeneralErrors {
    error InitError();
    error InvalidAddresses();
    error InvalidAddress();
    error InvalidInputLength();
    error InvalidCollateralIndex();
    error WrongParams();
    error WrongLength();
    error WrongOrder();
    error WrongIndex();
    error BlockOrder();
    error Overflow();
    error ZeroAddress();
    error ZeroValue();
    error AlreadyExists();
    error DoesntExist();
    error Paused();
    error BelowMin();
    error AboveMax();
    error NotAuthorized();
    error WrongTradeType();
    error WrongOrderType();
    error InsufficientBalance();
    error UnsupportedChain();
}

File 6 of 16 : IGNSAddressStore.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import "./types/IAddressStore.sol";
import "./IGeneralErrors.sol";

/**
 * @dev Interface for AddressStoreUtils library
 */
interface IGNSAddressStore is IAddressStore, IGeneralErrors {
    /**
     * @dev Initializes address store facet
     * @param _rolesManager roles manager address
     */
    function initialize(address _rolesManager) external;

    /**
     * @dev Returns addresses current values
     */
    function getAddresses() external view returns (Addresses memory);

    /**
     * @dev Returns whether an account has been granted a particular role
     * @param _account account address to check
     * @param _role role to check
     */
    function hasRole(address _account, Role _role) external view returns (bool);

    /**
     * @dev Returns whether an account has been granted at least one of two roles
     * @param _account address to check
     * @param _roleA first role to check
     * @param _roleB second role to check
     */
    function hasRoles(address _account, Role _roleA, Role _roleB) external view returns (bool);

    /**
     * @dev Updates access control for a list of accounts
     * @param _accounts accounts addresses to update
     * @param _roles corresponding roles to update
     * @param _values corresponding new values to set
     */
    function setRoles(address[] calldata _accounts, Role[] calldata _roles, bool[] calldata _values) external;

    /**
     * @dev Emitted when addresses are updated
     * @param addresses new addresses values
     */
    event AddressesUpdated(Addresses addresses);

    /**
     * @dev Emitted when access control is updated for an account
     * @param target account address to update
     * @param role role to update
     * @param access whether role is granted or revoked
     */
    event AccessControlUpdated(address target, Role role, bool access);

    error NotAllowed();
    error WrongAccess();
}

File 7 of 16 : IFeeTiersUtils.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import "../types/IFeeTiers.sol";

/**
 * @dev Interface for GNSFeeTiers facet (inherits types and also contains functions, events, and custom errors)
 */
interface IFeeTiersUtils is IFeeTiers {
    /**
     *
     * @param _groupIndices group indices (pairs storage fee index) to initialize
     * @param _groupVolumeMultipliers corresponding group volume multipliers (1e3)
     * @param _feeTiersIndices fee tiers indices to initialize
     * @param _feeTiers fee tiers values to initialize (feeMultiplier, pointsThreshold)
     */
    function initializeFeeTiers(
        uint256[] calldata _groupIndices,
        uint256[] calldata _groupVolumeMultipliers,
        uint256[] calldata _feeTiersIndices,
        IFeeTiersUtils.FeeTier[] calldata _feeTiers
    ) external;

    /**
     * @dev Updates groups volume multipliers
     * @param _groupIndices indices of groups to update
     * @param _groupVolumeMultipliers corresponding new volume multipliers (1e3)
     */
    function setGroupVolumeMultipliers(
        uint256[] calldata _groupIndices,
        uint256[] calldata _groupVolumeMultipliers
    ) external;

    /**
     * @dev Updates fee tiers
     * @param _feeTiersIndices indices of fee tiers to update
     * @param _feeTiers new fee tiers values (feeMultiplier, pointsThreshold)
     */
    function setFeeTiers(uint256[] calldata _feeTiersIndices, IFeeTiersUtils.FeeTier[] calldata _feeTiers) external;

    /**
     * @dev Updates traders enrollment status in fee tiers
     * @param _traders group of traders
     * @param _values corresponding enrollment values
     */
    function setTradersFeeTiersEnrollment(
        address[] calldata _traders,
        IFeeTiersUtils.TraderEnrollment[] calldata _values
    ) external;

    /**
     * @dev Credits points to traders
     * @param _traders traders addresses
     * @param _creditTypes types of credit (IMMEDIATE, CLAIMABLE)
     * @param _points points to credit (1e18)
     */
    function addTradersUnclaimedPoints(
        address[] calldata _traders,
        IFeeTiersUtils.CreditType[] calldata _creditTypes,
        uint224[] calldata _points
    ) external;

    /**
     * @dev Increases daily points from a new trade, re-calculate trailing points, and cache daily fee tier for a trader.
     * @param _trader trader address
     * @param _volumeUsd trading volume in USD (1e18)
     * @param _pairIndex pair index
     */
    function updateTraderPoints(address _trader, uint256 _volumeUsd, uint256 _pairIndex) external;

    /**
     * @dev Returns fee amount after applying the trader's active fee tier multiplier
     * @param _trader address of trader
     * @param _normalFeeAmountCollateral base fee amount (collateral precision)
     */
    function calculateFeeAmount(address _trader, uint256 _normalFeeAmountCollateral) external view returns (uint256);

    /**
     * Returns the current number of active fee tiers
     */
    function getFeeTiersCount() external view returns (uint256);

    /**
     * @dev Returns a fee tier's details (feeMultiplier, pointsThreshold)
     * @param _feeTierIndex fee tier index
     */
    function getFeeTier(uint256 _feeTierIndex) external view returns (IFeeTiersUtils.FeeTier memory);

    /**
     * @dev Returns a group's volume multiplier
     * @param _groupIndex group index (pairs storage fee index)
     */
    function getGroupVolumeMultiplier(uint256 _groupIndex) external view returns (uint256);

    /**
     * @dev Returns a trader's info (lastDayUpdated, trailingPoints)
     * @param _trader trader address
     */
    function getFeeTiersTraderInfo(address _trader) external view returns (IFeeTiersUtils.TraderInfo memory);

    /**
     * @dev Returns a trader's daily fee tier info (feeMultiplierCache, points)
     * @param _trader trader address
     * @param _day day
     */
    function getFeeTiersTraderDailyInfo(
        address _trader,
        uint32 _day
    ) external view returns (IFeeTiersUtils.TraderDailyInfo memory);

    /**
     * @dev Returns a trader's fee tiers enrollment status
     * @param _trader trader address
     */
    function getTraderFeeTiersEnrollment(
        address _trader
    ) external view returns (IFeeTiersUtils.TraderEnrollment memory);

    /**
     * @dev Returns a trader's unclaimed points, credited by Governance
     * @param _trader trader address
     */
    function getTraderUnclaimedPoints(address _trader) external view returns (uint224);

    /**
     * @dev Emitted when group volume multipliers are updated
     * @param groupIndices indices of updated groups
     * @param groupVolumeMultipliers new corresponding volume multipliers (1e3)
     */
    event GroupVolumeMultipliersUpdated(uint256[] groupIndices, uint256[] groupVolumeMultipliers);

    /**
     * @dev Emitted when fee tiers are updated
     * @param feeTiersIndices indices of updated fee tiers
     * @param feeTiers new corresponding fee tiers values (feeMultiplier, pointsThreshold)
     */
    event FeeTiersUpdated(uint256[] feeTiersIndices, IFeeTiersUtils.FeeTier[] feeTiers);

    /**
     * @dev Emitted when a trader's daily points are updated
     * @param trader trader address
     * @param day day
     * @param points points added (1e18 precision)
     */
    event TraderDailyPointsIncreased(address indexed trader, uint32 indexed day, uint224 points);

    /**
     * @dev Emitted when a trader info is updated for the first time
     * @param trader address of trader
     * @param day day
     */
    event TraderInfoFirstUpdate(address indexed trader, uint32 day);

    /**
     * @dev Emitted when a trader's trailing points are updated
     * @param trader trader address
     * @param fromDay from day
     * @param toDay to day
     * @param expiredPoints expired points amount (1e18 precision)
     */
    event TraderTrailingPointsExpired(address indexed trader, uint32 fromDay, uint32 toDay, uint224 expiredPoints);

    /**
     * @dev Emitted when a trader's info is updated
     * @param trader address of trader
     * @param traderInfo new trader info value (lastDayUpdated, trailingPoints)
     */
    event TraderInfoUpdated(address indexed trader, IFeeTiersUtils.TraderInfo traderInfo);

    /**
     * @dev Emitted when a trader's cached fee multiplier is updated (this is the one used in fee calculations)
     * @param trader address of trader
     * @param day day
     * @param feeMultiplier new fee multiplier (1e3 precision)
     */
    event TraderFeeMultiplierCached(address indexed trader, uint32 indexed day, uint32 feeMultiplier);

    /**
     * @dev Emitted when a trader's enrollment status is updated
     * @param trader address of trader
     * @param enrollment trader's new enrollment status
     */
    event TraderEnrollmentUpdated(address indexed trader, IFeeTiersUtils.TraderEnrollment enrollment);

    /**
     * @dev Emitted when a trader is credited points by governance
     * @param trader trader address
     * @param day day the points were credited on, may be different from the day the points were claimed
     * @param creditType credit type (IMMEDIATE, CLAIMABLE)
     * @param points points added (1e18 precision)
     */
    event TraderPointsCredited(
        address indexed trader,
        uint32 indexed day,
        IFeeTiers.CreditType creditType,
        uint224 points
    );

    /**
     * @dev Emitted when a trader's unclaimed points are claimed
     * @param trader trader address
     * @param day day of claim
     * @param points points added (1e18 precision)
     */
    event TraderUnclaimedPointsClaimed(address indexed trader, uint32 indexed day, uint224 points);

    error WrongFeeTier();
    error PointsOverflow();
}

File 8 of 16 : IPairsStorageUtils.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import "../types/IPairsStorage.sol";

/**
 * @dev Interface for GNSPairsStorage facet (inherits types and also contains functions, events, and custom errors)
 */
interface IPairsStorageUtils is IPairsStorage {
    /**
     * @dev Initializes liquidation params for all existing groups
     * @param _groupLiquidationParams liquidation params for each group (index corresponds to group index)
     */
    function initializeGroupLiquidationParams(
        IPairsStorage.GroupLiquidationParams[] memory _groupLiquidationParams
    ) external;

    /**
     * @dev Copies all existing fee groups to new mapping, multiplies existing groups min/max lev by 1e3, initializes new global trade fee params
     * @param _tradeFeeParams global trade fee params
     */
    function initializeNewFees(IPairsStorage.GlobalTradeFeeParams memory _tradeFeeParams) external;

    /**
     * @dev Adds new trading pairs
     * @param _pairs pairs to add
     */
    function addPairs(Pair[] calldata _pairs) external;

    /**
     * @dev Updates trading pairs
     * @param _pairIndices indices of pairs
     * @param _pairs new pairs values
     */
    function updatePairs(uint256[] calldata _pairIndices, Pair[] calldata _pairs) external;

    /**
     * @dev Adds new pair groups
     * @param _groups groups to add
     */
    function addGroups(Group[] calldata _groups) external;

    /**
     * @dev Updates pair groups
     * @param _ids indices of groups
     * @param _groups new groups values
     */
    function updateGroups(uint256[] calldata _ids, Group[] calldata _groups) external;

    /**
     * @dev Adds new pair fees groups
     * @param _fees fees to add
     */
    function addFees(FeeGroup[] calldata _fees) external;

    /**
     * @dev Updates pair fees groups
     * @param _ids indices of fees
     * @param _fees new fees values
     */
    function updateFees(uint256[] calldata _ids, FeeGroup[] calldata _fees) external;

    /**
     * @dev Updates pair custom max leverages (if unset group default is used); useful to delist a pair if new value is below the pair's group minLeverage
     * @param _indices indices of pairs
     * @param _values new custom max leverages (1e3 precision)
     */
    function setPairCustomMaxLeverages(uint256[] calldata _indices, uint256[] calldata _values) external;

    /**
     * @dev Updates group liquidation params (will only apply for trades opened after the change)
     * @param _groupIndex index of group
     * @param _params new liquidation params
     */
    function setGroupLiquidationParams(
        uint256 _groupIndex,
        IPairsStorage.GroupLiquidationParams memory _params
    ) external;

    /**
     * @dev Updates global trade fee params
     * @param _feeParams new fee params
     */
    function setGlobalTradeFeeParams(IPairsStorage.GlobalTradeFeeParams memory _feeParams) external;

    /**
     * @dev Returns data needed by price aggregator when doing a new price request
     * @param _pairIndex index of pair
     * @return from pair from (eg. BTC)
     * @return to pair to (eg. USD)
     */
    function pairJob(uint256 _pairIndex) external view returns (string memory from, string memory to);

    /**
     * @dev Returns whether a pair is listed
     * @param _from pair from (eg. BTC)
     * @param _to pair to (eg. USD)
     */
    function isPairListed(string calldata _from, string calldata _to) external view returns (bool);

    /**
     * @dev Returns whether a pair index is listed
     * @param _pairIndex index of pair to check
     */
    function isPairIndexListed(uint256 _pairIndex) external view returns (bool);

    /**
     * @dev Returns a pair's details
     * @param _index index of pair
     */
    function pairs(uint256 _index) external view returns (Pair memory);

    /**
     * @dev Returns number of listed pairs
     */
    function pairsCount() external view returns (uint256);

    /**
     * @dev Returns a pair's spread % (1e10 precision)
     * @param _pairIndex index of pair
     */
    function pairSpreadP(uint256 _pairIndex) external view returns (uint256);

    /**
     * @dev Returns a pair's min leverage (1e3 precision)
     * @param _pairIndex index of pair
     */
    function pairMinLeverage(uint256 _pairIndex) external view returns (uint256);

    /**
     * @dev Returns a pair's total position size fee % (1e10 precision)
     * @param _pairIndex index of pair
     */
    function pairTotalPositionSizeFeeP(uint256 _pairIndex) external view returns (uint256);

    /**
     * @dev Returns a pair's total liquidation collateral fee % (1e10 precision)
     * @param _pairIndex index of pair
     */
    function pairTotalLiqCollateralFeeP(uint256 _pairIndex) external view returns (uint256);

    /**
     * @dev Returns a pair's oracle position size fee % (1e10 precision)
     * @param _pairIndex index of pair
     */
    function pairOraclePositionSizeFeeP(uint256 _pairIndex) external view returns (uint256);

    /**
     * @dev Returns a pair's min position size in USD (1e18 precision)
     * @param _pairIndex index of pair
     */
    function pairMinPositionSizeUsd(uint256 _pairIndex) external view returns (uint256);

    /**
     * @dev Returns global trade fee params
     */
    function getGlobalTradeFeeParams() external view returns (IPairsStorage.GlobalTradeFeeParams memory);

    /**
     * @dev Returns a pair's minimum trading fee in USD (1e18 precision)
     * @param _pairIndex index of pair
     */
    function pairMinFeeUsd(uint256 _pairIndex) external view returns (uint256);

    /**
     * @dev Returns a group details
     * @param _index index of group
     */
    function groups(uint256 _index) external view returns (Group memory);

    /**
     * @dev Returns number of listed groups
     */
    function groupsCount() external view returns (uint256);

    /**
     * @dev Returns a fee group details
     * @param _index index of fee group
     */
    function fees(uint256 _index) external view returns (FeeGroup memory);

    /**
     * @dev Returns number of listed fee groups
     */
    function feesCount() external view returns (uint256);

    /**
     * @dev Returns a pair's active max leverage; custom if set, otherwise group default (1e3 precision)
     * @param _pairIndex index of pair
     */
    function pairMaxLeverage(uint256 _pairIndex) external view returns (uint256);

    /**
     * @dev Returns a pair's custom max leverage; 0 if not set (1e3 precision)
     * @param _pairIndex index of pair
     */
    function pairCustomMaxLeverage(uint256 _pairIndex) external view returns (uint256);

    /**
     * @dev Returns all listed pairs custom max leverages (1e3 precision)
     */
    function getAllPairsRestrictedMaxLeverage() external view returns (uint256[] memory);

    /**
     * @dev Returns a group's liquidation params
     */
    function getGroupLiquidationParams(
        uint256 _groupIndex
    ) external view returns (IPairsStorage.GroupLiquidationParams memory);

    /**
     * @dev Returns a pair's group liquidation params
     */
    function getPairLiquidationParams(
        uint256 _pairIndex
    ) external view returns (IPairsStorage.GroupLiquidationParams memory);

    /**
     * @dev Emitted when a new pair is listed
     * @param index index of pair
     * @param from pair from (eg. BTC)
     * @param to pair to (eg. USD)
     */
    event PairAdded(uint256 index, string from, string to);

    /**
     * @dev Emitted when a pair is updated
     * @param index index of pair
     */
    event PairUpdated(uint256 index);

    /**
     * @dev Emitted when a pair's custom max leverage is updated
     * @param index index of pair
     * @param maxLeverage new max leverage (1e3 precision)
     */
    event PairCustomMaxLeverageUpdated(uint256 indexed index, uint256 maxLeverage);

    /**
     * @dev Emitted when a new group is added
     * @param index index of group
     * @param name name of group
     */
    event GroupAdded(uint256 index, string name);

    /**
     * @dev Emitted when a group is updated
     * @param index index of group
     */
    event GroupUpdated(uint256 index);

    /**
     * @dev Emitted when a new fee group is added
     * @param index index of fee group
     * @param feeGroup fee group
     */
    event FeeAdded(uint256 index, FeeGroup feeGroup);

    /**
     * @dev Emitted when a fee group is updated
     * @param index index of fee group
     * @param feeGroup updated fee group
     */
    event FeeUpdated(uint256 index, FeeGroup feeGroup);

    /**
     * @dev Emitted when a group liquidation params are updated
     * @param index index of group
     * @param params new group liquidation params
     */
    event GroupLiquidationParamsUpdated(uint256 index, IPairsStorage.GroupLiquidationParams params);

    /**
     * @dev Emitted when global trade fee params are updated
     * @param feeParams new fee params
     */
    event GlobalTradeFeeParamsUpdated(IPairsStorage.GlobalTradeFeeParams feeParams);

    error PairNotListed();
    error GroupNotListed();
    error FeeNotListed();
    error WrongLeverages();
    error WrongFees();
    error PairAlreadyListed();
    error MaxLiqSpreadPTooHigh();
    error WrongLiqParamsThresholds();
    error WrongLiqParamsLeverages();
    error StartLiqThresholdTooHigh();
    error EndLiqThresholdTooLow();
    error StartLeverageTooLow();
    error EndLeverageTooHigh();
}

File 9 of 16 : IAddressStore.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

/**
 * @dev Contains the types for the GNSAddressStore facet
 */
interface IAddressStore {
    enum Role {
        GOV_TIMELOCK,
        GOV,
        MANAGER,
        GOV_EMERGENCY
    }

    struct Addresses {
        address gns;
        address gnsStaking;
        address treasury;
    }

    struct AddressStore {
        uint256 __deprecated; // previously globalAddresses (gns token only, 1 slot)
        mapping(address => mapping(Role => bool)) accessControl;
        Addresses globalAddresses;
        uint256[7] __gap1; // gap for global addresses
        // insert new storage here
        uint256[38] __gap2; // gap for rest of diamond storage
    }
}

File 10 of 16 : IFeeTiers.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

/**
 * @dev Contains the types for the GNSFeeTiers facet
 */
interface IFeeTiers {
    struct FeeTiersStorage {
        FeeTier[8] feeTiers;
        mapping(uint256 => uint256) groupVolumeMultipliers; // groupIndex (pairs storage) => multiplier (1e3)
        mapping(address => TraderInfo) traderInfos; // trader => TraderInfo
        mapping(address => mapping(uint32 => TraderDailyInfo)) traderDailyInfos; // trader => day => TraderDailyInfo
        mapping(address => TraderEnrollment) traderEnrollments; // trader => TraderEnrollment
        mapping(address => uint224) unclaimedPoints; // trader => points (1e18)
        uint256[37] __gap;
    }

    enum TraderEnrollmentStatus {
        ENROLLED,
        EXCLUDED
    }

    enum CreditType {
        IMMEDIATE,
        CLAIMABLE
    }

    struct FeeTier {
        uint32 feeMultiplier; // 1e3
        uint32 pointsThreshold;
    }

    struct TraderInfo {
        uint32 lastDayUpdated;
        uint224 trailingPoints; // 1e18
    }

    struct TraderDailyInfo {
        uint32 feeMultiplierCache; // 1e3
        uint224 points; // 1e18
    }

    struct TraderEnrollment {
        TraderEnrollmentStatus status;
        uint248 __placeholder;
    }
}

File 11 of 16 : IPairsStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

/**
 * @dev Contains the types for the GNSPairsStorage facet
 */
interface IPairsStorage {
    struct PairsStorage {
        mapping(uint256 => Pair) pairs;
        mapping(uint256 => Group) groups;
        mapping(uint256 => Fee) fees; /// @custom:deprecated
        mapping(string => mapping(string => bool)) isPairListed;
        mapping(uint256 => uint256) pairCustomMaxLeverage; // 1e3 precision
        uint256 currentOrderId; /// @custom:deprecated
        uint256 pairsCount;
        uint256 groupsCount;
        uint256 feesCount;
        mapping(uint256 => GroupLiquidationParams) groupLiquidationParams;
        mapping(uint256 => FeeGroup) feeGroups;
        GlobalTradeFeeParams globalTradeFeeParams;
        uint256[38] __gap;
    }

    struct Pair {
        string from;
        string to;
        Feed feed; /// @custom:deprecated
        uint256 spreadP; // 1e10
        uint256 groupIndex;
        uint256 feeIndex;
    }

    struct Group {
        string name;
        bytes32 job; /// @custom:deprecated
        uint256 minLeverage; // 1e3 precision
        uint256 maxLeverage; // 1e3 precision
    }

    struct GlobalTradeFeeParams {
        uint24 referralFeeP; // 1e3 (%)
        uint24 govFeeP; // 1e3 (%)
        uint24 triggerOrderFeeP; // 1e3 (%)
        uint24 gnsOtcFeeP; // 1e3 (%)
        uint24 gTokenFeeP; // 1e3 (%)
        uint136 __placeholder;
    }

    struct FeeGroup {
        uint40 totalPositionSizeFeeP; // 1e10 (%)
        uint40 totalLiqCollateralFeeP; // 1e10 (%)
        uint40 oraclePositionSizeFeeP; // 1e10 (%)
        uint32 minPositionSizeUsd; // 1e3
        uint104 __placeholder;
    }

    struct TradeFees {
        uint256 totalFeeCollateral; // collateral precision
        uint256 referralFeeCollateral; // collateral precision
        uint256 govFeeCollateral; // collateral precision
        uint256 triggerOrderFeeCollateral; // collateral precision
        uint256 gnsOtcFeeCollateral; // collateral precision
        uint256 gTokenFeeCollateral; // collateral precision
    }

    struct GroupLiquidationParams {
        uint40 maxLiqSpreadP; // 1e10 (%)
        uint40 startLiqThresholdP; // 1e10 (%)
        uint40 endLiqThresholdP; // 1e10 (%)
        uint24 startLeverage; // 1e3
        uint24 endLeverage; // 1e3
    }

    // Deprecated structs
    enum FeedCalculation {
        DEFAULT,
        INVERT,
        COMBINE
    } /// @custom:deprecated
    struct Feed {
        address feed1;
        address feed2;
        FeedCalculation feedCalculation;
        uint256 maxDeviationP;
    } /// @custom:deprecated
    struct Fee {
        string name;
        uint256 openFeeP; // 1e10 (% of position size)
        uint256 closeFeeP; // 1e10 (% of position size)
        uint256 oracleFeeP; // 1e10 (% of position size)
        uint256 triggerOrderFeeP; // 1e10 (% of position size)
        uint256 minPositionSizeUsd; // 1e18 (collateral x leverage, useful for min fee)
    } /// @custom:deprecated
}

File 12 of 16 : ITradingStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import "./IPairsStorage.sol";

/**
 * @dev Contains the types for the GNSTradingStorage facet
 */
interface ITradingStorage {
    struct TradingStorage {
        TradingActivated tradingActivated; // 8 bits
        uint8 lastCollateralIndex; // 8 bits
        uint240 __placeholder; // 240 bits
        mapping(uint8 => Collateral) collaterals;
        mapping(uint8 => address) gTokens;
        mapping(address => uint8) collateralIndex;
        mapping(address => mapping(uint32 => Trade)) trades;
        mapping(address => mapping(uint32 => TradeInfo)) tradeInfos;
        mapping(address => mapping(uint32 => mapping(PendingOrderType => uint256))) tradePendingOrderBlock;
        mapping(address => mapping(uint32 => PendingOrder)) pendingOrders;
        mapping(address => mapping(CounterType => Counter)) userCounters;
        address[] traders;
        mapping(address => bool) traderStored;
        mapping(address => mapping(uint32 => IPairsStorage.GroupLiquidationParams)) tradeLiquidationParams;
        uint256[38] __gap;
    }

    enum PendingOrderType {
        MARKET_OPEN,
        MARKET_CLOSE,
        LIMIT_OPEN,
        STOP_OPEN,
        TP_CLOSE,
        SL_CLOSE,
        LIQ_CLOSE,
        UPDATE_LEVERAGE,
        MARKET_PARTIAL_OPEN,
        MARKET_PARTIAL_CLOSE
    }

    enum CounterType {
        TRADE,
        PENDING_ORDER
    }

    enum TradeType {
        TRADE,
        LIMIT,
        STOP
    }

    enum TradingActivated {
        ACTIVATED,
        CLOSE_ONLY,
        PAUSED
    }

    enum ContractsVersion {
        BEFORE_V9_2,
        V9_2
    }

    struct Collateral {
        // slot 1
        address collateral; // 160 bits
        bool isActive; // 8 bits
        uint88 __placeholder; // 88 bits
        // slot 2
        uint128 precision;
        uint128 precisionDelta;
    }

    struct Id {
        address user; // 160 bits
        uint32 index; // max: 4,294,967,295
    }

    struct Trade {
        // slot 1
        address user; // 160 bits
        uint32 index; // max: 4,294,967,295
        uint16 pairIndex; // max: 65,535
        uint24 leverage; // 1e3; max: 16,777.215
        bool long; // 8 bits
        bool isOpen; // 8 bits
        uint8 collateralIndex; // max: 255
        // slot 2
        TradeType tradeType; // 8 bits
        uint120 collateralAmount; // 1e18; max: 3.402e+38
        uint64 openPrice; // 1e10; max: 1.8e19
        uint64 tp; // 1e10; max: 1.8e19
        // slot 3 (192 bits left)
        uint64 sl; // 1e10; max: 1.8e19
        uint192 __placeholder;
    }

    struct TradeInfo {
        uint32 createdBlock; // for lookbacks
        uint32 tpLastUpdatedBlock; // for lookbacks
        uint32 slLastUpdatedBlock; // for lookbacks
        uint16 maxSlippageP; // 1e3 (%)
        uint48 lastOiUpdateTs; // deprecated
        uint48 collateralPriceUsd; // 1e8 collateral price at trade open
        ContractsVersion contractsVersion;
        uint32 lastPosIncreaseBlock; // for protection close factor
        uint8 __placeholder;
    }

    struct PendingOrder {
        // slots 1-3
        Trade trade;
        // slot 4
        address user; // 160 bits
        uint32 index; // max: 4,294,967,295
        bool isOpen; // 8 bits
        PendingOrderType orderType; // 8 bits
        uint32 createdBlock; // max: 4,294,967,295
        uint16 maxSlippageP; // 1e3 (%), max: 65.535%
    }

    struct Counter {
        uint32 currentIndex;
        uint32 openCount;
        uint192 __placeholder;
    }
}

File 13 of 16 : ConstantsUtils.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import "../interfaces/types/ITradingStorage.sol";

/**
 *
 * @dev Internal library for important constants commonly used in many places
 */
library ConstantsUtils {
    uint256 internal constant P_10 = 1e10; // 10 decimals (DO NOT UPDATE)
    uint256 internal constant MAX_PNL_P = 900; // 900% PnL (10x)
    uint256 internal constant SL_LIQ_BUFFER_P = 10 * P_10; // SL has to be 10% closer than liq price
    uint256 internal constant LEGACY_LIQ_THRESHOLD_P = 90 * P_10; // -90% pnl
    uint256 internal constant MIN_LIQ_THRESHOLD_P = 50 * P_10; // -50% pnl
    uint256 internal constant MAX_OPEN_NEGATIVE_PNL_P = 40 * P_10; // -40% pnl
    uint256 internal constant MAX_LIQ_SPREAD_P = (5 * P_10) / 100; // 0.05%
    uint16 internal constant DEFAULT_MAX_CLOSING_SLIPPAGE_P = 1 * 1e3; // 1%

    function getMarketOrderTypes() internal pure returns (ITradingStorage.PendingOrderType[5] memory) {
        return [
            ITradingStorage.PendingOrderType.MARKET_OPEN,
            ITradingStorage.PendingOrderType.MARKET_CLOSE,
            ITradingStorage.PendingOrderType.UPDATE_LEVERAGE,
            ITradingStorage.PendingOrderType.MARKET_PARTIAL_OPEN,
            ITradingStorage.PendingOrderType.MARKET_PARTIAL_CLOSE
        ];
    }

    /**
     * @dev Returns pending order type (market open/limit open/stop open) for a trade type (trade/limit/stop)
     * @param _tradeType the trade type
     */
    function getPendingOpenOrderType(
        ITradingStorage.TradeType _tradeType
    ) internal pure returns (ITradingStorage.PendingOrderType) {
        return
            _tradeType == ITradingStorage.TradeType.TRADE
                ? ITradingStorage.PendingOrderType.MARKET_OPEN
                : _tradeType == ITradingStorage.TradeType.LIMIT
                ? ITradingStorage.PendingOrderType.LIMIT_OPEN
                : ITradingStorage.PendingOrderType.STOP_OPEN;
    }

    /**
     * @dev Returns true if order type is market
     * @param _orderType order type
     */
    function isOrderTypeMarket(ITradingStorage.PendingOrderType _orderType) internal pure returns (bool) {
        ITradingStorage.PendingOrderType[5] memory marketOrderTypes = ConstantsUtils.getMarketOrderTypes();
        for (uint256 i; i < marketOrderTypes.length; ++i) {
            if (_orderType == marketOrderTypes[i]) return true;
        }
        return false;
    }
}

File 14 of 16 : FeeTiersUtils.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import "../interfaces/libraries/IFeeTiersUtils.sol";
import "../interfaces/IGeneralErrors.sol";

import "../interfaces/types/IFeeTiers.sol";

import "./StorageUtils.sol";

/**
 * @dev GNSFeeTiers facet internal library
 *
 * This is a library to apply fee tiers to trading fees based on a trailing point system.
 */
library FeeTiersUtils {
    uint256 private constant MAX_FEE_TIERS = 8;
    uint32 private constant TRAILING_PERIOD_DAYS = 30;
    uint32 private constant FEE_MULTIPLIER_SCALE = 1e3;
    uint224 private constant POINTS_THRESHOLD_SCALE = 1e18;
    uint256 private constant GROUP_VOLUME_MULTIPLIER_SCALE = 1e3;
    uint224 private constant MAX_CREDITED_POINTS_PER_DAY = type(uint224).max / TRAILING_PERIOD_DAYS / 2;

    /**
     * @dev Check IFeeTiersUtils interface for documentation
     */
    function initializeFeeTiers(
        uint256[] calldata _groupIndices,
        uint256[] calldata _groupVolumeMultipliers,
        uint256[] calldata _feeTiersIndices,
        IFeeTiers.FeeTier[] calldata _feeTiers
    ) internal {
        setGroupVolumeMultipliers(_groupIndices, _groupVolumeMultipliers);
        setFeeTiers(_feeTiersIndices, _feeTiers);
    }

    /**
     * @dev Check IFeeTiersUtils interface for documentation
     */
    function setGroupVolumeMultipliers(
        uint256[] calldata _groupIndices,
        uint256[] calldata _groupVolumeMultipliers
    ) internal {
        if (_groupIndices.length != _groupVolumeMultipliers.length) {
            revert IGeneralErrors.WrongLength();
        }

        mapping(uint256 => uint256) storage groupVolumeMultipliers = _getStorage().groupVolumeMultipliers;

        for (uint256 i; i < _groupIndices.length; ++i) {
            groupVolumeMultipliers[_groupIndices[i]] = _groupVolumeMultipliers[i];
        }

        emit IFeeTiersUtils.GroupVolumeMultipliersUpdated(_groupIndices, _groupVolumeMultipliers);
    }

    /**
     * @dev Check IFeeTiersUtils interface for documentation
     */
    function setFeeTiers(uint256[] calldata _feeTiersIndices, IFeeTiers.FeeTier[] calldata _feeTiers) internal {
        if (_feeTiersIndices.length != _feeTiers.length) {
            revert IGeneralErrors.WrongLength();
        }

        IFeeTiers.FeeTier[8] storage feeTiersStorage = _getStorage().feeTiers;

        // First do all updates
        for (uint256 i; i < _feeTiersIndices.length; ++i) {
            feeTiersStorage[_feeTiersIndices[i]] = _feeTiers[i];
        }

        // Then check updates are valid
        for (uint256 i; i < _feeTiersIndices.length; ++i) {
            _checkFeeTierUpdateValid(_feeTiersIndices[i], _feeTiers[i], feeTiersStorage);
        }

        emit IFeeTiersUtils.FeeTiersUpdated(_feeTiersIndices, _feeTiers);
    }

    /**
     * @dev Check IFeeTiersUtils interface for documentation
     */
    function setTradersFeeTiersEnrollment(
        address[] calldata _traders,
        IFeeTiers.TraderEnrollment[] calldata _values
    ) internal {
        if (_traders.length != _values.length) {
            revert IGeneralErrors.WrongLength();
        }

        IFeeTiers.FeeTiersStorage storage s = _getStorage();

        for (uint256 i; i < _traders.length; ++i) {
            (address trader, IFeeTiers.TraderEnrollment memory enrollment) = (_traders[i], _values[i]);

            // Ensure __placeholder remains 0 for future compatibility
            enrollment.__placeholder = 0;

            // Update trader enrollment mapping
            s.traderEnrollments[trader] = enrollment;

            emit IFeeTiersUtils.TraderEnrollmentUpdated(trader, enrollment);
        }
    }

    /**
     * @dev Check IFeeTiersUtils interface for documentation
     */
    function addTradersUnclaimedPoints(
        address[] calldata _traders,
        IFeeTiers.CreditType[] calldata _creditTypes,
        uint224[] calldata _points
    ) internal {
        if (_traders.length != _creditTypes.length || _traders.length != _points.length) {
            revert IGeneralErrors.WrongLength();
        }

        IFeeTiers.FeeTiersStorage storage s = _getStorage();
        uint32 currentDay = _getCurrentDay();

        for (uint256 i; i < _traders.length; ++i) {
            (address trader, IFeeTiers.CreditType creditType, uint224 points) = (
                _traders[i],
                _creditTypes[i],
                _points[i]
            );

            // Calculate new total daily points for trader, including unclaimed ones.
            // This ensures that the total daily points for a trader are capped at MAX_CREDITED_POINTS_PER_DAY to prevent trailingPoints
            // from overflowing when points added through trading or other credit events.
            uint224 totalDailyPoints = s.traderDailyInfos[trader][currentDay].points +
                s.unclaimedPoints[trader] +
                points;

            // Check total available points are within the safe range
            if (totalDailyPoints > MAX_CREDITED_POINTS_PER_DAY) {
                revert IFeeTiersUtils.PointsOverflow();
            }

            // Add points to unclaimed points storage
            s.unclaimedPoints[trader] += points;

            // If points are to be credited immediately, trigger a points update
            if (creditType == IFeeTiers.CreditType.IMMEDIATE) {
                updateTraderPoints(trader, 0, 0);
            }

            emit IFeeTiersUtils.TraderPointsCredited(trader, currentDay, creditType, points);
        }
    }

    /**
     * @dev Check IFeeTiersUtils interface for documentation
     */
    function updateTraderPoints(address _trader, uint256 _volumeUsd, uint256 _groupIndex) internal {
        IFeeTiers.FeeTiersStorage storage s = _getStorage();

        // Claim any pending points before updating
        _claimUnclaimedPoints(_trader);

        // Scale amount by group multiplier
        uint224 points = uint224((_volumeUsd * s.groupVolumeMultipliers[_groupIndex]) / GROUP_VOLUME_MULTIPLIER_SCALE);

        mapping(uint32 => IFeeTiers.TraderDailyInfo) storage traderDailyInfo = s.traderDailyInfos[_trader];
        uint32 currentDay = _getCurrentDay();
        IFeeTiers.TraderDailyInfo storage traderCurrentDayInfo = traderDailyInfo[currentDay];

        // Increase points for current day
        if (points > 0) {
            traderCurrentDayInfo.points += points;
            emit IFeeTiersUtils.TraderDailyPointsIncreased(_trader, currentDay, points);
        }

        IFeeTiers.TraderInfo storage traderInfo = s.traderInfos[_trader];

        // Return early if first update ever for trader since trailing points would be 0 anyway
        if (traderInfo.lastDayUpdated == 0) {
            traderInfo.lastDayUpdated = currentDay;
            emit IFeeTiersUtils.TraderInfoFirstUpdate(_trader, currentDay);

            return;
        }

        // Update trailing points & re-calculate cached fee tier.
        // Only run if at least 1 day elapsed since last update
        if (currentDay > traderInfo.lastDayUpdated) {
            // Trailing points = sum of all daily points accumulated for last TRAILING_PERIOD_DAYS.
            // It determines which fee tier to apply (pointsThreshold)
            uint224 curTrailingPoints;

            // Calculate trailing points if less than or exactly TRAILING_PERIOD_DAYS have elapsed since update.
            // Otherwise, trailing points is 0 anyway.
            uint32 earliestActiveDay = currentDay - TRAILING_PERIOD_DAYS;

            if (traderInfo.lastDayUpdated >= earliestActiveDay) {
                // Load current trailing points and add last day updated points since they are now finalized
                curTrailingPoints = traderInfo.trailingPoints + traderDailyInfo[traderInfo.lastDayUpdated].points;

                // Expire outdated trailing points
                uint32 earliestOutdatedDay = traderInfo.lastDayUpdated - TRAILING_PERIOD_DAYS;
                uint32 lastOutdatedDay = earliestActiveDay - 1;

                uint224 expiredTrailingPoints;
                for (uint32 i = earliestOutdatedDay; i <= lastOutdatedDay; ++i) {
                    expiredTrailingPoints += traderDailyInfo[i].points;
                }

                curTrailingPoints -= expiredTrailingPoints;

                emit IFeeTiersUtils.TraderTrailingPointsExpired(
                    _trader,
                    earliestOutdatedDay,
                    lastOutdatedDay,
                    expiredTrailingPoints
                );
            }

            // Store last updated day and new trailing points
            traderInfo.lastDayUpdated = currentDay;
            traderInfo.trailingPoints = curTrailingPoints;

            emit IFeeTiersUtils.TraderInfoUpdated(_trader, traderInfo);

            // Re-calculate current fee tier for trader
            uint32 newFeeMultiplier = FEE_MULTIPLIER_SCALE; // use 1 by default (if no fee tier corresponds)

            for (uint256 i = getFeeTiersCount(); i > 0; --i) {
                IFeeTiers.FeeTier memory feeTier = s.feeTiers[i - 1];

                if (curTrailingPoints >= uint224(feeTier.pointsThreshold) * POINTS_THRESHOLD_SCALE) {
                    newFeeMultiplier = feeTier.feeMultiplier;
                    break;
                }
            }

            // Update trader cached fee multiplier
            traderCurrentDayInfo.feeMultiplierCache = newFeeMultiplier;
            emit IFeeTiersUtils.TraderFeeMultiplierCached(_trader, currentDay, newFeeMultiplier);
        }
    }

    /**
     * @dev Check IFeeTiersUtils interface for documentation
     */
    function calculateFeeAmount(address _trader, uint256 _normalFeeAmountCollateral) internal view returns (uint256) {
        IFeeTiers.FeeTiersStorage storage s = _getStorage();
        IFeeTiers.TraderEnrollment storage enrollment = s.traderEnrollments[_trader];
        uint32 feeMultiplier = s.traderDailyInfos[_trader][_getCurrentDay()].feeMultiplierCache;

        return
            // If  fee multiplier is 0 or trader is excluded, return normal fee amount, otherwise apply multiplier
            feeMultiplier == 0 || enrollment.status == IFeeTiers.TraderEnrollmentStatus.EXCLUDED
                ? _normalFeeAmountCollateral
                : (uint256(feeMultiplier) * _normalFeeAmountCollateral) / uint256(FEE_MULTIPLIER_SCALE);
    }

    /**
     * @dev Check IFeeTiersUtils interface for documentation
     */
    function getFeeTiersCount() internal view returns (uint256) {
        IFeeTiers.FeeTier[8] storage _feeTiers = _getStorage().feeTiers;

        for (uint256 i = MAX_FEE_TIERS; i > 0; --i) {
            if (_feeTiers[i - 1].feeMultiplier > 0) {
                return i;
            }
        }

        return 0;
    }

    /**
     * @dev Check IFeeTiersUtils interface for documentation
     */
    function getFeeTier(uint256 _feeTierIndex) internal view returns (IFeeTiers.FeeTier memory) {
        return _getStorage().feeTiers[_feeTierIndex];
    }

    /**
     * @dev Check IFeeTiersUtils interface for documentation
     */
    function getGroupVolumeMultiplier(uint256 _groupIndex) internal view returns (uint256) {
        return _getStorage().groupVolumeMultipliers[_groupIndex];
    }

    /**
     * @dev Check IFeeTiersUtils interface for documentation
     */
    function getFeeTiersTraderInfo(address _trader) internal view returns (IFeeTiers.TraderInfo memory) {
        return _getStorage().traderInfos[_trader];
    }

    /**
     * @dev Check IFeeTiersUtils interface for documentation
     */
    function getTraderFeeTiersEnrollment(address _trader) internal view returns (IFeeTiers.TraderEnrollment memory) {
        return _getStorage().traderEnrollments[_trader];
    }

    /**
     * @dev Check IFeeTiersUtils interface for documentation
     */
    function getTraderUnclaimedPoints(address _trader) internal view returns (uint224) {
        return _getStorage().unclaimedPoints[_trader];
    }

    /**
     * @dev Check IFeeTiersUtils interface for documentation
     */
    function getFeeTiersTraderDailyInfo(
        address _trader,
        uint32 _day
    ) internal view returns (IFeeTiers.TraderDailyInfo memory) {
        return _getStorage().traderDailyInfos[_trader][_day];
    }

    /**
     * @dev Returns storage slot to use when fetching storage relevant to library
     */
    function _getSlot() internal pure returns (uint256) {
        return StorageUtils.GLOBAL_FEE_TIERS_SLOT;
    }

    /**
     * @dev Returns storage pointer for storage struct in diamond contract, at defined slot
     */
    function _getStorage() internal pure returns (IFeeTiers.FeeTiersStorage storage s) {
        uint256 storageSlot = _getSlot();
        assembly {
            s.slot := storageSlot
        }
    }

    /**
     * @dev Checks validity of a single fee tier update (feeMultiplier: descending, pointsThreshold: ascending, no gap)
     * @param _index index of the fee tier that was updated
     * @param _feeTier fee tier new value
     * @param _feeTiers all fee tiers
     */
    function _checkFeeTierUpdateValid(
        uint256 _index,
        IFeeTiers.FeeTier calldata _feeTier,
        IFeeTiers.FeeTier[8] storage _feeTiers
    ) internal view {
        bool isDisabled = _feeTier.feeMultiplier == 0 && _feeTier.pointsThreshold == 0;

        // Either both feeMultiplier and pointsThreshold are 0 or none
        // And make sure feeMultiplier < 1 && feeMultiplier >= 0.5 to cap discount to 50%
        if (
            !isDisabled &&
            (_feeTier.feeMultiplier >= FEE_MULTIPLIER_SCALE ||
                _feeTier.feeMultiplier < FEE_MULTIPLIER_SCALE / 2 ||
                _feeTier.pointsThreshold == 0)
        ) {
            revert IFeeTiersUtils.WrongFeeTier();
        }

        bool hasNextValue = _index < MAX_FEE_TIERS - 1;

        // If disabled, only need to check the next fee tier is disabled as well to create no gaps in active tiers
        if (isDisabled) {
            if (hasNextValue && _feeTiers[_index + 1].feeMultiplier > 0) {
                revert IGeneralErrors.WrongOrder();
            }
        } else {
            // Check next value order
            if (hasNextValue) {
                IFeeTiers.FeeTier memory feeTier = _feeTiers[_index + 1];
                if (
                    feeTier.feeMultiplier != 0 &&
                    (feeTier.feeMultiplier >= _feeTier.feeMultiplier ||
                        feeTier.pointsThreshold <= _feeTier.pointsThreshold)
                ) {
                    revert IGeneralErrors.WrongOrder();
                }
            }

            // Check previous value order
            if (_index > 0) {
                IFeeTiers.FeeTier memory feeTier = _feeTiers[_index - 1];
                if (
                    feeTier.feeMultiplier <= _feeTier.feeMultiplier ||
                    feeTier.pointsThreshold >= _feeTier.pointsThreshold
                ) {
                    revert IGeneralErrors.WrongOrder();
                }
            }
        }
    }

    /**
     * @dev Get current day (index of mapping traderDailyInfo)
     */
    function _getCurrentDay() internal view returns (uint32) {
        return uint32(block.timestamp / 1 days);
    }

    /**
     * @dev Claims unclaimed points for a trader and adds them to the daily points for the current day.
     * @dev In the event that it's the first points update for the trader, backdates points to yesterday so the tier discount becomes immediate.
     * @param _trader trader address
     */
    function _claimUnclaimedPoints(address _trader) internal {
        IFeeTiers.FeeTiersStorage storage s = _getStorage();

        // Load unclaimed points for trader
        uint224 unclaimedPoints = s.unclaimedPoints[_trader];

        // Return early if no unclaimed points
        if (unclaimedPoints == 0) {
            return;
        }

        IFeeTiers.TraderInfo storage traderInfo = s.traderInfos[_trader];
        uint32 currentDay = _getCurrentDay();

        // Reset unclaimed points storage for trader
        s.unclaimedPoints[_trader] = 0;

        // If it's the first points update we can safely backdate points to yesterday so the tier discount becomes immediate
        if (traderInfo.lastDayUpdated == 0) {
            uint32 yesterday = currentDay - 1;

            // Set trader's last day updated to yesterday (backdate)
            traderInfo.lastDayUpdated = yesterday;
            // Add unclaimed points to yesterday's points
            s.traderDailyInfos[_trader][yesterday].points = unclaimedPoints;

            emit IFeeTiersUtils.TraderInfoFirstUpdate(_trader, yesterday);
        } else {
            // Add unclaimed points to `currentDay`'s points
            s.traderDailyInfos[_trader][currentDay].points += unclaimedPoints;
        }

        emit IFeeTiersUtils.TraderUnclaimedPointsClaimed(_trader, currentDay, unclaimedPoints);
    }
}

File 15 of 16 : PairsStorageUtils.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import "../interfaces/libraries/IPairsStorageUtils.sol";
import "../interfaces/types/IPairsStorage.sol";
import "../interfaces/IGeneralErrors.sol";

import "./StorageUtils.sol";
import "./ConstantsUtils.sol";

/**
 * @dev GNSPairsStorage facet internal library
 */
library PairsStorageUtils {
    uint256 private constant MIN_LEVERAGE = 1.1e3; // 1.1x (1e3 precision)
    uint256 private constant MAX_LEVERAGE = 1000e3; // 1000x (1e3 precision)

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function initializeGroupLiquidationParams(
        IPairsStorage.GroupLiquidationParams[] memory _groupLiquidationParams
    ) internal {
        IPairsStorage.PairsStorage storage s = _getStorage();
        if (_groupLiquidationParams.length != s.groupsCount) revert IGeneralErrors.WrongLength();

        for (uint256 i = 0; i < _groupLiquidationParams.length; ++i) {
            setGroupLiquidationParams(i, _groupLiquidationParams[i]);
        }
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function initializeNewFees(IPairsStorage.GlobalTradeFeeParams memory _tradeFeeParams) internal {
        IPairsStorage.PairsStorage storage s = _getStorage();

        // 1. Copy existing fees to new mapping
        uint256 existingFeesCount = s.feesCount;
        s.feesCount = 0;

        for (uint256 i = 0; i < existingFeesCount; ++i) {
            IPairsStorage.Fee memory oldFeeGroup = s.fees[i];

            _addFee(
                IPairsStorage.FeeGroup(
                    uint40(oldFeeGroup.openFeeP * 2 + oldFeeGroup.triggerOrderFeeP),
                    uint40(10 * ConstantsUtils.P_10),
                    uint40(oldFeeGroup.oracleFeeP),
                    uint32((oldFeeGroup.minPositionSizeUsd * 1e3) / 1e18),
                    0
                )
            );
        }

        // 2. Multiply existing groups min/max lev by 1e3
        for (uint256 i = 0; i < s.groupsCount; ++i) {
            IPairsStorage.Group storage oldGroup = s.groups[i];
            oldGroup.minLeverage *= 1e3;
            oldGroup.maxLeverage *= 1e3;
        }

        // 3. Global trade fee params
        setGlobalTradeFeeParams(_tradeFeeParams);
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function addPairs(IPairsStorage.Pair[] calldata _pairs) internal {
        for (uint256 i = 0; i < _pairs.length; ++i) {
            _addPair(_pairs[i]);
        }
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function updatePairs(uint256[] calldata _pairIndices, IPairsStorage.Pair[] calldata _pairs) internal {
        if (_pairIndices.length != _pairs.length) revert IGeneralErrors.WrongLength();

        for (uint256 i = 0; i < _pairs.length; ++i) {
            _updatePair(_pairIndices[i], _pairs[i]);
        }
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function addGroups(IPairsStorage.Group[] calldata _groups) internal {
        for (uint256 i = 0; i < _groups.length; ++i) {
            _addGroup(_groups[i]);
        }
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function updateGroups(uint256[] calldata _ids, IPairsStorage.Group[] calldata _groups) internal {
        if (_ids.length != _groups.length) revert IGeneralErrors.WrongLength();

        for (uint256 i = 0; i < _groups.length; ++i) {
            _updateGroup(_ids[i], _groups[i]);
        }
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function addFees(IPairsStorage.FeeGroup[] memory _fees) internal {
        for (uint256 i = 0; i < _fees.length; ++i) {
            _addFee(_fees[i]);
        }
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function updateFees(uint256[] calldata _ids, IPairsStorage.FeeGroup[] memory _fees) internal {
        if (_ids.length != _fees.length) revert IGeneralErrors.WrongLength();

        for (uint256 i = 0; i < _fees.length; ++i) {
            _updateFee(_ids[i], _fees[i]);
        }
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function setPairCustomMaxLeverages(uint256[] calldata _indices, uint256[] calldata _values) internal {
        if (_indices.length != _values.length) revert IGeneralErrors.WrongLength();

        IPairsStorage.PairsStorage storage s = _getStorage();

        for (uint256 i; i < _indices.length; ++i) {
            s.pairCustomMaxLeverage[_indices[i]] = _values[i];

            emit IPairsStorageUtils.PairCustomMaxLeverageUpdated(_indices[i], _values[i]);
        }
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function setGroupLiquidationParams(
        uint256 _groupIndex,
        IPairsStorage.GroupLiquidationParams memory _params
    ) internal groupListed(_groupIndex) {
        IPairsStorage.PairsStorage storage s = _getStorage();

        if (
            _params.maxLiqSpreadP == 0 ||
            _params.startLiqThresholdP == 0 ||
            _params.endLiqThresholdP == 0 ||
            _params.startLeverage == 0 ||
            _params.endLeverage == 0
        ) revert IGeneralErrors.ZeroValue();

        if (_params.maxLiqSpreadP > ConstantsUtils.MAX_LIQ_SPREAD_P) revert IPairsStorageUtils.MaxLiqSpreadPTooHigh();

        if (_params.startLiqThresholdP < _params.endLiqThresholdP) revert IPairsStorageUtils.WrongLiqParamsThresholds();
        if (_params.startLiqThresholdP > ConstantsUtils.LEGACY_LIQ_THRESHOLD_P)
            revert IPairsStorageUtils.StartLiqThresholdTooHigh();
        if (_params.endLiqThresholdP < ConstantsUtils.MIN_LIQ_THRESHOLD_P)
            revert IPairsStorageUtils.EndLiqThresholdTooLow();

        if (_params.startLeverage > _params.endLeverage) revert IPairsStorageUtils.WrongLiqParamsLeverages();
        if (_params.startLeverage < groups(_groupIndex).minLeverage) revert IPairsStorageUtils.StartLeverageTooLow();
        if (_params.endLeverage > groups(_groupIndex).maxLeverage) revert IPairsStorageUtils.EndLeverageTooHigh();

        s.groupLiquidationParams[_groupIndex] = _params;

        emit IPairsStorageUtils.GroupLiquidationParamsUpdated(_groupIndex, _params);
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function setGlobalTradeFeeParams(IPairsStorage.GlobalTradeFeeParams memory _feeParams) internal {
        if (
            _feeParams.referralFeeP == 0 ||
            _feeParams.govFeeP == 0 ||
            _feeParams.triggerOrderFeeP == 0 ||
            _feeParams.gnsOtcFeeP == 0 ||
            _feeParams.gTokenFeeP == 0 ||
            _feeParams.__placeholder != 0
        ) revert IGeneralErrors.ZeroValue();

        if (
            _feeParams.referralFeeP +
                _feeParams.govFeeP +
                _feeParams.triggerOrderFeeP +
                _feeParams.gnsOtcFeeP +
                _feeParams.gTokenFeeP !=
            100 * 1e3
        ) revert IGeneralErrors.WrongParams();

        _getStorage().globalTradeFeeParams = _feeParams;

        emit IPairsStorageUtils.GlobalTradeFeeParamsUpdated(_feeParams);
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function pairJob(uint256 _pairIndex) internal view returns (string memory, string memory) {
        IPairsStorage.PairsStorage storage s = _getStorage();

        IPairsStorage.Pair storage p = s.pairs[_pairIndex];
        if (!s.isPairListed[p.from][p.to]) revert IPairsStorageUtils.PairNotListed();

        return (p.from, p.to);
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function isPairListed(string calldata _from, string calldata _to) internal view returns (bool) {
        return _getStorage().isPairListed[_from][_to];
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function isPairIndexListed(uint256 _pairIndex) internal view returns (bool) {
        return _pairIndex < _getStorage().pairsCount;
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function pairs(uint256 _index) internal view returns (IPairsStorage.Pair storage) {
        return _getStorage().pairs[_index];
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function pairsCount() internal view returns (uint256) {
        return _getStorage().pairsCount;
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function pairSpreadP(uint256 _pairIndex) internal view returns (uint256) {
        return pairs(_pairIndex).spreadP;
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function pairMinLeverage(uint256 _pairIndex) internal view returns (uint256) {
        return groups(pairs(_pairIndex).groupIndex).minLeverage;
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function pairTotalPositionSizeFeeP(uint256 _pairIndex) internal view returns (uint256) {
        return fees(pairs(_pairIndex).feeIndex).totalPositionSizeFeeP;
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function pairTotalLiqCollateralFeeP(uint256 _pairIndex) internal view returns (uint256) {
        return fees(pairs(_pairIndex).feeIndex).totalLiqCollateralFeeP;
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function pairOraclePositionSizeFeeP(uint256 _pairIndex) internal view returns (uint256) {
        return fees(pairs(_pairIndex).feeIndex).oraclePositionSizeFeeP;
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function pairMinPositionSizeUsd(uint256 _pairIndex) internal view returns (uint256) {
        return (uint256(fees(pairs(_pairIndex).feeIndex).minPositionSizeUsd) * 1e18) / 1e3;
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function getGlobalTradeFeeParams() internal view returns (IPairsStorage.GlobalTradeFeeParams memory) {
        return _getStorage().globalTradeFeeParams;
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function pairMinFeeUsd(uint256 _pairIndex) internal view returns (uint256) {
        return (pairMinPositionSizeUsd(_pairIndex) * pairTotalPositionSizeFeeP(_pairIndex)) / ConstantsUtils.P_10 / 100;
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function pairFeeIndex(uint256 _pairIndex) internal view returns (uint256) {
        return _getStorage().pairs[_pairIndex].feeIndex;
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function groups(uint256 _index) internal view returns (IPairsStorage.Group storage) {
        return _getStorage().groups[_index];
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function groupsCount() internal view returns (uint256) {
        return _getStorage().groupsCount;
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function fees(uint256 _index) internal view returns (IPairsStorage.FeeGroup memory) {
        return _getStorage().feeGroups[_index];
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function feesCount() internal view returns (uint256) {
        return _getStorage().feesCount;
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function pairMaxLeverage(uint256 _pairIndex) internal view returns (uint256) {
        IPairsStorage.PairsStorage storage s = _getStorage();

        uint256 maxLeverage = s.pairCustomMaxLeverage[_pairIndex];
        return maxLeverage > 0 ? maxLeverage : s.groups[s.pairs[_pairIndex].groupIndex].maxLeverage;
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function pairCustomMaxLeverage(uint256 _pairIndex) internal view returns (uint256) {
        return _getStorage().pairCustomMaxLeverage[_pairIndex];
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function getAllPairsRestrictedMaxLeverage() internal view returns (uint256[] memory) {
        uint256[] memory lev = new uint256[](pairsCount());

        for (uint256 i; i < lev.length; ++i) {
            lev[i] = pairCustomMaxLeverage(i);
        }

        return lev;
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function getGroupLiquidationParams(
        uint256 _groupIndex
    ) internal view returns (IPairsStorage.GroupLiquidationParams memory) {
        return _getStorage().groupLiquidationParams[_groupIndex];
    }

    /**
     * @dev Check IPairsStorageUtils interface for documentation
     */
    function getPairLiquidationParams(
        uint256 _pairIndex
    ) internal view returns (IPairsStorage.GroupLiquidationParams memory) {
        return _getStorage().groupLiquidationParams[pairs(_pairIndex).groupIndex];
    }

    /**
     * @dev Returns storage slot to use when fetching storage relevant to library
     */
    function _getSlot() internal pure returns (uint256) {
        return StorageUtils.GLOBAL_PAIRS_STORAGE_SLOT;
    }

    /**
     * @dev Returns storage pointer for storage struct in diamond contract, at defined slot
     */
    function _getStorage() internal pure returns (IPairsStorage.PairsStorage storage s) {
        uint256 storageSlot = _getSlot();
        assembly {
            s.slot := storageSlot
        }
    }

    /**
     * Reverts if group is not listed
     * @param _groupIndex group index to check
     */
    modifier groupListed(uint256 _groupIndex) {
        if (_getStorage().groups[_groupIndex].minLeverage == 0) revert IPairsStorageUtils.GroupNotListed();
        _;
    }

    /**
     * Reverts if fee is not listed
     * @param _feeIndex fee index to check
     */
    modifier feeListed(uint256 _feeIndex) {
        if (_getStorage().feeGroups[_feeIndex].totalPositionSizeFeeP == 0) revert IPairsStorageUtils.FeeNotListed();
        _;
    }

    /**
     * Reverts if group is not valid
     * @param _group group to check
     */
    modifier groupOk(IPairsStorage.Group calldata _group) {
        if (
            _group.minLeverage < MIN_LEVERAGE ||
            _group.maxLeverage > MAX_LEVERAGE ||
            _group.minLeverage >= _group.maxLeverage
        ) revert IPairsStorageUtils.WrongLeverages();
        _;
    }

    /**
     * @dev Reverts if fee is not valid
     * @param _fee fee to check
     */
    modifier feeOk(IPairsStorage.FeeGroup memory _fee) {
        if (
            _fee.totalPositionSizeFeeP == 0 ||
            _fee.totalLiqCollateralFeeP == 0 ||
            _fee.oraclePositionSizeFeeP == 0 ||
            _fee.oraclePositionSizeFeeP > _fee.totalPositionSizeFeeP ||
            _fee.minPositionSizeUsd == 0 ||
            _fee.__placeholder != 0
        ) revert IPairsStorageUtils.WrongFees();
        _;
    }

    /**
     * @dev Adds a new trading pair
     * @param _pair pair to add
     */
    function _addPair(
        IPairsStorage.Pair calldata _pair
    ) internal groupListed(_pair.groupIndex) feeListed(_pair.feeIndex) {
        IPairsStorage.PairsStorage storage s = _getStorage();
        if (s.isPairListed[_pair.from][_pair.to]) revert IPairsStorageUtils.PairAlreadyListed();

        s.pairs[s.pairsCount] = _pair;
        s.isPairListed[_pair.from][_pair.to] = true;

        emit IPairsStorageUtils.PairAdded(s.pairsCount++, _pair.from, _pair.to);
    }

    /**
     * @dev Updates an existing trading pair
     * @param _pairIndex index of pair to update
     * @param _pair new pair value
     */
    function _updatePair(
        uint256 _pairIndex,
        IPairsStorage.Pair calldata _pair
    ) internal groupListed(_pair.groupIndex) feeListed(_pair.feeIndex) {
        IPairsStorage.PairsStorage storage s = _getStorage();

        IPairsStorage.Pair storage p = s.pairs[_pairIndex];
        if (!s.isPairListed[p.from][p.to]) revert IPairsStorageUtils.PairNotListed();

        p.feed = _pair.feed;
        p.spreadP = _pair.spreadP;
        p.groupIndex = _pair.groupIndex;
        p.feeIndex = _pair.feeIndex;

        emit IPairsStorageUtils.PairUpdated(_pairIndex);
    }

    /**
     * @dev Adds a new pair group
     * @param _group group to add
     */
    function _addGroup(IPairsStorage.Group calldata _group) internal groupOk(_group) {
        IPairsStorage.PairsStorage storage s = _getStorage();
        s.groups[s.groupsCount] = _group;

        emit IPairsStorageUtils.GroupAdded(s.groupsCount++, _group.name);
    }

    /**
     * @dev Updates an existing pair group
     * @param _id index of group to update
     * @param _group new group value
     */
    function _updateGroup(uint256 _id, IPairsStorage.Group calldata _group) internal groupListed(_id) groupOk(_group) {
        _getStorage().groups[_id] = _group;

        emit IPairsStorageUtils.GroupUpdated(_id);
    }

    /**
     * @dev Adds a new pair fee group
     * @param _fee fee to add
     */
    function _addFee(IPairsStorage.FeeGroup memory _fee) internal feeOk(_fee) {
        IPairsStorage.PairsStorage storage s = _getStorage();
        s.feeGroups[s.feesCount] = _fee;

        emit IPairsStorageUtils.FeeAdded(s.feesCount++, _fee);
    }

    /**
     * @dev Updates an existing pair fee group
     * @param _id index of fee to update
     * @param _fee new fee value
     */
    function _updateFee(uint256 _id, IPairsStorage.FeeGroup memory _fee) internal feeListed(_id) feeOk(_fee) {
        _getStorage().feeGroups[_id] = _fee;

        emit IPairsStorageUtils.FeeUpdated(_id, _fee);
    }
}

File 16 of 16 : StorageUtils.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

/**
 *
 * @dev Internal library to manage storage slots of GNSMultiCollatDiamond contract diamond storage structs.
 *
 * BE EXTREMELY CAREFUL, DO NOT EDIT THIS WITHOUT A GOOD REASON
 *
 */
library StorageUtils {
    uint256 internal constant GLOBAL_ADDRESSES_SLOT = 3;
    uint256 internal constant GLOBAL_PAIRS_STORAGE_SLOT = 51;
    uint256 internal constant GLOBAL_REFERRALS_SLOT = 101;
    uint256 internal constant GLOBAL_FEE_TIERS_SLOT = 151;
    uint256 internal constant GLOBAL_PRICE_IMPACT_SLOT = 201;
    uint256 internal constant GLOBAL_DIAMOND_SLOT = 251;
    uint256 internal constant GLOBAL_TRADING_STORAGE_SLOT = 301;
    uint256 internal constant GLOBAL_TRIGGER_REWARDS_SLOT = 351;
    uint256 internal constant GLOBAL_TRADING_SLOT = 401;
    uint256 internal constant GLOBAL_TRADING_CALLBACKS_SLOT = 451;
    uint256 internal constant GLOBAL_BORROWING_FEES_SLOT = 501;
    uint256 internal constant GLOBAL_PRICE_AGGREGATOR_SLOT = 551;
    uint256 internal constant GLOBAL_OTC_SLOT = 601;
    uint256 internal constant GLOBAL_CHAIN_CONFIG_SLOT = 651;
}

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

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AboveMax","type":"error"},{"inputs":[],"name":"AlreadyExists","type":"error"},{"inputs":[],"name":"BelowMin","type":"error"},{"inputs":[],"name":"BlockOrder","type":"error"},{"inputs":[],"name":"DoesntExist","type":"error"},{"inputs":[],"name":"InitError","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidAddresses","type":"error"},{"inputs":[],"name":"InvalidCollateralIndex","type":"error"},{"inputs":[],"name":"InvalidInputLength","type":"error"},{"inputs":[],"name":"NotAllowed","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"Overflow","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[],"name":"PointsOverflow","type":"error"},{"inputs":[],"name":"UnsupportedChain","type":"error"},{"inputs":[],"name":"WrongAccess","type":"error"},{"inputs":[],"name":"WrongFeeTier","type":"error"},{"inputs":[],"name":"WrongIndex","type":"error"},{"inputs":[],"name":"WrongLength","type":"error"},{"inputs":[],"name":"WrongOrder","type":"error"},{"inputs":[],"name":"WrongOrderType","type":"error"},{"inputs":[],"name":"WrongParams","type":"error"},{"inputs":[],"name":"WrongTradeType","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroValue","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"enum IAddressStore.Role","name":"role","type":"uint8"},{"indexed":false,"internalType":"bool","name":"access","type":"bool"}],"name":"AccessControlUpdated","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"gns","type":"address"},{"internalType":"address","name":"gnsStaking","type":"address"},{"internalType":"address","name":"treasury","type":"address"}],"indexed":false,"internalType":"struct IAddressStore.Addresses","name":"addresses","type":"tuple"}],"name":"AddressesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"feeTiersIndices","type":"uint256[]"},{"components":[{"internalType":"uint32","name":"feeMultiplier","type":"uint32"},{"internalType":"uint32","name":"pointsThreshold","type":"uint32"}],"indexed":false,"internalType":"struct IFeeTiers.FeeTier[]","name":"feeTiers","type":"tuple[]"}],"name":"FeeTiersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"groupIndices","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"groupVolumeMultipliers","type":"uint256[]"}],"name":"GroupVolumeMultipliersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"uint32","name":"day","type":"uint32"},{"indexed":false,"internalType":"uint224","name":"points","type":"uint224"}],"name":"TraderDailyPointsIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"components":[{"internalType":"enum IFeeTiers.TraderEnrollmentStatus","name":"status","type":"uint8"},{"internalType":"uint248","name":"__placeholder","type":"uint248"}],"indexed":false,"internalType":"struct IFeeTiers.TraderEnrollment","name":"enrollment","type":"tuple"}],"name":"TraderEnrollmentUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"uint32","name":"day","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"feeMultiplier","type":"uint32"}],"name":"TraderFeeMultiplierCached","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"uint32","name":"day","type":"uint32"}],"name":"TraderInfoFirstUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"components":[{"internalType":"uint32","name":"lastDayUpdated","type":"uint32"},{"internalType":"uint224","name":"trailingPoints","type":"uint224"}],"indexed":false,"internalType":"struct IFeeTiers.TraderInfo","name":"traderInfo","type":"tuple"}],"name":"TraderInfoUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"uint32","name":"day","type":"uint32"},{"indexed":false,"internalType":"enum IFeeTiers.CreditType","name":"creditType","type":"uint8"},{"indexed":false,"internalType":"uint224","name":"points","type":"uint224"}],"name":"TraderPointsCredited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"uint32","name":"fromDay","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"toDay","type":"uint32"},{"indexed":false,"internalType":"uint224","name":"expiredPoints","type":"uint224"}],"name":"TraderTrailingPointsExpired","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"uint32","name":"day","type":"uint32"},{"indexed":false,"internalType":"uint224","name":"points","type":"uint224"}],"name":"TraderUnclaimedPointsClaimed","type":"event"},{"inputs":[{"internalType":"address[]","name":"_traders","type":"address[]"},{"internalType":"enum IFeeTiers.CreditType[]","name":"_creditTypes","type":"uint8[]"},{"internalType":"uint224[]","name":"_points","type":"uint224[]"}],"name":"addTradersUnclaimedPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_trader","type":"address"},{"internalType":"uint256","name":"_normalFeeAmountCollateral","type":"uint256"}],"name":"calculateFeeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAddresses","outputs":[{"components":[{"internalType":"address","name":"gns","type":"address"},{"internalType":"address","name":"gnsStaking","type":"address"},{"internalType":"address","name":"treasury","type":"address"}],"internalType":"struct IAddressStore.Addresses","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_feeTierIndex","type":"uint256"}],"name":"getFeeTier","outputs":[{"components":[{"internalType":"uint32","name":"feeMultiplier","type":"uint32"},{"internalType":"uint32","name":"pointsThreshold","type":"uint32"}],"internalType":"struct IFeeTiers.FeeTier","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeeTiersCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_trader","type":"address"},{"internalType":"uint32","name":"_day","type":"uint32"}],"name":"getFeeTiersTraderDailyInfo","outputs":[{"components":[{"internalType":"uint32","name":"feeMultiplierCache","type":"uint32"},{"internalType":"uint224","name":"points","type":"uint224"}],"internalType":"struct IFeeTiers.TraderDailyInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_trader","type":"address"}],"name":"getFeeTiersTraderInfo","outputs":[{"components":[{"internalType":"uint32","name":"lastDayUpdated","type":"uint32"},{"internalType":"uint224","name":"trailingPoints","type":"uint224"}],"internalType":"struct IFeeTiers.TraderInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_groupIndex","type":"uint256"}],"name":"getGroupVolumeMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_trader","type":"address"}],"name":"getTraderFeeTiersEnrollment","outputs":[{"components":[{"internalType":"enum IFeeTiers.TraderEnrollmentStatus","name":"status","type":"uint8"},{"internalType":"uint248","name":"__placeholder","type":"uint248"}],"internalType":"struct IFeeTiers.TraderEnrollment","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_trader","type":"address"}],"name":"getTraderUnclaimedPoints","outputs":[{"internalType":"uint224","name":"","type":"uint224"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"enum IAddressStore.Role","name":"_role","type":"uint8"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"enum IAddressStore.Role","name":"_roleA","type":"uint8"},{"internalType":"enum IAddressStore.Role","name":"_roleB","type":"uint8"}],"name":"hasRoles","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_govTimelock","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_groupIndices","type":"uint256[]"},{"internalType":"uint256[]","name":"_groupVolumeMultipliers","type":"uint256[]"},{"internalType":"uint256[]","name":"_feeTiersIndices","type":"uint256[]"},{"components":[{"internalType":"uint32","name":"feeMultiplier","type":"uint32"},{"internalType":"uint32","name":"pointsThreshold","type":"uint32"}],"internalType":"struct IFeeTiers.FeeTier[]","name":"_feeTiers","type":"tuple[]"}],"name":"initializeFeeTiers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_feeTiersIndices","type":"uint256[]"},{"components":[{"internalType":"uint32","name":"feeMultiplier","type":"uint32"},{"internalType":"uint32","name":"pointsThreshold","type":"uint32"}],"internalType":"struct IFeeTiers.FeeTier[]","name":"_feeTiers","type":"tuple[]"}],"name":"setFeeTiers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_groupIndices","type":"uint256[]"},{"internalType":"uint256[]","name":"_groupVolumeMultipliers","type":"uint256[]"}],"name":"setGroupVolumeMultipliers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_accounts","type":"address[]"},{"internalType":"enum IAddressStore.Role[]","name":"_roles","type":"uint8[]"},{"internalType":"bool[]","name":"_values","type":"bool[]"}],"name":"setRoles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_traders","type":"address[]"},{"components":[{"internalType":"enum IFeeTiers.TraderEnrollmentStatus","name":"status","type":"uint8"},{"internalType":"uint248","name":"__placeholder","type":"uint248"}],"internalType":"struct IFeeTiers.TraderEnrollment[]","name":"_values","type":"tuple[]"}],"name":"setTradersFeeTiersEnrollment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_trader","type":"address"},{"internalType":"uint256","name":"_volumeUsd","type":"uint256"},{"internalType":"uint256","name":"_pairIndex","type":"uint256"}],"name":"updateTraderPoints","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61265b80620000f36000396000f3fe608060405234801561001057600080fd5b50600436106101515760003560e01c806395a8c58d116100cd578063b9c9722911610081578063eccea3e211610066578063eccea3e214610344578063eced52491461037b578063fed8a1901461038e57600080fd5b8063b9c972291461031e578063c4d66de81461033157600080fd5b8063a89db8e5116100b2578063a89db8e5146102f0578063acbaaf33146102f8578063b61ce13b1461030b57600080fd5b806395a8c58d14610248578063a39fac121461026b57600080fd5b8063508cbfbe1161012457806384e3ebe21161010957806384e3ebe2146101f757806388f16bd114610222578063944f577a1461023557600080fd5b8063508cbfbe146101b7578063794d8520146101d757600080fd5b8063101e65031461015657806331ca48871461016b57806333534de2146101915780634f09a236146101a4575b600080fd5b610169610164366004611d55565b6103a1565b005b61017e610179366004611def565b610506565b6040519081526020015b60405180910390f35b61016961019f366004611e4d565b610517565b61017e6101b2366004611f2d565b610611565b6101ca6101c5366004611f57565b610624565b6040516101889190611f98565b6101ea6101e5366004611fd7565b610641565b604051610188919061200e565b61020a610205366004611f57565b61065f565b6040516001600160e01b039091168152602001610188565b610169610230366004612034565b61066a565b6101696102433660046120a0565b61068c565b61025b61025636600461210f565b6106aa565b6040519015158152602001610188565b6102be604080516060810182526000808252602082018190529181019190915250604080516060810182526003546001600160a01b03908116825260045481166020830152600554169181019190915290565b6040805182516001600160a01b0390811682526020808501518216908301529282015190921690820152606001610188565b61017e610701565b6101ea610306366004611f57565b610710565b610169610319366004611d55565b61072d565b61025b61032c366004612142565b61074f565b61016961033f366004611f57565b6107fe565b610357610352366004611def565b61093c565b60408051825163ffffffff9081168252602093840151169281019290925201610188565b610169610389366004612034565b610959565b61016961039c366004612185565b610970565b60006103ac816109a8565b85841415806103bb5750858214155b156103d957604051637db491eb60e01b815260040160405180910390fd5b60005b868110156104fc5760008686838181106103f8576103f86121b8565b905060200201602081019061040d91906121ce565b600381111561041e5761041e611f72565b148015610459575033888883818110610439576104396121b8565b905060200201602081019061044e9190611f57565b6001600160a01b0316145b1561047757604051631eb49d6d60e11b815260040160405180910390fd5b6104f488888381811061048c5761048c6121b8565b90506020020160208101906104a19190611f57565b8787848181106104b3576104b36121b8565b90506020020160208101906104c891906121ce565b8686858181106104da576104da6121b8565b90506020020160208101906104ef91906121e9565b6109d2565b6001016103dc565b5050505050505050565b600061051182610a74565b92915050565b600054600490610100900460ff16158015610539575060005460ff8083169116105b6105a15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805461ffff191660ff8316176101001790556105c58989898989898989610a92565b6000805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050505050565b600061061d8383610aaa565b9392505050565b604080518082019091526000808252602082015261051182610b58565b604080518082019091526000808252602082015261061d8383610be1565b600061051182610c59565b600160036106788282610c8e565b61068486868686610cb6565b505050505050565b6001610697816109a8565b6106a385858585610df9565b5050505050565b6001600160a01b0382166000908152600260205260408120818360038111156106d5576106d5611f72565b60038111156106e6576106e6611f72565b815260208101919091526040016000205460ff169392505050565b600061070b610ec8565b905090565b604080518082019091526000808252602082015261051182610f29565b6001610738816109a8565b610746878787878787610f91565b50505050505050565b6001600160a01b03831660009081526002602052604081208184600381111561077a5761077a611f72565b600381111561078b5761078b611f72565b815260208101919091526040016000205460ff16806107f657506001600160a01b0384166000908152600260205260408120908360038111156107d0576107d0611f72565b60038111156107e1576107e1611f72565b815260208101919091526040016000205460ff165b949350505050565b600054610100900460ff161580801561081e5750600054600160ff909116105b806108385750303b158015610838575060005460ff166001145b61089b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610598565b6000805460ff1916600117905580156108be576000805461ff0019166101001790555b6001600160a01b0382166108e557604051632c1c702960e21b815260040160405180910390fd5b6108f282600060016109d2565b8015610938576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b604080518082019091526000808252602082015261051182611209565b6001610964816109a8565b6106a385858585611262565b33301461099057604051631b17ff5560e21b815260040160405180910390fd5b6109a3838361099e84611374565b611392565b505050565b6109b233826106aa565b6109cf57604051631b17ff5560e21b815260040160405180910390fd5b50565b6001600160a01b038316600090815260026020526040812082918460038111156109fe576109fe611f72565b6003811115610a0f57610a0f611f72565b815260200190815260200160002060006101000a81548160ff0219169083151502179055507f8d7fdec37f50c07219a6a0859420936836eb9254bf412035e3acede18b8b093d838383604051610a679392919061220b565b60405180910390a1505050565b6000610a7e611825565b600092835260080160205250604090205490565b610a9e88888888610df9565b6104fc84848484611262565b600080610ab5611825565b6001600160a01b0385166000908152600b820160209081526040808320600a850190925282209293509181610ae861182f565b63ffffffff9081168252602082019290925260400160002054169050801580610b2657506001825460ff166001811115610b2457610b24611f72565b145b610b4c576103e8610b3d8663ffffffff8416612257565b610b479190612284565b610b4e565b845b9695505050505050565b6040805180820190915260008082526020820152610b74611825565b6001600160a01b0383166000908152600b9190910160205260409081902081518083019092528054829060ff166001811115610bb257610bb2611f72565b6001811115610bc357610bc3611f72565b8152905461010090046001600160f81b031660209091015292915050565b6040805180820190915260008082526020820152610bfd611825565b6001600160a01b03939093166000908152600a939093016020908152604080852063ffffffff948516865282529384902084518086019095525492831684526401000000009092046001600160e01b0316918301919091525090565b6000610c63611825565b6001600160a01b039092166000908152600c929092016020525060409020546001600160e01b031690565b610c9933838361074f565b61093857604051631b17ff5560e21b815260040160405180910390fd5b828114610cd6576040516349552d5960e11b815260040160405180910390fd5b6000610ce0611825565b905060005b8481101561068457600080878784818110610d0257610d026121b8565b9050602002016020810190610d179190611f57565b868685818110610d2957610d296121b8565b905060400201803603810190610d3f91906122a5565b600060208083018290526001600160a01b0384168252600b8801905260409020815181549395509193508392909190829060ff191660018381811115610d8757610d87611f72565b02179055506020919091015181546001600160f81b039091166101000260ff9091161790556040516001600160a01b038316907f2d222f8a9169a5d38b64fa1a56389af27712a1d7f1743022cdd8b466c27141eb90610de7908490611f98565b60405180910390a25050600101610ce5565b828114610e19576040516349552d5960e11b815260040160405180910390fd5b6000610e23611825565b600801905060005b84811015610e8357838382818110610e4557610e456121b8565b90506020020135826000888885818110610e6157610e616121b8565b6020908102929092013583525081019190915260400160002055600101610e2b565b507fb173e04a52e3de8d79b981e4ffc87d49e6577ceab559ebf36a70bba02cc2569c85858585604051610eb99493929190612369565b60405180910390a15050505050565b600080610ed3611825565b905060085b8015610f2057600082610eec60018461239b565b60088110610efc57610efc6121b8565b015463ffffffff161115610f105792915050565b610f19816123ae565b9050610ed8565b50600091505090565b6040805180820190915260008082526020820152610f45611825565b6001600160a01b039290921660009081526009909201602090815260409283902083518085019094525463ffffffff8116845264010000000090046001600160e01b0316908301525090565b8483141580610fa05750848114155b15610fbe576040516349552d5960e11b815260040160405180910390fd5b6000610fc8611825565b90506000610fd461182f565b905060005b878110156111fe5760008060008b8b85818110610ff857610ff86121b8565b905060200201602081019061100d9190611f57565b8a8a8681811061101f5761101f6121b8565b905060200201602081019061103491906123c5565b898987818110611046576110466121b8565b905060200201602081019061105b91906123e2565b6001600160a01b0383166000908152600c8a016020908152604080832054600a8d01835281842063ffffffff8d1685529092528220549497509295509093509183916110bc916001600160e01b03918216916401000000009091041661240b565b6110c6919061240b565b905060026110dc601e6001600160e01b03612432565b6110e69190612432565b6001600160e01b0316816001600160e01b031611156111185760405163034080e960e51b815260040160405180910390fd5b6001600160a01b0384166000908152600c880160205260408120805484929061114b9084906001600160e01b031661240b565b92506101000a8154816001600160e01b0302191690836001600160e01b031602179055506000600181111561118257611182611f72565b83600181111561119457611194611f72565b036111a5576111a584600080611392565b8563ffffffff16846001600160a01b03167ff050ee240db213d72ebabd2f46c0d3270c8206c02d51e074d447c4ca20bd7a6f85856040516111e7929190612458565b60405180910390a350505050806001019050610fd9565b505050505050505050565b6040805180820190915260008082526020820152611225611825565b8260088110611236576112366121b8565b6040805180820190915291015463ffffffff808216835264010000000090910416602082015292915050565b828114611282576040516349552d5960e11b815260040160405180910390fd5b600061128c611825565b905060005b848110156112f0578383828181106112ab576112ab6121b8565b905060400201828787848181106112c4576112c46121b8565b90506020020135600881106112db576112db6121b8565b016112e6828261247d565b5050600101611291565b5060005b8481101561133e57611336868683818110611311576113116121b8565b9050602002013585858481811061132a5761132a6121b8565b9050604002018461183e565b6001016112f4565b507fa6ec87cc1a516d9ebb5c03260f77d2bd8c22dc8d28d71e740b320fbd4d70413185858585604051610eb994939291906124d3565b600061137e611ae4565b600092835260205250604090206007015490565b600061139c611825565b90506113a784611aee565b60008281526008820160205260408120546103e8906113c69086612257565b6113d09190612284565b6001600160a01b0386166000908152600a8401602052604081209192506113f561182f565b63ffffffff811660009081526020849052604090209091506001600160e01b038416156114bd5780548490829060049061144190849064010000000090046001600160e01b031661240b565b92506101000a8154816001600160e01b0302191690836001600160e01b031602179055508163ffffffff16886001600160a01b03167f4f6f49815b9e6682a4f6bc21ba0b5261e803cc5d56c97477a5dc75925fd74e68866040516114b491906001600160e01b0391909116815260200190565b60405180910390a35b6001600160a01b038816600090815260098601602052604081208054909163ffffffff909116900361154757805463ffffffff191663ffffffff841690811782556040519081526001600160a01b038a16907f8aa104927dea7fb70b6e5eb2e2891e3022714eea9e80c493fdabffce48b423939060200160405180910390a2505050505050505050565b805463ffffffff90811690841611156111fe57600080611568601e8661254c565b835490915063ffffffff8083169116106116ab57825463ffffffff81166000908152602088905260409020546115b6916001600160e01b03640100000000928390048116929091041661240b565b83549092506000906115d090601e9063ffffffff1661254c565b905060006115df60018461254c565b90506000825b8263ffffffff168163ffffffff161161163b5763ffffffff8116600090815260208b905260409020546116299064010000000090046001600160e01b03168361240b565b915061163481612569565b90506115e5565b50611646818661258c565b6040805163ffffffff8087168252851660208201526001600160e01b038416918101919091529095506001600160a01b038f16907f964f0f6a92f6d7eedbff7670a2e850f5511e59321724a9dbef638c8068b7527b9060600160405180910390a25050505b6001600160e01b0382166401000000000263ffffffff86161783556040516001600160a01b038c16907f211bcdec669891da564d4d5bd35fa76cf6cc72a218db19f402ec042770fb83fb9061171490865463ffffffff81168252602090811c9082015260400190565b60405180910390a26103e86000611729610ec8565b90505b80156117bf5760008a61174060018461239b565b60088110611750576117506121b8565b6040805180820190915291015463ffffffff8082168352640100000000909104166020820181905290915061178e90670de0b6b3a7640000906125ac565b6001600160e01b0316856001600160e01b0316106117ae575191506117bf565b506117b8816123ae565b905061172c565b50845463ffffffff191663ffffffff82811691821787556040519182528716906001600160a01b038e16907f136cc4347dc65b38625089ea9df2874eda024554dc7d0a363036d6fa6d7e4c9e9060200160405180910390a3505050505050505050505050565b6000806097610511565b600061070b6201518042612284565b600061184d60208401846125de565b63ffffffff16158015611873575061186b60408401602085016125de565b63ffffffff16155b9050801580156118e257506103e861188e60208501856125de565b63ffffffff161015806118c457506118a960026103e86125fb565b63ffffffff166118bc60208501856125de565b63ffffffff16105b806118e257506118da60408401602085016125de565b63ffffffff16155b156119005760405163841ff20360e01b815260040160405180910390fd5b600061190e6001600861239b565b85109050811561196b57808015611948575060008361192e876001612612565b6008811061193e5761193e6121b8565b015463ffffffff16115b15611966576040516304b4359960e11b815260040160405180910390fd5b6106a3565b8015611a2c5760008361197f876001612612565b6008811061198f5761198f6121b8565b6040805180820190915291015463ffffffff80821680845264010000000090920416602083015290915015801590611a0c57506119cf60208601866125de565b63ffffffff16816000015163ffffffff16101580611a0c57506119f860408601602087016125de565b63ffffffff16816020015163ffffffff1611155b15611a2a576040516304b4359960e11b815260040160405180910390fd5b505b84156106a357600083611a4060018861239b565b60088110611a5057611a506121b8565b6040805180820190915291015463ffffffff808216835264010000000090910416602080830191909152909150611a89908601866125de565b63ffffffff16816000015163ffffffff16111580611ac65750611ab260408601602087016125de565b63ffffffff16816020015163ffffffff1610155b15610684576040516304b4359960e11b815260040160405180910390fd5b6000806033610511565b6000611af8611825565b6001600160a01b0383166000908152600c820160205260408120549192506001600160e01b0390911690819003611b2e57505050565b6001600160a01b0383166000908152600983016020526040812090611b5161182f565b6001600160a01b0386166000908152600c86016020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000169055835491925063ffffffff9091169003611c3f576000611bb160018361254c565b835463ffffffff191663ffffffff82811691821786556001600160a01b0389166000818152600a8a016020908152604080832086845282529182902080549094166401000000006001600160e01b038c160217909355519283529293507f8aa104927dea7fb70b6e5eb2e2891e3022714eea9e80c493fdabffce48b42393910160405180910390a250611cb3565b6001600160a01b0385166000908152600a85016020908152604080832063ffffffff8516845290915290208054849190600490611c8e90849064010000000090046001600160e01b031661240b565b92506101000a8154816001600160e01b0302191690836001600160e01b031602179055505b6040516001600160e01b038416815263ffffffff8216906001600160a01b038716907f8b1dd1669c243ea81885b90c31d292a58996045d48bd261b3aea98a09cd66f1e9060200160405180910390a35050505050565b60008083601f840112611d1b57600080fd5b50813567ffffffffffffffff811115611d3357600080fd5b6020830191508360208260051b8501011115611d4e57600080fd5b9250929050565b60008060008060008060608789031215611d6e57600080fd5b863567ffffffffffffffff80821115611d8657600080fd5b611d928a838b01611d09565b90985096506020890135915080821115611dab57600080fd5b611db78a838b01611d09565b90965094506040890135915080821115611dd057600080fd5b50611ddd89828a01611d09565b979a9699509497509295939492505050565b600060208284031215611e0157600080fd5b5035919050565b60008083601f840112611e1a57600080fd5b50813567ffffffffffffffff811115611e3257600080fd5b6020830191508360208260061b8501011115611d4e57600080fd5b6000806000806000806000806080898b031215611e6957600080fd5b883567ffffffffffffffff80821115611e8157600080fd5b611e8d8c838d01611d09565b909a50985060208b0135915080821115611ea657600080fd5b611eb28c838d01611d09565b909850965060408b0135915080821115611ecb57600080fd5b611ed78c838d01611d09565b909650945060608b0135915080821115611ef057600080fd5b50611efd8b828c01611e08565b999c989b5096995094979396929594505050565b80356001600160a01b0381168114611f2857600080fd5b919050565b60008060408385031215611f4057600080fd5b611f4983611f11565b946020939093013593505050565b600060208284031215611f6957600080fd5b61061d82611f11565b634e487b7160e01b600052602160045260246000fd5b600281106109cf576109cf611f72565b81516040820190611fa881611f88565b808352506001600160f81b03602084015116602083015292915050565b63ffffffff811681146109cf57600080fd5b60008060408385031215611fea57600080fd5b611ff383611f11565b9150602083013561200381611fc5565b809150509250929050565b815163ffffffff1681526020808301516001600160e01b03169082015260408101610511565b6000806000806040858703121561204a57600080fd5b843567ffffffffffffffff8082111561206257600080fd5b61206e88838901611d09565b9096509450602087013591508082111561208757600080fd5b5061209487828801611e08565b95989497509550505050565b600080600080604085870312156120b657600080fd5b843567ffffffffffffffff808211156120ce57600080fd5b6120da88838901611d09565b909650945060208701359150808211156120f357600080fd5b5061209487828801611d09565b803560048110611f2857600080fd5b6000806040838503121561212257600080fd5b61212b83611f11565b915061213960208401612100565b90509250929050565b60008060006060848603121561215757600080fd5b61216084611f11565b925061216e60208501612100565b915061217c60408501612100565b90509250925092565b60008060006060848603121561219a57600080fd5b6121a384611f11565b95602085013595506040909401359392505050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156121e057600080fd5b61061d82612100565b6000602082840312156121fb57600080fd5b8135801515811461061d57600080fd5b6001600160a01b0384168152606081016004841061222b5761222b611f72565b8360208301528215156040830152949350505050565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761051157610511612241565b634e487b7160e01b600052601260045260246000fd5b6000826122935761229361226e565b500490565b600281106109cf57600080fd5b6000604082840312156122b757600080fd5b6040516040810181811067ffffffffffffffff821117156122e857634e487b7160e01b600052604160045260246000fd5b60405282356122f681612298565b815260208301356001600160f81b038116811461231257600080fd5b60208201529392505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561235057600080fd5b8260051b80836020870137939093016020019392505050565b60408152600061237d60408301868861231e565b828103602084015261239081858761231e565b979650505050505050565b8181038181111561051157610511612241565b6000816123bd576123bd612241565b506000190190565b6000602082840312156123d757600080fd5b813561061d81612298565b6000602082840312156123f457600080fd5b81356001600160e01b038116811461061d57600080fd5b6001600160e01b0381811683821601908082111561242b5761242b612241565b5092915050565b60006001600160e01b038084168061244c5761244c61226e565b92169190910492915050565b6040810161246584611f88565b9281526001600160e01b039190911660209091015290565b813561248881611fc5565b63ffffffff8116905081548163ffffffff19821617835560208401356124ad81611fc5565b67ffffffff000000008160201b168367ffffffffffffffff198416171784555050505050565b600060408083526124e860408401878961231e565b8381036020858101919091528582528691810160005b8781101561253e57833561251181611fc5565b63ffffffff9081168352848401359061252982611fc5565b168284015292840192908401906001016124fe565b509998505050505050505050565b63ffffffff82811682821603908082111561242b5761242b612241565b600063ffffffff80831681810361258257612582612241565b6001019392505050565b6001600160e01b0382811682821603908082111561242b5761242b612241565b6001600160e01b038281168282168181028316929181158285048214176125d5576125d5612241565b50505092915050565b6000602082840312156125f057600080fd5b813561061d81611fc5565b600063ffffffff8084168061244c5761244c61226e565b808201808211156105115761051161224156fea26469706673582212208ae2c3340314882d2b9c72ce1083cc8f0994570c1408d4817e4fd5e5966893e264736f6c63430008170033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101515760003560e01c806395a8c58d116100cd578063b9c9722911610081578063eccea3e211610066578063eccea3e214610344578063eced52491461037b578063fed8a1901461038e57600080fd5b8063b9c972291461031e578063c4d66de81461033157600080fd5b8063a89db8e5116100b2578063a89db8e5146102f0578063acbaaf33146102f8578063b61ce13b1461030b57600080fd5b806395a8c58d14610248578063a39fac121461026b57600080fd5b8063508cbfbe1161012457806384e3ebe21161010957806384e3ebe2146101f757806388f16bd114610222578063944f577a1461023557600080fd5b8063508cbfbe146101b7578063794d8520146101d757600080fd5b8063101e65031461015657806331ca48871461016b57806333534de2146101915780634f09a236146101a4575b600080fd5b610169610164366004611d55565b6103a1565b005b61017e610179366004611def565b610506565b6040519081526020015b60405180910390f35b61016961019f366004611e4d565b610517565b61017e6101b2366004611f2d565b610611565b6101ca6101c5366004611f57565b610624565b6040516101889190611f98565b6101ea6101e5366004611fd7565b610641565b604051610188919061200e565b61020a610205366004611f57565b61065f565b6040516001600160e01b039091168152602001610188565b610169610230366004612034565b61066a565b6101696102433660046120a0565b61068c565b61025b61025636600461210f565b6106aa565b6040519015158152602001610188565b6102be604080516060810182526000808252602082018190529181019190915250604080516060810182526003546001600160a01b03908116825260045481166020830152600554169181019190915290565b6040805182516001600160a01b0390811682526020808501518216908301529282015190921690820152606001610188565b61017e610701565b6101ea610306366004611f57565b610710565b610169610319366004611d55565b61072d565b61025b61032c366004612142565b61074f565b61016961033f366004611f57565b6107fe565b610357610352366004611def565b61093c565b60408051825163ffffffff9081168252602093840151169281019290925201610188565b610169610389366004612034565b610959565b61016961039c366004612185565b610970565b60006103ac816109a8565b85841415806103bb5750858214155b156103d957604051637db491eb60e01b815260040160405180910390fd5b60005b868110156104fc5760008686838181106103f8576103f86121b8565b905060200201602081019061040d91906121ce565b600381111561041e5761041e611f72565b148015610459575033888883818110610439576104396121b8565b905060200201602081019061044e9190611f57565b6001600160a01b0316145b1561047757604051631eb49d6d60e11b815260040160405180910390fd5b6104f488888381811061048c5761048c6121b8565b90506020020160208101906104a19190611f57565b8787848181106104b3576104b36121b8565b90506020020160208101906104c891906121ce565b8686858181106104da576104da6121b8565b90506020020160208101906104ef91906121e9565b6109d2565b6001016103dc565b5050505050505050565b600061051182610a74565b92915050565b600054600490610100900460ff16158015610539575060005460ff8083169116105b6105a15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805461ffff191660ff8316176101001790556105c58989898989898989610a92565b6000805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050505050565b600061061d8383610aaa565b9392505050565b604080518082019091526000808252602082015261051182610b58565b604080518082019091526000808252602082015261061d8383610be1565b600061051182610c59565b600160036106788282610c8e565b61068486868686610cb6565b505050505050565b6001610697816109a8565b6106a385858585610df9565b5050505050565b6001600160a01b0382166000908152600260205260408120818360038111156106d5576106d5611f72565b60038111156106e6576106e6611f72565b815260208101919091526040016000205460ff169392505050565b600061070b610ec8565b905090565b604080518082019091526000808252602082015261051182610f29565b6001610738816109a8565b610746878787878787610f91565b50505050505050565b6001600160a01b03831660009081526002602052604081208184600381111561077a5761077a611f72565b600381111561078b5761078b611f72565b815260208101919091526040016000205460ff16806107f657506001600160a01b0384166000908152600260205260408120908360038111156107d0576107d0611f72565b60038111156107e1576107e1611f72565b815260208101919091526040016000205460ff165b949350505050565b600054610100900460ff161580801561081e5750600054600160ff909116105b806108385750303b158015610838575060005460ff166001145b61089b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610598565b6000805460ff1916600117905580156108be576000805461ff0019166101001790555b6001600160a01b0382166108e557604051632c1c702960e21b815260040160405180910390fd5b6108f282600060016109d2565b8015610938576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b604080518082019091526000808252602082015261051182611209565b6001610964816109a8565b6106a385858585611262565b33301461099057604051631b17ff5560e21b815260040160405180910390fd5b6109a3838361099e84611374565b611392565b505050565b6109b233826106aa565b6109cf57604051631b17ff5560e21b815260040160405180910390fd5b50565b6001600160a01b038316600090815260026020526040812082918460038111156109fe576109fe611f72565b6003811115610a0f57610a0f611f72565b815260200190815260200160002060006101000a81548160ff0219169083151502179055507f8d7fdec37f50c07219a6a0859420936836eb9254bf412035e3acede18b8b093d838383604051610a679392919061220b565b60405180910390a1505050565b6000610a7e611825565b600092835260080160205250604090205490565b610a9e88888888610df9565b6104fc84848484611262565b600080610ab5611825565b6001600160a01b0385166000908152600b820160209081526040808320600a850190925282209293509181610ae861182f565b63ffffffff9081168252602082019290925260400160002054169050801580610b2657506001825460ff166001811115610b2457610b24611f72565b145b610b4c576103e8610b3d8663ffffffff8416612257565b610b479190612284565b610b4e565b845b9695505050505050565b6040805180820190915260008082526020820152610b74611825565b6001600160a01b0383166000908152600b9190910160205260409081902081518083019092528054829060ff166001811115610bb257610bb2611f72565b6001811115610bc357610bc3611f72565b8152905461010090046001600160f81b031660209091015292915050565b6040805180820190915260008082526020820152610bfd611825565b6001600160a01b03939093166000908152600a939093016020908152604080852063ffffffff948516865282529384902084518086019095525492831684526401000000009092046001600160e01b0316918301919091525090565b6000610c63611825565b6001600160a01b039092166000908152600c929092016020525060409020546001600160e01b031690565b610c9933838361074f565b61093857604051631b17ff5560e21b815260040160405180910390fd5b828114610cd6576040516349552d5960e11b815260040160405180910390fd5b6000610ce0611825565b905060005b8481101561068457600080878784818110610d0257610d026121b8565b9050602002016020810190610d179190611f57565b868685818110610d2957610d296121b8565b905060400201803603810190610d3f91906122a5565b600060208083018290526001600160a01b0384168252600b8801905260409020815181549395509193508392909190829060ff191660018381811115610d8757610d87611f72565b02179055506020919091015181546001600160f81b039091166101000260ff9091161790556040516001600160a01b038316907f2d222f8a9169a5d38b64fa1a56389af27712a1d7f1743022cdd8b466c27141eb90610de7908490611f98565b60405180910390a25050600101610ce5565b828114610e19576040516349552d5960e11b815260040160405180910390fd5b6000610e23611825565b600801905060005b84811015610e8357838382818110610e4557610e456121b8565b90506020020135826000888885818110610e6157610e616121b8565b6020908102929092013583525081019190915260400160002055600101610e2b565b507fb173e04a52e3de8d79b981e4ffc87d49e6577ceab559ebf36a70bba02cc2569c85858585604051610eb99493929190612369565b60405180910390a15050505050565b600080610ed3611825565b905060085b8015610f2057600082610eec60018461239b565b60088110610efc57610efc6121b8565b015463ffffffff161115610f105792915050565b610f19816123ae565b9050610ed8565b50600091505090565b6040805180820190915260008082526020820152610f45611825565b6001600160a01b039290921660009081526009909201602090815260409283902083518085019094525463ffffffff8116845264010000000090046001600160e01b0316908301525090565b8483141580610fa05750848114155b15610fbe576040516349552d5960e11b815260040160405180910390fd5b6000610fc8611825565b90506000610fd461182f565b905060005b878110156111fe5760008060008b8b85818110610ff857610ff86121b8565b905060200201602081019061100d9190611f57565b8a8a8681811061101f5761101f6121b8565b905060200201602081019061103491906123c5565b898987818110611046576110466121b8565b905060200201602081019061105b91906123e2565b6001600160a01b0383166000908152600c8a016020908152604080832054600a8d01835281842063ffffffff8d1685529092528220549497509295509093509183916110bc916001600160e01b03918216916401000000009091041661240b565b6110c6919061240b565b905060026110dc601e6001600160e01b03612432565b6110e69190612432565b6001600160e01b0316816001600160e01b031611156111185760405163034080e960e51b815260040160405180910390fd5b6001600160a01b0384166000908152600c880160205260408120805484929061114b9084906001600160e01b031661240b565b92506101000a8154816001600160e01b0302191690836001600160e01b031602179055506000600181111561118257611182611f72565b83600181111561119457611194611f72565b036111a5576111a584600080611392565b8563ffffffff16846001600160a01b03167ff050ee240db213d72ebabd2f46c0d3270c8206c02d51e074d447c4ca20bd7a6f85856040516111e7929190612458565b60405180910390a350505050806001019050610fd9565b505050505050505050565b6040805180820190915260008082526020820152611225611825565b8260088110611236576112366121b8565b6040805180820190915291015463ffffffff808216835264010000000090910416602082015292915050565b828114611282576040516349552d5960e11b815260040160405180910390fd5b600061128c611825565b905060005b848110156112f0578383828181106112ab576112ab6121b8565b905060400201828787848181106112c4576112c46121b8565b90506020020135600881106112db576112db6121b8565b016112e6828261247d565b5050600101611291565b5060005b8481101561133e57611336868683818110611311576113116121b8565b9050602002013585858481811061132a5761132a6121b8565b9050604002018461183e565b6001016112f4565b507fa6ec87cc1a516d9ebb5c03260f77d2bd8c22dc8d28d71e740b320fbd4d70413185858585604051610eb994939291906124d3565b600061137e611ae4565b600092835260205250604090206007015490565b600061139c611825565b90506113a784611aee565b60008281526008820160205260408120546103e8906113c69086612257565b6113d09190612284565b6001600160a01b0386166000908152600a8401602052604081209192506113f561182f565b63ffffffff811660009081526020849052604090209091506001600160e01b038416156114bd5780548490829060049061144190849064010000000090046001600160e01b031661240b565b92506101000a8154816001600160e01b0302191690836001600160e01b031602179055508163ffffffff16886001600160a01b03167f4f6f49815b9e6682a4f6bc21ba0b5261e803cc5d56c97477a5dc75925fd74e68866040516114b491906001600160e01b0391909116815260200190565b60405180910390a35b6001600160a01b038816600090815260098601602052604081208054909163ffffffff909116900361154757805463ffffffff191663ffffffff841690811782556040519081526001600160a01b038a16907f8aa104927dea7fb70b6e5eb2e2891e3022714eea9e80c493fdabffce48b423939060200160405180910390a2505050505050505050565b805463ffffffff90811690841611156111fe57600080611568601e8661254c565b835490915063ffffffff8083169116106116ab57825463ffffffff81166000908152602088905260409020546115b6916001600160e01b03640100000000928390048116929091041661240b565b83549092506000906115d090601e9063ffffffff1661254c565b905060006115df60018461254c565b90506000825b8263ffffffff168163ffffffff161161163b5763ffffffff8116600090815260208b905260409020546116299064010000000090046001600160e01b03168361240b565b915061163481612569565b90506115e5565b50611646818661258c565b6040805163ffffffff8087168252851660208201526001600160e01b038416918101919091529095506001600160a01b038f16907f964f0f6a92f6d7eedbff7670a2e850f5511e59321724a9dbef638c8068b7527b9060600160405180910390a25050505b6001600160e01b0382166401000000000263ffffffff86161783556040516001600160a01b038c16907f211bcdec669891da564d4d5bd35fa76cf6cc72a218db19f402ec042770fb83fb9061171490865463ffffffff81168252602090811c9082015260400190565b60405180910390a26103e86000611729610ec8565b90505b80156117bf5760008a61174060018461239b565b60088110611750576117506121b8565b6040805180820190915291015463ffffffff8082168352640100000000909104166020820181905290915061178e90670de0b6b3a7640000906125ac565b6001600160e01b0316856001600160e01b0316106117ae575191506117bf565b506117b8816123ae565b905061172c565b50845463ffffffff191663ffffffff82811691821787556040519182528716906001600160a01b038e16907f136cc4347dc65b38625089ea9df2874eda024554dc7d0a363036d6fa6d7e4c9e9060200160405180910390a3505050505050505050505050565b6000806097610511565b600061070b6201518042612284565b600061184d60208401846125de565b63ffffffff16158015611873575061186b60408401602085016125de565b63ffffffff16155b9050801580156118e257506103e861188e60208501856125de565b63ffffffff161015806118c457506118a960026103e86125fb565b63ffffffff166118bc60208501856125de565b63ffffffff16105b806118e257506118da60408401602085016125de565b63ffffffff16155b156119005760405163841ff20360e01b815260040160405180910390fd5b600061190e6001600861239b565b85109050811561196b57808015611948575060008361192e876001612612565b6008811061193e5761193e6121b8565b015463ffffffff16115b15611966576040516304b4359960e11b815260040160405180910390fd5b6106a3565b8015611a2c5760008361197f876001612612565b6008811061198f5761198f6121b8565b6040805180820190915291015463ffffffff80821680845264010000000090920416602083015290915015801590611a0c57506119cf60208601866125de565b63ffffffff16816000015163ffffffff16101580611a0c57506119f860408601602087016125de565b63ffffffff16816020015163ffffffff1611155b15611a2a576040516304b4359960e11b815260040160405180910390fd5b505b84156106a357600083611a4060018861239b565b60088110611a5057611a506121b8565b6040805180820190915291015463ffffffff808216835264010000000090910416602080830191909152909150611a89908601866125de565b63ffffffff16816000015163ffffffff16111580611ac65750611ab260408601602087016125de565b63ffffffff16816020015163ffffffff1610155b15610684576040516304b4359960e11b815260040160405180910390fd5b6000806033610511565b6000611af8611825565b6001600160a01b0383166000908152600c820160205260408120549192506001600160e01b0390911690819003611b2e57505050565b6001600160a01b0383166000908152600983016020526040812090611b5161182f565b6001600160a01b0386166000908152600c86016020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000169055835491925063ffffffff9091169003611c3f576000611bb160018361254c565b835463ffffffff191663ffffffff82811691821786556001600160a01b0389166000818152600a8a016020908152604080832086845282529182902080549094166401000000006001600160e01b038c160217909355519283529293507f8aa104927dea7fb70b6e5eb2e2891e3022714eea9e80c493fdabffce48b42393910160405180910390a250611cb3565b6001600160a01b0385166000908152600a85016020908152604080832063ffffffff8516845290915290208054849190600490611c8e90849064010000000090046001600160e01b031661240b565b92506101000a8154816001600160e01b0302191690836001600160e01b031602179055505b6040516001600160e01b038416815263ffffffff8216906001600160a01b038716907f8b1dd1669c243ea81885b90c31d292a58996045d48bd261b3aea98a09cd66f1e9060200160405180910390a35050505050565b60008083601f840112611d1b57600080fd5b50813567ffffffffffffffff811115611d3357600080fd5b6020830191508360208260051b8501011115611d4e57600080fd5b9250929050565b60008060008060008060608789031215611d6e57600080fd5b863567ffffffffffffffff80821115611d8657600080fd5b611d928a838b01611d09565b90985096506020890135915080821115611dab57600080fd5b611db78a838b01611d09565b90965094506040890135915080821115611dd057600080fd5b50611ddd89828a01611d09565b979a9699509497509295939492505050565b600060208284031215611e0157600080fd5b5035919050565b60008083601f840112611e1a57600080fd5b50813567ffffffffffffffff811115611e3257600080fd5b6020830191508360208260061b8501011115611d4e57600080fd5b6000806000806000806000806080898b031215611e6957600080fd5b883567ffffffffffffffff80821115611e8157600080fd5b611e8d8c838d01611d09565b909a50985060208b0135915080821115611ea657600080fd5b611eb28c838d01611d09565b909850965060408b0135915080821115611ecb57600080fd5b611ed78c838d01611d09565b909650945060608b0135915080821115611ef057600080fd5b50611efd8b828c01611e08565b999c989b5096995094979396929594505050565b80356001600160a01b0381168114611f2857600080fd5b919050565b60008060408385031215611f4057600080fd5b611f4983611f11565b946020939093013593505050565b600060208284031215611f6957600080fd5b61061d82611f11565b634e487b7160e01b600052602160045260246000fd5b600281106109cf576109cf611f72565b81516040820190611fa881611f88565b808352506001600160f81b03602084015116602083015292915050565b63ffffffff811681146109cf57600080fd5b60008060408385031215611fea57600080fd5b611ff383611f11565b9150602083013561200381611fc5565b809150509250929050565b815163ffffffff1681526020808301516001600160e01b03169082015260408101610511565b6000806000806040858703121561204a57600080fd5b843567ffffffffffffffff8082111561206257600080fd5b61206e88838901611d09565b9096509450602087013591508082111561208757600080fd5b5061209487828801611e08565b95989497509550505050565b600080600080604085870312156120b657600080fd5b843567ffffffffffffffff808211156120ce57600080fd5b6120da88838901611d09565b909650945060208701359150808211156120f357600080fd5b5061209487828801611d09565b803560048110611f2857600080fd5b6000806040838503121561212257600080fd5b61212b83611f11565b915061213960208401612100565b90509250929050565b60008060006060848603121561215757600080fd5b61216084611f11565b925061216e60208501612100565b915061217c60408501612100565b90509250925092565b60008060006060848603121561219a57600080fd5b6121a384611f11565b95602085013595506040909401359392505050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156121e057600080fd5b61061d82612100565b6000602082840312156121fb57600080fd5b8135801515811461061d57600080fd5b6001600160a01b0384168152606081016004841061222b5761222b611f72565b8360208301528215156040830152949350505050565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761051157610511612241565b634e487b7160e01b600052601260045260246000fd5b6000826122935761229361226e565b500490565b600281106109cf57600080fd5b6000604082840312156122b757600080fd5b6040516040810181811067ffffffffffffffff821117156122e857634e487b7160e01b600052604160045260246000fd5b60405282356122f681612298565b815260208301356001600160f81b038116811461231257600080fd5b60208201529392505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561235057600080fd5b8260051b80836020870137939093016020019392505050565b60408152600061237d60408301868861231e565b828103602084015261239081858761231e565b979650505050505050565b8181038181111561051157610511612241565b6000816123bd576123bd612241565b506000190190565b6000602082840312156123d757600080fd5b813561061d81612298565b6000602082840312156123f457600080fd5b81356001600160e01b038116811461061d57600080fd5b6001600160e01b0381811683821601908082111561242b5761242b612241565b5092915050565b60006001600160e01b038084168061244c5761244c61226e565b92169190910492915050565b6040810161246584611f88565b9281526001600160e01b039190911660209091015290565b813561248881611fc5565b63ffffffff8116905081548163ffffffff19821617835560208401356124ad81611fc5565b67ffffffff000000008160201b168367ffffffffffffffff198416171784555050505050565b600060408083526124e860408401878961231e565b8381036020858101919091528582528691810160005b8781101561253e57833561251181611fc5565b63ffffffff9081168352848401359061252982611fc5565b168284015292840192908401906001016124fe565b509998505050505050505050565b63ffffffff82811682821603908082111561242b5761242b612241565b600063ffffffff80831681810361258257612582612241565b6001019392505050565b6001600160e01b0382811682821603908082111561242b5761242b612241565b6001600160e01b038281168282168181028316929181158285048214176125d5576125d5612241565b50505092915050565b6000602082840312156125f057600080fd5b813561061d81611fc5565b600063ffffffff8084168061244c5761244c61226e565b808201808211156105115761051161224156fea26469706673582212208ae2c3340314882d2b9c72ce1083cc8f0994570c1408d4817e4fd5e5966893e264736f6c63430008170033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

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.