ETH Price: $2,431.33 (-9.73%)

Contract

0x8f8BccE4c180B699F81499005281fA89440D1e95

Overview

ETH Balance

241 wei

ETH Value

Less Than $0.01 (@ $2,431.33/ETH)

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Add Liquidity3502977992025-06-23 7:57:02222 days ago1750665422IN
0x8f8BccE4...9440D1e95
0 ETH0.000002060.01
Add Liquidity3502972772025-06-23 7:54:52222 days ago1750665292IN
0x8f8BccE4...9440D1e95
0 ETH0.000002090.01
Add Liquidity3502959132025-06-23 7:49:10222 days ago1750664950IN
0x8f8BccE4...9440D1e95
0 ETH0.000002080.01
Add Liquidity3502950852025-06-23 7:45:45222 days ago1750664745IN
0x8f8BccE4...9440D1e95
0 ETH0.000002060.01
Set Delegate3502943832025-06-23 7:42:49222 days ago1750664569IN
0x8f8BccE4...9440D1e95
0 ETH0.000000570.01036
Add Liquidity3502942202025-06-23 7:42:10222 days ago1750664530IN
0x8f8BccE4...9440D1e95
0 ETH0.000002520.012291
Add Liquidity3502928372025-06-23 7:36:23222 days ago1750664183IN
0x8f8BccE4...9440D1e95
0 ETH0.000002740.013381
0x7895ba4d3483823952025-06-17 18:28:41228 days ago1750184921IN
0x8f8BccE4...9440D1e95
0 ETH0.000005050.01
0x7895ba4d3483823342025-06-17 18:28:26228 days ago1750184906IN
0x8f8BccE4...9440D1e95
0 ETH0.000005020.01
0x7895ba4d3483822832025-06-17 18:28:13228 days ago1750184893IN
0x8f8BccE4...9440D1e95
0 ETH0.000005050.01
0x7895ba4d3483821732025-06-17 18:27:45228 days ago1750184865IN
0x8f8BccE4...9440D1e95
0 ETH0.000005040.01
0x7895ba4d3483821212025-06-17 18:27:32228 days ago1750184852IN
0x8f8BccE4...9440D1e95
0 ETH0.000005020.01
0x7895ba4d3483820722025-06-17 18:27:20228 days ago1750184840IN
0x8f8BccE4...9440D1e95
0 ETH0.000005030.01
0x7895ba4d3483818242025-06-17 18:26:18228 days ago1750184778IN
0x8f8BccE4...9440D1e95
0 ETH0.000005170.01
0x7895ba4d3483817712025-06-17 18:26:04228 days ago1750184764IN
0x8f8BccE4...9440D1e95
0 ETH0.000005060.01
Clear Traders In...3483807642025-06-17 18:21:51228 days ago1750184511IN
0x8f8BccE4...9440D1e95
0 ETH0.000003320.01
Toggle Perp Emer...3483807442025-06-17 18:21:46228 days ago1750184506IN
0x8f8BccE4...9440D1e95
0 ETH0.000001450.01
Set Emergency St...3483807242025-06-17 18:21:41228 days ago1750184501IN
0x8f8BccE4...9440D1e95
0 ETH0.000001530.01
Clear Traders In...3483807022025-06-17 18:21:35228 days ago1750184495IN
0x8f8BccE4...9440D1e95
0 ETH0.000003380.01
Toggle Perp Emer...3483806822025-06-17 18:21:30228 days ago1750184490IN
0x8f8BccE4...9440D1e95
0 ETH0.000001450.01
Set Emergency St...3483806622025-06-17 18:21:25228 days ago1750184485IN
0x8f8BccE4...9440D1e95
0 ETH0.000001530.01
Clear Traders In...3483806412025-06-17 18:21:20228 days ago1750184480IN
0x8f8BccE4...9440D1e95
0 ETH0.000003320.01
Toggle Perp Emer...3483806202025-06-17 18:21:15228 days ago1750184475IN
0x8f8BccE4...9440D1e95
0 ETH0.000001450.01
Set Emergency St...3483806002025-06-17 18:21:10228 days ago1750184470IN
0x8f8BccE4...9440D1e95
0 ETH0.00000150.01
Clear Traders In...3483805782025-06-17 18:21:04228 days ago1750184464IN
0x8f8BccE4...9440D1e95
0 ETH0.000003270.01
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
3483197572025-06-17 14:07:02228 days ago1750169222
0x8f8BccE4...9440D1e95
1 wei
3483197572025-06-17 14:07:02228 days ago1750169222
0x8f8BccE4...9440D1e95
1 wei
3466337132025-06-12 16:44:02233 days ago1749746642
0x8f8BccE4...9440D1e95
1 wei
3466337132025-06-12 16:44:02233 days ago1749746642
0x8f8BccE4...9440D1e95
1 wei
3444181082025-06-06 6:14:32239 days ago1749190472
0x8f8BccE4...9440D1e95
1 wei
3444181082025-06-06 6:14:32239 days ago1749190472
0x8f8BccE4...9440D1e95
1 wei
3443686832025-06-06 2:47:50240 days ago1749178070
0x8f8BccE4...9440D1e95
1 wei
3443686832025-06-06 2:47:50240 days ago1749178070
0x8f8BccE4...9440D1e95
1 wei
3419325362025-05-30 0:53:32247 days ago1748566412
0x8f8BccE4...9440D1e95
1 wei
3419325362025-05-30 0:53:32247 days ago1748566412
0x8f8BccE4...9440D1e95
1 wei
3419325312025-05-30 0:53:31247 days ago1748566411
0x8f8BccE4...9440D1e95
1 wei
3419325312025-05-30 0:53:31247 days ago1748566411
0x8f8BccE4...9440D1e95
1 wei
3418033212025-05-29 15:51:36247 days ago1748533896
0x8f8BccE4...9440D1e95
1 wei
3418033212025-05-29 15:51:36247 days ago1748533896
0x8f8BccE4...9440D1e95
1 wei
3393909662025-05-22 15:43:54254 days ago1747928634
0x8f8BccE4...9440D1e95
1 wei
3393909662025-05-22 15:43:54254 days ago1747928634
0x8f8BccE4...9440D1e95
1 wei
3393908352025-05-22 15:43:21254 days ago1747928601
0x8f8BccE4...9440D1e95
1 wei
3393908352025-05-22 15:43:21254 days ago1747928601
0x8f8BccE4...9440D1e95
1 wei
3382644552025-05-19 9:15:00257 days ago1747646100
0x8f8BccE4...9440D1e95
1 wei
3382644552025-05-19 9:15:00257 days ago1747646100
0x8f8BccE4...9440D1e95
1 wei
3300756772025-04-25 13:14:10281 days ago1745586850
0x8f8BccE4...9440D1e95
1 wei
3300756772025-04-25 13:14:10281 days ago1745586850
0x8f8BccE4...9440D1e95
1 wei
3300755612025-04-25 13:13:41281 days ago1745586821
0x8f8BccE4...9440D1e95
1 wei
3300755612025-04-25 13:13:41281 days ago1745586821
0x8f8BccE4...9440D1e95
1 wei
3300753592025-04-25 13:12:51281 days ago1745586771
0x8f8BccE4...9440D1e95
1 wei
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PerpetualManagerProxy

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 10000000 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import "@openzeppelin/contracts/proxy/Proxy.sol";
import "./PerpStorage.sol";
import "../interfaces/ILibraryEvents.sol";
import "../interfaces/IFunctionList.sol";
import "../../libraries/EnumerableBytes4Set.sol";
import "../../libraries/Utils.sol";

contract PerpetualManagerProxy is PerpStorage, Proxy, ILibraryEvents {
    using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set;

    bytes32 private constant KEY_IMPLEMENTATION = keccak256("key.implementation");
    bytes32 private constant KEY_OWNER = keccak256("key.proxy.owner");

    event ProxyOwnershipTransferred(address indexed _oldOwner, address indexed _newOwner);
    event ImplementationChanged(
        bytes4 _sig,
        address indexed _oldImplementation,
        address indexed _newImplementation
    );

    /**
     * @notice Set sender as an owner.
     */
    constructor() {
        _setProxyOwner(msg.sender);
    }

    /**
     * @notice Throw error if called not by an owner.
     */
    modifier onlyProxyOwner() {
        require(msg.sender == getProxyOwner(), "Proxy:access denied");
        _;
    }

    function _implementation() internal view override returns (address) {
        address implementation = _getImplementation(msg.sig);
        require(implementation != address(0), "Proxy:Implementation not found");
        return implementation;
    }

    function getImplementation(bytes4 _sig) external view returns (address) {
        return _getImplementation(_sig);
    }

    function _getImplementation(bytes4 _sig) internal view returns (address) {
        bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));
        address implementation;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            implementation := sload(key)
        }
        return implementation;
    }

    /// @dev to delete module deploy a dummy module with the same name in getFunctionList() as being deleted
    /// it will remove all previous implementation functions
    function setImplementation(address _impl) external onlyProxyOwner {
        _setImplementation(_impl, false);
    }

    ///@dev allows replacement of functions from other modules. Use only if you realize consequences.
    function setImplementationCrossModules(address _impl) external onlyProxyOwner {
        _setImplementation(_impl, true);
    }

    ///@param _impl module address
    ///@param replaceOtherModulesFuncs allow to replace functions of other modules, use with caution
    function _setImplementation(address _impl, bool replaceOtherModulesFuncs) internal {
        require(_impl != address(0), "invalid implementation address");

        (bytes4[] memory functions, bytes32 moduleName) = IFunctionList(_impl).getFunctionList();

        require(moduleName != bytes32(0), "Module name cannot be empty");

        EnumerableBytes4Set.Bytes4Set
            storage moduleActiveFunctionsSet = moduleActiveFuncSignatureList[moduleName];
        bool moduleIsBeingUpdated = moduleActiveFunctionsSet.length() > 0;
        uint256 length = functions.length;
        for (uint256 i = 0; i < length; i++) {
            bytes4 funcSig = functions[i];
            if (!moduleActiveFunctionsSet.contains(functions[i])) {
                // if the function registered with another module
                address anotherModuleImplAddress = _getImplementation(funcSig);
                if (anotherModuleImplAddress != address(0)) {
                    require(replaceOtherModulesFuncs, "cant replace modules funcs");
                    moduleActiveFuncSignatureList[
                        moduleAddressToModuleName[anotherModuleImplAddress]
                    ].removeBytes4(funcSig);
                }
                moduleActiveFunctionsSet.addBytes4(functions[i]);
            }
            _setImplementation(functions[i], _impl);
        }

        /// remove functions of the previous module version
        if (moduleIsBeingUpdated) {
            bytes4[] memory moduleActiveFuncsArray = moduleActiveFunctionsSet.enumerate(
                0,
                moduleActiveFunctionsSet.length()
            );
            length = moduleActiveFuncsArray.length;
            for (uint256 i; i < length; i++) {
                bytes4 funcSig = moduleActiveFuncsArray[i];
                if (_getImplementation(funcSig) != _impl) {
                    _setImplementation(funcSig, address(0));
                    moduleActiveFunctionsSet.removeBytes4(funcSig);
                }
            }
        }

        moduleNameToAddress[moduleName] = _impl;
        moduleAddressToModuleName[_impl] = moduleName;
    }

    function getModuleImplementationAddress(string calldata _moduleName)
        external
        view
        returns (address)
    {
        return moduleNameToAddress[Utils.stringToBytes32(_moduleName)];
    }

    function _setImplementation(bytes4 _sig, address _impl) internal {
        _checkClashing(_sig);
        emit ImplementationChanged(_sig, _getImplementation(_sig), _impl);

        bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));
        // solhint-disable-next-line no-inline-assembly
        assembly {
            sstore(key, _impl)
        }
    }

    /**
     * @notice Set address of the owner.
     * @param _owner Address of the owner.
     * */
    function setProxyOwner(address _owner) external onlyProxyOwner {
        _setProxyOwner(_owner);
    }

    function _setProxyOwner(address _owner) internal {
        require(_owner != address(0), "invalid proxy owner address");
        emit ProxyOwnershipTransferred(getProxyOwner(), _owner);

        bytes32 key = KEY_OWNER;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            sstore(key, _owner)
        }
    }

    /**
     * @notice Return address of the owner.
     * @return _owner Address of the owner.
     */
    function getProxyOwner() public view returns (address _owner) {
        bytes32 key = KEY_OWNER;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            _owner := sload(key)
        }
    }

    function _checkClashing(bytes4 _sig) internal pure {
        bytes4[] memory functionList = _getFunctionList();
        uint256 length = functionList.length;
        for (uint256 i = 0; i < length; i++) {
            require(_sig != functionList[i], "function id already exists");
        }
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function pause() external whenNotPaused onlyMaintainer {
        _pause();
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function unpause() external virtual whenPaused onlyMaintainer {
        _unpause();
    }

    function _getFunctionList() internal pure returns (bytes4[] memory) {
        bytes4[] memory functionList = new bytes4[](8);
        functionList[0] = this.getImplementation.selector;
        functionList[1] = this.setImplementation.selector;
        functionList[2] = this.setImplementationCrossModules.selector;
        functionList[3] = this.getModuleImplementationAddress.selector;
        functionList[4] = this.setProxyOwner.selector;
        functionList[5] = this.getProxyOwner.selector;
        functionList[6] = this.pause.selector;
        functionList[7] = this.unpause.selector;
        return functionList;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)

pragma solidity ^0.8.0;

/**
 * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
 * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
 * be specified by overriding the virtual {_implementation} function.
 *
 * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
 * different contract through the {_delegate} function.
 *
 * The success and return data of the delegated call will be returned back to the caller of the proxy.
 */
abstract contract Proxy {
    /**
     * @dev Delegates the current call to `implementation`.
     *
     * This function does not return to its internal call site, it will return directly to the external caller.
     */
    function _delegate(address implementation) internal virtual {
        assembly {
            // Copy msg.data. We take full control of memory in this inline assembly
            // block because it will not return to Solidity code. We overwrite the
            // Solidity scratch pad at memory position 0.
            calldatacopy(0, 0, calldatasize())

            // Call the implementation.
            // out and outsize are 0 because we don't know the size yet.
            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)

            // Copy the returned data.
            returndatacopy(0, 0, returndatasize())

            switch result
            // delegatecall returns 0 on error.
            case 0 {
                revert(0, returndatasize())
            }
            default {
                return(0, returndatasize())
            }
        }
    }

    /**
     * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
     * and {_fallback} should delegate.
     */
    function _implementation() internal view virtual returns (address);

    /**
     * @dev Delegates the current call to the address returned by `_implementation()`.
     *
     * This function does not return to its internal call site, it will return directly to the external caller.
     */
    function _fallback() internal virtual {
        _beforeFallback();
        _delegate(_implementation());
    }

    /**
     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
     * function in the contract matches the call data.
     */
    fallback() external payable virtual {
        _fallback();
    }

    /**
     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
     * is empty.
     */
    receive() external payable virtual {
        _fallback();
    }

    /**
     * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
     * call, or as part of the Solidity `fallback` or `receive` functions.
     *
     * If overridden should call `super._beforeFallback()`.
     */
    function _beforeFallback() internal virtual {}
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)
// D8X, 2022

pragma solidity 0.8.21;

/**
 * This is a modified version of the OpenZeppelin ownable contract
 * Modifications
 * - instead of an owner, we have two actors: maintainer and governance
 * - maintainer can have certain priviledges but cannot transfer maintainer mandate
 * - governance can exchange maintainer and exchange itself
 * - renounceOwnership is removed
 *
 *
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Maintainable {
    address private _maintainer;
    address private _governance;

    event MaintainerTransferred(address indexed previousMaintainer, address indexed newMaintainer);
    event GovernanceTransferred(address indexed previousGovernance, address indexed newGovernance);

    /**
     * @dev Initializes the contract setting the deployer as the initial maintainer.
     */
    constructor() {
        _transferMaintainer(msg.sender);
        _transferGovernance(msg.sender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function maintainer() public view virtual returns (address) {
        return _maintainer;
    }

    /**
     * @dev Returns the address of the governance.
     */
    function governance() public view virtual returns (address) {
        return _governance;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyMaintainer() {
        require(maintainer() == msg.sender, "only maintainer");
        _;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyGovernance() {
        require(governance() == msg.sender, "only governance");
        _;
    }

    /**
     * @dev Transfers maintainer mandate of the contract to a new account (`newMaintainer`).
     * Can only be called by the governance.
     */
    function transferMaintainer(address newMaintainer) public virtual {
        require(msg.sender == _governance, "only governance");
        require(newMaintainer != address(0), "zero address");
        _transferMaintainer(newMaintainer);
    }

    /**
     * @dev Transfers governance mandate of the contract to a new account (`newGovernance`).
     * Can only be called by the governance.
     */
    function transferGovernance(address newGovernance) public virtual {
        require(msg.sender == _governance, "only governance");
        require(newGovernance != address(0), "zero address");
        _transferGovernance(newGovernance);
    }

    /**
     * @dev Transfers maintainer of the contract to a new account (`newMaintainer`).
     * Internal function without access restriction.
     */
    function _transferMaintainer(address newMaintainer) internal virtual {
        address oldM = _maintainer;
        _maintainer = newMaintainer;
        emit MaintainerTransferred(oldM, newMaintainer);
    }

    /**
     * @dev Transfers governance of the contract to a new account (`newGovernance`).
     * Internal function without access restriction.
     */
    function _transferGovernance(address newGovernance) internal virtual {
        address oldG = _governance;
        _governance = newGovernance;
        emit GovernanceTransferred(oldG, newGovernance);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.21;

interface IShareTokenFactory {
    function createShareToken(uint8 _poolId, address _marginTokenAddr) external returns (address);
}

// SPDX-License-Identifier: BSD-4-Clause
/*
 * ABDK Math 64.64 Smart Contract Library.  Copyright © 2019 by ABDK Consulting.
 * Author: Mikhail Vladimirov <[email protected]>
 */
pragma solidity 0.8.21;

/**
 * Smart contract library of mathematical functions operating with signed
 * 64.64-bit fixed point numbers.  Signed 64.64-bit fixed point number is
 * basically a simple fraction whose numerator is signed 128-bit integer and
 * denominator is 2^64.  As long as denominator is always the same, there is no
 * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are
 * represented by int128 type holding only the numerator.
 */
library ABDKMath64x64 {
    /*
     * Minimum value signed 64.64-bit fixed point number may have.
     */
    int128 private constant MIN_64x64 = -0x80000000000000000000000000000000;

    /*
     * Maximum value signed 64.64-bit fixed point number may have.
     */
    int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

    /**
     * Convert signed 256-bit integer number into signed 64.64-bit fixed point
     * number.  Revert on overflow.
     *
     * @param x signed 256-bit integer number
     * @return signed 64.64-bit fixed point number
     */
    function fromInt(int256 x) internal pure returns (int128) {
        require(x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF, "ABDK.fromInt");
        return int128(x << 64);
    }

    /**
     * Convert signed 64.64 fixed point number into signed 64-bit integer number
     * rounding down.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64-bit integer number
     */
    function toInt(int128 x) internal pure returns (int64) {
        return int64(x >> 64);
    }

    /**
     * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point
     * number.  Revert on overflow.
     *
     * @param x unsigned 256-bit integer number
     * @return signed 64.64-bit fixed point number
     */
    function fromUInt(uint256 x) internal pure returns (int128) {
        require(x <= 0x7FFFFFFFFFFFFFFF, "ABDK.fromUInt");
        return int128(int256(x << 64));
    }

    /**
     * Convert signed 64.64 fixed point number into unsigned 64-bit integer
     * number rounding down.  Revert on underflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @return unsigned 64-bit integer number
     */
    function toUInt(int128 x) internal pure returns (uint64) {
        require(x >= 0, "ABDK.toUInt");
        return uint64(uint128(x >> 64));
    }

    /**
     * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point
     * number rounding down.  Revert on overflow.
     *
     * @param x signed 128.128-bin fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function from128x128(int256 x) internal pure returns (int128) {
        int256 result = x >> 64;
        require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.from128x128");
        return int128(result);
    }

    /**
     * Convert signed 64.64 fixed point number into signed 128.128 fixed point
     * number.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 128.128 fixed point number
     */
    function to128x128(int128 x) internal pure returns (int256) {
        return int256(x) << 64;
    }

    /**
     * Calculate x + y.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @param y signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function add(int128 x, int128 y) internal pure returns (int128) {
        int256 result = int256(x) + y;
        require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.add");
        return int128(result);
    }

    /**
     * Calculate x - y.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @param y signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function sub(int128 x, int128 y) internal pure returns (int128) {
        int256 result = int256(x) - y;
        require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.sub");
        return int128(result);
    }

    /**
     * Calculate x * y rounding down.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @param y signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function mul(int128 x, int128 y) internal pure returns (int128) {
        int256 result = (int256(x) * y) >> 64;
        require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.mul");
        return int128(result);
    }

    /**
     * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point
     * number and y is signed 256-bit integer number.  Revert on overflow.
     *
     * @param x signed 64.64 fixed point number
     * @param y signed 256-bit integer number
     * @return signed 256-bit integer number
     */
    function muli(int128 x, int256 y) internal pure returns (int256) {
        if (x == MIN_64x64) {
            require(
                y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF &&
                    y <= 0x1000000000000000000000000000000000000000000000000,
                "ABDK.muli-1"
            );
            return -y << 63;
        } else {
            bool negativeResult = false;
            if (x < 0) {
                x = -x;
                negativeResult = true;
            }
            if (y < 0) {
                y = -y;
                // We rely on overflow behavior here
                negativeResult = !negativeResult;
            }
            uint256 absoluteResult = mulu(x, uint256(y));
            if (negativeResult) {
                require(
                    absoluteResult <=
                        0x8000000000000000000000000000000000000000000000000000000000000000,
                    "ABDK.muli-2"
                );
                return -int256(absoluteResult);
                // We rely on overflow behavior here
            } else {
                require(
                    absoluteResult <=
                        0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
                    "ABDK.muli-3"
                );
                return int256(absoluteResult);
            }
        }
    }

    /**
     * Calculate x * y rounding down, where x is signed 64.64 fixed point number
     * and y is unsigned 256-bit integer number.  Revert on overflow.
     *
     * @param x signed 64.64 fixed point number
     * @param y unsigned 256-bit integer number
     * @return unsigned 256-bit integer number
     */
    function mulu(int128 x, uint256 y) internal pure returns (uint256) {
        if (y == 0) return 0;

        require(x >= 0, "ABDK.mulu-1");

        uint256 lo = (uint256(int256(x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64;
        uint256 hi = uint256(int256(x)) * (y >> 128);

        require(hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "ABDK.mulu-2");
        hi <<= 64;

        require(
            hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo,
            "ABDK.mulu-3"
        );
        return hi + lo;
    }

    /**
     * Calculate x / y rounding towards zero.  Revert on overflow or when y is
     * zero.
     *
     * @param x signed 64.64-bit fixed point number
     * @param y signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function div(int128 x, int128 y) internal pure returns (int128) {
        require(y != 0, "ABDK.div-1");
        int256 result = (int256(x) << 64) / y;
        require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.div-2");
        return int128(result);
    }

    /**
     * Calculate x / y rounding towards zero, where x and y are signed 256-bit
     * integer numbers.  Revert on overflow or when y is zero.
     *
     * @param x signed 256-bit integer number
     * @param y signed 256-bit integer number
     * @return signed 64.64-bit fixed point number
     */
    function divi(int256 x, int256 y) internal pure returns (int128) {
        require(y != 0, "ABDK.divi-1");

        bool negativeResult = false;
        if (x < 0) {
            x = -x;
            // We rely on overflow behavior here
            negativeResult = true;
        }
        if (y < 0) {
            y = -y;
            // We rely on overflow behavior here
            negativeResult = !negativeResult;
        }
        uint128 absoluteResult = divuu(uint256(x), uint256(y));
        if (negativeResult) {
            require(absoluteResult <= 0x80000000000000000000000000000000, "ABDK.divi-2");
            return -int128(absoluteResult);
            // We rely on overflow behavior here
        } else {
            require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "ABDK.divi-3");
            return int128(absoluteResult);
            // We rely on overflow behavior here
        }
    }

    /**
     * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
     * integer numbers.  Revert on overflow or when y is zero.
     *
     * @param x unsigned 256-bit integer number
     * @param y unsigned 256-bit integer number
     * @return signed 64.64-bit fixed point number
     */
    function divu(uint256 x, uint256 y) internal pure returns (int128) {
        require(y != 0, "ABDK.divu-1");
        uint128 result = divuu(x, y);
        require(result <= uint128(MAX_64x64), "ABDK.divu-2");
        return int128(result);
    }

    /**
     * Calculate -x.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function neg(int128 x) internal pure returns (int128) {
        require(x != MIN_64x64, "ABDK.neg");
        return -x;
    }

    /**
     * Calculate |x|.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function abs(int128 x) internal pure returns (int128) {
        require(x != MIN_64x64, "ABDK.abs");
        return x < 0 ? -x : x;
    }

    /**
     * Calculate 1 / x rounding towards zero.  Revert on overflow or when x is
     * zero.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function inv(int128 x) internal pure returns (int128) {
        require(x != 0, "ABDK.inv-1");
        int256 result = int256(0x100000000000000000000000000000000) / x;
        require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.inv-2");
        return int128(result);
    }

    /**
     * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down.
     *
     * @param x signed 64.64-bit fixed point number
     * @param y signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function avg(int128 x, int128 y) internal pure returns (int128) {
        return int128((int256(x) + int256(y)) >> 1);
    }

    /**
     * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down.
     * Revert on overflow or in case x * y is negative.
     *
     * @param x signed 64.64-bit fixed point number
     * @param y signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function gavg(int128 x, int128 y) internal pure returns (int128) {
        int256 m = int256(x) * int256(y);
        require(m >= 0, "ABDK.gavg-1");
        require(
            m < 0x4000000000000000000000000000000000000000000000000000000000000000,
            "ABDK.gavg-2"
        );
        return int128(sqrtu(uint256(m)));
    }

    /**
     * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number
     * and y is unsigned 256-bit integer number.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @param y uint256 value
     * @return signed 64.64-bit fixed point number
     */
    function pow(int128 x, uint256 y) internal pure returns (int128) {
        bool negative = x < 0 && y & 1 == 1;

        uint256 absX = uint128(x < 0 ? -x : x);
        uint256 absResult;
        absResult = 0x100000000000000000000000000000000;

        if (absX <= 0x10000000000000000) {
            absX <<= 63;
            while (y != 0) {
                if (y & 0x1 != 0) {
                    absResult = (absResult * absX) >> 127;
                }
                absX = (absX * absX) >> 127;

                if (y & 0x2 != 0) {
                    absResult = (absResult * absX) >> 127;
                }
                absX = (absX * absX) >> 127;

                if (y & 0x4 != 0) {
                    absResult = (absResult * absX) >> 127;
                }
                absX = (absX * absX) >> 127;

                if (y & 0x8 != 0) {
                    absResult = (absResult * absX) >> 127;
                }
                absX = (absX * absX) >> 127;

                y >>= 4;
            }

            absResult >>= 64;
        } else {
            uint256 absXShift = 63;
            if (absX < 0x1000000000000000000000000) {
                absX <<= 32;
                absXShift -= 32;
            }
            if (absX < 0x10000000000000000000000000000) {
                absX <<= 16;
                absXShift -= 16;
            }
            if (absX < 0x1000000000000000000000000000000) {
                absX <<= 8;
                absXShift -= 8;
            }
            if (absX < 0x10000000000000000000000000000000) {
                absX <<= 4;
                absXShift -= 4;
            }
            if (absX < 0x40000000000000000000000000000000) {
                absX <<= 2;
                absXShift -= 2;
            }
            if (absX < 0x80000000000000000000000000000000) {
                absX <<= 1;
                absXShift -= 1;
            }

            uint256 resultShift;
            while (y != 0) {
                require(absXShift < 64, "ABDK.pow-1");

                if (y & 0x1 != 0) {
                    absResult = (absResult * absX) >> 127;
                    resultShift += absXShift;
                    if (absResult > 0x100000000000000000000000000000000) {
                        absResult >>= 1;
                        resultShift += 1;
                    }
                }
                absX = (absX * absX) >> 127;
                absXShift <<= 1;
                if (absX >= 0x100000000000000000000000000000000) {
                    absX >>= 1;
                    absXShift += 1;
                }

                y >>= 1;
            }

            require(resultShift < 64, "ABDK.pow-2");
            absResult >>= 64 - resultShift;
        }
        int256 result = negative ? -int256(absResult) : int256(absResult);
        require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.pow-3");
        return int128(result);
    }

    /**
     * Calculate sqrt (x) rounding down.  Revert if x < 0.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function sqrt(int128 x) internal pure returns (int128) {
        require(x >= 0, "ABDK.sqrt");
        return int128(sqrtu(uint256(int256(x)) << 64));
    }

    /**
     * Calculate binary logarithm of x.  Revert if x <= 0.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function log_2(int128 x) internal pure returns (int128) {
        require(x > 0, "ABDK.log_2");

        int256 msb;
        int256 xc = x;
        if (xc >= 0x10000000000000000) {
            xc >>= 64;
            msb += 64;
        }
        if (xc >= 0x100000000) {
            xc >>= 32;
            msb += 32;
        }
        if (xc >= 0x10000) {
            xc >>= 16;
            msb += 16;
        }
        if (xc >= 0x100) {
            xc >>= 8;
            msb += 8;
        }
        if (xc >= 0x10) {
            xc >>= 4;
            msb += 4;
        }
        if (xc >= 0x4) {
            xc >>= 2;
            msb += 2;
        }
        if (xc >= 0x2) msb += 1;
        // No need to shift xc anymore

        int256 result = (msb - 64) << 64;
        uint256 ux = uint256(int256(x)) << uint256(127 - msb);
        for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) {
            ux *= ux;
            uint256 b = ux >> 255;
            ux >>= 127 + b;
            result += bit * int256(b);
        }

        return int128(result);
    }

    /**
     * Calculate natural logarithm of x.  Revert if x <= 0.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function ln(int128 x) internal pure returns (int128) {
        unchecked {
            require(x > 0, "ABDK.ln");

            return
                int128(
                    int256((uint256(int256(log_2(x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF) >> 128)
                );
        }
    }

    /**
     * Calculate binary exponent of x.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function exp_2(int128 x) internal pure returns (int128) {
        require(x < 0x400000000000000000, "ABDK.exp_2-1");
        // Overflow

        if (x < -0x400000000000000000) return 0;
        // Underflow

        uint256 result = 0x80000000000000000000000000000000;

        if (x & 0x8000000000000000 > 0)
            result = (result * 0x16A09E667F3BCC908B2FB1366EA957D3E) >> 128;
        if (x & 0x4000000000000000 > 0)
            result = (result * 0x1306FE0A31B7152DE8D5A46305C85EDEC) >> 128;
        if (x & 0x2000000000000000 > 0)
            result = (result * 0x1172B83C7D517ADCDF7C8C50EB14A791F) >> 128;
        if (x & 0x1000000000000000 > 0)
            result = (result * 0x10B5586CF9890F6298B92B71842A98363) >> 128;
        if (x & 0x800000000000000 > 0)
            result = (result * 0x1059B0D31585743AE7C548EB68CA417FD) >> 128;
        if (x & 0x400000000000000 > 0)
            result = (result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8) >> 128;
        if (x & 0x200000000000000 > 0)
            result = (result * 0x10163DA9FB33356D84A66AE336DCDFA3F) >> 128;
        if (x & 0x100000000000000 > 0)
            result = (result * 0x100B1AFA5ABCBED6129AB13EC11DC9543) >> 128;
        if (x & 0x80000000000000 > 0)
            result = (result * 0x10058C86DA1C09EA1FF19D294CF2F679B) >> 128;
        if (x & 0x40000000000000 > 0)
            result = (result * 0x1002C605E2E8CEC506D21BFC89A23A00F) >> 128;
        if (x & 0x20000000000000 > 0)
            result = (result * 0x100162F3904051FA128BCA9C55C31E5DF) >> 128;
        if (x & 0x10000000000000 > 0)
            result = (result * 0x1000B175EFFDC76BA38E31671CA939725) >> 128;
        if (x & 0x8000000000000 > 0)
            result = (result * 0x100058BA01FB9F96D6CACD4B180917C3D) >> 128;
        if (x & 0x4000000000000 > 0)
            result = (result * 0x10002C5CC37DA9491D0985C348C68E7B3) >> 128;
        if (x & 0x2000000000000 > 0)
            result = (result * 0x1000162E525EE054754457D5995292026) >> 128;
        if (x & 0x1000000000000 > 0)
            result = (result * 0x10000B17255775C040618BF4A4ADE83FC) >> 128;
        if (x & 0x800000000000 > 0) result = (result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB) >> 128;
        if (x & 0x400000000000 > 0) result = (result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9) >> 128;
        if (x & 0x200000000000 > 0) result = (result * 0x10000162E43F4F831060E02D839A9D16D) >> 128;
        if (x & 0x100000000000 > 0) result = (result * 0x100000B1721BCFC99D9F890EA06911763) >> 128;
        if (x & 0x80000000000 > 0) result = (result * 0x10000058B90CF1E6D97F9CA14DBCC1628) >> 128;
        if (x & 0x40000000000 > 0) result = (result * 0x1000002C5C863B73F016468F6BAC5CA2B) >> 128;
        if (x & 0x20000000000 > 0) result = (result * 0x100000162E430E5A18F6119E3C02282A5) >> 128;
        if (x & 0x10000000000 > 0) result = (result * 0x1000000B1721835514B86E6D96EFD1BFE) >> 128;
        if (x & 0x8000000000 > 0) result = (result * 0x100000058B90C0B48C6BE5DF846C5B2EF) >> 128;
        if (x & 0x4000000000 > 0) result = (result * 0x10000002C5C8601CC6B9E94213C72737A) >> 128;
        if (x & 0x2000000000 > 0) result = (result * 0x1000000162E42FFF037DF38AA2B219F06) >> 128;
        if (x & 0x1000000000 > 0) result = (result * 0x10000000B17217FBA9C739AA5819F44F9) >> 128;
        if (x & 0x800000000 > 0) result = (result * 0x1000000058B90BFCDEE5ACD3C1CEDC823) >> 128;
        if (x & 0x400000000 > 0) result = (result * 0x100000002C5C85FE31F35A6A30DA1BE50) >> 128;
        if (x & 0x200000000 > 0) result = (result * 0x10000000162E42FF0999CE3541B9FFFCF) >> 128;
        if (x & 0x100000000 > 0) result = (result * 0x100000000B17217F80F4EF5AADDA45554) >> 128;
        if (x & 0x80000000 > 0) result = (result * 0x10000000058B90BFBF8479BD5A81B51AD) >> 128;
        if (x & 0x40000000 > 0) result = (result * 0x1000000002C5C85FDF84BD62AE30A74CC) >> 128;
        if (x & 0x20000000 > 0) result = (result * 0x100000000162E42FEFB2FED257559BDAA) >> 128;
        if (x & 0x10000000 > 0) result = (result * 0x1000000000B17217F7D5A7716BBA4A9AE) >> 128;
        if (x & 0x8000000 > 0) result = (result * 0x100000000058B90BFBE9DDBAC5E109CCE) >> 128;
        if (x & 0x4000000 > 0) result = (result * 0x10000000002C5C85FDF4B15DE6F17EB0D) >> 128;
        if (x & 0x2000000 > 0) result = (result * 0x1000000000162E42FEFA494F1478FDE05) >> 128;
        if (x & 0x1000000 > 0) result = (result * 0x10000000000B17217F7D20CF927C8E94C) >> 128;
        if (x & 0x800000 > 0) result = (result * 0x1000000000058B90BFBE8F71CB4E4B33D) >> 128;
        if (x & 0x400000 > 0) result = (result * 0x100000000002C5C85FDF477B662B26945) >> 128;
        if (x & 0x200000 > 0) result = (result * 0x10000000000162E42FEFA3AE53369388C) >> 128;
        if (x & 0x100000 > 0) result = (result * 0x100000000000B17217F7D1D351A389D40) >> 128;
        if (x & 0x80000 > 0) result = (result * 0x10000000000058B90BFBE8E8B2D3D4EDE) >> 128;
        if (x & 0x40000 > 0) result = (result * 0x1000000000002C5C85FDF4741BEA6E77E) >> 128;
        if (x & 0x20000 > 0) result = (result * 0x100000000000162E42FEFA39FE95583C2) >> 128;
        if (x & 0x10000 > 0) result = (result * 0x1000000000000B17217F7D1CFB72B45E1) >> 128;
        if (x & 0x8000 > 0) result = (result * 0x100000000000058B90BFBE8E7CC35C3F0) >> 128;
        if (x & 0x4000 > 0) result = (result * 0x10000000000002C5C85FDF473E242EA38) >> 128;
        if (x & 0x2000 > 0) result = (result * 0x1000000000000162E42FEFA39F02B772C) >> 128;
        if (x & 0x1000 > 0) result = (result * 0x10000000000000B17217F7D1CF7D83C1A) >> 128;
        if (x & 0x800 > 0) result = (result * 0x1000000000000058B90BFBE8E7BDCBE2E) >> 128;
        if (x & 0x400 > 0) result = (result * 0x100000000000002C5C85FDF473DEA871F) >> 128;
        if (x & 0x200 > 0) result = (result * 0x10000000000000162E42FEFA39EF44D91) >> 128;
        if (x & 0x100 > 0) result = (result * 0x100000000000000B17217F7D1CF79E949) >> 128;
        if (x & 0x80 > 0) result = (result * 0x10000000000000058B90BFBE8E7BCE544) >> 128;
        if (x & 0x40 > 0) result = (result * 0x1000000000000002C5C85FDF473DE6ECA) >> 128;
        if (x & 0x20 > 0) result = (result * 0x100000000000000162E42FEFA39EF366F) >> 128;
        if (x & 0x10 > 0) result = (result * 0x1000000000000000B17217F7D1CF79AFA) >> 128;
        if (x & 0x8 > 0) result = (result * 0x100000000000000058B90BFBE8E7BCD6D) >> 128;
        if (x & 0x4 > 0) result = (result * 0x10000000000000002C5C85FDF473DE6B2) >> 128;
        if (x & 0x2 > 0) result = (result * 0x1000000000000000162E42FEFA39EF358) >> 128;
        if (x & 0x1 > 0) result = (result * 0x10000000000000000B17217F7D1CF79AB) >> 128;

        result >>= uint256(int256(63 - (x >> 64)));
        require(result <= uint256(int256(MAX_64x64)), "ABDK.exp_2-2");

        return int128(int256(result));
    }

    /**
     * Calculate natural exponent of x.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function exp(int128 x) internal pure returns (int128) {
        require(x < 0x400000000000000000, "ABDK.exp");
        // Overflow

        if (x < -0x400000000000000000) return 0;
        // Underflow

        return exp_2(int128((int256(x) * 0x171547652B82FE1777D0FFDA0D23A7D12) >> 128));
    }

    /**
     * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
     * integer numbers.  Revert on overflow or when y is zero.
     *
     * @param x unsigned 256-bit integer number
     * @param y unsigned 256-bit integer number
     * @return unsigned 64.64-bit fixed point number
     */
    function divuu(uint256 x, uint256 y) private pure returns (uint128) {
        require(y != 0, "ABDK.divuu-1");

        uint256 result;

        if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) result = (x << 64) / y;
        else {
            uint256 msb = 192;
            uint256 xc = x >> 192;
            if (xc >= 0x100000000) {
                xc >>= 32;
                msb += 32;
            }
            if (xc >= 0x10000) {
                xc >>= 16;
                msb += 16;
            }
            if (xc >= 0x100) {
                xc >>= 8;
                msb += 8;
            }
            if (xc >= 0x10) {
                xc >>= 4;
                msb += 4;
            }
            if (xc >= 0x4) {
                xc >>= 2;
                msb += 2;
            }
            if (xc >= 0x2) msb += 1;
            // No need to shift xc anymore

            result = (x << (255 - msb)) / (((y - 1) >> (msb - 191)) + 1);
            require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "ABDK.divuu-2");

            uint256 hi = result * (y >> 128);
            uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);

            uint256 xh = x >> 192;
            uint256 xl = x << 64;

            if (xl < lo) xh -= 1;
            xl -= lo;
            // We rely on overflow behavior here
            lo = hi << 128;
            if (xl < lo) xh -= 1;
            xl -= lo;
            // We rely on overflow behavior here

            assert(xh == hi >> 128);

            result += xl / y;
        }

        require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "ABDK.divuu-3");
        return uint128(result);
    }

    /**
     * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer
     * number.
     *
     * @param x unsigned 256-bit integer number
     * @return unsigned 128-bit integer number
     */
    function sqrtu(uint256 x) private pure returns (uint128) {
        if (x == 0) return 0;
        else {
            uint256 xx = x;
            uint256 r = 1;
            if (xx >= 0x100000000000000000000000000000000) {
                xx >>= 128;
                r <<= 64;
            }
            if (xx >= 0x10000000000000000) {
                xx >>= 64;
                r <<= 32;
            }
            if (xx >= 0x100000000) {
                xx >>= 32;
                r <<= 16;
            }
            if (xx >= 0x10000) {
                xx >>= 16;
                r <<= 8;
            }
            if (xx >= 0x100) {
                xx >>= 8;
                r <<= 4;
            }
            if (xx >= 0x10) {
                xx >>= 4;
                r <<= 2;
            }
            if (xx >= 0x8) {
                r <<= 1;
            }
            r = (r + x / r) >> 1;
            r = (r + x / r) >> 1;
            r = (r + x / r) >> 1;
            r = (r + x / r) >> 1;
            r = (r + x / r) >> 1;
            r = (r + x / r) >> 1;
            r = (r + x / r) >> 1;
            // Seven iterations should be enough
            uint256 r1 = x / r;
            return uint128(r < r1 ? r : r1);
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import "./ABDKMath64x64.sol";

library ConverterDec18 {
    using ABDKMath64x64 for int128;
    /*
     * Minimum value signed 64.64-bit fixed point number may have.
     */
    int128 private constant MIN_64x64 = -0x80000000000000000000000000000000;

    /*
     * Maximum value signed 64.64-bit fixed point number may have.
     */
    int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

    int256 private constant DECIMALS = 10**18;

    int128 private constant ONE_64x64 = 0x010000000000000000;

    int128 public constant HALF_TBPS = 92233720368548; //1e-5 * 0.5 * 2**64

    // convert tenth of basis point to dec 18:
    uint256 public constant TBPSTODEC18 = 0x9184e72a000; // hex(10^18 * 10^-5)=(10^13)
    // convert tenth of basis point to ABDK 64x64:
    int128 public constant TBPSTOABDK = 0xa7c5ac471b48; // hex(2^64 * 10^-5)
    // convert two-digit integer reprentation to ABDK
    int128 public constant TDRTOABDK = 0x28f5c28f5c28f5c; // hex(2^64 * 10^-2)

    function tbpsToDec18(uint16 Vtbps) internal pure returns (uint256) {
        return TBPSTODEC18 * uint256(Vtbps);
    }

    function tbpsToABDK(uint16 Vtbps) internal pure returns (int128) {
        return int128(uint128(TBPSTOABDK) * uint128(Vtbps));
    }

    function TDRToABDK(uint16 V2Tdr) internal pure returns (int128) {
        return int128(uint128(TDRTOABDK) * uint128(V2Tdr));
    }

    function ABDKToTbps(int128 Vabdk) internal pure returns (uint16) {
        // add 0.5 * 1e-5 to ensure correct rounding to tenth of bps
        return uint16(uint128(Vabdk.add(HALF_TBPS) / TBPSTOABDK));
    }

    function fromDec18(int256 x) internal pure returns (int128) {
        int256 result = (x * ONE_64x64) / DECIMALS;
        require(x >= MIN_64x64 && x <= MAX_64x64, "result out of range");
        return int128(result);
    }

    function toDec18(int128 x) internal pure returns (int256) {
        return (int256(x) * DECIMALS) / ONE_64x64;
    }

    function toUDec18(int128 x) internal pure returns (uint256) {
        require(x >= 0, "negative value");
        return uint256(toDec18(x));
    }

    function toUDecN(int128 x, uint8 decimals) internal pure returns (uint256) {
        require(x >= 0, "negative value");
        return uint256((int256(x) * int256(10**decimals)) / ONE_64x64);
    }

    function fromDecN(int256 x, uint8 decimals) internal pure returns (int128) {
        int256 result = (x * ONE_64x64) / int256(10**decimals);
        require(x >= MIN_64x64 && x <= MAX_64x64, "result out of range");
        return int128(result);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.21;

/**
 * @title Library for managing loan sets.
 *
 * @notice Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * Include with `using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set;`.
 * */
library EnumerableBytes4Set {
    struct Bytes4Set {
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes4 => uint256) index;
        bytes4[] values;
    }

    /**
     * @notice Add a value to a set. O(1).
     *
     * @param set The set of values.
     * @param value The new value to add.
     *
     * @return False if the value was already in the set.
     */
    function addBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {
        if (!contains(set, value)) {
            set.values.push(value);
            set.index[value] = set.values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @notice Remove a value from a set. O(1).
     *
     * @param set The set of values.
     * @param value The value to remove.
     *
     * @return False if the value was not present in the set.
     */
    function removeBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {
        if (contains(set, value)) {
            uint256 toDeleteIndex = set.index[value] - 1;
            uint256 lastIndex = set.values.length - 1;

            /// If the element we're deleting is the last one,
            /// we can just remove it without doing a swap.
            if (lastIndex != toDeleteIndex) {
                bytes4 lastValue = set.values[lastIndex];

                /// Move the last value to the index where the deleted value is.
                set.values[toDeleteIndex] = lastValue;

                /// Update the index for the moved value.
                set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based
            }

            /// Delete the index entry for the deleted value.
            delete set.index[value];

            /// Delete the old entry for the moved value.
            set.values.pop();

            return true;
        } else {
            return false;
        }
    }

    /**
     * @notice Find out whether a value exists in the set.
     *
     * @param set The set of values.
     * @param value The value to find.
     *
     * @return True if the value is in the set. O(1).
     */
    function contains(Bytes4Set storage set, bytes4 value) internal view returns (bool) {
        return set.index[value] != 0;
    }

    /**
     * @notice Get all set values.
     *
     * @param set The set of values.
     * @param start The offset of the returning set.
     * @param count The limit of number of values to return.
     *
     * @return output An array with all values in the set. O(N).
     *
     * @dev Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * WARNING: This function may run out of gas on large sets: use {length} and
     * {get} instead in these cases.
     */
    function enumerate(
        Bytes4Set storage set,
        uint256 start,
        uint256 count
    ) internal view returns (bytes4[] memory output) {
        uint256 end = start + count;
        require(end >= start, "addition overflow");
        end = set.values.length < end ? set.values.length : end;
        if (end == 0 || start >= end) {
            return output;
        }

        output = new bytes4[](end - start);
        for (uint256 i; i < end - start; i++) {
            output[i] = set.values[i + start];
        }
        return output;
    }

    /**
     * @notice Get the legth of the set.
     *
     * @param set The set of values.
     *
     * @return the number of elements on the set. O(1).
     */
    function length(Bytes4Set storage set) internal view returns (uint256) {
        return set.values.length;
    }

    /**
     * @notice Get an item from the set by its index.
     *
     * @dev Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     *
     * @param set The set of values.
     * @param index The index of the value to return.
     *
     * @return the element stored at position `index` in the set. O(1).
     */
    function get(Bytes4Set storage set, uint256 index) internal view returns (bytes4) {
        return set.values[index];
    }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.21;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 */
library EnumerableSetUpgradeable {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            bytes32 lastvalue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        require(set._values.length > index, "EnumerableSet: idx out of bounds");
        return set._values[index];
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    function enumerate(
        AddressSet storage set,
        uint256 start,
        uint256 count
    ) internal view returns (address[] memory output) {
        uint256 end = start + count;
        require(end >= start, "addition overflow");
        uint256 len = length(set);
        end = len < end ? len : end;
        if (end == 0 || start >= end) {
            return output;
        }

        output = new address[](end - start);
        for (uint256 i; i < end - start; i++) {
            output[i] = at(set, i + start);
        }
        return output;
    }

    function enumerateAll(AddressSet storage set) internal view returns (address[] memory output) {
        return enumerate(set, 0, length(set));
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.21;

library Utils {
    function stringToBytes32(string memory source) internal pure returns (bytes32 result) {
        bytes memory tempEmptyStringTest = bytes(source);
        if (tempEmptyStringTest.length == 0) {
            return 0x0;
        }

        assembly {
            result := mload(add(source, 32))
        }
    }
}

File 14 of 19 : PerpStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/security/Pausable.sol";

import "../../interface/IShareTokenFactory.sol";
import "../../libraries/ABDKMath64x64.sol";
import "./../functions/AMMPerpLogic.sol";
import "../../libraries/EnumerableSetUpgradeable.sol";
import "../../libraries/EnumerableBytes4Set.sol";
import "../../governance/Maintainable.sol";

/* solhint-disable max-states-count */
contract PerpStorage is Maintainable, Pausable, ReentrancyGuard {
    using ABDKMath64x64 for int128;
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
    using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set; // enumerable map of bytes4 or addresses
    /**
     * @notice  Perpetual state:
     *          - INVALID:      Uninitialized or not non-existent perpetual.
     *          - INITIALIZING: Only when LiquidityPoolData.isRunning == false. Traders cannot perform operations.
     *          - NORMAL:       Full functional state. Traders are able to perform all operations.
     *          - EMERGENCY:    Perpetual is unsafe and the perpetual needs to be settled.
     *          - SETTLE:       Perpetual ready to be settled
     *          - CLEARED:      All margin accounts are cleared. Traders can withdraw remaining margin balance.
     */
    enum PerpetualState {
        INVALID,
        INITIALIZING,
        NORMAL,
        EMERGENCY,
        SETTLE,
        CLEARED
    }

    // margin and liquidity pool are held in 'collateral currency' which can be either of
    // quote currency, base currency, or quanto currency
    // solhint-disable-next-line const-name-snakecase
    int128 internal constant ONE_64x64 = 0x10000000000000000; // 2^64
    int128 internal constant FUNDING_INTERVAL_SEC = 0x70800000000000000000; //3600 * 8 * 0x10000000000000000 = 8h in seconds scaled by 2^64 for ABDKMath64x64
    int128 internal constant MIN_NUM_LOTS_PER_POSITION = 0x0a0000000000000000; // 10, minimal position size in number of lots
    uint8 internal constant MASK_ORDER_CANCELLED = 0x1;
    uint8 internal constant MASK_ORDER_EXECUTED = 0x2;
    // at target, 1% of missing amount is transferred
    // at every rebalance
    uint8 internal iPoolCount;
    // delay required for trades to mitigate oracle front-running in seconds
    uint8 internal iTradeDelaySec;
    address internal ammPerpLogic;

    IShareTokenFactory internal shareTokenFactory;

    //pool id (incremental index, starts from 1) => pool data
    mapping(uint8 => LiquidityPoolData) internal liquidityPools;

    //perpetual id  => pool id
    mapping(uint24 => uint8) internal perpetualPoolIds;

    address internal orderBookFactory;

    /**
     * @notice  Data structure to store oracle price data.
     */
    struct PriceTimeData {
        int128 fPrice;
        uint64 time;
    }

    /**
     * @notice  Data structure to store user margin information.
     */
    struct MarginAccount {
        int128 fLockedInValueQC; // unrealized value locked-in when trade occurs
        int128 fCashCC; // cash in collateral currency (base, quote, or quanto)
        int128 fPositionBC; // position in base currency (e.g., 1 BTC for BTCUSD)
        int128 fUnitAccumulatedFundingStart; // accumulated funding rate
    }

    /**
     * @notice  Store information for a given perpetual market.
     */
    struct PerpetualData {
        // ------ 0
        uint8 poolId;
        uint24 id;
        int32 fInitialMarginRate; //parameter: initial margin
        int32 fSigma2; // parameter: volatility of base-quote pair
        uint32 iLastFundingTime; //timestamp since last funding rate payment
        int32 fDFCoverNRate; // parameter: cover-n rule for default fund. E.g., fDFCoverNRate=0.05 -> we try to cover 5% of active accounts with default fund
        int32 fMaintenanceMarginRate; // parameter: maintenance margin
        PerpetualState state; // Perpetual AMM state
        AMMPerpLogic.CollateralCurrency eCollateralCurrency; //parameter: in what currency is the collateral held?
        // uint16 minimalSpreadTbps; //parameter: minimal spread between long and short perpetual price
        // ------ 1
        bytes4 S2BaseCCY; //base currency of S2
        bytes4 S2QuoteCCY; //quote currency of S2
        uint16 incentiveSpreadTbps; //parameter: maximum spread added to the PD
        uint16 minimalSpreadTbps; //parameter: minimal spread between long and short perpetual price
        bytes4 S3BaseCCY; //base currency of S3
        bytes4 S3QuoteCCY; //quote currency of S3
        int32 fSigma3; // parameter: volatility of quanto-quote pair
        int32 fRho23; // parameter: correlation of quanto/base returns
        uint16 liquidationPenaltyRateTbps; //parameter: penalty if AMM closes the position and not the trader
        //------- 2
        PriceTimeData currentMarkPremiumRate; //relative diff to index price EMA, used for markprice.
        //------- 3
        int128 premiumRatesEMA; // EMA of premium rate
        int128 fUnitAccumulatedFunding; //accumulated funding in collateral currency
        //------- 4
        int128 fOpenInterest; //open interest is the larger of the amount of long and short positions in base currency
        int128 fTargetAMMFundSize; //target liquidity pool funds to allocate to the AMM
        //------- 5
        int128 fCurrentTraderExposureEMA; // trade amounts (storing absolute value)
        int128 fCurrentFundingRate; // current instantaneous funding rate
        //------- 6
        int128 fLotSizeBC; //parameter: minimal trade unit (in base currency) to avoid dust positions
        int128 fReferralRebateCC; //parameter: referall rebate in collateral currency
        //------- 7
        int128 fTargetDFSize; // target default fund size
        int128 fkStar; // signed trade size that minimizes the AMM risk
        //------- 8
        int128 fAMMTargetDD; // parameter: target distance to default (=inverse of default probability)
        int128 fAMMMinSizeCC; // parameter: minimal size of AMM pool, regardless of current exposure
        //------- 9
        int128 fMinimalTraderExposureEMA; // parameter: minimal value for fCurrentTraderExposureEMA that we don't want to undershoot
        int128 fMinimalAMMExposureEMA; // parameter: minimal abs value for fCurrentAMMExposureEMA that we don't want to undershoot
        //------- 10
        int128 fSettlementS3PriceData; //quanto index
        int128 fSettlementS2PriceData; //base-quote pair. Used as last price in normal state.
        //------- 11
        int128 fTotalMarginBalance; //calculated for settlement, in collateral currency
        int32 fMarkPriceEMALambda; // parameter: Lambda parameter for EMA used in mark-price for funding rates
        int32 fFundingRateClamp; // parameter: funding rate clamp between which we charge 1bps
        int32 fMaximalTradeSizeBumpUp; // parameter: >1, users can create a maximal position of size fMaximalTradeSizeBumpUp*fCurrentAMMExposureEMA
        uint32 iLastTargetPoolSizeTime; //timestamp (seconds) since last update of fTargetDFSize and fTargetAMMFundSize
        //------- 12

        //-------
        int128[2] fStressReturnS3; // parameter: negative and positive stress returns for quanto-quote asset
        int128[2] fDFLambda; // parameter: EMA lambda for AMM and trader exposure K,k: EMA*lambda + (1-lambda)*K. 0 regular lambda, 1 if current value exceeds past
        int128[2] fCurrentAMMExposureEMA; // 0: negative aggregated exposure (storing negative value), 1: positive
        int128[2] fStressReturnS2; // parameter: negative and positive stress returns for base-quote asset
        // -----
    }

    address internal oracleFactoryAddress;

    // users
    mapping(uint24 => EnumerableSetUpgradeable.AddressSet) internal activeAccounts; //perpetualId => traderAddressSet
    // accounts
    mapping(uint24 => mapping(address => MarginAccount)) internal marginAccounts;
    // delegates
    mapping(address => address) internal delegates;

    // broker maps: poolId -> brokeraddress-> lots contributed
    // contains non-zero entries for brokers. Brokers pay default fund contributions.
    mapping(uint8 => mapping(address => uint32)) internal brokerMap;

    struct LiquidityPoolData {
        bool isRunning; // state
        uint8 iPerpetualCount; // state
        uint8 id; // parameter: index, starts from 1
        int32 fCeilPnLShare; // parameter: cap on the share of PnL allocated to liquidity providers
        uint8 marginTokenDecimals; // parameter: decimals of margin token, inferred from token contract
        uint16 iTargetPoolSizeUpdateTime; //parameter: timestamp in seconds. How often we update the pool's target size
        address marginTokenAddress; //parameter: address of the margin token
        // -----
        uint64 prevAnchor; // state: keep track of timestamp since last withdrawal was initiated
        int128 fRedemptionRate; // state: used for settlement in case of AMM default
        address shareTokenAddress; // parameter
        // -----
        int128 fPnLparticipantsCashCC; // state: addLiquidity/withdrawLiquidity + profit/loss - rebalance
        int128 fTargetAMMFundSize; // state: target liquidity for all perpetuals in pool (sum)
        // -----
        int128 fDefaultFundCashCC; // state: profit/loss
        int128 fTargetDFSize; // state: target default fund size for all perpetuals in pool
        // -----
        int128 fBrokerCollateralLotSize; // param:how much collateral do brokers deposit when providing "1 lot" (not trading lot)
        uint128 prevTokenAmount; // state
        // -----
        uint128 nextTokenAmount; // state
        uint128 totalSupplyShareToken; // state
        // -----
        int128 fBrokerFundCashCC; // state: amount of cash in broker fund
    }

    address internal treasuryAddress; // address for the protocol treasury

    //pool id => perpetual id list
    mapping(uint8 => uint24[]) internal perpetualIds;

    //pool id => perpetual id => data
    mapping(uint8 => mapping(uint24 => PerpetualData)) internal perpetuals;

    /// @dev flag whether MarginTradeOrder was already executed or cancelled
    mapping(bytes32 => uint8) internal executedOrCancelledOrders;

    //proxy
    mapping(bytes32 => EnumerableBytes4Set.Bytes4Set) internal moduleActiveFuncSignatureList;
    mapping(bytes32 => address) internal moduleNameToAddress;
    mapping(address => bytes32) internal moduleAddressToModuleName;

    // fee structure
    struct VolumeEMA {
        int128 fTradingVolumeEMAusd; //trading volume EMA in usd
        uint64 timestamp; // timestamp of last trade
    }

    uint256[] public traderVolumeTiers; // dec18, regardless of token
    uint256[] public brokerVolumeTiers; // dec18, regardless of token
    uint16[] public traderVolumeFeesTbps;
    uint16[] public brokerVolumeFeesTbps;
    mapping(uint24 => address) public perpBaseToUSDOracle;
    mapping(uint24 => int128) public perpToLastBaseToUSD;
    mapping(uint8 => mapping(address => VolumeEMA)) public traderVolumeEMA;
    mapping(uint8 => mapping(address => VolumeEMA)) public brokerVolumeEMA;
    uint64 public lastBaseToUSDUpdateTs;

    // liquidity withdrawals
    struct WithdrawRequest {
        address lp;
        uint256 shareTokens;
        uint64 withdrawTimestamp;
    }

    mapping(address => mapping(uint8 => WithdrawRequest)) internal lpWithdrawMap;

    // users who initiated withdrawals are registered here
    mapping(uint8 => EnumerableSetUpgradeable.AddressSet) internal activeWithdrawals; //poolId => lpAddressSet

    mapping(uint8 => bool) public liquidityProvisionIsPaused;
}
/* solhint-enable max-states-count */

// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import "../../libraries/ABDKMath64x64.sol";
import "../../libraries/ConverterDec18.sol";
import "../../perpetual/interfaces/IAMMPerpLogic.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract AMMPerpLogic is Ownable, IAMMPerpLogic {
    using ABDKMath64x64 for int128;
    /* solhint-disable const-name-snakecase */
    int128 internal constant ONE_64x64 = 0x10000000000000000; // 2^64
    int128 internal constant TWO_64x64 = 0x20000000000000000; // 2*2^64
    int128 internal constant FOUR_64x64 = 0x40000000000000000; //4*2^64
    int128 internal constant HALF_64x64 = 0x8000000000000000; //0.5*2^64
    int128 internal constant TWENTY_64x64 = 0x140000000000000000; //20*2^64
    int128 private constant CDF_CONST_0 = 0x023a6ce358298c;
    int128 private constant CDF_CONST_1 = -0x216c61522a6f3f;
    int128 private constant CDF_CONST_2 = 0xc9320d9945b6c3;
    int128 private constant CDF_CONST_3 = -0x01bcfd4bf0995aaf;
    int128 private constant CDF_CONST_4 = -0x086de76427c7c501;
    int128 private constant CDF_CONST_5 = 0x749741d084e83004;
    int128 private constant CDF_CONST_6 = 0xcc42299ea1b28805;
    int128 private constant CDF_CONST_7 = 0x0281b263fec4e0a007;
    int128 private constant EXPM1_Q0 = 0x0a26c00000000000000000;
    int128 private constant EXPM1_Q1 = 0x0127500000000000000000;
    int128 private constant EXPM1_P0 = 0x0513600000000000000000;
    int128 private constant EXPM1_P1 = 0x27600000000000000000;
    int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

    /* solhint-enable const-name-snakecase */

    enum CollateralCurrency {
        QUOTE,
        BASE,
        QUANTO
    }

    struct AMMVariables {
        // all variables are
        // signed 64.64-bit fixed point number
        int128 fLockedValue1; // L1 in quote currency
        int128 fPoolM1; // M1 in quote currency
        int128 fPoolM2; // M2 in base currency
        int128 fPoolM3; // M3 in quanto currency
        int128 fAMM_K2; // AMM exposure (positive if trader long)
        int128 fCurrentTraderExposureEMA; // current average unsigned trader exposure
    }

    struct MarketVariables {
        int128 fIndexPriceS2; // base index
        int128 fIndexPriceS3; // quanto index
        int128 fSigma2; // standard dev of base currency
        int128 fSigma3; // standard dev of quanto currency
        int128 fRho23; // correlation base/quanto currency
    }

    /**
     * Calculate a EWMA when the last observation happened n periods ago
     * @dev Given is x_t = (1 - lambda) * mean + lambda * x_t-1, and x_0 = _newObs
     * it returns the value of x_deltaTime
     * @param _mean long term mean
     * @param _newObs observation deltaTime periods ago
     * @param _fLambda lambda of the EWMA
     * @param _deltaTime number of periods elapsed
     * @return result EWMA at deltaPeriods
     */
    function _emaWithTimeJumps(
        uint16 _mean,
        uint16 _newObs,
        int128 _fLambda,
        uint256 _deltaTime
    ) internal pure returns (int128 result) {
        _fLambda = _fLambda.pow(_deltaTime);
        result = ConverterDec18.tbpsToABDK(_mean).mul(ONE_64x64.sub(_fLambda));
        result = result.add(_fLambda.mul(ConverterDec18.tbpsToABDK(_newObs)));
    }

    /**
     *  Calculate the normal CDF value of _fX, i.e.,
     *  k=P(X<=_fX), for X~normal(0,1)
     *  The approximation is of the form
     *  Phi(x) = 1 - phi(x) / (x + exp(p(x))),
     *  where p(x) is a polynomial of degree 6
     *  @param _fX signed 64.64-bit fixed point number
     *  @return fY approximated normal-cdf evaluated at X
     */
    function _normalCDF(int128 _fX) internal pure returns (int128 fY) {
        bool isNegative = _fX < 0;
        if (isNegative) {
            _fX = _fX.neg();
        }
        if (_fX > FOUR_64x64) {
            fY = int128(0);
        } else {
            fY = _fX.mul(CDF_CONST_0).add(CDF_CONST_1);
            fY = _fX.mul(fY).add(CDF_CONST_2);
            fY = _fX.mul(fY).add(CDF_CONST_3);
            fY = _fX.mul(fY).add(CDF_CONST_4);
            fY = _fX.mul(fY).add(CDF_CONST_5).mul(_fX).neg().exp();
            fY = fY.mul(CDF_CONST_6).add(_fX);
            fY = _fX.mul(_fX).mul(HALF_64x64).neg().exp().div(CDF_CONST_7).div(fY);
        }
        if (!isNegative) {
            fY = ONE_64x64.sub(fY);
        }
        return fY;
    }

    /**
     *  Calculate the target size for the default fund
     *
     *  @param _fK2AMM       signed 64.64-bit fixed point number, Conservative negative[0]/positive[1] AMM exposure
     *  @param _fk2Trader    signed 64.64-bit fixed point number, Conservative (absolute) trader exposure
     *  @param _fCoverN      signed 64.64-bit fixed point number, cover-n rule for default fund parameter
     *  @param fStressRet2   signed 64.64-bit fixed point number, negative[0]/positive[1] stress returns for base/quote pair
     *  @param fStressRet3   signed 64.64-bit fixed point number, negative[0]/positive[1] stress returns for quanto/quote currency
     *  @param fIndexPrices  signed 64.64-bit fixed point number, spot price for base/quote[0] and quanto/quote[1] pairs
     *  @param _eCCY         enum that specifies in which currency the collateral is held: QUOTE, BASE, QUANTO
     *  @return approximated normal-cdf evaluated at X
     */
    function calculateDefaultFundSize(
        int128[2] memory _fK2AMM,
        int128 _fk2Trader,
        int128 _fCoverN,
        int128[2] memory fStressRet2,
        int128[2] memory fStressRet3,
        int128[2] memory fIndexPrices,
        AMMPerpLogic.CollateralCurrency _eCCY
    ) external pure override returns (int128) {
        require(_fK2AMM[0] < 0, "_fK2AMM[0] must be negative");
        require(_fK2AMM[1] > 0, "_fK2AMM[1] must be positive");
        require(_fk2Trader > 0, "_fk2Trader must be positive");

        int128[2] memory fEll;
        // downward stress scenario
        fEll[0] = (_fK2AMM[0].abs().add(_fk2Trader.mul(_fCoverN))).mul(
            ONE_64x64.sub((fStressRet2[0].exp()))
        );
        // upward stress scenario
        fEll[1] = (_fK2AMM[1].abs().add(_fk2Trader.mul(_fCoverN))).mul(
            (fStressRet2[1].exp().sub(ONE_64x64))
        );
        int128 fIstar;
        if (_eCCY == AMMPerpLogic.CollateralCurrency.BASE) {
            fIstar = fEll[0].div(fStressRet2[0].exp());
            int128 fI2 = fEll[1].div(fStressRet2[1].exp());
            if (fI2 > fIstar) {
                fIstar = fI2;
            }
        } else if (_eCCY == AMMPerpLogic.CollateralCurrency.QUANTO) {
            fIstar = fEll[0].div(fStressRet3[0].exp());
            int128 fI2 = fEll[1].div(fStressRet3[1].exp());
            if (fI2 > fIstar) {
                fIstar = fI2;
            }
            fIstar = fIstar.mul(fIndexPrices[0].div(fIndexPrices[1]));
        } else {
            assert(_eCCY == AMMPerpLogic.CollateralCurrency.QUOTE);
            if (fEll[0] > fEll[1]) {
                fIstar = fEll[0].mul(fIndexPrices[0]);
            } else {
                fIstar = fEll[1].mul(fIndexPrices[0]);
            }
        }
        return fIstar;
    }

    /**
     *  Calculate the risk neutral Distance to Default (Phi(DD)=default probability) when
     *  there is no quanto currency collateral.
     *  We assume r=0 everywhere.
     *  The underlying distribution is log-normal, hence the log below.
     *  All variables are 64.64-bit fixed point number (or struct thereof)
     *  @param fSigma2 current Market variables (price&params)
     *  @param _fSign signed 64.64-bit fixed point number, sign of denominator of distance to default
     *  @return _fThresh signed 64.64-bit fixed point number, number for which the log is the unnormalized distance to default
     */
    function _calculateRiskNeutralDDNoQuanto(
        int128 fSigma2,
        int128 _fSign,
        int128 _fThresh
    ) internal pure returns (int128) {
        require(_fThresh > 0, "argument to log must be >0");
        int128 _fLogTresh = _fThresh.ln();
        int128 fSigma2_2 = fSigma2.mul(fSigma2);
        int128 fMean = fSigma2_2.div(TWO_64x64).neg();
        int128 fDistanceToDefault = ABDKMath64x64.sub(_fLogTresh, fMean).div(fSigma2);
        // because 1-Phi(x) = Phi(-x) we change the sign if _fSign<0
        // now we would like to get the normal cdf of that beast
        if (_fSign < 0) {
            fDistanceToDefault = fDistanceToDefault.neg();
        }
        return fDistanceToDefault;
    }

    /**
     *  Calculate the standard deviation for the random variable
     *  evolving when quanto currencies are involved.
     *  We assume r=0 everywhere.
     *  All variables are 64.64-bit fixed point number (or struct thereof)
     *  @param _mktVars current Market variables (price&params)
     *  @param _fC3 signed 64.64-bit fixed point number current AMM/Market variables
     *  @param _fC3_2 signed 64.64-bit fixed point number, squared fC3
     *  @return fSigmaZ standard deviation, 64.64-bit fixed point number
     */
    function _calculateStandardDeviationQuanto(
        MarketVariables memory _mktVars,
        int128 _fC3,
        int128 _fC3_2
    ) internal pure returns (int128 fSigmaZ) {
        // fVarA = (exp(sigma2^2) - 1)
        int128 fVarA = _mktVars.fSigma2.mul(_mktVars.fSigma2);

        // fVarB = 2*(exp(sigma2*sigma3*rho) - 1)
        int128 fVarB = _mktVars.fSigma2.mul(_mktVars.fSigma3).mul(_mktVars.fRho23).mul(TWO_64x64);

        // fVarC = exp(sigma3^2) - 1
        int128 fVarC = _mktVars.fSigma3.mul(_mktVars.fSigma3);

        // sigmaZ = fVarA*C^2 + fVarB*C + fVarC
        fSigmaZ = fVarA.mul(_fC3_2).add(fVarB.mul(_fC3)).add(fVarC).sqrt();
    }

    /**
     *  Calculate the risk neutral Distance to Default (Phi(DD)=default probability) when
     *  presence of quanto currency collateral.
     *
     *  We approximate the distribution with a normal distribution
     *  We assume r=0 everywhere.
     *  All variables are 64.64-bit fixed point number
     *  @param _ammVars current AMM/Market variables
     *  @param _mktVars current Market variables (price&params)
     *  @param _fSign 64.64-bit fixed point number, current AMM/Market variables
     *  @return fDistanceToDefault signed 64.64-bit fixed point number
     */
    function _calculateRiskNeutralDDWithQuanto(
        AMMVariables memory _ammVars,
        MarketVariables memory _mktVars,
        int128 _fSign,
        int128 _fThresh
    ) internal pure returns (int128 fDistanceToDefault) {
        require(_fSign > 0, "no sign in quanto case");
        // 1) Calculate C3
        int128 fC3 = _mktVars.fIndexPriceS2.mul(_ammVars.fPoolM2.sub(_ammVars.fAMM_K2)).div(
            _ammVars.fPoolM3.mul(_mktVars.fIndexPriceS3)
        );
        int128 fC3_2 = fC3.mul(fC3);

        // 2) Calculate Variance
        int128 fSigmaZ = _calculateStandardDeviationQuanto(_mktVars, fC3, fC3_2);

        // 3) Calculate mean
        int128 fMean = fC3.add(ONE_64x64);
        // 4) Distance to default
        fDistanceToDefault = _fThresh.sub(fMean).div(fSigmaZ);
    }

    function calculateRiskNeutralPD(
        AMMVariables memory _ammVars,
        MarketVariables memory _mktVars,
        int128 _fTradeAmount,
        bool _withCDF
    ) external view virtual override returns (int128, int128) {
        return _calculateRiskNeutralPD(_ammVars, _mktVars, _fTradeAmount, _withCDF);
    }

    /**
     *  Calculate the risk neutral default probability (>=0).
     *  Function decides whether pricing with or without quanto CCY is chosen.
     *  We assume r=0 everywhere.
     *  All variables are 64.64-bit fixed point number (or struct thereof)
     *  @param _ammVars         current AMM variables.
     *  @param _mktVars         current Market variables (price&params)
     *  @param _fTradeAmount    Trade amount (can be 0), hence amounts k2 are not already factored in
     *                          that is, function will set K2:=K2+k2, L1:=L1+k2*s2 (k2=_fTradeAmount)
     *  @param _withCDF         bool. If false, the normal-cdf is not evaluated (in case the caller is only
     *                          interested in the distance-to-default, this saves calculations)
     *  @return (default probabilit, distance to default) ; 64.64-bit fixed point numbers
     */
    function _calculateRiskNeutralPD(
        AMMVariables memory _ammVars,
        MarketVariables memory _mktVars,
        int128 _fTradeAmount,
        bool _withCDF
    ) internal pure returns (int128, int128) {
        int128 dL = _fTradeAmount.mul(_mktVars.fIndexPriceS2);
        int128 dK = _fTradeAmount;
        _ammVars.fLockedValue1 = _ammVars.fLockedValue1.add(dL);
        _ammVars.fAMM_K2 = _ammVars.fAMM_K2.add(dK);
        // -L1 - k*s2 - M1
        int128 fNumerator = (_ammVars.fLockedValue1.neg()).sub(_ammVars.fPoolM1);
        // s2*(M2-k2-K2) if no quanto, else M3 * s3
        int128 fDenominator = _ammVars.fPoolM3 == 0
            ? (_ammVars.fPoolM2.sub(_ammVars.fAMM_K2)).mul(_mktVars.fIndexPriceS2)
            : _ammVars.fPoolM3.mul(_mktVars.fIndexPriceS3);
        // handle edge sign cases first
        int128 fThresh;
        if (_ammVars.fPoolM3 == 0) {
            if (fNumerator < 0) {
                if (fDenominator >= 0) {
                    // P( den * exp(x) < 0) = 0
                    return (int128(0), TWENTY_64x64.neg());
                } else {
                    // num < 0 and den < 0, and P(exp(x) > infty) = 0
                    int256 result = (int256(fNumerator) << 64) / fDenominator;
                    if (result > MAX_64x64) {
                        return (int128(0), TWENTY_64x64.neg());
                    }
                    fThresh = int128(result);
                }
            } else if (fNumerator > 0) {
                if (fDenominator <= 0) {
                    // P( exp(x) >= 0) = 1
                    return (int128(ONE_64x64), TWENTY_64x64);
                } else {
                    // num > 0 and den > 0, and P(exp(x) < infty) = 1
                    int256 result = (int256(fNumerator) << 64) / fDenominator;
                    if (result > MAX_64x64) {
                        return (int128(ONE_64x64), TWENTY_64x64);
                    }
                    fThresh = int128(result);
                }
            } else {
                return
                    fDenominator >= 0
                        ? (int128(0), TWENTY_64x64.neg())
                        : (int128(ONE_64x64), TWENTY_64x64);
            }
        } else {
            // denom is O(M3 * S3), div should not overflow
            fThresh = fNumerator.div(fDenominator);
        }
        // if we're here fDenominator !=0 and fThresh did not overflow
        // sign tells us whether we consider norm.cdf(f(threshold)) or 1-norm.cdf(f(threshold))
        // we recycle fDenominator to store the sign since it's no longer used
        fDenominator = fDenominator < 0 ? ONE_64x64.neg() : ONE_64x64;
        int128 dd = _ammVars.fPoolM3 == 0
            ? _calculateRiskNeutralDDNoQuanto(_mktVars.fSigma2, fDenominator, fThresh)
            : _calculateRiskNeutralDDWithQuanto(_ammVars, _mktVars, fDenominator, fThresh);

        int128 q;
        if (_withCDF) {
            q = _normalCDF(dd);
        }
        return (q, dd);
    }

    /**
     *  Calculate additional/non-risk based slippage.
     *  Ensures slippage is bounded away from zero for small trades,
     *  and plateaus for larger-than-average trades, so that price becomes risk based.
     *
     *  All variables are 64.64-bit fixed point number (or struct thereof)
     *  @param _ammVars current AMM variables - we need the current average exposure per trader
     *  @param _fTradeAmount 64.64-bit fixed point number, signed size of trade
     *  @return 64.64-bit fixed point number, a number between minus one and one
     */
    function _calculateBoundedSlippage(
        AMMVariables memory _ammVars,
        int128 _fTradeAmount
    ) internal pure returns (int128) {
        int128 fTradeSizeEMA = _ammVars.fCurrentTraderExposureEMA;
        int128 fSlippageSize = ONE_64x64;
        if (_fTradeAmount.abs() < fTradeSizeEMA) {
            fSlippageSize = fSlippageSize.sub(_fTradeAmount.abs().div(fTradeSizeEMA));
            fSlippageSize = ONE_64x64.sub(fSlippageSize.mul(fSlippageSize));
        }
        return _fTradeAmount > 0 ? fSlippageSize : fSlippageSize.neg();
    }

    /**
     *  Calculate AMM price.
     *
     *  All variables are 64.64-bit fixed point number (or struct thereof)
     *  @param _ammVars current AMM variables.
     *  @param _mktVars current Market variables (price&params)
     *                 Trader amounts k2 must already be factored in
     *                 that is, K2:=K2+k2, L1:=L1+k2*s2
     *  @param _fTradeAmount 64.64-bit fixed point number, signed size of trade
     *  @param _fHBidAskSpread half bid-ask spread, 64.64-bit fixed point number
     *  @return 64.64-bit fixed point number, AMM price
     */
    function calculatePerpetualPrice(
        AMMVariables memory _ammVars,
        MarketVariables memory _mktVars,
        int128 _fTradeAmount,
        int128 _fHBidAskSpread,
        int128 _fIncentiveSpread
    ) external view virtual override returns (int128) {
        // add minimal spread in quote currency
        _fHBidAskSpread = _fTradeAmount > 0 ? _fHBidAskSpread : _fHBidAskSpread.neg();
        if (_fTradeAmount == 0) {
            _fHBidAskSpread = 0;
        }
        // get risk-neutral default probability (always >0)
        {
            int128 fQ;
            int128 dd;
            int128 fkStar = _ammVars.fPoolM2.sub(_ammVars.fAMM_K2);
            (fQ, dd) = _calculateRiskNeutralPD(_ammVars, _mktVars, _fTradeAmount, true);
            if (_ammVars.fPoolM3 != 0) {
                // amend K* (see whitepaper)
                int128 nominator = _mktVars.fRho23.mul(_mktVars.fSigma2.mul(_mktVars.fSigma3));
                int128 denom = _mktVars.fSigma2.mul(_mktVars.fSigma2);
                int128 h = nominator.div(denom).mul(_ammVars.fPoolM3);
                h = h.mul(_mktVars.fIndexPriceS3).div(_mktVars.fIndexPriceS2);
                fkStar = fkStar.add(h);
            }
            // decide on sign of premium
            if (_fTradeAmount < fkStar) {
                fQ = fQ.neg();
            }
            // no rebate if exposure increases
            if (_fTradeAmount > 0 && _ammVars.fAMM_K2 > 0) {
                fQ = fQ > 0 ? fQ : int128(0);
            } else if (_fTradeAmount < 0 && _ammVars.fAMM_K2 < 0) {
                fQ = fQ < 0 ? fQ : int128(0);
            }
            // handle discontinuity at zero
            if (
                _fTradeAmount == 0 &&
                ((fQ < 0 && _ammVars.fAMM_K2 > 0) || (fQ > 0 && _ammVars.fAMM_K2 < 0))
            ) {
                fQ = fQ.div(TWO_64x64);
            }
            _fHBidAskSpread = _fHBidAskSpread.add(fQ);
        }
        // get additional slippage
        if (_fTradeAmount != 0) {
            _fIncentiveSpread = _fIncentiveSpread.mul(
                _calculateBoundedSlippage(_ammVars, _fTradeAmount)
            );
            _fHBidAskSpread = _fHBidAskSpread.add(_fIncentiveSpread);
        }
        // s2*(1 + sign(qp-q)*q + sign(k)*minSpread)
        return _mktVars.fIndexPriceS2.mul(ONE_64x64.add(_fHBidAskSpread));
    }

    /**
     *  Calculate target collateral M1 (Quote Currency), when no M2, M3 is present
     *  The targeted default probability is expressed using the inverse
     *  _fTargetDD = Phi^(-1)(targetPD)
     *  _fK2 in absolute terms must be 'reasonably large'
     *  sigma3, rho23, IndexpriceS3 not relevant.
     *  @param _fK2 signed 64.64-bit fixed point number, !=0, EWMA of actual K.
     *  @param _fL1 signed 64.64-bit fixed point number, >0, EWMA of actual L.
     *  @param  _mktVars contains 64.64 values for fIndexPriceS2*, fIndexPriceS3, fSigma2*, fSigma3, fRho23
     *  @param _fTargetDD signed 64.64-bit fixed point number
     *  @return M1Star signed 64.64-bit fixed point number, >0
     */
    function getTargetCollateralM1(
        int128 _fK2,
        int128 _fL1,
        MarketVariables memory _mktVars,
        int128 _fTargetDD
    ) external pure virtual override returns (int128) {
        assert(_fK2 != 0);
        assert(_mktVars.fSigma3 == 0);
        assert(_mktVars.fIndexPriceS3 == 0);
        assert(_mktVars.fRho23 == 0);
        int128 fMu2 = HALF_64x64.neg().mul(_mktVars.fSigma2).mul(_mktVars.fSigma2);
        int128 ddScaled = _fK2 < 0
            ? _mktVars.fSigma2.mul(_fTargetDD)
            : _mktVars.fSigma2.mul(_fTargetDD).neg();
        int128 A1 = ABDKMath64x64.exp(fMu2.add(ddScaled));
        return _fK2.mul(_mktVars.fIndexPriceS2).mul(A1).sub(_fL1);
    }

    /**
     *  Calculate target collateral *M2* (Base Currency), when no M1, M3 is present
     *  The targeted default probability is expressed using the inverse
     *  _fTargetDD = Phi^(-1)(targetPD)
     *  _fK2 in absolute terms must be 'reasonably large'
     *  sigma3, rho23, IndexpriceS3 not relevant.
     *  @param _fK2 signed 64.64-bit fixed point number, EWMA of actual K.
     *  @param _fL1 signed 64.64-bit fixed point number, EWMA of actual L.
     *  @param _mktVars contains 64.64 values for fIndexPriceS2, fIndexPriceS3, fSigma2, fSigma3, fRho23
     *  @param _fTargetDD signed 64.64-bit fixed point number
     *  @return M2Star signed 64.64-bit fixed point number
     */
    function getTargetCollateralM2(
        int128 _fK2,
        int128 _fL1,
        MarketVariables memory _mktVars,
        int128 _fTargetDD
    ) external pure virtual override returns (int128) {
        assert(_fK2 != 0);
        assert(_mktVars.fSigma3 == 0);
        assert(_mktVars.fIndexPriceS3 == 0);
        assert(_mktVars.fRho23 == 0);
        int128 fMu2 = HALF_64x64.mul(_mktVars.fSigma2).mul(_mktVars.fSigma2).neg();
        int128 ddScaled = _fL1 < 0
            ? _mktVars.fSigma2.mul(_fTargetDD)
            : _mktVars.fSigma2.mul(_fTargetDD).neg();
        int128 A1 = ABDKMath64x64.exp(fMu2.add(ddScaled)).mul(_mktVars.fIndexPriceS2);
        return _fK2.sub(_fL1.div(A1));
    }

    /**
     *  Calculate target collateral M3 (Quanto Currency), when no M1, M2 not present
     *  @param _fK2 signed 64.64-bit fixed point number. EWMA of actual K.
     *  @param _fL1 signed 64.64-bit fixed point number.  EWMA of actual L.
     *  @param  _mktVars contains 64.64 values for
     *           fIndexPriceS2, fIndexPriceS3, fSigma2, fSigma3, fRho23 - all required
     *  @param _fTargetDD signed 64.64-bit fixed point number
     *  @return M2Star signed 64.64-bit fixed point number
     */
    function getTargetCollateralM3(
        int128 _fK2,
        int128 _fL1,
        MarketVariables memory _mktVars,
        int128 _fTargetDD
    ) external pure override returns (int128) {
        assert(_fK2 != 0);
        assert(_mktVars.fSigma3 != 0);
        assert(_mktVars.fIndexPriceS3 != 0);
        // we solve the quadratic equation A x^2 + Bx + C = 0
        // B = 2 * [X + Y * target_dd^2 * (exp(rho*sigma2*sigma3) - 1) ]
        // C = X^2  - Y^2 * target_dd^2 * (exp(sigma2^2) - 1)
        // where:
        // X = L1 / S3 - Y and Y = K2 * S2 / S3
        // we re-use L1 for X and K2 for Y to save memory since they don't enter the equations otherwise
        _fK2 = _fK2.mul(_mktVars.fIndexPriceS2).div(_mktVars.fIndexPriceS3); // Y
        _fL1 = _fL1.div(_mktVars.fIndexPriceS3).sub(_fK2); // X
        // we only need the square of the target DD
        _fTargetDD = _fTargetDD.mul(_fTargetDD);
        // and we only need B/2
        int128 fHalfB = _fL1.add(
            _fK2.mul(_fTargetDD.mul(_mktVars.fRho23.mul(_mktVars.fSigma2.mul(_mktVars.fSigma3))))
        );
        int128 fC = _fL1.mul(_fL1).sub(
            _fK2.mul(_fK2).mul(_fTargetDD).mul(_mktVars.fSigma2.mul(_mktVars.fSigma2))
        );
        // A = 1 - (exp(sigma3^2) - 1) * target_dd^2
        int128 fA = ONE_64x64.sub(_mktVars.fSigma3.mul(_mktVars.fSigma3).mul(_fTargetDD));
        // we re-use C to store the discriminant: D = (B/2)^2 - A * C
        fC = fHalfB.mul(fHalfB).sub(fA.mul(fC));
        if (fC < 0) {
            // no solutions -> AMM is in profit, probability is smaller than target regardless of capital
            return int128(0);
        }
        // we want the larger of (-B/2 + sqrt((B/2)^2-A*C)) / A and (-B/2 - sqrt((B/2)^2-A*C)) / A
        // so it depends on the sign of A, or, equivalently, the sign of sqrt(...)/A
        fC = ABDKMath64x64.sqrt(fC).div(fA);
        fHalfB = fHalfB.div(fA);
        return fC > 0 ? fC.sub(fHalfB) : fC.neg().sub(fHalfB);
    }

    /**
     *  Calculate the required deposit for a new position
     *  of size _fPosition+_fTradeAmount and leverage _fTargetLeverage,
     *  having an existing position with balance fBalance0 and size _fPosition.
     *  This is the amount to be added to the margin collateral and can be negative (hence remove).
     *  Fees not factored-in.
     *  @param _fPosition0   signed 64.64-bit fixed point number. Position in base currency
     *  @param _fBalance0   signed 64.64-bit fixed point number. Current balance.
     *  @param _fTradeAmount signed 64.64-bit fixed point number. Trade amt in base currency
     *  @param _fTargetLeverage signed 64.64-bit fixed point number. Desired leverage
     *  @param _fPrice signed 64.64-bit fixed point number. Price for the trade of size _fTradeAmount
     *  @param _fS2Mark signed 64.64-bit fixed point number. Mark-price
     *  @param _fS3 signed 64.64-bit fixed point number. Collateral 2 quote conversion
     *  @return signed 64.64-bit fixed point number. Required cash_cc
     */
    function getDepositAmountForLvgPosition(
        int128 _fPosition0,
        int128 _fBalance0,
        int128 _fTradeAmount,
        int128 _fTargetLeverage,
        int128 _fPrice,
        int128 _fS2Mark,
        int128 _fS3,
        int128 _fS2
    ) external pure override returns (int128) {
        // calculation has to be aligned with _getAvailableMargin and _executeTrade
        // calculation
        // otherwise the calculated deposit might not be enough to declare
        // the margin to be enough
        // aligned with get available margin balance
        int128 fPremiumCash = _fTradeAmount.mul(_fPrice.sub(_fS2));
        int128 fDeltaLockedValue = _fTradeAmount.mul(_fS2);
        int128 fPnL = _fTradeAmount.mul(_fS2Mark);
        // we replace _fTradeAmount * price/S3 by
        // fDeltaLockedValue + fPremiumCash to be in line with
        // _executeTrade
        fPnL = fPnL.sub(fDeltaLockedValue).sub(fPremiumCash);
        int128 fLvgFrac = _fPosition0.add(_fTradeAmount).abs();
        fLvgFrac = fLvgFrac.mul(_fS2Mark).div(_fTargetLeverage);
        fPnL = fPnL.sub(fLvgFrac).div(_fS3);
        _fBalance0 = _fBalance0.add(fPnL);
        return _fBalance0.neg();
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import "../functions/AMMPerpLogic.sol";

interface IAMMPerpLogic {
    function calculateDefaultFundSize(
        int128[2] memory _fK2AMM,
        int128 _fk2Trader,
        int128 _fCoverN,
        int128[2] memory fStressRet2,
        int128[2] memory fStressRet3,
        int128[2] memory fIndexPrices,
        AMMPerpLogic.CollateralCurrency _eCCY
    ) external pure returns (int128);

    function calculateRiskNeutralPD(
        AMMPerpLogic.AMMVariables memory _ammVars,
        AMMPerpLogic.MarketVariables memory _mktVars,
        int128 _fTradeAmount,
        bool _withCDF
    ) external view returns (int128, int128);

    function calculatePerpetualPrice(
        AMMPerpLogic.AMMVariables memory _ammVars,
        AMMPerpLogic.MarketVariables memory _mktVars,
        int128 _fTradeAmount,
        int128 _fBidAskSpread,
        int128 _fIncentiveSpread
    ) external view returns (int128);

    function getTargetCollateralM1(
        int128 _fK2,
        int128 _fL1,
        AMMPerpLogic.MarketVariables memory _mktVars,
        int128 _fTargetDD
    ) external pure returns (int128);

    function getTargetCollateralM2(
        int128 _fK2,
        int128 _fL1,
        AMMPerpLogic.MarketVariables memory _mktVars,
        int128 _fTargetDD
    ) external pure returns (int128);

    function getTargetCollateralM3(
        int128 _fK2,
        int128 _fL1,
        AMMPerpLogic.MarketVariables memory _mktVars,
        int128 _fTargetDD
    ) external pure returns (int128);

    function getDepositAmountForLvgPosition(
        int128 _fPosition0,
        int128 _fBalance0,
        int128 _fTradeAmount,
        int128 _fTargetLeverage,
        int128 _fPrice,
        int128 _fS2Mark,
        int128 _fS3,
        int128 _fS2
    ) external pure returns (int128);
}

File 17 of 19 : IFunctionList.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

interface IFunctionList {
    function getFunctionList()
        external
        pure
        returns (bytes4[] memory functionSignatures, bytes32 moduleName);
}

File 18 of 19 : ILibraryEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import "./IPerpetualOrder.sol";

/**
 * @notice  The libraryEvents defines events that will be raised from modules (contract/modules).
 * @dev     DO REMEMBER to add new events in modules here.
 */
interface ILibraryEvents {
    // PerpetualModule
    event Clear(uint24 indexed perpetualId, address indexed trader);
    event Settle(uint24 indexed perpetualId, address indexed trader, int256 amount);
    event SettlementComplete(uint24 indexed perpetualId);
    event SetNormalState(uint24 indexed perpetualId);
    event SetEmergencyState(
        uint24 indexed perpetualId,
        int128 fSettlementMarkPremiumRate,
        int128 fSettlementS2Price,
        int128 fSettlementS3Price
    );
    event SettleState(uint24 indexed perpetualId);
    event SetClearedState(uint24 indexed perpetualId);

    // Participation pool
    event LiquidityAdded(
        uint8 indexed poolId,
        address indexed user,
        uint256 tokenAmount,
        uint256 shareAmount
    );
    event LiquidityProvisionPaused(bool pauseOn, uint8 poolId);
    event LiquidityRemoved(
        uint8 indexed poolId,
        address indexed user,
        uint256 tokenAmount,
        uint256 shareAmount
    );
    event LiquidityWithdrawalInitiated(
        uint8 indexed poolId,
        address indexed user,
        uint256 shareAmount
    );

    // setters
    // oracles
    event SetOracles(uint24 indexed perpetualId, bytes4[2] baseQuoteS2, bytes4[2] baseQuoteS3);
    // perp parameters
    event SetPerpetualBaseParameters(uint24 indexed perpetualId, int128[7] baseParams);
    event SetPerpetualRiskParameters(
        uint24 indexed perpetualId,
        int128[5] underlyingRiskParams,
        int128[12] defaultFundRiskParams
    );
    event SetParameter(uint24 indexed perpetualId, string name, int128 value);
    event SetParameterPair(uint24 indexed perpetualId, string name, int128 value1, int128 value2);
    // pool parameters
    event SetPoolParameter(uint8 indexed poolId, string name, int128 value);

    event TransferAddressTo(string name, address oldOBFactory, address newOBFactory); // only governance
    event SetBlockDelay(uint8 delay);

    // fee structure parameters
    event SetBrokerDesignations(uint32[] designations, uint16[] fees);
    event SetBrokerTiers(uint256[] tiers, uint16[] feesTbps);
    event SetTraderTiers(uint256[] tiers, uint16[] feesTbps);
    event SetTraderVolumeTiers(uint256[] tiers, uint16[] feesTbps);
    event SetBrokerVolumeTiers(uint256[] tiers, uint16[] feesTbps);
    event SetUtilityToken(address tokenAddr);

    event BrokerLotsTransferred(
        uint8 indexed poolId,
        address oldOwner,
        address newOwner,
        uint32 numLots
    );
    event BrokerVolumeTransferred(
        uint8 indexed poolId,
        address oldOwner,
        address newOwner,
        int128 fVolume
    );

    // brokers
    event UpdateBrokerAddedCash(uint8 indexed poolId, uint32 iLots, uint32 iNewBrokerLots);

    // TradeModule

    event Trade(
        uint24 indexed perpetualId,
        address indexed trader,
        IPerpetualOrder.Order order,
        bytes32 orderDigest,
        int128 newPositionSizeBC,
        int128 price,
        int128 fFeeCC,
        int128 fPnlCC,
        int128 fB2C
    );

    event UpdateMarginAccount(
        uint24 indexed perpetualId,
        address indexed trader,
        int128 fFundingPaymentCC
    );

    event Liquidate(
        uint24 perpetualId,
        address indexed liquidator,
        address indexed trader,
        int128 amountLiquidatedBC,
        int128 liquidationPrice,
        int128 newPositionSizeBC,
        int128 fFeeCC,
        int128 fPnlCC
    );

    event PerpetualLimitOrderCancelled(uint24 indexed perpetualId, bytes32 indexed orderHash);
    event DistributeFees(
        uint8 indexed poolId,
        uint24 indexed perpetualId,
        address indexed trader,
        int128 protocolFeeCC,
        int128 participationFundFeeCC
    );

    // PerpetualManager/factory
    event RunLiquidityPool(uint8 _liqPoolID);
    event LiquidityPoolCreated(
        uint8 id,
        address marginTokenAddress,
        address shareTokenAddress,
        uint16 iTargetPoolSizeUpdateTime,
        int128 fBrokerCollateralLotSize
    );
    event PerpetualCreated(
        uint8 poolId,
        uint24 id,
        int128[7] baseParams,
        int128[5] underlyingRiskParams,
        int128[12] defaultFundRiskParams,
        uint256 eCollateralCurrency
    );

    // emit tokenAddr==0x0 if the token paid is the aggregated token, otherwise the address of the token
    event TokensDeposited(uint24 indexed perpetualId, address indexed trader, int128 amount);
    event TokensWithdrawn(uint24 indexed perpetualId, address indexed trader, int128 amount);

    event UpdateMarkPrice(
        uint24 indexed perpetualId,
        int128 fMidPricePremium,
        int128 fMarkPricePremium,
        int128 fSpotIndexPrice
    );

    event UpdateFundingRate(uint24 indexed perpetualId, int128 fFundingRate);

    event SetDelegate(address indexed trader, address indexed delegate, uint256 index);
}

File 19 of 19 : IPerpetualOrder.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

interface IPerpetualOrder {
    struct Order {
        uint16 leverageTDR; // 12.43x leverage is represented by 1243 (two-digit integer representation); 0 if deposit and trade separate
        uint16 brokerFeeTbps; // broker can set their own fee
        uint24 iPerpetualId; // global id for perpetual
        address traderAddr; // address of trader
        uint32 executionTimestamp; // normally set to current timestamp; order will not be executed prior to this timestamp.
        address brokerAddr; // address of the broker or zero
        uint32 submittedTimestamp;
        uint32 flags; // order flags
        uint32 iDeadline; //deadline for price (seconds timestamp)
        address executorAddr; // address of the executor set by contract
        int128 fAmount; // amount in base currency to be traded
        int128 fLimitPrice; // limit price
        int128 fTriggerPrice; //trigger price. Non-zero for stop orders.
        bytes brokerSignature; //signature of broker (or 0)
    }
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"},{"indexed":false,"internalType":"uint32","name":"numLots","type":"uint32"}],"name":"BrokerLotsTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"},{"indexed":false,"internalType":"int128","name":"fVolume","type":"int128"}],"name":"BrokerVolumeTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"trader","type":"address"}],"name":"Clear","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int128","name":"protocolFeeCC","type":"int128"},{"indexed":false,"internalType":"int128","name":"participationFundFeeCC","type":"int128"}],"name":"DistributeFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"}],"name":"GovernanceTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"_sig","type":"bytes4"},{"indexed":true,"internalType":"address","name":"_oldImplementation","type":"address"},{"indexed":true,"internalType":"address","name":"_newImplementation","type":"address"}],"name":"ImplementationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int128","name":"amountLiquidatedBC","type":"int128"},{"indexed":false,"internalType":"int128","name":"liquidationPrice","type":"int128"},{"indexed":false,"internalType":"int128","name":"newPositionSizeBC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fFeeCC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fPnlCC","type":"int128"}],"name":"Liquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shareAmount","type":"uint256"}],"name":"LiquidityAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"id","type":"uint8"},{"indexed":false,"internalType":"address","name":"marginTokenAddress","type":"address"},{"indexed":false,"internalType":"address","name":"shareTokenAddress","type":"address"},{"indexed":false,"internalType":"uint16","name":"iTargetPoolSizeUpdateTime","type":"uint16"},{"indexed":false,"internalType":"int128","name":"fBrokerCollateralLotSize","type":"int128"}],"name":"LiquidityPoolCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"pauseOn","type":"bool"},{"indexed":false,"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"LiquidityProvisionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shareAmount","type":"uint256"}],"name":"LiquidityRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"shareAmount","type":"uint256"}],"name":"LiquidityWithdrawalInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousMaintainer","type":"address"},{"indexed":true,"internalType":"address","name":"newMaintainer","type":"address"}],"name":"MaintainerTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"uint24","name":"id","type":"uint24"},{"indexed":false,"internalType":"int128[7]","name":"baseParams","type":"int128[7]"},{"indexed":false,"internalType":"int128[5]","name":"underlyingRiskParams","type":"int128[5]"},{"indexed":false,"internalType":"int128[12]","name":"defaultFundRiskParams","type":"int128[12]"},{"indexed":false,"internalType":"uint256","name":"eCollateralCurrency","type":"uint256"}],"name":"PerpetualCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"PerpetualLimitOrderCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"ProxyOwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"_liqPoolID","type":"uint8"}],"name":"RunLiquidityPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"delay","type":"uint8"}],"name":"SetBlockDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32[]","name":"designations","type":"uint32[]"},{"indexed":false,"internalType":"uint16[]","name":"fees","type":"uint16[]"}],"name":"SetBrokerDesignations","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"tiers","type":"uint256[]"},{"indexed":false,"internalType":"uint16[]","name":"feesTbps","type":"uint16[]"}],"name":"SetBrokerTiers","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"tiers","type":"uint256[]"},{"indexed":false,"internalType":"uint16[]","name":"feesTbps","type":"uint16[]"}],"name":"SetBrokerVolumeTiers","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"}],"name":"SetClearedState","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"SetDelegate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"int128","name":"fSettlementMarkPremiumRate","type":"int128"},{"indexed":false,"internalType":"int128","name":"fSettlementS2Price","type":"int128"},{"indexed":false,"internalType":"int128","name":"fSettlementS3Price","type":"int128"}],"name":"SetEmergencyState","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"}],"name":"SetNormalState","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"bytes4[2]","name":"baseQuoteS2","type":"bytes4[2]"},{"indexed":false,"internalType":"bytes4[2]","name":"baseQuoteS3","type":"bytes4[2]"}],"name":"SetOracles","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"int128","name":"value","type":"int128"}],"name":"SetParameter","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"int128","name":"value1","type":"int128"},{"indexed":false,"internalType":"int128","name":"value2","type":"int128"}],"name":"SetParameterPair","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"int128[7]","name":"baseParams","type":"int128[7]"}],"name":"SetPerpetualBaseParameters","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"int128[5]","name":"underlyingRiskParams","type":"int128[5]"},{"indexed":false,"internalType":"int128[12]","name":"defaultFundRiskParams","type":"int128[12]"}],"name":"SetPerpetualRiskParameters","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"int128","name":"value","type":"int128"}],"name":"SetPoolParameter","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"tiers","type":"uint256[]"},{"indexed":false,"internalType":"uint16[]","name":"feesTbps","type":"uint16[]"}],"name":"SetTraderTiers","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"tiers","type":"uint256[]"},{"indexed":false,"internalType":"uint16[]","name":"feesTbps","type":"uint16[]"}],"name":"SetTraderVolumeTiers","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenAddr","type":"address"}],"name":"SetUtilityToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int256","name":"amount","type":"int256"}],"name":"Settle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"}],"name":"SettleState","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"}],"name":"SettlementComplete","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int128","name":"amount","type":"int128"}],"name":"TokensDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int128","name":"amount","type":"int128"}],"name":"TokensWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"components":[{"internalType":"uint16","name":"leverageTDR","type":"uint16"},{"internalType":"uint16","name":"brokerFeeTbps","type":"uint16"},{"internalType":"uint24","name":"iPerpetualId","type":"uint24"},{"internalType":"address","name":"traderAddr","type":"address"},{"internalType":"uint32","name":"executionTimestamp","type":"uint32"},{"internalType":"address","name":"brokerAddr","type":"address"},{"internalType":"uint32","name":"submittedTimestamp","type":"uint32"},{"internalType":"uint32","name":"flags","type":"uint32"},{"internalType":"uint32","name":"iDeadline","type":"uint32"},{"internalType":"address","name":"executorAddr","type":"address"},{"internalType":"int128","name":"fAmount","type":"int128"},{"internalType":"int128","name":"fLimitPrice","type":"int128"},{"internalType":"int128","name":"fTriggerPrice","type":"int128"},{"internalType":"bytes","name":"brokerSignature","type":"bytes"}],"indexed":false,"internalType":"struct IPerpetualOrder.Order","name":"order","type":"tuple"},{"indexed":false,"internalType":"bytes32","name":"orderDigest","type":"bytes32"},{"indexed":false,"internalType":"int128","name":"newPositionSizeBC","type":"int128"},{"indexed":false,"internalType":"int128","name":"price","type":"int128"},{"indexed":false,"internalType":"int128","name":"fFeeCC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fPnlCC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fB2C","type":"int128"}],"name":"Trade","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"oldOBFactory","type":"address"},{"indexed":false,"internalType":"address","name":"newOBFactory","type":"address"}],"name":"TransferAddressTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"uint32","name":"iLots","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"iNewBrokerLots","type":"uint32"}],"name":"UpdateBrokerAddedCash","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"int128","name":"fFundingRate","type":"int128"}],"name":"UpdateFundingRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int128","name":"fFundingPaymentCC","type":"int128"}],"name":"UpdateMarginAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"int128","name":"fMidPricePremium","type":"int128"},{"indexed":false,"internalType":"int128","name":"fMarkPricePremium","type":"int128"},{"indexed":false,"internalType":"int128","name":"fSpotIndexPrice","type":"int128"}],"name":"UpdateMarkPrice","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"address","name":"","type":"address"}],"name":"brokerVolumeEMA","outputs":[{"internalType":"int128","name":"fTradingVolumeEMAusd","type":"int128"},{"internalType":"uint64","name":"timestamp","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"brokerVolumeFeesTbps","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"brokerVolumeTiers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_sig","type":"bytes4"}],"name":"getImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_moduleName","type":"string"}],"name":"getModuleImplementationAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProxyOwner","outputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastBaseToUSDUpdateTs","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"liquidityProvisionIsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maintainer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint24","name":"","type":"uint24"}],"name":"perpBaseToUSDOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint24","name":"","type":"uint24"}],"name":"perpToLastBaseToUSD","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_impl","type":"address"}],"name":"setImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_impl","type":"address"}],"name":"setImplementationCrossModules","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setProxyOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"address","name":"","type":"address"}],"name":"traderVolumeEMA","outputs":[{"internalType":"int128","name":"fTradingVolumeEMAusd","type":"int128"},{"internalType":"uint64","name":"timestamp","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"traderVolumeFeesTbps","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"traderVolumeTiers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newGovernance","type":"address"}],"name":"transferGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newMaintainer","type":"address"}],"name":"transferMaintainer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040523480156200001157600080fd5b506200001d3362000049565b620000283362000099565b6001805460ff60a01b191681556002556200004333620000eb565b620001b0565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f2f3ffaaaad93928855c8700645d1a3643e6ccfdd500efa9fda048a88f557cf019190a35050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce8090600090a35050565b6001600160a01b038116620001465760405162461bcd60e51b815260206004820152601b60248201527f696e76616c69642070726f7879206f776e657220616464726573730000000000604482015260640160405180910390fd5b6001600160a01b038116620001686000805160206200274a8339815191525490565b6001600160a01b03167f5a3e66efaa1e445ebd894728a69d6959842ea1e97bd79b892797106e270efcd960405160405180910390a36000805160206200274a83398151915255565b61258a80620001c06000396000f3fe6080604052600436106101835760003560e01c80636700c019116100d6578063caaee91c1161007f578063dc9cc64511610059578063dc9cc6451461058a578063e7332410146105aa578063e7e21fde146105e457610192565b8063caaee91c1461052a578063d38bfff41461054a578063d784d4261461056a57610192565b80639850d32b116100b05780639850d32b146104835780639ecab3f5146104ae578063bffd952a1461050a57610192565b80636700c019146103f85780638456cb591461042b57806388b825281461044057610192565b80633f4ba83a116101385780635c975abb116101125780635c975abb146103295780635ca8b972146103595780635fdfecbe1461037957610192565b80633f4ba83a146102bb57806355f1c7d5146102d05780635aa6e675146102fe57610192565b80631ab7710d116101695780631ab7710d146102045780633a839d15146102385780633baf4f6f1461027b57610192565b806233c04b1461019a5780630e1cf91b146101e457610192565b3661019257610190610604565b005b610190610604565b3480156101a657600080fd5b506101ba6101b53660046121ab565b610616565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156101f057600080fd5b506101906101ff366004612241565b61068b565b34801561021057600080fd5b507fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d8546101ba565b34801561024457600080fd5b5061026861025336600461225c565b601960205260009081526040902054600f0b81565b604051600f9190910b81526020016101db565b34801561028757600080fd5b506102ab610296366004612292565b601f6020526000908152604090205460ff1681565b60405190151581526020016101db565b3480156102c757600080fd5b50610190610754565b3480156102dc57600080fd5b506102f06102eb3660046122ad565b610801565b6040519081526020016101db565b34801561030a57600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166101ba565b34801561033557600080fd5b5060015474010000000000000000000000000000000000000000900460ff166102ab565b34801561036557600080fd5b506102f06103743660046122ad565b610822565b34801561038557600080fd5b506103d56103943660046122c6565b601a602090815260009283526040808420909152908252902054600f81900b90700100000000000000000000000000000000900467ffffffffffffffff1682565b60408051600f9390930b835267ffffffffffffffff9091166020830152016101db565b34801561040457600080fd5b506104186104133660046122ad565b610832565b60405161ffff90911681526020016101db565b34801561043757600080fd5b5061019061086a565b34801561044c57600080fd5b506101ba61045b36600461225c565b60186020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561048f57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101ba565b3480156104ba57600080fd5b506103d56104c93660046122c6565b601b602090815260009283526040808420909152908252902054600f81900b90700100000000000000000000000000000000900467ffffffffffffffff1682565b34801561051657600080fd5b50610190610525366004612241565b610917565b34801561053657600080fd5b50610190610545366004612241565b610a1e565b34801561055657600080fd5b50610190610565366004612241565b610add565b34801561057657600080fd5b50610190610585366004612241565b610be4565b34801561059657600080fd5b506101ba6105a5366004612327565b610ca5565b3480156105b657600080fd5b50601c546105cb9067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101db565b3480156105f057600080fd5b506104186105ff3660046122ad565b610d19565b61061461060f610d29565b610e49565b565b60006012600061065b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e6d92505050565b815260208101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff1690505b92915050565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610746576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e6965640000000000000000000000000060448201526064015b60405180910390fd5b610751816001610e8c565b50565b61075c6113a2565b3361077c60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16146107f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c79206d61696e7461696e65720000000000000000000000000000000000604482015260640161073d565b610614611426565b6014818154811061081157600080fd5b600091825260209091200154905081565b6015818154811061081157600080fd5b6016818154811061084257600080fd5b9060005260206000209060109182820401919006600202915054906101000a900461ffff1681565b6108726114a3565b3361089260005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461090f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c79206d61696e7461696e65720000000000000000000000000000000000604482015260640161073d565b610614611528565b60015473ffffffffffffffffffffffffffffffffffffffff163314610998576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c7920676f7665726e616e63650000000000000000000000000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff8116610a15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f20616464726573730000000000000000000000000000000000000000604482015260640161073d565b61075181611597565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610ad4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e69656400000000000000000000000000604482015260640161073d565b6107518161160c565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c7920676f7665726e616e63650000000000000000000000000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff8116610bdb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f20616464726573730000000000000000000000000000000000000000604482015260640161073d565b6107518161172e565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c9a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e69656400000000000000000000000000604482015260640161073d565b610751816000610e8c565b604080517fffffffff0000000000000000000000000000000000000000000000000000000083166020808301919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc8828401528251808303840181526060909201909252805191012054600090610685565b6017818154811061084257600080fd5b600080610dc56000357fffffffff0000000000000000000000000000000000000000000000000000000016604080517fffffffff00000000000000000000000000000000000000000000000000000000929092166020808401919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883830152815180840383018152606090930190915281519101205490565b905073ffffffffffffffffffffffffffffffffffffffff8116610e44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f50726f78793a496d706c656d656e746174696f6e206e6f7420666f756e640000604482015260640161073d565b919050565b3660008037600080366000845af43d6000803e808015610e68573d6000f35b3d6000fd5b805160009082908203610e835750600092915050565b50506020015190565b73ffffffffffffffffffffffffffffffffffffffff8216610f09576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f696e76616c696420696d706c656d656e746174696f6e20616464726573730000604482015260640161073d565b6000808373ffffffffffffffffffffffffffffffffffffffff16633e6b8c0d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610f57573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610f9d919081019061237e565b909250905080611009576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d6f64756c65206e616d652063616e6e6f7420626520656d7074790000000000604482015260640161073d565b60008181526011602052604081209080611024836001015490565b85519110915060005b8181101561121557600086828151811061104957611049612469565b6020026020010151905061107f87838151811061106857611068612469565b6020026020010151866117a590919063ffffffff16565b6111df57604080517fffffffff0000000000000000000000000000000000000000000000000000000083166020808301919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc882840152825180830384018152606090920190925280519101205473ffffffffffffffffffffffffffffffffffffffff8116156111b05788611172576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f63616e74207265706c616365206d6f64756c65732066756e6373000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601360209081526040808320548352601190915290206111ae90836117dc565b505b6111dc8884815181106111c5576111c5612469565b6020026020010151876119d890919063ffffffff16565b50505b6112028783815181106111f4576111f4612469565b60200260200101518a611a88565b508061120d816124c7565b91505061102d565b508115611339576000611236600061122e866001015490565b869190611bbb565b90508051915060005b8281101561133657600082828151811061125b5761125b612469565b602002602001015190508973ffffffffffffffffffffffffffffffffffffffff166112f182604080517fffffffff00000000000000000000000000000000000000000000000000000000929092166020808401919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883830152815180840383018152606090930190915281519101205490565b73ffffffffffffffffffffffffffffffffffffffff161461132357611317816000611a88565b61132186826117dc565b505b508061132e816124c7565b91505061123f565b50505b5050506000818152601260209081526040808320805473ffffffffffffffffffffffffffffffffffffffff9098167fffffffffffffffffffffffff0000000000000000000000000000000000000000909816881790559582526013905293909320929092555050565b60015474010000000000000000000000000000000000000000900460ff16610614576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161073d565b61142e6113a2565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b60015474010000000000000000000000000000000000000000900460ff1615610614576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161073d565b6115306114a3565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586114793390565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f2f3ffaaaad93928855c8700645d1a3643e6ccfdd500efa9fda048a88f557cf019190a35050565b73ffffffffffffffffffffffffffffffffffffffff8116611689576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c69642070726f7879206f776e657220616464726573730000000000604482015260640161073d565b8073ffffffffffffffffffffffffffffffffffffffff166116c87fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85490565b73ffffffffffffffffffffffffffffffffffffffff167f5a3e66efaa1e445ebd894728a69d6959842ea1e97bd79b892797106e270efcd960405160405180910390a37fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d855565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce8090600090a35050565b7fffffffff000000000000000000000000000000000000000000000000000000001660009081526020919091526040902054151590565b7fffffffff000000000000000000000000000000000000000000000000000000008116600090815260208390526040812054156119d0577fffffffff000000000000000000000000000000000000000000000000000000008216600090815260208490526040812054611851906001906124ff565b60018581015491925060009161186791906124ff565b905081811461193357600085600101828154811061188757611887612469565b90600052602060002090600891828204019190066004029054906101000a900460e01b9050808660010184815481106118c2576118c2612469565b90600052602060002090600891828204019190066004026101000a81548163ffffffff021916908360e01c02179055508260016118ff9190612512565b7fffffffff000000000000000000000000000000000000000000000000000000009091166000908152602087905260409020555b7fffffffff0000000000000000000000000000000000000000000000000000000084166000908152602086905260408120556001850180548061197857611978612525565b60008281526020902060087fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191820401805463ffffffff600460078516026101000a0219169055905550600191506106859050565b506000610685565b7fffffffff0000000000000000000000000000000000000000000000000000000081166000908152602083905260408120546119d05750600182810180548083018255600082815260208082206008840401805463ffffffff60079095166004026101000a948502191660e088901c949094029390931790925591547fffffffff000000000000000000000000000000000000000000000000000000008516835290859052604090912055610685565b611a9182611d68565b604080517fffffffff00000000000000000000000000000000000000000000000000000000841660208083018290527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883850152835180840385018152606084018086528151919092012054919052915173ffffffffffffffffffffffffffffffffffffffff8481169316917f347b48699b991c95bb339a3a778222488794b19790e9f46171825933c63a9cc4919081900360800190a3604080517fffffffff00000000000000000000000000000000000000000000000000000000939093166020808501919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc8848301528151808503830181526060909401909152825192019190912055565b60606000611bc98385612512565b905083811015611c35576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6164646974696f6e206f766572666c6f77000000000000000000000000000000604482015260640161073d565b60018501548111611c465780611c4c565b60018501545b9050801580611c5b5750808410155b15611c665750611d61565b611c7084826124ff565b67ffffffffffffffff811115611c8857611c88612344565b604051908082528060200260200182016040528015611cb1578160200160208202803683370190505b50915060005b611cc185836124ff565b811015611d5e5760018601611cd68683612512565b81548110611ce657611ce6612469565b90600052602060002090600891828204019190066004029054906101000a900460e01b838281518110611d1b57611d1b612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280611d56816124c7565b915050611cb7565b50505b9392505050565b6000611d72611e5a565b805190915060005b81811015611e5457828181518110611d9457611d94612469565b60200260200101517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603611e42576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f66756e6374696f6e20696420616c726561647920657869737473000000000000604482015260640161073d565b80611e4c816124c7565b915050611d7a565b50505050565b604080516008808252610120820190925260609160009190602082016101008036833701905050905063dc9cc64560e01b81600081518110611e9e57611e9e612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517fd784d426000000000000000000000000000000000000000000000000000000009082906001908110611f0657611f06612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f0e1cf91b000000000000000000000000000000000000000000000000000000009082906002908110611f6e57611f6e612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517e33c04b000000000000000000000000000000000000000000000000000000009082906003908110611fd557611fd5612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517fcaaee91c00000000000000000000000000000000000000000000000000000000908290600490811061203d5761203d612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f1ab7710d0000000000000000000000000000000000000000000000000000000090829060059081106120a5576120a5612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f8456cb5900000000000000000000000000000000000000000000000000000000908290600690811061210d5761210d612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f3f4ba83a00000000000000000000000000000000000000000000000000000000908290600790811061217557612175612469565b7fffffffff0000000000000000000000000000000000000000000000000000000090921660209283029190910190910152919050565b600080602083850312156121be57600080fd5b823567ffffffffffffffff808211156121d657600080fd5b818501915085601f8301126121ea57600080fd5b8135818111156121f957600080fd5b86602082850101111561220b57600080fd5b60209290920196919550909350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e4457600080fd5b60006020828403121561225357600080fd5b611d618261221d565b60006020828403121561226e57600080fd5b813562ffffff81168114611d6157600080fd5b803560ff81168114610e4457600080fd5b6000602082840312156122a457600080fd5b611d6182612281565b6000602082840312156122bf57600080fd5b5035919050565b600080604083850312156122d957600080fd5b6122e283612281565b91506122f06020840161221d565b90509250929050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461075157600080fd5b60006020828403121561233957600080fd5b8135611d61816122f9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8051610e44816122f9565b6000806040838503121561239157600080fd5b825167ffffffffffffffff808211156123a957600080fd5b818501915085601f8301126123bd57600080fd5b81516020828211156123d1576123d1612344565b8160051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110868211171561241457612414612344565b60405292835281830193508481018201928984111561243257600080fd5b948201945b838610156124575761244886612373565b85529482019493820193612437565b97909101519698969750505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036124f8576124f8612498565b5060010190565b8181038181111561068557610685612498565b8082018082111561068557610685612498565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220baa4e6a5c992cd94607a99f04e80a0f38c585f60a6688a7da706e3f04726e06664736f6c63430008150033b5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d8

Deployed Bytecode

0x6080604052600436106101835760003560e01c80636700c019116100d6578063caaee91c1161007f578063dc9cc64511610059578063dc9cc6451461058a578063e7332410146105aa578063e7e21fde146105e457610192565b8063caaee91c1461052a578063d38bfff41461054a578063d784d4261461056a57610192565b80639850d32b116100b05780639850d32b146104835780639ecab3f5146104ae578063bffd952a1461050a57610192565b80636700c019146103f85780638456cb591461042b57806388b825281461044057610192565b80633f4ba83a116101385780635c975abb116101125780635c975abb146103295780635ca8b972146103595780635fdfecbe1461037957610192565b80633f4ba83a146102bb57806355f1c7d5146102d05780635aa6e675146102fe57610192565b80631ab7710d116101695780631ab7710d146102045780633a839d15146102385780633baf4f6f1461027b57610192565b806233c04b1461019a5780630e1cf91b146101e457610192565b3661019257610190610604565b005b610190610604565b3480156101a657600080fd5b506101ba6101b53660046121ab565b610616565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156101f057600080fd5b506101906101ff366004612241565b61068b565b34801561021057600080fd5b507fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d8546101ba565b34801561024457600080fd5b5061026861025336600461225c565b601960205260009081526040902054600f0b81565b604051600f9190910b81526020016101db565b34801561028757600080fd5b506102ab610296366004612292565b601f6020526000908152604090205460ff1681565b60405190151581526020016101db565b3480156102c757600080fd5b50610190610754565b3480156102dc57600080fd5b506102f06102eb3660046122ad565b610801565b6040519081526020016101db565b34801561030a57600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166101ba565b34801561033557600080fd5b5060015474010000000000000000000000000000000000000000900460ff166102ab565b34801561036557600080fd5b506102f06103743660046122ad565b610822565b34801561038557600080fd5b506103d56103943660046122c6565b601a602090815260009283526040808420909152908252902054600f81900b90700100000000000000000000000000000000900467ffffffffffffffff1682565b60408051600f9390930b835267ffffffffffffffff9091166020830152016101db565b34801561040457600080fd5b506104186104133660046122ad565b610832565b60405161ffff90911681526020016101db565b34801561043757600080fd5b5061019061086a565b34801561044c57600080fd5b506101ba61045b36600461225c565b60186020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561048f57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101ba565b3480156104ba57600080fd5b506103d56104c93660046122c6565b601b602090815260009283526040808420909152908252902054600f81900b90700100000000000000000000000000000000900467ffffffffffffffff1682565b34801561051657600080fd5b50610190610525366004612241565b610917565b34801561053657600080fd5b50610190610545366004612241565b610a1e565b34801561055657600080fd5b50610190610565366004612241565b610add565b34801561057657600080fd5b50610190610585366004612241565b610be4565b34801561059657600080fd5b506101ba6105a5366004612327565b610ca5565b3480156105b657600080fd5b50601c546105cb9067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101db565b3480156105f057600080fd5b506104186105ff3660046122ad565b610d19565b61061461060f610d29565b610e49565b565b60006012600061065b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e6d92505050565b815260208101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff1690505b92915050565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610746576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e6965640000000000000000000000000060448201526064015b60405180910390fd5b610751816001610e8c565b50565b61075c6113a2565b3361077c60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16146107f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c79206d61696e7461696e65720000000000000000000000000000000000604482015260640161073d565b610614611426565b6014818154811061081157600080fd5b600091825260209091200154905081565b6015818154811061081157600080fd5b6016818154811061084257600080fd5b9060005260206000209060109182820401919006600202915054906101000a900461ffff1681565b6108726114a3565b3361089260005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461090f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c79206d61696e7461696e65720000000000000000000000000000000000604482015260640161073d565b610614611528565b60015473ffffffffffffffffffffffffffffffffffffffff163314610998576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c7920676f7665726e616e63650000000000000000000000000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff8116610a15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f20616464726573730000000000000000000000000000000000000000604482015260640161073d565b61075181611597565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610ad4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e69656400000000000000000000000000604482015260640161073d565b6107518161160c565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c7920676f7665726e616e63650000000000000000000000000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff8116610bdb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f20616464726573730000000000000000000000000000000000000000604482015260640161073d565b6107518161172e565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c9a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e69656400000000000000000000000000604482015260640161073d565b610751816000610e8c565b604080517fffffffff0000000000000000000000000000000000000000000000000000000083166020808301919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc8828401528251808303840181526060909201909252805191012054600090610685565b6017818154811061084257600080fd5b600080610dc56000357fffffffff0000000000000000000000000000000000000000000000000000000016604080517fffffffff00000000000000000000000000000000000000000000000000000000929092166020808401919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883830152815180840383018152606090930190915281519101205490565b905073ffffffffffffffffffffffffffffffffffffffff8116610e44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f50726f78793a496d706c656d656e746174696f6e206e6f7420666f756e640000604482015260640161073d565b919050565b3660008037600080366000845af43d6000803e808015610e68573d6000f35b3d6000fd5b805160009082908203610e835750600092915050565b50506020015190565b73ffffffffffffffffffffffffffffffffffffffff8216610f09576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f696e76616c696420696d706c656d656e746174696f6e20616464726573730000604482015260640161073d565b6000808373ffffffffffffffffffffffffffffffffffffffff16633e6b8c0d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610f57573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610f9d919081019061237e565b909250905080611009576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d6f64756c65206e616d652063616e6e6f7420626520656d7074790000000000604482015260640161073d565b60008181526011602052604081209080611024836001015490565b85519110915060005b8181101561121557600086828151811061104957611049612469565b6020026020010151905061107f87838151811061106857611068612469565b6020026020010151866117a590919063ffffffff16565b6111df57604080517fffffffff0000000000000000000000000000000000000000000000000000000083166020808301919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc882840152825180830384018152606090920190925280519101205473ffffffffffffffffffffffffffffffffffffffff8116156111b05788611172576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f63616e74207265706c616365206d6f64756c65732066756e6373000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601360209081526040808320548352601190915290206111ae90836117dc565b505b6111dc8884815181106111c5576111c5612469565b6020026020010151876119d890919063ffffffff16565b50505b6112028783815181106111f4576111f4612469565b60200260200101518a611a88565b508061120d816124c7565b91505061102d565b508115611339576000611236600061122e866001015490565b869190611bbb565b90508051915060005b8281101561133657600082828151811061125b5761125b612469565b602002602001015190508973ffffffffffffffffffffffffffffffffffffffff166112f182604080517fffffffff00000000000000000000000000000000000000000000000000000000929092166020808401919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883830152815180840383018152606090930190915281519101205490565b73ffffffffffffffffffffffffffffffffffffffff161461132357611317816000611a88565b61132186826117dc565b505b508061132e816124c7565b91505061123f565b50505b5050506000818152601260209081526040808320805473ffffffffffffffffffffffffffffffffffffffff9098167fffffffffffffffffffffffff0000000000000000000000000000000000000000909816881790559582526013905293909320929092555050565b60015474010000000000000000000000000000000000000000900460ff16610614576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161073d565b61142e6113a2565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b60015474010000000000000000000000000000000000000000900460ff1615610614576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161073d565b6115306114a3565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586114793390565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f2f3ffaaaad93928855c8700645d1a3643e6ccfdd500efa9fda048a88f557cf019190a35050565b73ffffffffffffffffffffffffffffffffffffffff8116611689576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c69642070726f7879206f776e657220616464726573730000000000604482015260640161073d565b8073ffffffffffffffffffffffffffffffffffffffff166116c87fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85490565b73ffffffffffffffffffffffffffffffffffffffff167f5a3e66efaa1e445ebd894728a69d6959842ea1e97bd79b892797106e270efcd960405160405180910390a37fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d855565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce8090600090a35050565b7fffffffff000000000000000000000000000000000000000000000000000000001660009081526020919091526040902054151590565b7fffffffff000000000000000000000000000000000000000000000000000000008116600090815260208390526040812054156119d0577fffffffff000000000000000000000000000000000000000000000000000000008216600090815260208490526040812054611851906001906124ff565b60018581015491925060009161186791906124ff565b905081811461193357600085600101828154811061188757611887612469565b90600052602060002090600891828204019190066004029054906101000a900460e01b9050808660010184815481106118c2576118c2612469565b90600052602060002090600891828204019190066004026101000a81548163ffffffff021916908360e01c02179055508260016118ff9190612512565b7fffffffff000000000000000000000000000000000000000000000000000000009091166000908152602087905260409020555b7fffffffff0000000000000000000000000000000000000000000000000000000084166000908152602086905260408120556001850180548061197857611978612525565b60008281526020902060087fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191820401805463ffffffff600460078516026101000a0219169055905550600191506106859050565b506000610685565b7fffffffff0000000000000000000000000000000000000000000000000000000081166000908152602083905260408120546119d05750600182810180548083018255600082815260208082206008840401805463ffffffff60079095166004026101000a948502191660e088901c949094029390931790925591547fffffffff000000000000000000000000000000000000000000000000000000008516835290859052604090912055610685565b611a9182611d68565b604080517fffffffff00000000000000000000000000000000000000000000000000000000841660208083018290527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883850152835180840385018152606084018086528151919092012054919052915173ffffffffffffffffffffffffffffffffffffffff8481169316917f347b48699b991c95bb339a3a778222488794b19790e9f46171825933c63a9cc4919081900360800190a3604080517fffffffff00000000000000000000000000000000000000000000000000000000939093166020808501919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc8848301528151808503830181526060909401909152825192019190912055565b60606000611bc98385612512565b905083811015611c35576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6164646974696f6e206f766572666c6f77000000000000000000000000000000604482015260640161073d565b60018501548111611c465780611c4c565b60018501545b9050801580611c5b5750808410155b15611c665750611d61565b611c7084826124ff565b67ffffffffffffffff811115611c8857611c88612344565b604051908082528060200260200182016040528015611cb1578160200160208202803683370190505b50915060005b611cc185836124ff565b811015611d5e5760018601611cd68683612512565b81548110611ce657611ce6612469565b90600052602060002090600891828204019190066004029054906101000a900460e01b838281518110611d1b57611d1b612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280611d56816124c7565b915050611cb7565b50505b9392505050565b6000611d72611e5a565b805190915060005b81811015611e5457828181518110611d9457611d94612469565b60200260200101517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603611e42576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f66756e6374696f6e20696420616c726561647920657869737473000000000000604482015260640161073d565b80611e4c816124c7565b915050611d7a565b50505050565b604080516008808252610120820190925260609160009190602082016101008036833701905050905063dc9cc64560e01b81600081518110611e9e57611e9e612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517fd784d426000000000000000000000000000000000000000000000000000000009082906001908110611f0657611f06612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f0e1cf91b000000000000000000000000000000000000000000000000000000009082906002908110611f6e57611f6e612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517e33c04b000000000000000000000000000000000000000000000000000000009082906003908110611fd557611fd5612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517fcaaee91c00000000000000000000000000000000000000000000000000000000908290600490811061203d5761203d612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f1ab7710d0000000000000000000000000000000000000000000000000000000090829060059081106120a5576120a5612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f8456cb5900000000000000000000000000000000000000000000000000000000908290600690811061210d5761210d612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f3f4ba83a00000000000000000000000000000000000000000000000000000000908290600790811061217557612175612469565b7fffffffff0000000000000000000000000000000000000000000000000000000090921660209283029190910190910152919050565b600080602083850312156121be57600080fd5b823567ffffffffffffffff808211156121d657600080fd5b818501915085601f8301126121ea57600080fd5b8135818111156121f957600080fd5b86602082850101111561220b57600080fd5b60209290920196919550909350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e4457600080fd5b60006020828403121561225357600080fd5b611d618261221d565b60006020828403121561226e57600080fd5b813562ffffff81168114611d6157600080fd5b803560ff81168114610e4457600080fd5b6000602082840312156122a457600080fd5b611d6182612281565b6000602082840312156122bf57600080fd5b5035919050565b600080604083850312156122d957600080fd5b6122e283612281565b91506122f06020840161221d565b90509250929050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461075157600080fd5b60006020828403121561233957600080fd5b8135611d61816122f9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8051610e44816122f9565b6000806040838503121561239157600080fd5b825167ffffffffffffffff808211156123a957600080fd5b818501915085601f8301126123bd57600080fd5b81516020828211156123d1576123d1612344565b8160051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110868211171561241457612414612344565b60405292835281830193508481018201928984111561243257600080fd5b948201945b838610156124575761244886612373565b85529482019493820193612437565b97909101519698969750505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036124f8576124f8612498565b5060010190565b8181038181111561068557610685612498565b8082018082111561068557610685612498565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220baa4e6a5c992cd94607a99f04e80a0f38c585f60a6688a7da706e3f04726e06664736f6c63430008150033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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