Latest 25 from a total of 3,803 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Add Liquidity | 350297799 | 222 days ago | IN | 0 ETH | 0.00000206 | ||||
| Add Liquidity | 350297277 | 222 days ago | IN | 0 ETH | 0.00000209 | ||||
| Add Liquidity | 350295913 | 222 days ago | IN | 0 ETH | 0.00000208 | ||||
| Add Liquidity | 350295085 | 222 days ago | IN | 0 ETH | 0.00000206 | ||||
| Set Delegate | 350294383 | 222 days ago | IN | 0 ETH | 0.00000057 | ||||
| Add Liquidity | 350294220 | 222 days ago | IN | 0 ETH | 0.00000252 | ||||
| Add Liquidity | 350292837 | 222 days ago | IN | 0 ETH | 0.00000274 | ||||
| 0x7895ba4d | 348382395 | 228 days ago | IN | 0 ETH | 0.00000505 | ||||
| 0x7895ba4d | 348382334 | 228 days ago | IN | 0 ETH | 0.00000502 | ||||
| 0x7895ba4d | 348382283 | 228 days ago | IN | 0 ETH | 0.00000505 | ||||
| 0x7895ba4d | 348382173 | 228 days ago | IN | 0 ETH | 0.00000504 | ||||
| 0x7895ba4d | 348382121 | 228 days ago | IN | 0 ETH | 0.00000502 | ||||
| 0x7895ba4d | 348382072 | 228 days ago | IN | 0 ETH | 0.00000503 | ||||
| 0x7895ba4d | 348381824 | 228 days ago | IN | 0 ETH | 0.00000517 | ||||
| 0x7895ba4d | 348381771 | 228 days ago | IN | 0 ETH | 0.00000506 | ||||
| Clear Traders In... | 348380764 | 228 days ago | IN | 0 ETH | 0.00000332 | ||||
| Toggle Perp Emer... | 348380744 | 228 days ago | IN | 0 ETH | 0.00000145 | ||||
| Set Emergency St... | 348380724 | 228 days ago | IN | 0 ETH | 0.00000153 | ||||
| Clear Traders In... | 348380702 | 228 days ago | IN | 0 ETH | 0.00000338 | ||||
| Toggle Perp Emer... | 348380682 | 228 days ago | IN | 0 ETH | 0.00000145 | ||||
| Set Emergency St... | 348380662 | 228 days ago | IN | 0 ETH | 0.00000153 | ||||
| Clear Traders In... | 348380641 | 228 days ago | IN | 0 ETH | 0.00000332 | ||||
| Toggle Perp Emer... | 348380620 | 228 days ago | IN | 0 ETH | 0.00000145 | ||||
| Set Emergency St... | 348380600 | 228 days ago | IN | 0 ETH | 0.0000015 | ||||
| Clear Traders In... | 348380578 | 228 days ago | IN | 0 ETH | 0.00000327 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 348319757 | 228 days ago | 1 wei | ||||
| 348319757 | 228 days ago | 1 wei | ||||
| 346633713 | 233 days ago | 1 wei | ||||
| 346633713 | 233 days ago | 1 wei | ||||
| 344418108 | 239 days ago | 1 wei | ||||
| 344418108 | 239 days ago | 1 wei | ||||
| 344368683 | 240 days ago | 1 wei | ||||
| 344368683 | 240 days ago | 1 wei | ||||
| 341932536 | 247 days ago | 1 wei | ||||
| 341932536 | 247 days ago | 1 wei | ||||
| 341932531 | 247 days ago | 1 wei | ||||
| 341932531 | 247 days ago | 1 wei | ||||
| 341803321 | 247 days ago | 1 wei | ||||
| 341803321 | 247 days ago | 1 wei | ||||
| 339390966 | 254 days ago | 1 wei | ||||
| 339390966 | 254 days ago | 1 wei | ||||
| 339390835 | 254 days ago | 1 wei | ||||
| 339390835 | 254 days ago | 1 wei | ||||
| 338264455 | 257 days ago | 1 wei | ||||
| 338264455 | 257 days ago | 1 wei | ||||
| 330075677 | 281 days ago | 1 wei | ||||
| 330075677 | 281 days ago | 1 wei | ||||
| 330075561 | 281 days ago | 1 wei | ||||
| 330075561 | 281 days ago | 1 wei | ||||
| 330075359 | 281 days ago | 1 wei |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
PerpetualManagerProxy
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 10000000 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.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
pragma solidity ^0.8.0;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive() external payable virtual {
_fallback();
}
/**
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
* call, or as part of the Solidity `fallback` or `receive` functions.
*
* If overridden should call `super._beforeFallback()`.
*/
function _beforeFallback() internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)
// D8X, 2022
pragma solidity 0.8.21;
/**
* This is a modified version of the OpenZeppelin ownable contract
* Modifications
* - instead of an owner, we have two actors: maintainer and governance
* - maintainer can have certain priviledges but cannot transfer maintainer mandate
* - governance can exchange maintainer and exchange itself
* - renounceOwnership is removed
*
*
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Maintainable {
address private _maintainer;
address private _governance;
event MaintainerTransferred(address indexed previousMaintainer, address indexed newMaintainer);
event GovernanceTransferred(address indexed previousGovernance, address indexed newGovernance);
/**
* @dev Initializes the contract setting the deployer as the initial maintainer.
*/
constructor() {
_transferMaintainer(msg.sender);
_transferGovernance(msg.sender);
}
/**
* @dev Returns the address of the current owner.
*/
function maintainer() public view virtual returns (address) {
return _maintainer;
}
/**
* @dev Returns the address of the governance.
*/
function governance() public view virtual returns (address) {
return _governance;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyMaintainer() {
require(maintainer() == msg.sender, "only maintainer");
_;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyGovernance() {
require(governance() == msg.sender, "only governance");
_;
}
/**
* @dev Transfers maintainer mandate of the contract to a new account (`newMaintainer`).
* Can only be called by the governance.
*/
function transferMaintainer(address newMaintainer) public virtual {
require(msg.sender == _governance, "only governance");
require(newMaintainer != address(0), "zero address");
_transferMaintainer(newMaintainer);
}
/**
* @dev Transfers governance mandate of the contract to a new account (`newGovernance`).
* Can only be called by the governance.
*/
function transferGovernance(address newGovernance) public virtual {
require(msg.sender == _governance, "only governance");
require(newGovernance != address(0), "zero address");
_transferGovernance(newGovernance);
}
/**
* @dev Transfers maintainer of the contract to a new account (`newMaintainer`).
* Internal function without access restriction.
*/
function _transferMaintainer(address newMaintainer) internal virtual {
address oldM = _maintainer;
_maintainer = newMaintainer;
emit MaintainerTransferred(oldM, newMaintainer);
}
/**
* @dev Transfers governance of the contract to a new account (`newGovernance`).
* Internal function without access restriction.
*/
function _transferGovernance(address newGovernance) internal virtual {
address oldG = _governance;
_governance = newGovernance;
emit GovernanceTransferred(oldG, newGovernance);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
interface IShareTokenFactory {
function createShareToken(uint8 _poolId, address _marginTokenAddr) external returns (address);
}// SPDX-License-Identifier: BSD-4-Clause /* * ABDK Math 64.64 Smart Contract Library. Copyright © 2019 by ABDK Consulting. * Author: Mikhail Vladimirov <[email protected]> */ pragma solidity 0.8.21; /** * Smart contract library of mathematical functions operating with signed * 64.64-bit fixed point numbers. Signed 64.64-bit fixed point number is * basically a simple fraction whose numerator is signed 128-bit integer and * denominator is 2^64. As long as denominator is always the same, there is no * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are * represented by int128 type holding only the numerator. */ library ABDKMath64x64 { /* * Minimum value signed 64.64-bit fixed point number may have. */ int128 private constant MIN_64x64 = -0x80000000000000000000000000000000; /* * Maximum value signed 64.64-bit fixed point number may have. */ int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; /** * Convert signed 256-bit integer number into signed 64.64-bit fixed point * number. Revert on overflow. * * @param x signed 256-bit integer number * @return signed 64.64-bit fixed point number */ function fromInt(int256 x) internal pure returns (int128) { require(x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF, "ABDK.fromInt"); return int128(x << 64); } /** * Convert signed 64.64 fixed point number into signed 64-bit integer number * rounding down. * * @param x signed 64.64-bit fixed point number * @return signed 64-bit integer number */ function toInt(int128 x) internal pure returns (int64) { return int64(x >> 64); } /** * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point * number. Revert on overflow. * * @param x unsigned 256-bit integer number * @return signed 64.64-bit fixed point number */ function fromUInt(uint256 x) internal pure returns (int128) { require(x <= 0x7FFFFFFFFFFFFFFF, "ABDK.fromUInt"); return int128(int256(x << 64)); } /** * Convert signed 64.64 fixed point number into unsigned 64-bit integer * number rounding down. Revert on underflow. * * @param x signed 64.64-bit fixed point number * @return unsigned 64-bit integer number */ function toUInt(int128 x) internal pure returns (uint64) { require(x >= 0, "ABDK.toUInt"); return uint64(uint128(x >> 64)); } /** * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point * number rounding down. Revert on overflow. * * @param x signed 128.128-bin fixed point number * @return signed 64.64-bit fixed point number */ function from128x128(int256 x) internal pure returns (int128) { int256 result = x >> 64; require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.from128x128"); return int128(result); } /** * Convert signed 64.64 fixed point number into signed 128.128 fixed point * number. * * @param x signed 64.64-bit fixed point number * @return signed 128.128 fixed point number */ function to128x128(int128 x) internal pure returns (int256) { return int256(x) << 64; } /** * Calculate x + y. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function add(int128 x, int128 y) internal pure returns (int128) { int256 result = int256(x) + y; require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.add"); return int128(result); } /** * Calculate x - y. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function sub(int128 x, int128 y) internal pure returns (int128) { int256 result = int256(x) - y; require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.sub"); return int128(result); } /** * Calculate x * y rounding down. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function mul(int128 x, int128 y) internal pure returns (int128) { int256 result = (int256(x) * y) >> 64; require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.mul"); return int128(result); } /** * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point * number and y is signed 256-bit integer number. Revert on overflow. * * @param x signed 64.64 fixed point number * @param y signed 256-bit integer number * @return signed 256-bit integer number */ function muli(int128 x, int256 y) internal pure returns (int256) { if (x == MIN_64x64) { require( y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF && y <= 0x1000000000000000000000000000000000000000000000000, "ABDK.muli-1" ); return -y << 63; } else { bool negativeResult = false; if (x < 0) { x = -x; negativeResult = true; } if (y < 0) { y = -y; // We rely on overflow behavior here negativeResult = !negativeResult; } uint256 absoluteResult = mulu(x, uint256(y)); if (negativeResult) { require( absoluteResult <= 0x8000000000000000000000000000000000000000000000000000000000000000, "ABDK.muli-2" ); return -int256(absoluteResult); // We rely on overflow behavior here } else { require( absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "ABDK.muli-3" ); return int256(absoluteResult); } } } /** * Calculate x * y rounding down, where x is signed 64.64 fixed point number * and y is unsigned 256-bit integer number. Revert on overflow. * * @param x signed 64.64 fixed point number * @param y unsigned 256-bit integer number * @return unsigned 256-bit integer number */ function mulu(int128 x, uint256 y) internal pure returns (uint256) { if (y == 0) return 0; require(x >= 0, "ABDK.mulu-1"); uint256 lo = (uint256(int256(x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64; uint256 hi = uint256(int256(x)) * (y >> 128); require(hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "ABDK.mulu-2"); hi <<= 64; require( hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo, "ABDK.mulu-3" ); return hi + lo; } /** * Calculate x / y rounding towards zero. Revert on overflow or when y is * zero. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function div(int128 x, int128 y) internal pure returns (int128) { require(y != 0, "ABDK.div-1"); int256 result = (int256(x) << 64) / y; require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.div-2"); return int128(result); } /** * Calculate x / y rounding towards zero, where x and y are signed 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x signed 256-bit integer number * @param y signed 256-bit integer number * @return signed 64.64-bit fixed point number */ function divi(int256 x, int256 y) internal pure returns (int128) { require(y != 0, "ABDK.divi-1"); bool negativeResult = false; if (x < 0) { x = -x; // We rely on overflow behavior here negativeResult = true; } if (y < 0) { y = -y; // We rely on overflow behavior here negativeResult = !negativeResult; } uint128 absoluteResult = divuu(uint256(x), uint256(y)); if (negativeResult) { require(absoluteResult <= 0x80000000000000000000000000000000, "ABDK.divi-2"); return -int128(absoluteResult); // We rely on overflow behavior here } else { require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "ABDK.divi-3"); return int128(absoluteResult); // We rely on overflow behavior here } } /** * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x unsigned 256-bit integer number * @param y unsigned 256-bit integer number * @return signed 64.64-bit fixed point number */ function divu(uint256 x, uint256 y) internal pure returns (int128) { require(y != 0, "ABDK.divu-1"); uint128 result = divuu(x, y); require(result <= uint128(MAX_64x64), "ABDK.divu-2"); return int128(result); } /** * Calculate -x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function neg(int128 x) internal pure returns (int128) { require(x != MIN_64x64, "ABDK.neg"); return -x; } /** * Calculate |x|. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function abs(int128 x) internal pure returns (int128) { require(x != MIN_64x64, "ABDK.abs"); return x < 0 ? -x : x; } /** * Calculate 1 / x rounding towards zero. Revert on overflow or when x is * zero. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function inv(int128 x) internal pure returns (int128) { require(x != 0, "ABDK.inv-1"); int256 result = int256(0x100000000000000000000000000000000) / x; require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.inv-2"); return int128(result); } /** * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function avg(int128 x, int128 y) internal pure returns (int128) { return int128((int256(x) + int256(y)) >> 1); } /** * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down. * Revert on overflow or in case x * y is negative. * * @param x signed 64.64-bit fixed point number * @param y signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function gavg(int128 x, int128 y) internal pure returns (int128) { int256 m = int256(x) * int256(y); require(m >= 0, "ABDK.gavg-1"); require( m < 0x4000000000000000000000000000000000000000000000000000000000000000, "ABDK.gavg-2" ); return int128(sqrtu(uint256(m))); } /** * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number * and y is unsigned 256-bit integer number. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @param y uint256 value * @return signed 64.64-bit fixed point number */ function pow(int128 x, uint256 y) internal pure returns (int128) { bool negative = x < 0 && y & 1 == 1; uint256 absX = uint128(x < 0 ? -x : x); uint256 absResult; absResult = 0x100000000000000000000000000000000; if (absX <= 0x10000000000000000) { absX <<= 63; while (y != 0) { if (y & 0x1 != 0) { absResult = (absResult * absX) >> 127; } absX = (absX * absX) >> 127; if (y & 0x2 != 0) { absResult = (absResult * absX) >> 127; } absX = (absX * absX) >> 127; if (y & 0x4 != 0) { absResult = (absResult * absX) >> 127; } absX = (absX * absX) >> 127; if (y & 0x8 != 0) { absResult = (absResult * absX) >> 127; } absX = (absX * absX) >> 127; y >>= 4; } absResult >>= 64; } else { uint256 absXShift = 63; if (absX < 0x1000000000000000000000000) { absX <<= 32; absXShift -= 32; } if (absX < 0x10000000000000000000000000000) { absX <<= 16; absXShift -= 16; } if (absX < 0x1000000000000000000000000000000) { absX <<= 8; absXShift -= 8; } if (absX < 0x10000000000000000000000000000000) { absX <<= 4; absXShift -= 4; } if (absX < 0x40000000000000000000000000000000) { absX <<= 2; absXShift -= 2; } if (absX < 0x80000000000000000000000000000000) { absX <<= 1; absXShift -= 1; } uint256 resultShift; while (y != 0) { require(absXShift < 64, "ABDK.pow-1"); if (y & 0x1 != 0) { absResult = (absResult * absX) >> 127; resultShift += absXShift; if (absResult > 0x100000000000000000000000000000000) { absResult >>= 1; resultShift += 1; } } absX = (absX * absX) >> 127; absXShift <<= 1; if (absX >= 0x100000000000000000000000000000000) { absX >>= 1; absXShift += 1; } y >>= 1; } require(resultShift < 64, "ABDK.pow-2"); absResult >>= 64 - resultShift; } int256 result = negative ? -int256(absResult) : int256(absResult); require(result >= MIN_64x64 && result <= MAX_64x64, "ABDK.pow-3"); return int128(result); } /** * Calculate sqrt (x) rounding down. Revert if x < 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function sqrt(int128 x) internal pure returns (int128) { require(x >= 0, "ABDK.sqrt"); return int128(sqrtu(uint256(int256(x)) << 64)); } /** * Calculate binary logarithm of x. Revert if x <= 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function log_2(int128 x) internal pure returns (int128) { require(x > 0, "ABDK.log_2"); int256 msb; int256 xc = x; if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; } if (xc >= 0x100000000) { xc >>= 32; msb += 32; } if (xc >= 0x10000) { xc >>= 16; msb += 16; } if (xc >= 0x100) { xc >>= 8; msb += 8; } if (xc >= 0x10) { xc >>= 4; msb += 4; } if (xc >= 0x4) { xc >>= 2; msb += 2; } if (xc >= 0x2) msb += 1; // No need to shift xc anymore int256 result = (msb - 64) << 64; uint256 ux = uint256(int256(x)) << uint256(127 - msb); for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) { ux *= ux; uint256 b = ux >> 255; ux >>= 127 + b; result += bit * int256(b); } return int128(result); } /** * Calculate natural logarithm of x. Revert if x <= 0. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function ln(int128 x) internal pure returns (int128) { unchecked { require(x > 0, "ABDK.ln"); return int128( int256((uint256(int256(log_2(x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF) >> 128) ); } } /** * Calculate binary exponent of x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function exp_2(int128 x) internal pure returns (int128) { require(x < 0x400000000000000000, "ABDK.exp_2-1"); // Overflow if (x < -0x400000000000000000) return 0; // Underflow uint256 result = 0x80000000000000000000000000000000; if (x & 0x8000000000000000 > 0) result = (result * 0x16A09E667F3BCC908B2FB1366EA957D3E) >> 128; if (x & 0x4000000000000000 > 0) result = (result * 0x1306FE0A31B7152DE8D5A46305C85EDEC) >> 128; if (x & 0x2000000000000000 > 0) result = (result * 0x1172B83C7D517ADCDF7C8C50EB14A791F) >> 128; if (x & 0x1000000000000000 > 0) result = (result * 0x10B5586CF9890F6298B92B71842A98363) >> 128; if (x & 0x800000000000000 > 0) result = (result * 0x1059B0D31585743AE7C548EB68CA417FD) >> 128; if (x & 0x400000000000000 > 0) result = (result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8) >> 128; if (x & 0x200000000000000 > 0) result = (result * 0x10163DA9FB33356D84A66AE336DCDFA3F) >> 128; if (x & 0x100000000000000 > 0) result = (result * 0x100B1AFA5ABCBED6129AB13EC11DC9543) >> 128; if (x & 0x80000000000000 > 0) result = (result * 0x10058C86DA1C09EA1FF19D294CF2F679B) >> 128; if (x & 0x40000000000000 > 0) result = (result * 0x1002C605E2E8CEC506D21BFC89A23A00F) >> 128; if (x & 0x20000000000000 > 0) result = (result * 0x100162F3904051FA128BCA9C55C31E5DF) >> 128; if (x & 0x10000000000000 > 0) result = (result * 0x1000B175EFFDC76BA38E31671CA939725) >> 128; if (x & 0x8000000000000 > 0) result = (result * 0x100058BA01FB9F96D6CACD4B180917C3D) >> 128; if (x & 0x4000000000000 > 0) result = (result * 0x10002C5CC37DA9491D0985C348C68E7B3) >> 128; if (x & 0x2000000000000 > 0) result = (result * 0x1000162E525EE054754457D5995292026) >> 128; if (x & 0x1000000000000 > 0) result = (result * 0x10000B17255775C040618BF4A4ADE83FC) >> 128; if (x & 0x800000000000 > 0) result = (result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB) >> 128; if (x & 0x400000000000 > 0) result = (result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9) >> 128; if (x & 0x200000000000 > 0) result = (result * 0x10000162E43F4F831060E02D839A9D16D) >> 128; if (x & 0x100000000000 > 0) result = (result * 0x100000B1721BCFC99D9F890EA06911763) >> 128; if (x & 0x80000000000 > 0) result = (result * 0x10000058B90CF1E6D97F9CA14DBCC1628) >> 128; if (x & 0x40000000000 > 0) result = (result * 0x1000002C5C863B73F016468F6BAC5CA2B) >> 128; if (x & 0x20000000000 > 0) result = (result * 0x100000162E430E5A18F6119E3C02282A5) >> 128; if (x & 0x10000000000 > 0) result = (result * 0x1000000B1721835514B86E6D96EFD1BFE) >> 128; if (x & 0x8000000000 > 0) result = (result * 0x100000058B90C0B48C6BE5DF846C5B2EF) >> 128; if (x & 0x4000000000 > 0) result = (result * 0x10000002C5C8601CC6B9E94213C72737A) >> 128; if (x & 0x2000000000 > 0) result = (result * 0x1000000162E42FFF037DF38AA2B219F06) >> 128; if (x & 0x1000000000 > 0) result = (result * 0x10000000B17217FBA9C739AA5819F44F9) >> 128; if (x & 0x800000000 > 0) result = (result * 0x1000000058B90BFCDEE5ACD3C1CEDC823) >> 128; if (x & 0x400000000 > 0) result = (result * 0x100000002C5C85FE31F35A6A30DA1BE50) >> 128; if (x & 0x200000000 > 0) result = (result * 0x10000000162E42FF0999CE3541B9FFFCF) >> 128; if (x & 0x100000000 > 0) result = (result * 0x100000000B17217F80F4EF5AADDA45554) >> 128; if (x & 0x80000000 > 0) result = (result * 0x10000000058B90BFBF8479BD5A81B51AD) >> 128; if (x & 0x40000000 > 0) result = (result * 0x1000000002C5C85FDF84BD62AE30A74CC) >> 128; if (x & 0x20000000 > 0) result = (result * 0x100000000162E42FEFB2FED257559BDAA) >> 128; if (x & 0x10000000 > 0) result = (result * 0x1000000000B17217F7D5A7716BBA4A9AE) >> 128; if (x & 0x8000000 > 0) result = (result * 0x100000000058B90BFBE9DDBAC5E109CCE) >> 128; if (x & 0x4000000 > 0) result = (result * 0x10000000002C5C85FDF4B15DE6F17EB0D) >> 128; if (x & 0x2000000 > 0) result = (result * 0x1000000000162E42FEFA494F1478FDE05) >> 128; if (x & 0x1000000 > 0) result = (result * 0x10000000000B17217F7D20CF927C8E94C) >> 128; if (x & 0x800000 > 0) result = (result * 0x1000000000058B90BFBE8F71CB4E4B33D) >> 128; if (x & 0x400000 > 0) result = (result * 0x100000000002C5C85FDF477B662B26945) >> 128; if (x & 0x200000 > 0) result = (result * 0x10000000000162E42FEFA3AE53369388C) >> 128; if (x & 0x100000 > 0) result = (result * 0x100000000000B17217F7D1D351A389D40) >> 128; if (x & 0x80000 > 0) result = (result * 0x10000000000058B90BFBE8E8B2D3D4EDE) >> 128; if (x & 0x40000 > 0) result = (result * 0x1000000000002C5C85FDF4741BEA6E77E) >> 128; if (x & 0x20000 > 0) result = (result * 0x100000000000162E42FEFA39FE95583C2) >> 128; if (x & 0x10000 > 0) result = (result * 0x1000000000000B17217F7D1CFB72B45E1) >> 128; if (x & 0x8000 > 0) result = (result * 0x100000000000058B90BFBE8E7CC35C3F0) >> 128; if (x & 0x4000 > 0) result = (result * 0x10000000000002C5C85FDF473E242EA38) >> 128; if (x & 0x2000 > 0) result = (result * 0x1000000000000162E42FEFA39F02B772C) >> 128; if (x & 0x1000 > 0) result = (result * 0x10000000000000B17217F7D1CF7D83C1A) >> 128; if (x & 0x800 > 0) result = (result * 0x1000000000000058B90BFBE8E7BDCBE2E) >> 128; if (x & 0x400 > 0) result = (result * 0x100000000000002C5C85FDF473DEA871F) >> 128; if (x & 0x200 > 0) result = (result * 0x10000000000000162E42FEFA39EF44D91) >> 128; if (x & 0x100 > 0) result = (result * 0x100000000000000B17217F7D1CF79E949) >> 128; if (x & 0x80 > 0) result = (result * 0x10000000000000058B90BFBE8E7BCE544) >> 128; if (x & 0x40 > 0) result = (result * 0x1000000000000002C5C85FDF473DE6ECA) >> 128; if (x & 0x20 > 0) result = (result * 0x100000000000000162E42FEFA39EF366F) >> 128; if (x & 0x10 > 0) result = (result * 0x1000000000000000B17217F7D1CF79AFA) >> 128; if (x & 0x8 > 0) result = (result * 0x100000000000000058B90BFBE8E7BCD6D) >> 128; if (x & 0x4 > 0) result = (result * 0x10000000000000002C5C85FDF473DE6B2) >> 128; if (x & 0x2 > 0) result = (result * 0x1000000000000000162E42FEFA39EF358) >> 128; if (x & 0x1 > 0) result = (result * 0x10000000000000000B17217F7D1CF79AB) >> 128; result >>= uint256(int256(63 - (x >> 64))); require(result <= uint256(int256(MAX_64x64)), "ABDK.exp_2-2"); return int128(int256(result)); } /** * Calculate natural exponent of x. Revert on overflow. * * @param x signed 64.64-bit fixed point number * @return signed 64.64-bit fixed point number */ function exp(int128 x) internal pure returns (int128) { require(x < 0x400000000000000000, "ABDK.exp"); // Overflow if (x < -0x400000000000000000) return 0; // Underflow return exp_2(int128((int256(x) * 0x171547652B82FE1777D0FFDA0D23A7D12) >> 128)); } /** * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit * integer numbers. Revert on overflow or when y is zero. * * @param x unsigned 256-bit integer number * @param y unsigned 256-bit integer number * @return unsigned 64.64-bit fixed point number */ function divuu(uint256 x, uint256 y) private pure returns (uint128) { require(y != 0, "ABDK.divuu-1"); uint256 result; if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) result = (x << 64) / y; else { uint256 msb = 192; uint256 xc = x >> 192; if (xc >= 0x100000000) { xc >>= 32; msb += 32; } if (xc >= 0x10000) { xc >>= 16; msb += 16; } if (xc >= 0x100) { xc >>= 8; msb += 8; } if (xc >= 0x10) { xc >>= 4; msb += 4; } if (xc >= 0x4) { xc >>= 2; msb += 2; } if (xc >= 0x2) msb += 1; // No need to shift xc anymore result = (x << (255 - msb)) / (((y - 1) >> (msb - 191)) + 1); require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "ABDK.divuu-2"); uint256 hi = result * (y >> 128); uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); uint256 xh = x >> 192; uint256 xl = x << 64; if (xl < lo) xh -= 1; xl -= lo; // We rely on overflow behavior here lo = hi << 128; if (xl < lo) xh -= 1; xl -= lo; // We rely on overflow behavior here assert(xh == hi >> 128); result += xl / y; } require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "ABDK.divuu-3"); return uint128(result); } /** * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer * number. * * @param x unsigned 256-bit integer number * @return unsigned 128-bit integer number */ function sqrtu(uint256 x) private pure returns (uint128) { if (x == 0) return 0; else { uint256 xx = x; uint256 r = 1; if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; } if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; } if (xx >= 0x100000000) { xx >>= 32; r <<= 16; } if (xx >= 0x10000) { xx >>= 16; r <<= 8; } if (xx >= 0x100) { xx >>= 8; r <<= 4; } if (xx >= 0x10) { xx >>= 4; r <<= 2; } if (xx >= 0x8) { r <<= 1; } r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; // Seven iterations should be enough uint256 r1 = x / r; return uint128(r < r1 ? r : r1); } } }
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import "./ABDKMath64x64.sol";
library ConverterDec18 {
using ABDKMath64x64 for int128;
/*
* Minimum value signed 64.64-bit fixed point number may have.
*/
int128 private constant MIN_64x64 = -0x80000000000000000000000000000000;
/*
* Maximum value signed 64.64-bit fixed point number may have.
*/
int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
int256 private constant DECIMALS = 10**18;
int128 private constant ONE_64x64 = 0x010000000000000000;
int128 public constant HALF_TBPS = 92233720368548; //1e-5 * 0.5 * 2**64
// convert tenth of basis point to dec 18:
uint256 public constant TBPSTODEC18 = 0x9184e72a000; // hex(10^18 * 10^-5)=(10^13)
// convert tenth of basis point to ABDK 64x64:
int128 public constant TBPSTOABDK = 0xa7c5ac471b48; // hex(2^64 * 10^-5)
// convert two-digit integer reprentation to ABDK
int128 public constant TDRTOABDK = 0x28f5c28f5c28f5c; // hex(2^64 * 10^-2)
function tbpsToDec18(uint16 Vtbps) internal pure returns (uint256) {
return TBPSTODEC18 * uint256(Vtbps);
}
function tbpsToABDK(uint16 Vtbps) internal pure returns (int128) {
return int128(uint128(TBPSTOABDK) * uint128(Vtbps));
}
function TDRToABDK(uint16 V2Tdr) internal pure returns (int128) {
return int128(uint128(TDRTOABDK) * uint128(V2Tdr));
}
function ABDKToTbps(int128 Vabdk) internal pure returns (uint16) {
// add 0.5 * 1e-5 to ensure correct rounding to tenth of bps
return uint16(uint128(Vabdk.add(HALF_TBPS) / TBPSTOABDK));
}
function fromDec18(int256 x) internal pure returns (int128) {
int256 result = (x * ONE_64x64) / DECIMALS;
require(x >= MIN_64x64 && x <= MAX_64x64, "result out of range");
return int128(result);
}
function toDec18(int128 x) internal pure returns (int256) {
return (int256(x) * DECIMALS) / ONE_64x64;
}
function toUDec18(int128 x) internal pure returns (uint256) {
require(x >= 0, "negative value");
return uint256(toDec18(x));
}
function toUDecN(int128 x, uint8 decimals) internal pure returns (uint256) {
require(x >= 0, "negative value");
return uint256((int256(x) * int256(10**decimals)) / ONE_64x64);
}
function fromDecN(int256 x, uint8 decimals) internal pure returns (int128) {
int256 result = (x * ONE_64x64) / int256(10**decimals);
require(x >= MIN_64x64 && x <= MAX_64x64, "result out of range");
return int128(result);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
/**
* @title Library for managing loan sets.
*
* @notice Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* Include with `using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set;`.
* */
library EnumerableBytes4Set {
struct Bytes4Set {
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes4 => uint256) index;
bytes4[] values;
}
/**
* @notice Add a value to a set. O(1).
*
* @param set The set of values.
* @param value The new value to add.
*
* @return False if the value was already in the set.
*/
function addBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {
if (!contains(set, value)) {
set.values.push(value);
set.index[value] = set.values.length;
return true;
} else {
return false;
}
}
/**
* @notice Remove a value from a set. O(1).
*
* @param set The set of values.
* @param value The value to remove.
*
* @return False if the value was not present in the set.
*/
function removeBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {
if (contains(set, value)) {
uint256 toDeleteIndex = set.index[value] - 1;
uint256 lastIndex = set.values.length - 1;
/// If the element we're deleting is the last one,
/// we can just remove it without doing a swap.
if (lastIndex != toDeleteIndex) {
bytes4 lastValue = set.values[lastIndex];
/// Move the last value to the index where the deleted value is.
set.values[toDeleteIndex] = lastValue;
/// Update the index for the moved value.
set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based
}
/// Delete the index entry for the deleted value.
delete set.index[value];
/// Delete the old entry for the moved value.
set.values.pop();
return true;
} else {
return false;
}
}
/**
* @notice Find out whether a value exists in the set.
*
* @param set The set of values.
* @param value The value to find.
*
* @return True if the value is in the set. O(1).
*/
function contains(Bytes4Set storage set, bytes4 value) internal view returns (bool) {
return set.index[value] != 0;
}
/**
* @notice Get all set values.
*
* @param set The set of values.
* @param start The offset of the returning set.
* @param count The limit of number of values to return.
*
* @return output An array with all values in the set. O(N).
*
* @dev Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* WARNING: This function may run out of gas on large sets: use {length} and
* {get} instead in these cases.
*/
function enumerate(
Bytes4Set storage set,
uint256 start,
uint256 count
) internal view returns (bytes4[] memory output) {
uint256 end = start + count;
require(end >= start, "addition overflow");
end = set.values.length < end ? set.values.length : end;
if (end == 0 || start >= end) {
return output;
}
output = new bytes4[](end - start);
for (uint256 i; i < end - start; i++) {
output[i] = set.values[i + start];
}
return output;
}
/**
* @notice Get the legth of the set.
*
* @param set The set of values.
*
* @return the number of elements on the set. O(1).
*/
function length(Bytes4Set storage set) internal view returns (uint256) {
return set.values.length;
}
/**
* @notice Get an item from the set by its index.
*
* @dev Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*
* @param set The set of values.
* @param index The index of the value to return.
*
* @return the element stored at position `index` in the set. O(1).
*/
function get(Bytes4Set storage set, uint256 index) internal view returns (bytes4) {
return set.values[index];
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*/
library EnumerableSetUpgradeable {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
// When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
// so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
bytes32 lastvalue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastvalue;
// Update the index for the moved value
set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
require(set._values.length > index, "EnumerableSet: idx out of bounds");
return set._values[index];
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
function enumerate(
AddressSet storage set,
uint256 start,
uint256 count
) internal view returns (address[] memory output) {
uint256 end = start + count;
require(end >= start, "addition overflow");
uint256 len = length(set);
end = len < end ? len : end;
if (end == 0 || start >= end) {
return output;
}
output = new address[](end - start);
for (uint256 i; i < end - start; i++) {
output[i] = at(set, i + start);
}
return output;
}
function enumerateAll(AddressSet storage set) internal view returns (address[] memory output) {
return enumerate(set, 0, length(set));
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
library Utils {
function stringToBytes32(string memory source) internal pure returns (bytes32 result) {
bytes memory tempEmptyStringTest = bytes(source);
if (tempEmptyStringTest.length == 0) {
return 0x0;
}
assembly {
result := mload(add(source, 32))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "../../interface/IShareTokenFactory.sol";
import "../../libraries/ABDKMath64x64.sol";
import "./../functions/AMMPerpLogic.sol";
import "../../libraries/EnumerableSetUpgradeable.sol";
import "../../libraries/EnumerableBytes4Set.sol";
import "../../governance/Maintainable.sol";
/* solhint-disable max-states-count */
contract PerpStorage is Maintainable, Pausable, ReentrancyGuard {
using ABDKMath64x64 for int128;
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set; // enumerable map of bytes4 or addresses
/**
* @notice Perpetual state:
* - INVALID: Uninitialized or not non-existent perpetual.
* - INITIALIZING: Only when LiquidityPoolData.isRunning == false. Traders cannot perform operations.
* - NORMAL: Full functional state. Traders are able to perform all operations.
* - EMERGENCY: Perpetual is unsafe and the perpetual needs to be settled.
* - SETTLE: Perpetual ready to be settled
* - CLEARED: All margin accounts are cleared. Traders can withdraw remaining margin balance.
*/
enum PerpetualState {
INVALID,
INITIALIZING,
NORMAL,
EMERGENCY,
SETTLE,
CLEARED
}
// margin and liquidity pool are held in 'collateral currency' which can be either of
// quote currency, base currency, or quanto currency
// solhint-disable-next-line const-name-snakecase
int128 internal constant ONE_64x64 = 0x10000000000000000; // 2^64
int128 internal constant FUNDING_INTERVAL_SEC = 0x70800000000000000000; //3600 * 8 * 0x10000000000000000 = 8h in seconds scaled by 2^64 for ABDKMath64x64
int128 internal constant MIN_NUM_LOTS_PER_POSITION = 0x0a0000000000000000; // 10, minimal position size in number of lots
uint8 internal constant MASK_ORDER_CANCELLED = 0x1;
uint8 internal constant MASK_ORDER_EXECUTED = 0x2;
// at target, 1% of missing amount is transferred
// at every rebalance
uint8 internal iPoolCount;
// delay required for trades to mitigate oracle front-running in seconds
uint8 internal iTradeDelaySec;
address internal ammPerpLogic;
IShareTokenFactory internal shareTokenFactory;
//pool id (incremental index, starts from 1) => pool data
mapping(uint8 => LiquidityPoolData) internal liquidityPools;
//perpetual id => pool id
mapping(uint24 => uint8) internal perpetualPoolIds;
address internal orderBookFactory;
/**
* @notice Data structure to store oracle price data.
*/
struct PriceTimeData {
int128 fPrice;
uint64 time;
}
/**
* @notice Data structure to store user margin information.
*/
struct MarginAccount {
int128 fLockedInValueQC; // unrealized value locked-in when trade occurs
int128 fCashCC; // cash in collateral currency (base, quote, or quanto)
int128 fPositionBC; // position in base currency (e.g., 1 BTC for BTCUSD)
int128 fUnitAccumulatedFundingStart; // accumulated funding rate
}
/**
* @notice Store information for a given perpetual market.
*/
struct PerpetualData {
// ------ 0
uint8 poolId;
uint24 id;
int32 fInitialMarginRate; //parameter: initial margin
int32 fSigma2; // parameter: volatility of base-quote pair
uint32 iLastFundingTime; //timestamp since last funding rate payment
int32 fDFCoverNRate; // parameter: cover-n rule for default fund. E.g., fDFCoverNRate=0.05 -> we try to cover 5% of active accounts with default fund
int32 fMaintenanceMarginRate; // parameter: maintenance margin
PerpetualState state; // Perpetual AMM state
AMMPerpLogic.CollateralCurrency eCollateralCurrency; //parameter: in what currency is the collateral held?
// uint16 minimalSpreadTbps; //parameter: minimal spread between long and short perpetual price
// ------ 1
bytes4 S2BaseCCY; //base currency of S2
bytes4 S2QuoteCCY; //quote currency of S2
uint16 incentiveSpreadTbps; //parameter: maximum spread added to the PD
uint16 minimalSpreadTbps; //parameter: minimal spread between long and short perpetual price
bytes4 S3BaseCCY; //base currency of S3
bytes4 S3QuoteCCY; //quote currency of S3
int32 fSigma3; // parameter: volatility of quanto-quote pair
int32 fRho23; // parameter: correlation of quanto/base returns
uint16 liquidationPenaltyRateTbps; //parameter: penalty if AMM closes the position and not the trader
//------- 2
PriceTimeData currentMarkPremiumRate; //relative diff to index price EMA, used for markprice.
//------- 3
int128 premiumRatesEMA; // EMA of premium rate
int128 fUnitAccumulatedFunding; //accumulated funding in collateral currency
//------- 4
int128 fOpenInterest; //open interest is the larger of the amount of long and short positions in base currency
int128 fTargetAMMFundSize; //target liquidity pool funds to allocate to the AMM
//------- 5
int128 fCurrentTraderExposureEMA; // trade amounts (storing absolute value)
int128 fCurrentFundingRate; // current instantaneous funding rate
//------- 6
int128 fLotSizeBC; //parameter: minimal trade unit (in base currency) to avoid dust positions
int128 fReferralRebateCC; //parameter: referall rebate in collateral currency
//------- 7
int128 fTargetDFSize; // target default fund size
int128 fkStar; // signed trade size that minimizes the AMM risk
//------- 8
int128 fAMMTargetDD; // parameter: target distance to default (=inverse of default probability)
int128 fAMMMinSizeCC; // parameter: minimal size of AMM pool, regardless of current exposure
//------- 9
int128 fMinimalTraderExposureEMA; // parameter: minimal value for fCurrentTraderExposureEMA that we don't want to undershoot
int128 fMinimalAMMExposureEMA; // parameter: minimal abs value for fCurrentAMMExposureEMA that we don't want to undershoot
//------- 10
int128 fSettlementS3PriceData; //quanto index
int128 fSettlementS2PriceData; //base-quote pair. Used as last price in normal state.
//------- 11
int128 fTotalMarginBalance; //calculated for settlement, in collateral currency
int32 fMarkPriceEMALambda; // parameter: Lambda parameter for EMA used in mark-price for funding rates
int32 fFundingRateClamp; // parameter: funding rate clamp between which we charge 1bps
int32 fMaximalTradeSizeBumpUp; // parameter: >1, users can create a maximal position of size fMaximalTradeSizeBumpUp*fCurrentAMMExposureEMA
uint32 iLastTargetPoolSizeTime; //timestamp (seconds) since last update of fTargetDFSize and fTargetAMMFundSize
//------- 12
//-------
int128[2] fStressReturnS3; // parameter: negative and positive stress returns for quanto-quote asset
int128[2] fDFLambda; // parameter: EMA lambda for AMM and trader exposure K,k: EMA*lambda + (1-lambda)*K. 0 regular lambda, 1 if current value exceeds past
int128[2] fCurrentAMMExposureEMA; // 0: negative aggregated exposure (storing negative value), 1: positive
int128[2] fStressReturnS2; // parameter: negative and positive stress returns for base-quote asset
// -----
}
address internal oracleFactoryAddress;
// users
mapping(uint24 => EnumerableSetUpgradeable.AddressSet) internal activeAccounts; //perpetualId => traderAddressSet
// accounts
mapping(uint24 => mapping(address => MarginAccount)) internal marginAccounts;
// delegates
mapping(address => address) internal delegates;
// broker maps: poolId -> brokeraddress-> lots contributed
// contains non-zero entries for brokers. Brokers pay default fund contributions.
mapping(uint8 => mapping(address => uint32)) internal brokerMap;
struct LiquidityPoolData {
bool isRunning; // state
uint8 iPerpetualCount; // state
uint8 id; // parameter: index, starts from 1
int32 fCeilPnLShare; // parameter: cap on the share of PnL allocated to liquidity providers
uint8 marginTokenDecimals; // parameter: decimals of margin token, inferred from token contract
uint16 iTargetPoolSizeUpdateTime; //parameter: timestamp in seconds. How often we update the pool's target size
address marginTokenAddress; //parameter: address of the margin token
// -----
uint64 prevAnchor; // state: keep track of timestamp since last withdrawal was initiated
int128 fRedemptionRate; // state: used for settlement in case of AMM default
address shareTokenAddress; // parameter
// -----
int128 fPnLparticipantsCashCC; // state: addLiquidity/withdrawLiquidity + profit/loss - rebalance
int128 fTargetAMMFundSize; // state: target liquidity for all perpetuals in pool (sum)
// -----
int128 fDefaultFundCashCC; // state: profit/loss
int128 fTargetDFSize; // state: target default fund size for all perpetuals in pool
// -----
int128 fBrokerCollateralLotSize; // param:how much collateral do brokers deposit when providing "1 lot" (not trading lot)
uint128 prevTokenAmount; // state
// -----
uint128 nextTokenAmount; // state
uint128 totalSupplyShareToken; // state
// -----
int128 fBrokerFundCashCC; // state: amount of cash in broker fund
}
address internal treasuryAddress; // address for the protocol treasury
//pool id => perpetual id list
mapping(uint8 => uint24[]) internal perpetualIds;
//pool id => perpetual id => data
mapping(uint8 => mapping(uint24 => PerpetualData)) internal perpetuals;
/// @dev flag whether MarginTradeOrder was already executed or cancelled
mapping(bytes32 => uint8) internal executedOrCancelledOrders;
//proxy
mapping(bytes32 => EnumerableBytes4Set.Bytes4Set) internal moduleActiveFuncSignatureList;
mapping(bytes32 => address) internal moduleNameToAddress;
mapping(address => bytes32) internal moduleAddressToModuleName;
// fee structure
struct VolumeEMA {
int128 fTradingVolumeEMAusd; //trading volume EMA in usd
uint64 timestamp; // timestamp of last trade
}
uint256[] public traderVolumeTiers; // dec18, regardless of token
uint256[] public brokerVolumeTiers; // dec18, regardless of token
uint16[] public traderVolumeFeesTbps;
uint16[] public brokerVolumeFeesTbps;
mapping(uint24 => address) public perpBaseToUSDOracle;
mapping(uint24 => int128) public perpToLastBaseToUSD;
mapping(uint8 => mapping(address => VolumeEMA)) public traderVolumeEMA;
mapping(uint8 => mapping(address => VolumeEMA)) public brokerVolumeEMA;
uint64 public lastBaseToUSDUpdateTs;
// liquidity withdrawals
struct WithdrawRequest {
address lp;
uint256 shareTokens;
uint64 withdrawTimestamp;
}
mapping(address => mapping(uint8 => WithdrawRequest)) internal lpWithdrawMap;
// users who initiated withdrawals are registered here
mapping(uint8 => EnumerableSetUpgradeable.AddressSet) internal activeWithdrawals; //poolId => lpAddressSet
mapping(uint8 => bool) public liquidityProvisionIsPaused;
}
/* solhint-enable max-states-count */// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import "../../libraries/ABDKMath64x64.sol";
import "../../libraries/ConverterDec18.sol";
import "../../perpetual/interfaces/IAMMPerpLogic.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract AMMPerpLogic is Ownable, IAMMPerpLogic {
using ABDKMath64x64 for int128;
/* solhint-disable const-name-snakecase */
int128 internal constant ONE_64x64 = 0x10000000000000000; // 2^64
int128 internal constant TWO_64x64 = 0x20000000000000000; // 2*2^64
int128 internal constant FOUR_64x64 = 0x40000000000000000; //4*2^64
int128 internal constant HALF_64x64 = 0x8000000000000000; //0.5*2^64
int128 internal constant TWENTY_64x64 = 0x140000000000000000; //20*2^64
int128 private constant CDF_CONST_0 = 0x023a6ce358298c;
int128 private constant CDF_CONST_1 = -0x216c61522a6f3f;
int128 private constant CDF_CONST_2 = 0xc9320d9945b6c3;
int128 private constant CDF_CONST_3 = -0x01bcfd4bf0995aaf;
int128 private constant CDF_CONST_4 = -0x086de76427c7c501;
int128 private constant CDF_CONST_5 = 0x749741d084e83004;
int128 private constant CDF_CONST_6 = 0xcc42299ea1b28805;
int128 private constant CDF_CONST_7 = 0x0281b263fec4e0a007;
int128 private constant EXPM1_Q0 = 0x0a26c00000000000000000;
int128 private constant EXPM1_Q1 = 0x0127500000000000000000;
int128 private constant EXPM1_P0 = 0x0513600000000000000000;
int128 private constant EXPM1_P1 = 0x27600000000000000000;
int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
/* solhint-enable const-name-snakecase */
enum CollateralCurrency {
QUOTE,
BASE,
QUANTO
}
struct AMMVariables {
// all variables are
// signed 64.64-bit fixed point number
int128 fLockedValue1; // L1 in quote currency
int128 fPoolM1; // M1 in quote currency
int128 fPoolM2; // M2 in base currency
int128 fPoolM3; // M3 in quanto currency
int128 fAMM_K2; // AMM exposure (positive if trader long)
int128 fCurrentTraderExposureEMA; // current average unsigned trader exposure
}
struct MarketVariables {
int128 fIndexPriceS2; // base index
int128 fIndexPriceS3; // quanto index
int128 fSigma2; // standard dev of base currency
int128 fSigma3; // standard dev of quanto currency
int128 fRho23; // correlation base/quanto currency
}
/**
* Calculate a EWMA when the last observation happened n periods ago
* @dev Given is x_t = (1 - lambda) * mean + lambda * x_t-1, and x_0 = _newObs
* it returns the value of x_deltaTime
* @param _mean long term mean
* @param _newObs observation deltaTime periods ago
* @param _fLambda lambda of the EWMA
* @param _deltaTime number of periods elapsed
* @return result EWMA at deltaPeriods
*/
function _emaWithTimeJumps(
uint16 _mean,
uint16 _newObs,
int128 _fLambda,
uint256 _deltaTime
) internal pure returns (int128 result) {
_fLambda = _fLambda.pow(_deltaTime);
result = ConverterDec18.tbpsToABDK(_mean).mul(ONE_64x64.sub(_fLambda));
result = result.add(_fLambda.mul(ConverterDec18.tbpsToABDK(_newObs)));
}
/**
* Calculate the normal CDF value of _fX, i.e.,
* k=P(X<=_fX), for X~normal(0,1)
* The approximation is of the form
* Phi(x) = 1 - phi(x) / (x + exp(p(x))),
* where p(x) is a polynomial of degree 6
* @param _fX signed 64.64-bit fixed point number
* @return fY approximated normal-cdf evaluated at X
*/
function _normalCDF(int128 _fX) internal pure returns (int128 fY) {
bool isNegative = _fX < 0;
if (isNegative) {
_fX = _fX.neg();
}
if (_fX > FOUR_64x64) {
fY = int128(0);
} else {
fY = _fX.mul(CDF_CONST_0).add(CDF_CONST_1);
fY = _fX.mul(fY).add(CDF_CONST_2);
fY = _fX.mul(fY).add(CDF_CONST_3);
fY = _fX.mul(fY).add(CDF_CONST_4);
fY = _fX.mul(fY).add(CDF_CONST_5).mul(_fX).neg().exp();
fY = fY.mul(CDF_CONST_6).add(_fX);
fY = _fX.mul(_fX).mul(HALF_64x64).neg().exp().div(CDF_CONST_7).div(fY);
}
if (!isNegative) {
fY = ONE_64x64.sub(fY);
}
return fY;
}
/**
* Calculate the target size for the default fund
*
* @param _fK2AMM signed 64.64-bit fixed point number, Conservative negative[0]/positive[1] AMM exposure
* @param _fk2Trader signed 64.64-bit fixed point number, Conservative (absolute) trader exposure
* @param _fCoverN signed 64.64-bit fixed point number, cover-n rule for default fund parameter
* @param fStressRet2 signed 64.64-bit fixed point number, negative[0]/positive[1] stress returns for base/quote pair
* @param fStressRet3 signed 64.64-bit fixed point number, negative[0]/positive[1] stress returns for quanto/quote currency
* @param fIndexPrices signed 64.64-bit fixed point number, spot price for base/quote[0] and quanto/quote[1] pairs
* @param _eCCY enum that specifies in which currency the collateral is held: QUOTE, BASE, QUANTO
* @return approximated normal-cdf evaluated at X
*/
function calculateDefaultFundSize(
int128[2] memory _fK2AMM,
int128 _fk2Trader,
int128 _fCoverN,
int128[2] memory fStressRet2,
int128[2] memory fStressRet3,
int128[2] memory fIndexPrices,
AMMPerpLogic.CollateralCurrency _eCCY
) external pure override returns (int128) {
require(_fK2AMM[0] < 0, "_fK2AMM[0] must be negative");
require(_fK2AMM[1] > 0, "_fK2AMM[1] must be positive");
require(_fk2Trader > 0, "_fk2Trader must be positive");
int128[2] memory fEll;
// downward stress scenario
fEll[0] = (_fK2AMM[0].abs().add(_fk2Trader.mul(_fCoverN))).mul(
ONE_64x64.sub((fStressRet2[0].exp()))
);
// upward stress scenario
fEll[1] = (_fK2AMM[1].abs().add(_fk2Trader.mul(_fCoverN))).mul(
(fStressRet2[1].exp().sub(ONE_64x64))
);
int128 fIstar;
if (_eCCY == AMMPerpLogic.CollateralCurrency.BASE) {
fIstar = fEll[0].div(fStressRet2[0].exp());
int128 fI2 = fEll[1].div(fStressRet2[1].exp());
if (fI2 > fIstar) {
fIstar = fI2;
}
} else if (_eCCY == AMMPerpLogic.CollateralCurrency.QUANTO) {
fIstar = fEll[0].div(fStressRet3[0].exp());
int128 fI2 = fEll[1].div(fStressRet3[1].exp());
if (fI2 > fIstar) {
fIstar = fI2;
}
fIstar = fIstar.mul(fIndexPrices[0].div(fIndexPrices[1]));
} else {
assert(_eCCY == AMMPerpLogic.CollateralCurrency.QUOTE);
if (fEll[0] > fEll[1]) {
fIstar = fEll[0].mul(fIndexPrices[0]);
} else {
fIstar = fEll[1].mul(fIndexPrices[0]);
}
}
return fIstar;
}
/**
* Calculate the risk neutral Distance to Default (Phi(DD)=default probability) when
* there is no quanto currency collateral.
* We assume r=0 everywhere.
* The underlying distribution is log-normal, hence the log below.
* All variables are 64.64-bit fixed point number (or struct thereof)
* @param fSigma2 current Market variables (price¶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();
}
}// 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);
}// 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 fSpotIndexPrice
);
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": 10000000
},
"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":"fSpotIndexPrice","type":"int128"}],"name":"UpdateMarkPrice","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"address","name":"","type":"address"}],"name":"brokerVolumeEMA","outputs":[{"internalType":"int128","name":"fTradingVolumeEMAusd","type":"int128"},{"internalType":"uint64","name":"timestamp","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"brokerVolumeFeesTbps","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"brokerVolumeTiers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_sig","type":"bytes4"}],"name":"getImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_moduleName","type":"string"}],"name":"getModuleImplementationAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProxyOwner","outputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastBaseToUSDUpdateTs","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"liquidityProvisionIsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maintainer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint24","name":"","type":"uint24"}],"name":"perpBaseToUSDOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint24","name":"","type":"uint24"}],"name":"perpToLastBaseToUSD","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_impl","type":"address"}],"name":"setImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_impl","type":"address"}],"name":"setImplementationCrossModules","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setProxyOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"address","name":"","type":"address"}],"name":"traderVolumeEMA","outputs":[{"internalType":"int128","name":"fTradingVolumeEMAusd","type":"int128"},{"internalType":"uint64","name":"timestamp","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"traderVolumeFeesTbps","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"traderVolumeTiers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newGovernance","type":"address"}],"name":"transferGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newMaintainer","type":"address"}],"name":"transferMaintainer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040523480156200001157600080fd5b506200001d3362000049565b620000283362000099565b6001805460ff60a01b191681556002556200004333620000eb565b620001b0565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f2f3ffaaaad93928855c8700645d1a3643e6ccfdd500efa9fda048a88f557cf019190a35050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce8090600090a35050565b6001600160a01b038116620001465760405162461bcd60e51b815260206004820152601b60248201527f696e76616c69642070726f7879206f776e657220616464726573730000000000604482015260640160405180910390fd5b6001600160a01b038116620001686000805160206200274a8339815191525490565b6001600160a01b03167f5a3e66efaa1e445ebd894728a69d6959842ea1e97bd79b892797106e270efcd960405160405180910390a36000805160206200274a83398151915255565b61258a80620001c06000396000f3fe6080604052600436106101835760003560e01c80636700c019116100d6578063caaee91c1161007f578063dc9cc64511610059578063dc9cc6451461058a578063e7332410146105aa578063e7e21fde146105e457610192565b8063caaee91c1461052a578063d38bfff41461054a578063d784d4261461056a57610192565b80639850d32b116100b05780639850d32b146104835780639ecab3f5146104ae578063bffd952a1461050a57610192565b80636700c019146103f85780638456cb591461042b57806388b825281461044057610192565b80633f4ba83a116101385780635c975abb116101125780635c975abb146103295780635ca8b972146103595780635fdfecbe1461037957610192565b80633f4ba83a146102bb57806355f1c7d5146102d05780635aa6e675146102fe57610192565b80631ab7710d116101695780631ab7710d146102045780633a839d15146102385780633baf4f6f1461027b57610192565b806233c04b1461019a5780630e1cf91b146101e457610192565b3661019257610190610604565b005b610190610604565b3480156101a657600080fd5b506101ba6101b53660046121ab565b610616565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156101f057600080fd5b506101906101ff366004612241565b61068b565b34801561021057600080fd5b507fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d8546101ba565b34801561024457600080fd5b5061026861025336600461225c565b601960205260009081526040902054600f0b81565b604051600f9190910b81526020016101db565b34801561028757600080fd5b506102ab610296366004612292565b601f6020526000908152604090205460ff1681565b60405190151581526020016101db565b3480156102c757600080fd5b50610190610754565b3480156102dc57600080fd5b506102f06102eb3660046122ad565b610801565b6040519081526020016101db565b34801561030a57600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166101ba565b34801561033557600080fd5b5060015474010000000000000000000000000000000000000000900460ff166102ab565b34801561036557600080fd5b506102f06103743660046122ad565b610822565b34801561038557600080fd5b506103d56103943660046122c6565b601a602090815260009283526040808420909152908252902054600f81900b90700100000000000000000000000000000000900467ffffffffffffffff1682565b60408051600f9390930b835267ffffffffffffffff9091166020830152016101db565b34801561040457600080fd5b506104186104133660046122ad565b610832565b60405161ffff90911681526020016101db565b34801561043757600080fd5b5061019061086a565b34801561044c57600080fd5b506101ba61045b36600461225c565b60186020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561048f57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101ba565b3480156104ba57600080fd5b506103d56104c93660046122c6565b601b602090815260009283526040808420909152908252902054600f81900b90700100000000000000000000000000000000900467ffffffffffffffff1682565b34801561051657600080fd5b50610190610525366004612241565b610917565b34801561053657600080fd5b50610190610545366004612241565b610a1e565b34801561055657600080fd5b50610190610565366004612241565b610add565b34801561057657600080fd5b50610190610585366004612241565b610be4565b34801561059657600080fd5b506101ba6105a5366004612327565b610ca5565b3480156105b657600080fd5b50601c546105cb9067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101db565b3480156105f057600080fd5b506104186105ff3660046122ad565b610d19565b61061461060f610d29565b610e49565b565b60006012600061065b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e6d92505050565b815260208101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff1690505b92915050565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610746576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e6965640000000000000000000000000060448201526064015b60405180910390fd5b610751816001610e8c565b50565b61075c6113a2565b3361077c60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16146107f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c79206d61696e7461696e65720000000000000000000000000000000000604482015260640161073d565b610614611426565b6014818154811061081157600080fd5b600091825260209091200154905081565b6015818154811061081157600080fd5b6016818154811061084257600080fd5b9060005260206000209060109182820401919006600202915054906101000a900461ffff1681565b6108726114a3565b3361089260005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461090f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c79206d61696e7461696e65720000000000000000000000000000000000604482015260640161073d565b610614611528565b60015473ffffffffffffffffffffffffffffffffffffffff163314610998576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c7920676f7665726e616e63650000000000000000000000000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff8116610a15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f20616464726573730000000000000000000000000000000000000000604482015260640161073d565b61075181611597565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610ad4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e69656400000000000000000000000000604482015260640161073d565b6107518161160c565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c7920676f7665726e616e63650000000000000000000000000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff8116610bdb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f20616464726573730000000000000000000000000000000000000000604482015260640161073d565b6107518161172e565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c9a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e69656400000000000000000000000000604482015260640161073d565b610751816000610e8c565b604080517fffffffff0000000000000000000000000000000000000000000000000000000083166020808301919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc8828401528251808303840181526060909201909252805191012054600090610685565b6017818154811061084257600080fd5b600080610dc56000357fffffffff0000000000000000000000000000000000000000000000000000000016604080517fffffffff00000000000000000000000000000000000000000000000000000000929092166020808401919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883830152815180840383018152606090930190915281519101205490565b905073ffffffffffffffffffffffffffffffffffffffff8116610e44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f50726f78793a496d706c656d656e746174696f6e206e6f7420666f756e640000604482015260640161073d565b919050565b3660008037600080366000845af43d6000803e808015610e68573d6000f35b3d6000fd5b805160009082908203610e835750600092915050565b50506020015190565b73ffffffffffffffffffffffffffffffffffffffff8216610f09576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f696e76616c696420696d706c656d656e746174696f6e20616464726573730000604482015260640161073d565b6000808373ffffffffffffffffffffffffffffffffffffffff16633e6b8c0d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610f57573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610f9d919081019061237e565b909250905080611009576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d6f64756c65206e616d652063616e6e6f7420626520656d7074790000000000604482015260640161073d565b60008181526011602052604081209080611024836001015490565b85519110915060005b8181101561121557600086828151811061104957611049612469565b6020026020010151905061107f87838151811061106857611068612469565b6020026020010151866117a590919063ffffffff16565b6111df57604080517fffffffff0000000000000000000000000000000000000000000000000000000083166020808301919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc882840152825180830384018152606090920190925280519101205473ffffffffffffffffffffffffffffffffffffffff8116156111b05788611172576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f63616e74207265706c616365206d6f64756c65732066756e6373000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601360209081526040808320548352601190915290206111ae90836117dc565b505b6111dc8884815181106111c5576111c5612469565b6020026020010151876119d890919063ffffffff16565b50505b6112028783815181106111f4576111f4612469565b60200260200101518a611a88565b508061120d816124c7565b91505061102d565b508115611339576000611236600061122e866001015490565b869190611bbb565b90508051915060005b8281101561133657600082828151811061125b5761125b612469565b602002602001015190508973ffffffffffffffffffffffffffffffffffffffff166112f182604080517fffffffff00000000000000000000000000000000000000000000000000000000929092166020808401919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883830152815180840383018152606090930190915281519101205490565b73ffffffffffffffffffffffffffffffffffffffff161461132357611317816000611a88565b61132186826117dc565b505b508061132e816124c7565b91505061123f565b50505b5050506000818152601260209081526040808320805473ffffffffffffffffffffffffffffffffffffffff9098167fffffffffffffffffffffffff0000000000000000000000000000000000000000909816881790559582526013905293909320929092555050565b60015474010000000000000000000000000000000000000000900460ff16610614576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161073d565b61142e6113a2565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b60015474010000000000000000000000000000000000000000900460ff1615610614576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161073d565b6115306114a3565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586114793390565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f2f3ffaaaad93928855c8700645d1a3643e6ccfdd500efa9fda048a88f557cf019190a35050565b73ffffffffffffffffffffffffffffffffffffffff8116611689576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c69642070726f7879206f776e657220616464726573730000000000604482015260640161073d565b8073ffffffffffffffffffffffffffffffffffffffff166116c87fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85490565b73ffffffffffffffffffffffffffffffffffffffff167f5a3e66efaa1e445ebd894728a69d6959842ea1e97bd79b892797106e270efcd960405160405180910390a37fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d855565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce8090600090a35050565b7fffffffff000000000000000000000000000000000000000000000000000000001660009081526020919091526040902054151590565b7fffffffff000000000000000000000000000000000000000000000000000000008116600090815260208390526040812054156119d0577fffffffff000000000000000000000000000000000000000000000000000000008216600090815260208490526040812054611851906001906124ff565b60018581015491925060009161186791906124ff565b905081811461193357600085600101828154811061188757611887612469565b90600052602060002090600891828204019190066004029054906101000a900460e01b9050808660010184815481106118c2576118c2612469565b90600052602060002090600891828204019190066004026101000a81548163ffffffff021916908360e01c02179055508260016118ff9190612512565b7fffffffff000000000000000000000000000000000000000000000000000000009091166000908152602087905260409020555b7fffffffff0000000000000000000000000000000000000000000000000000000084166000908152602086905260408120556001850180548061197857611978612525565b60008281526020902060087fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191820401805463ffffffff600460078516026101000a0219169055905550600191506106859050565b506000610685565b7fffffffff0000000000000000000000000000000000000000000000000000000081166000908152602083905260408120546119d05750600182810180548083018255600082815260208082206008840401805463ffffffff60079095166004026101000a948502191660e088901c949094029390931790925591547fffffffff000000000000000000000000000000000000000000000000000000008516835290859052604090912055610685565b611a9182611d68565b604080517fffffffff00000000000000000000000000000000000000000000000000000000841660208083018290527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883850152835180840385018152606084018086528151919092012054919052915173ffffffffffffffffffffffffffffffffffffffff8481169316917f347b48699b991c95bb339a3a778222488794b19790e9f46171825933c63a9cc4919081900360800190a3604080517fffffffff00000000000000000000000000000000000000000000000000000000939093166020808501919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc8848301528151808503830181526060909401909152825192019190912055565b60606000611bc98385612512565b905083811015611c35576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6164646974696f6e206f766572666c6f77000000000000000000000000000000604482015260640161073d565b60018501548111611c465780611c4c565b60018501545b9050801580611c5b5750808410155b15611c665750611d61565b611c7084826124ff565b67ffffffffffffffff811115611c8857611c88612344565b604051908082528060200260200182016040528015611cb1578160200160208202803683370190505b50915060005b611cc185836124ff565b811015611d5e5760018601611cd68683612512565b81548110611ce657611ce6612469565b90600052602060002090600891828204019190066004029054906101000a900460e01b838281518110611d1b57611d1b612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280611d56816124c7565b915050611cb7565b50505b9392505050565b6000611d72611e5a565b805190915060005b81811015611e5457828181518110611d9457611d94612469565b60200260200101517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603611e42576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f66756e6374696f6e20696420616c726561647920657869737473000000000000604482015260640161073d565b80611e4c816124c7565b915050611d7a565b50505050565b604080516008808252610120820190925260609160009190602082016101008036833701905050905063dc9cc64560e01b81600081518110611e9e57611e9e612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517fd784d426000000000000000000000000000000000000000000000000000000009082906001908110611f0657611f06612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f0e1cf91b000000000000000000000000000000000000000000000000000000009082906002908110611f6e57611f6e612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517e33c04b000000000000000000000000000000000000000000000000000000009082906003908110611fd557611fd5612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517fcaaee91c00000000000000000000000000000000000000000000000000000000908290600490811061203d5761203d612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f1ab7710d0000000000000000000000000000000000000000000000000000000090829060059081106120a5576120a5612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f8456cb5900000000000000000000000000000000000000000000000000000000908290600690811061210d5761210d612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f3f4ba83a00000000000000000000000000000000000000000000000000000000908290600790811061217557612175612469565b7fffffffff0000000000000000000000000000000000000000000000000000000090921660209283029190910190910152919050565b600080602083850312156121be57600080fd5b823567ffffffffffffffff808211156121d657600080fd5b818501915085601f8301126121ea57600080fd5b8135818111156121f957600080fd5b86602082850101111561220b57600080fd5b60209290920196919550909350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e4457600080fd5b60006020828403121561225357600080fd5b611d618261221d565b60006020828403121561226e57600080fd5b813562ffffff81168114611d6157600080fd5b803560ff81168114610e4457600080fd5b6000602082840312156122a457600080fd5b611d6182612281565b6000602082840312156122bf57600080fd5b5035919050565b600080604083850312156122d957600080fd5b6122e283612281565b91506122f06020840161221d565b90509250929050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461075157600080fd5b60006020828403121561233957600080fd5b8135611d61816122f9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8051610e44816122f9565b6000806040838503121561239157600080fd5b825167ffffffffffffffff808211156123a957600080fd5b818501915085601f8301126123bd57600080fd5b81516020828211156123d1576123d1612344565b8160051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110868211171561241457612414612344565b60405292835281830193508481018201928984111561243257600080fd5b948201945b838610156124575761244886612373565b85529482019493820193612437565b97909101519698969750505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036124f8576124f8612498565b5060010190565b8181038181111561068557610685612498565b8082018082111561068557610685612498565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220baa4e6a5c992cd94607a99f04e80a0f38c585f60a6688a7da706e3f04726e06664736f6c63430008150033b5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d8
Deployed Bytecode
0x6080604052600436106101835760003560e01c80636700c019116100d6578063caaee91c1161007f578063dc9cc64511610059578063dc9cc6451461058a578063e7332410146105aa578063e7e21fde146105e457610192565b8063caaee91c1461052a578063d38bfff41461054a578063d784d4261461056a57610192565b80639850d32b116100b05780639850d32b146104835780639ecab3f5146104ae578063bffd952a1461050a57610192565b80636700c019146103f85780638456cb591461042b57806388b825281461044057610192565b80633f4ba83a116101385780635c975abb116101125780635c975abb146103295780635ca8b972146103595780635fdfecbe1461037957610192565b80633f4ba83a146102bb57806355f1c7d5146102d05780635aa6e675146102fe57610192565b80631ab7710d116101695780631ab7710d146102045780633a839d15146102385780633baf4f6f1461027b57610192565b806233c04b1461019a5780630e1cf91b146101e457610192565b3661019257610190610604565b005b610190610604565b3480156101a657600080fd5b506101ba6101b53660046121ab565b610616565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156101f057600080fd5b506101906101ff366004612241565b61068b565b34801561021057600080fd5b507fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d8546101ba565b34801561024457600080fd5b5061026861025336600461225c565b601960205260009081526040902054600f0b81565b604051600f9190910b81526020016101db565b34801561028757600080fd5b506102ab610296366004612292565b601f6020526000908152604090205460ff1681565b60405190151581526020016101db565b3480156102c757600080fd5b50610190610754565b3480156102dc57600080fd5b506102f06102eb3660046122ad565b610801565b6040519081526020016101db565b34801561030a57600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166101ba565b34801561033557600080fd5b5060015474010000000000000000000000000000000000000000900460ff166102ab565b34801561036557600080fd5b506102f06103743660046122ad565b610822565b34801561038557600080fd5b506103d56103943660046122c6565b601a602090815260009283526040808420909152908252902054600f81900b90700100000000000000000000000000000000900467ffffffffffffffff1682565b60408051600f9390930b835267ffffffffffffffff9091166020830152016101db565b34801561040457600080fd5b506104186104133660046122ad565b610832565b60405161ffff90911681526020016101db565b34801561043757600080fd5b5061019061086a565b34801561044c57600080fd5b506101ba61045b36600461225c565b60186020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561048f57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101ba565b3480156104ba57600080fd5b506103d56104c93660046122c6565b601b602090815260009283526040808420909152908252902054600f81900b90700100000000000000000000000000000000900467ffffffffffffffff1682565b34801561051657600080fd5b50610190610525366004612241565b610917565b34801561053657600080fd5b50610190610545366004612241565b610a1e565b34801561055657600080fd5b50610190610565366004612241565b610add565b34801561057657600080fd5b50610190610585366004612241565b610be4565b34801561059657600080fd5b506101ba6105a5366004612327565b610ca5565b3480156105b657600080fd5b50601c546105cb9067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101db565b3480156105f057600080fd5b506104186105ff3660046122ad565b610d19565b61061461060f610d29565b610e49565b565b60006012600061065b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e6d92505050565b815260208101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff1690505b92915050565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610746576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e6965640000000000000000000000000060448201526064015b60405180910390fd5b610751816001610e8c565b50565b61075c6113a2565b3361077c60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16146107f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c79206d61696e7461696e65720000000000000000000000000000000000604482015260640161073d565b610614611426565b6014818154811061081157600080fd5b600091825260209091200154905081565b6015818154811061081157600080fd5b6016818154811061084257600080fd5b9060005260206000209060109182820401919006600202915054906101000a900461ffff1681565b6108726114a3565b3361089260005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461090f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c79206d61696e7461696e65720000000000000000000000000000000000604482015260640161073d565b610614611528565b60015473ffffffffffffffffffffffffffffffffffffffff163314610998576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c7920676f7665726e616e63650000000000000000000000000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff8116610a15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f20616464726573730000000000000000000000000000000000000000604482015260640161073d565b61075181611597565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610ad4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e69656400000000000000000000000000604482015260640161073d565b6107518161160c565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6f6e6c7920676f7665726e616e63650000000000000000000000000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff8116610bdb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f7a65726f20616464726573730000000000000000000000000000000000000000604482015260640161073d565b6107518161172e565b7fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c9a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f50726f78793a6163636573732064656e69656400000000000000000000000000604482015260640161073d565b610751816000610e8c565b604080517fffffffff0000000000000000000000000000000000000000000000000000000083166020808301919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc8828401528251808303840181526060909201909252805191012054600090610685565b6017818154811061084257600080fd5b600080610dc56000357fffffffff0000000000000000000000000000000000000000000000000000000016604080517fffffffff00000000000000000000000000000000000000000000000000000000929092166020808401919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883830152815180840383018152606090930190915281519101205490565b905073ffffffffffffffffffffffffffffffffffffffff8116610e44576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f50726f78793a496d706c656d656e746174696f6e206e6f7420666f756e640000604482015260640161073d565b919050565b3660008037600080366000845af43d6000803e808015610e68573d6000f35b3d6000fd5b805160009082908203610e835750600092915050565b50506020015190565b73ffffffffffffffffffffffffffffffffffffffff8216610f09576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f696e76616c696420696d706c656d656e746174696f6e20616464726573730000604482015260640161073d565b6000808373ffffffffffffffffffffffffffffffffffffffff16633e6b8c0d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610f57573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610f9d919081019061237e565b909250905080611009576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d6f64756c65206e616d652063616e6e6f7420626520656d7074790000000000604482015260640161073d565b60008181526011602052604081209080611024836001015490565b85519110915060005b8181101561121557600086828151811061104957611049612469565b6020026020010151905061107f87838151811061106857611068612469565b6020026020010151866117a590919063ffffffff16565b6111df57604080517fffffffff0000000000000000000000000000000000000000000000000000000083166020808301919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc882840152825180830384018152606090920190925280519101205473ffffffffffffffffffffffffffffffffffffffff8116156111b05788611172576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f63616e74207265706c616365206d6f64756c65732066756e6373000000000000604482015260640161073d565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601360209081526040808320548352601190915290206111ae90836117dc565b505b6111dc8884815181106111c5576111c5612469565b6020026020010151876119d890919063ffffffff16565b50505b6112028783815181106111f4576111f4612469565b60200260200101518a611a88565b508061120d816124c7565b91505061102d565b508115611339576000611236600061122e866001015490565b869190611bbb565b90508051915060005b8281101561133657600082828151811061125b5761125b612469565b602002602001015190508973ffffffffffffffffffffffffffffffffffffffff166112f182604080517fffffffff00000000000000000000000000000000000000000000000000000000929092166020808401919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883830152815180840383018152606090930190915281519101205490565b73ffffffffffffffffffffffffffffffffffffffff161461132357611317816000611a88565b61132186826117dc565b505b508061132e816124c7565b91505061123f565b50505b5050506000818152601260209081526040808320805473ffffffffffffffffffffffffffffffffffffffff9098167fffffffffffffffffffffffff0000000000000000000000000000000000000000909816881790559582526013905293909320929092555050565b60015474010000000000000000000000000000000000000000900460ff16610614576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161073d565b61142e6113a2565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b60015474010000000000000000000000000000000000000000900460ff1615610614576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161073d565b6115306114a3565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586114793390565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f2f3ffaaaad93928855c8700645d1a3643e6ccfdd500efa9fda048a88f557cf019190a35050565b73ffffffffffffffffffffffffffffffffffffffff8116611689576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f696e76616c69642070726f7879206f776e657220616464726573730000000000604482015260640161073d565b8073ffffffffffffffffffffffffffffffffffffffff166116c87fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d85490565b73ffffffffffffffffffffffffffffffffffffffff167f5a3e66efaa1e445ebd894728a69d6959842ea1e97bd79b892797106e270efcd960405160405180910390a37fb5f6074d2b374487ffe12d401cf0891c7591a84c4944ef117f69d13b80c4d6d855565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce8090600090a35050565b7fffffffff000000000000000000000000000000000000000000000000000000001660009081526020919091526040902054151590565b7fffffffff000000000000000000000000000000000000000000000000000000008116600090815260208390526040812054156119d0577fffffffff000000000000000000000000000000000000000000000000000000008216600090815260208490526040812054611851906001906124ff565b60018581015491925060009161186791906124ff565b905081811461193357600085600101828154811061188757611887612469565b90600052602060002090600891828204019190066004029054906101000a900460e01b9050808660010184815481106118c2576118c2612469565b90600052602060002090600891828204019190066004026101000a81548163ffffffff021916908360e01c02179055508260016118ff9190612512565b7fffffffff000000000000000000000000000000000000000000000000000000009091166000908152602087905260409020555b7fffffffff0000000000000000000000000000000000000000000000000000000084166000908152602086905260408120556001850180548061197857611978612525565b60008281526020902060087fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191820401805463ffffffff600460078516026101000a0219169055905550600191506106859050565b506000610685565b7fffffffff0000000000000000000000000000000000000000000000000000000081166000908152602083905260408120546119d05750600182810180548083018255600082815260208082206008840401805463ffffffff60079095166004026101000a948502191660e088901c949094029390931790925591547fffffffff000000000000000000000000000000000000000000000000000000008516835290859052604090912055610685565b611a9182611d68565b604080517fffffffff00000000000000000000000000000000000000000000000000000000841660208083018290527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc883850152835180840385018152606084018086528151919092012054919052915173ffffffffffffffffffffffffffffffffffffffff8481169316917f347b48699b991c95bb339a3a778222488794b19790e9f46171825933c63a9cc4919081900360800190a3604080517fffffffff00000000000000000000000000000000000000000000000000000000939093166020808501919091527f950d7e977b74051843ed988c77d53a700cd967d2ac5480d98dd4c1edaf0b4dc8848301528151808503830181526060909401909152825192019190912055565b60606000611bc98385612512565b905083811015611c35576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6164646974696f6e206f766572666c6f77000000000000000000000000000000604482015260640161073d565b60018501548111611c465780611c4c565b60018501545b9050801580611c5b5750808410155b15611c665750611d61565b611c7084826124ff565b67ffffffffffffffff811115611c8857611c88612344565b604051908082528060200260200182016040528015611cb1578160200160208202803683370190505b50915060005b611cc185836124ff565b811015611d5e5760018601611cd68683612512565b81548110611ce657611ce6612469565b90600052602060002090600891828204019190066004029054906101000a900460e01b838281518110611d1b57611d1b612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280611d56816124c7565b915050611cb7565b50505b9392505050565b6000611d72611e5a565b805190915060005b81811015611e5457828181518110611d9457611d94612469565b60200260200101517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603611e42576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f66756e6374696f6e20696420616c726561647920657869737473000000000000604482015260640161073d565b80611e4c816124c7565b915050611d7a565b50505050565b604080516008808252610120820190925260609160009190602082016101008036833701905050905063dc9cc64560e01b81600081518110611e9e57611e9e612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517fd784d426000000000000000000000000000000000000000000000000000000009082906001908110611f0657611f06612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f0e1cf91b000000000000000000000000000000000000000000000000000000009082906002908110611f6e57611f6e612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517e33c04b000000000000000000000000000000000000000000000000000000009082906003908110611fd557611fd5612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517fcaaee91c00000000000000000000000000000000000000000000000000000000908290600490811061203d5761203d612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f1ab7710d0000000000000000000000000000000000000000000000000000000090829060059081106120a5576120a5612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f8456cb5900000000000000000000000000000000000000000000000000000000908290600690811061210d5761210d612469565b7fffffffff000000000000000000000000000000000000000000000000000000009092166020928302919091019091015280517f3f4ba83a00000000000000000000000000000000000000000000000000000000908290600790811061217557612175612469565b7fffffffff0000000000000000000000000000000000000000000000000000000090921660209283029190910190910152919050565b600080602083850312156121be57600080fd5b823567ffffffffffffffff808211156121d657600080fd5b818501915085601f8301126121ea57600080fd5b8135818111156121f957600080fd5b86602082850101111561220b57600080fd5b60209290920196919550909350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e4457600080fd5b60006020828403121561225357600080fd5b611d618261221d565b60006020828403121561226e57600080fd5b813562ffffff81168114611d6157600080fd5b803560ff81168114610e4457600080fd5b6000602082840312156122a457600080fd5b611d6182612281565b6000602082840312156122bf57600080fd5b5035919050565b600080604083850312156122d957600080fd5b6122e283612281565b91506122f06020840161221d565b90509250929050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461075157600080fd5b60006020828403121561233957600080fd5b8135611d61816122f9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8051610e44816122f9565b6000806040838503121561239157600080fd5b825167ffffffffffffffff808211156123a957600080fd5b818501915085601f8301126123bd57600080fd5b81516020828211156123d1576123d1612344565b8160051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110868211171561241457612414612344565b60405292835281830193508481018201928984111561243257600080fd5b948201945b838610156124575761244886612373565b85529482019493820193612437565b97909101519698969750505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036124f8576124f8612498565b5060010190565b8181038181111561068557610685612498565b8082018082111561068557610685612498565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220baa4e6a5c992cd94607a99f04e80a0f38c585f60a6688a7da706e3f04726e06664736f6c63430008150033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.