More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
4081700 | 15 mins ago | 1 wei | ||||
4081700 | 15 mins ago | 1 wei | ||||
4081700 | 15 mins ago | 1 wei | ||||
4081700 | 15 mins ago | 1 wei | ||||
4081694 | 16 mins ago | 1 wei | ||||
4081694 | 16 mins ago | 1 wei | ||||
4080683 | 49 mins ago | 1 wei | ||||
4080683 | 49 mins ago | 1 wei | ||||
4079586 | 1 hr ago | 1 wei | ||||
4079586 | 1 hr ago | 1 wei | ||||
4079586 | 1 hr ago | 1 wei | ||||
4079586 | 1 hr ago | 1 wei | ||||
4078368 | 2 hrs ago | 1 wei | ||||
4078368 | 2 hrs ago | 1 wei | ||||
4078368 | 2 hrs ago | 1 wei | ||||
4078368 | 2 hrs ago | 1 wei | ||||
4078367 | 2 hrs ago | 1 wei | ||||
4078367 | 2 hrs ago | 1 wei | ||||
4078362 | 2 hrs ago | 1 wei | ||||
4078362 | 2 hrs ago | 1 wei | ||||
4077983 | 2 hrs ago | 1 wei | ||||
4077983 | 2 hrs ago | 1 wei | ||||
4077983 | 2 hrs ago | 1 wei | ||||
4077983 | 2 hrs ago | 1 wei | ||||
4077959 | 2 hrs ago | 1 wei |
Loading...
Loading
Contract Name:
PerpetualManagerProxy
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 100000000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.21; import "@openzeppelin/contracts/proxy/Proxy.sol"; import "./PerpStorage.sol"; import "../interfaces/ILibraryEvents.sol"; import "../interfaces/IFunctionList.sol"; import "../../libraries/EnumerableBytes4Set.sol"; import "../../libraries/Utils.sol"; contract PerpetualManagerProxy is PerpStorage, Proxy, ILibraryEvents { using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set; bytes32 private constant KEY_IMPLEMENTATION = keccak256("key.implementation"); bytes32 private constant KEY_OWNER = keccak256("key.proxy.owner"); event ProxyOwnershipTransferred(address indexed _oldOwner, address indexed _newOwner); event ImplementationChanged( bytes4 _sig, address indexed _oldImplementation, address indexed _newImplementation ); /** * @notice Set sender as an owner. */ constructor() { _setProxyOwner(msg.sender); } /** * @notice Throw error if called not by an owner. */ modifier onlyProxyOwner() { require(msg.sender == getProxyOwner(), "Proxy:access denied"); _; } function _implementation() internal view override returns (address) { address implementation = _getImplementation(msg.sig); require(implementation != address(0), "Proxy:Implementation not found"); return implementation; } function getImplementation(bytes4 _sig) external view returns (address) { return _getImplementation(_sig); } function _getImplementation(bytes4 _sig) internal view returns (address) { bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION)); address implementation; // solhint-disable-next-line no-inline-assembly assembly { implementation := sload(key) } return implementation; } /// @dev to delete module deploy a dummy module with the same name in getFunctionList() as being deleted /// it will remove all previous implementation functions function setImplementation(address _impl) external onlyProxyOwner { _setImplementation(_impl, false); } ///@dev allows replacement of functions from other modules. Use only if you realize consequences. function setImplementationCrossModules(address _impl) external onlyProxyOwner { _setImplementation(_impl, true); } ///@param _impl module address ///@param replaceOtherModulesFuncs allow to replace functions of other modules, use with caution function _setImplementation(address _impl, bool replaceOtherModulesFuncs) internal { require(_impl != address(0), "invalid implementation address"); (bytes4[] memory functions, bytes32 moduleName) = IFunctionList(_impl).getFunctionList(); require(moduleName != bytes32(0), "Module name cannot be empty"); EnumerableBytes4Set.Bytes4Set storage moduleActiveFunctionsSet = moduleActiveFuncSignatureList[moduleName]; bool moduleIsBeingUpdated = moduleActiveFunctionsSet.length() > 0; uint256 length = functions.length; for (uint256 i = 0; i < length; i++) { bytes4 funcSig = functions[i]; if (!moduleActiveFunctionsSet.contains(functions[i])) { // if the function registered with another module address anotherModuleImplAddress = _getImplementation(funcSig); if (anotherModuleImplAddress != address(0)) { require(replaceOtherModulesFuncs, "cant replace modules funcs"); moduleActiveFuncSignatureList[ moduleAddressToModuleName[anotherModuleImplAddress] ].removeBytes4(funcSig); } moduleActiveFunctionsSet.addBytes4(functions[i]); } _setImplementation(functions[i], _impl); } /// remove functions of the previous module version if (moduleIsBeingUpdated) { bytes4[] memory moduleActiveFuncsArray = moduleActiveFunctionsSet.enumerate( 0, moduleActiveFunctionsSet.length() ); length = moduleActiveFuncsArray.length; for (uint256 i; i < length; i++) { bytes4 funcSig = moduleActiveFuncsArray[i]; if (_getImplementation(funcSig) != _impl) { _setImplementation(funcSig, address(0)); moduleActiveFunctionsSet.removeBytes4(funcSig); } } } moduleNameToAddress[moduleName] = _impl; moduleAddressToModuleName[_impl] = moduleName; } function getModuleImplementationAddress(string calldata _moduleName) external view returns (address) { return moduleNameToAddress[Utils.stringToBytes32(_moduleName)]; } function _setImplementation(bytes4 _sig, address _impl) internal { _checkClashing(_sig); emit ImplementationChanged(_sig, _getImplementation(_sig), _impl); bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION)); // solhint-disable-next-line no-inline-assembly assembly { sstore(key, _impl) } } /** * @notice Set address of the owner. * @param _owner Address of the owner. * */ function setProxyOwner(address _owner) external onlyProxyOwner { _setProxyOwner(_owner); } function _setProxyOwner(address _owner) internal { require(_owner != address(0), "invalid proxy owner address"); emit ProxyOwnershipTransferred(getProxyOwner(), _owner); bytes32 key = KEY_OWNER; // solhint-disable-next-line no-inline-assembly assembly { sstore(key, _owner) } } /** * @notice Return address of the owner. * @return _owner Address of the owner. */ function getProxyOwner() public view returns (address _owner) { bytes32 key = KEY_OWNER; // solhint-disable-next-line no-inline-assembly assembly { _owner := sload(key) } } function _checkClashing(bytes4 _sig) internal pure { bytes4[] memory functionList = _getFunctionList(); uint256 length = functionList.length; for (uint256 i = 0; i < length; i++) { require(_sig != functionList[i], "function id already exists"); } } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function pause() external whenNotPaused onlyMaintainer { _pause(); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function unpause() external virtual whenPaused onlyMaintainer { _unpause(); } function _getFunctionList() internal pure returns (bytes4[] memory) { bytes4[] memory functionList = new bytes4[](8); functionList[0] = this.getImplementation.selector; functionList[1] = this.setImplementation.selector; functionList[2] = this.setImplementationCrossModules.selector; functionList[3] = this.getModuleImplementationAddress.selector; functionList[4] = this.setProxyOwner.selector; functionList[5] = this.getProxyOwner.selector; functionList[6] = this.pause.selector; functionList[7] = this.unpause.selector; return functionList; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol) pragma solidity ^0.8.0; /** * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to * be specified by overriding the virtual {_implementation} function. * * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a * different contract through the {_delegate} function. * * The success and return data of the delegated call will be returned back to the caller of the proxy. */ abstract contract Proxy { /** * @dev Delegates the current call to `implementation`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _delegate(address implementation) internal virtual { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function * and {_fallback} should delegate. */ function _implementation() internal view virtual returns (address); /** * @dev Delegates the current call to the address returned by `_implementation()`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _fallback() internal virtual { _beforeFallback(); _delegate(_implementation()); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other * function in the contract matches the call data. */ fallback() external payable virtual { _fallback(); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data * is empty. */ receive() external payable virtual { _fallback(); } /** * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` * call, or as part of the Solidity `fallback` or `receive` functions. * * If overridden should call `super._beforeFallback()`. */ function _beforeFallback() internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) // D8X, 2022 pragma solidity 0.8.21; /** * This is a modified version of the OpenZeppelin ownable contract * Modifications * - instead of an owner, we have two actors: maintainer and governance * - maintainer can have certain priviledges but cannot transfer maintainer mandate * - governance can exchange maintainer and exchange itself * - renounceOwnership is removed * * * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Maintainable { address private _maintainer; address private _governance; event MaintainerTransferred(address indexed previousMaintainer, address indexed newMaintainer); event GovernanceTransferred(address indexed previousGovernance, address indexed newGovernance); /** * @dev Initializes the contract setting the deployer as the initial maintainer. */ constructor() { _transferMaintainer(msg.sender); _transferGovernance(msg.sender); } /** * @dev Returns the address of the current owner. */ function maintainer() public view virtual returns (address) { return _maintainer; } /** * @dev Returns the address of the governance. */ function governance() public view virtual returns (address) { return _governance; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyMaintainer() { require(maintainer() == msg.sender, "only maintainer"); _; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyGovernance() { require(governance() == msg.sender, "only governance"); _; } /** * @dev Transfers maintainer mandate of the contract to a new account (`newMaintainer`). * Can only be called by the governance. */ function transferMaintainer(address newMaintainer) public virtual { require(msg.sender == _governance, "only governance"); require(newMaintainer != address(0), "zero address"); _transferMaintainer(newMaintainer); } /** * @dev Transfers governance mandate of the contract to a new account (`newGovernance`). * Can only be called by the governance. */ function transferGovernance(address newGovernance) public virtual { require(msg.sender == _governance, "only governance"); require(newGovernance != address(0), "zero address"); _transferGovernance(newGovernance); } /** * @dev Transfers maintainer of the contract to a new account (`newMaintainer`). * Internal function without access restriction. */ function _transferMaintainer(address newMaintainer) internal virtual { address oldM = _maintainer; _maintainer = newMaintainer; emit MaintainerTransferred(oldM, newMaintainer); } /** * @dev Transfers governance of the contract to a new account (`newGovernance`). * Internal function without access restriction. */ function _transferGovernance(address newGovernance) internal virtual { address oldG = _governance; _governance = newGovernance; emit GovernanceTransferred(oldG, newGovernance); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.21; interface IShareTokenFactory { function createShareToken(uint8 _poolId, address _marginTokenAddr) external returns (address); }
// SPDX-License-Identifier: BSD-4-Clause /* * ABDK Math 64.64 Smart Contract Library. Copyright © 2019 by ABDK Consulting. * Author: Mikhail Vladimirov <[email protected]> */ pragma solidity 0.8.21; /** * Smart contract library of mathematical functions operating with signed * 64.64-bit fixed point numbers. Signed 64.64-bit fixed point number is * basically a simple fraction whose numerator is signed 128-bit integer and * denominator is 2^64. As long as denominator is always the same, there is no * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are * represented by int128 type holding only the numerator. */ library ABDKMath64x64 { /* * Minimum value signed 64.64-bit fixed point number may have. */ int128 private constant MIN_64x64 = -0x80000000000000000000000000000000; /* * Maximum value signed 64.64-bit fixed point number may have. */ int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; /** * Convert signed 256-bit integer number into signed 64.64-bit fixed point * number. Revert on overflow. * * @param x signed 256-bit integer number * @return signed 64.64-bit fixed point number */ function fromInt(int256 x) internal pure returns (int128) { require(x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF, "ABDK.fromInt"); return int128(x << 64); } /** * Convert signed 64.64 fixed point number into signed 64-bit integer number * rounding down. * * @param x signed 64.64-bit fixed point number * @return signed 64-bit integer number */ function toInt(int128 x) internal pure returns (int64) { return int64(x >> 64); } /** * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point * number. Revert on overflow. * * @param x unsigned 256-bit integer number * @return signed 64.64-bit fixed point number */ function fromUInt(uint256 x) internal pure returns (int128) { require(x <= 0x7FFFFFFFFFFFFFFF, "ABDK.fromUInt"); return int128(int256(x << 64)); } /** * Convert signed 64.64 fixed point number into unsigned 64-bit integer * number rounding down. Revert on underflow. * * @param x signed 64.64-bit fixed point number * @return unsigned 64-bit integer number */ function toUInt(int128 x) internal pure returns (uint64) { require(x >= 0, "ABDK.toUInt"); return uint64(uint128(x >> 64)); } /** * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point * number rounding down. Revert on overflow. * * @param x signed 128.128-bin fixed point number * @return signed 64.64-bit fixed point number */ function from128x128(int256 x) internal pure returns (int128) { int256 result = x >> 64; require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.from128x128"); return int128(result); } /** * Convert signed 64.64 fixed point number into signed 128.128 fixed point * number. * * @param x signed 64.64-bit fixed point number * @return signed 128.128 fixed point number */ function to128x128(int128 x) internal pure returns (int256) { return int256(x) << 64; } /** * Calculate x + y. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function add(int128 x, int128 y) internal pure returns (int128) { int256 result = int256(x) + y; require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.add"); return int128(result); } /** * Calculate x - y. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function sub(int128 x, int128 y) internal pure returns (int128) { int256 result = int256(x) - y; require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.sub"); return int128(result); } /** * Calculate x * y rounding down. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function mul(int128 x, int128 y) internal pure returns (int128) { int256 result = (int256(x) * y) >> 64; require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.mul"); return int128(result); } /** * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point * number and y is signed 256-bit integer number. Revert on overflow. * * @param x signed 64.64 fixed point number * @param y signed 256-bit integer number * @return signed 256-bit integer number */ function muli(int128 x, int256 y) internal pure returns (int256) { if (x == MIN_64x64) { require( y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF && y <= 0x1000000000000000000000000000000000000000000000000, "ABDK.muli-1" ); return -y << 63; } else { bool negativeResult = false; if (x < 0) { x = -x; negativeResult = true; } if (y < 0) { y = -y; // We rely on overflow behavior here negativeResult = !negativeResult; } uint256 absoluteResult = mulu(x, uint256(y)); if (negativeResult) { require( absoluteResult <= 0x8000000000000000000000000000000000000000000000000000000000000000, "ABDK.muli-2" ); return -int256(absoluteResult); // We rely on overflow behavior here } else { require( absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "ABDK.muli-3" ); return int256(absoluteResult); } } } /** * Calculate x * y rounding down, where x is signed 64.64 fixed point number * and y is unsigned 256-bit integer number. Revert on overflow. * * @param x signed 64.64 fixed point number * @param y unsigned 256-bit integer number * @return unsigned 256-bit integer number */ function mulu(int128 x, uint256 y) internal pure returns (uint256) { if (y == 0) return 0; require(x >= 0, "ABDK.mulu-1"); uint256 lo = (uint256(int256(x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64; uint256 hi = uint256(int256(x)) * (y >> 128); require(hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "ABDK.mulu-2"); hi <<= 64; require( hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo, "ABDK.mulu-3" ); return hi + lo; } /** * Calculate x / y rounding towards zero. Revert on overflow or when y is * zero. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function div(int128 x, int128 y) internal pure returns (int128) { require(y != 0, "ABDK.div-1"); int256 result = (int256(x) << 64) / y; require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.div-2"); return int128(result); } /** * Calculate x / y rounding towards zero, where x and y are signed 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x signed 256-bit integer number * @param y signed 256-bit integer number * @return signed 64.64-bit fixed point number */ function divi(int256 x, int256 y) internal pure returns (int128) { require(y != 0, "ABDK.divi-1"); bool negativeResult = false; if (x < 0) { x = -x; // We rely on overflow behavior here negativeResult = true; } if (y < 0) { y = -y; // We rely on overflow behavior here negativeResult = !negativeResult; } uint128 absoluteResult = divuu(uint256(x), uint256(y)); if (negativeResult) { require(absoluteResult <= 0x80000000000000000000000000000000, "ABDK.divi-2"); return -int128(absoluteResult); // We rely on overflow behavior here } else { require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "ABDK.divi-3"); return int128(absoluteResult); // We rely on overflow behavior here } } /** * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x unsigned 256-bit integer number * @param y unsigned 256-bit integer number * @return signed 64.64-bit fixed point number */ function divu(uint256 x, uint256 y) internal pure returns (int128) { require(y != 0, "ABDK.divu-1"); uint128 result = divuu(x, y); require(result <= uint128(MAX_64x64), "ABDK.divu-2"); return int128(result); } /** * Calculate -x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function neg(int128 x) internal pure returns (int128) { require(x != MIN_64x64, "ABDK.neg"); return -x; } /** * Calculate |x|. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function abs(int128 x) internal pure returns (int128) { require(x != MIN_64x64, "ABDK.abs"); return x < 0 ? -x : x; } /** * Calculate 1 / x rounding towards zero. Revert on overflow or when x is * zero. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function inv(int128 x) internal pure returns (int128) { require(x != 0, "ABDK.inv-1"); int256 result = int256(0x100000000000000000000000000000000) / x; require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.inv-2"); return int128(result); } /** * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function avg(int128 x, int128 y) internal pure returns (int128) { return int128((int256(x) + int256(y)) >> 1); } /** * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down. * Revert on overflow or in case x * y is negative. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function gavg(int128 x, int128 y) internal pure returns (int128) { int256 m = int256(x) * int256(y); require(m >= 0, "ABDK.gavg-1"); require( m < 0x4000000000000000000000000000000000000000000000000000000000000000, "ABDK.gavg-2" ); return int128(sqrtu(uint256(m))); } /** * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number * and y is unsigned 256-bit integer number. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y uint256 value * @return signed 64.64-bit fixed point number */ function pow(int128 x, uint256 y) internal pure returns (int128) { bool negative = x < 0 && y & 1 == 1; uint256 absX = uint128(x < 0 ? -x : x); uint256 absResult; absResult = 0x100000000000000000000000000000000; if (absX <= 0x10000000000000000) { absX <<= 63; while (y != 0) { if (y & 0x1 != 0) { absResult = (absResult * absX) >> 127; } absX = (absX * absX) >> 127; if (y & 0x2 != 0) { absResult = (absResult * absX) >> 127; } absX = (absX * absX) >> 127; if (y & 0x4 != 0) { absResult = (absResult * absX) >> 127; } absX = (absX * absX) >> 127; if (y & 0x8 != 0) { absResult = (absResult * absX) >> 127; } absX = (absX * absX) >> 127; y >>= 4; } absResult >>= 64; } else { uint256 absXShift = 63; if (absX < 0x1000000000000000000000000) { absX <<= 32; absXShift -= 32; } if (absX < 0x10000000000000000000000000000) { absX <<= 16; absXShift -= 16; } if (absX < 0x1000000000000000000000000000000) { absX <<= 8; absXShift -= 8; } if (absX < 0x10000000000000000000000000000000) { absX <<= 4; absXShift -= 4; } if (absX < 0x40000000000000000000000000000000) { absX <<= 2; absXShift -= 2; } if (absX < 0x80000000000000000000000000000000) { absX <<= 1; absXShift -= 1; } uint256 resultShift; while (y != 0) { require(absXShift < 64, "ABDK.pow-1"); if (y & 0x1 != 0) { absResult = (absResult * absX) >> 127; resultShift += absXShift; if (absResult > 0x100000000000000000000000000000000) { absResult >>= 1; resultShift += 1; } } absX = (absX * absX) >> 127; absXShift <<= 1; if (absX >= 0x100000000000000000000000000000000) { absX >>= 1; absXShift += 1; } y >>= 1; } require(resultShift < 64, "ABDK.pow-2"); absResult >>= 64 - resultShift; } int256 result = negative ? -int256(absResult) : int256(absResult); require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.pow-3"); return int128(result); } /** * Calculate sqrt (x) rounding down. Revert if x < 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function sqrt(int128 x) internal pure returns (int128) { require(x >= 0, "ABDK.sqrt"); return int128(sqrtu(uint256(int256(x)) << 64)); } /** * Calculate binary logarithm of x. Revert if x <= 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function log_2(int128 x) internal pure returns (int128) { require(x > 0, "ABDK.log_2"); int256 msb; int256 xc = x; if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; } if (xc >= 0x100000000) { xc >>= 32; msb += 32; } if (xc >= 0x10000) { xc >>= 16; msb += 16; } if (xc >= 0x100) { xc >>= 8; msb += 8; } if (xc >= 0x10) { xc >>= 4; msb += 4; } if (xc >= 0x4) { xc >>= 2; msb += 2; } if (xc >= 0x2) msb += 1; // No need to shift xc anymore int256 result = (msb - 64) << 64; uint256 ux = uint256(int256(x)) << uint256(127 - msb); for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) { ux *= ux; uint256 b = ux >> 255; ux >>= 127 + b; result += bit * int256(b); } return int128(result); } /** * Calculate natural logarithm of x. Revert if x <= 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function ln(int128 x) internal pure returns (int128) { unchecked { require(x > 0, "ABDK.ln"); return int128( int256((uint256(int256(log_2(x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF) >> 128) ); } } /** * Calculate binary exponent of x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function exp_2(int128 x) internal pure returns (int128) { require(x < 0x400000000000000000, "ABDK.exp_2-1"); // Overflow if (x < -0x400000000000000000) return 0; // Underflow uint256 result = 0x80000000000000000000000000000000; if (x & 0x8000000000000000 > 0) result = (result * 0x16A09E667F3BCC908B2FB1366EA957D3E) >> 128; if (x & 0x4000000000000000 > 0) result = (result * 0x1306FE0A31B7152DE8D5A46305C85EDEC) >> 128; if (x & 0x2000000000000000 > 0) result = (result * 0x1172B83C7D517ADCDF7C8C50EB14A791F) >> 128; if (x & 0x1000000000000000 > 0) result = (result * 0x10B5586CF9890F6298B92B71842A98363) >> 128; if (x & 0x800000000000000 > 0) result = (result * 0x1059B0D31585743AE7C548EB68CA417FD) >> 128; if (x & 0x400000000000000 > 0) result = (result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8) >> 128; if (x & 0x200000000000000 > 0) result = (result * 0x10163DA9FB33356D84A66AE336DCDFA3F) >> 128; if (x & 0x100000000000000 > 0) result = (result * 0x100B1AFA5ABCBED6129AB13EC11DC9543) >> 128; if (x & 0x80000000000000 > 0) result = (result * 0x10058C86DA1C09EA1FF19D294CF2F679B) >> 128; if (x & 0x40000000000000 > 0) result = (result * 0x1002C605E2E8CEC506D21BFC89A23A00F) >> 128; if (x & 0x20000000000000 > 0) result = (result * 0x100162F3904051FA128BCA9C55C31E5DF) >> 128; if (x & 0x10000000000000 > 0) result = (result * 0x1000B175EFFDC76BA38E31671CA939725) >> 128; if (x & 0x8000000000000 > 0) result = (result * 0x100058BA01FB9F96D6CACD4B180917C3D) >> 128; if (x & 0x4000000000000 > 0) result = (result * 0x10002C5CC37DA9491D0985C348C68E7B3) >> 128; if (x & 0x2000000000000 > 0) result = (result * 0x1000162E525EE054754457D5995292026) >> 128; if (x & 0x1000000000000 > 0) result = (result * 0x10000B17255775C040618BF4A4ADE83FC) >> 128; if (x & 0x800000000000 > 0) result = (result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB) >> 128; if (x & 0x400000000000 > 0) result = (result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9) >> 128; if (x & 0x200000000000 > 0) result = (result * 0x10000162E43F4F831060E02D839A9D16D) >> 128; if (x & 0x100000000000 > 0) result = (result * 0x100000B1721BCFC99D9F890EA06911763) >> 128; if (x & 0x80000000000 > 0) result = (result * 0x10000058B90CF1E6D97F9CA14DBCC1628) >> 128; if (x & 0x40000000000 > 0) result = (result * 0x1000002C5C863B73F016468F6BAC5CA2B) >> 128; if (x & 0x20000000000 > 0) result = (result * 0x100000162E430E5A18F6119E3C02282A5) >> 128; if (x & 0x10000000000 > 0) result = (result * 0x1000000B1721835514B86E6D96EFD1BFE) >> 128; if (x & 0x8000000000 > 0) result = (result * 0x100000058B90C0B48C6BE5DF846C5B2EF) >> 128; if (x & 0x4000000000 > 0) result = (result * 0x10000002C5C8601CC6B9E94213C72737A) >> 128; if (x & 0x2000000000 > 0) result = (result * 0x1000000162E42FFF037DF38AA2B219F06) >> 128; if (x & 0x1000000000 > 0) result = (result * 0x10000000B17217FBA9C739AA5819F44F9) >> 128; if (x & 0x800000000 > 0) result = (result * 0x1000000058B90BFCDEE5ACD3C1CEDC823) >> 128; if (x & 0x400000000 > 0) result = (result * 0x100000002C5C85FE31F35A6A30DA1BE50) >> 128; if (x & 0x200000000 > 0) result = (result * 0x10000000162E42FF0999CE3541B9FFFCF) >> 128; if (x & 0x100000000 > 0) result = (result * 0x100000000B17217F80F4EF5AADDA45554) >> 128; if (x & 0x80000000 > 0) result = (result * 0x10000000058B90BFBF8479BD5A81B51AD) >> 128; if (x & 0x40000000 > 0) result = (result * 0x1000000002C5C85FDF84BD62AE30A74CC) >> 128; if (x & 0x20000000 > 0) result = (result * 0x100000000162E42FEFB2FED257559BDAA) >> 128; if (x & 0x10000000 > 0) result = (result * 0x1000000000B17217F7D5A7716BBA4A9AE) >> 128; if (x & 0x8000000 > 0) result = (result * 0x100000000058B90BFBE9DDBAC5E109CCE) >> 128; if (x & 0x4000000 > 0) result = (result * 0x10000000002C5C85FDF4B15DE6F17EB0D) >> 128; if (x & 0x2000000 > 0) result = (result * 0x1000000000162E42FEFA494F1478FDE05) >> 128; if (x & 0x1000000 > 0) result = (result * 0x10000000000B17217F7D20CF927C8E94C) >> 128; if (x & 0x800000 > 0) result = (result * 0x1000000000058B90BFBE8F71CB4E4B33D) >> 128; if (x & 0x400000 > 0) result = (result * 0x100000000002C5C85FDF477B662B26945) >> 128; if (x & 0x200000 > 0) result = (result * 0x10000000000162E42FEFA3AE53369388C) >> 128; if (x & 0x100000 > 0) result = (result * 0x100000000000B17217F7D1D351A389D40) >> 128; if (x & 0x80000 > 0) result = (result * 0x10000000000058B90BFBE8E8B2D3D4EDE) >> 128; if (x & 0x40000 > 0) result = (result * 0x1000000000002C5C85FDF4741BEA6E77E) >> 128; if (x & 0x20000 > 0) result = (result * 0x100000000000162E42FEFA39FE95583C2) >> 128; if (x & 0x10000 > 0) result = (result * 0x1000000000000B17217F7D1CFB72B45E1) >> 128; if (x & 0x8000 > 0) result = (result * 0x100000000000058B90BFBE8E7CC35C3F0) >> 128; if (x & 0x4000 > 0) result = (result * 0x10000000000002C5C85FDF473E242EA38) >> 128; if (x & 0x2000 > 0) result = (result * 0x1000000000000162E42FEFA39F02B772C) >> 128; if (x & 0x1000 > 0) result = (result * 0x10000000000000B17217F7D1CF7D83C1A) >> 128; if (x & 0x800 > 0) result = (result * 0x1000000000000058B90BFBE8E7BDCBE2E) >> 128; if (x & 0x400 > 0) result = (result * 0x100000000000002C5C85FDF473DEA871F) >> 128; if (x & 0x200 > 0) result = (result * 0x10000000000000162E42FEFA39EF44D91) >> 128; if (x & 0x100 > 0) result = (result * 0x100000000000000B17217F7D1CF79E949) >> 128; if (x & 0x80 > 0) result = (result * 0x10000000000000058B90BFBE8E7BCE544) >> 128; if (x & 0x40 > 0) result = (result * 0x1000000000000002C5C85FDF473DE6ECA) >> 128; if (x & 0x20 > 0) result = (result * 0x100000000000000162E42FEFA39EF366F) >> 128; if (x & 0x10 > 0) result = (result * 0x1000000000000000B17217F7D1CF79AFA) >> 128; if (x & 0x8 > 0) result = (result * 0x100000000000000058B90BFBE8E7BCD6D) >> 128; if (x & 0x4 > 0) result = (result * 0x10000000000000002C5C85FDF473DE6B2) >> 128; if (x & 0x2 > 0) result = (result * 0x1000000000000000162E42FEFA39EF358) >> 128; if (x & 0x1 > 0) result = (result * 0x10000000000000000B17217F7D1CF79AB) >> 128; result >>= uint256(int256(63 - (x >> 64))); require(result <= uint256(int256(MAX_64x64)), "ABDK.exp_2-2"); return int128(int256(result)); } /** * Calculate natural exponent of x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function exp(int128 x) internal pure returns (int128) { require(x < 0x400000000000000000, "ABDK.exp"); // Overflow if (x < -0x400000000000000000) return 0; // Underflow return exp_2(int128((int256(x) * 0x171547652B82FE1777D0FFDA0D23A7D12) >> 128)); } /** * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x unsigned 256-bit integer number * @param y unsigned 256-bit integer number * @return unsigned 64.64-bit fixed point number */ function divuu(uint256 x, uint256 y) private pure returns (uint128) { require(y != 0, "ABDK.divuu-1"); uint256 result; if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) result = (x << 64) / y; else { uint256 msb = 192; uint256 xc = x >> 192; if (xc >= 0x100000000) { xc >>= 32; msb += 32; } if (xc >= 0x10000) { xc >>= 16; msb += 16; } if (xc >= 0x100) { xc >>= 8; msb += 8; } if (xc >= 0x10) { xc >>= 4; msb += 4; } if (xc >= 0x4) { xc >>= 2; msb += 2; } if (xc >= 0x2) msb += 1; // No need to shift xc anymore result = (x << (255 - msb)) / (((y - 1) >> (msb - 191)) + 1); require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "ABDK.divuu-2"); uint256 hi = result * (y >> 128); uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); uint256 xh = x >> 192; uint256 xl = x << 64; if (xl < lo) xh -= 1; xl -= lo; // We rely on overflow behavior here lo = hi << 128; if (xl < lo) xh -= 1; xl -= lo; // We rely on overflow behavior here assert(xh == hi >> 128); result += xl / y; } require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "ABDK.divuu-3"); return uint128(result); } /** * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer * number. * * @param x unsigned 256-bit integer number * @return unsigned 128-bit integer number */ function sqrtu(uint256 x) private pure returns (uint128) { if (x == 0) return 0; else { uint256 xx = x; uint256 r = 1; if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; } if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; } if (xx >= 0x100000000) { xx >>= 32; r <<= 16; } if (xx >= 0x10000) { xx >>= 16; r <<= 8; } if (xx >= 0x100) { xx >>= 8; r <<= 4; } if (xx >= 0x10) { xx >>= 4; r <<= 2; } if (xx >= 0x8) { r <<= 1; } r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; // Seven iterations should be enough uint256 r1 = x / r; return uint128(r < r1 ? r : r1); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.21; import "./ABDKMath64x64.sol"; library ConverterDec18 { using ABDKMath64x64 for int128; /* * Minimum value signed 64.64-bit fixed point number may have. */ int128 private constant MIN_64x64 = -0x80000000000000000000000000000000; /* * Maximum value signed 64.64-bit fixed point number may have. */ int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; int256 private constant DECIMALS = 10**18; int128 private constant ONE_64x64 = 0x010000000000000000; int128 public constant HALF_TBPS = 92233720368548; //1e-5 * 0.5 * 2**64 int128 public constant HALF_BPS = 922337203685478; //1e-4 * 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 basis point to ABDK 64x64: int128 public constant BPSTOABDK = 0x68db8bac710cb; // hex(2^64 * 10^-4) // 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 bpsToABDK(uint16 Vtbps) internal pure returns (int128) { return int128(uint128(BPSTOABDK) * 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 ABDKToBps(int128 Vabdk) internal pure returns (uint16) { // add 0.5 * 1e-4 to ensure correct rounding to tenth of bps return uint16(uint128(Vabdk.add(HALF_BPS) / BPSTOABDK)); } function fromDec18(int256 x) internal pure returns (int128) { int256 result = (x * ONE_64x64) / DECIMALS; require(x >= MIN_64x64 && x <= MAX_64x64, "result out of range"); return int128(result); } function toDec18(int128 x) internal pure returns (int256) { return (int256(x) * DECIMALS) / ONE_64x64; } function toUDec18(int128 x) internal pure returns (uint256) { require(x >= 0, "negative value"); return uint256(toDec18(x)); } function toUDecN(int128 x, uint8 decimals) internal pure returns (uint256) { require(x >= 0, "negative value"); return uint256((int256(x) * int256(10**decimals)) / ONE_64x64); } function fromDecN(int256 x, uint8 decimals) internal pure returns (int128) { int256 result = (x * ONE_64x64) / int256(10**decimals); require(x >= MIN_64x64 && x <= MAX_64x64, "result out of range"); return int128(result); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.21; /** * @title Library for managing loan sets. * * @notice Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * Include with `using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set;`. * */ library EnumerableBytes4Set { struct Bytes4Set { // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes4 => uint256) index; bytes4[] values; } /** * @notice Add a value to a set. O(1). * * @param set The set of values. * @param value The new value to add. * * @return False if the value was already in the set. */ function addBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) { if (!contains(set, value)) { set.values.push(value); set.index[value] = set.values.length; return true; } else { return false; } } /** * @notice Remove a value from a set. O(1). * * @param set The set of values. * @param value The value to remove. * * @return False if the value was not present in the set. */ function removeBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) { if (contains(set, value)) { uint256 toDeleteIndex = set.index[value] - 1; uint256 lastIndex = set.values.length - 1; /// If the element we're deleting is the last one, /// we can just remove it without doing a swap. if (lastIndex != toDeleteIndex) { bytes4 lastValue = set.values[lastIndex]; /// Move the last value to the index where the deleted value is. set.values[toDeleteIndex] = lastValue; /// Update the index for the moved value. set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based } /// Delete the index entry for the deleted value. delete set.index[value]; /// Delete the old entry for the moved value. set.values.pop(); return true; } else { return false; } } /** * @notice Find out whether a value exists in the set. * * @param set The set of values. * @param value The value to find. * * @return True if the value is in the set. O(1). */ function contains(Bytes4Set storage set, bytes4 value) internal view returns (bool) { return set.index[value] != 0; } /** * @notice Get all set values. * * @param set The set of values. * @param start The offset of the returning set. * @param count The limit of number of values to return. * * @return output An array with all values in the set. O(N). * * @dev Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * WARNING: This function may run out of gas on large sets: use {length} and * {get} instead in these cases. */ function enumerate( Bytes4Set storage set, uint256 start, uint256 count ) internal view returns (bytes4[] memory output) { uint256 end = start + count; require(end >= start, "addition overflow"); end = set.values.length < end ? set.values.length : end; if (end == 0 || start >= end) { return output; } output = new bytes4[](end - start); for (uint256 i; i < end - start; i++) { output[i] = set.values[i + start]; } return output; } /** * @notice Get the legth of the set. * * @param set The set of values. * * @return the number of elements on the set. O(1). */ function length(Bytes4Set storage set) internal view returns (uint256) { return set.values.length; } /** * @notice Get an item from the set by its index. * * @dev Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. * * @param set The set of values. * @param index The index of the value to return. * * @return the element stored at position `index` in the set. O(1). */ function get(Bytes4Set storage set, uint256 index) internal view returns (bytes4) { return set.values[index]; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.21; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSetUpgradeable { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { require(set._values.length > index, "EnumerableSet: idx out of bounds"); return set._values[index]; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } function enumerate( AddressSet storage set, uint256 start, uint256 count ) internal view returns (address[] memory output) { uint256 end = start + count; require(end >= start, "addition overflow"); uint256 len = length(set); end = len < end ? len : end; if (end == 0 || start >= end) { return output; } output = new address[](end - start); for (uint256 i; i < end - start; i++) { output[i] = at(set, i + start); } return output; } function enumerateAll(AddressSet storage set) internal view returns (address[] memory output) { return enumerate(set, 0, length(set)); } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.21; library Utils { function stringToBytes32(string memory source) internal pure returns (bytes32 result) { bytes memory tempEmptyStringTest = bytes(source); if (tempEmptyStringTest.length == 0) { return 0x0; } assembly { result := mload(add(source, 32)) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.21; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/security/Pausable.sol"; import "../../interface/IShareTokenFactory.sol"; import "../../libraries/ABDKMath64x64.sol"; import "./../functions/AMMPerpLogic.sol"; import "../../libraries/EnumerableSetUpgradeable.sol"; import "../../libraries/EnumerableBytes4Set.sol"; import "../../governance/Maintainable.sol"; /* solhint-disable max-states-count */ contract PerpStorage is Maintainable, Pausable, ReentrancyGuard { using ABDKMath64x64 for int128; using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set; // enumerable map of bytes4 or addresses /** * @notice Perpetual state: * - INVALID: Uninitialized or not non-existent perpetual. * - INITIALIZING: Only when LiquidityPoolData.isRunning == false. Traders cannot perform operations. * - NORMAL: Full functional state. Traders are able to perform all operations. * - EMERGENCY: Perpetual is unsafe and the perpetual needs to be settled. * - SETTLE: Perpetual ready to be settled * - CLEARED: All margin accounts are cleared. Traders can withdraw remaining margin balance. */ enum PerpetualState { INVALID, INITIALIZING, NORMAL, EMERGENCY, SETTLE, CLEARED } // margin and liquidity pool are held in 'collateral currency' which can be either of // quote currency, base currency, or quanto currency // solhint-disable-next-line const-name-snakecase int128 internal constant ONE_64x64 = 0x10000000000000000; // 2^64 int128 internal constant FUNDING_INTERVAL_SEC = 0x70800000000000000000; //3600 * 8 * 0x10000000000000000 = 8h in seconds scaled by 2^64 for ABDKMath64x64 int128 internal constant MIN_NUM_LOTS_PER_POSITION = 0x0a0000000000000000; // 10, minimal position size in number of lots uint8 internal constant MASK_ORDER_CANCELLED = 0x1; uint8 internal constant MASK_ORDER_EXECUTED = 0x2; // at target, 1% of missing amount is transferred // at every rebalance uint8 internal iPoolCount; // delay required for trades to mitigate oracle front-running in seconds uint8 internal iTradeDelaySec; address internal ammPerpLogic; IShareTokenFactory internal shareTokenFactory; //pool id (incremental index, starts from 1) => pool data mapping(uint8 => LiquidityPoolData) internal liquidityPools; //perpetual id => pool id mapping(uint24 => uint8) internal perpetualPoolIds; address internal orderBookFactory; /** * @notice Data structure to store oracle price data. */ struct PriceTimeData { int128 fPrice; uint64 time; } /** * @notice Data structure to store user margin information. */ struct MarginAccount { int128 fLockedInValueQC; // unrealized value locked-in when trade occurs int128 fCashCC; // cash in collateral currency (base, quote, or quanto) int128 fPositionBC; // position in base currency (e.g., 1 BTC for BTCUSD) int128 fUnitAccumulatedFundingStart; // accumulated funding rate } /** * @notice Store information for a given perpetual market. */ struct PerpetualData { // ------ 0 uint8 poolId; uint24 id; int32 fInitialMarginRate; //parameter: initial margin int32 fSigma2; // parameter: volatility of base-quote pair uint32 iLastFundingTime; //timestamp since last funding rate payment int32 fDFCoverNRate; // parameter: cover-n rule for default fund. E.g., fDFCoverNRate=0.05 -> we try to cover 5% of active accounts with default fund int32 fMaintenanceMarginRate; // parameter: maintenance margin PerpetualState state; // Perpetual AMM state AMMPerpLogic.CollateralCurrency eCollateralCurrency; //parameter: in what currency is the collateral held? // ------ 1 bytes4 S2BaseCCY; //base currency of S2 bytes4 S2QuoteCCY; //quote currency of S2 uint16 incentiveSpreadTbps; //parameter: maximum spread added to the PD uint16 minimalSpreadBps; //parameter: minimal spread between long and short perpetual price, in basis points 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 weight 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: referral 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), or for prediction markets the maturity ts int128 perpFlags; // flags for the perpetual //------- 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 fParams; //used as total margin balance for for settlement (in collateral currency), otherwise slippage params int32 fMarkPriceEMALambda; // parameter: Lambda parameter for EMA used in mark-price for funding rates int32 fFundingRateClamp; // parameter: funding rate clamp between which we charge 1bps int32 fMaximalTradeSizeBumpUp; // parameter: >1, users can create a maximal position of size fMaximalTradeSizeBumpUp*fCurrentAMMExposureEMA uint32 iLastTargetPoolSizeTime; //timestamp (seconds) since last update of fTargetDFSize and fTargetAMMFundSize //------- 12 //------- int128[2] fStressReturnS3; // parameter: negative and positive stress returns for quanto-quote asset int128[2] fDFLambda; // parameter: EMA lambda for AMM and trader exposure K,k: EMA*lambda + (1-lambda)*K. 0 regular lambda, 1 if current value exceeds past int128[2] fCurrentAMMExposureEMA; // 0: negative aggregated exposure (storing negative value), 1: positive int128[2] fStressReturnS2; // parameter: negative and positive stress returns for base-quote asset // ----- } address internal oracleFactoryAddress; // users mapping(uint24 => EnumerableSetUpgradeable.AddressSet) internal activeAccounts; //perpetualId => traderAddressSet // accounts mapping(uint24 => mapping(address => MarginAccount)) internal marginAccounts; // delegates mapping(address => address) internal delegates; // broker maps: poolId -> brokeraddress-> lots contributed // contains non-zero entries for brokers. Brokers pay default fund contributions. mapping(uint8 => mapping(address => uint32)) internal brokerMap; struct LiquidityPoolData { bool isRunning; // state uint8 iPerpetualCount; // state uint8 id; // parameter: index, starts from 1 int32 fCeilPnLShare; // parameter: cap on the share of PnL allocated to liquidity providers uint8 marginTokenDecimals; // parameter: decimals of margin token, inferred from token contract uint16 iTargetPoolSizeUpdateTime; //parameter: timestamp in seconds. How often we update the pool's target size address marginTokenAddress; //parameter: address of the margin token // ----- uint64 prevAnchor; // state: keep track of timestamp since last withdrawal was initiated int128 fRedemptionRate; // state: used for settlement in case of AMM default address shareTokenAddress; // parameter // ----- int128 fPnLparticipantsCashCC; // state: addLiquidity/withdrawLiquidity + profit/loss - rebalance int128 fTargetAMMFundSize; // state: target liquidity for all perpetuals in pool (sum of weights) // ----- int128 fDefaultFundCashCC; // state: profit/loss int128 fTargetDFSize; // state: target default fund size for all perpetuals in pool // ----- int128 fBrokerCollateralLotSize; // param:how much collateral do brokers deposit when providing "1 lot" (not trading lot) uint128 prevTokenAmount; // state // ----- uint128 nextTokenAmount; // state uint128 totalSupplyShareToken; // state // ----- int128 fBrokerFundCashCC; // state: amount of cash in broker fund } address internal treasuryAddress; // address for the protocol treasury //pool id => perpetual id list mapping(uint8 => uint24[]) internal perpetualIds; //pool id => perpetual id => data mapping(uint8 => mapping(uint24 => PerpetualData)) internal perpetuals; /// @dev flag whether MarginTradeOrder was already executed or cancelled mapping(bytes32 => uint8) internal executedOrCancelledOrders; //proxy mapping(bytes32 => EnumerableBytes4Set.Bytes4Set) internal moduleActiveFuncSignatureList; mapping(bytes32 => address) internal moduleNameToAddress; mapping(address => bytes32) internal moduleAddressToModuleName; // fee structure struct VolumeEMA { int128 fTradingVolumeEMAusd; //trading volume EMA in usd uint64 timestamp; // timestamp of last trade } uint256[] public traderVolumeTiers; // dec18, regardless of token uint256[] public brokerVolumeTiers; // dec18, regardless of token uint16[] public traderVolumeFeesTbps; uint16[] public brokerVolumeFeesTbps; mapping(uint24 => address) public perpBaseToUSDOracle; mapping(uint24 => int128) public perpToLastBaseToUSD; mapping(uint8 => mapping(address => VolumeEMA)) public traderVolumeEMA; mapping(uint8 => mapping(address => VolumeEMA)) public brokerVolumeEMA; uint64 public lastBaseToUSDUpdateTs; // liquidity withdrawals struct WithdrawRequest { address lp; uint256 shareTokens; uint64 withdrawTimestamp; } mapping(address => mapping(uint8 => WithdrawRequest)) internal lpWithdrawMap; // users who initiated withdrawals are registered here mapping(uint8 => EnumerableSetUpgradeable.AddressSet) internal activeWithdrawals; //poolId => lpAddressSet mapping(uint8 => bool) public liquidityProvisionIsPaused; } /* solhint-enable max-states-count */
// SPDX-License-Identifier: MIT pragma solidity 0.8.21; import "../../libraries/ABDKMath64x64.sol"; import "../../libraries/ConverterDec18.sol"; import "../../perpetual/interfaces/IAMMPerpLogic.sol"; contract AMMPerpLogic is 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 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¶ms) * @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¶ms) * @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¶ms) * @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¶ms) * @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¶ms) * Trader amounts k2 must already be factored in * that is, K2:=K2+k2, L1:=L1+k2*s2 * @param _fTradeAmount 64.64-bit fixed point number, signed size of trade * @param _fHBidAskSpread half bid-ask spread, 64.64-bit fixed point number * @return 64.64-bit fixed point number, AMM price */ function calculatePerpetualPrice( AMMVariables memory _ammVars, MarketVariables memory _mktVars, int128 _fTradeAmount, int128 _fHBidAskSpread, int128 _fIncentiveSpread ) external view virtual override returns (int128) { // add minimal spread in quote currency _fHBidAskSpread = _fTradeAmount > 0 ? _fHBidAskSpread : _fHBidAskSpread.neg(); if (_fTradeAmount == 0) { _fHBidAskSpread = 0; } // get risk-neutral default probability (always >0) { int128 fQ; int128 dd; int128 fkStar = _ammVars.fPoolM2.sub(_ammVars.fAMM_K2); (fQ, dd) = _calculateRiskNeutralPD(_ammVars, _mktVars, _fTradeAmount, true); if (_ammVars.fPoolM3 != 0) { // amend K* (see whitepaper) int128 nominator = _mktVars.fRho23.mul(_mktVars.fSigma2.mul(_mktVars.fSigma3)); int128 denom = _mktVars.fSigma2.mul(_mktVars.fSigma2); int128 h = nominator.div(denom).mul(_ammVars.fPoolM3); h = h.mul(_mktVars.fIndexPriceS3).div(_mktVars.fIndexPriceS2); fkStar = fkStar.add(h); } // decide on sign of premium if (_fTradeAmount < fkStar) { fQ = fQ.neg(); } // no rebate if exposure increases if (_fTradeAmount > 0 && _ammVars.fAMM_K2 > 0) { fQ = fQ > 0 ? fQ : int128(0); } else if (_fTradeAmount < 0 && _ammVars.fAMM_K2 < 0) { fQ = fQ < 0 ? fQ : int128(0); } // handle discontinuity at zero if ( _fTradeAmount == 0 && ((fQ < 0 && _ammVars.fAMM_K2 > 0) || (fQ > 0 && _ammVars.fAMM_K2 < 0)) ) { fQ = fQ.div(TWO_64x64); } _fHBidAskSpread = _fHBidAskSpread.add(fQ); } // get additional slippage if (_fTradeAmount != 0) { _fIncentiveSpread = _fIncentiveSpread.mul( _calculateBoundedSlippage(_ammVars, _fTradeAmount) ); _fHBidAskSpread = _fHBidAskSpread.add(_fIncentiveSpread); } // s2*(1 + sign(qp-q)*q + sign(k)*minSpread) return _mktVars.fIndexPriceS2.mul(ONE_64x64.add(_fHBidAskSpread)); } /** * Calculate target collateral M1 (Quote Currency), when no M2, M3 is present * The targeted default probability is expressed using the inverse * _fTargetDD = Phi^(-1)(targetPD) * _fK2 in absolute terms must be 'reasonably large' * sigma3, rho23, IndexpriceS3 not relevant. * @param _fK2 signed 64.64-bit fixed point number, !=0, EWMA of actual K. * @param _fL1 signed 64.64-bit fixed point number, >0, EWMA of actual L. * @param _mktVars contains 64.64 values for fIndexPriceS2*, fIndexPriceS3, fSigma2*, fSigma3, fRho23 * @param _fTargetDD signed 64.64-bit fixed point number * @return M1Star signed 64.64-bit fixed point number, >0 */ function getTargetCollateralM1( int128 _fK2, int128 _fL1, MarketVariables memory _mktVars, int128 _fTargetDD ) external pure virtual override returns (int128) { assert(_fK2 != 0); assert(_mktVars.fSigma3 == 0); assert(_mktVars.fIndexPriceS3 == 0); assert(_mktVars.fRho23 == 0); int128 fMu2 = HALF_64x64.neg().mul(_mktVars.fSigma2).mul(_mktVars.fSigma2); int128 ddScaled = _fK2 < 0 ? _mktVars.fSigma2.mul(_fTargetDD) : _mktVars.fSigma2.mul(_fTargetDD).neg(); int128 A1 = ABDKMath64x64.exp(fMu2.add(ddScaled)); return _fK2.mul(_mktVars.fIndexPriceS2).mul(A1).sub(_fL1); } /** * Calculate target collateral *M2* (Base Currency), when no M1, M3 is present * The targeted default probability is expressed using the inverse * _fTargetDD = Phi^(-1)(targetPD) * _fK2 in absolute terms must be 'reasonably large' * sigma3, rho23, IndexpriceS3 not relevant. * @param _fK2 signed 64.64-bit fixed point number, EWMA of actual K. * @param _fL1 signed 64.64-bit fixed point number, EWMA of actual L. * @param _mktVars contains 64.64 values for fIndexPriceS2, fIndexPriceS3, fSigma2, fSigma3, fRho23 * @param _fTargetDD signed 64.64-bit fixed point number * @return M2Star signed 64.64-bit fixed point number */ function getTargetCollateralM2( int128 _fK2, int128 _fL1, MarketVariables memory _mktVars, int128 _fTargetDD ) external pure virtual override returns (int128) { assert(_fK2 != 0); assert(_mktVars.fSigma3 == 0); assert(_mktVars.fIndexPriceS3 == 0); assert(_mktVars.fRho23 == 0); int128 fMu2 = HALF_64x64.mul(_mktVars.fSigma2).mul(_mktVars.fSigma2).neg(); int128 ddScaled = _fL1 < 0 ? _mktVars.fSigma2.mul(_fTargetDD) : _mktVars.fSigma2.mul(_fTargetDD).neg(); int128 A1 = ABDKMath64x64.exp(fMu2.add(ddScaled)).mul(_mktVars.fIndexPriceS2); return _fK2.sub(_fL1.div(A1)); } /** * Calculate target collateral M3 (Quanto Currency), when no M1, M2 not present * @param _fK2 signed 64.64-bit fixed point number. EWMA of actual K. * @param _fL1 signed 64.64-bit fixed point number. EWMA of actual L. * @param _mktVars contains 64.64 values for * fIndexPriceS2, fIndexPriceS3, fSigma2, fSigma3, fRho23 - all required * @param _fTargetDD signed 64.64-bit fixed point number * @return M2Star signed 64.64-bit fixed point number */ function getTargetCollateralM3( int128 _fK2, int128 _fL1, MarketVariables memory _mktVars, int128 _fTargetDD ) external pure override returns (int128) { assert(_fK2 != 0); assert(_mktVars.fSigma3 != 0); assert(_mktVars.fIndexPriceS3 != 0); // we solve the quadratic equation A x^2 + Bx + C = 0 // B = 2 * [X + Y * target_dd^2 * (exp(rho*sigma2*sigma3) - 1) ] // C = X^2 - Y^2 * target_dd^2 * (exp(sigma2^2) - 1) // where: // X = L1 / S3 - Y and Y = K2 * S2 / S3 // we re-use L1 for X and K2 for Y to save memory since they don't enter the equations otherwise _fK2 = _fK2.mul(_mktVars.fIndexPriceS2).div(_mktVars.fIndexPriceS3); // Y _fL1 = _fL1.div(_mktVars.fIndexPriceS3).sub(_fK2); // X // we only need the square of the target DD _fTargetDD = _fTargetDD.mul(_fTargetDD); // and we only need B/2 int128 fHalfB = _fL1.add( _fK2.mul(_fTargetDD.mul(_mktVars.fRho23.mul(_mktVars.fSigma2.mul(_mktVars.fSigma3)))) ); int128 fC = _fL1.mul(_fL1).sub( _fK2.mul(_fK2).mul(_fTargetDD).mul(_mktVars.fSigma2.mul(_mktVars.fSigma2)) ); // A = 1 - (exp(sigma3^2) - 1) * target_dd^2 int128 fA = ONE_64x64.sub(_mktVars.fSigma3.mul(_mktVars.fSigma3).mul(_fTargetDD)); // we re-use C to store the discriminant: D = (B/2)^2 - A * C fC = fHalfB.mul(fHalfB).sub(fA.mul(fC)); if (fC < 0) { // no solutions -> AMM is in profit, probability is smaller than target regardless of capital return int128(0); } // we want the larger of (-B/2 + sqrt((B/2)^2-A*C)) / A and (-B/2 - sqrt((B/2)^2-A*C)) / A // so it depends on the sign of A, or, equivalently, the sign of sqrt(...)/A fC = ABDKMath64x64.sqrt(fC).div(fA); fHalfB = fHalfB.div(fA); return fC > 0 ? fC.sub(fHalfB) : fC.neg().sub(fHalfB); } /** * Calculate the required deposit for a new position * of size _fPosition+_fTradeAmount and leverage _fTargetLeverage, * having an existing position with balance fBalance0 and size _fPosition. * This is the amount to be added to the margin collateral and can be negative (hence remove). * Fees not factored-in. * @param _fPosition0 signed 64.64-bit fixed point number. Position in base currency * @param _fBalance0 signed 64.64-bit fixed point number. Current balance. * @param _fTradeAmount signed 64.64-bit fixed point number. Trade amt in base currency * @param _fTargetLeverage signed 64.64-bit fixed point number. Desired leverage * @param _fPrice signed 64.64-bit fixed point number. Price for the trade of size _fTradeAmount * @param _fS2Mark signed 64.64-bit fixed point number. Mark-price * @param _fS3 signed 64.64-bit fixed point number. Collateral 2 quote conversion * @return signed 64.64-bit fixed point number. Required cash_cc */ function getDepositAmountForLvgPosition( int128 _fPosition0, int128 _fBalance0, int128 _fTradeAmount, int128 _fTargetLeverage, int128 _fPrice, int128 _fS2Mark, int128 _fS3, int128 _fS2 ) external pure override returns (int128) { // calculation has to be aligned with _getAvailableMargin and _executeTrade // calculation // otherwise the calculated deposit might not be enough to declare // the margin to be enough // aligned with get available margin balance int128 fPremiumCash = _fTradeAmount.mul(_fPrice.sub(_fS2)); int128 fDeltaLockedValue = _fTradeAmount.mul(_fS2); int128 fPnL = _fTradeAmount.mul(_fS2Mark); // we replace _fTradeAmount * price/S3 by // fDeltaLockedValue + fPremiumCash to be in line with // _executeTrade fPnL = fPnL.sub(fDeltaLockedValue).sub(fPremiumCash); int128 fLvgFrac = _fPosition0.add(_fTradeAmount).abs(); fLvgFrac = fLvgFrac.mul(_fS2Mark).div(_fTargetLeverage); fPnL = fPnL.sub(fLvgFrac).div(_fS3); _fBalance0 = _fBalance0.add(fPnL); return _fBalance0.neg(); } function entropy(int128 _p) external pure override returns (int128) { return _entropy(_p); } function _entropy(int128 _p) internal pure returns (int128) { //- p * log2(p) - (1-p) * log2(1-p) if (_p <= 0) { return 0; } if (_p >= ONE_64x64) { return 0; } if (_p < 184467440737) { // approximate to avoid numerical troubles // 184467440737=1e-8 return _p; } if (_p > 18446743889242110879) { // approximate to avoid numerical troubles // 18446743889242110879 = 1-1e-8 return ONE_64x64.sub(_p); } int128 h = ONE_64x64.sub(_p).mul(ONE_64x64.sub(_p).log_2()); h = _p.mul(_p.log_2()).add(h); return h.neg(); } function first_nonzeronum(uint16 numDec) internal pure returns (uint256) { uint256 pos = 0; while (numDec > 0) { numDec = numDec / 10; pos = pos + 1; } return pos; } /** * Decode uint16-float and convert into ABDK int128 fixed point number * Uint16-float is custom. * @param num number that encodes a float */ function decodeUint16Float(uint16 num) external pure returns (int128) { return _decodeUint16Float(num); } function _decodeUint16Float(uint16 num) internal pure returns (int128) { uint16 sgnNum = num >> 15; uint16 sgnE = (num >> 14) & 1; uint16 val = (num >> 4) & ((2 ** 10) - 1); uint16 exponent = num & ((2 ** 4) - 1); //convert val abcde to normalized form a.bcde int128 v = int128(uint128(val)) * ONE_64x64; uint256 exponent1 = (first_nonzeronum(val) - 1); v = v.div(ABDKMath64x64.pow(10 * ONE_64x64, exponent1)); if (sgnE == 1) { v = v.div(ABDKMath64x64.pow(10 * ONE_64x64, uint256(exponent))); } else { v = v.mul(ABDKMath64x64.pow(10 * ONE_64x64, uint256(exponent))); } if (sgnNum == 1) { v = v.neg(); } return v; } /** * Calculate the price impact for betting market trades * @param _amount trade amount (signed base currency) * @param _params float encoded parameters for bid side (left 32 bit) and ask side (right 32 bit) */ function priceImpact(int128 _amount, uint64 _params) external pure returns (int128) { uint32 params; if (_amount > 0) { params = uint32(_params & ((2 ** 32) - 1)); } else { params = uint32(_params >> 32); } int128 a = _decodeUint16Float(uint16(params >> 16)); int128 m = _decodeUint16Float(uint16(params & ((2 ** 16) - 1))); int128 l = a.add(_amount.abs().mul(m)); if (l<0x200000000000000000) { // here if impact is not close to overflow return _amount < 0 ? -l.exp() : l.exp(); } // return a very big number return _amount < 0 ? -int128(0x40000000000000000000000000000000) : int128(0x40000000000000000000000000000000); } function _expectedLossImpact( int128 _fp, //probability (long) int128 _m, //max maint margin rate int128 _tradeAmt, //amount being traded int128 _mgnRate //margin rate for trade. If zero, set to maintenance margin rate ) internal pure returns (int128) { //maintMgnRate = (0.4-m)*entropy(p) + m int128 maintMgnRate = _entropy(_fp); maintMgnRate = ABDKMath64x64.sub(7378697629483820646, _m).mul(maintMgnRate).add(_m); if (_mgnRate == 0) { _mgnRate = maintMgnRate; } int128 a; int128 b; { int128 dlm; int128 dsm; int128 dl; int128 ds; if (_tradeAmt > 0) { dlm = _fp.mul(_tradeAmt); dlm = dlm.mul(_mgnRate); dl = _tradeAmt; } else if (_tradeAmt < 0) { dsm = ONE_64x64.sub(_fp); dsm = dsm.mul(_tradeAmt).neg().mul(_mgnRate); ds = _tradeAmt.neg(); } a = dl.sub(dsm); b = ds.sub(dlm); } int128 el; el = a.add(b); if (el < 0) { return 0; } _fp = _fp.mul(ONE_64x64.sub(_fp)); return el.mul(_fp); } /** * Returns $fee/tradeamt * @param _fPx price (1+p) * @param _fm max maint margin rate * @param _fTradeAmt amount being traded * @param _fMgnRate margin rate for trade. If zero maintenance margin will be used */ function prdMktsLvgFee( int128 _fPx, //price (1+p) int128 _fm, //max maint margin rate int128 _fTradeAmt, //amount being traded int128 _fMgnRate //margin rate for trade ) external pure returns (int128) { /* fee application: tradeAmtCC = pos * s2/s3 fee = tradeAmtCC * feeRate we need to calculate 'feeRate'. The fee here is however the dollar fee, so $fee/s3 is the fee charged in USD-collateral currency -> $fee/S3 = tradeamt*feeRate/s3 -> we calculate feeRate -> feeRate = $fee/tradeamt. */ _fPx = _fPx.sub(ONE_64x64); // convert to probability int128 dEl = _expectedLossImpact(_fPx, _fm, _fTradeAmt, _fMgnRate); // diff (elAfter.sub(elBefore)) is the fee in dollar terms, // now we calculate r*s2 dEl = dEl.div(_fTradeAmt.abs()); if (dEl < 18446744073709552) { // if smaller than 0.1 cent per contract, set to 0.1 cent dEl = 18446744073709552; } return dEl; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.21; import "../functions/AMMPerpLogic.sol"; interface IAMMPerpLogic { function calculateDefaultFundSize( int128[2] memory _fK2AMM, int128 _fk2Trader, int128 _fCoverN, int128[2] memory fStressRet2, int128[2] memory fStressRet3, int128[2] memory fIndexPrices, AMMPerpLogic.CollateralCurrency _eCCY ) external pure returns (int128); function calculateRiskNeutralPD( AMMPerpLogic.AMMVariables memory _ammVars, AMMPerpLogic.MarketVariables memory _mktVars, int128 _fTradeAmount, bool _withCDF ) external view returns (int128, int128); function calculatePerpetualPrice( AMMPerpLogic.AMMVariables memory _ammVars, AMMPerpLogic.MarketVariables memory _mktVars, int128 _fTradeAmount, int128 _fBidAskSpread, int128 _fIncentiveSpread ) external view returns (int128); function getTargetCollateralM1( int128 _fK2, int128 _fL1, AMMPerpLogic.MarketVariables memory _mktVars, int128 _fTargetDD ) external pure returns (int128); function getTargetCollateralM2( int128 _fK2, int128 _fL1, AMMPerpLogic.MarketVariables memory _mktVars, int128 _fTargetDD ) external pure returns (int128); function getTargetCollateralM3( int128 _fK2, int128 _fL1, AMMPerpLogic.MarketVariables memory _mktVars, int128 _fTargetDD ) external pure returns (int128); function getDepositAmountForLvgPosition( int128 _fPosition0, int128 _fBalance0, int128 _fTradeAmount, int128 _fTargetLeverage, int128 _fPrice, int128 _fS2Mark, int128 _fS3, int128 _fS2 ) external pure returns (int128); function entropy(int128 _p) external pure returns (int128); function decodeUint16Float(uint16 num) external pure returns (int128); function priceImpact(int128 _amount, uint64 _params) external pure returns (int128); function prdMktsLvgFee( int128 _fPx, int128 _fm, int128 _fTradeAmt, int128 _fMgnRate ) external pure returns (int128); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.21; interface IFunctionList { function getFunctionList() external pure returns (bytes4[] memory functionSignatures, bytes32 moduleName); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.21; import "./IPerpetualOrder.sol"; /** * @notice The libraryEvents defines events that will be raised from modules (contract/modules). * @dev DO REMEMBER to add new events in modules here. */ interface ILibraryEvents { // PerpetualModule event Clear(uint24 indexed perpetualId, address indexed trader); event Settle(uint24 indexed perpetualId, address indexed trader, int256 amount); event SettlementComplete(uint24 indexed perpetualId); event SetNormalState(uint24 indexed perpetualId); event SetEmergencyState( uint24 indexed perpetualId, int128 fSettlementMarkPremiumRate, int128 fSettlementS2Price, int128 fSettlementS3Price ); event SettleState(uint24 indexed perpetualId); event SetClearedState(uint24 indexed perpetualId); // Participation pool event LiquidityAdded( uint8 indexed poolId, address indexed user, uint256 tokenAmount, uint256 shareAmount ); event LiquidityProvisionPaused(bool pauseOn, uint8 poolId); event LiquidityRemoved( uint8 indexed poolId, address indexed user, uint256 tokenAmount, uint256 shareAmount ); event LiquidityWithdrawalInitiated( uint8 indexed poolId, address indexed user, uint256 shareAmount ); // setters // oracles event SetOracles(uint24 indexed perpetualId, bytes4[2] baseQuoteS2, bytes4[2] baseQuoteS3); // perp parameters event SetPerpetualBaseParameters(uint24 indexed perpetualId, int128[7] baseParams); event SetPerpetualRiskParameters( uint24 indexed perpetualId, int128[5] underlyingRiskParams, int128[12] defaultFundRiskParams ); event SetParameter(uint24 indexed perpetualId, string name, int128 value); event SetParameterPair(uint24 indexed perpetualId, string name, int128 value1, int128 value2); // pool parameters event SetPoolParameter(uint8 indexed poolId, string name, int128 value); event TransferAddressTo(string name, address oldOBFactory, address newOBFactory); // only governance event SetBlockDelay(uint8 delay); // fee structure parameters event SetBrokerDesignations(uint32[] designations, uint16[] fees); event SetBrokerTiers(uint256[] tiers, uint16[] feesTbps); event SetTraderTiers(uint256[] tiers, uint16[] feesTbps); event SetTraderVolumeTiers(uint256[] tiers, uint16[] feesTbps); event SetBrokerVolumeTiers(uint256[] tiers, uint16[] feesTbps); event SetUtilityToken(address tokenAddr); event BrokerLotsTransferred( uint8 indexed poolId, address oldOwner, address newOwner, uint32 numLots ); event BrokerVolumeTransferred( uint8 indexed poolId, address oldOwner, address newOwner, int128 fVolume ); // brokers event UpdateBrokerAddedCash(uint8 indexed poolId, uint32 iLots, uint32 iNewBrokerLots); // TradeModule event Trade( uint24 indexed perpetualId, address indexed trader, IPerpetualOrder.Order order, bytes32 orderDigest, int128 newPositionSizeBC, int128 price, int128 fFeeCC, int128 fPnlCC, int128 fB2C ); event UpdateMarginAccount( uint24 indexed perpetualId, address indexed trader, int128 fFundingPaymentCC ); event Liquidate( uint24 perpetualId, address indexed liquidator, address indexed trader, int128 amountLiquidatedBC, int128 liquidationPrice, int128 newPositionSizeBC, int128 fFeeCC, int128 fPnlCC ); event PerpetualLimitOrderCancelled(uint24 indexed perpetualId, bytes32 indexed orderHash); event DistributeFees( uint8 indexed poolId, uint24 indexed perpetualId, address indexed trader, int128 protocolFeeCC, int128 participationFundFeeCC ); // PerpetualManager/factory event RunLiquidityPool(uint8 _liqPoolID); event LiquidityPoolCreated( uint8 id, address marginTokenAddress, address shareTokenAddress, uint16 iTargetPoolSizeUpdateTime, int128 fBrokerCollateralLotSize ); event PerpetualCreated( uint8 poolId, uint24 id, int128[7] baseParams, int128[5] underlyingRiskParams, int128[12] defaultFundRiskParams, uint256 eCollateralCurrency ); // emit tokenAddr==0x0 if the token paid is the aggregated token, otherwise the address of the token event TokensDeposited(uint24 indexed perpetualId, address indexed trader, int128 amount); event TokensWithdrawn(uint24 indexed perpetualId, address indexed trader, int128 amount); event UpdateMarkPrice( uint24 indexed perpetualId, int128 fMidPricePremium, int128 fMarkPricePremium, int128 fMarkIndexPrice //either spot or "ema" for prd mkts ); event UpdateFundingRate(uint24 indexed perpetualId, int128 fFundingRate); event SetDelegate(address indexed trader, address indexed delegate, uint256 index); }
// 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) } }
{ "optimizer": { "enabled": true, "runs": 100000000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"},{"indexed":false,"internalType":"uint32","name":"numLots","type":"uint32"}],"name":"BrokerLotsTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"},{"indexed":false,"internalType":"int128","name":"fVolume","type":"int128"}],"name":"BrokerVolumeTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"trader","type":"address"}],"name":"Clear","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int128","name":"protocolFeeCC","type":"int128"},{"indexed":false,"internalType":"int128","name":"participationFundFeeCC","type":"int128"}],"name":"DistributeFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"}],"name":"GovernanceTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"_sig","type":"bytes4"},{"indexed":true,"internalType":"address","name":"_oldImplementation","type":"address"},{"indexed":true,"internalType":"address","name":"_newImplementation","type":"address"}],"name":"ImplementationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int128","name":"amountLiquidatedBC","type":"int128"},{"indexed":false,"internalType":"int128","name":"liquidationPrice","type":"int128"},{"indexed":false,"internalType":"int128","name":"newPositionSizeBC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fFeeCC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fPnlCC","type":"int128"}],"name":"Liquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shareAmount","type":"uint256"}],"name":"LiquidityAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"id","type":"uint8"},{"indexed":false,"internalType":"address","name":"marginTokenAddress","type":"address"},{"indexed":false,"internalType":"address","name":"shareTokenAddress","type":"address"},{"indexed":false,"internalType":"uint16","name":"iTargetPoolSizeUpdateTime","type":"uint16"},{"indexed":false,"internalType":"int128","name":"fBrokerCollateralLotSize","type":"int128"}],"name":"LiquidityPoolCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"pauseOn","type":"bool"},{"indexed":false,"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"LiquidityProvisionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shareAmount","type":"uint256"}],"name":"LiquidityRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"shareAmount","type":"uint256"}],"name":"LiquidityWithdrawalInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousMaintainer","type":"address"},{"indexed":true,"internalType":"address","name":"newMaintainer","type":"address"}],"name":"MaintainerTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"uint24","name":"id","type":"uint24"},{"indexed":false,"internalType":"int128[7]","name":"baseParams","type":"int128[7]"},{"indexed":false,"internalType":"int128[5]","name":"underlyingRiskParams","type":"int128[5]"},{"indexed":false,"internalType":"int128[12]","name":"defaultFundRiskParams","type":"int128[12]"},{"indexed":false,"internalType":"uint256","name":"eCollateralCurrency","type":"uint256"}],"name":"PerpetualCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"PerpetualLimitOrderCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"ProxyOwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"_liqPoolID","type":"uint8"}],"name":"RunLiquidityPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"delay","type":"uint8"}],"name":"SetBlockDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32[]","name":"designations","type":"uint32[]"},{"indexed":false,"internalType":"uint16[]","name":"fees","type":"uint16[]"}],"name":"SetBrokerDesignations","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"tiers","type":"uint256[]"},{"indexed":false,"internalType":"uint16[]","name":"feesTbps","type":"uint16[]"}],"name":"SetBrokerTiers","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"tiers","type":"uint256[]"},{"indexed":false,"internalType":"uint16[]","name":"feesTbps","type":"uint16[]"}],"name":"SetBrokerVolumeTiers","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"}],"name":"SetClearedState","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"SetDelegate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"int128","name":"fSettlementMarkPremiumRate","type":"int128"},{"indexed":false,"internalType":"int128","name":"fSettlementS2Price","type":"int128"},{"indexed":false,"internalType":"int128","name":"fSettlementS3Price","type":"int128"}],"name":"SetEmergencyState","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"}],"name":"SetNormalState","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"bytes4[2]","name":"baseQuoteS2","type":"bytes4[2]"},{"indexed":false,"internalType":"bytes4[2]","name":"baseQuoteS3","type":"bytes4[2]"}],"name":"SetOracles","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"int128","name":"value","type":"int128"}],"name":"SetParameter","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"int128","name":"value1","type":"int128"},{"indexed":false,"internalType":"int128","name":"value2","type":"int128"}],"name":"SetParameterPair","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"int128[7]","name":"baseParams","type":"int128[7]"}],"name":"SetPerpetualBaseParameters","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"int128[5]","name":"underlyingRiskParams","type":"int128[5]"},{"indexed":false,"internalType":"int128[12]","name":"defaultFundRiskParams","type":"int128[12]"}],"name":"SetPerpetualRiskParameters","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"int128","name":"value","type":"int128"}],"name":"SetPoolParameter","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"tiers","type":"uint256[]"},{"indexed":false,"internalType":"uint16[]","name":"feesTbps","type":"uint16[]"}],"name":"SetTraderTiers","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"tiers","type":"uint256[]"},{"indexed":false,"internalType":"uint16[]","name":"feesTbps","type":"uint16[]"}],"name":"SetTraderVolumeTiers","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenAddr","type":"address"}],"name":"SetUtilityToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int256","name":"amount","type":"int256"}],"name":"Settle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"}],"name":"SettleState","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"}],"name":"SettlementComplete","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int128","name":"amount","type":"int128"}],"name":"TokensDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int128","name":"amount","type":"int128"}],"name":"TokensWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"components":[{"internalType":"uint16","name":"leverageTDR","type":"uint16"},{"internalType":"uint16","name":"brokerFeeTbps","type":"uint16"},{"internalType":"uint24","name":"iPerpetualId","type":"uint24"},{"internalType":"address","name":"traderAddr","type":"address"},{"internalType":"uint32","name":"executionTimestamp","type":"uint32"},{"internalType":"address","name":"brokerAddr","type":"address"},{"internalType":"uint32","name":"submittedTimestamp","type":"uint32"},{"internalType":"uint32","name":"flags","type":"uint32"},{"internalType":"uint32","name":"iDeadline","type":"uint32"},{"internalType":"address","name":"executorAddr","type":"address"},{"internalType":"int128","name":"fAmount","type":"int128"},{"internalType":"int128","name":"fLimitPrice","type":"int128"},{"internalType":"int128","name":"fTriggerPrice","type":"int128"},{"internalType":"bytes","name":"brokerSignature","type":"bytes"}],"indexed":false,"internalType":"struct IPerpetualOrder.Order","name":"order","type":"tuple"},{"indexed":false,"internalType":"bytes32","name":"orderDigest","type":"bytes32"},{"indexed":false,"internalType":"int128","name":"newPositionSizeBC","type":"int128"},{"indexed":false,"internalType":"int128","name":"price","type":"int128"},{"indexed":false,"internalType":"int128","name":"fFeeCC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fPnlCC","type":"int128"},{"indexed":false,"internalType":"int128","name":"fB2C","type":"int128"}],"name":"Trade","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"oldOBFactory","type":"address"},{"indexed":false,"internalType":"address","name":"newOBFactory","type":"address"}],"name":"TransferAddressTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"uint32","name":"iLots","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"iNewBrokerLots","type":"uint32"}],"name":"UpdateBrokerAddedCash","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"int128","name":"fFundingRate","type":"int128"}],"name":"UpdateFundingRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int128","name":"fFundingPaymentCC","type":"int128"}],"name":"UpdateMarginAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint24","name":"perpetualId","type":"uint24"},{"indexed":false,"internalType":"int128","name":"fMidPricePremium","type":"int128"},{"indexed":false,"internalType":"int128","name":"fMarkPricePremium","type":"int128"},{"indexed":false,"internalType":"int128","name":"fMarkIndexPrice","type":"int128"}],"name":"UpdateMarkPrice","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"address","name":"","type":"address"}],"name":"brokerVolumeEMA","outputs":[{"internalType":"int128","name":"fTradingVolumeEMAusd","type":"int128"},{"internalType":"uint64","name":"timestamp","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"brokerVolumeFeesTbps","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"brokerVolumeTiers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_sig","type":"bytes4"}],"name":"getImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_moduleName","type":"string"}],"name":"getModuleImplementationAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProxyOwner","outputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastBaseToUSDUpdateTs","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"liquidityProvisionIsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maintainer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint24","name":"","type":"uint24"}],"name":"perpBaseToUSDOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint24","name":"","type":"uint24"}],"name":"perpToLastBaseToUSD","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_impl","type":"address"}],"name":"setImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_impl","type":"address"}],"name":"setImplementationCrossModules","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setProxyOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"address","name":"","type":"address"}],"name":"traderVolumeEMA","outputs":[{"internalType":"int128","name":"fTradingVolumeEMAusd","type":"int128"},{"internalType":"uint64","name":"timestamp","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"traderVolumeFeesTbps","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"traderVolumeTiers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newGovernance","type":"address"}],"name":"transferGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newMaintainer","type":"address"}],"name":"transferMaintainer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200001d3362000049565b620000283362000099565b6001805460ff60a01b191681556002556200004333620000eb565b620001b0565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f2f3ffaaaad93928855c8700645d1a3643e6ccfdd500efa9fda048a88f557cf019190a35050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce8090600090a35050565b6001600160a01b038116620001465760405162461bcd60e51b815260206004820152601b60248201527f696e76616c69642070726f7879206f776e657220616464726573730000000000604482015260640160405180910390fd5b6001600160a01b038116620001686000805160206200274a8339815191525490565b6001600160a01b03167f5a3e66efaa1e445ebd894728a69d6959842ea1e97bd79b892797106e270efcd960405160405180910390a36000805160206200274a83398151915255565b61258a80620001c06000396000f3fe6080604052600436106101835760003560e01c80636700c019116100d6578063caaee91c1161007f578063dc9cc64511610059578063dc9cc6451461058a578063e7332410146105aa578063e7e21fde146105e457610192565b8063caaee91c1461052a578063d38bfff41461054a578063d784d4261461056a57610192565b80639850d32b116100b05780639850d32b146104835780639ecab3f5146104ae578063bffd952a1461050a57610192565b80636700c019146103f85780638456cb591461042b57806388b825281461044057610192565b80633f4ba83a116101385780635c975abb116101125780635c975abb146103295780635ca8b972146103595780635fdfecbe1461037957610192565b80633f4ba83a146102bb57806355f1c7d5146102d05780635aa6e675146102fe57610192565b80631ab7710d116101695780631ab7710d146102045780633a839d15146102385780633baf4f6f1461027b57610192565b806233c04b1461019a5780630e1cf91b146101e457610192565b3661019257610190610604565b005b610190610604565b3480156101a657600080fd5b506101ba6101b53660046121ab565b610616565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156101f057600080fd5b506101906101ff366004612241565b61068b565b34801561021057600080fd5b507fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d8546101ba565b34801561024457600080fd5b5061026861025336600461225c565b601960205260009081526040902054600f0b81565b604051600f9190910b81526020016101db565b34801561028757600080fd5b506102ab610296366004612292565b601f6020526000908152604090205460ff1681565b60405190151581526020016101db565b3480156102c757600080fd5b50610190610754565b3480156102dc57600080fd5b506102f06102eb3660046122ad565b610801565b6040519081526020016101db565b34801561030a57600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166101ba565b34801561033557600080fd5b5060015474010000000000000000000000000000000000000000900460ff166102ab565b34801561036557600080fd5b506102f06103743660046122ad565b610822565b34801561038557600080fd5b506103d56103943660046122c6565b601a602090815260009283526040808420909152908252902054600f81900b90700100000000000000000000000000000000900467ffffffffffffffff1682565b60408051600f9390930b835267ffffffffffffffff9091166020830152016101db565b34801561040457600080fd5b506104186104133660046122ad565b610832565b60405161ffff90911681526020016101db565b34801561043757600080fd5b5061019061086a565b34801561044c57600080fd5b506101ba61045b36600461225c565b60186020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561048f57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101ba565b3480156104ba57600080fd5b506103d56104c93660046122c6565b601b602090815260009283526040808420909152908252902054600f81900b90700100000000000000000000000000000000900467ffffffffffffffff1682565b34801561051657600080fd5b50610190610525366004612241565b610917565b34801561053657600080fd5b50610190610545366004612241565b610a1e565b34801561055657600080fd5b50610190610565366004612241565b610add565b34801561057657600080fd5b50610190610585366004612241565b610be4565b34801561059657600080fd5b506101ba6105a5366004612327565b610ca5565b3480156105b657600080fd5b50601c546105cb9067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101db565b3480156105f057600080fd5b506104186105ff3660046122ad565b610d19565b61061461060f610d29565b610e49565b565b60006012600061065b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e6d92505050565b815260208101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff1690505b92915050565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610746576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e6965640000000000000000000000000060448201526064015b60405180910390fd5b610751816001610e8c565b50565b61075c6113a2565b3361077c60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16146107f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c79206d61696e7461696e65720000000000000000000000000000000000604482015260640161073d565b610614611426565b6014818154811061081157600080fd5b600091825260209091200154905081565b6015818154811061081157600080fd5b6016818154811061084257600080fd5b9060005260206000209060109182820401919006600202915054906101000a900461ffff1681565b6108726114a3565b3361089260005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461090f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c79206d61696e7461696e65720000000000000000000000000000000000604482015260640161073d565b610614611528565b60015473ffffffffffffffffffffffffffffffffffffffff163314610998576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c7920676f7665726e616e63650000000000000000000000000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff8116610a15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f20616464726573730000000000000000000000000000000000000000604482015260640161073d565b61075181611597565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610ad4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e69656400000000000000000000000000604482015260640161073d565b6107518161160c565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c7920676f7665726e616e63650000000000000000000000000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff8116610bdb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f20616464726573730000000000000000000000000000000000000000604482015260640161073d565b6107518161172e565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c9a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e69656400000000000000000000000000604482015260640161073d565b610751816000610e8c565b604080517fffffffff0000000000000000000000000000000000000000000000000000000083166020808301919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc8828401528251808303840181526060909201909252805191012054600090610685565b6017818154811061084257600080fd5b600080610dc56000357fffffffff0000000000000000000000000000000000000000000000000000000016604080517fffffffff00000000000000000000000000000000000000000000000000000000929092166020808401919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883830152815180840383018152606090930190915281519101205490565b905073ffffffffffffffffffffffffffffffffffffffff8116610e44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f50726f78793a496d706c656d656e746174696f6e206e6f7420666f756e640000604482015260640161073d565b919050565b3660008037600080366000845af43d6000803e808015610e68573d6000f35b3d6000fd5b805160009082908203610e835750600092915050565b50506020015190565b73ffffffffffffffffffffffffffffffffffffffff8216610f09576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f696e76616c696420696d706c656d656e746174696f6e20616464726573730000604482015260640161073d565b6000808373ffffffffffffffffffffffffffffffffffffffff16633e6b8c0d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610f57573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610f9d919081019061237e565b909250905080611009576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d6f64756c65206e616d652063616e6e6f7420626520656d7074790000000000604482015260640161073d565b60008181526011602052604081209080611024836001015490565b85519110915060005b8181101561121557600086828151811061104957611049612469565b6020026020010151905061107f87838151811061106857611068612469565b6020026020010151866117a590919063ffffffff16565b6111df57604080517fffffffff0000000000000000000000000000000000000000000000000000000083166020808301919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc882840152825180830384018152606090920190925280519101205473ffffffffffffffffffffffffffffffffffffffff8116156111b05788611172576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f63616e74207265706c616365206d6f64756c65732066756e6373000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601360209081526040808320548352601190915290206111ae90836117dc565b505b6111dc8884815181106111c5576111c5612469565b6020026020010151876119d890919063ffffffff16565b50505b6112028783815181106111f4576111f4612469565b60200260200101518a611a88565b508061120d816124c7565b91505061102d565b508115611339576000611236600061122e866001015490565b869190611bbb565b90508051915060005b8281101561133657600082828151811061125b5761125b612469565b602002602001015190508973ffffffffffffffffffffffffffffffffffffffff166112f182604080517fffffffff00000000000000000000000000000000000000000000000000000000929092166020808401919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883830152815180840383018152606090930190915281519101205490565b73ffffffffffffffffffffffffffffffffffffffff161461132357611317816000611a88565b61132186826117dc565b505b508061132e816124c7565b91505061123f565b50505b5050506000818152601260209081526040808320805473ffffffffffffffffffffffffffffffffffffffff9098167fffffffffffffffffffffffff0000000000000000000000000000000000000000909816881790559582526013905293909320929092555050565b60015474010000000000000000000000000000000000000000900460ff16610614576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161073d565b61142e6113a2565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b60015474010000000000000000000000000000000000000000900460ff1615610614576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161073d565b6115306114a3565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586114793390565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f2f3ffaaaad93928855c8700645d1a3643e6ccfdd500efa9fda048a88f557cf019190a35050565b73ffffffffffffffffffffffffffffffffffffffff8116611689576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c69642070726f7879206f776e657220616464726573730000000000604482015260640161073d565b8073ffffffffffffffffffffffffffffffffffffffff166116c87fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85490565b73ffffffffffffffffffffffffffffffffffffffff167f5a3e66efaa1e445ebd894728a69d6959842ea1e97bd79b892797106e270efcd960405160405180910390a37fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d855565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce8090600090a35050565b7fffffffff000000000000000000000000000000000000000000000000000000001660009081526020919091526040902054151590565b7fffffffff000000000000000000000000000000000000000000000000000000008116600090815260208390526040812054156119d0577fffffffff000000000000000000000000000000000000000000000000000000008216600090815260208490526040812054611851906001906124ff565b60018581015491925060009161186791906124ff565b905081811461193357600085600101828154811061188757611887612469565b90600052602060002090600891828204019190066004029054906101000a900460e01b9050808660010184815481106118c2576118c2612469565b90600052602060002090600891828204019190066004026101000a81548163ffffffff021916908360e01c02179055508260016118ff9190612512565b7fffffffff000000000000000000000000000000000000000000000000000000009091166000908152602087905260409020555b7fffffffff0000000000000000000000000000000000000000000000000000000084166000908152602086905260408120556001850180548061197857611978612525565b60008281526020902060087fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191820401805463ffffffff600460078516026101000a0219169055905550600191506106859050565b506000610685565b7fffffffff0000000000000000000000000000000000000000000000000000000081166000908152602083905260408120546119d05750600182810180548083018255600082815260208082206008840401805463ffffffff60079095166004026101000a948502191660e088901c949094029390931790925591547fffffffff000000000000000000000000000000000000000000000000000000008516835290859052604090912055610685565b611a9182611d68565b604080517fffffffff00000000000000000000000000000000000000000000000000000000841660208083018290527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883850152835180840385018152606084018086528151919092012054919052915173ffffffffffffffffffffffffffffffffffffffff8481169316917f347b48699b991c95bb339a3a778222488794b19790e9f46171825933c63a9cc4919081900360800190a3604080517fffffffff00000000000000000000000000000000000000000000000000000000939093166020808501919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc8848301528151808503830181526060909401909152825192019190912055565b60606000611bc98385612512565b905083811015611c35576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6164646974696f6e206f766572666c6f77000000000000000000000000000000604482015260640161073d565b60018501548111611c465780611c4c565b60018501545b9050801580611c5b5750808410155b15611c665750611d61565b611c7084826124ff565b67ffffffffffffffff811115611c8857611c88612344565b604051908082528060200260200182016040528015611cb1578160200160208202803683370190505b50915060005b611cc185836124ff565b811015611d5e5760018601611cd68683612512565b81548110611ce657611ce6612469565b90600052602060002090600891828204019190066004029054906101000a900460e01b838281518110611d1b57611d1b612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280611d56816124c7565b915050611cb7565b50505b9392505050565b6000611d72611e5a565b805190915060005b81811015611e5457828181518110611d9457611d94612469565b60200260200101517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603611e42576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f66756e6374696f6e20696420616c726561647920657869737473000000000000604482015260640161073d565b80611e4c816124c7565b915050611d7a565b50505050565b604080516008808252610120820190925260609160009190602082016101008036833701905050905063dc9cc64560e01b81600081518110611e9e57611e9e612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517fd784d426000000000000000000000000000000000000000000000000000000009082906001908110611f0657611f06612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f0e1cf91b000000000000000000000000000000000000000000000000000000009082906002908110611f6e57611f6e612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517e33c04b000000000000000000000000000000000000000000000000000000009082906003908110611fd557611fd5612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517fcaaee91c00000000000000000000000000000000000000000000000000000000908290600490811061203d5761203d612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f1ab7710d0000000000000000000000000000000000000000000000000000000090829060059081106120a5576120a5612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f8456cb5900000000000000000000000000000000000000000000000000000000908290600690811061210d5761210d612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f3f4ba83a00000000000000000000000000000000000000000000000000000000908290600790811061217557612175612469565b7fffffffff0000000000000000000000000000000000000000000000000000000090921660209283029190910190910152919050565b600080602083850312156121be57600080fd5b823567ffffffffffffffff808211156121d657600080fd5b818501915085601f8301126121ea57600080fd5b8135818111156121f957600080fd5b86602082850101111561220b57600080fd5b60209290920196919550909350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e4457600080fd5b60006020828403121561225357600080fd5b611d618261221d565b60006020828403121561226e57600080fd5b813562ffffff81168114611d6157600080fd5b803560ff81168114610e4457600080fd5b6000602082840312156122a457600080fd5b611d6182612281565b6000602082840312156122bf57600080fd5b5035919050565b600080604083850312156122d957600080fd5b6122e283612281565b91506122f06020840161221d565b90509250929050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461075157600080fd5b60006020828403121561233957600080fd5b8135611d61816122f9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8051610e44816122f9565b6000806040838503121561239157600080fd5b825167ffffffffffffffff808211156123a957600080fd5b818501915085601f8301126123bd57600080fd5b81516020828211156123d1576123d1612344565b8160051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110868211171561241457612414612344565b60405292835281830193508481018201928984111561243257600080fd5b948201945b838610156124575761244886612373565b85529482019493820193612437565b97909101519698969750505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036124f8576124f8612498565b5060010190565b8181038181111561068557610685612498565b8082018082111561068557610685612498565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea264697066735822122068744860d75a4537237f557979b48b9ca9b039108dd9eb25a5100a7dcee3f0a564736f6c63430008150033b5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d8
Deployed Bytecode
0x6080604052600436106101835760003560e01c80636700c019116100d6578063caaee91c1161007f578063dc9cc64511610059578063dc9cc6451461058a578063e7332410146105aa578063e7e21fde146105e457610192565b8063caaee91c1461052a578063d38bfff41461054a578063d784d4261461056a57610192565b80639850d32b116100b05780639850d32b146104835780639ecab3f5146104ae578063bffd952a1461050a57610192565b80636700c019146103f85780638456cb591461042b57806388b825281461044057610192565b80633f4ba83a116101385780635c975abb116101125780635c975abb146103295780635ca8b972146103595780635fdfecbe1461037957610192565b80633f4ba83a146102bb57806355f1c7d5146102d05780635aa6e675146102fe57610192565b80631ab7710d116101695780631ab7710d146102045780633a839d15146102385780633baf4f6f1461027b57610192565b806233c04b1461019a5780630e1cf91b146101e457610192565b3661019257610190610604565b005b610190610604565b3480156101a657600080fd5b506101ba6101b53660046121ab565b610616565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156101f057600080fd5b506101906101ff366004612241565b61068b565b34801561021057600080fd5b507fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d8546101ba565b34801561024457600080fd5b5061026861025336600461225c565b601960205260009081526040902054600f0b81565b604051600f9190910b81526020016101db565b34801561028757600080fd5b506102ab610296366004612292565b601f6020526000908152604090205460ff1681565b60405190151581526020016101db565b3480156102c757600080fd5b50610190610754565b3480156102dc57600080fd5b506102f06102eb3660046122ad565b610801565b6040519081526020016101db565b34801561030a57600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166101ba565b34801561033557600080fd5b5060015474010000000000000000000000000000000000000000900460ff166102ab565b34801561036557600080fd5b506102f06103743660046122ad565b610822565b34801561038557600080fd5b506103d56103943660046122c6565b601a602090815260009283526040808420909152908252902054600f81900b90700100000000000000000000000000000000900467ffffffffffffffff1682565b60408051600f9390930b835267ffffffffffffffff9091166020830152016101db565b34801561040457600080fd5b506104186104133660046122ad565b610832565b60405161ffff90911681526020016101db565b34801561043757600080fd5b5061019061086a565b34801561044c57600080fd5b506101ba61045b36600461225c565b60186020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561048f57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101ba565b3480156104ba57600080fd5b506103d56104c93660046122c6565b601b602090815260009283526040808420909152908252902054600f81900b90700100000000000000000000000000000000900467ffffffffffffffff1682565b34801561051657600080fd5b50610190610525366004612241565b610917565b34801561053657600080fd5b50610190610545366004612241565b610a1e565b34801561055657600080fd5b50610190610565366004612241565b610add565b34801561057657600080fd5b50610190610585366004612241565b610be4565b34801561059657600080fd5b506101ba6105a5366004612327565b610ca5565b3480156105b657600080fd5b50601c546105cb9067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101db565b3480156105f057600080fd5b506104186105ff3660046122ad565b610d19565b61061461060f610d29565b610e49565b565b60006012600061065b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e6d92505050565b815260208101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff1690505b92915050565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610746576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e6965640000000000000000000000000060448201526064015b60405180910390fd5b610751816001610e8c565b50565b61075c6113a2565b3361077c60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16146107f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c79206d61696e7461696e65720000000000000000000000000000000000604482015260640161073d565b610614611426565b6014818154811061081157600080fd5b600091825260209091200154905081565b6015818154811061081157600080fd5b6016818154811061084257600080fd5b9060005260206000209060109182820401919006600202915054906101000a900461ffff1681565b6108726114a3565b3361089260005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461090f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c79206d61696e7461696e65720000000000000000000000000000000000604482015260640161073d565b610614611528565b60015473ffffffffffffffffffffffffffffffffffffffff163314610998576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c7920676f7665726e616e63650000000000000000000000000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff8116610a15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f20616464726573730000000000000000000000000000000000000000604482015260640161073d565b61075181611597565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610ad4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e69656400000000000000000000000000604482015260640161073d565b6107518161160c565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c7920676f7665726e616e63650000000000000000000000000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff8116610bdb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f20616464726573730000000000000000000000000000000000000000604482015260640161073d565b6107518161172e565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c9a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e69656400000000000000000000000000604482015260640161073d565b610751816000610e8c565b604080517fffffffff0000000000000000000000000000000000000000000000000000000083166020808301919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc8828401528251808303840181526060909201909252805191012054600090610685565b6017818154811061084257600080fd5b600080610dc56000357fffffffff0000000000000000000000000000000000000000000000000000000016604080517fffffffff00000000000000000000000000000000000000000000000000000000929092166020808401919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883830152815180840383018152606090930190915281519101205490565b905073ffffffffffffffffffffffffffffffffffffffff8116610e44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f50726f78793a496d706c656d656e746174696f6e206e6f7420666f756e640000604482015260640161073d565b919050565b3660008037600080366000845af43d6000803e808015610e68573d6000f35b3d6000fd5b805160009082908203610e835750600092915050565b50506020015190565b73ffffffffffffffffffffffffffffffffffffffff8216610f09576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f696e76616c696420696d706c656d656e746174696f6e20616464726573730000604482015260640161073d565b6000808373ffffffffffffffffffffffffffffffffffffffff16633e6b8c0d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610f57573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610f9d919081019061237e565b909250905080611009576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d6f64756c65206e616d652063616e6e6f7420626520656d7074790000000000604482015260640161073d565b60008181526011602052604081209080611024836001015490565b85519110915060005b8181101561121557600086828151811061104957611049612469565b6020026020010151905061107f87838151811061106857611068612469565b6020026020010151866117a590919063ffffffff16565b6111df57604080517fffffffff0000000000000000000000000000000000000000000000000000000083166020808301919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc882840152825180830384018152606090920190925280519101205473ffffffffffffffffffffffffffffffffffffffff8116156111b05788611172576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f63616e74207265706c616365206d6f64756c65732066756e6373000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601360209081526040808320548352601190915290206111ae90836117dc565b505b6111dc8884815181106111c5576111c5612469565b6020026020010151876119d890919063ffffffff16565b50505b6112028783815181106111f4576111f4612469565b60200260200101518a611a88565b508061120d816124c7565b91505061102d565b508115611339576000611236600061122e866001015490565b869190611bbb565b90508051915060005b8281101561133657600082828151811061125b5761125b612469565b602002602001015190508973ffffffffffffffffffffffffffffffffffffffff166112f182604080517fffffffff00000000000000000000000000000000000000000000000000000000929092166020808401919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883830152815180840383018152606090930190915281519101205490565b73ffffffffffffffffffffffffffffffffffffffff161461132357611317816000611a88565b61132186826117dc565b505b508061132e816124c7565b91505061123f565b50505b5050506000818152601260209081526040808320805473ffffffffffffffffffffffffffffffffffffffff9098167fffffffffffffffffffffffff0000000000000000000000000000000000000000909816881790559582526013905293909320929092555050565b60015474010000000000000000000000000000000000000000900460ff16610614576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161073d565b61142e6113a2565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b60015474010000000000000000000000000000000000000000900460ff1615610614576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161073d565b6115306114a3565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586114793390565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f2f3ffaaaad93928855c8700645d1a3643e6ccfdd500efa9fda048a88f557cf019190a35050565b73ffffffffffffffffffffffffffffffffffffffff8116611689576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c69642070726f7879206f776e657220616464726573730000000000604482015260640161073d565b8073ffffffffffffffffffffffffffffffffffffffff166116c87fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85490565b73ffffffffffffffffffffffffffffffffffffffff167f5a3e66efaa1e445ebd894728a69d6959842ea1e97bd79b892797106e270efcd960405160405180910390a37fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d855565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce8090600090a35050565b7fffffffff000000000000000000000000000000000000000000000000000000001660009081526020919091526040902054151590565b7fffffffff000000000000000000000000000000000000000000000000000000008116600090815260208390526040812054156119d0577fffffffff000000000000000000000000000000000000000000000000000000008216600090815260208490526040812054611851906001906124ff565b60018581015491925060009161186791906124ff565b905081811461193357600085600101828154811061188757611887612469565b90600052602060002090600891828204019190066004029054906101000a900460e01b9050808660010184815481106118c2576118c2612469565b90600052602060002090600891828204019190066004026101000a81548163ffffffff021916908360e01c02179055508260016118ff9190612512565b7fffffffff000000000000000000000000000000000000000000000000000000009091166000908152602087905260409020555b7fffffffff0000000000000000000000000000000000000000000000000000000084166000908152602086905260408120556001850180548061197857611978612525565b60008281526020902060087fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191820401805463ffffffff600460078516026101000a0219169055905550600191506106859050565b506000610685565b7fffffffff0000000000000000000000000000000000000000000000000000000081166000908152602083905260408120546119d05750600182810180548083018255600082815260208082206008840401805463ffffffff60079095166004026101000a948502191660e088901c949094029390931790925591547fffffffff000000000000000000000000000000000000000000000000000000008516835290859052604090912055610685565b611a9182611d68565b604080517fffffffff00000000000000000000000000000000000000000000000000000000841660208083018290527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883850152835180840385018152606084018086528151919092012054919052915173ffffffffffffffffffffffffffffffffffffffff8481169316917f347b48699b991c95bb339a3a778222488794b19790e9f46171825933c63a9cc4919081900360800190a3604080517fffffffff00000000000000000000000000000000000000000000000000000000939093166020808501919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc8848301528151808503830181526060909401909152825192019190912055565b60606000611bc98385612512565b905083811015611c35576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6164646974696f6e206f766572666c6f77000000000000000000000000000000604482015260640161073d565b60018501548111611c465780611c4c565b60018501545b9050801580611c5b5750808410155b15611c665750611d61565b611c7084826124ff565b67ffffffffffffffff811115611c8857611c88612344565b604051908082528060200260200182016040528015611cb1578160200160208202803683370190505b50915060005b611cc185836124ff565b811015611d5e5760018601611cd68683612512565b81548110611ce657611ce6612469565b90600052602060002090600891828204019190066004029054906101000a900460e01b838281518110611d1b57611d1b612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280611d56816124c7565b915050611cb7565b50505b9392505050565b6000611d72611e5a565b805190915060005b81811015611e5457828181518110611d9457611d94612469565b60200260200101517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603611e42576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f66756e6374696f6e20696420616c726561647920657869737473000000000000604482015260640161073d565b80611e4c816124c7565b915050611d7a565b50505050565b604080516008808252610120820190925260609160009190602082016101008036833701905050905063dc9cc64560e01b81600081518110611e9e57611e9e612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517fd784d426000000000000000000000000000000000000000000000000000000009082906001908110611f0657611f06612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f0e1cf91b000000000000000000000000000000000000000000000000000000009082906002908110611f6e57611f6e612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517e33c04b000000000000000000000000000000000000000000000000000000009082906003908110611fd557611fd5612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517fcaaee91c00000000000000000000000000000000000000000000000000000000908290600490811061203d5761203d612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f1ab7710d0000000000000000000000000000000000000000000000000000000090829060059081106120a5576120a5612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f8456cb5900000000000000000000000000000000000000000000000000000000908290600690811061210d5761210d612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f3f4ba83a00000000000000000000000000000000000000000000000000000000908290600790811061217557612175612469565b7fffffffff0000000000000000000000000000000000000000000000000000000090921660209283029190910190910152919050565b600080602083850312156121be57600080fd5b823567ffffffffffffffff808211156121d657600080fd5b818501915085601f8301126121ea57600080fd5b8135818111156121f957600080fd5b86602082850101111561220b57600080fd5b60209290920196919550909350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e4457600080fd5b60006020828403121561225357600080fd5b611d618261221d565b60006020828403121561226e57600080fd5b813562ffffff81168114611d6157600080fd5b803560ff81168114610e4457600080fd5b6000602082840312156122a457600080fd5b611d6182612281565b6000602082840312156122bf57600080fd5b5035919050565b600080604083850312156122d957600080fd5b6122e283612281565b91506122f06020840161221d565b90509250929050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461075157600080fd5b60006020828403121561233957600080fd5b8135611d61816122f9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8051610e44816122f9565b6000806040838503121561239157600080fd5b825167ffffffffffffffff808211156123a957600080fd5b818501915085601f8301126123bd57600080fd5b81516020828211156123d1576123d1612344565b8160051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110868211171561241457612414612344565b60405292835281830193508481018201928984111561243257600080fd5b948201945b838610156124575761244886612373565b85529482019493820193612437565b97909101519698969750505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036124f8576124f8612498565b5060010190565b8181038181111561068557610685612498565b8082018082111561068557610685612498565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea264697066735822122068744860d75a4537237f557979b48b9ca9b039108dd9eb25a5100a7dcee3f0a564736f6c63430008150033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
BERA | 100.00% | $3.66 | 0.000000000000003075 | <$0.000001 |
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.