ETH Price: $2,073.70 (+0.24%)

Contract

0xaB7794EcD2c8e9Decc6B577864b40eBf9204720f

Overview

ETH Balance

270 wei

ETH Value

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

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Settle Next Trad...164609662024-09-30 19:17:14176 days ago1727723834IN
0xaB7794Ec...f9204720f
0 ETH0.00001780.31
Settle Next Trad...164609582024-09-30 19:16:50176 days ago1727723810IN
0xaB7794Ec...f9204720f
0 ETH0.0000170.296
Settle Next Trad...164609502024-09-30 19:16:26176 days ago1727723786IN
0xaB7794Ec...f9204720f
0 ETH0.000082610.278
Withdraw From De...164596422024-09-30 18:10:42176 days ago1727719842IN
0xaB7794Ec...f9204720f
0 ETH0.000007930.27
Settle164583762024-09-30 17:06:59176 days ago1727716019IN
0xaB7794Ec...f9204720f
0 ETH0.000021880.282
Settle164583712024-09-30 17:06:44176 days ago1727716004IN
0xaB7794Ec...f9204720f
0 ETH0.000022040.297
Settle164583672024-09-30 17:06:32176 days ago1727715992IN
0xaB7794Ec...f9204720f
0 ETH0.000025450.303
Settle164583622024-09-30 17:06:17176 days ago1727715977IN
0xaB7794Ec...f9204720f
0 ETH0.00002470.294
Settle Next Trad...164583422024-09-30 17:05:16176 days ago1727715916IN
0xaB7794Ec...f9204720f
0 ETH0.000049640.278
Settle Next Trad...164583382024-09-30 17:05:04176 days ago1727715904IN
0xaB7794Ec...f9204720f
0 ETH0.000041890.278
Settle Next Trad...164583342024-09-30 17:04:52176 days ago1727715892IN
0xaB7794Ec...f9204720f
0 ETH0.000042950.285
Settle Next Trad...164583302024-09-30 17:04:41176 days ago1727715881IN
0xaB7794Ec...f9204720f
0 ETH0.000047150.281
Settle164580622024-09-30 16:51:07176 days ago1727715067IN
0xaB7794Ec...f9204720f
0 ETH0.000015410.262
Settle164580562024-09-30 16:50:49176 days ago1727715049IN
0xaB7794Ec...f9204720f
0 ETH0.000023740.26
Settle164580512024-09-30 16:50:34176 days ago1727715034IN
0xaB7794Ec...f9204720f
0 ETH0.000019590.264
Settle164580462024-09-30 16:50:19176 days ago1727715019IN
0xaB7794Ec...f9204720f
0 ETH0.000021920.261
Settle164580412024-09-30 16:50:05176 days ago1727715005IN
0xaB7794Ec...f9204720f
0 ETH0.000026890.266
Settle164580372024-09-30 16:49:53176 days ago1727714993IN
0xaB7794Ec...f9204720f
0 ETH0.000022340.266
Settle164580252024-09-30 16:49:17176 days ago1727714957IN
0xaB7794Ec...f9204720f
0 ETH0.000025380.278
Settle164580202024-09-30 16:49:01176 days ago1727714941IN
0xaB7794Ec...f9204720f
0 ETH0.000024190.265
Settle164580172024-09-30 16:48:52176 days ago1727714932IN
0xaB7794Ec...f9204720f
0 ETH0.000018110.264
Settle164580122024-09-30 16:48:37176 days ago1727714917IN
0xaB7794Ec...f9204720f
0 ETH0.0000190.256
Settle164580072024-09-30 16:48:22176 days ago1727714902IN
0xaB7794Ec...f9204720f
0 ETH0.000023740.26
Settle164580032024-09-30 16:48:10176 days ago1727714890IN
0xaB7794Ec...f9204720f
0 ETH0.000023560.258
Settle164579992024-09-30 16:47:58176 days ago1727714878IN
0xaB7794Ec...f9204720f
0 ETH0.000021850.255
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
149073072024-08-07 13:08:35230 days ago1723036115
0xaB7794Ec...f9204720f
2 wei
149073072024-08-07 13:08:35230 days ago1723036115
0xaB7794Ec...f9204720f
0xaB7794Ec...f9204720f
2 wei
149073062024-08-07 13:08:32230 days ago1723036112
0xaB7794Ec...f9204720f
2 wei
149073062024-08-07 13:08:32230 days ago1723036112
0xaB7794Ec...f9204720f
0xaB7794Ec...f9204720f
2 wei
149073042024-08-07 13:08:26230 days ago1723036106
0xaB7794Ec...f9204720f
2 wei
149073042024-08-07 13:08:26230 days ago1723036106
0xaB7794Ec...f9204720f
0xaB7794Ec...f9204720f
2 wei
149073032024-08-07 13:08:23230 days ago1723036103
0xaB7794Ec...f9204720f
2 wei
149073032024-08-07 13:08:23230 days ago1723036103
0xaB7794Ec...f9204720f
0xaB7794Ec...f9204720f
2 wei
149073022024-08-07 13:08:19230 days ago1723036099
0xaB7794Ec...f9204720f
2 wei
149073022024-08-07 13:08:19230 days ago1723036099
0xaB7794Ec...f9204720f
0xaB7794Ec...f9204720f
2 wei
149073012024-08-07 13:08:16230 days ago1723036096
0xaB7794Ec...f9204720f
2 wei
149073012024-08-07 13:08:16230 days ago1723036096
0xaB7794Ec...f9204720f
0xaB7794Ec...f9204720f
2 wei
149072992024-08-07 13:08:11230 days ago1723036091
0xaB7794Ec...f9204720f
2 wei
149072992024-08-07 13:08:11230 days ago1723036091
0xaB7794Ec...f9204720f
0xaB7794Ec...f9204720f
2 wei
149072982024-08-07 13:08:08230 days ago1723036088
0xaB7794Ec...f9204720f
2 wei
149072982024-08-07 13:08:08230 days ago1723036088
0xaB7794Ec...f9204720f
0xaB7794Ec...f9204720f
2 wei
149072972024-08-07 13:08:05230 days ago1723036085
0xaB7794Ec...f9204720f
2 wei
149072972024-08-07 13:08:05230 days ago1723036085
0xaB7794Ec...f9204720f
0xaB7794Ec...f9204720f
2 wei
149072952024-08-07 13:07:59230 days ago1723036079
0xaB7794Ec...f9204720f
2 wei
149072952024-08-07 13:07:59230 days ago1723036079
0xaB7794Ec...f9204720f
0xaB7794Ec...f9204720f
2 wei
149072942024-08-07 13:07:55230 days ago1723036075
0xaB7794Ec...f9204720f
2 wei
149072942024-08-07 13:07:55230 days ago1723036075
0xaB7794Ec...f9204720f
0xaB7794Ec...f9204720f
2 wei
149072932024-08-07 13:07:52230 days ago1723036072
0xaB7794Ec...f9204720f
2 wei
149072932024-08-07 13:07:52230 days ago1723036072
0xaB7794Ec...f9204720f
0xaB7794Ec...f9204720f
2 wei
149072922024-08-07 13:07:49230 days ago1723036069
0xaB7794Ec...f9204720f
2 wei
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PerpetualManagerProxy

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 400 runs

Other Settings:
default evmVersion
File 1 of 19 : PerpetualManagerProxy.sol
// 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;
    }
}

File 2 of 19 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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 Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing 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);
    }
}

File 3 of 19 : Proxy.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.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 overriden 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 internall 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 overriden should call `super._beforeFallback()`.
     */
    function _beforeFallback() internal virtual {}
}

File 4 of 19 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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 Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

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

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        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());
    }
}

File 5 of 19 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

        _;

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

File 6 of 19 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

File 7 of 19 : Maintainable.sol
// 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);
    }
}

File 8 of 19 : IShareTokenFactory.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.21;

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

File 9 of 19 : ABDKMath64x64.sol
// 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);
        }
    }
}

File 10 of 19 : ConverterDec18.sol
// 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);
    }
}

File 11 of 19 : EnumerableBytes4Set.sol
// 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];
    }
}

File 12 of 19 : EnumerableSetUpgradeable.sol
// 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));
    }
}

File 13 of 19 : Utils.sol
// 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
        uint64 iLastOpenTimestamp; // timestamp in seconds when the position was last opened/increased
        uint16 feeTbps; // exchange fee in tenth of a basis point
        uint16 brokerFeeTbps; // broker fee in tenth of a basis point
        bytes16 positionId; // unique id for the position (for given trader, and perpetual). Current position, zero otherwise.
    }

    /**
     * @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
        uint32 iLastSettlementPriceUpdateTimestamp; // timestamp when last price was observed happened
        uint32 iLastPriceJumpTimestamp; // timestamp when last price jump happened
        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 jumpSpreadTbps; // spread that is adjusted based on price jumps
        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
        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
        //-------
        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;
}
/* solhint-enable max-states-count */

File 15 of 19 : AMMPerpLogic.sol
// 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 half-spread that depends on past jumps
     * @dev if more than 30 seconds the function returns minimal spread.
     * Accuracy of this is obviously parametrization dependent
     * @param _jumpTbps    jump spread based on return of oracle price
     * @param _minimalSpreadTbps   minimal spread the EMA converges to
     * @param _numSecSinceJump    time passed since jump
     * @param _fLambda   convergence
     * @return fHalfSpread (int128)
     */
    function volatilitySpread(
        uint16 _jumpTbps,
        uint16 _minimalSpreadTbps,
        uint256 _numSecSinceJump,
        int128 _fLambda
    ) external pure returns (int128) {
        // v0 = (1-L**numBlocksSinceJump) * minimalSpread
        // v1 = jump*L**numBlocksSinceJump
        // return v0+v1
        if (_numSecSinceJump > 30) {
            return ConverterDec18.tbpsToABDK(_minimalSpreadTbps);
        }
        return _emaWithTimeJumps(_minimalSpreadTbps, _jumpTbps, _fLambda, _numSecSinceJump);
    }

    /**
     * Calculate the penalty for closing a position before the holding period is satisfied
     * @dev The penalty is 8 bps for same second and decreases exponentially to 0 at 32 seconds
     * @param _secondsSinceLastOpen how much time passed since the position was opened
     * @param _fLambda lambda for the exponential decay: penalty_nSeconds ~ lambda ^ nSeconds
     * @return penalty Penalty in tbps
     */
    function holdingPeriodPenalty(uint256 _secondsSinceLastOpen, int128 _fLambda)
        external
        pure
        returns (uint16 penalty)
    {
        if (_secondsSinceLastOpen > 32) {
            return 0;
        }
        penalty = ConverterDec18.ABDKToTbps(
            _emaWithTimeJumps(0, 80, _fLambda, _secondsSinceLastOpen)
        );
    }

    /**
     * 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);
        assert(_mktVars.fRho23 != 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();
    }
}

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

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

interface IAMMPerpLogic {
    function volatilitySpread(
        uint16 _jumpTbps,
        uint16 _MinimalSpreadTbps,
        uint256 _numBlockSinceJump,
        int128 _fLambda
    ) external pure returns (int128);

    function holdingPeriodPenalty(uint256 _numBlockSinceLastOpen, int128 _fLambda)
        external
        pure
        returns (uint16);

    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);
    event UpdateUnitAccumulatedFunding(uint24 perpetualId, int128 unitAccumulativeFunding);

    // 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
    );

    // funds
    event UpdateParticipationFundCash(
        uint8 indexed poolId,
        int128 fDeltaAmountCC,
        int128 fNewFundCash
    );
    event UpdateDefaultFundCash(uint8 indexed poolId, int128 fDeltaAmountCC, int128 fNewFundCash);

    // brokers
    event UpdateBrokerAddedCash(uint8 indexed poolId, uint32 iLots, uint32 iNewBrokerLots);
    event UpdateBrokerFundCash(uint8 indexed poolId, int128 fDeltaAmountCC, int128 fNewFundCash);

    // TradeModule

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

    event UpdateMarginAccount(
        uint24 indexed perpetualId,
        address indexed trader,
        bytes16 indexed positionId,
        int128 fPositionBC,
        int128 fCashCC,
        int128 fLockedInValueQC,
        int128 fFundingPaymentCC,
        int128 fOpenInterestBC
    );

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

    event TransferFeeToexecutor(
        uint24 indexed perpetualId,
        address indexed trader,
        address indexed executor,
        int128 referralRebate
    );
    event TransferFeeToBroker(uint24 indexed perpetualId, address indexed broker, int128 feeCC);

    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 UpdateAMMFundTargetSize(
        uint24 indexed perpetualId,
        uint8 indexed liquidityPoolId,
        int128 fTargetAMMFundSizeInPerpetual,
        int128 fTargetAMMFundSizeInPool
    );

    event UpdateDefaultFundTargetSize(
        uint8 indexed liquidityPoolId,
        int128 fDefaultFundCashCC,
        int128 fTargetDFSize
    );

    event UpdateReprTradeSizes(
        uint24 indexed perpetualId,
        int128 fCurrentTraderExposureEMA,
        int128 fCurrentAMMExposureEMAShort,
        int128 fCurrentAMMExposureEMALong
    );

    event TransferEarningsToTreasury(uint8 _poolId, int128 fEarnings, int128 newDefaultFundSize);

    event SetDelegate(address trader, address delegate);
}

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": 400
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "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":true,"internalType":"bytes16","name":"positionId","type":"bytes16"},{"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":false,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"address","name":"delegate","type":"address"}],"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"},{"indexed":true,"internalType":"bytes16","name":"positionId","type":"bytes16"},{"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":"uint8","name":"_poolId","type":"uint8"},{"indexed":false,"internalType":"int128","name":"fEarnings","type":"int128"},{"indexed":false,"internalType":"int128","name":"newDefaultFundSize","type":"int128"}],"name":"TransferEarningsToTreasury","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"broker","type":"address"},{"indexed":false,"internalType":"int128","name":"feeCC","type":"int128"}],"name":"TransferFeeToBroker","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"address","name":"executor","type":"address"},{"indexed":false,"internalType":"int128","name":"referralRebate","type":"int128"}],"name":"TransferFeeToexecutor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"uint8","name":"liquidityPoolId","type":"uint8"},{"indexed":false,"internalType":"int128","name":"fTargetAMMFundSizeInPerpetual","type":"int128"},{"indexed":false,"internalType":"int128","name":"fTargetAMMFundSizeInPool","type":"int128"}],"name":"UpdateAMMFundTargetSize","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":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"int128","name":"fDeltaAmountCC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fNewFundCash","type":"int128"}],"name":"UpdateBrokerFundCash","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"int128","name":"fDeltaAmountCC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fNewFundCash","type":"int128"}],"name":"UpdateDefaultFundCash","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"liquidityPoolId","type":"uint8"},{"indexed":false,"internalType":"int128","name":"fDefaultFundCashCC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fTargetDFSize","type":"int128"}],"name":"UpdateDefaultFundTargetSize","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":true,"internalType":"bytes16","name":"positionId","type":"bytes16"},{"indexed":false,"internalType":"int128","name":"fPositionBC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fCashCC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fLockedInValueQC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fFundingPaymentCC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fOpenInterestBC","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"int128","name":"fDeltaAmountCC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fNewFundCash","type":"int128"}],"name":"UpdateParticipationFundCash","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"int128","name":"fCurrentTraderExposureEMA","type":"int128"},{"indexed":false,"internalType":"int128","name":"fCurrentAMMExposureEMAShort","type":"int128"},{"indexed":false,"internalType":"int128","name":"fCurrentAMMExposureEMALong","type":"int128"}],"name":"UpdateReprTradeSizes","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"int128","name":"unitAccumulativeFunding","type":"int128"}],"name":"UpdateUnitAccumulatedFunding","type":"event"},{"stateMutability":"payable","type":"fallback"},{"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":"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":"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":"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"}]

608060405234801562000010575f80fd5b506200001c3362000048565b620000273362000097565b6001805460ff60a01b191681556002556200004233620000e8565b620001ab565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f2f3ffaaaad93928855c8700645d1a3643e6ccfdd500efa9fda048a88f557cf019190a35050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce80905f90a35050565b6001600160a01b038116620001435760405162461bcd60e51b815260206004820152601b60248201527f696e76616c69642070726f7879206f776e657220616464726573730000000000604482015260640160405180910390fd5b6001600160a01b038116620001645f80516020620018db8339815191525490565b6001600160a01b03167f5a3e66efaa1e445ebd894728a69d6959842ea1e97bd79b892797106e270efcd960405160405180910390a35f80516020620018db83398151915255565b61172280620001b95f395ff3fe6080604052600436106100d4575f3560e01c80638456cb591161007e578063caaee91c11610058578063caaee91c1461020f578063d38bfff41461022e578063d784d4261461024d578063dc9cc6451461026c576100e3565b80638456cb59146101c05780639850d32b146101d4578063bffd952a146101f0576100e3565b80633f4ba83a116100af5780633f4ba83a146101665780635aa6e6751461017a5780635c975abb14610197576100e3565b806233c04b146100eb5780630e1cf91b146101275780631ab7710d14610146576100e3565b366100e3576100e161028b565b005b6100e161028b565b3480156100f6575f80fd5b5061010a6101053660046114a9565b61029d565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610132575f80fd5b506100e1610141366004611515565b610301565b348015610151575f80fd5b505f805160206116cd8339815191525461010a565b348015610171575f80fd5b506100e1610379565b348015610185575f80fd5b506001546001600160a01b031661010a565b3480156101a2575f80fd5b50600154600160a01b900460ff16604051901515815260200161011e565b3480156101cb575f80fd5b506100e161042b565b3480156101df575f80fd5b505f546001600160a01b031661010a565b3480156101fb575f80fd5b506100e161020a366004611515565b6104da565b34801561021a575f80fd5b506100e1610229366004611515565b610574565b348015610239575f80fd5b506100e1610248366004611515565b6105e2565b348015610258575f80fd5b506100e1610267366004611515565b61067c565b348015610277575f80fd5b5061010a610286366004611550565b6106eb565b61029b6102966106f5565b610768565b565b5f60125f6102df85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061078692505050565b815260208101919091526040015f20546001600160a01b031690505b92915050565b5f805160206116cd833981519152546001600160a01b0316336001600160a01b03161461036b5760405162461bcd60e51b8152602060048201526013602482015272141c9bde1e4e9858d8d95cdcc819195b9a5959606a1b60448201526064015b60405180910390fd5b6103768160016107a3565b50565b600154600160a01b900460ff166103c95760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610362565b336103db5f546001600160a01b031690565b6001600160a01b0316146104235760405162461bcd60e51b815260206004820152600f60248201526e37b7363c9036b0b4b73a30b4b732b960891b6044820152606401610362565b61029b610aff565b600154600160a01b900460ff16156104785760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610362565b3361048a5f546001600160a01b031690565b6001600160a01b0316146104d25760405162461bcd60e51b815260206004820152600f60248201526e37b7363c9036b0b4b73a30b4b732b960891b6044820152606401610362565b61029b610b9c565b6001546001600160a01b031633146105265760405162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b6044820152606401610362565b6001600160a01b03811661056b5760405162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b6044820152606401610362565b61037681610c24565b5f805160206116cd833981519152546001600160a01b0316336001600160a01b0316146105d95760405162461bcd60e51b8152602060048201526013602482015272141c9bde1e4e9858d8d95cdcc819195b9a5959606a1b6044820152606401610362565b61037681610c73565b6001546001600160a01b0316331461062e5760405162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b6044820152606401610362565b6001600160a01b0381166106735760405162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b6044820152606401610362565b61037681610d2e565b5f805160206116cd833981519152546001600160a01b0316336001600160a01b0316146106e15760405162461bcd60e51b8152602060048201526013602482015272141c9bde1e4e9858d8d95cdcc819195b9a5959606a1b6044820152606401610362565b610376815f6107a3565b5f6102fb82610d7f565b5f8061070b5f356001600160e01b031916610d7f565b90506001600160a01b0381166107635760405162461bcd60e51b815260206004820152601e60248201527f50726f78793a496d706c656d656e746174696f6e206e6f7420666f756e6400006044820152606401610362565b919050565b365f80375f80365f845af43d5f803e808015610782573d5ff35b3d5ffd5b80515f908290820361079a57505f92915050565b50506020015190565b6001600160a01b0382166107f95760405162461bcd60e51b815260206004820152601e60248201527f696e76616c696420696d706c656d656e746174696f6e206164647265737300006044820152606401610362565b5f80836001600160a01b0316633e6b8c0d6040518163ffffffff1660e01b81526004015f60405180830381865afa158015610836573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261085d919081019061158a565b9092509050806108af5760405162461bcd60e51b815260206004820152601b60248201527f4d6f64756c65206e616d652063616e6e6f7420626520656d70747900000000006044820152606401610362565b5f81815260116020526040812090806108c9836001015490565b8551911091505f5b81811015610a23575f8682815181106108ec576108ec611652565b6020026020010151905061092287838151811061090b5761090b611652565b602002602001015186610dd890919063ffffffff16565b6109ed575f61093082610d7f565b90506001600160a01b038116156109be578861098e5760405162461bcd60e51b815260206004820152601a60248201527f63616e74207265706c616365206d6f64756c65732066756e63730000000000006044820152606401610362565b6001600160a01b0381165f908152601360209081526040808320548352601190915290206109bc9083610df6565b505b6109ea8884815181106109d3576109d3611652565b602002602001015187610f6790919063ffffffff16565b50505b610a10878381518110610a0257610a02611652565b60200260200101518a610fe5565b5080610a1b8161167a565b9150506108d1565b508115610abc575f610a425f610a3a866001015490565b8691906110a6565b9050805191505f5b82811015610ab9575f828281518110610a6557610a65611652565b60200260200101519050896001600160a01b0316610a8282610d7f565b6001600160a01b031614610aa657610a9a815f610fe5565b610aa48682610df6565b505b5080610ab18161167a565b915050610a4a565b50505b5050505f81815260126020908152604080832080546001600160a01b039098166001600160a01b0319909816881790559582526013905293909320929092555050565b600154600160a01b900460ff16610b4f5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610362565b6001805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b600154600160a01b900460ff1615610be95760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610362565b6001805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610b7f3390565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f2f3ffaaaad93928855c8700645d1a3643e6ccfdd500efa9fda048a88f557cf019190a35050565b6001600160a01b038116610cc95760405162461bcd60e51b815260206004820152601b60248201527f696e76616c69642070726f7879206f776e6572206164647265737300000000006044820152606401610362565b806001600160a01b0316610ce85f805160206116cd8339815191525490565b6001600160a01b03167f5a3e66efaa1e445ebd894728a69d6959842ea1e97bd79b892797106e270efcd960405160405180910390a35f805160206116cd83398151915255565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce80905f90a35050565b604080516001600160e01b0319929092166020808401919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883830152815180840383018152606090930190915281519101205490565b6001600160e01b0319165f9081526020919091526040902054151590565b6001600160e01b031981165f9081526020839052604081205415610f60576001600160e01b031982165f90815260208490526040812054610e3990600190611692565b6001858101549192505f91610e4e9190611692565b9050818114610efc575f856001018281548110610e6d57610e6d611652565b905f5260205f2090600891828204019190066004029054906101000a900460e01b905080866001018481548110610ea657610ea6611652565b905f5260205f2090600891828204019190066004026101000a81548163ffffffff021916908360e01c0217905550826001610ee191906116a5565b6001600160e01b03199091165f908152602087905260409020555b6001600160e01b031984165f9081526020869052604081205560018501805480610f2857610f286116b8565b5f8281526020902060085f1990920191820401805463ffffffff600460078516026101000a0219169055905550600191506102fb9050565b505f6102fb565b6001600160e01b031981165f90815260208390526040812054610f6057506001828101805480830182555f82815260208082206008840401805463ffffffff60079095166004026101000a948502191660e088901c949094029390931790925591546001600160e01b031985168352908590526040909120556102fb565b610fee8261121d565b806001600160a01b031661100183610d7f565b6040516001600160e01b0319851681526001600160a01b0391909116907f347b48699b991c95bb339a3a778222488794b19790e9f46171825933c63a9cc49060200160405180910390a3604080516001600160e01b0319939093166020808501919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc8848301528151808503830181526060909401909152825192019190912055565b60605f6110b383856116a5565b9050838110156111055760405162461bcd60e51b815260206004820152601160248201527f6164646974696f6e206f766572666c6f770000000000000000000000000000006044820152606401610362565b60018501548111611116578061111c565b60018501545b905080158061112b5750808410155b156111365750611216565b6111408482611692565b67ffffffffffffffff8111156111585761115861156b565b604051908082528060200260200182016040528015611181578160200160208202803683370190505b5091505f5b6111908583611692565b81101561121357600186016111a586836116a5565b815481106111b5576111b5611652565b905f5260205f2090600891828204019190066004029054906101000a900460e01b8382815181106111e8576111e8611652565b6001600160e01b0319909216602092830291909101909101528061120b8161167a565b915050611186565b50505b9392505050565b5f6112266112c9565b80519091505f5b818110156112c35782818151811061124757611247611652565b60200260200101516001600160e01b031916846001600160e01b031916036112b15760405162461bcd60e51b815260206004820152601a60248201527f66756e6374696f6e20696420616c7265616479206578697374730000000000006044820152606401610362565b806112bb8161167a565b91505061122d565b50505050565b60408051600880825261012082019092526060915f9190602082016101008036833701905050905063dc9cc64560e01b815f8151811061130b5761130b611652565b6001600160e01b0319909216602092830291909101909101528051636bc26a1360e11b908290600190811061134257611342611652565b6001600160e01b0319909216602092830291909101909101528051630e1cf91b60e01b908290600290811061137957611379611652565b6001600160e01b03199092166020928302919091019091015280516233c04b60e01b90829060039081106113af576113af611652565b6001600160e01b03199092166020928302919091019091015280516332abba4760e21b90829060049081106113e6576113e6611652565b6001600160e01b0319909216602092830291909101909101528051631ab7710d60e01b908290600590811061141d5761141d611652565b6001600160e01b0319909216602092830291909101909101528051638456cb5960e01b908290600690811061145457611454611652565b6001600160e01b0319909216602092830291909101909101528051631fa5d41d60e11b908290600790811061148b5761148b611652565b6001600160e01b031990921660209283029190910190910152919050565b5f80602083850312156114ba575f80fd5b823567ffffffffffffffff808211156114d1575f80fd5b818501915085601f8301126114e4575f80fd5b8135818111156114f2575f80fd5b866020828501011115611503575f80fd5b60209290920196919550909350505050565b5f60208284031215611525575f80fd5b81356001600160a01b0381168114611216575f80fd5b6001600160e01b031981168114610376575f80fd5b5f60208284031215611560575f80fd5b81356112168161153b565b634e487b7160e01b5f52604160045260245ffd5b80516107638161153b565b5f806040838503121561159b575f80fd5b825167ffffffffffffffff808211156115b2575f80fd5b818501915085601f8301126115c5575f80fd5b81516020828211156115d9576115d961156b565b8160051b604051601f19603f830116810181811086821117156115fe576115fe61156b565b60405292835281830193508481018201928984111561161b575f80fd5b948201945b83861015611640576116318661157f565b85529482019493820193611620565b97909101519698969750505050505050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f6001820161168b5761168b611666565b5060010190565b818103818111156102fb576102fb611666565b808201808211156102fb576102fb611666565b634e487b7160e01b5f52603160045260245ffdfeb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d8a264697066735822122090e7122bc8d3ea42235cdf8d59d4687ca19d2c41d243027e640f1c695b907a2664736f6c63430008150033b5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d8

Deployed Bytecode

0x6080604052600436106100d4575f3560e01c80638456cb591161007e578063caaee91c11610058578063caaee91c1461020f578063d38bfff41461022e578063d784d4261461024d578063dc9cc6451461026c576100e3565b80638456cb59146101c05780639850d32b146101d4578063bffd952a146101f0576100e3565b80633f4ba83a116100af5780633f4ba83a146101665780635aa6e6751461017a5780635c975abb14610197576100e3565b806233c04b146100eb5780630e1cf91b146101275780631ab7710d14610146576100e3565b366100e3576100e161028b565b005b6100e161028b565b3480156100f6575f80fd5b5061010a6101053660046114a9565b61029d565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610132575f80fd5b506100e1610141366004611515565b610301565b348015610151575f80fd5b505f805160206116cd8339815191525461010a565b348015610171575f80fd5b506100e1610379565b348015610185575f80fd5b506001546001600160a01b031661010a565b3480156101a2575f80fd5b50600154600160a01b900460ff16604051901515815260200161011e565b3480156101cb575f80fd5b506100e161042b565b3480156101df575f80fd5b505f546001600160a01b031661010a565b3480156101fb575f80fd5b506100e161020a366004611515565b6104da565b34801561021a575f80fd5b506100e1610229366004611515565b610574565b348015610239575f80fd5b506100e1610248366004611515565b6105e2565b348015610258575f80fd5b506100e1610267366004611515565b61067c565b348015610277575f80fd5b5061010a610286366004611550565b6106eb565b61029b6102966106f5565b610768565b565b5f60125f6102df85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061078692505050565b815260208101919091526040015f20546001600160a01b031690505b92915050565b5f805160206116cd833981519152546001600160a01b0316336001600160a01b03161461036b5760405162461bcd60e51b8152602060048201526013602482015272141c9bde1e4e9858d8d95cdcc819195b9a5959606a1b60448201526064015b60405180910390fd5b6103768160016107a3565b50565b600154600160a01b900460ff166103c95760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610362565b336103db5f546001600160a01b031690565b6001600160a01b0316146104235760405162461bcd60e51b815260206004820152600f60248201526e37b7363c9036b0b4b73a30b4b732b960891b6044820152606401610362565b61029b610aff565b600154600160a01b900460ff16156104785760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610362565b3361048a5f546001600160a01b031690565b6001600160a01b0316146104d25760405162461bcd60e51b815260206004820152600f60248201526e37b7363c9036b0b4b73a30b4b732b960891b6044820152606401610362565b61029b610b9c565b6001546001600160a01b031633146105265760405162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b6044820152606401610362565b6001600160a01b03811661056b5760405162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b6044820152606401610362565b61037681610c24565b5f805160206116cd833981519152546001600160a01b0316336001600160a01b0316146105d95760405162461bcd60e51b8152602060048201526013602482015272141c9bde1e4e9858d8d95cdcc819195b9a5959606a1b6044820152606401610362565b61037681610c73565b6001546001600160a01b0316331461062e5760405162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b6044820152606401610362565b6001600160a01b0381166106735760405162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b6044820152606401610362565b61037681610d2e565b5f805160206116cd833981519152546001600160a01b0316336001600160a01b0316146106e15760405162461bcd60e51b8152602060048201526013602482015272141c9bde1e4e9858d8d95cdcc819195b9a5959606a1b6044820152606401610362565b610376815f6107a3565b5f6102fb82610d7f565b5f8061070b5f356001600160e01b031916610d7f565b90506001600160a01b0381166107635760405162461bcd60e51b815260206004820152601e60248201527f50726f78793a496d706c656d656e746174696f6e206e6f7420666f756e6400006044820152606401610362565b919050565b365f80375f80365f845af43d5f803e808015610782573d5ff35b3d5ffd5b80515f908290820361079a57505f92915050565b50506020015190565b6001600160a01b0382166107f95760405162461bcd60e51b815260206004820152601e60248201527f696e76616c696420696d706c656d656e746174696f6e206164647265737300006044820152606401610362565b5f80836001600160a01b0316633e6b8c0d6040518163ffffffff1660e01b81526004015f60405180830381865afa158015610836573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261085d919081019061158a565b9092509050806108af5760405162461bcd60e51b815260206004820152601b60248201527f4d6f64756c65206e616d652063616e6e6f7420626520656d70747900000000006044820152606401610362565b5f81815260116020526040812090806108c9836001015490565b8551911091505f5b81811015610a23575f8682815181106108ec576108ec611652565b6020026020010151905061092287838151811061090b5761090b611652565b602002602001015186610dd890919063ffffffff16565b6109ed575f61093082610d7f565b90506001600160a01b038116156109be578861098e5760405162461bcd60e51b815260206004820152601a60248201527f63616e74207265706c616365206d6f64756c65732066756e63730000000000006044820152606401610362565b6001600160a01b0381165f908152601360209081526040808320548352601190915290206109bc9083610df6565b505b6109ea8884815181106109d3576109d3611652565b602002602001015187610f6790919063ffffffff16565b50505b610a10878381518110610a0257610a02611652565b60200260200101518a610fe5565b5080610a1b8161167a565b9150506108d1565b508115610abc575f610a425f610a3a866001015490565b8691906110a6565b9050805191505f5b82811015610ab9575f828281518110610a6557610a65611652565b60200260200101519050896001600160a01b0316610a8282610d7f565b6001600160a01b031614610aa657610a9a815f610fe5565b610aa48682610df6565b505b5080610ab18161167a565b915050610a4a565b50505b5050505f81815260126020908152604080832080546001600160a01b039098166001600160a01b0319909816881790559582526013905293909320929092555050565b600154600160a01b900460ff16610b4f5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610362565b6001805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b600154600160a01b900460ff1615610be95760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610362565b6001805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610b7f3390565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f2f3ffaaaad93928855c8700645d1a3643e6ccfdd500efa9fda048a88f557cf019190a35050565b6001600160a01b038116610cc95760405162461bcd60e51b815260206004820152601b60248201527f696e76616c69642070726f7879206f776e6572206164647265737300000000006044820152606401610362565b806001600160a01b0316610ce85f805160206116cd8339815191525490565b6001600160a01b03167f5a3e66efaa1e445ebd894728a69d6959842ea1e97bd79b892797106e270efcd960405160405180910390a35f805160206116cd83398151915255565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce80905f90a35050565b604080516001600160e01b0319929092166020808401919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883830152815180840383018152606090930190915281519101205490565b6001600160e01b0319165f9081526020919091526040902054151590565b6001600160e01b031981165f9081526020839052604081205415610f60576001600160e01b031982165f90815260208490526040812054610e3990600190611692565b6001858101549192505f91610e4e9190611692565b9050818114610efc575f856001018281548110610e6d57610e6d611652565b905f5260205f2090600891828204019190066004029054906101000a900460e01b905080866001018481548110610ea657610ea6611652565b905f5260205f2090600891828204019190066004026101000a81548163ffffffff021916908360e01c0217905550826001610ee191906116a5565b6001600160e01b03199091165f908152602087905260409020555b6001600160e01b031984165f9081526020869052604081205560018501805480610f2857610f286116b8565b5f8281526020902060085f1990920191820401805463ffffffff600460078516026101000a0219169055905550600191506102fb9050565b505f6102fb565b6001600160e01b031981165f90815260208390526040812054610f6057506001828101805480830182555f82815260208082206008840401805463ffffffff60079095166004026101000a948502191660e088901c949094029390931790925591546001600160e01b031985168352908590526040909120556102fb565b610fee8261121d565b806001600160a01b031661100183610d7f565b6040516001600160e01b0319851681526001600160a01b0391909116907f347b48699b991c95bb339a3a778222488794b19790e9f46171825933c63a9cc49060200160405180910390a3604080516001600160e01b0319939093166020808501919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc8848301528151808503830181526060909401909152825192019190912055565b60605f6110b383856116a5565b9050838110156111055760405162461bcd60e51b815260206004820152601160248201527f6164646974696f6e206f766572666c6f770000000000000000000000000000006044820152606401610362565b60018501548111611116578061111c565b60018501545b905080158061112b5750808410155b156111365750611216565b6111408482611692565b67ffffffffffffffff8111156111585761115861156b565b604051908082528060200260200182016040528015611181578160200160208202803683370190505b5091505f5b6111908583611692565b81101561121357600186016111a586836116a5565b815481106111b5576111b5611652565b905f5260205f2090600891828204019190066004029054906101000a900460e01b8382815181106111e8576111e8611652565b6001600160e01b0319909216602092830291909101909101528061120b8161167a565b915050611186565b50505b9392505050565b5f6112266112c9565b80519091505f5b818110156112c35782818151811061124757611247611652565b60200260200101516001600160e01b031916846001600160e01b031916036112b15760405162461bcd60e51b815260206004820152601a60248201527f66756e6374696f6e20696420616c7265616479206578697374730000000000006044820152606401610362565b806112bb8161167a565b91505061122d565b50505050565b60408051600880825261012082019092526060915f9190602082016101008036833701905050905063dc9cc64560e01b815f8151811061130b5761130b611652565b6001600160e01b0319909216602092830291909101909101528051636bc26a1360e11b908290600190811061134257611342611652565b6001600160e01b0319909216602092830291909101909101528051630e1cf91b60e01b908290600290811061137957611379611652565b6001600160e01b03199092166020928302919091019091015280516233c04b60e01b90829060039081106113af576113af611652565b6001600160e01b03199092166020928302919091019091015280516332abba4760e21b90829060049081106113e6576113e6611652565b6001600160e01b0319909216602092830291909101909101528051631ab7710d60e01b908290600590811061141d5761141d611652565b6001600160e01b0319909216602092830291909101909101528051638456cb5960e01b908290600690811061145457611454611652565b6001600160e01b0319909216602092830291909101909101528051631fa5d41d60e11b908290600790811061148b5761148b611652565b6001600160e01b031990921660209283029190910190910152919050565b5f80602083850312156114ba575f80fd5b823567ffffffffffffffff808211156114d1575f80fd5b818501915085601f8301126114e4575f80fd5b8135818111156114f2575f80fd5b866020828501011115611503575f80fd5b60209290920196919550909350505050565b5f60208284031215611525575f80fd5b81356001600160a01b0381168114611216575f80fd5b6001600160e01b031981168114610376575f80fd5b5f60208284031215611560575f80fd5b81356112168161153b565b634e487b7160e01b5f52604160045260245ffd5b80516107638161153b565b5f806040838503121561159b575f80fd5b825167ffffffffffffffff808211156115b2575f80fd5b818501915085601f8301126115c5575f80fd5b81516020828211156115d9576115d961156b565b8160051b604051601f19603f830116810181811086821117156115fe576115fe61156b565b60405292835281830193508481018201928984111561161b575f80fd5b948201945b83861015611640576116318661157f565b85529482019493820193611620565b97909101519698969750505050505050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f6001820161168b5761168b611666565b5060010190565b818103818111156102fb576102fb611666565b808201808211156102fb576102fb611666565b634e487b7160e01b5f52603160045260245ffdfeb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d8a264697066735822122090e7122bc8d3ea42235cdf8d59d4687ca19d2c41d243027e640f1c695b907a2664736f6c63430008150033

Block Transaction Gas Used Reward
view all blocks sequenced

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

Validator Index Block Amount
View All Withdrawals

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

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