Contract
0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e2
2
Contract Overview
Balance:
0 ETH
ETH Value:
$0.00
My Name Tag:
Not Available
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
PoolFactory
Compiler Version
v0.8.7+commit.e28d00a7
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity 0.8.7; import "../interfaces/IPoolFactory.sol"; import "../interfaces/ILeveragedPool.sol"; import "../interfaces/IPoolCommitterDeployer.sol"; import "../interfaces/IPoolCommitter.sol"; import "../interfaces/IERC20DecimalsWrapper.sol"; import "./LeveragedPool.sol"; import "./PoolToken.sol"; import "./PoolKeeper.sol"; import "@openzeppelin/contracts/proxy/Clones.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; /// @title The pool factory contract contract PoolFactory is IPoolFactory, Ownable { // #### Globals PoolToken public pairTokenBase; address public immutable pairTokenBaseAddress; LeveragedPool public poolBase; address public immutable poolBaseAddress; IPoolKeeper public poolKeeper; IPoolCommitterDeployer public poolCommitterDeployer; // Default max leverage of 10 uint16 public maxLeverage = 10; // Contract address to receive protocol fees address public feeReceiver; // Default fee; Fee value as a decimal multiplied by 10^18. For example, 0.5% is represented as 0.5 * 10^18 uint256 public fee; // This is required because we must pass along *some* value for decimal // precision to the base pool tokens as we use the Cloneable pattern uint8 constant DEFAULT_NUM_DECIMALS = 18; /** * @notice Format: Pool counter => pool address */ mapping(uint256 => address) public override pools; uint256 public override numPools; /** * @notice Format: Pool address => validity */ mapping(address => bool) public override isValidPool; // #### Functions constructor(address _feeReceiver) { // Deploy base contracts pairTokenBase = new PoolToken(DEFAULT_NUM_DECIMALS); pairTokenBaseAddress = address(pairTokenBase); poolBase = new LeveragedPool(); poolBaseAddress = address(poolBase); ILeveragedPool.Initialization memory baseInitialization = ILeveragedPool.Initialization( address(this), address(this), address(this), address(this), address(this), address(this), address(this), "BASE_POOL", 15, 30, 0, 1, address(this), address(this) ); // Init bases poolBase.initialize(baseInitialization); pairTokenBase.initialize(address(this), "BASE_TOKEN", "BASE", DEFAULT_NUM_DECIMALS); feeReceiver = _feeReceiver; } /** * @notice Deploy a leveraged pool with given parameters * @param deploymentParameters Deployment parameters of the market. Some may be reconfigurable * @return Address of the created pool */ function deployPool(PoolDeployment calldata deploymentParameters) external override onlyGov returns (address) { address _poolKeeper = address(poolKeeper); require(_poolKeeper != address(0), "PoolKeeper not set"); require(address(poolCommitterDeployer) != address(0), "PoolCommitterDeployer not set"); address poolCommitter = poolCommitterDeployer.deploy( deploymentParameters.minimumCommitSize, deploymentParameters.maximumCommitQueueLength ); require( deploymentParameters.leverageAmount >= 1 && deploymentParameters.leverageAmount <= maxLeverage, "PoolKeeper: leveraged amount invalid" ); require(IERC20DecimalsWrapper(deploymentParameters.quoteToken).decimals() <= 18, "Token decimals > 18"); LeveragedPool pool = LeveragedPool(Clones.clone(poolBaseAddress)); address _pool = address(pool); emit DeployPool(_pool, deploymentParameters.poolName); string memory leverage = uint2str(deploymentParameters.leverageAmount); string memory longString = string(abi.encodePacked(leverage, "L-", deploymentParameters.poolName)); string memory shortString = string(abi.encodePacked(leverage, "S-", deploymentParameters.poolName)); uint8 settlementDecimals = IERC20DecimalsWrapper(deploymentParameters.quoteToken).decimals(); address shortToken = deployPairToken(_pool, shortString, shortString, settlementDecimals); address longToken = deployPairToken(_pool, longString, longString, settlementDecimals); ILeveragedPool.Initialization memory initialization = ILeveragedPool.Initialization( owner(), // governance is the owner of pools -- if this changes, `onlyGov` breaks _poolKeeper, deploymentParameters.oracleWrapper, deploymentParameters.settlementEthOracle, longToken, shortToken, poolCommitter, string(abi.encodePacked(leverage, "-", deploymentParameters.poolName)), deploymentParameters.frontRunningInterval, deploymentParameters.updateInterval, fee, deploymentParameters.leverageAmount, feeReceiver, deploymentParameters.quoteToken ); // approve the quote token on the pool committer to finalise linking // this also stores the pool address in the committer // finalise pool setup pool.initialize(initialization); // approve the quote token on the pool commiter to finalise linking // this also stores the pool address in the commiter IPoolCommitter(poolCommitter).setQuoteAndPool(deploymentParameters.quoteToken, _pool); poolKeeper.newPool(_pool); pools[numPools] = _pool; numPools += 1; isValidPool[_pool] = true; return _pool; } /** * @notice Deploy a contract for pool tokens * @param name Name of the token * @param symbol Symbol of the token * @param decimals Number of decimal places to be supported * @return Address of the pool token */ function deployPairToken( address owner, string memory name, string memory symbol, uint8 decimals ) internal returns (address) { PoolToken pairToken = PoolToken(Clones.clone(pairTokenBaseAddress)); pairToken.initialize(owner, name, symbol, decimals); return address(pairToken); } function setPoolKeeper(address _poolKeeper) external override onlyOwner { require(_poolKeeper != address(0), "address cannot be null"); poolKeeper = IPoolKeeper(_poolKeeper); } function setMaxLeverage(uint16 newMaxLeverage) external override onlyOwner { require(newMaxLeverage > 0, "Maximum leverage must be non-zero"); maxLeverage = newMaxLeverage; } function setFeeReceiver(address _feeReceiver) external override onlyOwner { require(_feeReceiver != address(0), "address cannot be null"); feeReceiver = _feeReceiver; } /** * @notice Set the fee amount. This is a percentage multiplied by 10^18. * e.g. 5% is 0.05 * 10^18 * @param _fee The fee amount as a percentage multiplied by 10^18 */ function setFee(uint256 _fee) external override onlyOwner { fee = _fee; } function setPoolCommitterDeployer(address _poolCommitterDeployer) external override onlyOwner { require(_poolCommitterDeployer != address(0), "address cannot be null"); poolCommitterDeployer = IPoolCommitterDeployer(_poolCommitterDeployer); } function getOwner() external view override returns (address) { return owner(); } /** * @notice Converts a uint to a str * @dev Assumes ASCII strings * @return raw string representation of the uint */ function uint2str(uint256 _i) internal pure returns (string memory) { if (_i == 0) { return "0"; } uint256 j = _i; uint256 len; while (j != 0) { len++; j /= 10; } bytes memory bstr = new bytes(len); uint256 k = len; while (_i != 0) { k = k - 1; uint8 temp = (48 + uint8(_i - (_i / 10) * 10)); bytes1 b1 = bytes1(temp); bstr[k] = b1; _i /= 10; } return string(bstr); } modifier onlyGov() { require(msg.sender == owner(), "msg.sender not governance"); _; } }
//SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity 0.8.7; /// @title The contract factory for the keeper and pool contracts. Utilizes minimal clones to keep gas costs low interface IPoolFactory { struct PoolDeployment { string poolName; // The name to identify a pool by uint32 frontRunningInterval; // The minimum number of seconds that must elapse before a commit can be executed. Must be smaller than or equal to the update interval to prevent deadlock uint32 updateInterval; // The minimum number of seconds that must elapse before a price change uint16 leverageAmount; // The amount of exposure to price movements for the pool address quoteToken; // The digital asset that the pool accepts address oracleWrapper; // The IOracleWrapper implementation for fetching price feed data address settlementEthOracle; // The oracle to fetch the price of Ether in terms of the settlement token uint128 minimumCommitSize; // The minimum amount (in settlement tokens) that a user can commit in a single commitment uint128 maximumCommitQueueLength; // The maximum number of commitments that can be made for a given updateInterval } // #### Events /** * @notice Creates a notification when a pool is deployed * @param pool Address of the new pool * @param ticker Ticker of the neew pool */ event DeployPool(address indexed pool, string ticker); // #### Getters for Globals function pools(uint256 id) external view returns (address); function numPools() external view returns (uint256); function isValidPool(address _pool) external view returns (bool); // #### Functions function deployPool(PoolDeployment calldata deploymentParameters) external returns (address); function getOwner() external returns (address); function setPoolKeeper(address _poolKeeper) external; function setMaxLeverage(uint16 newMaxLeverage) external; function setFeeReceiver(address _feeReceiver) external; function setFee(uint256 _fee) external; function setPoolCommitterDeployer(address _poolCommitterDeployer) external; }
//SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity 0.8.7; /// @title The pool controller contract interface interface ILeveragedPool { // Initialisation parameters for new market struct Initialization { address _owner; // Owner of the contract address _keeper; // The address of the PoolKeeper contract address _oracleWrapper; // The oracle wrapper for the derivative price feed address _settlementEthOracle; // The oracle wrapper for the SettlementToken/ETH price feed address _longToken; // Address of the long pool token address _shortToken; // Address of the short pool token address _poolCommitter; // Address of the PoolCommitter contract string _poolName; // The pool identification name uint32 _frontRunningInterval; // The minimum number of seconds that must elapse before a commit is forced to wait until the next interval uint32 _updateInterval; // The minimum number of seconds that must elapse before a commit can be executed uint256 _fee; // The fund movement fee. This amount is extracted from the deposited asset with every update and sent to the fee address uint16 _leverageAmount; // The amount of exposure to price movements for the pool address _feeAddress; // The address that the fund movement fee is sent to address _quoteToken; // The digital asset that the pool accepts. Must have a decimals() function } // #### Events /** * @notice Creates a notification when the pool is setup and ready for use * @param longToken The address of the LONG pair token * @param shortToken The address of the SHORT pair token * @param quoteToken The address of the digital asset that the pool accepts * @param poolName The pool code for the pool */ event PoolInitialized(address indexed longToken, address indexed shortToken, address quoteToken, string poolName); /** * @notice Creates a notification when the pool is rebalanced * @param shortBalanceChange The change of funds in the short side * @param longBalanceChange The change of funds in the long side */ event PoolRebalance(int256 shortBalanceChange, int256 longBalanceChange); /** * @notice Creates a notification when the pool's price execution fails * @param startPrice Price prior to price change execution * @param endPrice Price during price change execution */ event PriceChangeError(int256 indexed startPrice, int256 indexed endPrice); /** * @notice Represents change in fee receiver's address * @param oldAddress Previous address * @param newAddress Address after change */ event FeeAddressUpdated(address indexed oldAddress, address indexed newAddress); /** * @notice Represents change in keeper's address * @param oldAddress Previous address * @param newAddress Address after change */ event KeeperAddressChanged(address indexed oldAddress, address indexed newAddress); /** * @notice Represents proposed change in governance address * @param newAddress Proposed address */ event ProvisionalGovernanceChanged(address indexed newAddress); /** * @notice Represents change in governance address * @param oldAddress Previous address * @param newAddress Address after change */ event GovernanceAddressChanged(address indexed oldAddress, address indexed newAddress); function leverageAmount() external view returns (bytes16); function poolCommitter() external view returns (address); function quoteToken() external view returns (address); function oracleWrapper() external view returns (address); function lastPriceTimestamp() external view returns (uint256); function poolName() external view returns (string calldata); function updateInterval() external view returns (uint32); function shortBalance() external view returns (uint256); function longBalance() external view returns (uint256); function frontRunningInterval() external view returns (uint32); function poolTokens() external view returns (address[2] memory); function settlementEthOracle() external view returns (address); // #### Functions /** * @notice Configures the pool on deployment. The pools are EIP 1167 clones. * @dev This should only be able to be run once to prevent abuse of the pool. Use of Openzeppelin Initializable or similar is recommended * @param initialization The struct Initialization containing initialization data */ function initialize(Initialization calldata initialization) external; function poolUpkeep(int256 _oldPrice, int256 _newPrice) external; function quoteTokenTransferFrom( address from, address to, uint256 amount ) external; function payKeeperFromBalances(address to, uint256 amount) external returns (bool); function quoteTokenTransfer(address to, uint256 amount) external; function setNewPoolBalances(uint256 _longBalance, uint256 _shortBalance) external; /** * @return _latestPrice The oracle price * @return _data The oracleWrapper's metadata. Implementations can choose what data to return here * @return _lastPriceTimestamp The timestamp of the last upkeep * @return _updateInterval The update frequency for this pool * @dev To save gas so PoolKeeper does not have to make three external calls */ function getUpkeepInformation() external view returns ( int256 _latestPrice, bytes memory _data, uint256 _lastPriceTimestamp, uint256 _updateInterval ); function getOraclePrice() external view returns (int256); function intervalPassed() external view returns (bool); function balances() external view returns (uint256 _shortBalance, uint256 _longBalance); function setKeeper(address _keeper) external; function transferGovernance(address _governance) external; function claimGovernance() external; function updateFeeAddress(address account) external; function mintTokens( uint256 token, uint256 amount, address burner ) external; function burnTokens( uint256 token, uint256 amount, address burner ) external; }
//SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity 0.8.7; /// @title The PoolCommitterDeployer interface interface IPoolCommitterDeployer { function deploy(uint128 _minimumCommitSize, uint128 _maximumCommitQueueLength) external returns (address); }
//SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity 0.8.7; /// @title The interface for the contract that handles pool commitments interface IPoolCommitter { /// Type of commit enum CommitType { ShortMint, ShortBurn, LongMint, LongBurn } // Commit information struct Commit { uint256 amount; CommitType commitType; uint40 created; address owner; } /** * @notice Creates a notification when a commit is created * @param commitID ID of the commit * @param amount Amount of the commit * @param commitType Type of the commit (Short v Long, Mint v Burn) */ event CreateCommit(uint128 indexed commitID, uint256 indexed amount, CommitType indexed commitType); /** * @notice Creates a notification when a commit is removed (uncommitted) * @param commitID ID of the commit * @param amount Amount of the commit * @param commitType Type of the commit (Short v Long, Mint v Burn) */ event RemoveCommit(uint128 indexed commitID, uint256 indexed amount, CommitType indexed commitType); /** * @notice Creates a notification when a commit is executed * @param commitID ID of the commit that's executed */ event ExecuteCommit(uint128 commitID); /** * @notice Creates a notification when a commit fails to execute * @param commitID ID of the commit */ event FailedCommitExecution(uint128 commitID); // #### Functions function commit(CommitType commitType, uint256 amount) external; function executeAllCommitments() external; function executeCommitment(Commit memory _commit) external; function getCommit(uint128 _commitID) external view returns (Commit memory); function setQuoteAndPool(address quoteToken, address leveragedPool) external; function setMinimumCommitSize(uint128 _minimumCommitSize) external; function setMaxCommitQueueLength(uint128 _maximumCommitQueueLength) external; }
//SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity 0.8.7; /// @title The decimals interface for extending the ERC20 interface interface IERC20DecimalsWrapper { function decimals() external view returns (uint8); }
//SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity 0.8.7; import "../interfaces/ILeveragedPool.sol"; import "../interfaces/IPoolCommitter.sol"; import "../interfaces/IPoolToken.sol"; import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./PoolSwapLibrary.sol"; import "../interfaces/IOracleWrapper.sol"; /// @title The pool contract itself contract LeveragedPool is ILeveragedPool, Initializable { using SafeERC20 for IERC20; // #### Globals // Each balance is the amount of quote tokens in the pair uint256 public override shortBalance; uint256 public override longBalance; uint32 public override frontRunningInterval; uint32 public override updateInterval; bytes16 public fee; bytes16 public override leverageAmount; // Index 0 is the LONG token, index 1 is the SHORT token address[2] public tokens; address public governance; address public keeper; address public feeAddress; address public override quoteToken; address public override poolCommitter; uint256 public override lastPriceTimestamp; // The last time the pool was upkept string public override poolName; address public override oracleWrapper; address public override settlementEthOracle; address public provisionalGovernance; bool public governanceTransferInProgress; bool public paused; event Paused(); event Unpaused(); // #### Functions function initialize(ILeveragedPool.Initialization calldata initialization) external override initializer { require(initialization._feeAddress != address(0), "Fee address cannot be 0 address"); require(initialization._quoteToken != address(0), "Quote token cannot be 0 address"); require(initialization._oracleWrapper != address(0), "Oracle wrapper cannot be 0 address"); require(initialization._settlementEthOracle != address(0), "Keeper oracle cannot be 0 address"); require(initialization._owner != address(0), "Owner cannot be 0 address"); require(initialization._keeper != address(0), "Keeper cannot be 0 address"); require(initialization._longToken != address(0), "Long token cannot be 0 address"); require(initialization._shortToken != address(0), "Short token cannot be 0 address"); require(initialization._poolCommitter != address(0), "PoolCommitter cannot be 0 address"); require(initialization._frontRunningInterval < initialization._updateInterval, "frontRunning > updateInterval"); require(initialization._fee < 1 * PoolSwapLibrary.WAD_PRECISION, "Fee >= 100%"); // set the owner of the pool. This is governance when deployed from the factory governance = initialization._owner; // Setup variables keeper = initialization._keeper; oracleWrapper = initialization._oracleWrapper; settlementEthOracle = initialization._settlementEthOracle; quoteToken = initialization._quoteToken; frontRunningInterval = initialization._frontRunningInterval; updateInterval = initialization._updateInterval; fee = PoolSwapLibrary.convertUIntToDecimal(initialization._fee); leverageAmount = PoolSwapLibrary.convertUIntToDecimal(initialization._leverageAmount); feeAddress = initialization._feeAddress; lastPriceTimestamp = block.timestamp; poolName = initialization._poolName; tokens[0] = initialization._longToken; tokens[1] = initialization._shortToken; poolCommitter = initialization._poolCommitter; emit PoolInitialized( initialization._longToken, initialization._shortToken, initialization._quoteToken, initialization._poolName ); } /** * @notice Execute a price change, then execute all commits in PoolCommitter * @dev This is the entry point to upkeep a market */ function poolUpkeep(int256 _oldPrice, int256 _newPrice) external override onlyKeeper onlyUnpaused { require(intervalPassed(), "Update interval hasn't passed"); // perform price change and update pool balances executePriceChange(_oldPrice, _newPrice); // execute pending commitments to enter and exit the pool IPoolCommitter(poolCommitter).executeAllCommitments(); lastPriceTimestamp = block.timestamp; } /** * @notice Pay keeper some amount in the collateral token for the perpetual pools market * @param to Address of the pool keeper to pay * @param amount Amount to pay the pool keeper * @return Whether the keeper is going to be paid; false if the amount exceeds the balances of the * long and short pool, and true if the keeper can successfully be paid out */ function payKeeperFromBalances(address to, uint256 amount) external override onlyKeeper onlyUnpaused returns (bool) { require(to != address(0), "Receipient address cannot be null"); uint256 _shortBalance = shortBalance; uint256 _longBalance = longBalance; // If the rewards are more than the balances of the pool, the keeper does not get paid if (amount >= _shortBalance + _longBalance) { return false; } (uint256 shortBalanceAfterRewards, uint256 longBalanceAfterRewards) = PoolSwapLibrary.getBalancesAfterFees( amount, _shortBalance, _longBalance ); shortBalance = shortBalanceAfterRewards; longBalance = longBalanceAfterRewards; // Pay keeper IERC20(quoteToken).safeTransfer(to, amount); return true; } /** * @notice Transfer tokens from pool to user * @param to Address of account to transfer to * @param amount Amount of quote tokens being transferred */ function quoteTokenTransfer(address to, uint256 amount) external override onlyPoolCommitter onlyUnpaused { require(to != address(0), "To address cannot be 0 address"); IERC20(quoteToken).safeTransfer(to, amount); } /** * @notice Transfer tokens from user to account * @param from The account that's transferring quote tokens * @param to Address of account to transfer to * @param amount Amount of quote tokens being transferred */ function quoteTokenTransferFrom( address from, address to, uint256 amount ) external override onlyPoolCommitter onlyUnpaused { require(from != address(0), "From address cannot be 0 address"); require(to != address(0), "To address cannot be 0 address"); IERC20(quoteToken).safeTransferFrom(from, to, amount); } /** * @notice Execute the price change once the interval period ticks over, updating the long & short * balances based on the change of the feed (upwards or downwards) and paying fees * @dev Can only be called by poolUpkeep; emits PriceChangeError if execution does not take place * @param _oldPrice Old price from the oracle * @param _newPrice New price from the oracle */ function executePriceChange(int256 _oldPrice, int256 _newPrice) internal onlyUnpaused { // prevent a division by 0 in computing the price change // prevent negative pricing if (_oldPrice <= 0 || _newPrice <= 0) { emit PriceChangeError(_oldPrice, _newPrice); } else { uint256 _shortBalance = shortBalance; uint256 _longBalance = longBalance; PoolSwapLibrary.PriceChangeData memory priceChangeData = PoolSwapLibrary.PriceChangeData( _oldPrice, _newPrice, _longBalance, _shortBalance, leverageAmount, fee ); (uint256 newLongBalance, uint256 newShortBalance, uint256 totalFeeAmount) = PoolSwapLibrary .calculatePriceChange(priceChangeData); emit PoolRebalance( int256(newShortBalance) - int256(_shortBalance), int256(newLongBalance) - int256(_longBalance) ); // Update pool balances longBalance = newLongBalance; shortBalance = newShortBalance; // Pay the fee IERC20(quoteToken).safeTransfer(feeAddress, totalFeeAmount); } } /** * @notice Sets the long and short balances of the pools * @dev Can only be called by & used by the pool committer * @param _longBalance New balance of the long pool * @param _shortBalance New balancee of the short pool */ function setNewPoolBalances(uint256 _longBalance, uint256 _shortBalance) external override onlyPoolCommitter onlyUnpaused { longBalance = _longBalance; shortBalance = _shortBalance; } /** * @notice Mint tokens to a user * @dev Can only be called by & used by the pool committer * @param token Index of token * @param amount Amount of tokens to mint * @param minter Address of user/minter */ function mintTokens( uint256 token, uint256 amount, address minter ) external override onlyPoolCommitter onlyUnpaused { require(minter != address(0), "Minter address cannot be 0 address"); require(token == 0 || token == 1, "Pool: token out of range"); require(IPoolToken(tokens[token]).mint(amount, minter), "Mint failed"); } /** * @notice Burn tokens by a user * @dev Can only be called by & used by the pool committer * @param token Index of token * @param amount Amount of tokens to burn * @param burner Address of user/burner */ function burnTokens( uint256 token, uint256 amount, address burner ) external override onlyPoolCommitter onlyUnpaused { require(burner != address(0), "Burner address cannot be 0 address"); require(token == 0 || token == 1, "Pool: token out of range"); require(IPoolToken(tokens[token]).burn(amount, burner), "Burn failed"); } /** * @return true if the price was last updated more than updateInterval seconds ago */ function intervalPassed() public view override returns (bool) { return block.timestamp >= lastPriceTimestamp + updateInterval; } /** * @notice Updates the fee address of the pool * @param account New address of the fee address/receiver */ function updateFeeAddress(address account) external override onlyGov onlyUnpaused { require(account != address(0), "Account cannot be 0 address"); address oldFeeAddress = feeAddress; feeAddress = account; emit FeeAddressUpdated(oldFeeAddress, feeAddress); } /** * @notice Updates the keeper contract of the pool * @param _keeper New address of the keeper contract */ function setKeeper(address _keeper) external override onlyGov onlyUnpaused { require(_keeper != address(0), "Keeper address cannot be 0 address"); address oldKeeper = keeper; keeper = _keeper; emit KeeperAddressChanged(oldKeeper, keeper); } /** * @notice Starts to transfer governance of the pool. The new governance * address must call `claimGovernance` in order for this to take * effect. Until this occurs, the existing governance address * remains in control of the pool. * @param _governance New address of the governance of the pool * @dev First step of the two-step governance transfer process * @dev Sets the governance transfer flag to true * @dev See `claimGovernance` */ function transferGovernance(address _governance) external override onlyGov onlyUnpaused { require(_governance != address(0), "Governance address cannot be 0 address"); provisionalGovernance = _governance; governanceTransferInProgress = true; emit ProvisionalGovernanceChanged(provisionalGovernance); } /** * @notice Completes transfer of governance by actually changing permissions * over the pool. * @dev Second and final step of the two-step governance transfer process * @dev See `transferGovernance` * @dev Sets the governance transfer flag to false * @dev After a successful call to this function, the actual governance * address and the provisional governance address MUST be equal. */ function claimGovernance() external override onlyUnpaused { require(governanceTransferInProgress, "No governance change active"); require(msg.sender == provisionalGovernance, "Not provisional governor"); address oldGovernance = governance; /* for later event emission */ governance = provisionalGovernance; governanceTransferInProgress = false; emit GovernanceAddressChanged(oldGovernance, governance); } /** * @return _latestPrice The oracle price * @return _data The oracleWrapper's metadata. Implementations can choose what data to return here * @return _lastPriceTimestamp The timestamp of the last upkeep * @return _updateInterval The update frequency for this pool * @dev To save gas so PoolKeeper does not have to make three external calls */ function getUpkeepInformation() external view override returns ( int256 _latestPrice, bytes memory _data, uint256 _lastPriceTimestamp, uint256 _updateInterval ) { (_latestPrice, _data) = IOracleWrapper(oracleWrapper).getPriceAndMetadata(); return (_latestPrice, _data, lastPriceTimestamp, updateInterval); } /** * @return The price of the pool's feed oracle */ function getOraclePrice() external view override returns (int256) { return IOracleWrapper(oracleWrapper).getPrice(); } function poolTokens() external view override returns (address[2] memory) { return tokens; } function balances() external view override returns (uint256 _shortBalance, uint256 _longBalance) { return (shortBalance, longBalance); } /** * @notice Withdraws all available quote asset from the pool * @dev Pool must not be paused * @dev ERC20 transfer */ function withdrawQuote() external onlyGov { require(paused, "Pool is live"); IERC20 quoteERC = IERC20(quoteToken); uint256 balance = quoteERC.balanceOf(address(this)); IERC20(quoteToken).safeTransfer(msg.sender, balance); } /** * @notice Pauses the pool * @dev Prevents all state updates until unpaused */ function pause() external onlyGov { paused = true; emit Paused(); } /** * @notice Unpauses the pool * @dev Prevents all state updates until unpaused */ function unpause() external onlyGov { paused = false; emit Unpaused(); } // #### Modifiers modifier onlyUnpaused() { require(!paused, "Pool is paused"); _; } modifier onlyKeeper() { require(msg.sender == keeper, "msg.sender not keeper"); _; } modifier onlyPoolCommitter() { require(msg.sender == poolCommitter, "msg.sender not poolCommitter"); _; } modifier onlyFeeReceiver() { require(msg.sender == feeAddress, "msg.sender not feeReceiver"); _; } modifier onlyGov() { require(msg.sender == governance, "msg.sender not governance"); _; } }
//SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity 0.8.7; import "../vendors/ERC20_Cloneable.sol"; import "../interfaces/IPoolToken.sol"; /// @title The pool token; used for ownership/shares of the underlying tokens of the long/short pool /// @dev ERC_20_Cloneable contains onlyOwner code implemented for use with the cloneable setup contract PoolToken is ERC20_Cloneable, IPoolToken { // #### Global state // #### Functions constructor(uint8 _decimals) ERC20_Cloneable("BASE_TOKEN", "BASE", _decimals) {} /** * @notice Mints pool tokens * @param amount Pool tokens to burn * @param account Account to burn pool tokens to * @return Whether the mint was successful */ function mint(uint256 amount, address account) external override onlyOwner returns (bool) { _mint(account, amount); return true; } /** * @notice Burns pool tokens * @param amount Pool tokens to burn * @param account Account to burn pool tokens from * @return Whether the burn was successful */ function burn(uint256 amount, address account) external override onlyOwner returns (bool) { _burn(account, amount); return true; } }
//SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity 0.8.7; import "../interfaces/IPoolKeeper.sol"; import "../interfaces/IOracleWrapper.sol"; import "../interfaces/IPoolFactory.sol"; import "../interfaces/ILeveragedPool.sol"; import "../interfaces/IERC20DecimalsWrapper.sol"; import "../interfaces/IERC20DecimalsWrapper.sol"; import "./PoolSwapLibrary.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/proxy/Clones.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "abdk-libraries-solidity/ABDKMathQuad.sol"; import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV2V3Interface.sol"; /// @title The manager contract for multiple markets and the pools in them contract PoolKeeper is IPoolKeeper, Ownable { /* Constants */ uint256 public constant BASE_TIP = 5; // 5% base tip uint256 public constant TIP_DELTA_PER_BLOCK = 5; // 5% increase per block uint256 public constant BLOCK_TIME = 13; /* in seconds */ uint256 public constant MAX_DECIMALS = 18; // #### Global variables /** * @notice Format: Pool address => last executionPrice */ mapping(address => int256) public executionPrice; IPoolFactory public factory; bytes16 constant fixedPoint = 0x403abc16d674ec800000000000000000; // 1 ether uint256 public gasPrice = 10 gwei; // #### Functions constructor(address _factory) { require(_factory != address(0), "Factory cannot be 0 address"); factory = IPoolFactory(_factory); } /** * @notice When a pool is created, this function is called by the factory to initiate price trackings * @param _poolAddress The address of the newly-created pools */ function newPool(address _poolAddress) external override onlyFactory { address oracleWrapper = ILeveragedPool(_poolAddress).oracleWrapper(); int256 firstPrice = IOracleWrapper(oracleWrapper).getPrice(); require(firstPrice > 0, "First price is non-positive"); int256 startingPrice = ABDKMathQuad.toInt(ABDKMathQuad.mul(ABDKMathQuad.fromInt(firstPrice), fixedPoint)); emit PoolAdded(_poolAddress, firstPrice); executionPrice[_poolAddress] = startingPrice; } // Keeper network /** * @notice Check if upkeep is required * @param _pool The address of the pool to upkeep * @return upkeepNeeded Whether or not upkeep is needed for this single pool */ function checkUpkeepSinglePool(address _pool) public view override returns (bool) { if (!factory.isValidPool(_pool)) { return false; } // The update interval has passed return ILeveragedPool(_pool).intervalPassed(); } /** * @notice Checks multiple pools if any of them need updating * @param _pools The array of pools to check * @return upkeepNeeded Whether or not at least one pool needs upkeeping */ function checkUpkeepMultiplePools(address[] calldata _pools) external view override returns (bool) { for (uint256 i = 0; i < _pools.length; i++) { if (checkUpkeepSinglePool(_pools[i])) { // One has been found that requires upkeeping return true; } } return false; } /** * @notice Called by keepers to perform an update on a single pool * @param _pool The pool code to perform the update for */ function performUpkeepSinglePool(address _pool) public override { uint256 startGas = gasleft(); // validate the pool, check that the interval time has passed if (!checkUpkeepSinglePool(_pool)) { return; } ILeveragedPool pool = ILeveragedPool(_pool); (int256 latestPrice, bytes memory data, uint256 savedPreviousUpdatedTimestamp, uint256 updateInterval) = pool .getUpkeepInformation(); // Start a new round // Get price in WAD format int256 lastExecutionPrice = executionPrice[_pool]; executionPrice[_pool] = latestPrice; // This allows us to still batch multiple calls to executePriceChange, even if some are invalid // Without reverting the entire transaction try pool.poolUpkeep(lastExecutionPrice, latestPrice) { // If poolUpkeep is successful, refund the keeper for their gas costs uint256 gasSpent = startGas - gasleft(); payKeeper(_pool, gasPrice, gasSpent, savedPreviousUpdatedTimestamp, updateInterval); emit UpkeepSuccessful(_pool, data, lastExecutionPrice, latestPrice); } catch Error(string memory reason) { // If poolUpkeep fails for any other reason, emit event emit PoolUpkeepError(_pool, reason); } } /** * @notice Called by keepers to perform an update on multiple pools * @param pools pool codes to perform the update for */ function performUpkeepMultiplePools(address[] calldata pools) external override { for (uint256 i = 0; i < pools.length; i++) { performUpkeepSinglePool(pools[i]); } } /** * @notice Pay keeper for upkeep * @param _pool Address of the given pool * @param _gasPrice Price of a single gas unit (in ETH) * @param _gasSpent Number of gas units spent * @param _savedPreviousUpdatedTimestamp Last timestamp when the pool's price execution happened * @param _updateInterval Pool interval of the given pool */ function payKeeper( address _pool, uint256 _gasPrice, uint256 _gasSpent, uint256 _savedPreviousUpdatedTimestamp, uint256 _updateInterval ) internal { uint256 reward = keeperReward(_pool, _gasPrice, _gasSpent, _savedPreviousUpdatedTimestamp, _updateInterval); if (ILeveragedPool(_pool).payKeeperFromBalances(msg.sender, reward)) { emit KeeperPaid(_pool, msg.sender, reward); } else { // Usually occurs if pool just started and does not have any funds emit KeeperPaymentError(_pool, msg.sender, reward); } } /** * @notice Payment keeper receives for performing upkeep on a given pool * @param _pool Address of the given pool * @param _gasPrice Price of a single gas unit (in ETH) * @param _gasSpent Number of gas units spent * @param _savedPreviousUpdatedTimestamp Last timestamp when the pool's price execution happened * @param _poolInterval Pool interval of the given pool * @return Number of settlement tokens to give to the keeper for work performed */ function keeperReward( address _pool, uint256 _gasPrice, uint256 _gasSpent, uint256 _savedPreviousUpdatedTimestamp, uint256 _poolInterval ) public view returns (uint256) { // keeper gas cost in wei. WAD formatted uint256 _keeperGas = keeperGas(_pool, _gasPrice, _gasSpent); // tip percent in wad units bytes16 _tipPercent = ABDKMathQuad.fromUInt(keeperTip(_savedPreviousUpdatedTimestamp, _poolInterval)); // amount of settlement tokens to give to the keeper _tipPercent = ABDKMathQuad.div(_tipPercent, ABDKMathQuad.fromUInt(100)); int256 wadRewardValue = ABDKMathQuad.toInt( ABDKMathQuad.add( ABDKMathQuad.fromUInt(_keeperGas), ABDKMathQuad.div((ABDKMathQuad.mul(ABDKMathQuad.fromUInt(_keeperGas), _tipPercent)), fixedPoint) ) ); uint256 decimals = IERC20DecimalsWrapper(ILeveragedPool(_pool).quoteToken()).decimals(); uint256 deWadifiedReward = PoolSwapLibrary.fromWad(uint256(wadRewardValue), decimals); // _keeperGas + _keeperGas * percentTip return deWadifiedReward; } /** * @notice Compensation a keeper will receive for their gas expenditure * @param _pool Address of the given pool * @param _gasPrice Price of a single gas unit (in ETH) * @param _gasSpent Number of gas units spent * @return Keeper's gas compensation */ function keeperGas( address _pool, uint256 _gasPrice, uint256 _gasSpent ) public view returns (uint256) { int256 settlementTokenPrice = IOracleWrapper(ILeveragedPool(_pool).settlementEthOracle()).getPrice(); if (settlementTokenPrice <= 0) { return 0; } else { /* safe due to explicit bounds check above */ /* (wei * Settlement / ETH) / fixed point (10^18) = amount in settlement */ bytes16 _weiSpent = ABDKMathQuad.fromUInt(_gasPrice * _gasSpent); bytes16 _settlementTokenPrice = ABDKMathQuad.fromUInt(uint256(settlementTokenPrice)); return ABDKMathQuad.toUInt(ABDKMathQuad.div(ABDKMathQuad.mul(_weiSpent, _settlementTokenPrice), fixedPoint)); } } /** * @notice Tip a keeper will receive for successfully updating the specified pool * @param _savedPreviousUpdatedTimestamp Last timestamp when the pool's price execution happened * @param _poolInterval Pool interval of the given pool * @return Percent of the `keeperGas` cost to add to payment, as a percent */ function keeperTip(uint256 _savedPreviousUpdatedTimestamp, uint256 _poolInterval) public view returns (uint256) { /* the number of blocks that have elapsed since the given pool's updateInterval passed */ uint256 elapsedBlocksNumerator = (block.timestamp - (_savedPreviousUpdatedTimestamp + _poolInterval)); uint256 keeperTip = BASE_TIP + (TIP_DELTA_PER_BLOCK * elapsedBlocksNumerator) / BLOCK_TIME; // In case of network outages or otherwise, we want to cap the tip so that the keeper cost isn't unbounded if (keeperTip > 100) { return 100; } else { return keeperTip; } } function setFactory(address _factory) external override onlyOwner { factory = IPoolFactory(_factory); } /** * @notice Sets the gas price to be used in compensating keepers for successful upkeep * @param _price Price (in ETH) per unit gas * @dev Only owner */ function setGasPrice(uint256 _price) external onlyOwner { gasPrice = _price; } modifier onlyFactory() { require(msg.sender == address(factory), "Caller not factory"); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for * deploying minimal proxy contracts, also known as "clones". * * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies * > a minimal bytecode implementation that delegates all calls to a known, fixed address. * * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the * deterministic method. * * _Available since v3.4._ */ library Clones { /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create opcode, which should never revert. */ function clone(address implementation) internal returns (address instance) { assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, implementation)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) instance := create(0, ptr, 0x37) } require(instance != address(0), "ERC1167: create failed"); } /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create2 opcode and a `salt` to deterministically deploy * the clone. Using the same `implementation` and `salt` multiple time will revert, since * the clones cannot be deployed twice at the same address. */ function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, implementation)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) instance := create2(0, ptr, 0x37, salt) } require(instance != address(0), "ERC1167: create2 failed"); } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, implementation)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000) mstore(add(ptr, 0x38), shl(0x60, deployer)) mstore(add(ptr, 0x4c), salt) mstore(add(ptr, 0x6c), keccak256(ptr, 0x37)) predicted := keccak256(add(ptr, 0x37), 0x55) } } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress(address implementation, bytes32 salt) internal view returns (address predicted) { return predictDeterministicAddress(implementation, salt, address(this)); } }
// SPDX-License-Identifier: MIT 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() { _setOwner(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _setOwner(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"); _setOwner(newOwner); } function _setOwner(address newOwner) private { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
//SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity 0.8.7; /// @title Interface for the pool tokens interface IPoolToken { function mint(uint256 amount, address account) external returns (bool); function burn(uint256 amount, address account) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
//SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity 0.8.7; import "abdk-libraries-solidity/ABDKMathQuad.sol"; /// @title Library for various useful (mostly) mathematical functions library PoolSwapLibrary { bytes16 public constant one = 0x3fff0000000000000000000000000000; bytes16 public constant zero = 0x00000000000000000000000000000000; /* ABDKMathQuad defines this but it's private */ bytes16 private constant NEGATIVE_ZERO = 0x80000000000000000000000000000000; uint256 public constant MAX_DECIMALS = 18; uint256 public constant WAD_PRECISION = 10**18; struct PriceChangeData { int256 oldPrice; int256 newPrice; uint256 longBalance; uint256 shortBalance; bytes16 leverageAmount; bytes16 fee; } /** * @notice Calculates the ratio between two numbers * @dev Rounds any overflow towards 0. If either parameter is zero, the ratio is 0 * @param _numerator The "parts per" side of the equation. If this is zero, the ratio is zero * @param _denominator The "per part" side of the equation. If this is zero, the ratio is zero * @return the ratio, as an ABDKMathQuad number (IEEE 754 quadruple precision floating point) */ function getRatio(uint256 _numerator, uint256 _denominator) public pure returns (bytes16) { // Catch the divide by zero error. if (_denominator == 0) { return 0; } return ABDKMathQuad.div(ABDKMathQuad.fromUInt(_numerator), ABDKMathQuad.fromUInt(_denominator)); } /** * @notice Gets the short and long balances after the keeper rewards have been paid out * Keeper rewards are paid proportionally to the short and long pool * @dev Assumes shortBalance + longBalance >= reward * @param reward Amount of keeper reward * @param shortBalance Short balance of the pool * @param longBalance Long balance of the pool * @return shortBalanceAfterFees Short balance of the pool after the keeper reward has been paid * @return longBalanceAfterFees Long balance of the pool after the keeper reward has been paid */ function getBalancesAfterFees( uint256 reward, uint256 shortBalance, uint256 longBalance ) external pure returns (uint256, uint256) { bytes16 ratioShort = getRatio(shortBalance, shortBalance + longBalance); uint256 shortFees = convertDecimalToUInt(multiplyDecimalByUInt(ratioShort, reward)); uint256 shortBalanceAfterFees = shortBalance - shortFees; uint256 longBalanceAfterFees = longBalance - (reward - shortFees); // Return shortBalance and longBalance after rewards are paid out return (shortBalanceAfterFees, longBalanceAfterFees); } /** * @notice Compares two decimal numbers * @param x The first number to compare * @param y The second number to compare * @return -1 if x < y, 0 if x = y, or 1 if x > y */ function compareDecimals(bytes16 x, bytes16 y) public pure returns (int8) { return ABDKMathQuad.cmp(x, y); } /** * @notice Converts an integer value to a compatible decimal value * @param amount The amount to convert * @return The amount as a IEEE754 quadruple precision number */ function convertUIntToDecimal(uint256 amount) external pure returns (bytes16) { return ABDKMathQuad.fromUInt(amount); } /** * @notice Converts a raw decimal value to a more readable uint256 value * @param ratio The value to convert * @return The converted value */ function convertDecimalToUInt(bytes16 ratio) public pure returns (uint256) { return ABDKMathQuad.toUInt(ratio); } /** * @notice Multiplies a decimal and an unsigned integer * @param a The first term * @param b The second term * @return The product of a*b as a decimal */ function multiplyDecimalByUInt(bytes16 a, uint256 b) public pure returns (bytes16) { return ABDKMathQuad.mul(a, ABDKMathQuad.fromUInt(b)); } /** * @notice Divides two integers * @param a The dividend * @param b The divisor * @return The quotient */ function divInt(int256 a, int256 b) public pure returns (bytes16) { return ABDKMathQuad.div(ABDKMathQuad.fromInt(a), ABDKMathQuad.fromInt(b)); } /** * @notice Calculates the loss multiplier to apply to the losing pool. Includes the power leverage * @param ratio The ratio of new price to old price * @param direction The direction of the change. -1 if it's decreased, 0 if it hasn't changed, and 1 if it's increased * @param leverage The amount of leverage to apply * @return The multiplier */ function getLossMultiplier( bytes16 ratio, int8 direction, bytes16 leverage ) public pure returns (bytes16) { // If decreased: 2 ^ (leverage * log2[(1 * new/old) + [(0 * 1) / new/old]]) // = 2 ^ (leverage * log2[(new/old)]) // If increased: 2 ^ (leverage * log2[(0 * new/old) + [(1 * 1) / new/old]]) // = 2 ^ (leverage * log2([1 / new/old])) // = 2 ^ (leverage * log2([old/new])) return ABDKMathQuad.pow_2( ABDKMathQuad.mul(leverage, ABDKMathQuad.log_2(direction < 0 ? ratio : ABDKMathQuad.div(one, ratio))) ); } /** * @notice Calculates the amount to take from the losing pool * @param lossMultiplier The multiplier to use * @param balance The balance of the losing pool */ function getLossAmount(bytes16 lossMultiplier, uint256 balance) public pure returns (uint256) { return ABDKMathQuad.toUInt( ABDKMathQuad.mul(ABDKMathQuad.sub(one, lossMultiplier), ABDKMathQuad.fromUInt(balance)) ); } /** * @notice Calculates the effect of a price change. This involves calculating how many funds to transfer from the losing pool to the other. * @dev This function should be called by the LeveragedPool. * @param priceChange The struct containing necessary data to calculate price change */ function calculatePriceChange(PriceChangeData memory priceChange) external pure returns ( uint256, uint256, uint256 ) { uint256 shortBalance = priceChange.shortBalance; uint256 longBalance = priceChange.longBalance; bytes16 leverageAmount = priceChange.leverageAmount; int256 oldPrice = priceChange.oldPrice; int256 newPrice = priceChange.newPrice; bytes16 fee = priceChange.fee; // Calculate fees from long and short sides uint256 longFeeAmount = convertDecimalToUInt(multiplyDecimalByUInt(fee, longBalance)) / PoolSwapLibrary.WAD_PRECISION; uint256 shortFeeAmount = convertDecimalToUInt(multiplyDecimalByUInt(fee, shortBalance)) / PoolSwapLibrary.WAD_PRECISION; shortBalance = shortBalance - shortFeeAmount; longBalance = longBalance - longFeeAmount; uint256 totalFeeAmount = shortFeeAmount + longFeeAmount; // Use the ratio to determine if the price increased or decreased and therefore which direction // the funds should be transferred towards. bytes16 ratio = divInt(newPrice, oldPrice); int8 direction = compareDecimals(ratio, PoolSwapLibrary.one); // Take into account the leverage bytes16 lossMultiplier = getLossMultiplier(ratio, direction, leverageAmount); if (direction >= 0 && shortBalance > 0) { // Move funds from short to long pair uint256 lossAmount = getLossAmount(lossMultiplier, shortBalance); shortBalance = shortBalance - lossAmount; longBalance = longBalance + lossAmount; } else if (direction < 0 && longBalance > 0) { // Move funds from long to short pair uint256 lossAmount = getLossAmount(lossMultiplier, longBalance); shortBalance = shortBalance + lossAmount; longBalance = longBalance - lossAmount; } return (longBalance, shortBalance, totalFeeAmount); } /** * @notice Returns true if the given timestamp is BEFORE the frontRunningInterval starts, * which is allowed for uncommitment. * @dev If you try to uncommit AFTER the frontRunningInterval, it should revert. * @param subjectTime The timestamp for which you want to calculate if it was beforeFrontRunningInterval * @param lastPriceTimestamp The timestamp of the last price update * @param updateInterval The interval between price updates * @param frontRunningInterval The window of time before a price udpate users can not uncommit or have their commit executed from */ function isBeforeFrontRunningInterval( uint256 subjectTime, uint256 lastPriceTimestamp, uint256 updateInterval, uint256 frontRunningInterval ) external pure returns (bool) { return lastPriceTimestamp + updateInterval - frontRunningInterval > subjectTime; } /** * @notice Gets the number of settlement tokens to be withdrawn based on a pool token burn amount * @dev Calculates as `balance * amountIn / (tokenSupply + shadowBalance) * @param tokenSupply Total supply of pool tokens * @param amountIn Commitment amount of collateral tokens going into the pool * @param balance Balance of the pool (no. of underlying collateral tokens in pool) * @param shadowBalance Balance the shadow pool at time of mint * @return Number of settlement tokens to be withdrawn on a burn */ function getWithdrawAmountOnBurn( uint256 tokenSupply, uint256 amountIn, uint256 balance, uint256 shadowBalance ) external pure returns (uint256) { require(amountIn > 0, "Invalid amount"); // Catch the divide by zero error. if (balance == 0 || tokenSupply + shadowBalance == 0) { return amountIn; } bytes16 numerator = ABDKMathQuad.mul(ABDKMathQuad.fromUInt(balance), ABDKMathQuad.fromUInt(amountIn)); return ABDKMathQuad.toUInt(ABDKMathQuad.div(numerator, ABDKMathQuad.fromUInt(tokenSupply + shadowBalance))); } /** * @notice Gets the number of pool tokens to be minted based on existing tokens * @dev Calculated as (tokenSupply + shadowBalance) * amountIn / balance * @param tokenSupply Total supply of pool tokens * @param amountIn Commitment amount of collateral tokens going into the pool * @param balance Balance of the pool (no. of underlying collateral tokens in pool) * @param shadowBalance Balance the shadow pool at time of mint * @return Number of pool tokens to be minted */ function getMintAmount( uint256 tokenSupply, uint256 amountIn, uint256 balance, uint256 shadowBalance ) external pure returns (uint256) { require(amountIn > 0, "Invalid amount"); // Catch the divide by zero error. if (balance == 0 || tokenSupply + shadowBalance == 0) { return amountIn; } bytes16 numerator = ABDKMathQuad.mul( ABDKMathQuad.fromUInt(tokenSupply + shadowBalance), ABDKMathQuad.fromUInt(amountIn) ); return ABDKMathQuad.toUInt(ABDKMathQuad.div(numerator, ABDKMathQuad.fromUInt(balance))); } /** * @notice Converts from a WAD to normal value * @return Converted non-WAD value */ function fromWad(uint256 _wadValue, uint256 _decimals) external pure returns (uint256) { uint256 scaler = 10**(MAX_DECIMALS - _decimals); return _wadValue / scaler; } }
//SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity 0.8.7; /// @title The oracle wrapper contract interface interface IOracleWrapper { function oracle() external view returns (address); // #### Functions /** * @notice Sets the oracle for a given market * @dev Should be secured, ideally only allowing the PoolKeeper to access * @param _oracle The oracle to set for the market */ function setOracle(address _oracle) external; /** * @notice Returns the current price for the asset in question * @return The latest price */ function getPrice() external view returns (int256); /** * @return _price The latest round data price * @return _data The metadata. Implementations can choose what data to return here */ function getPriceAndMetadata() external view returns (int256 _price, bytes memory _data); /** * @notice Converts from a WAD to normal value * @return Converted non-WAD value */ function fromWad(int256 wad) external view returns (int256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) private pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: BSD-4-Clause /* * ABDK Math Quad Smart Contract Library. Copyright © 2019 by ABDK Consulting. * Author: Mikhail Vladimirov <[email protected]> */ pragma solidity ^0.8.0; /** * Smart contract library of mathematical functions operating with IEEE 754 * quadruple-precision binary floating-point numbers (quadruple precision * numbers). As long as quadruple precision numbers are 16-bytes long, they are * represented by bytes16 type. */ library ABDKMathQuad { /* * 0. */ bytes16 private constant POSITIVE_ZERO = 0x00000000000000000000000000000000; /* * -0. */ bytes16 private constant NEGATIVE_ZERO = 0x80000000000000000000000000000000; /* * +Infinity. */ bytes16 private constant POSITIVE_INFINITY = 0x7FFF0000000000000000000000000000; /* * -Infinity. */ bytes16 private constant NEGATIVE_INFINITY = 0xFFFF0000000000000000000000000000; /* * Canonical NaN value. */ bytes16 private constant NaN = 0x7FFF8000000000000000000000000000; /** * Convert signed 256-bit integer number into quadruple precision number. * * @param x signed 256-bit integer number * @return quadruple precision number */ function fromInt (int256 x) internal pure returns (bytes16) { unchecked { if (x == 0) return bytes16 (0); else { // We rely on overflow behavior here uint256 result = uint256 (x > 0 ? x : -x); uint256 msb = mostSignificantBit (result); if (msb < 112) result <<= 112 - msb; else if (msb > 112) result >>= msb - 112; result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16383 + msb << 112; if (x < 0) result |= 0x80000000000000000000000000000000; return bytes16 (uint128 (result)); } } } /** * Convert quadruple precision number into signed 256-bit integer number * rounding towards zero. Revert on overflow. * * @param x quadruple precision number * @return signed 256-bit integer number */ function toInt (bytes16 x) internal pure returns (int256) { unchecked { uint256 exponent = uint128 (x) >> 112 & 0x7FFF; require (exponent <= 16638); // Overflow if (exponent < 16383) return 0; // Underflow uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 0x10000000000000000000000000000; if (exponent < 16495) result >>= 16495 - exponent; else if (exponent > 16495) result <<= exponent - 16495; if (uint128 (x) >= 0x80000000000000000000000000000000) { // Negative require (result <= 0x8000000000000000000000000000000000000000000000000000000000000000); return -int256 (result); // We rely on overflow behavior here } else { require (result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return int256 (result); } } } /** * Convert unsigned 256-bit integer number into quadruple precision number. * * @param x unsigned 256-bit integer number * @return quadruple precision number */ function fromUInt (uint256 x) internal pure returns (bytes16) { unchecked { if (x == 0) return bytes16 (0); else { uint256 result = x; uint256 msb = mostSignificantBit (result); if (msb < 112) result <<= 112 - msb; else if (msb > 112) result >>= msb - 112; result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16383 + msb << 112; return bytes16 (uint128 (result)); } } } /** * Convert quadruple precision number into unsigned 256-bit integer number * rounding towards zero. Revert on underflow. Note, that negative floating * point numbers in range (-1.0 .. 0.0) may be converted to unsigned integer * without error, because they are rounded to zero. * * @param x quadruple precision number * @return unsigned 256-bit integer number */ function toUInt (bytes16 x) internal pure returns (uint256) { unchecked { uint256 exponent = uint128 (x) >> 112 & 0x7FFF; if (exponent < 16383) return 0; // Underflow require (uint128 (x) < 0x80000000000000000000000000000000); // Negative require (exponent <= 16638); // Overflow uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 0x10000000000000000000000000000; if (exponent < 16495) result >>= 16495 - exponent; else if (exponent > 16495) result <<= exponent - 16495; return result; } } /** * Convert signed 128.128 bit fixed point number into quadruple precision * number. * * @param x signed 128.128 bit fixed point number * @return quadruple precision number */ function from128x128 (int256 x) internal pure returns (bytes16) { unchecked { if (x == 0) return bytes16 (0); else { // We rely on overflow behavior here uint256 result = uint256 (x > 0 ? x : -x); uint256 msb = mostSignificantBit (result); if (msb < 112) result <<= 112 - msb; else if (msb > 112) result >>= msb - 112; result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16255 + msb << 112; if (x < 0) result |= 0x80000000000000000000000000000000; return bytes16 (uint128 (result)); } } } /** * Convert quadruple precision number into signed 128.128 bit fixed point * number. Revert on overflow. * * @param x quadruple precision number * @return signed 128.128 bit fixed point number */ function to128x128 (bytes16 x) internal pure returns (int256) { unchecked { uint256 exponent = uint128 (x) >> 112 & 0x7FFF; require (exponent <= 16510); // Overflow if (exponent < 16255) return 0; // Underflow uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 0x10000000000000000000000000000; if (exponent < 16367) result >>= 16367 - exponent; else if (exponent > 16367) result <<= exponent - 16367; if (uint128 (x) >= 0x80000000000000000000000000000000) { // Negative require (result <= 0x8000000000000000000000000000000000000000000000000000000000000000); return -int256 (result); // We rely on overflow behavior here } else { require (result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return int256 (result); } } } /** * Convert signed 64.64 bit fixed point number into quadruple precision * number. * * @param x signed 64.64 bit fixed point number * @return quadruple precision number */ function from64x64 (int128 x) internal pure returns (bytes16) { unchecked { if (x == 0) return bytes16 (0); else { // We rely on overflow behavior here uint256 result = uint128 (x > 0 ? x : -x); uint256 msb = mostSignificantBit (result); if (msb < 112) result <<= 112 - msb; else if (msb > 112) result >>= msb - 112; result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16319 + msb << 112; if (x < 0) result |= 0x80000000000000000000000000000000; return bytes16 (uint128 (result)); } } } /** * Convert quadruple precision number into signed 64.64 bit fixed point * number. Revert on overflow. * * @param x quadruple precision number * @return signed 64.64 bit fixed point number */ function to64x64 (bytes16 x) internal pure returns (int128) { unchecked { uint256 exponent = uint128 (x) >> 112 & 0x7FFF; require (exponent <= 16446); // Overflow if (exponent < 16319) return 0; // Underflow uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 0x10000000000000000000000000000; if (exponent < 16431) result >>= 16431 - exponent; else if (exponent > 16431) result <<= exponent - 16431; if (uint128 (x) >= 0x80000000000000000000000000000000) { // Negative require (result <= 0x80000000000000000000000000000000); return -int128 (int256 (result)); // We rely on overflow behavior here } else { require (result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); return int128 (int256 (result)); } } } /** * Convert octuple precision number into quadruple precision number. * * @param x octuple precision number * @return quadruple precision number */ function fromOctuple (bytes32 x) internal pure returns (bytes16) { unchecked { bool negative = x & 0x8000000000000000000000000000000000000000000000000000000000000000 > 0; uint256 exponent = uint256 (x) >> 236 & 0x7FFFF; uint256 significand = uint256 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (exponent == 0x7FFFF) { if (significand > 0) return NaN; else return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY; } if (exponent > 278526) return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY; else if (exponent < 245649) return negative ? NEGATIVE_ZERO : POSITIVE_ZERO; else if (exponent < 245761) { significand = (significand | 0x100000000000000000000000000000000000000000000000000000000000) >> 245885 - exponent; exponent = 0; } else { significand >>= 124; exponent -= 245760; } uint128 result = uint128 (significand | exponent << 112); if (negative) result |= 0x80000000000000000000000000000000; return bytes16 (result); } } /** * Convert quadruple precision number into octuple precision number. * * @param x quadruple precision number * @return octuple precision number */ function toOctuple (bytes16 x) internal pure returns (bytes32) { unchecked { uint256 exponent = uint128 (x) >> 112 & 0x7FFF; uint256 result = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (exponent == 0x7FFF) exponent = 0x7FFFF; // Infinity or NaN else if (exponent == 0) { if (result > 0) { uint256 msb = mostSignificantBit (result); result = result << 236 - msb & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; exponent = 245649 + msb; } } else { result <<= 124; exponent += 245760; } result |= exponent << 236; if (uint128 (x) >= 0x80000000000000000000000000000000) result |= 0x8000000000000000000000000000000000000000000000000000000000000000; return bytes32 (result); } } /** * Convert double precision number into quadruple precision number. * * @param x double precision number * @return quadruple precision number */ function fromDouble (bytes8 x) internal pure returns (bytes16) { unchecked { uint256 exponent = uint64 (x) >> 52 & 0x7FF; uint256 result = uint64 (x) & 0xFFFFFFFFFFFFF; if (exponent == 0x7FF) exponent = 0x7FFF; // Infinity or NaN else if (exponent == 0) { if (result > 0) { uint256 msb = mostSignificantBit (result); result = result << 112 - msb & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; exponent = 15309 + msb; } } else { result <<= 60; exponent += 15360; } result |= exponent << 112; if (x & 0x8000000000000000 > 0) result |= 0x80000000000000000000000000000000; return bytes16 (uint128 (result)); } } /** * Convert quadruple precision number into double precision number. * * @param x quadruple precision number * @return double precision number */ function toDouble (bytes16 x) internal pure returns (bytes8) { unchecked { bool negative = uint128 (x) >= 0x80000000000000000000000000000000; uint256 exponent = uint128 (x) >> 112 & 0x7FFF; uint256 significand = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (exponent == 0x7FFF) { if (significand > 0) return 0x7FF8000000000000; // NaN else return negative ? bytes8 (0xFFF0000000000000) : // -Infinity bytes8 (0x7FF0000000000000); // Infinity } if (exponent > 17406) return negative ? bytes8 (0xFFF0000000000000) : // -Infinity bytes8 (0x7FF0000000000000); // Infinity else if (exponent < 15309) return negative ? bytes8 (0x8000000000000000) : // -0 bytes8 (0x0000000000000000); // 0 else if (exponent < 15361) { significand = (significand | 0x10000000000000000000000000000) >> 15421 - exponent; exponent = 0; } else { significand >>= 60; exponent -= 15360; } uint64 result = uint64 (significand | exponent << 52); if (negative) result |= 0x8000000000000000; return bytes8 (result); } } /** * Test whether given quadruple precision number is NaN. * * @param x quadruple precision number * @return true if x is NaN, false otherwise */ function isNaN (bytes16 x) internal pure returns (bool) { unchecked { return uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF > 0x7FFF0000000000000000000000000000; } } /** * Test whether given quadruple precision number is positive or negative * infinity. * * @param x quadruple precision number * @return true if x is positive or negative infinity, false otherwise */ function isInfinity (bytes16 x) internal pure returns (bool) { unchecked { return uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x7FFF0000000000000000000000000000; } } /** * Calculate sign of x, i.e. -1 if x is negative, 0 if x if zero, and 1 if x * is positive. Note that sign (-0) is zero. Revert if x is NaN. * * @param x quadruple precision number * @return sign of x */ function sign (bytes16 x) internal pure returns (int8) { unchecked { uint128 absoluteX = uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; require (absoluteX <= 0x7FFF0000000000000000000000000000); // Not NaN if (absoluteX == 0) return 0; else if (uint128 (x) >= 0x80000000000000000000000000000000) return -1; else return 1; } } /** * Calculate sign (x - y). Revert if either argument is NaN, or both * arguments are infinities of the same sign. * * @param x quadruple precision number * @param y quadruple precision number * @return sign (x - y) */ function cmp (bytes16 x, bytes16 y) internal pure returns (int8) { unchecked { uint128 absoluteX = uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; require (absoluteX <= 0x7FFF0000000000000000000000000000); // Not NaN uint128 absoluteY = uint128 (y) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; require (absoluteY <= 0x7FFF0000000000000000000000000000); // Not NaN // Not infinities of the same sign require (x != y || absoluteX < 0x7FFF0000000000000000000000000000); if (x == y) return 0; else { bool negativeX = uint128 (x) >= 0x80000000000000000000000000000000; bool negativeY = uint128 (y) >= 0x80000000000000000000000000000000; if (negativeX) { if (negativeY) return absoluteX > absoluteY ? -1 : int8 (1); else return -1; } else { if (negativeY) return 1; else return absoluteX > absoluteY ? int8 (1) : -1; } } } } /** * Test whether x equals y. NaN, infinity, and -infinity are not equal to * anything. * * @param x quadruple precision number * @param y quadruple precision number * @return true if x equals to y, false otherwise */ function eq (bytes16 x, bytes16 y) internal pure returns (bool) { unchecked { if (x == y) { return uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF < 0x7FFF0000000000000000000000000000; } else return false; } } /** * Calculate x + y. Special values behave in the following way: * * NaN + x = NaN for any x. * Infinity + x = Infinity for any finite x. * -Infinity + x = -Infinity for any finite x. * Infinity + Infinity = Infinity. * -Infinity + -Infinity = -Infinity. * Infinity + -Infinity = -Infinity + Infinity = NaN. * * @param x quadruple precision number * @param y quadruple precision number * @return quadruple precision number */ function add (bytes16 x, bytes16 y) internal pure returns (bytes16) { unchecked { uint256 xExponent = uint128 (x) >> 112 & 0x7FFF; uint256 yExponent = uint128 (y) >> 112 & 0x7FFF; if (xExponent == 0x7FFF) { if (yExponent == 0x7FFF) { if (x == y) return x; else return NaN; } else return x; } else if (yExponent == 0x7FFF) return y; else { bool xSign = uint128 (x) >= 0x80000000000000000000000000000000; uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0) xExponent = 1; else xSignifier |= 0x10000000000000000000000000000; bool ySign = uint128 (y) >= 0x80000000000000000000000000000000; uint256 ySignifier = uint128 (y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (yExponent == 0) yExponent = 1; else ySignifier |= 0x10000000000000000000000000000; if (xSignifier == 0) return y == NEGATIVE_ZERO ? POSITIVE_ZERO : y; else if (ySignifier == 0) return x == NEGATIVE_ZERO ? POSITIVE_ZERO : x; else { int256 delta = int256 (xExponent) - int256 (yExponent); if (xSign == ySign) { if (delta > 112) return x; else if (delta > 0) ySignifier >>= uint256 (delta); else if (delta < -112) return y; else if (delta < 0) { xSignifier >>= uint256 (-delta); xExponent = yExponent; } xSignifier += ySignifier; if (xSignifier >= 0x20000000000000000000000000000) { xSignifier >>= 1; xExponent += 1; } if (xExponent == 0x7FFF) return xSign ? NEGATIVE_INFINITY : POSITIVE_INFINITY; else { if (xSignifier < 0x10000000000000000000000000000) xExponent = 0; else xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; return bytes16 (uint128 ( (xSign ? 0x80000000000000000000000000000000 : 0) | (xExponent << 112) | xSignifier)); } } else { if (delta > 0) { xSignifier <<= 1; xExponent -= 1; } else if (delta < 0) { ySignifier <<= 1; xExponent = yExponent - 1; } if (delta > 112) ySignifier = 1; else if (delta > 1) ySignifier = (ySignifier - 1 >> uint256 (delta - 1)) + 1; else if (delta < -112) xSignifier = 1; else if (delta < -1) xSignifier = (xSignifier - 1 >> uint256 (-delta - 1)) + 1; if (xSignifier >= ySignifier) xSignifier -= ySignifier; else { xSignifier = ySignifier - xSignifier; xSign = ySign; } if (xSignifier == 0) return POSITIVE_ZERO; uint256 msb = mostSignificantBit (xSignifier); if (msb == 113) { xSignifier = xSignifier >> 1 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; xExponent += 1; } else if (msb < 112) { uint256 shift = 112 - msb; if (xExponent > shift) { xSignifier = xSignifier << shift & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; xExponent -= shift; } else { xSignifier <<= xExponent - 1; xExponent = 0; } } else xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0x7FFF) return xSign ? NEGATIVE_INFINITY : POSITIVE_INFINITY; else return bytes16 (uint128 ( (xSign ? 0x80000000000000000000000000000000 : 0) | (xExponent << 112) | xSignifier)); } } } } } /** * Calculate x - y. Special values behave in the following way: * * NaN - x = NaN for any x. * Infinity - x = Infinity for any finite x. * -Infinity - x = -Infinity for any finite x. * Infinity - -Infinity = Infinity. * -Infinity - Infinity = -Infinity. * Infinity - Infinity = -Infinity - -Infinity = NaN. * * @param x quadruple precision number * @param y quadruple precision number * @return quadruple precision number */ function sub (bytes16 x, bytes16 y) internal pure returns (bytes16) { unchecked { return add (x, y ^ 0x80000000000000000000000000000000); } } /** * Calculate x * y. Special values behave in the following way: * * NaN * x = NaN for any x. * Infinity * x = Infinity for any finite positive x. * Infinity * x = -Infinity for any finite negative x. * -Infinity * x = -Infinity for any finite positive x. * -Infinity * x = Infinity for any finite negative x. * Infinity * 0 = NaN. * -Infinity * 0 = NaN. * Infinity * Infinity = Infinity. * Infinity * -Infinity = -Infinity. * -Infinity * Infinity = -Infinity. * -Infinity * -Infinity = Infinity. * * @param x quadruple precision number * @param y quadruple precision number * @return quadruple precision number */ function mul (bytes16 x, bytes16 y) internal pure returns (bytes16) { unchecked { uint256 xExponent = uint128 (x) >> 112 & 0x7FFF; uint256 yExponent = uint128 (y) >> 112 & 0x7FFF; if (xExponent == 0x7FFF) { if (yExponent == 0x7FFF) { if (x == y) return x ^ y & 0x80000000000000000000000000000000; else if (x ^ y == 0x80000000000000000000000000000000) return x | y; else return NaN; } else { if (y & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN; else return x ^ y & 0x80000000000000000000000000000000; } } else if (yExponent == 0x7FFF) { if (x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN; else return y ^ x & 0x80000000000000000000000000000000; } else { uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0) xExponent = 1; else xSignifier |= 0x10000000000000000000000000000; uint256 ySignifier = uint128 (y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (yExponent == 0) yExponent = 1; else ySignifier |= 0x10000000000000000000000000000; xSignifier *= ySignifier; if (xSignifier == 0) return (x ^ y) & 0x80000000000000000000000000000000 > 0 ? NEGATIVE_ZERO : POSITIVE_ZERO; xExponent += yExponent; uint256 msb = xSignifier >= 0x200000000000000000000000000000000000000000000000000000000 ? 225 : xSignifier >= 0x100000000000000000000000000000000000000000000000000000000 ? 224 : mostSignificantBit (xSignifier); if (xExponent + msb < 16496) { // Underflow xExponent = 0; xSignifier = 0; } else if (xExponent + msb < 16608) { // Subnormal if (xExponent < 16496) xSignifier >>= 16496 - xExponent; else if (xExponent > 16496) xSignifier <<= xExponent - 16496; xExponent = 0; } else if (xExponent + msb > 49373) { xExponent = 0x7FFF; xSignifier = 0; } else { if (msb > 112) xSignifier >>= msb - 112; else if (msb < 112) xSignifier <<= 112 - msb; xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; xExponent = xExponent + msb - 16607; } return bytes16 (uint128 (uint128 ((x ^ y) & 0x80000000000000000000000000000000) | xExponent << 112 | xSignifier)); } } } /** * Calculate x / y. Special values behave in the following way: * * NaN / x = NaN for any x. * x / NaN = NaN for any x. * Infinity / x = Infinity for any finite non-negative x. * Infinity / x = -Infinity for any finite negative x including -0. * -Infinity / x = -Infinity for any finite non-negative x. * -Infinity / x = Infinity for any finite negative x including -0. * x / Infinity = 0 for any finite non-negative x. * x / -Infinity = -0 for any finite non-negative x. * x / Infinity = -0 for any finite non-negative x including -0. * x / -Infinity = 0 for any finite non-negative x including -0. * * Infinity / Infinity = NaN. * Infinity / -Infinity = -NaN. * -Infinity / Infinity = -NaN. * -Infinity / -Infinity = NaN. * * Division by zero behaves in the following way: * * x / 0 = Infinity for any finite positive x. * x / -0 = -Infinity for any finite positive x. * x / 0 = -Infinity for any finite negative x. * x / -0 = Infinity for any finite negative x. * 0 / 0 = NaN. * 0 / -0 = NaN. * -0 / 0 = NaN. * -0 / -0 = NaN. * * @param x quadruple precision number * @param y quadruple precision number * @return quadruple precision number */ function div (bytes16 x, bytes16 y) internal pure returns (bytes16) { unchecked { uint256 xExponent = uint128 (x) >> 112 & 0x7FFF; uint256 yExponent = uint128 (y) >> 112 & 0x7FFF; if (xExponent == 0x7FFF) { if (yExponent == 0x7FFF) return NaN; else return x ^ y & 0x80000000000000000000000000000000; } else if (yExponent == 0x7FFF) { if (y & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFF != 0) return NaN; else return POSITIVE_ZERO | (x ^ y) & 0x80000000000000000000000000000000; } else if (y & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) { if (x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN; else return POSITIVE_INFINITY | (x ^ y) & 0x80000000000000000000000000000000; } else { uint256 ySignifier = uint128 (y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (yExponent == 0) yExponent = 1; else ySignifier |= 0x10000000000000000000000000000; uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0) { if (xSignifier != 0) { uint shift = 226 - mostSignificantBit (xSignifier); xSignifier <<= shift; xExponent = 1; yExponent += shift - 114; } } else { xSignifier = (xSignifier | 0x10000000000000000000000000000) << 114; } xSignifier = xSignifier / ySignifier; if (xSignifier == 0) return (x ^ y) & 0x80000000000000000000000000000000 > 0 ? NEGATIVE_ZERO : POSITIVE_ZERO; assert (xSignifier >= 0x1000000000000000000000000000); uint256 msb = xSignifier >= 0x80000000000000000000000000000 ? mostSignificantBit (xSignifier) : xSignifier >= 0x40000000000000000000000000000 ? 114 : xSignifier >= 0x20000000000000000000000000000 ? 113 : 112; if (xExponent + msb > yExponent + 16497) { // Overflow xExponent = 0x7FFF; xSignifier = 0; } else if (xExponent + msb + 16380 < yExponent) { // Underflow xExponent = 0; xSignifier = 0; } else if (xExponent + msb + 16268 < yExponent) { // Subnormal if (xExponent + 16380 > yExponent) xSignifier <<= xExponent + 16380 - yExponent; else if (xExponent + 16380 < yExponent) xSignifier >>= yExponent - xExponent - 16380; xExponent = 0; } else { // Normal if (msb > 112) xSignifier >>= msb - 112; xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; xExponent = xExponent + msb + 16269 - yExponent; } return bytes16 (uint128 (uint128 ((x ^ y) & 0x80000000000000000000000000000000) | xExponent << 112 | xSignifier)); } } } /** * Calculate -x. * * @param x quadruple precision number * @return quadruple precision number */ function neg (bytes16 x) internal pure returns (bytes16) { unchecked { return x ^ 0x80000000000000000000000000000000; } } /** * Calculate |x|. * * @param x quadruple precision number * @return quadruple precision number */ function abs (bytes16 x) internal pure returns (bytes16) { unchecked { return x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; } } /** * Calculate square root of x. Return NaN on negative x excluding -0. * * @param x quadruple precision number * @return quadruple precision number */ function sqrt (bytes16 x) internal pure returns (bytes16) { unchecked { if (uint128 (x) > 0x80000000000000000000000000000000) return NaN; else { uint256 xExponent = uint128 (x) >> 112 & 0x7FFF; if (xExponent == 0x7FFF) return x; else { uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0) xExponent = 1; else xSignifier |= 0x10000000000000000000000000000; if (xSignifier == 0) return POSITIVE_ZERO; bool oddExponent = xExponent & 0x1 == 0; xExponent = xExponent + 16383 >> 1; if (oddExponent) { if (xSignifier >= 0x10000000000000000000000000000) xSignifier <<= 113; else { uint256 msb = mostSignificantBit (xSignifier); uint256 shift = (226 - msb) & 0xFE; xSignifier <<= shift; xExponent -= shift - 112 >> 1; } } else { if (xSignifier >= 0x10000000000000000000000000000) xSignifier <<= 112; else { uint256 msb = mostSignificantBit (xSignifier); uint256 shift = (225 - msb) & 0xFE; xSignifier <<= shift; xExponent -= shift - 112 >> 1; } } uint256 r = 0x10000000000000000000000000000; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; r = (r + xSignifier / r) >> 1; // Seven iterations should be enough uint256 r1 = xSignifier / r; if (r1 < r) r = r1; return bytes16 (uint128 (xExponent << 112 | r & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF)); } } } } /** * Calculate binary logarithm of x. Return NaN on negative x excluding -0. * * @param x quadruple precision number * @return quadruple precision number */ function log_2 (bytes16 x) internal pure returns (bytes16) { unchecked { if (uint128 (x) > 0x80000000000000000000000000000000) return NaN; else if (x == 0x3FFF0000000000000000000000000000) return POSITIVE_ZERO; else { uint256 xExponent = uint128 (x) >> 112 & 0x7FFF; if (xExponent == 0x7FFF) return x; else { uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0) xExponent = 1; else xSignifier |= 0x10000000000000000000000000000; if (xSignifier == 0) return NEGATIVE_INFINITY; bool resultNegative; uint256 resultExponent = 16495; uint256 resultSignifier; if (xExponent >= 0x3FFF) { resultNegative = false; resultSignifier = xExponent - 0x3FFF; xSignifier <<= 15; } else { resultNegative = true; if (xSignifier >= 0x10000000000000000000000000000) { resultSignifier = 0x3FFE - xExponent; xSignifier <<= 15; } else { uint256 msb = mostSignificantBit (xSignifier); resultSignifier = 16493 - msb; xSignifier <<= 127 - msb; } } if (xSignifier == 0x80000000000000000000000000000000) { if (resultNegative) resultSignifier += 1; uint256 shift = 112 - mostSignificantBit (resultSignifier); resultSignifier <<= shift; resultExponent -= shift; } else { uint256 bb = resultNegative ? 1 : 0; while (resultSignifier < 0x10000000000000000000000000000) { resultSignifier <<= 1; resultExponent -= 1; xSignifier *= xSignifier; uint256 b = xSignifier >> 255; resultSignifier += b ^ bb; xSignifier >>= 127 + b; } } return bytes16 (uint128 ((resultNegative ? 0x80000000000000000000000000000000 : 0) | resultExponent << 112 | resultSignifier & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF)); } } } } /** * Calculate natural logarithm of x. Return NaN on negative x excluding -0. * * @param x quadruple precision number * @return quadruple precision number */ function ln (bytes16 x) internal pure returns (bytes16) { unchecked { return mul (log_2 (x), 0x3FFE62E42FEFA39EF35793C7673007E5); } } /** * Calculate 2^x. * * @param x quadruple precision number * @return quadruple precision number */ function pow_2 (bytes16 x) internal pure returns (bytes16) { unchecked { bool xNegative = uint128 (x) > 0x80000000000000000000000000000000; uint256 xExponent = uint128 (x) >> 112 & 0x7FFF; uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xExponent == 0x7FFF && xSignifier != 0) return NaN; else if (xExponent > 16397) return xNegative ? POSITIVE_ZERO : POSITIVE_INFINITY; else if (xExponent < 16255) return 0x3FFF0000000000000000000000000000; else { if (xExponent == 0) xExponent = 1; else xSignifier |= 0x10000000000000000000000000000; if (xExponent > 16367) xSignifier <<= xExponent - 16367; else if (xExponent < 16367) xSignifier >>= 16367 - xExponent; if (xNegative && xSignifier > 0x406E00000000000000000000000000000000) return POSITIVE_ZERO; if (!xNegative && xSignifier > 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) return POSITIVE_INFINITY; uint256 resultExponent = xSignifier >> 128; xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; if (xNegative && xSignifier != 0) { xSignifier = ~xSignifier; resultExponent += 1; } uint256 resultSignifier = 0x80000000000000000000000000000000; if (xSignifier & 0x80000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128; if (xSignifier & 0x40000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128; if (xSignifier & 0x20000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128; if (xSignifier & 0x10000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10B5586CF9890F6298B92B71842A98363 >> 128; if (xSignifier & 0x8000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1059B0D31585743AE7C548EB68CA417FD >> 128; if (xSignifier & 0x4000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128; if (xSignifier & 0x2000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128; if (xSignifier & 0x1000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128; if (xSignifier & 0x800000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128; if (xSignifier & 0x400000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128; if (xSignifier & 0x200000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100162F3904051FA128BCA9C55C31E5DF >> 128; if (xSignifier & 0x100000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000B175EFFDC76BA38E31671CA939725 >> 128; if (xSignifier & 0x80000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128; if (xSignifier & 0x40000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128; if (xSignifier & 0x20000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000162E525EE054754457D5995292026 >> 128; if (xSignifier & 0x10000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000B17255775C040618BF4A4ADE83FC >> 128; if (xSignifier & 0x8000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128; if (xSignifier & 0x4000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128; if (xSignifier & 0x2000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000162E43F4F831060E02D839A9D16D >> 128; if (xSignifier & 0x1000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000B1721BCFC99D9F890EA06911763 >> 128; if (xSignifier & 0x800000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128; if (xSignifier & 0x400000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128; if (xSignifier & 0x200000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000162E430E5A18F6119E3C02282A5 >> 128; if (xSignifier & 0x100000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000B1721835514B86E6D96EFD1BFE >> 128; if (xSignifier & 0x80000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128; if (xSignifier & 0x40000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000002C5C8601CC6B9E94213C72737A >> 128; if (xSignifier & 0x20000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000162E42FFF037DF38AA2B219F06 >> 128; if (xSignifier & 0x10000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000B17217FBA9C739AA5819F44F9 >> 128; if (xSignifier & 0x8000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128; if (xSignifier & 0x4000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128; if (xSignifier & 0x2000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000162E42FF0999CE3541B9FFFCF >> 128; if (xSignifier & 0x1000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000B17217F80F4EF5AADDA45554 >> 128; if (xSignifier & 0x800000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000058B90BFBF8479BD5A81B51AD >> 128; if (xSignifier & 0x400000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128; if (xSignifier & 0x200000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000162E42FEFB2FED257559BDAA >> 128; if (xSignifier & 0x100000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128; if (xSignifier & 0x80000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128; if (xSignifier & 0x40000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128; if (xSignifier & 0x20000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000162E42FEFA494F1478FDE05 >> 128; if (xSignifier & 0x10000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000B17217F7D20CF927C8E94C >> 128; if (xSignifier & 0x8000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128; if (xSignifier & 0x4000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000002C5C85FDF477B662B26945 >> 128; if (xSignifier & 0x2000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000162E42FEFA3AE53369388C >> 128; if (xSignifier & 0x1000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000B17217F7D1D351A389D40 >> 128; if (xSignifier & 0x800000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128; if (xSignifier & 0x400000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000002C5C85FDF4741BEA6E77E >> 128; if (xSignifier & 0x200000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000162E42FEFA39FE95583C2 >> 128; if (xSignifier & 0x100000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000B17217F7D1CFB72B45E1 >> 128; if (xSignifier & 0x80000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128; if (xSignifier & 0x40000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000002C5C85FDF473E242EA38 >> 128; if (xSignifier & 0x20000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000162E42FEFA39F02B772C >> 128; if (xSignifier & 0x10000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000B17217F7D1CF7D83C1A >> 128; if (xSignifier & 0x8000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128; if (xSignifier & 0x4000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000002C5C85FDF473DEA871F >> 128; if (xSignifier & 0x2000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000162E42FEFA39EF44D91 >> 128; if (xSignifier & 0x1000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000B17217F7D1CF79E949 >> 128; if (xSignifier & 0x800000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000058B90BFBE8E7BCE544 >> 128; if (xSignifier & 0x400000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000002C5C85FDF473DE6ECA >> 128; if (xSignifier & 0x200000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000162E42FEFA39EF366F >> 128; if (xSignifier & 0x100000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000B17217F7D1CF79AFA >> 128; if (xSignifier & 0x80000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000058B90BFBE8E7BCD6D >> 128; if (xSignifier & 0x40000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000002C5C85FDF473DE6B2 >> 128; if (xSignifier & 0x20000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000162E42FEFA39EF358 >> 128; if (xSignifier & 0x10000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000B17217F7D1CF79AB >> 128; if (xSignifier & 0x8000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000058B90BFBE8E7BCD5 >> 128; if (xSignifier & 0x4000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000002C5C85FDF473DE6A >> 128; if (xSignifier & 0x2000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000162E42FEFA39EF34 >> 128; if (xSignifier & 0x1000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000B17217F7D1CF799 >> 128; if (xSignifier & 0x800000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000058B90BFBE8E7BCC >> 128; if (xSignifier & 0x400000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000002C5C85FDF473DE5 >> 128; if (xSignifier & 0x200000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000162E42FEFA39EF2 >> 128; if (xSignifier & 0x100000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000B17217F7D1CF78 >> 128; if (xSignifier & 0x80000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000058B90BFBE8E7BB >> 128; if (xSignifier & 0x40000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000002C5C85FDF473DD >> 128; if (xSignifier & 0x20000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000162E42FEFA39EE >> 128; if (xSignifier & 0x10000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000B17217F7D1CF6 >> 128; if (xSignifier & 0x8000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000058B90BFBE8E7A >> 128; if (xSignifier & 0x4000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000002C5C85FDF473C >> 128; if (xSignifier & 0x2000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000162E42FEFA39D >> 128; if (xSignifier & 0x1000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000B17217F7D1CE >> 128; if (xSignifier & 0x800000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000058B90BFBE8E6 >> 128; if (xSignifier & 0x400000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000002C5C85FDF472 >> 128; if (xSignifier & 0x200000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000162E42FEFA38 >> 128; if (xSignifier & 0x100000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000B17217F7D1B >> 128; if (xSignifier & 0x80000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000058B90BFBE8D >> 128; if (xSignifier & 0x40000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000002C5C85FDF46 >> 128; if (xSignifier & 0x20000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000162E42FEFA2 >> 128; if (xSignifier & 0x10000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000B17217F7D0 >> 128; if (xSignifier & 0x8000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000058B90BFBE7 >> 128; if (xSignifier & 0x4000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000002C5C85FDF3 >> 128; if (xSignifier & 0x2000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000162E42FEF9 >> 128; if (xSignifier & 0x1000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000B17217F7C >> 128; if (xSignifier & 0x800000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000058B90BFBD >> 128; if (xSignifier & 0x400000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000002C5C85FDE >> 128; if (xSignifier & 0x200000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000162E42FEE >> 128; if (xSignifier & 0x100000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000B17217F6 >> 128; if (xSignifier & 0x80000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000058B90BFA >> 128; if (xSignifier & 0x40000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000002C5C85FC >> 128; if (xSignifier & 0x20000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000162E42FD >> 128; if (xSignifier & 0x10000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000B17217E >> 128; if (xSignifier & 0x8000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000058B90BE >> 128; if (xSignifier & 0x4000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000002C5C85E >> 128; if (xSignifier & 0x2000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000162E42E >> 128; if (xSignifier & 0x1000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000B17216 >> 128; if (xSignifier & 0x800000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000058B90A >> 128; if (xSignifier & 0x400000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000002C5C84 >> 128; if (xSignifier & 0x200000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000162E41 >> 128; if (xSignifier & 0x100000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000B1720 >> 128; if (xSignifier & 0x80000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000058B8F >> 128; if (xSignifier & 0x40000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000002C5C7 >> 128; if (xSignifier & 0x20000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000162E3 >> 128; if (xSignifier & 0x10000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000B171 >> 128; if (xSignifier & 0x8000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000058B8 >> 128; if (xSignifier & 0x4000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000002C5B >> 128; if (xSignifier & 0x2000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000162D >> 128; if (xSignifier & 0x1000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000B16 >> 128; if (xSignifier & 0x800 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000058A >> 128; if (xSignifier & 0x400 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000002C4 >> 128; if (xSignifier & 0x200 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000161 >> 128; if (xSignifier & 0x100 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000000B0 >> 128; if (xSignifier & 0x80 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000057 >> 128; if (xSignifier & 0x40 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000002B >> 128; if (xSignifier & 0x20 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000015 >> 128; if (xSignifier & 0x10 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000000A >> 128; if (xSignifier & 0x8 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000004 >> 128; if (xSignifier & 0x4 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000001 >> 128; if (!xNegative) { resultSignifier = resultSignifier >> 15 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; resultExponent += 0x3FFF; } else if (resultExponent <= 0x3FFE) { resultSignifier = resultSignifier >> 15 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; resultExponent = 0x3FFF - resultExponent; } else { resultSignifier = resultSignifier >> resultExponent - 16367; resultExponent = 0; } return bytes16 (uint128 (resultExponent << 112 | resultSignifier)); } } } /** * Calculate e^x. * * @param x quadruple precision number * @return quadruple precision number */ function exp (bytes16 x) internal pure returns (bytes16) { unchecked { return pow_2 (mul (x, 0x3FFF71547652B82FE1777D0FFDA0D23A)); } } /** * Get index of the most significant non-zero bit in binary representation of * x. Reverts if x is zero. * * @return index of the most significant non-zero bit in binary representation * of x */ function mostSignificantBit (uint256 x) private pure returns (uint256) { unchecked { require (x > 0); uint256 result = 0; if (x >= 0x100000000000000000000000000000000) { x >>= 128; result += 128; } if (x >= 0x10000000000000000) { x >>= 64; result += 64; } if (x >= 0x100000000) { x >>= 32; result += 32; } if (x >= 0x10000) { x >>= 16; result += 16; } if (x >= 0x100) { x >>= 8; result += 8; } if (x >= 0x10) { x >>= 4; result += 4; } if (x >= 0x4) { x >>= 2; result += 2; } if (x >= 0x2) result += 1; // No need to shift x anymore return result; } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.7; import "@openzeppelin/contracts/utils/Context.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; /** * @dev Minimal Clones compatible implementation of the {IERC20} interface. * @dev Based Openzeppelin 3.4 ERC20 contract * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20_Cloneable is Context, ERC20, Initializable { uint8 _decimals; string private _name; string private _symbol; address public owner; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor( string memory name_, string memory symbol_, uint8 decimals_ ) ERC20(name_, symbol_) { _decimals = decimals_; } function initialize( address _pool, string memory name_, string memory symbol_, uint8 decimals_ ) external initializer { owner = _pool; _name = name_; _symbol = symbol_; _decimals = decimals_; } function decimals() public view virtual override returns (uint8) { return _decimals; } function name() public view virtual override returns (string memory) { return _name; } function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @notice Transfer ownership. Implemented to help with initializable */ function transferOwnership(address _owner) external onlyOwner { require(_owner != address(0), "Owner: setting to 0 address"); owner = _owner; } modifier onlyOwner() { require(msg.sender == owner, "msg.sender not owner"); _; } }
// SPDX-License-Identifier: MIT 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; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); uint256 currentAllowance = _allowances[sender][_msgSender()]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); unchecked { _approve(sender, _msgSender(), currentAllowance - amount); } return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { uint256 currentAllowance = _allowances[_msgSender()][spender]; require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(_msgSender(), spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `sender` to `recipient`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); uint256 senderBalance = _balances[sender]; require(senderBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[sender] = senderBalance - amount; } _balances[recipient] += amount; emit Transfer(sender, recipient, amount); _afterTokenTransfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; } _totalSupply -= amount; emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
//SPDX-License-Identifier: CC-BY-NC-ND-4.0 pragma solidity 0.8.7; /// @title The manager contract interface for multiple markets and the pools in them interface IPoolKeeper { // #### Events /** * @notice Creates a notification when a pool is created * @param poolAddress The pool address of the newly created pool * @param firstPrice The price of the market oracle when the pool was created */ event PoolAdded(address indexed poolAddress, int256 indexed firstPrice); /** * @notice Creates a notification when a call to LeveragedPool:poolUpkeep is successful * @param pool The pool address being upkept * @param data Extra data about the price fetch. This could be roundID in the case of Chainlink Oracles * @param startPrice The previous price of the pool * @param endPrice The new price of the pool */ event UpkeepSuccessful(address indexed pool, bytes data, int256 indexed startPrice, int256 indexed endPrice); /** * @notice Creates a notification when a keeper is paid for doing upkeep for a pool * @param _pool Address of pool being upkept * @param keeper Keeper to be rewarded for upkeeping * @param reward Keeper's reward (in settlement tokens) */ event KeeperPaid(address indexed _pool, address indexed keeper, uint256 reward); /** * @notice Creates a notification when a keeper's payment for upkeeping a pool failed * @param _pool Address of pool being upkept * @param keeper Keeper to be rewarded for upkeeping * @param expectedReward Keeper's expected reward (in settlement tokens); not actually transferred */ event KeeperPaymentError(address indexed _pool, address indexed keeper, uint256 expectedReward); /** * @notice Creates a notification of a failed pool update * @param pool The pool that failed to update * @param reason The reason for the error */ event PoolUpkeepError(address indexed pool, string reason); // #### Functions function newPool(address _poolAddress) external; function setFactory(address _factory) external; function checkUpkeepSinglePool(address pool) external view returns (bool); function checkUpkeepMultiplePools(address[] calldata pools) external view returns (bool); function performUpkeepSinglePool(address pool) external; function performUpkeepMultiplePools(address[] calldata pools) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./AggregatorInterface.sol"; import "./AggregatorV3Interface.sol"; interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface { }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface AggregatorInterface { function latestAnswer() external view returns ( int256 ); function latestTimestamp() external view returns ( uint256 ); function latestRound() external view returns ( uint256 ); function getAnswer( uint256 roundId ) external view returns ( int256 ); function getTimestamp( uint256 roundId ) external view returns ( uint256 ); event AnswerUpdated( int256 indexed current, uint256 indexed roundId, uint256 updatedAt ); event NewRound( uint256 indexed roundId, address indexed startedBy, uint256 startedAt ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface AggregatorV3Interface { function decimals() external view returns ( uint8 ); function description() external view returns ( string memory ); function version() external view returns ( uint256 ); // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. function getRoundData( uint80 _roundId ) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": { "contracts/implementation/PoolSwapLibrary.sol": { "PoolSwapLibrary": "0x542848e66d8f387a78717be7b39f7259b7782bae" } } }
[{"inputs":[{"internalType":"address","name":"_feeReceiver","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"string","name":"ticker","type":"string"}],"name":"DeployPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"components":[{"internalType":"string","name":"poolName","type":"string"},{"internalType":"uint32","name":"frontRunningInterval","type":"uint32"},{"internalType":"uint32","name":"updateInterval","type":"uint32"},{"internalType":"uint16","name":"leverageAmount","type":"uint16"},{"internalType":"address","name":"quoteToken","type":"address"},{"internalType":"address","name":"oracleWrapper","type":"address"},{"internalType":"address","name":"settlementEthOracle","type":"address"},{"internalType":"uint128","name":"minimumCommitSize","type":"uint128"},{"internalType":"uint128","name":"maximumCommitQueueLength","type":"uint128"}],"internalType":"struct IPoolFactory.PoolDeployment","name":"deploymentParameters","type":"tuple"}],"name":"deployPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isValidPool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLeverage","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numPools","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pairTokenBase","outputs":[{"internalType":"contract PoolToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pairTokenBaseAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolBase","outputs":[{"internalType":"contract LeveragedPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolBaseAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolCommitterDeployer","outputs":[{"internalType":"contract IPoolCommitterDeployer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolKeeper","outputs":[{"internalType":"contract IPoolKeeper","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pools","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeReceiver","type":"address"}],"name":"setFeeReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newMaxLeverage","type":"uint16"}],"name":"setMaxLeverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_poolCommitterDeployer","type":"address"}],"name":"setPoolCommitterDeployer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_poolKeeper","type":"address"}],"name":"setPoolKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60c06040526004805461ffff60a01b1916600560a11b1790553480156200002557600080fd5b5060405162005a9b38038062005a9b833981016040819052620000489162000332565b6200005333620002c6565b6012604051620000639062000316565b60ff9091168152602001604051809103906000f0801580156200008a573d6000803e3d6000fd5b50600180546001600160a01b0319166001600160a01b03831617905560601b6001600160601b031916608052604051620000c49062000324565b604051809103906000f080158015620000e1573d6000803e3d6000fd5b50600280546001600160a01b0319166001600160a01b038316908117909155606091821b6001600160601b03191660a0908152604080516101c0810182523080825260208083018290528284018290529582018190526080820181905292810183905260c08101839052815180830183526009815268109054d157d413d3d360ba1b9581019590955260e0810194909452600f610100850152601e6101208501526000610140850152600161016085015261018084018290526101a08401919091525163554bb62160e01b815263554bb62190620001c4908490600401620003b4565b600060405180830381600087803b158015620001df57600080fd5b505af1158015620001f4573d6000803e3d6000fd5b5050600154604051637b69774360e11b81523060048083019190915260806024830152600a6084830152692120a9a2afaa27a5a2a760b11b60a483015260c0604483015260c4820152634241534560e01b60e4820152601260648201526001600160a01b03909116925063f6d2ee86915061010401600060405180830381600087803b1580156200028457600080fd5b505af115801562000299573d6000803e3d6000fd5b5050600580546001600160a01b0319166001600160a01b0395909516949094179093555062000507915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6112108062001c3083390190565b612c5b8062002e4083390190565b6000602082840312156200034557600080fd5b81516001600160a01b03811681146200035d57600080fd5b9392505050565b6000815180845260005b818110156200038c576020818501810151868301820152016200036e565b818111156200039f576000602083870101525b50601f01601f19169290920160200192915050565b60208152620003cf6020820183516001600160a01b03169052565b60006020830151620003ec60408401826001600160a01b03169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e08301516101c06101008181860152620004766101e086018462000364565b90860151909250610120620004928682018363ffffffff169052565b8601519050610140620004ac8682018363ffffffff169052565b860151610160868101919091528601519050610180620004d18187018361ffff169052565b86015190506101a0620004ee868201836001600160a01b03169052565b909501516001600160a01b031693019290925250919050565b60805160601c60a05160601c6116ef620005416000396000818161030d015261072e0152600081816101ce015261102601526116ef6000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c8063715018a6116100b8578063b3f006741161007c578063b3f00674146102d9578063d723c68b146102ec578063ddca3f43146102ff578063ed3f7e2614610308578063efdcd9741461032f578063f2fde38b1461034257600080fd5b8063715018a61461026f578063893d20e8146102775780638da5cb5b14610277578063ac4afa3814610288578063ae3302c2146102b157600080fd5b80634690092c1161010a5780634690092c146101c9578063568212f6146101f05780635ab78ee1146102035780635bae377a1461023657806367e047561461024957806369fe0e2d1461025c57600080fd5b80630679d36214610147578063178f9e351461015c57806335c62bc21461018c57806340339cbf146101a3578063430ed6eb146101b6575b600080fd5b61015a6101553660046111b1565b610355565b005b60035461016f906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61019560085481565b604051908152602001610183565b61016f6101b136600461114c565b610408565b61015a6101c436600461110b565b610c07565b61016f7f000000000000000000000000000000000000000000000000000000000000000081565b61015a6101fe36600461110b565b610c79565b61022661021136600461110b565b60096020526000908152604090205460ff1681565b6040519015158152602001610183565b60025461016f906001600160a01b031681565b60045461016f906001600160a01b031681565b61015a61026a3660046111d5565b610ceb565b61015a610d1a565b6000546001600160a01b031661016f565b61016f6102963660046111d5565b6007602052600090815260409020546001600160a01b031681565b6004546102c690600160a01b900461ffff1681565b60405161ffff9091168152602001610183565b60055461016f906001600160a01b031681565b60015461016f906001600160a01b031681565b61019560065481565b61016f7f000000000000000000000000000000000000000000000000000000000000000081565b61015a61033d36600461110b565b610d50565b61015a61035036600461110b565b610dc2565b6000546001600160a01b031633146103885760405162461bcd60e51b815260040161037f90611384565b60405180910390fd5b60008161ffff16116103e65760405162461bcd60e51b815260206004820152602160248201527f4d6178696d756d206c65766572616765206d757374206265206e6f6e2d7a65726044820152606f60f81b606482015260840161037f565b6004805461ffff909216600160a01b0261ffff60a01b19909216919091179055565b600080546001600160a01b031633146104635760405162461bcd60e51b815260206004820152601960248201527f6d73672e73656e646572206e6f7420676f7665726e616e636500000000000000604482015260640161037f565b6003546001600160a01b0316806104b15760405162461bcd60e51b8152602060048201526012602482015271141bdbdb12d9595c195c881b9bdd081cd95d60721b604482015260640161037f565b6004546001600160a01b03166105095760405162461bcd60e51b815260206004820152601d60248201527f506f6f6c436f6d6d69747465724465706c6f796572206e6f7420736574000000604482015260640161037f565b6004546000906001600160a01b0316639604198361052e610100870160e08801611188565b61054061012088016101008901611188565b6040516001600160e01b031960e085901b1681526001600160801b03928316600482015291166024820152604401602060405180830381600087803b15801561058857600080fd5b505af115801561059c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c0919061112f565b905060016105d460808601606087016111b1565b61ffff16101580156106065750600454600160a01b900461ffff166105ff60808601606087016111b1565b61ffff1611155b61065e5760405162461bcd60e51b8152602060048201526024808201527f506f6f6c4b65657065723a206c657665726167656420616d6f756e7420696e76604482015263185b1a5960e21b606482015260840161037f565b601261067060a086016080870161110b565b6001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156106a857600080fd5b505afa1580156106bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e09190611214565b60ff1611156107275760405162461bcd60e51b81526020600482015260136024820152720a8ded6cadc40c8cac6d2dac2d8e6407c40627606b1b604482015260640161037f565b60006107527f0000000000000000000000000000000000000000000000000000000000000000610e5d565b9050806001600160a01b0381167fd76cdb035f3aba359cb02087e4c5bd75f911562b407fc3a52ed2bedfb46585b661078a8880611534565b604051610798929190611355565b60405180910390a260006107be6107b56080890160608a016111b1565b61ffff16610ef5565b90506000816107cd8980611534565b6040516020016107df93929190611263565b60408051601f1981840301815291905290506000826107fe8a80611534565b6040516020016108109392919061129b565b60408051601f198184030181529190529050600061083460a08b0160808c0161110b565b6001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561086c57600080fd5b505afa158015610880573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a49190611214565b905060006108b48684858561101e565b905060006108c48786878661101e565b90506000604051806101c001604052806108e66000546001600160a01b031690565b6001600160a01b031681526020018c6001600160a01b031681526020018e60a0016020810190610916919061110b565b6001600160a01b031681526020018e60c0016020810190610937919061110b565b6001600160a01b03168152602001836001600160a01b03168152602001846001600160a01b031681526020018b6001600160a01b03168152602001888f80600001906109839190611534565b604051602001610995939291906112d3565b60405160208183030381529060405281526020018e60200160208101906109bc91906111ee565b63ffffffff1681526020018e60400160208101906109da91906111ee565b63ffffffff16815260200160065481526020018e6060016020810190610a0091906111b1565b61ffff168152602001600560009054906101000a90046001600160a01b03166001600160a01b031681526020018e6080016020810190610a40919061110b565b6001600160a01b03168152509050886001600160a01b031663554bb621826040518263ffffffff1660e01b8152600401610a7a91906113e9565b600060405180830381600087803b158015610a9457600080fd5b505af1158015610aa8573d6000803e3d6000fd5b50505050896001600160a01b031663fd555fb98e6080016020810190610ace919061110b565b6040516001600160e01b031960e084901b1681526001600160a01b039182166004820152908b166024820152604401600060405180830381600087803b158015610b1757600080fd5b505af1158015610b2b573d6000803e3d6000fd5b5050600354604051633c5c7fb360e01b81526001600160a01b038c811660048301529091169250633c5c7fb39150602401600060405180830381600087803b158015610b7657600080fd5b505af1158015610b8a573d6000803e3d6000fd5b505060088054600090815260076020526040812080546001600160a01b0319166001600160a01b038e1617905581546001945091925090610bcc908490611582565b9091555050506001600160a01b0387166000908152600960205260409020805460ff191660011790555094985050505050505050505b919050565b6000546001600160a01b03163314610c315760405162461bcd60e51b815260040161037f90611384565b6001600160a01b038116610c575760405162461bcd60e51b815260040161037f906113b9565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610ca35760405162461bcd60e51b815260040161037f90611384565b6001600160a01b038116610cc95760405162461bcd60e51b815260040161037f906113b9565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610d155760405162461bcd60e51b815260040161037f90611384565b600655565b6000546001600160a01b03163314610d445760405162461bcd60e51b815260040161037f90611384565b610d4e60006110bb565b565b6000546001600160a01b03163314610d7a5760405162461bcd60e51b815260040161037f90611384565b6001600160a01b038116610da05760405162461bcd60e51b815260040161037f906113b9565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610dec5760405162461bcd60e51b815260040161037f90611384565b6001600160a01b038116610e515760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161037f565b610e5a816110bb565b50565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528260601b60148201526e5af43d82803e903d91602b57fd5bf360881b60288201526037816000f09150506001600160a01b038116610c025760405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b604482015260640161037f565b606081610f195750506040805180820190915260018152600360fc1b602082015290565b8160005b8115610f435780610f2d81611647565b9150610f3c9050600a836115bf565b9150610f1d565b60008167ffffffffffffffff811115610f5e57610f5e61168e565b6040519080825280601f01601f191660200182016040528015610f88576020820181803683370190505b509050815b851561101557610f9e600182611600565b90506000610fad600a886115bf565b610fb890600a6115e1565b610fc29088611600565b610fcd90603061159a565b905060008160f81b905080848481518110610fea57610fea611678565b60200101906001600160f81b031916908160001a90535061100c600a896115bf565b97505050610f8d565b50949350505050565b60008061104a7f0000000000000000000000000000000000000000000000000000000000000000610e5d565b604051637b69774360e11b81529091506001600160a01b0382169063f6d2ee869061107f90899089908990899060040161130a565b600060405180830381600087803b15801561109957600080fd5b505af11580156110ad573d6000803e3d6000fd5b509298975050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006020828403121561111d57600080fd5b8135611128816116a4565b9392505050565b60006020828403121561114157600080fd5b8151611128816116a4565b60006020828403121561115e57600080fd5b813567ffffffffffffffff81111561117557600080fd5b8201610120818503121561112857600080fd5b60006020828403121561119a57600080fd5b81356001600160801b038116811461112857600080fd5b6000602082840312156111c357600080fd5b813561ffff8116811461112857600080fd5b6000602082840312156111e757600080fd5b5035919050565b60006020828403121561120057600080fd5b813563ffffffff8116811461112857600080fd5b60006020828403121561122657600080fd5b815160ff8116811461112857600080fd5b6000815180845261124f816020860160208601611617565b601f01601f19169290920160200192915050565b60008451611275818460208901611617565b614c2d60f01b908301908152838560028301376000930160020192835250909392505050565b600084516112ad818460208901611617565b61532d60f01b908301908152838560028301376000930160020192835250909392505050565b600084516112e5818460208901611617565b602d60f81b908301908152838560018301376000930160010192835250909392505050565b6001600160a01b038516815260806020820181905260009061132e90830186611237565b82810360408401526113408186611237565b91505060ff8316606083015295945050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601690820152751859191c995cdcc818d85b9b9bdd081899481b9d5b1b60521b604082015260600190565b602081526114036020820183516001600160a01b03169052565b6000602083015161141f60408401826001600160a01b03169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e08301516101c061010081818601526114a76101e0860184611237565b908601519092506101206114c28682018363ffffffff169052565b86015190506101406114db8682018363ffffffff169052565b8601516101608681019190915286015190506101806114ff8187018361ffff169052565b86015190506101a061151b868201836001600160a01b03169052565b909501516001600160a01b031693019290925250919050565b6000808335601e1984360301811261154b57600080fd5b83018035915067ffffffffffffffff82111561156657600080fd5b60200191503681900382131561157b57600080fd5b9250929050565b6000821982111561159557611595611662565b500190565b600060ff821660ff84168060ff038211156115b7576115b7611662565b019392505050565b6000826115dc57634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156115fb576115fb611662565b500290565b60008282101561161257611612611662565b500390565b60005b8381101561163257818101518382015260200161161a565b83811115611641576000848401525b50505050565b600060001982141561165b5761165b611662565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610e5a57600080fdfea26469706673582212201fae6fbed720990652cf3a5ffc0343c1ecd694a5037b6c5be000ef40f617c45964736f6c6343000807003360806040523480156200001157600080fd5b506040516200121038038062001210833981016040819052620000349162000175565b6040518060400160405280600a8152602001692120a9a2afaa27a5a2a760b11b815250604051806040016040528060048152602001634241534560e01b81525082828281600390805190602001906200008f929190620000cf565b508051620000a5906004906020840190620000cf565b50506005805460ff909316620100000262ff0000199093169290921790915550620001de92505050565b828054620000dd90620001a1565b90600052602060002090601f0160209004810192826200010157600085556200014c565b82601f106200011c57805160ff19168380011785556200014c565b828001600101855582156200014c579182015b828111156200014c5782518255916020019190600101906200012f565b506200015a9291506200015e565b5090565b5b808211156200015a57600081556001016200015f565b6000602082840312156200018857600080fd5b815160ff811681146200019a57600080fd5b9392505050565b600181811c90821680620001b657607f821691505b60208210811415620001d857634e487b7160e01b600052602260045260246000fd5b50919050565b61102280620001ee6000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c806394bf804d11610097578063dd62ed3e11610066578063dd62ed3e14610231578063f2fde38b1461026a578063f6d2ee861461027f578063fcd3533c1461029257600080fd5b806394bf804d146101f057806395d89b4114610203578063a457c2d71461020b578063a9059cbb1461021e57600080fd5b8063313ce567116100d3578063313ce5671461016b578063395093511461018957806370a082311461019c5780638da5cb5b146101c557600080fd5b806306fdde0314610105578063095ea7b31461012357806318160ddd1461014657806323b872dd14610158575b600080fd5b61010d6102a5565b60405161011a9190610ed3565b60405180910390f35b610136610131366004610e86565b610337565b604051901515815260200161011a565b6002545b60405190815260200161011a565b610136610166366004610dbd565b61034d565b60055462010000900460ff1660405160ff909116815260200161011a565b610136610197366004610e86565b6103fc565b61014a6101aa366004610d68565b6001600160a01b031660009081526020819052604090205490565b6008546101d8906001600160a01b031681565b6040516001600160a01b03909116815260200161011a565b6101366101fe366004610eb0565b610438565b61010d61046f565b610136610219366004610e86565b61047e565b61013661022c366004610e86565b610517565b61014a61023f366004610d8a565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b61027d610278366004610d68565b610524565b005b61027d61028d366004610df9565b6105c6565b6101366102a0366004610eb0565b6106d6565b6060600680546102b490610f85565b80601f01602080910402602001604051908101604052809291908181526020018280546102e090610f85565b801561032d5780601f106103025761010080835404028352916020019161032d565b820191906000526020600020905b81548152906001019060200180831161031057829003601f168201915b5050505050905090565b600061034433848461070d565b50600192915050565b600061035a848484610832565b6001600160a01b0384166000908152600160209081526040808320338452909152902054828110156103e45760405162461bcd60e51b815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616044820152676c6c6f77616e636560c01b60648201526084015b60405180910390fd5b6103f1853385840361070d565b506001949350505050565b3360008181526001602090815260408083206001600160a01b03871684529091528120549091610344918590610433908690610f56565b61070d565b6008546000906001600160a01b031633146104655760405162461bcd60e51b81526004016103db90610f28565b6103448284610a01565b6060600780546102b490610f85565b3360009081526001602090815260408083206001600160a01b0386168452909152812054828110156105005760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016103db565b61050d338585840361070d565b5060019392505050565b6000610344338484610832565b6008546001600160a01b0316331461054e5760405162461bcd60e51b81526004016103db90610f28565b6001600160a01b0381166105a45760405162461bcd60e51b815260206004820152601b60248201527f4f776e65723a2073657474696e6720746f20302061646472657373000000000060448201526064016103db565b600880546001600160a01b0319166001600160a01b0392909216919091179055565b600554610100900460ff16806105df575060055460ff16155b6106425760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016103db565b600554610100900460ff16158015610664576005805461ffff19166101011790555b600880546001600160a01b0319166001600160a01b0387161790558351610692906006906020870190610c26565b5082516106a6906007906020860190610c26565b506005805462ff000019166201000060ff85160217905580156106cf576005805461ff00191690555b5050505050565b6008546000906001600160a01b031633146107035760405162461bcd60e51b81526004016103db90610f28565b6103448284610ae0565b6001600160a01b03831661076f5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016103db565b6001600160a01b0382166107d05760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016103db565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b0383166108965760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016103db565b6001600160a01b0382166108f85760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016103db565b6001600160a01b038316600090815260208190526040902054818110156109705760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016103db565b6001600160a01b038085166000908152602081905260408082208585039055918516815290812080548492906109a7908490610f56565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516109f391815260200190565b60405180910390a350505050565b6001600160a01b038216610a575760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016103db565b8060026000828254610a699190610f56565b90915550506001600160a01b03821660009081526020819052604081208054839290610a96908490610f56565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b6001600160a01b038216610b405760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016103db565b6001600160a01b03821660009081526020819052604090205481811015610bb45760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016103db565b6001600160a01b0383166000908152602081905260408120838303905560028054849290610be3908490610f6e565b90915550506040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001610825565b828054610c3290610f85565b90600052602060002090601f016020900481019282610c545760008555610c9a565b82601f10610c6d57805160ff1916838001178555610c9a565b82800160010185558215610c9a579182015b82811115610c9a578251825591602001919060010190610c7f565b50610ca6929150610caa565b5090565b5b80821115610ca65760008155600101610cab565b80356001600160a01b0381168114610cd657600080fd5b919050565b600082601f830112610cec57600080fd5b813567ffffffffffffffff80821115610d0757610d07610fd6565b604051601f8301601f19908116603f01168101908282118183101715610d2f57610d2f610fd6565b81604052838152866020858801011115610d4857600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060208284031215610d7a57600080fd5b610d8382610cbf565b9392505050565b60008060408385031215610d9d57600080fd5b610da683610cbf565b9150610db460208401610cbf565b90509250929050565b600080600060608486031215610dd257600080fd5b610ddb84610cbf565b9250610de960208501610cbf565b9150604084013590509250925092565b60008060008060808587031215610e0f57600080fd5b610e1885610cbf565b9350602085013567ffffffffffffffff80821115610e3557600080fd5b610e4188838901610cdb565b94506040870135915080821115610e5757600080fd5b50610e6487828801610cdb565b925050606085013560ff81168114610e7b57600080fd5b939692955090935050565b60008060408385031215610e9957600080fd5b610ea283610cbf565b946020939093013593505050565b60008060408385031215610ec357600080fd5b82359150610db460208401610cbf565b600060208083528351808285015260005b81811015610f0057858101830151858201604001528201610ee4565b81811115610f12576000604083870101525b50601f01601f1916929092016040019392505050565b60208082526014908201527336b9b39739b2b73232b9103737ba1037bbb732b960611b604082015260600190565b60008219821115610f6957610f69610fc0565b500190565b600082821015610f8057610f80610fc0565b500390565b600181811c90821680610f9957607f821691505b60208210811415610fba57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fdfea26469706673582212207c87cda234a81f67da55383e6777723cd02e3646c72a9ac54ed0abd1942c4c2864736f6c63430008070033608060405234801561001057600080fd5b50612c3b806100206000396000f3fe608060405234801561001057600080fd5b506004361061023d5760003560e01c80637bbf10331161013b578063b9ed8abf116100b8578063ddca3f431161007c578063ddca3f43146104de578063f164e2a7146104f2578063f3466dfa14610506578063f633a7401461051b578063fd2c80ae1461052e57600080fd5b8063b9ed8abf14610489578063ba8d54681461049c578063bbcaac38146104a5578063cd39f30f146104b8578063d38bfff4146104cb57600080fd5b80638456cb59116100ff5780638456cb591461042257806387f9ca5d1461042a5780639fd552451461043d578063ab47c2b314610450578063aced16611461047657600080fd5b80637bbf1033146103d05780637bfe789a146103d85780637de93f93146103fd5780637e71fc7d146104065780638226f3961461040f57600080fd5b80635aa6e675116101c9578063748747e61161018d578063748747e61461036657806375c66e2f14610379578063796da7af1461038c5780637b0a0c90146103a25780637bb98a68146103b557600080fd5b80635aa6e675146102ff5780635c975abb146103125780635d36b190146103365780636d3e313e1461033e5780636dc2b2711461035357600080fd5b80633f4ba83a116102105780633f4ba83a146102ab57806341275358146102b35780634f64b2be146102c6578063554bb621146102d95780635817f0c6146102ec57600080fd5b806304883c2714610242578063217a4b70146102635780633c3f82521461028e5780633d4c485d146102a3575b600080fd5b61024a610546565b60405161025a94939291906129c3565b60405180910390f35b600a54610276906001600160a01b031681565b6040516001600160a01b03909116815260200161025a565b6102a161029c3660046127b9565b6105f9565b005b6102a1610661565b6102a1610771565b600954610276906001600160a01b031681565b6102766102d436600461283b565b6107d3565b6102a16102e73660046127db565b6107f3565b6102a16102fa366004612671565b61117d565b600754610276906001600160a01b031681565b60105461032690600160a81b900460ff1681565b604051901515815260200161025a565b6102a161123e565b61034661137c565b60405161025a9190612989565b610326610361366004612671565b6113c0565b6102a161037436600461261a565b61158a565b6102a1610387366004612878565b611691565b610394611871565b60405190815260200161025a565b6102a16103b0366004612635565b6118f3565b6001546002546040805192835260208301919091520161025a565b610326611a0b565b6003546103e89063ffffffff1681565b60405163ffffffff909116815260200161025a565b610394600c5481565b61039460025481565b600f54610276906001600160a01b031681565b6102a1611a35565b6102a1610438366004612878565b611a9d565b601054610276906001600160a01b031681565b60045461045d9060801b81565b6040516001600160801b0319909116815260200161025a565b600854610276906001600160a01b031681565b600e54610276906001600160a01b031681565b61039460015481565b6102a16104b336600461261a565b611c78565b600b54610276906001600160a01b031681565b6102a16104d936600461261a565b611d74565b60035461045d90600160401b900460801b81565b60105461032690600160a01b900460ff1681565b61050e611e83565b60405161025a91906129ef565b6102a16105293660046127b9565b611f11565b6003546103e890640100000000900463ffffffff1681565b60006060600080600e60009054906101000a90046001600160a01b03166001600160a01b031663db6d8fcf6040518163ffffffff1660e01b815260040160006040518083038186803b15801561059b57600080fd5b505afa1580156105af573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105d79190810190612700565b600c546003549297919650945064010000000090910463ffffffff1692509050565b600b546001600160a01b0316331461062c5760405162461bcd60e51b815260040161062390612a2a565b60405180910390fd5b601054600160a81b900460ff16156106565760405162461bcd60e51b815260040161062390612a02565b600291909155600155565b6007546001600160a01b0316331461068b5760405162461bcd60e51b815260040161062390612a61565b601054600160a81b900460ff166106d35760405162461bcd60e51b815260206004820152600c60248201526b506f6f6c206973206c69766560a01b6044820152606401610623565b600a546040516370a0823160e01b81523060048201526001600160a01b039091169060009082906370a082319060240160206040518083038186803b15801561071b57600080fd5b505afa15801561072f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075391906126e7565b600a5490915061076d906001600160a01b0316338361205b565b5050565b6007546001600160a01b0316331461079b5760405162461bcd60e51b815260040161062390612a61565b6010805460ff60a81b191690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d1693390600090a1565b600581600281106107e357600080fd5b01546001600160a01b0316905081565b600054610100900460ff168061080c575060005460ff16155b61086f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610623565b600054610100900460ff16158015610891576000805461ffff19166101011790555b60006108a56101a08401610180850161261a565b6001600160a01b031614156108fc5760405162461bcd60e51b815260206004820152601f60248201527f46656520616464726573732063616e6e6f7420626520302061646472657373006044820152606401610623565b60006109106101c084016101a0850161261a565b6001600160a01b031614156109675760405162461bcd60e51b815260206004820152601f60248201527f51756f746520746f6b656e2063616e6e6f7420626520302061646472657373006044820152606401610623565b6000610979606084016040850161261a565b6001600160a01b031614156109db5760405162461bcd60e51b815260206004820152602260248201527f4f7261636c6520777261707065722063616e6e6f742062652030206164647265604482015261737360f01b6064820152608401610623565b60006109ed608084016060850161261a565b6001600160a01b03161415610a4e5760405162461bcd60e51b815260206004820152602160248201527f4b6565706572206f7261636c652063616e6e6f742062652030206164647265736044820152607360f81b6064820152608401610623565b6000610a5d602084018461261a565b6001600160a01b03161415610ab45760405162461bcd60e51b815260206004820152601960248201527f4f776e65722063616e6e6f7420626520302061646472657373000000000000006044820152606401610623565b6000610ac6604084016020850161261a565b6001600160a01b03161415610b1d5760405162461bcd60e51b815260206004820152601a60248201527f4b65657065722063616e6e6f74206265203020616464726573730000000000006044820152606401610623565b6000610b2f60a084016080850161261a565b6001600160a01b03161415610b865760405162461bcd60e51b815260206004820152601e60248201527f4c6f6e6720746f6b656e2063616e6e6f742062652030206164647265737300006044820152606401610623565b6000610b9860c0840160a0850161261a565b6001600160a01b03161415610bef5760405162461bcd60e51b815260206004820152601f60248201527f53686f727420746f6b656e2063616e6e6f7420626520302061646472657373006044820152606401610623565b6000610c0160e0840160c0850161261a565b6001600160a01b03161415610c625760405162461bcd60e51b815260206004820152602160248201527f506f6f6c436f6d6d69747465722063616e6e6f742062652030206164647265736044820152607360f81b6064820152608401610623565b610c74610140830161012084016128db565b63ffffffff16610c8c610120840161010085016128db565b63ffffffff1610610cdf5760405162461bcd60e51b815260206004820152601d60248201527f66726f6e7452756e6e696e67203e20757064617465496e74657276616c0000006044820152606401610623565b610cf2670de0b6b3a76400006001612afe565b82610140013510610d335760405162461bcd60e51b815260206004820152600b60248201526a466565203e3d203130302560a81b6044820152606401610623565b610d40602083018361261a565b600780546001600160a01b0319166001600160a01b0392909216919091179055610d70604083016020840161261a565b600880546001600160a01b0319166001600160a01b0392909216919091179055610da0606083016040840161261a565b600e80546001600160a01b0319166001600160a01b0392909216919091179055610dd0608083016060840161261a565b600f80546001600160a01b0319166001600160a01b0392909216919091179055610e026101c083016101a0840161261a565b600a80546001600160a01b0319166001600160a01b0392909216919091179055610e34610120830161010084016128db565b6003805463ffffffff191663ffffffff92909216919091179055610e60610140830161012084016128db565b6003805463ffffffff929092166401000000000267ffffffff0000000019909216919091179055604051636fedf26d60e11b8152610140830135600482015273542848e66d8f387a78717be7b39f7259b7782bae9063dfdbe4da9060240160206040518083038186803b158015610ed657600080fd5b505af4158015610eea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0e91906126bd565b6003805460809290921c600160401b0277ffffffffffffffffffffffffffffffff00000000000000001990921691909117905573542848e66d8f387a78717be7b39f7259b7782bae63dfdbe4da610f6d61018085016101608601612817565b6040516001600160e01b031960e084901b16815261ffff909116600482015260240160206040518083038186803b158015610fa757600080fd5b505af4158015610fbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fdf91906126bd565b600480546001600160801b03191660809290921c91909117905561100b6101a08301610180840161261a565b600980546001600160a01b0319166001600160a01b039290921691909117905542600c5561103c60e0830183612a98565b61104891600d91612547565b5061105960a083016080840161261a565b600560000180546001600160a01b0319166001600160a01b039290921691909117905561108c60c0830160a0840161261a565b600560010180546001600160a01b0319166001600160a01b03929092169190911790556110bf60e0830160c0840161261a565b600b80546001600160a01b0319166001600160a01b03929092169190911790556110ef60c0830160a0840161261a565b6001600160a01b031661110860a084016080850161261a565b6001600160a01b03167fbc8bd61e5dd69ff5cb8c389529c029503515ba368eaafbdaa406e072fdd360726111446101c086016101a0870161261a565b61115160e0870187612a98565b60405161116093929190612949565b60405180910390a3801561076d576000805461ff00191690555050565b600b546001600160a01b031633146111a75760405162461bcd60e51b815260040161062390612a2a565b601054600160a81b900460ff16156111d15760405162461bcd60e51b815260040161062390612a02565b6001600160a01b0382166112275760405162461bcd60e51b815260206004820152601e60248201527f546f20616464726573732063616e6e6f742062652030206164647265737300006044820152606401610623565b600a5461076d906001600160a01b0316838361205b565b601054600160a81b900460ff16156112685760405162461bcd60e51b815260040161062390612a02565b601054600160a01b900460ff166112c15760405162461bcd60e51b815260206004820152601b60248201527f4e6f20676f7665726e616e6365206368616e67652061637469766500000000006044820152606401610623565b6010546001600160a01b0316331461131b5760405162461bcd60e51b815260206004820152601860248201527f4e6f742070726f766973696f6e616c20676f7665726e6f7200000000000000006044820152606401610623565b60078054601080546001600160a01b038082166001600160a01b03198516811790955560ff60a01b199091169091556040519116919082907f023588d3d1dcaad34e471c9e01b616b794156174bc693539c8fe15c0bfd5d82690600090a350565b6113846125cb565b60408051808201918290529060059060029082845b81546001600160a01b03168152600190910190602001808311611399575050505050905090565b6008546000906001600160a01b031633146114155760405162461bcd60e51b815260206004820152601560248201527436b9b39739b2b73232b9103737ba1035b2b2b832b960591b6044820152606401610623565b601054600160a81b900460ff161561143f5760405162461bcd60e51b815260040161062390612a02565b6001600160a01b03831661149f5760405162461bcd60e51b815260206004820152602160248201527f52656365697069656e7420616464726573732063616e6e6f74206265206e756c6044820152601b60fa1b6064820152608401610623565b6001546002546114af8183612ae6565b84106114c057600092505050611584565b60405163dc35bc1360e01b8152600481018590526024810183905260448101829052600090819073542848e66d8f387a78717be7b39f7259b7782bae9063dc35bc1390606401604080518083038186803b15801561151d57600080fd5b505af4158015611531573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115559190612854565b60018290556002819055600a54919350915061157b906001600160a01b0316888861205b565b60019450505050505b92915050565b6007546001600160a01b031633146115b45760405162461bcd60e51b815260040161062390612a61565b601054600160a81b900460ff16156115de5760405162461bcd60e51b815260040161062390612a02565b6001600160a01b03811661163f5760405162461bcd60e51b815260206004820152602260248201527f4b656570657220616464726573732063616e6e6f742062652030206164647265604482015261737360f01b6064820152608401610623565b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f402b3f9a8de3e388e7653c7a5892204fe18b579c8c23db19d6e00f1043ceb92190600090a35050565b600b546001600160a01b031633146116bb5760405162461bcd60e51b815260040161062390612a2a565b601054600160a81b900460ff16156116e55760405162461bcd60e51b815260040161062390612a02565b6001600160a01b0381166117465760405162461bcd60e51b815260206004820152602260248201527f4d696e74657220616464726573732063616e6e6f742062652030206164647265604482015261737360f01b6064820152608401610623565b8215806117535750826001145b61179a5760405162461bcd60e51b8152602060048201526018602482015277506f6f6c3a20746f6b656e206f7574206f662072616e676560401b6044820152606401610623565b600583600281106117ad576117ad612bd9565b01546040516394bf804d60e01b8152600481018490526001600160a01b038381166024830152909116906394bf804d90604401602060405180830381600087803b1580156117fa57600080fd5b505af115801561180e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611832919061269b565b61186c5760405162461bcd60e51b815260206004820152600b60248201526a135a5b9d0819985a5b195960aa1b6044820152606401610623565b505050565b600e5460408051634c6afee560e11b815290516000926001600160a01b0316916398d5fdca916004808301926020929190829003018186803b1580156118b657600080fd5b505afa1580156118ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ee91906126e7565b905090565b600b546001600160a01b0316331461191d5760405162461bcd60e51b815260040161062390612a2a565b601054600160a81b900460ff16156119475760405162461bcd60e51b815260040161062390612a02565b6001600160a01b03831661199d5760405162461bcd60e51b815260206004820181905260248201527f46726f6d20616464726573732063616e6e6f74206265203020616464726573736044820152606401610623565b6001600160a01b0382166119f35760405162461bcd60e51b815260206004820152601e60248201527f546f20616464726573732063616e6e6f742062652030206164647265737300006044820152606401610623565b600a5461186c906001600160a01b03168484846120be565b600354600c54600091611a2d9164010000000090910463ffffffff1690612ae6565b421015905090565b6007546001600160a01b03163314611a5f5760405162461bcd60e51b815260040161062390612a61565b6010805460ff60a81b1916600160a81b1790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e75290600090a1565b600b546001600160a01b03163314611ac75760405162461bcd60e51b815260040161062390612a2a565b601054600160a81b900460ff1615611af15760405162461bcd60e51b815260040161062390612a02565b6001600160a01b038116611b525760405162461bcd60e51b815260206004820152602260248201527f4275726e657220616464726573732063616e6e6f742062652030206164647265604482015261737360f01b6064820152608401610623565b821580611b5f5750826001145b611ba65760405162461bcd60e51b8152602060048201526018602482015277506f6f6c3a20746f6b656e206f7574206f662072616e676560401b6044820152606401610623565b60058360028110611bb957611bb9612bd9565b0154604051633f34d4cf60e21b8152600481018490526001600160a01b0383811660248301529091169063fcd3533c90604401602060405180830381600087803b158015611c0657600080fd5b505af1158015611c1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c3e919061269b565b61186c5760405162461bcd60e51b815260206004820152600b60248201526a109d5c9b8819985a5b195960aa1b6044820152606401610623565b6007546001600160a01b03163314611ca25760405162461bcd60e51b815260040161062390612a61565b601054600160a81b900460ff1615611ccc5760405162461bcd60e51b815260040161062390612a02565b6001600160a01b038116611d225760405162461bcd60e51b815260206004820152601b60248201527f4163636f756e742063616e6e6f742062652030206164647265737300000000006044820152606401610623565b600980546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f11f35a22548bcd4c3788ab4a7e4fba427a2014f02e5d5e2da9af62212c03183f90600090a35050565b6007546001600160a01b03163314611d9e5760405162461bcd60e51b815260040161062390612a61565b601054600160a81b900460ff1615611dc85760405162461bcd60e51b815260040161062390612a02565b6001600160a01b038116611e2d5760405162461bcd60e51b815260206004820152602660248201527f476f7665726e616e636520616464726573732063616e6e6f742062652030206160448201526564647265737360d01b6064820152608401610623565b601080546001600160a81b0319166001600160a01b0380841691909117600160a01b17918290556040519116907f35681f4f23137fb58510a9854f1b6e95f90a2cf0b66d2fce4df74cc0becc82d590600090a250565b600d8054611e9090612b88565b80601f0160208091040260200160405190810160405280929190818152602001828054611ebc90612b88565b8015611f095780601f10611ede57610100808354040283529160200191611f09565b820191906000526020600020905b815481529060010190602001808311611eec57829003601f168201915b505050505081565b6008546001600160a01b03163314611f635760405162461bcd60e51b815260206004820152601560248201527436b9b39739b2b73232b9103737ba1035b2b2b832b960591b6044820152606401610623565b601054600160a81b900460ff1615611f8d5760405162461bcd60e51b815260040161062390612a02565b611f95611a0b565b611fe15760405162461bcd60e51b815260206004820152601d60248201527f55706461746520696e74657276616c206861736e2774207061737365640000006044820152606401610623565b611feb82826120fc565b600b60009054906101000a90046001600160a01b03166001600160a01b0316631c536da46040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561203b57600080fd5b505af115801561204f573d6000803e3d6000fd5b505042600c5550505050565b6040516001600160a01b03831660248201526044810182905261186c90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526122fb565b6040516001600160a01b03808516602483015283166044820152606481018290526120f69085906323b872dd60e01b90608401612087565b50505050565b601054600160a81b900460ff16156121265760405162461bcd60e51b815260040161062390612a02565b600082131580612137575060008113155b1561216d57604051819083907f27f70c863f1bd3e335bb4d6bf2a31075c861752f0b21a03b816a356035b1dec690600090a35050565b6001546002546040805160c0810182528581526020810185815281830184815260608301868152600480546001600160801b0319608091821b8116828801908152600354600160401b900490921b811660a088019081529751632920706d60e21b815287519381019390935294516024830152925160448201529051606482015290518216608482015292511660a4830152906000908190819073542848e66d8f387a78717be7b39f7259b7782bae9063a481c1b49060c40160606040518083038186803b15801561223e57600080fd5b505af4158015612252573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061227691906128ad565b919450925090507f3a4a53e86baa9b577f931e849a3472fd6be844c0916377bc806be891847a5c2b6122a88784612b1d565b6122b28786612b1d565b6040805192835260208301919091520160405180910390a160028390556001829055600954600a546122f1916001600160a01b0391821691168361205b565b5050505050505050565b6000612350826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166123cd9092919063ffffffff16565b80519091501561186c578080602001905181019061236e919061269b565b61186c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610623565b60606123dc84846000856123e6565b90505b9392505050565b6060824710156124475760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610623565b843b6124955760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610623565b600080866001600160a01b031685876040516124b1919061292d565b60006040518083038185875af1925050503d80600081146124ee576040519150601f19603f3d011682016040523d82523d6000602084013e6124f3565b606091505b509150915061250382828661250e565b979650505050505050565b6060831561251d5750816123df565b82511561252d5782518084602001fd5b8160405162461bcd60e51b815260040161062391906129ef565b82805461255390612b88565b90600052602060002090601f01602090048101928261257557600085556125bb565b82601f1061258e5782800160ff198235161785556125bb565b828001600101855582156125bb579182015b828111156125bb5782358255916020019190600101906125a0565b506125c79291506125e9565b5090565b60405180604001604052806002906020820280368337509192915050565b5b808211156125c757600081556001016125ea565b80356001600160a01b038116811461261557600080fd5b919050565b60006020828403121561262c57600080fd5b6123df826125fe565b60008060006060848603121561264a57600080fd5b612653846125fe565b9250612661602085016125fe565b9150604084013590509250925092565b6000806040838503121561268457600080fd5b61268d836125fe565b946020939093013593505050565b6000602082840312156126ad57600080fd5b815180151581146123df57600080fd5b6000602082840312156126cf57600080fd5b81516001600160801b0319811681146123df57600080fd5b6000602082840312156126f957600080fd5b5051919050565b6000806040838503121561271357600080fd5b82519150602083015167ffffffffffffffff8082111561273257600080fd5b818501915085601f83011261274657600080fd5b81518181111561275857612758612bef565b604051601f8201601f19908116603f0116810190838211818310171561278057612780612bef565b8160405282815288602084870101111561279957600080fd5b6127aa836020830160208801612b5c565b80955050505050509250929050565b600080604083850312156127cc57600080fd5b50508035926020909101359150565b6000602082840312156127ed57600080fd5b813567ffffffffffffffff81111561280457600080fd5b82016101c081850312156123df57600080fd5b60006020828403121561282957600080fd5b813561ffff811681146123df57600080fd5b60006020828403121561284d57600080fd5b5035919050565b6000806040838503121561286757600080fd5b505080516020909101519092909150565b60008060006060848603121561288d57600080fd5b83359250602084013591506128a4604085016125fe565b90509250925092565b6000806000606084860312156128c257600080fd5b8351925060208401519150604084015190509250925092565b6000602082840312156128ed57600080fd5b813563ffffffff811681146123df57600080fd5b60008151808452612919816020860160208601612b5c565b601f01601f19169290920160200192915050565b6000825161293f818460208701612b5c565b9190910192915050565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b60408101818360005b60028110156129ba5781516001600160a01b0316835260209283019290910190600101612992565b50505092915050565b8481526080602082015260006129dc6080830186612901565b6040830194909452506060015292915050565b6020815260006123df6020830184612901565b6020808252600e908201526d141bdbdb081a5cc81c185d5cd95960921b604082015260600190565b6020808252601c908201527f6d73672e73656e646572206e6f7420706f6f6c436f6d6d697474657200000000604082015260600190565b60208082526019908201527f6d73672e73656e646572206e6f7420676f7665726e616e636500000000000000604082015260600190565b6000808335601e19843603018112612aaf57600080fd5b83018035915067ffffffffffffffff821115612aca57600080fd5b602001915036819003821315612adf57600080fd5b9250929050565b60008219821115612af957612af9612bc3565b500190565b6000816000190483118215151615612b1857612b18612bc3565b500290565b60008083128015600160ff1b850184121615612b3b57612b3b612bc3565b6001600160ff1b0384018313811615612b5657612b56612bc3565b50500390565b60005b83811015612b77578181015183820152602001612b5f565b838111156120f65750506000910152565b600181811c90821680612b9c57607f821691505b60208210811415612bbd57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfea264697066735822122069e0fd0f8969da041d0035e73ee854f756fe9bd42cda2186ad3cf2a3bfce859864736f6c634300080700330000000000000000000000000f79e82ae88e1318b8cfc8b4a205fe2f982b928a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000f79e82ae88e1318b8cfc8b4a205fe2f982b928a
-----Decoded View---------------
Arg [0] : _feeReceiver (address): 0x0f79e82ae88e1318b8cfc8b4a205fe2f982b928a
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000f79e82ae88e1318b8cfc8b4a205fe2f982b928a
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.