Overview
APE Balance
0 APE
APE Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 4603328 | 2 days ago | IN | 0 APE | 0.05594125 |
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
Contract Source Code (Solidity Standard Json-Input format)
// 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); } }
// 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; } }
// 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); } } }
// 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(); } _; } }
// 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(); }
// 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(); }
// 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(); }
// 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(); }
// 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 } }
// 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; } }
// 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 }
// 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; } }
// 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; } }
// 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); } }
// 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); } }
// 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; }
{ "optimizer": { "enabled": true, "runs": 800 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"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"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61265b80620000f36000396000f3fe608060405234801561001057600080fd5b50600436106101515760003560e01c806395a8c58d116100cd578063b9c9722911610081578063eccea3e211610066578063eccea3e214610344578063eced52491461037b578063fed8a1901461038e57600080fd5b8063b9c972291461031e578063c4d66de81461033157600080fd5b8063a89db8e5116100b2578063a89db8e5146102f0578063acbaaf33146102f8578063b61ce13b1461030b57600080fd5b806395a8c58d14610248578063a39fac121461026b57600080fd5b8063508cbfbe1161012457806384e3ebe21161010957806384e3ebe2146101f757806388f16bd114610222578063944f577a1461023557600080fd5b8063508cbfbe146101b7578063794d8520146101d757600080fd5b8063101e65031461015657806331ca48871461016b57806333534de2146101915780634f09a236146101a4575b600080fd5b610169610164366004611d55565b6103a1565b005b61017e610179366004611def565b610506565b6040519081526020015b60405180910390f35b61016961019f366004611e4d565b610517565b61017e6101b2366004611f2d565b610611565b6101ca6101c5366004611f57565b610624565b6040516101889190611f98565b6101ea6101e5366004611fd7565b610641565b604051610188919061200e565b61020a610205366004611f57565b61065f565b6040516001600160e01b039091168152602001610188565b610169610230366004612034565b61066a565b6101696102433660046120a0565b61068c565b61025b61025636600461210f565b6106aa565b6040519015158152602001610188565b6102be604080516060810182526000808252602082018190529181019190915250604080516060810182526003546001600160a01b03908116825260045481166020830152600554169181019190915290565b6040805182516001600160a01b0390811682526020808501518216908301529282015190921690820152606001610188565b61017e610701565b6101ea610306366004611f57565b610710565b610169610319366004611d55565b61072d565b61025b61032c366004612142565b61074f565b61016961033f366004611f57565b6107fe565b610357610352366004611def565b61093c565b60408051825163ffffffff9081168252602093840151169281019290925201610188565b610169610389366004612034565b610959565b61016961039c366004612185565b610970565b60006103ac816109a8565b85841415806103bb5750858214155b156103d957604051637db491eb60e01b815260040160405180910390fd5b60005b868110156104fc5760008686838181106103f8576103f86121b8565b905060200201602081019061040d91906121ce565b600381111561041e5761041e611f72565b148015610459575033888883818110610439576104396121b8565b905060200201602081019061044e9190611f57565b6001600160a01b0316145b1561047757604051631eb49d6d60e11b815260040160405180910390fd5b6104f488888381811061048c5761048c6121b8565b90506020020160208101906104a19190611f57565b8787848181106104b3576104b36121b8565b90506020020160208101906104c891906121ce565b8686858181106104da576104da6121b8565b90506020020160208101906104ef91906121e9565b6109d2565b6001016103dc565b5050505050505050565b600061051182610a74565b92915050565b600054600490610100900460ff16158015610539575060005460ff8083169116105b6105a15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805461ffff191660ff8316176101001790556105c58989898989898989610a92565b6000805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050505050565b600061061d8383610aaa565b9392505050565b604080518082019091526000808252602082015261051182610b58565b604080518082019091526000808252602082015261061d8383610be1565b600061051182610c59565b600160036106788282610c8e565b61068486868686610cb6565b505050505050565b6001610697816109a8565b6106a385858585610df9565b5050505050565b6001600160a01b0382166000908152600260205260408120818360038111156106d5576106d5611f72565b60038111156106e6576106e6611f72565b815260208101919091526040016000205460ff169392505050565b600061070b610ec8565b905090565b604080518082019091526000808252602082015261051182610f29565b6001610738816109a8565b610746878787878787610f91565b50505050505050565b6001600160a01b03831660009081526002602052604081208184600381111561077a5761077a611f72565b600381111561078b5761078b611f72565b815260208101919091526040016000205460ff16806107f657506001600160a01b0384166000908152600260205260408120908360038111156107d0576107d0611f72565b60038111156107e1576107e1611f72565b815260208101919091526040016000205460ff165b949350505050565b600054610100900460ff161580801561081e5750600054600160ff909116105b806108385750303b158015610838575060005460ff166001145b61089b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610598565b6000805460ff1916600117905580156108be576000805461ff0019166101001790555b6001600160a01b0382166108e557604051632c1c702960e21b815260040160405180910390fd5b6108f282600060016109d2565b8015610938576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b604080518082019091526000808252602082015261051182611209565b6001610964816109a8565b6106a385858585611262565b33301461099057604051631b17ff5560e21b815260040160405180910390fd5b6109a3838361099e84611374565b611392565b505050565b6109b233826106aa565b6109cf57604051631b17ff5560e21b815260040160405180910390fd5b50565b6001600160a01b038316600090815260026020526040812082918460038111156109fe576109fe611f72565b6003811115610a0f57610a0f611f72565b815260200190815260200160002060006101000a81548160ff0219169083151502179055507f8d7fdec37f50c07219a6a0859420936836eb9254bf412035e3acede18b8b093d838383604051610a679392919061220b565b60405180910390a1505050565b6000610a7e611825565b600092835260080160205250604090205490565b610a9e88888888610df9565b6104fc84848484611262565b600080610ab5611825565b6001600160a01b0385166000908152600b820160209081526040808320600a850190925282209293509181610ae861182f565b63ffffffff9081168252602082019290925260400160002054169050801580610b2657506001825460ff166001811115610b2457610b24611f72565b145b610b4c576103e8610b3d8663ffffffff8416612257565b610b479190612284565b610b4e565b845b9695505050505050565b6040805180820190915260008082526020820152610b74611825565b6001600160a01b0383166000908152600b9190910160205260409081902081518083019092528054829060ff166001811115610bb257610bb2611f72565b6001811115610bc357610bc3611f72565b8152905461010090046001600160f81b031660209091015292915050565b6040805180820190915260008082526020820152610bfd611825565b6001600160a01b03939093166000908152600a939093016020908152604080852063ffffffff948516865282529384902084518086019095525492831684526401000000009092046001600160e01b0316918301919091525090565b6000610c63611825565b6001600160a01b039092166000908152600c929092016020525060409020546001600160e01b031690565b610c9933838361074f565b61093857604051631b17ff5560e21b815260040160405180910390fd5b828114610cd6576040516349552d5960e11b815260040160405180910390fd5b6000610ce0611825565b905060005b8481101561068457600080878784818110610d0257610d026121b8565b9050602002016020810190610d179190611f57565b868685818110610d2957610d296121b8565b905060400201803603810190610d3f91906122a5565b600060208083018290526001600160a01b0384168252600b8801905260409020815181549395509193508392909190829060ff191660018381811115610d8757610d87611f72565b02179055506020919091015181546001600160f81b039091166101000260ff9091161790556040516001600160a01b038316907f2d222f8a9169a5d38b64fa1a56389af27712a1d7f1743022cdd8b466c27141eb90610de7908490611f98565b60405180910390a25050600101610ce5565b828114610e19576040516349552d5960e11b815260040160405180910390fd5b6000610e23611825565b600801905060005b84811015610e8357838382818110610e4557610e456121b8565b90506020020135826000888885818110610e6157610e616121b8565b6020908102929092013583525081019190915260400160002055600101610e2b565b507fb173e04a52e3de8d79b981e4ffc87d49e6577ceab559ebf36a70bba02cc2569c85858585604051610eb99493929190612369565b60405180910390a15050505050565b600080610ed3611825565b905060085b8015610f2057600082610eec60018461239b565b60088110610efc57610efc6121b8565b015463ffffffff161115610f105792915050565b610f19816123ae565b9050610ed8565b50600091505090565b6040805180820190915260008082526020820152610f45611825565b6001600160a01b039290921660009081526009909201602090815260409283902083518085019094525463ffffffff8116845264010000000090046001600160e01b0316908301525090565b8483141580610fa05750848114155b15610fbe576040516349552d5960e11b815260040160405180910390fd5b6000610fc8611825565b90506000610fd461182f565b905060005b878110156111fe5760008060008b8b85818110610ff857610ff86121b8565b905060200201602081019061100d9190611f57565b8a8a8681811061101f5761101f6121b8565b905060200201602081019061103491906123c5565b898987818110611046576110466121b8565b905060200201602081019061105b91906123e2565b6001600160a01b0383166000908152600c8a016020908152604080832054600a8d01835281842063ffffffff8d1685529092528220549497509295509093509183916110bc916001600160e01b03918216916401000000009091041661240b565b6110c6919061240b565b905060026110dc601e6001600160e01b03612432565b6110e69190612432565b6001600160e01b0316816001600160e01b031611156111185760405163034080e960e51b815260040160405180910390fd5b6001600160a01b0384166000908152600c880160205260408120805484929061114b9084906001600160e01b031661240b565b92506101000a8154816001600160e01b0302191690836001600160e01b031602179055506000600181111561118257611182611f72565b83600181111561119457611194611f72565b036111a5576111a584600080611392565b8563ffffffff16846001600160a01b03167ff050ee240db213d72ebabd2f46c0d3270c8206c02d51e074d447c4ca20bd7a6f85856040516111e7929190612458565b60405180910390a350505050806001019050610fd9565b505050505050505050565b6040805180820190915260008082526020820152611225611825565b8260088110611236576112366121b8565b6040805180820190915291015463ffffffff808216835264010000000090910416602082015292915050565b828114611282576040516349552d5960e11b815260040160405180910390fd5b600061128c611825565b905060005b848110156112f0578383828181106112ab576112ab6121b8565b905060400201828787848181106112c4576112c46121b8565b90506020020135600881106112db576112db6121b8565b016112e6828261247d565b5050600101611291565b5060005b8481101561133e57611336868683818110611311576113116121b8565b9050602002013585858481811061132a5761132a6121b8565b9050604002018461183e565b6001016112f4565b507fa6ec87cc1a516d9ebb5c03260f77d2bd8c22dc8d28d71e740b320fbd4d70413185858585604051610eb994939291906124d3565b600061137e611ae4565b600092835260205250604090206007015490565b600061139c611825565b90506113a784611aee565b60008281526008820160205260408120546103e8906113c69086612257565b6113d09190612284565b6001600160a01b0386166000908152600a8401602052604081209192506113f561182f565b63ffffffff811660009081526020849052604090209091506001600160e01b038416156114bd5780548490829060049061144190849064010000000090046001600160e01b031661240b565b92506101000a8154816001600160e01b0302191690836001600160e01b031602179055508163ffffffff16886001600160a01b03167f4f6f49815b9e6682a4f6bc21ba0b5261e803cc5d56c97477a5dc75925fd74e68866040516114b491906001600160e01b0391909116815260200190565b60405180910390a35b6001600160a01b038816600090815260098601602052604081208054909163ffffffff909116900361154757805463ffffffff191663ffffffff841690811782556040519081526001600160a01b038a16907f8aa104927dea7fb70b6e5eb2e2891e3022714eea9e80c493fdabffce48b423939060200160405180910390a2505050505050505050565b805463ffffffff90811690841611156111fe57600080611568601e8661254c565b835490915063ffffffff8083169116106116ab57825463ffffffff81166000908152602088905260409020546115b6916001600160e01b03640100000000928390048116929091041661240b565b83549092506000906115d090601e9063ffffffff1661254c565b905060006115df60018461254c565b90506000825b8263ffffffff168163ffffffff161161163b5763ffffffff8116600090815260208b905260409020546116299064010000000090046001600160e01b03168361240b565b915061163481612569565b90506115e5565b50611646818661258c565b6040805163ffffffff8087168252851660208201526001600160e01b038416918101919091529095506001600160a01b038f16907f964f0f6a92f6d7eedbff7670a2e850f5511e59321724a9dbef638c8068b7527b9060600160405180910390a25050505b6001600160e01b0382166401000000000263ffffffff86161783556040516001600160a01b038c16907f211bcdec669891da564d4d5bd35fa76cf6cc72a218db19f402ec042770fb83fb9061171490865463ffffffff81168252602090811c9082015260400190565b60405180910390a26103e86000611729610ec8565b90505b80156117bf5760008a61174060018461239b565b60088110611750576117506121b8565b6040805180820190915291015463ffffffff8082168352640100000000909104166020820181905290915061178e90670de0b6b3a7640000906125ac565b6001600160e01b0316856001600160e01b0316106117ae575191506117bf565b506117b8816123ae565b905061172c565b50845463ffffffff191663ffffffff82811691821787556040519182528716906001600160a01b038e16907f136cc4347dc65b38625089ea9df2874eda024554dc7d0a363036d6fa6d7e4c9e9060200160405180910390a3505050505050505050505050565b6000806097610511565b600061070b6201518042612284565b600061184d60208401846125de565b63ffffffff16158015611873575061186b60408401602085016125de565b63ffffffff16155b9050801580156118e257506103e861188e60208501856125de565b63ffffffff161015806118c457506118a960026103e86125fb565b63ffffffff166118bc60208501856125de565b63ffffffff16105b806118e257506118da60408401602085016125de565b63ffffffff16155b156119005760405163841ff20360e01b815260040160405180910390fd5b600061190e6001600861239b565b85109050811561196b57808015611948575060008361192e876001612612565b6008811061193e5761193e6121b8565b015463ffffffff16115b15611966576040516304b4359960e11b815260040160405180910390fd5b6106a3565b8015611a2c5760008361197f876001612612565b6008811061198f5761198f6121b8565b6040805180820190915291015463ffffffff80821680845264010000000090920416602083015290915015801590611a0c57506119cf60208601866125de565b63ffffffff16816000015163ffffffff16101580611a0c57506119f860408601602087016125de565b63ffffffff16816020015163ffffffff1611155b15611a2a576040516304b4359960e11b815260040160405180910390fd5b505b84156106a357600083611a4060018861239b565b60088110611a5057611a506121b8565b6040805180820190915291015463ffffffff808216835264010000000090910416602080830191909152909150611a89908601866125de565b63ffffffff16816000015163ffffffff16111580611ac65750611ab260408601602087016125de565b63ffffffff16816020015163ffffffff1610155b15610684576040516304b4359960e11b815260040160405180910390fd5b6000806033610511565b6000611af8611825565b6001600160a01b0383166000908152600c820160205260408120549192506001600160e01b0390911690819003611b2e57505050565b6001600160a01b0383166000908152600983016020526040812090611b5161182f565b6001600160a01b0386166000908152600c86016020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000169055835491925063ffffffff9091169003611c3f576000611bb160018361254c565b835463ffffffff191663ffffffff82811691821786556001600160a01b0389166000818152600a8a016020908152604080832086845282529182902080549094166401000000006001600160e01b038c160217909355519283529293507f8aa104927dea7fb70b6e5eb2e2891e3022714eea9e80c493fdabffce48b42393910160405180910390a250611cb3565b6001600160a01b0385166000908152600a85016020908152604080832063ffffffff8516845290915290208054849190600490611c8e90849064010000000090046001600160e01b031661240b565b92506101000a8154816001600160e01b0302191690836001600160e01b031602179055505b6040516001600160e01b038416815263ffffffff8216906001600160a01b038716907f8b1dd1669c243ea81885b90c31d292a58996045d48bd261b3aea98a09cd66f1e9060200160405180910390a35050505050565b60008083601f840112611d1b57600080fd5b50813567ffffffffffffffff811115611d3357600080fd5b6020830191508360208260051b8501011115611d4e57600080fd5b9250929050565b60008060008060008060608789031215611d6e57600080fd5b863567ffffffffffffffff80821115611d8657600080fd5b611d928a838b01611d09565b90985096506020890135915080821115611dab57600080fd5b611db78a838b01611d09565b90965094506040890135915080821115611dd057600080fd5b50611ddd89828a01611d09565b979a9699509497509295939492505050565b600060208284031215611e0157600080fd5b5035919050565b60008083601f840112611e1a57600080fd5b50813567ffffffffffffffff811115611e3257600080fd5b6020830191508360208260061b8501011115611d4e57600080fd5b6000806000806000806000806080898b031215611e6957600080fd5b883567ffffffffffffffff80821115611e8157600080fd5b611e8d8c838d01611d09565b909a50985060208b0135915080821115611ea657600080fd5b611eb28c838d01611d09565b909850965060408b0135915080821115611ecb57600080fd5b611ed78c838d01611d09565b909650945060608b0135915080821115611ef057600080fd5b50611efd8b828c01611e08565b999c989b5096995094979396929594505050565b80356001600160a01b0381168114611f2857600080fd5b919050565b60008060408385031215611f4057600080fd5b611f4983611f11565b946020939093013593505050565b600060208284031215611f6957600080fd5b61061d82611f11565b634e487b7160e01b600052602160045260246000fd5b600281106109cf576109cf611f72565b81516040820190611fa881611f88565b808352506001600160f81b03602084015116602083015292915050565b63ffffffff811681146109cf57600080fd5b60008060408385031215611fea57600080fd5b611ff383611f11565b9150602083013561200381611fc5565b809150509250929050565b815163ffffffff1681526020808301516001600160e01b03169082015260408101610511565b6000806000806040858703121561204a57600080fd5b843567ffffffffffffffff8082111561206257600080fd5b61206e88838901611d09565b9096509450602087013591508082111561208757600080fd5b5061209487828801611e08565b95989497509550505050565b600080600080604085870312156120b657600080fd5b843567ffffffffffffffff808211156120ce57600080fd5b6120da88838901611d09565b909650945060208701359150808211156120f357600080fd5b5061209487828801611d09565b803560048110611f2857600080fd5b6000806040838503121561212257600080fd5b61212b83611f11565b915061213960208401612100565b90509250929050565b60008060006060848603121561215757600080fd5b61216084611f11565b925061216e60208501612100565b915061217c60408501612100565b90509250925092565b60008060006060848603121561219a57600080fd5b6121a384611f11565b95602085013595506040909401359392505050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156121e057600080fd5b61061d82612100565b6000602082840312156121fb57600080fd5b8135801515811461061d57600080fd5b6001600160a01b0384168152606081016004841061222b5761222b611f72565b8360208301528215156040830152949350505050565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761051157610511612241565b634e487b7160e01b600052601260045260246000fd5b6000826122935761229361226e565b500490565b600281106109cf57600080fd5b6000604082840312156122b757600080fd5b6040516040810181811067ffffffffffffffff821117156122e857634e487b7160e01b600052604160045260246000fd5b60405282356122f681612298565b815260208301356001600160f81b038116811461231257600080fd5b60208201529392505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561235057600080fd5b8260051b80836020870137939093016020019392505050565b60408152600061237d60408301868861231e565b828103602084015261239081858761231e565b979650505050505050565b8181038181111561051157610511612241565b6000816123bd576123bd612241565b506000190190565b6000602082840312156123d757600080fd5b813561061d81612298565b6000602082840312156123f457600080fd5b81356001600160e01b038116811461061d57600080fd5b6001600160e01b0381811683821601908082111561242b5761242b612241565b5092915050565b60006001600160e01b038084168061244c5761244c61226e565b92169190910492915050565b6040810161246584611f88565b9281526001600160e01b039190911660209091015290565b813561248881611fc5565b63ffffffff8116905081548163ffffffff19821617835560208401356124ad81611fc5565b67ffffffff000000008160201b168367ffffffffffffffff198416171784555050505050565b600060408083526124e860408401878961231e565b8381036020858101919091528582528691810160005b8781101561253e57833561251181611fc5565b63ffffffff9081168352848401359061252982611fc5565b168284015292840192908401906001016124fe565b509998505050505050505050565b63ffffffff82811682821603908082111561242b5761242b612241565b600063ffffffff80831681810361258257612582612241565b6001019392505050565b6001600160e01b0382811682821603908082111561242b5761242b612241565b6001600160e01b038281168282168181028316929181158285048214176125d5576125d5612241565b50505092915050565b6000602082840312156125f057600080fd5b813561061d81611fc5565b600063ffffffff8084168061244c5761244c61226e565b808201808211156105115761051161224156fea26469706673582212208ae2c3340314882d2b9c72ce1083cc8f0994570c1408d4817e4fd5e5966893e264736f6c63430008170033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101515760003560e01c806395a8c58d116100cd578063b9c9722911610081578063eccea3e211610066578063eccea3e214610344578063eced52491461037b578063fed8a1901461038e57600080fd5b8063b9c972291461031e578063c4d66de81461033157600080fd5b8063a89db8e5116100b2578063a89db8e5146102f0578063acbaaf33146102f8578063b61ce13b1461030b57600080fd5b806395a8c58d14610248578063a39fac121461026b57600080fd5b8063508cbfbe1161012457806384e3ebe21161010957806384e3ebe2146101f757806388f16bd114610222578063944f577a1461023557600080fd5b8063508cbfbe146101b7578063794d8520146101d757600080fd5b8063101e65031461015657806331ca48871461016b57806333534de2146101915780634f09a236146101a4575b600080fd5b610169610164366004611d55565b6103a1565b005b61017e610179366004611def565b610506565b6040519081526020015b60405180910390f35b61016961019f366004611e4d565b610517565b61017e6101b2366004611f2d565b610611565b6101ca6101c5366004611f57565b610624565b6040516101889190611f98565b6101ea6101e5366004611fd7565b610641565b604051610188919061200e565b61020a610205366004611f57565b61065f565b6040516001600160e01b039091168152602001610188565b610169610230366004612034565b61066a565b6101696102433660046120a0565b61068c565b61025b61025636600461210f565b6106aa565b6040519015158152602001610188565b6102be604080516060810182526000808252602082018190529181019190915250604080516060810182526003546001600160a01b03908116825260045481166020830152600554169181019190915290565b6040805182516001600160a01b0390811682526020808501518216908301529282015190921690820152606001610188565b61017e610701565b6101ea610306366004611f57565b610710565b610169610319366004611d55565b61072d565b61025b61032c366004612142565b61074f565b61016961033f366004611f57565b6107fe565b610357610352366004611def565b61093c565b60408051825163ffffffff9081168252602093840151169281019290925201610188565b610169610389366004612034565b610959565b61016961039c366004612185565b610970565b60006103ac816109a8565b85841415806103bb5750858214155b156103d957604051637db491eb60e01b815260040160405180910390fd5b60005b868110156104fc5760008686838181106103f8576103f86121b8565b905060200201602081019061040d91906121ce565b600381111561041e5761041e611f72565b148015610459575033888883818110610439576104396121b8565b905060200201602081019061044e9190611f57565b6001600160a01b0316145b1561047757604051631eb49d6d60e11b815260040160405180910390fd5b6104f488888381811061048c5761048c6121b8565b90506020020160208101906104a19190611f57565b8787848181106104b3576104b36121b8565b90506020020160208101906104c891906121ce565b8686858181106104da576104da6121b8565b90506020020160208101906104ef91906121e9565b6109d2565b6001016103dc565b5050505050505050565b600061051182610a74565b92915050565b600054600490610100900460ff16158015610539575060005460ff8083169116105b6105a15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805461ffff191660ff8316176101001790556105c58989898989898989610a92565b6000805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050505050565b600061061d8383610aaa565b9392505050565b604080518082019091526000808252602082015261051182610b58565b604080518082019091526000808252602082015261061d8383610be1565b600061051182610c59565b600160036106788282610c8e565b61068486868686610cb6565b505050505050565b6001610697816109a8565b6106a385858585610df9565b5050505050565b6001600160a01b0382166000908152600260205260408120818360038111156106d5576106d5611f72565b60038111156106e6576106e6611f72565b815260208101919091526040016000205460ff169392505050565b600061070b610ec8565b905090565b604080518082019091526000808252602082015261051182610f29565b6001610738816109a8565b610746878787878787610f91565b50505050505050565b6001600160a01b03831660009081526002602052604081208184600381111561077a5761077a611f72565b600381111561078b5761078b611f72565b815260208101919091526040016000205460ff16806107f657506001600160a01b0384166000908152600260205260408120908360038111156107d0576107d0611f72565b60038111156107e1576107e1611f72565b815260208101919091526040016000205460ff165b949350505050565b600054610100900460ff161580801561081e5750600054600160ff909116105b806108385750303b158015610838575060005460ff166001145b61089b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610598565b6000805460ff1916600117905580156108be576000805461ff0019166101001790555b6001600160a01b0382166108e557604051632c1c702960e21b815260040160405180910390fd5b6108f282600060016109d2565b8015610938576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b604080518082019091526000808252602082015261051182611209565b6001610964816109a8565b6106a385858585611262565b33301461099057604051631b17ff5560e21b815260040160405180910390fd5b6109a3838361099e84611374565b611392565b505050565b6109b233826106aa565b6109cf57604051631b17ff5560e21b815260040160405180910390fd5b50565b6001600160a01b038316600090815260026020526040812082918460038111156109fe576109fe611f72565b6003811115610a0f57610a0f611f72565b815260200190815260200160002060006101000a81548160ff0219169083151502179055507f8d7fdec37f50c07219a6a0859420936836eb9254bf412035e3acede18b8b093d838383604051610a679392919061220b565b60405180910390a1505050565b6000610a7e611825565b600092835260080160205250604090205490565b610a9e88888888610df9565b6104fc84848484611262565b600080610ab5611825565b6001600160a01b0385166000908152600b820160209081526040808320600a850190925282209293509181610ae861182f565b63ffffffff9081168252602082019290925260400160002054169050801580610b2657506001825460ff166001811115610b2457610b24611f72565b145b610b4c576103e8610b3d8663ffffffff8416612257565b610b479190612284565b610b4e565b845b9695505050505050565b6040805180820190915260008082526020820152610b74611825565b6001600160a01b0383166000908152600b9190910160205260409081902081518083019092528054829060ff166001811115610bb257610bb2611f72565b6001811115610bc357610bc3611f72565b8152905461010090046001600160f81b031660209091015292915050565b6040805180820190915260008082526020820152610bfd611825565b6001600160a01b03939093166000908152600a939093016020908152604080852063ffffffff948516865282529384902084518086019095525492831684526401000000009092046001600160e01b0316918301919091525090565b6000610c63611825565b6001600160a01b039092166000908152600c929092016020525060409020546001600160e01b031690565b610c9933838361074f565b61093857604051631b17ff5560e21b815260040160405180910390fd5b828114610cd6576040516349552d5960e11b815260040160405180910390fd5b6000610ce0611825565b905060005b8481101561068457600080878784818110610d0257610d026121b8565b9050602002016020810190610d179190611f57565b868685818110610d2957610d296121b8565b905060400201803603810190610d3f91906122a5565b600060208083018290526001600160a01b0384168252600b8801905260409020815181549395509193508392909190829060ff191660018381811115610d8757610d87611f72565b02179055506020919091015181546001600160f81b039091166101000260ff9091161790556040516001600160a01b038316907f2d222f8a9169a5d38b64fa1a56389af27712a1d7f1743022cdd8b466c27141eb90610de7908490611f98565b60405180910390a25050600101610ce5565b828114610e19576040516349552d5960e11b815260040160405180910390fd5b6000610e23611825565b600801905060005b84811015610e8357838382818110610e4557610e456121b8565b90506020020135826000888885818110610e6157610e616121b8565b6020908102929092013583525081019190915260400160002055600101610e2b565b507fb173e04a52e3de8d79b981e4ffc87d49e6577ceab559ebf36a70bba02cc2569c85858585604051610eb99493929190612369565b60405180910390a15050505050565b600080610ed3611825565b905060085b8015610f2057600082610eec60018461239b565b60088110610efc57610efc6121b8565b015463ffffffff161115610f105792915050565b610f19816123ae565b9050610ed8565b50600091505090565b6040805180820190915260008082526020820152610f45611825565b6001600160a01b039290921660009081526009909201602090815260409283902083518085019094525463ffffffff8116845264010000000090046001600160e01b0316908301525090565b8483141580610fa05750848114155b15610fbe576040516349552d5960e11b815260040160405180910390fd5b6000610fc8611825565b90506000610fd461182f565b905060005b878110156111fe5760008060008b8b85818110610ff857610ff86121b8565b905060200201602081019061100d9190611f57565b8a8a8681811061101f5761101f6121b8565b905060200201602081019061103491906123c5565b898987818110611046576110466121b8565b905060200201602081019061105b91906123e2565b6001600160a01b0383166000908152600c8a016020908152604080832054600a8d01835281842063ffffffff8d1685529092528220549497509295509093509183916110bc916001600160e01b03918216916401000000009091041661240b565b6110c6919061240b565b905060026110dc601e6001600160e01b03612432565b6110e69190612432565b6001600160e01b0316816001600160e01b031611156111185760405163034080e960e51b815260040160405180910390fd5b6001600160a01b0384166000908152600c880160205260408120805484929061114b9084906001600160e01b031661240b565b92506101000a8154816001600160e01b0302191690836001600160e01b031602179055506000600181111561118257611182611f72565b83600181111561119457611194611f72565b036111a5576111a584600080611392565b8563ffffffff16846001600160a01b03167ff050ee240db213d72ebabd2f46c0d3270c8206c02d51e074d447c4ca20bd7a6f85856040516111e7929190612458565b60405180910390a350505050806001019050610fd9565b505050505050505050565b6040805180820190915260008082526020820152611225611825565b8260088110611236576112366121b8565b6040805180820190915291015463ffffffff808216835264010000000090910416602082015292915050565b828114611282576040516349552d5960e11b815260040160405180910390fd5b600061128c611825565b905060005b848110156112f0578383828181106112ab576112ab6121b8565b905060400201828787848181106112c4576112c46121b8565b90506020020135600881106112db576112db6121b8565b016112e6828261247d565b5050600101611291565b5060005b8481101561133e57611336868683818110611311576113116121b8565b9050602002013585858481811061132a5761132a6121b8565b9050604002018461183e565b6001016112f4565b507fa6ec87cc1a516d9ebb5c03260f77d2bd8c22dc8d28d71e740b320fbd4d70413185858585604051610eb994939291906124d3565b600061137e611ae4565b600092835260205250604090206007015490565b600061139c611825565b90506113a784611aee565b60008281526008820160205260408120546103e8906113c69086612257565b6113d09190612284565b6001600160a01b0386166000908152600a8401602052604081209192506113f561182f565b63ffffffff811660009081526020849052604090209091506001600160e01b038416156114bd5780548490829060049061144190849064010000000090046001600160e01b031661240b565b92506101000a8154816001600160e01b0302191690836001600160e01b031602179055508163ffffffff16886001600160a01b03167f4f6f49815b9e6682a4f6bc21ba0b5261e803cc5d56c97477a5dc75925fd74e68866040516114b491906001600160e01b0391909116815260200190565b60405180910390a35b6001600160a01b038816600090815260098601602052604081208054909163ffffffff909116900361154757805463ffffffff191663ffffffff841690811782556040519081526001600160a01b038a16907f8aa104927dea7fb70b6e5eb2e2891e3022714eea9e80c493fdabffce48b423939060200160405180910390a2505050505050505050565b805463ffffffff90811690841611156111fe57600080611568601e8661254c565b835490915063ffffffff8083169116106116ab57825463ffffffff81166000908152602088905260409020546115b6916001600160e01b03640100000000928390048116929091041661240b565b83549092506000906115d090601e9063ffffffff1661254c565b905060006115df60018461254c565b90506000825b8263ffffffff168163ffffffff161161163b5763ffffffff8116600090815260208b905260409020546116299064010000000090046001600160e01b03168361240b565b915061163481612569565b90506115e5565b50611646818661258c565b6040805163ffffffff8087168252851660208201526001600160e01b038416918101919091529095506001600160a01b038f16907f964f0f6a92f6d7eedbff7670a2e850f5511e59321724a9dbef638c8068b7527b9060600160405180910390a25050505b6001600160e01b0382166401000000000263ffffffff86161783556040516001600160a01b038c16907f211bcdec669891da564d4d5bd35fa76cf6cc72a218db19f402ec042770fb83fb9061171490865463ffffffff81168252602090811c9082015260400190565b60405180910390a26103e86000611729610ec8565b90505b80156117bf5760008a61174060018461239b565b60088110611750576117506121b8565b6040805180820190915291015463ffffffff8082168352640100000000909104166020820181905290915061178e90670de0b6b3a7640000906125ac565b6001600160e01b0316856001600160e01b0316106117ae575191506117bf565b506117b8816123ae565b905061172c565b50845463ffffffff191663ffffffff82811691821787556040519182528716906001600160a01b038e16907f136cc4347dc65b38625089ea9df2874eda024554dc7d0a363036d6fa6d7e4c9e9060200160405180910390a3505050505050505050505050565b6000806097610511565b600061070b6201518042612284565b600061184d60208401846125de565b63ffffffff16158015611873575061186b60408401602085016125de565b63ffffffff16155b9050801580156118e257506103e861188e60208501856125de565b63ffffffff161015806118c457506118a960026103e86125fb565b63ffffffff166118bc60208501856125de565b63ffffffff16105b806118e257506118da60408401602085016125de565b63ffffffff16155b156119005760405163841ff20360e01b815260040160405180910390fd5b600061190e6001600861239b565b85109050811561196b57808015611948575060008361192e876001612612565b6008811061193e5761193e6121b8565b015463ffffffff16115b15611966576040516304b4359960e11b815260040160405180910390fd5b6106a3565b8015611a2c5760008361197f876001612612565b6008811061198f5761198f6121b8565b6040805180820190915291015463ffffffff80821680845264010000000090920416602083015290915015801590611a0c57506119cf60208601866125de565b63ffffffff16816000015163ffffffff16101580611a0c57506119f860408601602087016125de565b63ffffffff16816020015163ffffffff1611155b15611a2a576040516304b4359960e11b815260040160405180910390fd5b505b84156106a357600083611a4060018861239b565b60088110611a5057611a506121b8565b6040805180820190915291015463ffffffff808216835264010000000090910416602080830191909152909150611a89908601866125de565b63ffffffff16816000015163ffffffff16111580611ac65750611ab260408601602087016125de565b63ffffffff16816020015163ffffffff1610155b15610684576040516304b4359960e11b815260040160405180910390fd5b6000806033610511565b6000611af8611825565b6001600160a01b0383166000908152600c820160205260408120549192506001600160e01b0390911690819003611b2e57505050565b6001600160a01b0383166000908152600983016020526040812090611b5161182f565b6001600160a01b0386166000908152600c86016020526040812080547fffffffff00000000000000000000000000000000000000000000000000000000169055835491925063ffffffff9091169003611c3f576000611bb160018361254c565b835463ffffffff191663ffffffff82811691821786556001600160a01b0389166000818152600a8a016020908152604080832086845282529182902080549094166401000000006001600160e01b038c160217909355519283529293507f8aa104927dea7fb70b6e5eb2e2891e3022714eea9e80c493fdabffce48b42393910160405180910390a250611cb3565b6001600160a01b0385166000908152600a85016020908152604080832063ffffffff8516845290915290208054849190600490611c8e90849064010000000090046001600160e01b031661240b565b92506101000a8154816001600160e01b0302191690836001600160e01b031602179055505b6040516001600160e01b038416815263ffffffff8216906001600160a01b038716907f8b1dd1669c243ea81885b90c31d292a58996045d48bd261b3aea98a09cd66f1e9060200160405180910390a35050505050565b60008083601f840112611d1b57600080fd5b50813567ffffffffffffffff811115611d3357600080fd5b6020830191508360208260051b8501011115611d4e57600080fd5b9250929050565b60008060008060008060608789031215611d6e57600080fd5b863567ffffffffffffffff80821115611d8657600080fd5b611d928a838b01611d09565b90985096506020890135915080821115611dab57600080fd5b611db78a838b01611d09565b90965094506040890135915080821115611dd057600080fd5b50611ddd89828a01611d09565b979a9699509497509295939492505050565b600060208284031215611e0157600080fd5b5035919050565b60008083601f840112611e1a57600080fd5b50813567ffffffffffffffff811115611e3257600080fd5b6020830191508360208260061b8501011115611d4e57600080fd5b6000806000806000806000806080898b031215611e6957600080fd5b883567ffffffffffffffff80821115611e8157600080fd5b611e8d8c838d01611d09565b909a50985060208b0135915080821115611ea657600080fd5b611eb28c838d01611d09565b909850965060408b0135915080821115611ecb57600080fd5b611ed78c838d01611d09565b909650945060608b0135915080821115611ef057600080fd5b50611efd8b828c01611e08565b999c989b5096995094979396929594505050565b80356001600160a01b0381168114611f2857600080fd5b919050565b60008060408385031215611f4057600080fd5b611f4983611f11565b946020939093013593505050565b600060208284031215611f6957600080fd5b61061d82611f11565b634e487b7160e01b600052602160045260246000fd5b600281106109cf576109cf611f72565b81516040820190611fa881611f88565b808352506001600160f81b03602084015116602083015292915050565b63ffffffff811681146109cf57600080fd5b60008060408385031215611fea57600080fd5b611ff383611f11565b9150602083013561200381611fc5565b809150509250929050565b815163ffffffff1681526020808301516001600160e01b03169082015260408101610511565b6000806000806040858703121561204a57600080fd5b843567ffffffffffffffff8082111561206257600080fd5b61206e88838901611d09565b9096509450602087013591508082111561208757600080fd5b5061209487828801611e08565b95989497509550505050565b600080600080604085870312156120b657600080fd5b843567ffffffffffffffff808211156120ce57600080fd5b6120da88838901611d09565b909650945060208701359150808211156120f357600080fd5b5061209487828801611d09565b803560048110611f2857600080fd5b6000806040838503121561212257600080fd5b61212b83611f11565b915061213960208401612100565b90509250929050565b60008060006060848603121561215757600080fd5b61216084611f11565b925061216e60208501612100565b915061217c60408501612100565b90509250925092565b60008060006060848603121561219a57600080fd5b6121a384611f11565b95602085013595506040909401359392505050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156121e057600080fd5b61061d82612100565b6000602082840312156121fb57600080fd5b8135801515811461061d57600080fd5b6001600160a01b0384168152606081016004841061222b5761222b611f72565b8360208301528215156040830152949350505050565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761051157610511612241565b634e487b7160e01b600052601260045260246000fd5b6000826122935761229361226e565b500490565b600281106109cf57600080fd5b6000604082840312156122b757600080fd5b6040516040810181811067ffffffffffffffff821117156122e857634e487b7160e01b600052604160045260246000fd5b60405282356122f681612298565b815260208301356001600160f81b038116811461231257600080fd5b60208201529392505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561235057600080fd5b8260051b80836020870137939093016020019392505050565b60408152600061237d60408301868861231e565b828103602084015261239081858761231e565b979650505050505050565b8181038181111561051157610511612241565b6000816123bd576123bd612241565b506000190190565b6000602082840312156123d757600080fd5b813561061d81612298565b6000602082840312156123f457600080fd5b81356001600160e01b038116811461061d57600080fd5b6001600160e01b0381811683821601908082111561242b5761242b612241565b5092915050565b60006001600160e01b038084168061244c5761244c61226e565b92169190910492915050565b6040810161246584611f88565b9281526001600160e01b039190911660209091015290565b813561248881611fc5565b63ffffffff8116905081548163ffffffff19821617835560208401356124ad81611fc5565b67ffffffff000000008160201b168367ffffffffffffffff198416171784555050505050565b600060408083526124e860408401878961231e565b8381036020858101919091528582528691810160005b8781101561253e57833561251181611fc5565b63ffffffff9081168352848401359061252982611fc5565b168284015292840192908401906001016124fe565b509998505050505050505050565b63ffffffff82811682821603908082111561242b5761242b612241565b600063ffffffff80831681810361258257612582612241565b6001019392505050565b6001600160e01b0382811682821603908082111561242b5761242b612241565b6001600160e01b038281168282168181028316929181158285048214176125d5576125d5612241565b50505092915050565b6000602082840312156125f057600080fd5b813561061d81611fc5565b600063ffffffff8084168061244c5761244c61226e565b808201808211156105115761051161224156fea26469706673582212208ae2c3340314882d2b9c72ce1083cc8f0994570c1408d4817e4fd5e5966893e264736f6c63430008170033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.