Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
PerpetualManagerFront
Compiler Version
v0.8.7+commit.e28d00a7
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "./PerpetualManager.sol"; /// @title PerpetualManagerFront /// @author Angle Core Team /// @notice `PerpetualManager` is the contract handling all the Hedging Agents perpetuals /// @dev There is one `PerpetualManager` contract per pair stablecoin/collateral in the protocol /// @dev This file contains the functions of the `PerpetualManager` that can be directly interacted /// with by external agents. These functions are the ones that need to be called to open, modify or close /// perpetuals /// @dev `PerpetualManager` naturally handles staking, the code allowing HAs to stake has been inspired from /// https://github.com/SetProtocol/index-coop-contracts/blob/master/contracts/staking/StakingRewardsV2.sol /// @dev Perpetuals at Angle protocol are treated as NFTs, this contract handles the logic for that contract PerpetualManagerFront is PerpetualManager, IPerpetualManagerFront { using SafeERC20 for IERC20; using CountersUpgradeable for CountersUpgradeable.Counter; // =============================== Deployer ==================================== /// @notice Initializes the `PerpetualManager` contract /// @param poolManager_ Reference to the `PoolManager` contract handling the collateral associated to the `PerpetualManager` /// @param rewardToken_ Reference to the `rewardtoken` that can be distributed to HAs as they have open positions /// @dev The reward token is most likely going to be the ANGLE token /// @dev Since this contract is upgradeable, this function is an `initialize` and not a `constructor` /// @dev Zero checks are only performed on addresses for which no external calls are made, in this case just /// the `rewardToken_` is checked /// @dev After initializing this contract, all the fee parameters should be initialized by governance using /// the setters in this contract function initialize(IPoolManager poolManager_, IERC20 rewardToken_) external initializer zeroCheck(address(rewardToken_)) { // Initializing contracts __Pausable_init(); __AccessControl_init(); // Creating references poolManager = poolManager_; _token = IERC20(poolManager_.token()); _stableMaster = IStableMaster(poolManager_.stableMaster()); rewardToken = rewardToken_; _collatBase = 10**(IERC20Metadata(address(_token)).decimals()); // The references to the `feeManager` and to the `oracle` contracts are to be set when the contract is deployed // Setting up Access Control for this contract // There is no need to store the reference to the `PoolManager` address here // Once the `POOLMANAGER_ROLE` has been granted, no new addresses can be granted or revoked // from this role: a `PerpetualManager` contract can only have one `PoolManager` associated _setupRole(POOLMANAGER_ROLE, address(poolManager)); // `PoolManager` is admin of all the roles. Most of the time, changes are propagated from it _setRoleAdmin(GUARDIAN_ROLE, POOLMANAGER_ROLE); _setRoleAdmin(POOLMANAGER_ROLE, POOLMANAGER_ROLE); // Pausing the contract because it is not functional till the collateral has really been deployed by the // `StableMaster` _pause(); } /// @custom:oz-upgrades-unsafe-allow constructor constructor() initializer {} // ================================= HAs ======================================= /// @notice Lets a HA join the protocol and create a perpetual /// @param owner Address of the future owner of the perpetual /// @param margin Amount of collateral brought by the HA /// @param committedAmount Amount of collateral covered by the HA /// @param maxOracleRate Maximum oracle value that the HA wants to see stored in the perpetual /// @param minNetMargin Minimum net margin that the HA is willing to see stored in the perpetual /// @return perpetualID The ID of the perpetual opened by this HA /// @dev The future owner of the perpetual cannot be the zero address /// @dev It is possible to open a perpetual on behalf of someone else /// @dev The `maxOracleRate` parameter serves as a protection against oracle manipulations for HAs opening perpetuals /// @dev `minNetMargin` is a protection against too big variations in the fees for HAs function openPerpetual( address owner, uint256 margin, uint256 committedAmount, uint256 maxOracleRate, uint256 minNetMargin ) external override whenNotPaused zeroCheck(owner) returns (uint256 perpetualID) { // Transaction will revert anyway if `margin` is zero require(committedAmount > 0, "27"); // There could be a reentrancy attack as a call to an external contract is done before state variables // updates. Yet in this case, the call involves a transfer from the `msg.sender` to the contract which // eliminates the risk _token.safeTransferFrom(msg.sender, address(poolManager), margin); // Computing the oracle value // Only the highest oracle value (between Chainlink and Uniswap) we get is stored in the perpetual (, uint256 rateUp) = _getOraclePrice(); // Checking if the oracle rate is not too big: a too big oracle rate could mean for a HA that the price // has become too high to make it interesting to open a perpetual require(rateUp <= maxOracleRate, "28"); // Computing the total amount of stablecoins that this perpetual is going to hedge for the protocol uint256 totalHedgeAmountUpdate = (committedAmount * rateUp) / _collatBase; // Computing the net amount brought by the HAs to store in the perpetual uint256 netMargin = _getNetMargin(margin, totalHedgeAmountUpdate, committedAmount); require(netMargin >= minNetMargin, "29"); // Checking if the perpetual is not too leveraged, even after computing the fees require((committedAmount * BASE_PARAMS) <= maxLeverage * netMargin, "30"); // ERC721 logic _perpetualIDcount.increment(); perpetualID = _perpetualIDcount.current(); // In the logic of the staking contract, the `_updateReward` should be called // before the perpetual is opened _updateReward(perpetualID, 0); // Updating the total amount of stablecoins hedged by HAs and creating the perpetual totalHedgeAmount += totalHedgeAmountUpdate; perpetualData[perpetualID] = Perpetual(rateUp, block.timestamp, netMargin, committedAmount); // Following ERC721 logic, the function `_mint(...)` calls `_checkOnERC721Received` and could then be used as // a reentrancy vector. Minting should then only be done at the very end after updating all variables. _mint(owner, perpetualID); emit PerpetualOpened(perpetualID, rateUp, netMargin, committedAmount); } /// @notice Lets a HA close a perpetual owned or controlled for the stablecoin/collateral pair associated /// to this `PerpetualManager` contract /// @param perpetualID ID of the perpetual to close /// @param to Address which will receive the proceeds from this perpetual /// @param minCashOutAmount Minimum net cash out amount that the HA is willing to get for closing the /// perpetual /// @dev The HA gets the current amount of her position depending on the entry oracle value /// and current oracle value minus some transaction fees computed on the committed amount /// @dev `msg.sender` should be the owner of `perpetualID` or be approved for this perpetual /// @dev If the `PoolManager` does not have enough collateral, the perpetual owner will be converted to a SLP and /// receive sanTokens /// @dev The `minCashOutAmount` serves as a protection for HAs closing their perpetuals: it protects them both /// from fees that would have become too high and from a too big decrease in oracle value function closePerpetual( uint256 perpetualID, address to, uint256 minCashOutAmount ) external override whenNotPaused onlyApprovedOrOwner(msg.sender, perpetualID) { // Loading perpetual data and getting the oracle price Perpetual memory perpetual = perpetualData[perpetualID]; (uint256 rateDown, ) = _getOraclePrice(); // The lowest oracle price between Chainlink and Uniswap is used to compute the perpetual's position at // the time of closing: it is the one that is most at the advantage of the protocol (uint256 cashOutAmount, uint256 liquidated) = _checkLiquidation(perpetualID, perpetual, rateDown); if (liquidated == 0) { // You need to wait `lockTime` before being able to withdraw funds from the protocol as a HA require(perpetual.entryTimestamp + lockTime <= block.timestamp, "31"); // Cashing out the perpetual internally _closePerpetual(perpetualID, perpetual); // Computing exit fees: they depend on how much is already hedgeded by HAs compared with what's to hedge (uint256 netCashOutAmount, ) = _getNetCashOutAmount( cashOutAmount, perpetual.committedAmount, // The perpetual has already been cashed out when calling this function, so there is no // `committedAmount` to add to the `totalHedgeAmount` to get the `currentHedgeAmount` _computeHedgeRatio(totalHedgeAmount) ); require(netCashOutAmount >= minCashOutAmount, "32"); emit PerpetualClosed(perpetualID, netCashOutAmount); _secureTransfer(to, netCashOutAmount); } } /// @notice Lets a HA increase the `margin` in a perpetual she controls for this /// stablecoin/collateral pair /// @param perpetualID ID of the perpetual to which amount should be added to `margin` /// @param amount Amount to add to the perpetual's `margin` /// @dev This decreases the leverage multiple of this perpetual /// @dev If this perpetual is to be liquidated, the HA is not going to be able to add liquidity to it /// @dev Since this function can be used to add liquidity to a perpetual, there is no need to restrict /// it to the owner of the perpetual /// @dev Calling this function on a non-existing perpetual makes it revert function addToPerpetual(uint256 perpetualID, uint256 amount) external override whenNotPaused { // Loading perpetual data and getting the oracle price Perpetual memory perpetual = perpetualData[perpetualID]; (uint256 rateDown, ) = _getOraclePrice(); (, uint256 liquidated) = _checkLiquidation(perpetualID, perpetual, rateDown); if (liquidated == 0) { // Overflow check _token.safeTransferFrom(msg.sender, address(poolManager), amount); perpetualData[perpetualID].margin += amount; emit PerpetualUpdated(perpetualID, perpetual.margin + amount); } } /// @notice Lets a HA decrease the `margin` in a perpetual she controls for this /// stablecoin/collateral pair /// @param perpetualID ID of the perpetual from which collateral should be removed /// @param amount Amount to remove from the perpetual's `margin` /// @param to Address which will receive the collateral removed from this perpetual /// @dev This increases the leverage multiple of this perpetual /// @dev `msg.sender` should be the owner of `perpetualID` or be approved for this perpetual function removeFromPerpetual( uint256 perpetualID, uint256 amount, address to ) external override whenNotPaused onlyApprovedOrOwner(msg.sender, perpetualID) { // Loading perpetual data and getting the oracle price Perpetual memory perpetual = perpetualData[perpetualID]; (uint256 rateDown, ) = _getOraclePrice(); (uint256 cashOutAmount, uint256 liquidated) = _checkLiquidation(perpetualID, perpetual, rateDown); if (liquidated == 0) { // Checking if money can be withdrawn from the perpetual require( // The perpetual should not have been opened too soon (perpetual.entryTimestamp + lockTime <= block.timestamp) && // The amount to withdraw should not be more important than the perpetual's `cashOutAmount` and `margin` (amount < cashOutAmount) && (amount < perpetual.margin) && // Withdrawing collateral should not make the leverage of the perpetual too important // Checking both on `cashOutAmount` and `perpetual.margin` (as we can have either // `cashOutAmount >= perpetual.margin` or `cashOutAmount<perpetual.margin`) // No checks are done on `maintenanceMargin`, as conditions on `maxLeverage` are more restrictive perpetual.committedAmount * BASE_PARAMS <= (cashOutAmount - amount) * maxLeverage && perpetual.committedAmount * BASE_PARAMS <= (perpetual.margin - amount) * maxLeverage, "33" ); perpetualData[perpetualID].margin -= amount; emit PerpetualUpdated(perpetualID, perpetual.margin - amount); _secureTransfer(to, amount); } } /// @notice Allows an outside caller to liquidate perpetuals if their margin ratio is /// under the maintenance margin /// @param perpetualIDs ID of the targeted perpetuals /// @dev Liquidation of a perpetual will succeed if the `cashOutAmount` of the perpetual is under the maintenance margin, /// and nothing will happen if the perpetual is still healthy /// @dev The outside caller (namely a keeper) gets a portion of the leftover cash out amount of the perpetual /// @dev As keepers may directly profit from this function, there may be front-running problems with miners bots, /// we may have to put an access control logic for this function to only allow white-listed addresses to act /// as keepers for the protocol function liquidatePerpetuals(uint256[] memory perpetualIDs) external override whenNotPaused { // Getting the oracle price (uint256 rateDown, ) = _getOraclePrice(); uint256 liquidationFees; for (uint256 i = 0; i < perpetualIDs.length; i++) { uint256 perpetualID = perpetualIDs[i]; if (_exists(perpetualID)) { // Loading perpetual data Perpetual memory perpetual = perpetualData[perpetualID]; (uint256 cashOutAmount, uint256 liquidated) = _checkLiquidation(perpetualID, perpetual, rateDown); if (liquidated == 1) { // Computing the incentive for the keeper as a function of the `cashOutAmount` of the perpetual // This incentivizes keepers to react fast when the price starts to go below the liquidation // margin liquidationFees += _computeKeeperLiquidationFees(cashOutAmount); } } } emit KeeperTransferred(msg.sender, liquidationFees); _secureTransfer(msg.sender, liquidationFees); } /// @notice Allows an outside caller to close perpetuals if too much of the collateral from /// users is hedged by HAs /// @param perpetualIDs IDs of the targeted perpetuals /// @dev This function allows to make sure that the protocol will not have too much HAs for a long period of time /// @dev A HA that owns a targeted perpetual will get the current value of her perpetual /// @dev The call to the function above will revert if HAs cannot be cashed out /// @dev As keepers may directly profit from this function, there may be front-running problems with miners bots, /// we may have to put an access control logic for this function to only allow white-listed addresses to act /// as keepers for the protocol function forceClosePerpetuals(uint256[] memory perpetualIDs) external override whenNotPaused { // Getting the oracle prices // `rateUp` is used to compute the cost of manipulation of the covered amounts (uint256 rateDown, uint256 rateUp) = _getOraclePrice(); // Fetching `stocksUsers` to check if perpetuals cover too much collateral uint256 stocksUsers = _stableMaster.getStocksUsers(); uint256 targetHedgeAmount = (stocksUsers * targetHAHedge) / BASE_PARAMS; // `totalHedgeAmount` should be greater than the limit hedge amount require(totalHedgeAmount > (stocksUsers * limitHAHedge) / BASE_PARAMS, "34"); uint256 liquidationFees; uint256 cashOutFees; // Array of pairs `(owner, netCashOutAmount)` Pairs[] memory outputPairs = new Pairs[](perpetualIDs.length); for (uint256 i = 0; i < perpetualIDs.length; i++) { uint256 perpetualID = perpetualIDs[i]; address owner = _owners[perpetualID]; if (owner != address(0)) { // Loading perpetual data and getting the oracle price Perpetual memory perpetual = perpetualData[perpetualID]; // First checking if the perpetual should not be liquidated (uint256 cashOutAmount, uint256 liquidated) = _checkLiquidation(perpetualID, perpetual, rateDown); if (liquidated == 1) { // This results in the perpetual being liquidated and the keeper being paid the same amount of fees as // what would have been paid if the perpetual had been liquidated using the `liquidatePerpetualFunction` // Computing the incentive for the keeper as a function of the `cashOutAmount` of the perpetual // This incentivizes keepers to react fast liquidationFees += _computeKeeperLiquidationFees(cashOutAmount); } else if (perpetual.entryTimestamp + lockTime <= block.timestamp) { // It is impossible to force the closing a perpetual that was just created: in the other case, this // function could be used to do some insider trading and to bypass the `lockTime` limit // If too much collateral is hedged by HAs, then the perpetual can be cashed out _closePerpetual(perpetualID, perpetual); uint64 ratioPostCashOut; // In this situation, `totalHedgeAmount` is the `currentHedgeAmount` if (targetHedgeAmount > totalHedgeAmount) { ratioPostCashOut = uint64((totalHedgeAmount * BASE_PARAMS) / targetHedgeAmount); } else { ratioPostCashOut = uint64(BASE_PARAMS); } // Computing how much the HA will get and the amount of fees paid at closing (uint256 netCashOutAmount, uint256 fees) = _getNetCashOutAmount( cashOutAmount, perpetual.committedAmount, ratioPostCashOut ); cashOutFees += fees; // Storing the owners of perpetuals that were forced cash out in a memory array to avoid // reentrancy attacks outputPairs[i] = Pairs(owner, netCashOutAmount); } // Checking if at this point enough perpetuals have been cashed out if (totalHedgeAmount <= targetHedgeAmount) break; } } uint64 ratio = (targetHedgeAmount == 0) ? 0 : uint64((totalHedgeAmount * BASE_PARAMS) / (2 * targetHedgeAmount)); // Computing the rewards given to the keeper calling this function // and transferring the rewards to the keeper // Using a cache value of `cashOutFees` to save some gas // The value below is the amount of fees that should go to the keeper forcing the closing of perpetuals // In the linear by part function, if `xKeeperFeesClosing` is greater than 0.5 (meaning we are not at target yet) // then keepers should get almost no fees cashOutFees = (cashOutFees * _piecewiseLinear(ratio, xKeeperFeesClosing, yKeeperFeesClosing)) / BASE_PARAMS; // The amount of fees that can go to keepers is capped by a parameter set by governance cashOutFees = cashOutFees < keeperFeesClosingCap ? cashOutFees : keeperFeesClosingCap; // A malicious attacker could take advantage of this function to take a flash loan, burn agTokens // to diminish the stocks users and then force close some perpetuals. We also need to check that assuming // really small burn transaction fees (of 0.05%), an attacker could make a profit with such flash loan // if current hedge is below the target hedge by making such flash loan. // The formula for the cost of such flash loan is: // `fees * (limitHAHedge - targetHAHedge) * stocksUsers / oracle` // In order to avoid doing multiplications after divisions, and to get everything in the correct base, we do: uint256 estimatedCost = (5 * (limitHAHedge - targetHAHedge) * stocksUsers * _collatBase) / (rateUp * 10000 * BASE_PARAMS); cashOutFees = cashOutFees < estimatedCost ? cashOutFees : estimatedCost; emit PerpetualsForceClosed(perpetualIDs, outputPairs, msg.sender, cashOutFees + liquidationFees); // Processing transfers after all calculations have been performed for (uint256 j = 0; j < perpetualIDs.length; j++) { if (outputPairs[j].netCashOutAmount > 0) { _secureTransfer(outputPairs[j].owner, outputPairs[j].netCashOutAmount); } } _secureTransfer(msg.sender, cashOutFees + liquidationFees); } // =========================== External View Function ========================== /// @notice Returns the `cashOutAmount` of the perpetual owned by someone at a given oracle value /// @param perpetualID ID of the perpetual /// @param rate Oracle value /// @return The `cashOutAmount` of the perpetual /// @return Whether the position of the perpetual is now too small compared with its initial position and should hence /// be liquidated /// @dev This function is used by the Collateral Settlement contract function getCashOutAmount(uint256 perpetualID, uint256 rate) external view override returns (uint256, uint256) { Perpetual memory perpetual = perpetualData[perpetualID]; return _getCashOutAmount(perpetual, rate); } // =========================== Reward Distribution ============================= /// @notice Allows to check the amount of reward tokens earned by a perpetual /// @param perpetualID ID of the perpetual to check function earned(uint256 perpetualID) external view returns (uint256) { return _earned(perpetualID, perpetualData[perpetualID].committedAmount * perpetualData[perpetualID].entryRate); } /// @notice Allows a perpetual owner to withdraw rewards /// @param perpetualID ID of the perpetual which accumulated tokens function getReward(uint256 perpetualID) external whenNotPaused { require(_exists(perpetualID), "2"); _getReward(perpetualID, perpetualData[perpetualID].committedAmount * perpetualData[perpetualID].entryRate); } // =============================== ERC721 logic ================================ /// @notice Gets the name of the NFT collection implemented by this contract function name() external pure override returns (string memory) { return "AnglePerp"; } /// @notice Gets the symbol of the NFT collection implemented by this contract function symbol() external pure override returns (string memory) { return "AnglePerp"; } /// @notice Gets the URI containing metadata /// @param perpetualID ID of the perpetual function tokenURI(uint256 perpetualID) external view override returns (string memory) { require(_exists(perpetualID), "2"); // There is no perpetual with `perpetualID` equal to 0, so the following variable is // always greater than zero uint256 temp = perpetualID; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (perpetualID != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(perpetualID % 10))); perpetualID /= 10; } return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, string(buffer))) : ""; } /// @notice Gets the balance of an owner /// @param owner Address of the owner /// @dev Balance here represents the number of perpetuals owned by a HA function balanceOf(address owner) external view override returns (uint256) { require(owner != address(0), "0"); return _balances[owner]; } /// @notice Gets the owner of the perpetual with ID perpetualID /// @param perpetualID ID of the perpetual function ownerOf(uint256 perpetualID) external view override returns (address) { return _ownerOf(perpetualID); } /// @notice Approves to an address specified by `to` a perpetual specified by `perpetualID` /// @param to Address to approve the perpetual to /// @param perpetualID ID of the perpetual /// @dev The approved address will have the right to transfer the perpetual, to cash it out /// on behalf of the owner, to add or remove collateral in it and to choose the destination /// address that will be able to receive the proceeds of the perpetual function approve(address to, uint256 perpetualID) external override { address owner = _ownerOf(perpetualID); require(to != owner, "35"); require(msg.sender == owner || isApprovedForAll(owner, msg.sender), "21"); _approve(to, perpetualID); } /// @notice Gets the approved address by a perpetual owner /// @param perpetualID ID of the concerned perpetual function getApproved(uint256 perpetualID) external view override returns (address) { require(_exists(perpetualID), "2"); return _getApproved(perpetualID); } /// @notice Sets approval on all perpetuals owned by the owner to an operator /// @param operator Address to approve (or block) on all perpetuals /// @param approved Whether the sender wants to approve or block the operator function setApprovalForAll(address operator, bool approved) external override { require(operator != msg.sender, "36"); _operatorApprovals[msg.sender][operator] = approved; emit ApprovalForAll(_msgSender(), operator, approved); } /// @notice Gets if the operator address is approved on all perpetuals by the owner /// @param owner Owner of perpetuals /// @param operator Address to check if approved function isApprovedForAll(address owner, address operator) public view override returns (bool) { return _operatorApprovals[owner][operator]; } /// @notice Gets if the sender address is approved for the perpetualId /// @param perpetualID ID of the perpetual function isApprovedOrOwner(address spender, uint256 perpetualID) external view override returns (bool) { return _isApprovedOrOwner(spender, perpetualID); } /// @notice Transfers the `perpetualID` from an address to another /// @param from Source address /// @param to Destination a address /// @param perpetualID ID of the perpetual to transfer function transferFrom( address from, address to, uint256 perpetualID ) external override onlyApprovedOrOwner(msg.sender, perpetualID) { _transfer(from, to, perpetualID); } /// @notice Safely transfers the `perpetualID` from an address to another without data in it /// @param from Source address /// @param to Destination a address /// @param perpetualID ID of the perpetual to transfer function safeTransferFrom( address from, address to, uint256 perpetualID ) external override { safeTransferFrom(from, to, perpetualID, ""); } /// @notice Safely transfers the `perpetualID` from an address to another with data in the transfer /// @param from Source address /// @param to Destination a address /// @param perpetualID ID of the perpetual to transfer function safeTransferFrom( address from, address to, uint256 perpetualID, bytes memory _data ) public override onlyApprovedOrOwner(msg.sender, perpetualID) { _safeTransfer(from, to, perpetualID, _data); } // =============================== ERC165 logic ================================ /// @notice Queries if a contract implements an interface /// @param interfaceId The interface identifier, as specified in ERC-165 /// @dev Interface identification is specified in ERC-165. This function uses less than 30,000 gas. /// Required by the ERC721 standard, so used to check that the IERC721 is implemented. /// @return `true` if the contract implements `interfaceID` and /// `interfaceID` is not 0xffffffff, `false` otherwise function supportsInterface(bytes4 interfaceId) external pure override(IERC165) returns (bool) { return interfaceId == type(IPerpetualManagerFront).interfaceId || interfaceId == type(IPerpetualManagerFunctions).interfaceId || interfaceId == type(IStakingRewards).interfaceId || interfaceId == type(IStakingRewardsFunctions).interfaceId || interfaceId == type(IAccessControl).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "./PerpetualManagerInternal.sol"; /// @title PerpetualManager /// @author Angle Core Team /// @notice `PerpetualManager` is the contract handling all the Hedging Agents positions and perpetuals /// @dev There is one `PerpetualManager` contract per pair stablecoin/collateral in the protocol /// @dev This file contains the functions of the `PerpetualManager` that can be interacted with /// by `StableMaster`, by the `PoolManager`, by the `FeeManager` and by governance contract PerpetualManager is PerpetualManagerInternal, IPerpetualManagerFunctions, IStakingRewardsFunctions, AccessControlUpgradeable, PausableUpgradeable { using SafeERC20 for IERC20; /// @notice Role for guardians, governors and `StableMaster` /// Made for the `StableMaster` to be able to update some parameters bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE"); /// @notice Role for `PoolManager` only bytes32 public constant POOLMANAGER_ROLE = keccak256("POOLMANAGER_ROLE"); // ============================== Modifiers ==================================== /// @notice Checks if the person interacting with the perpetual with `perpetualID` is approved /// @param caller Address of the person seeking to interact with the perpetual /// @param perpetualID ID of the concerned perpetual /// @dev Generally in `PerpetualManager`, perpetual owners should store the ID of the perpetuals /// they are able to interact with modifier onlyApprovedOrOwner(address caller, uint256 perpetualID) { require(_isApprovedOrOwner(caller, perpetualID), "21"); _; } /// @notice Checks if the message sender is the rewards distribution address modifier onlyRewardsDistribution() { require(msg.sender == rewardsDistribution, "1"); _; } // =============================== Deployer ==================================== /// @notice Notifies the address of the `_feeManager` and of the `oracle` /// to this contract and grants the correct roles /// @param governorList List of governor addresses of the protocol /// @param guardian Address of the guardian of the protocol /// @param feeManager_ Reference to the `FeeManager` contract which will be able to update fees /// @param oracle_ Reference to the `oracle` contract which will be able to update fees /// @dev Called by the `PoolManager` contract when it is activated by the `StableMaster` /// @dev The `governorList` and `guardian` here are those of the `Core` contract function deployCollateral( address[] memory governorList, address guardian, IFeeManager feeManager_, IOracle oracle_ ) external override onlyRole(POOLMANAGER_ROLE) { for (uint256 i = 0; i < governorList.length; i++) { _grantRole(GUARDIAN_ROLE, governorList[i]); } // In the end guardian should be revoked by governance _grantRole(GUARDIAN_ROLE, guardian); _grantRole(GUARDIAN_ROLE, address(_stableMaster)); _feeManager = feeManager_; oracle = oracle_; } // ========================== Rewards Distribution ============================= /// @notice Notifies the contract that rewards are going to be shared among HAs of this pool /// @param reward Amount of governance tokens to be distributed to HAs /// @dev Only the reward distributor contract is allowed to call this function which starts a staking cycle /// @dev This function is the equivalent of the `notifyRewardAmount` function found in all staking contracts function notifyRewardAmount(uint256 reward) external override onlyRewardsDistribution { rewardPerTokenStored = _rewardPerToken(); if (block.timestamp >= periodFinish) { // If the period is not done, then the reward rate changes rewardRate = reward / rewardsDuration; } else { uint256 remaining = periodFinish - block.timestamp; uint256 leftover = remaining * rewardRate; // If the period is not over, we compute the reward left and increase reward duration rewardRate = (reward + leftover) / rewardsDuration; } // Ensuring the provided reward amount is not more than the balance in the contract. // This keeps the reward rate in the right range, preventing overflows due to // very high values of `rewardRate` in the earned and `rewardsPerToken` functions; // Reward + leftover must be less than 2^256 / 10^18 to avoid overflow. uint256 balance = rewardToken.balanceOf(address(this)); require(rewardRate <= balance / rewardsDuration, "22"); lastUpdateTime = block.timestamp; // Change the duration periodFinish = block.timestamp + rewardsDuration; emit RewardAdded(reward); } /// @notice Supports recovering LP Rewards from other systems such as BAL to be distributed to holders /// or tokens that were mistakenly /// @param tokenAddress Address of the token to transfer /// @param to Address to give tokens to /// @param tokenAmount Amount of tokens to transfer function recoverERC20( address tokenAddress, address to, uint256 tokenAmount ) external override onlyRewardsDistribution { require(tokenAddress != address(rewardToken), "20"); IERC20(tokenAddress).safeTransfer(to, tokenAmount); emit Recovered(tokenAddress, to, tokenAmount); } /// @notice Changes the `rewardsDistribution` associated to this contract /// @param _rewardsDistribution Address of the new rewards distributor contract /// @dev This function is part of the staking rewards interface and it is used to propagate /// a change of rewards distributor notified by the current `rewardsDistribution` address /// @dev It has already been checked in the `RewardsDistributor` contract calling /// this function that the `newRewardsDistributor` had a compatible reward token /// @dev With this function, everything is as if `rewardsDistribution` was admin of its own role function setNewRewardsDistribution(address _rewardsDistribution) external override onlyRewardsDistribution { rewardsDistribution = _rewardsDistribution; emit RewardsDistributionUpdated(_rewardsDistribution); } // ================================= Keepers =================================== /// @notice Updates all the fees not depending on individual HA conditions via keeper utils functions /// @param feeDeposit New deposit global fees /// @param feeWithdraw New withdraw global fees /// @dev Governance may decide to incorporate a collateral ratio dependence in the fees for HAs, /// in this case it will be done through the `FeeManager` contract /// @dev This dependence can either be a bonus or a malus function setFeeKeeper(uint64 feeDeposit, uint64 feeWithdraw) external override { require(msg.sender == address(_feeManager), "1"); haBonusMalusDeposit = feeDeposit; haBonusMalusWithdraw = feeWithdraw; } // ======== Governance - Guardian Functions - Staking and Pauses =============== /// @notice Pauses the `getReward` method as well as the functions allowing to open, modify or close perpetuals /// @dev After calling this function, it is going to be impossible for HAs to interact with their perpetuals /// or claim their rewards on it function pause() external override onlyRole(GUARDIAN_ROLE) { _pause(); } /// @notice Unpauses HAs functions function unpause() external override onlyRole(GUARDIAN_ROLE) { _unpause(); } /// @notice Sets the conditions and specifies the duration of the reward distribution /// @param _rewardsDuration Duration for the rewards for this contract /// @param _rewardsDistribution Address which will give the reward tokens /// @dev It allows governance to directly change the rewards distribution contract and the conditions /// at which this distribution is done /// @dev The compatibility of the reward token is not checked here: it is checked /// in the rewards distribution contract when activating this as a staking contract, /// so if a reward distributor is set here but does not have a compatible reward token, then this reward /// distributor will not be able to set this contract as a staking contract function setRewardDistribution(uint256 _rewardsDuration, address _rewardsDistribution) external onlyRole(GUARDIAN_ROLE) zeroCheck(_rewardsDistribution) { rewardsDuration = _rewardsDuration; rewardsDistribution = _rewardsDistribution; emit RewardsDistributionDurationUpdated(rewardsDuration, rewardsDistribution); } // ============ Governance - Guardian Functions - Parameters =================== /// @notice Sets `baseURI` that is the URI to access ERC721 metadata /// @param _baseURI New `baseURI` parameter function setBaseURI(string memory _baseURI) external onlyRole(GUARDIAN_ROLE) { baseURI = _baseURI; emit BaseURIUpdated(_baseURI); } /// @notice Sets `lockTime` that is the minimum amount of time HAs have to stay within the protocol /// @param _lockTime New `lockTime` parameter /// @dev This parameter is used to prevent HAs from exiting before a certain amount of time and taking advantage /// of insiders' information they may have due to oracle latency function setLockTime(uint64 _lockTime) external override onlyRole(GUARDIAN_ROLE) { lockTime = _lockTime; emit LockTimeUpdated(_lockTime); } /// @notice Changes the maximum leverage authorized (commit/margin) and the maintenance margin under which /// perpetuals can be liquidated /// @param _maxLeverage New value of the maximum leverage allowed /// @param _maintenanceMargin The new maintenance margin /// @dev For a perpetual, the leverage is defined as the ratio between the committed amount and the margin /// @dev For a perpetual, the maintenance margin is defined as the ratio between the margin ratio / the committed amount function setBoundsPerpetual(uint64 _maxLeverage, uint64 _maintenanceMargin) external override onlyRole(GUARDIAN_ROLE) onlyCompatibleFees(_maintenanceMargin) { // Checking the compatibility of the parameters require(BASE_PARAMS**2 > _maxLeverage * _maintenanceMargin, "8"); maxLeverage = _maxLeverage; maintenanceMargin = _maintenanceMargin; emit BoundsPerpetualUpdated(_maxLeverage, _maintenanceMargin); } /// @notice Sets `xHAFees` that is the thresholds of values of the ratio between what's covered (hedged) /// divided by what's to hedge with HAs at which fees will change as well as /// `yHAFees` that is the value of the deposit or withdraw fees at threshold /// @param _xHAFees Array of the x-axis value for the fees (deposit or withdraw) /// @param _yHAFees Array of the y-axis value for the fees (deposit or withdraw) /// @param deposit Whether deposit or withdraw fees should be updated /// @dev Evolution of the fees is linear between two values of thresholds /// @dev These x values should be ranked in ascending order /// @dev For deposit fees, the higher the x that is the ratio between what's to hedge and what's hedged /// the higher y should be (the more expensive it should be for HAs to come in) /// @dev For withdraw fees, evolution should follow an opposite logic function setHAFees( uint64[] memory _xHAFees, uint64[] memory _yHAFees, uint8 deposit ) external override onlyRole(GUARDIAN_ROLE) onlyCompatibleInputArrays(_xHAFees, _yHAFees) { if (deposit == 1) { xHAFeesDeposit = _xHAFees; yHAFeesDeposit = _yHAFees; } else { xHAFeesWithdraw = _xHAFees; yHAFeesWithdraw = _yHAFees; } emit HAFeesUpdated(_xHAFees, _yHAFees, deposit); } /// @notice Sets the target and limit proportions of collateral from users that can be insured by HAs /// @param _targetHAHedge Proportion of collateral from users that HAs should hedge /// @param _limitHAHedge Proportion of collateral from users above which HAs can see their perpetuals /// cashed out /// @dev `targetHAHedge` equal to `BASE_PARAMS` means that all the collateral from users should be insured by HAs /// @dev `targetHAHedge` equal to 0 means HA should not cover (hedge) anything function setTargetAndLimitHAHedge(uint64 _targetHAHedge, uint64 _limitHAHedge) external override onlyRole(GUARDIAN_ROLE) onlyCompatibleFees(_targetHAHedge) onlyCompatibleFees(_limitHAHedge) { require(_targetHAHedge <= _limitHAHedge, "8"); limitHAHedge = _limitHAHedge; targetHAHedge = _targetHAHedge; // Updating the value in the `stableMaster` contract _stableMaster.setTargetHAHedge(_targetHAHedge); emit TargetAndLimitHAHedgeUpdated(_targetHAHedge, _limitHAHedge); } /// @notice Sets the portion of the leftover cash out amount of liquidated perpetuals that go to keepers /// @param _keeperFeesLiquidationRatio Proportion to keepers /// @dev This proportion should be inferior to `BASE_PARAMS` function setKeeperFeesLiquidationRatio(uint64 _keeperFeesLiquidationRatio) external override onlyRole(GUARDIAN_ROLE) onlyCompatibleFees(_keeperFeesLiquidationRatio) { keeperFeesLiquidationRatio = _keeperFeesLiquidationRatio; emit KeeperFeesLiquidationRatioUpdated(keeperFeesLiquidationRatio); } /// @notice Sets the maximum amounts going to the keepers when closing perpetuals /// because too much was hedged by HAs or when liquidating a perpetual /// @param _keeperFeesLiquidationCap Maximum reward going to the keeper liquidating a perpetual /// @param _keeperFeesClosingCap Maximum reward going to the keeper forcing the closing of an ensemble /// of perpetuals function setKeeperFeesCap(uint256 _keeperFeesLiquidationCap, uint256 _keeperFeesClosingCap) external override onlyRole(GUARDIAN_ROLE) { keeperFeesLiquidationCap = _keeperFeesLiquidationCap; keeperFeesClosingCap = _keeperFeesClosingCap; emit KeeperFeesCapUpdated(keeperFeesLiquidationCap, keeperFeesClosingCap); } /// @notice Sets the x-array (ie thresholds) for `FeeManager` when closing perpetuals and the y-array that is the /// value of the proportions of the fees going to keepers closing perpetuals /// @param _xKeeperFeesClosing Thresholds for closing fees /// @param _yKeeperFeesClosing Value of the fees at the different threshold values specified in `xKeeperFeesClosing` /// @dev The x thresholds correspond to values of the hedge ratio divided by two /// @dev `xKeeperFeesClosing` and `yKeeperFeesClosing` should have the same length function setKeeperFeesClosing(uint64[] memory _xKeeperFeesClosing, uint64[] memory _yKeeperFeesClosing) external override onlyRole(GUARDIAN_ROLE) onlyCompatibleInputArrays(_xKeeperFeesClosing, _yKeeperFeesClosing) { xKeeperFeesClosing = _xKeeperFeesClosing; yKeeperFeesClosing = _yKeeperFeesClosing; emit KeeperFeesClosingUpdated(xKeeperFeesClosing, yKeeperFeesClosing); } // ================ Governance - `PoolManager` Functions ======================= /// @notice Changes the reference to the `FeeManager` contract /// @param feeManager_ New `FeeManager` contract /// @dev This allows the `PoolManager` contract to propagate changes to the `PerpetualManager` /// @dev This is the only place where the `_feeManager` can be changed, it is as if there was /// a `FEEMANAGER_ROLE` for which `PoolManager` was the admin function setFeeManager(IFeeManager feeManager_) external override onlyRole(POOLMANAGER_ROLE) { _feeManager = feeManager_; } // ======================= `StableMaster` Function ============================= /// @notice Changes the oracle contract used to compute collateral price with respect to the stablecoin's price /// @param oracle_ Oracle contract /// @dev The collateral `PoolManager` does not store a reference to an oracle, the value of the oracle /// is hence directly set by the `StableMaster` function setOracle(IOracle oracle_) external override { require(msg.sender == address(_stableMaster), "1"); oracle = oracle_; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "./PerpetualManagerStorage.sol"; /// @title PerpetualManagerInternal /// @author Angle Core Team /// @notice `PerpetualManager` is the contract handling all the Hedging Agents perpetuals /// @dev There is one `PerpetualManager` contract per pair stablecoin/collateral in the protocol /// @dev This file contains all the internal functions of the `PerpetualManager` contract contract PerpetualManagerInternal is PerpetualManagerStorage { using Address for address; using SafeERC20 for IERC20; // ======================== State Modifying Functions ========================== /// @notice Cashes out a perpetual, which means that it simply deletes the references to the perpetual /// in the contract /// @param perpetualID ID of the perpetual /// @param perpetual Data of the perpetual function _closePerpetual(uint256 perpetualID, Perpetual memory perpetual) internal { // Handling the staking logic // Reward should always be updated before the `totalHedgeAmount` // Rewards are distributed to the perpetual which is liquidated uint256 hedge = perpetual.committedAmount * perpetual.entryRate; _getReward(perpetualID, hedge); delete perpetualRewardPerTokenPaid[perpetualID]; // Updating `totalHedgeAmount` to represent the fact that less money is insured totalHedgeAmount -= hedge / _collatBase; _burn(perpetualID); } /// @notice Allows the protocol to transfer collateral to an address while handling the case where there are /// not enough reserves /// @param owner Address of the receiver /// @param amount The amount of collateral sent /// @dev If there is not enough collateral in balance (this can happen when money has been lent to strategies), /// then the owner is reimbursed by receiving what is missing in sanTokens at the correct value function _secureTransfer(address owner, uint256 amount) internal { uint256 curBalance = poolManager.getBalance(); if (curBalance >= amount && amount > 0) { // Case where there is enough in reserves to reimburse the person _token.safeTransferFrom(address(poolManager), owner, amount); } else if (amount > 0) { // When there is not enough to reimburse the entire amount, the protocol reimburses // what it can using its reserves and the rest is paid in sanTokens at the current // exchange rate uint256 amountLeft = amount - curBalance; _token.safeTransferFrom(address(poolManager), owner, curBalance); _stableMaster.convertToSLP(amountLeft, owner); } } /// @notice Checks whether the perpetual should be liquidated or not, and if so liquidates the perpetual /// @param perpetualID ID of the perpetual to check and potentially liquidate /// @param perpetual Data of the perpetual to check /// @param rateDown Oracle value to compute the cash out amount of the perpetual /// @return Cash out amount of the perpetual /// @return Whether the perpetual was liquidated or not /// @dev Generally, to check for the liquidation of a perpetual, we use the lowest oracle value possible: /// it's the one that is most at the advantage of the protocol, hence the `rateDown` parameter function _checkLiquidation( uint256 perpetualID, Perpetual memory perpetual, uint256 rateDown ) internal returns (uint256, uint256) { uint256 liquidated; (uint256 cashOutAmount, uint256 reachMaintenanceMargin) = _getCashOutAmount(perpetual, rateDown); if (cashOutAmount == 0 || reachMaintenanceMargin == 1) { _closePerpetual(perpetualID, perpetual); // No need for an event to find out that a perpetual is liquidated liquidated = 1; } return (cashOutAmount, liquidated); } // ========================= Internal View Functions =========================== /// @notice Gets the current cash out amount of a perpetual /// @param perpetual Data of the concerned perpetual /// @param rate Value of the oracle /// @return cashOutAmount Amount that the HA could get by closing this perpetual /// @return reachMaintenanceMargin Whether the position of the perpetual is now too small /// compared with its initial position /// @dev Refer to the whitepaper or the doc for the formulas of the cash out amount /// @dev The notion of `maintenanceMargin` is standard in centralized platforms offering perpetual futures function _getCashOutAmount(Perpetual memory perpetual, uint256 rate) internal view returns (uint256 cashOutAmount, uint256 reachMaintenanceMargin) { // All these computations are made just because we are working with uint and not int // so we cannot do x-y if x<y uint256 newCommit = (perpetual.committedAmount * perpetual.entryRate) / rate; // Checking if a liquidation is needed: for this to happen the `cashOutAmount` should be inferior // to the maintenance margin of the perpetual reachMaintenanceMargin; if (newCommit >= perpetual.committedAmount + perpetual.margin) cashOutAmount = 0; else { // The definition of the margin ratio is `(margin + PnL) / committedAmount` // where `PnL = commit * (1-entryRate/currentRate)` // So here: `newCashOutAmount = margin + PnL` cashOutAmount = perpetual.committedAmount + perpetual.margin - newCommit; if (cashOutAmount * BASE_PARAMS <= perpetual.committedAmount * maintenanceMargin) reachMaintenanceMargin = 1; } } /// @notice Calls the oracle to read both Chainlink and Uniswap rates /// @return The lowest oracle value (between Chainlink and Uniswap) is the first outputted value /// @return The highest oracle value is the second output /// @dev If the oracle only involves a single oracle fees (like just Chainlink for USD-EUR), /// the same value is returned twice function _getOraclePrice() internal view returns (uint256, uint256) { return oracle.readAll(); } /// @notice Computes the incentive for the keeper as a function of the cash out amount of a liquidated perpetual /// which value falls below its maintenance margin /// @param cashOutAmount Value remaining in the perpetual /// @dev By computing keeper fees as a fraction of the cash out amount of a perpetual rather than as a fraction /// of the `committedAmount`, keepers are incentivized to react fast when a perpetual is below the maintenance margin /// @dev Perpetual exchange protocols typically compute liquidation fees using an equivalent of the `committedAmount`, /// this is not the case here function _computeKeeperLiquidationFees(uint256 cashOutAmount) internal view returns (uint256 keeperFees) { keeperFees = (cashOutAmount * keeperFeesLiquidationRatio) / BASE_PARAMS; keeperFees = keeperFees < keeperFeesLiquidationCap ? keeperFees : keeperFeesLiquidationCap; } /// @notice Gets the value of the hedge ratio that is the ratio between the amount currently hedged by HAs /// and the target amount that should be hedged by them /// @param currentHedgeAmount Amount currently covered by HAs /// @return ratio Ratio between the amount of collateral (in stablecoin value) currently hedged /// and the target amount to hedge function _computeHedgeRatio(uint256 currentHedgeAmount) internal view returns (uint64 ratio) { // Fetching info from the `StableMaster`: the amount to hedge is based on the `stocksUsers` // of the given collateral uint256 targetHedgeAmount = (_stableMaster.getStocksUsers() * targetHAHedge) / BASE_PARAMS; if (currentHedgeAmount < targetHedgeAmount) ratio = uint64((currentHedgeAmount * BASE_PARAMS) / targetHedgeAmount); else ratio = uint64(BASE_PARAMS); } // =========================== Fee Computation ================================= /// @notice Gets the net margin corrected from the fees at perpetual opening /// @param margin Amount brought in the perpetual at creation /// @param totalHedgeAmountUpdate Amount of stablecoins that this perpetual is going to insure /// @param committedAmount Committed amount in the perpetual, we need it to compute the fees /// paid by the HA /// @return netMargin Amount that will be written in the perpetual as the `margin` /// @dev The amount of stablecoins insured by a perpetual is `committedAmount * oracleRate / _collatBase` function _getNetMargin( uint256 margin, uint256 totalHedgeAmountUpdate, uint256 committedAmount ) internal view returns (uint256 netMargin) { // Checking if the HA has the right to open a perpetual with such amount // If HAs hedge more than the target amount, then new HAs will not be able to create perpetuals // The amount hedged by HAs after opening the perpetual is going to be: uint64 ratio = _computeHedgeRatio(totalHedgeAmount + totalHedgeAmountUpdate); require(ratio < uint64(BASE_PARAMS), "25"); // Computing the net margin of HAs to store in the perpetual: it consists simply in deducing fees // Those depend on how much is already hedged by HAs compared with what's to hedge uint256 haFeesDeposit = (haBonusMalusDeposit * _piecewiseLinear(ratio, xHAFeesDeposit, yHAFeesDeposit)) / BASE_PARAMS; // Fees are rounded to the advantage of the protocol haFeesDeposit = committedAmount - (committedAmount * (BASE_PARAMS - haFeesDeposit)) / BASE_PARAMS; // Fees are computed based on the committed amount of the perpetual // The following reverts if fees are too big compared to the margin netMargin = margin - haFeesDeposit; } /// @notice Gets the net amount to give to a HA (corrected from the fees) in case of a perpetual closing /// @param committedAmount Committed amount in the perpetual /// @param cashOutAmount The current cash out amount of the perpetual /// @param ratio What's hedged divided by what's to hedge /// @return netCashOutAmount Amount that will be distributed to the HA /// @return feesPaid Amount of fees paid by the HA at perpetual closing /// @dev This function is called by the `closePerpetual` and by the `forceClosePerpetuals` /// function /// @dev The amount of fees paid by the HA is used to compute the incentive given to HAs closing perpetuals /// when too much is covered function _getNetCashOutAmount( uint256 cashOutAmount, uint256 committedAmount, uint64 ratio ) internal view returns (uint256 netCashOutAmount, uint256 feesPaid) { feesPaid = (haBonusMalusWithdraw * _piecewiseLinear(ratio, xHAFeesWithdraw, yHAFeesWithdraw)) / BASE_PARAMS; // Rounding the fees at the protocol's advantage feesPaid = committedAmount - (committedAmount * (BASE_PARAMS - feesPaid)) / BASE_PARAMS; if (feesPaid >= cashOutAmount) { netCashOutAmount = 0; feesPaid = cashOutAmount; } else { netCashOutAmount = cashOutAmount - feesPaid; } } // ========================= Reward Distribution =============================== /// @notice View function to query the last timestamp at which a reward was distributed /// @return Current timestamp if a reward is being distributed or the last timestamp function _lastTimeRewardApplicable() internal view returns (uint256) { uint256 returnValue = block.timestamp < periodFinish ? block.timestamp : periodFinish; return returnValue; } /// @notice Used to actualize the `rewardPerTokenStored` /// @dev It adds to the reward per token: the time elapsed since the `rewardPerTokenStored` /// was last updated multiplied by the `rewardRate` divided by the number of tokens /// @dev Specific attention should be placed on the base here: `rewardRate` is in the base of the reward token /// and `totalHedgeAmount` is in `BASE_TOKENS` here: as this function concerns an amount of reward /// tokens, the output of this function should be in the base of the reward token too function _rewardPerToken() internal view returns (uint256) { if (totalHedgeAmount == 0) { return rewardPerTokenStored; } return rewardPerTokenStored + ((_lastTimeRewardApplicable() - lastUpdateTime) * rewardRate * BASE_TOKENS) / totalHedgeAmount; } /// @notice Allows a perpetual owner to withdraw rewards /// @param perpetualID ID of the perpetual which accumulated tokens /// @param hedge Perpetual commit amount times the entry rate /// @dev Internal version of the `getReward` function /// @dev In case where an approved address calls to close a perpetual, rewards are still going to get distributed /// to the owner of the perpetual, and not necessarily to the address getting the proceeds of the perpetual function _getReward(uint256 perpetualID, uint256 hedge) internal { _updateReward(perpetualID, hedge); uint256 reward = rewards[perpetualID]; if (reward > 0) { rewards[perpetualID] = 0; address owner = _owners[perpetualID]; // Attention here, there may be reentrancy attacks because of the following call // to an external contract done before other things are modified. Yet since the `rewardToken` // is mostly going to be a trusted contract controlled by governance (namely the ANGLE token), then // there is no point in putting an expensive `nonReentrant` modifier in the functions in `PerpetualManagerFront` // that allow indirect interactions with `_updateReward`. If new `rewardTokens` are set, we could think about // upgrading the `PerpetualManagerFront` contract rewardToken.safeTransfer(owner, reward); emit RewardPaid(owner, reward); } } /// @notice Allows to check the amount of gov tokens earned by a perpetual /// @param perpetualID ID of the perpetual which accumulated tokens /// @param hedge Perpetual commit amount times the entry rate /// @return Amount of gov tokens earned by the perpetual /// @dev A specific attention should be paid to have the base here: we consider that each HA stakes an amount /// equal to `committedAmount * entryRate / _collatBase`, here as the `hedge` corresponds to `committedAmount * entryRate`, /// we just need to divide by `_collatBase` /// @dev HAs earn reward tokens which are in base `BASE_TOKENS` function _earned(uint256 perpetualID, uint256 hedge) internal view returns (uint256) { return (hedge * (_rewardPerToken() - perpetualRewardPerTokenPaid[perpetualID])) / BASE_TOKENS / _collatBase + rewards[perpetualID]; } /// @notice Updates the amount of gov tokens earned by a perpetual /// @param perpetualID of the perpetual which earns tokens /// @param hedge Perpetual commit amount times the entry rate /// @dev When this function is called in the code, it has already been checked that the `perpetualID` /// exists function _updateReward(uint256 perpetualID, uint256 hedge) internal { rewardPerTokenStored = _rewardPerToken(); lastUpdateTime = _lastTimeRewardApplicable(); // No need to check if the `perpetualID` exists here, it has already been checked // in the code before when this internal function is called rewards[perpetualID] = _earned(perpetualID, hedge); perpetualRewardPerTokenPaid[perpetualID] = rewardPerTokenStored; } // =============================== ERC721 Logic ================================ /// @notice Gets the owner of a perpetual /// @param perpetualID ID of the concerned perpetual /// @return owner Owner of the perpetual function _ownerOf(uint256 perpetualID) internal view returns (address owner) { owner = _owners[perpetualID]; require(owner != address(0), "2"); } /// @notice Gets the addresses approved for a perpetual /// @param perpetualID ID of the concerned perpetual /// @return Address approved for this perpetual function _getApproved(uint256 perpetualID) internal view returns (address) { return _perpetualApprovals[perpetualID]; } /// @notice Safely transfers `perpetualID` token from `from` to `to`, checking first that contract recipients /// are aware of the ERC721 protocol to prevent tokens from being forever locked /// @param perpetualID ID of the concerned perpetual /// @param _data Additional data, it has no specified format and it is sent in call to `to` /// @dev This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. /// implement alternative mechanisms to perform token transfer, such as signature-based /// @dev Requirements: /// - `from` cannot be the zero address. /// - `to` cannot be the zero address. /// - `perpetualID` token must exist and be owned by `from`. /// - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. function _safeTransfer( address from, address to, uint256 perpetualID, bytes memory _data ) internal { _transfer(from, to, perpetualID); require(_checkOnERC721Received(from, to, perpetualID, _data), "24"); } /// @notice Returns whether `perpetualID` exists /// @dev Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll} /// @dev Tokens start existing when they are minted (`_mint`), /// and stop existing when they are burned (`_burn`) function _exists(uint256 perpetualID) internal view returns (bool) { return _owners[perpetualID] != address(0); } /// @notice Returns whether `spender` is allowed to manage `perpetualID` /// @dev `perpetualID` must exist function _isApprovedOrOwner(address spender, uint256 perpetualID) internal view returns (bool) { // The following checks if the perpetual exists address owner = _ownerOf(perpetualID); return (spender == owner || _getApproved(perpetualID) == spender || _operatorApprovals[owner][spender]); } /// @notice Mints `perpetualID` and transfers it to `to` /// @dev This method is equivalent to the `_safeMint` method used in OpenZeppelin ERC721 contract /// @dev `perpetualID` must not exist and `to` cannot be the zero address /// @dev Before calling this function it is checked that the `perpetualID` does not exist as it /// comes from a counter that has been incremented /// @dev Emits a {Transfer} event function _mint(address to, uint256 perpetualID) internal { _balances[to] += 1; _owners[perpetualID] = to; emit Transfer(address(0), to, perpetualID); require(_checkOnERC721Received(address(0), to, perpetualID, ""), "24"); } /// @notice Destroys `perpetualID` /// @dev `perpetualID` must exist /// @dev Emits a {Transfer} event function _burn(uint256 perpetualID) internal { address owner = _ownerOf(perpetualID); // Clear approvals _approve(address(0), perpetualID); _balances[owner] -= 1; delete _owners[perpetualID]; delete perpetualData[perpetualID]; emit Transfer(owner, address(0), perpetualID); } /// @notice Transfers `perpetualID` from `from` to `to` as opposed to {transferFrom}, /// this imposes no restrictions on msg.sender /// @dev `to` cannot be the zero address and `perpetualID` must be owned by `from` /// @dev Emits a {Transfer} event function _transfer( address from, address to, uint256 perpetualID ) internal { require(_ownerOf(perpetualID) == from, "1"); require(to != address(0), "26"); // Clear approvals from the previous owner _approve(address(0), perpetualID); _balances[from] -= 1; _balances[to] += 1; _owners[perpetualID] = to; emit Transfer(from, to, perpetualID); } /// @notice Approves `to` to operate on `perpetualID` function _approve(address to, uint256 perpetualID) internal { _perpetualApprovals[perpetualID] = to; emit Approval(_ownerOf(perpetualID), to, perpetualID); } /// @notice Internal function to invoke {IERC721Receiver-onERC721Received} on a target address /// The call is not executed if the target address is not a contract /// @param from Address representing the previous owner of the given token ID /// @param to Target address that will receive the tokens /// @param perpetualID ID of the token to be transferred /// @param _data Bytes optional data to send along with the call /// @return Bool whether the call correctly returned the expected magic value function _checkOnERC721Received( address from, address to, uint256 perpetualID, bytes memory _data ) private returns (bool) { if (to.isContract()) { try IERC721ReceiverUpgradeable(to).onERC721Received(msg.sender, from, perpetualID, _data) returns ( bytes4 retval ) { return retval == IERC721ReceiverUpgradeable(to).onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("24"); } else { // solhint-disable-next-line no-inline-assembly assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "./PerpetualManagerEvents.sol"; struct Perpetual { // Oracle value at the moment of perpetual opening uint256 entryRate; // Timestamp at which the perpetual was opened uint256 entryTimestamp; // Amount initially brought in the perpetual (net from fees) + amount added - amount removed from it // This is the only element that can be modified in the perpetual after its creation uint256 margin; // Amount of collateral covered by the perpetual. This cannot be modified once the perpetual is opened. // The amount covered is used interchangeably with the amount hedged uint256 committedAmount; } /// @title PerpetualManagerStorage /// @author Angle Core Team /// @notice `PerpetualManager` is the contract handling all the Hedging Agents positions and perpetuals /// @dev There is one `PerpetualManager` contract per pair stablecoin/collateral in the protocol /// @dev This file contains all the parameters and references used in the `PerpetualManager` contract // solhint-disable-next-line max-states-count contract PerpetualManagerStorage is PerpetualManagerEvents, FunctionUtils { // Base used in the collateral implementation (ERC20 decimal) uint256 internal _collatBase; // ============================== Perpetual Variables ========================== /// @notice Total amount of stablecoins that are insured (i.e. that could be redeemed against /// collateral thanks to HAs) /// When a HA opens a perpetual, it covers/hedges a fixed amount of stablecoins for the protocol, equal to /// the committed amount times the entry rate /// `totalHedgeAmount` is the sum of all these hedged amounts uint256 public totalHedgeAmount; // Counter to generate a unique `perpetualID` for each perpetual CountersUpgradeable.Counter internal _perpetualIDcount; // ========================== Mutable References ============================ /// @notice `Oracle` to give the rate feed, that is the price of the collateral /// with respect to the price of the stablecoin /// This reference can be modified by the corresponding `StableMaster` contract IOracle public oracle; // `FeeManager` address allowed to update the way fees are computed for this contract // This reference can be modified by the `PoolManager` contract IFeeManager internal _feeManager; // ========================== Immutable References ========================== /// @notice Interface for the `rewardToken` distributed as a reward /// As of Angle V1, only a single `rewardToken` can be distributed to HAs who own a perpetual /// This implementation assumes that reward tokens have a base of 18 decimals IERC20 public rewardToken; /// @notice Address of the `PoolManager` instance IPoolManager public poolManager; // Address of the `StableMaster` instance IStableMaster internal _stableMaster; // Interface for the underlying token accepted by this contract // This reference cannot be changed, it is taken from the `PoolManager` IERC20 internal _token; // ======================= Fees and other Parameters =========================== /// Deposit fees for HAs depend on the hedge ratio that is the ratio between what is hedged /// (or covered, this is a synonym) by HAs compared with the total amount to hedge /// @notice Thresholds for the ratio between to amount hedged and the amount to hedge /// The bigger the ratio the bigger the fees will be because this means that the max amount /// to insure is soon to be reached uint64[] public xHAFeesDeposit; /// @notice Deposit fees at threshold values /// This array should have the same length as the array above /// The evolution of the fees between two threshold values is linear uint64[] public yHAFeesDeposit; /// Withdraw fees for HAs also depend on the hedge ratio /// @notice Thresholds for the hedge ratio uint64[] public xHAFeesWithdraw; /// @notice Withdraw fees at threshold values uint64[] public yHAFeesWithdraw; /// @notice Maintenance Margin (in `BASE_PARAMS`) for each perpetual /// The margin ratio is defined for a perpetual as: `(initMargin + PnL) / committedAmount` where /// `PnL = committedAmount * (1 - initRate/currentRate)` /// If the `marginRatio` is below `maintenanceMargin`: then the perpetual can be liquidated uint64 public maintenanceMargin; /// @notice Maximum leverage multiplier authorized for HAs (`in BASE_PARAMS`) /// Leverage for a perpetual here corresponds to the ratio between the amount committed /// and the margin of the perpetual uint64 public maxLeverage; /// @notice Target proportion of stablecoins issued using this collateral to insure with HAs. /// This variable is exactly the same as the one in the `StableMaster` contract for this collateral. /// Above this hedge ratio, HAs cannot open new perpetuals /// When keepers are forcing the closing of some perpetuals, they are incentivized to bringing /// the hedge ratio to this proportion uint64 public targetHAHedge; /// @notice Limit proportion of stablecoins issued using this collateral that HAs can insure /// Above this ratio `forceCashOut` is activated and anyone can see its perpetual cashed out uint64 public limitHAHedge; /// @notice Extra parameter from the `FeeManager` contract that is multiplied to the fees from above and that /// can be used to change deposit fees. It works as a bonus - malus fee, if `haBonusMalusDeposit > BASE_PARAMS`, /// then the fee will be larger than `haFeesDeposit`, if `haBonusMalusDeposit < BASE_PARAMS`, fees will be smaller. /// This parameter, updated by keepers in the `FeeManager` contract, could most likely depend on the collateral ratio uint64 public haBonusMalusDeposit; /// @notice Extra parameter from the `FeeManager` contract that is multiplied to the fees from above and that /// can be used to change withdraw fees. It works as a bonus - malus fee, if `haBonusMalusWithdraw > BASE_PARAMS`, /// then the fee will be larger than `haFeesWithdraw`, if `haBonusMalusWithdraw < BASE_PARAMS`, fees will be smaller uint64 public haBonusMalusWithdraw; /// @notice Amount of time before HAs are allowed to withdraw funds from their perpetuals /// either using `removeFromPerpetual` or `closePerpetual`. New perpetuals cannot be forced closed in /// situations where the `forceClosePerpetuals` function is activated before this `lockTime` elapsed uint64 public lockTime; // ================================= Keeper fees ====================================== // All these parameters can be modified by their corresponding governance function /// @notice Portion of the leftover cash out amount of liquidated perpetuals that go to /// liquidating keepers uint64 public keeperFeesLiquidationRatio; /// @notice Cap on the fees that go to keepers liquidating a perpetual /// If a keeper liquidates n perpetuals in a single transaction, then this keeper is entitled to get as much as /// `n * keeperFeesLiquidationCap` as a reward uint256 public keeperFeesLiquidationCap; /// @notice Cap on the fees that go to keepers closing perpetuals when too much collateral is hedged by HAs /// (hedge ratio above `limitHAHedge`) /// If a keeper forces the closing of n perpetuals in a single transaction, then this keeper is entitled to get /// as much as `keeperFeesClosingCap`. This cap amount is independent of the number of perpetuals closed uint256 public keeperFeesClosingCap; /// @notice Thresholds on the values of the rate between the current hedged amount (`totalHedgeAmount`) and the /// target hedged amount by HAs (`targetHedgeAmount`) divided by 2. A value of `0.5` corresponds to a hedge ratio /// of `1`. Doing this allows to maintain an array with values of `x` inferior to `BASE_PARAMS`. uint64[] public xKeeperFeesClosing; /// @notice Values at thresholds of the proportions of the fees that should go to keepers closing perpetuals uint64[] public yKeeperFeesClosing; // =========================== Staking Parameters ============================== /// @notice Below are parameters that can also be found in other staking contracts /// to be able to compute rewards from staking (having perpetuals here) correctly uint256 public periodFinish; uint256 public rewardRate; uint256 public rewardsDuration; uint256 public lastUpdateTime; uint256 public rewardPerTokenStored; address public rewardsDistribution; // ============================== ERC721 Base URI ============================== /// @notice URI used for the metadata of the perpetuals string public baseURI; // =============================== Mappings ==================================== /// @notice Mapping from `perpetualID` to perpetual data mapping(uint256 => Perpetual) public perpetualData; /// @notice Mapping used to compute the rewards earned by a perpetual in a timeframe mapping(uint256 => uint256) public perpetualRewardPerTokenPaid; /// @notice Mapping used to get how much rewards in governance tokens are gained by a perpetual // identified by its ID mapping(uint256 => uint256) public rewards; // Mapping from `perpetualID` to owner address mapping(uint256 => address) internal _owners; // Mapping from owner address to perpetual owned count mapping(address => uint256) internal _balances; // Mapping from `perpetualID` to approved address mapping(uint256 => address) internal _perpetualApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) internal _operatorApprovals; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../external/AccessControlUpgradeable.sol"; import "../interfaces/IFeeManager.sol"; import "../interfaces/IPoolManager.sol"; import "../interfaces/IOracle.sol"; import "../interfaces/IPerpetualManager.sol"; import "../interfaces/IRewardsDistributor.sol"; import "../interfaces/IStableMaster.sol"; import "../interfaces/IStakingRewards.sol"; import "../utils/FunctionUtils.sol"; // Used in the `forceCashOutPerpetuals` function to store owners of perpetuals which have been force cashed // out, along with the amount associated to it struct Pairs { address owner; uint256 netCashOutAmount; } /// @title PerpetualManagerEvents /// @author Angle Core Team /// @notice `PerpetualManager` is the contract handling all the Hedging Agents perpetuals /// @dev There is one `PerpetualManager` contract per pair stablecoin/collateral in the protocol /// @dev This file contains all the events of the `PerpetualManager` contract contract PerpetualManagerEvents { event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); event PerpetualUpdated(uint256 _perpetualID, uint256 _margin); event PerpetualOpened(uint256 _perpetualID, uint256 _entryRate, uint256 _margin, uint256 _committedAmount); event PerpetualClosed(uint256 _perpetualID, uint256 _closeAmount); event PerpetualsForceClosed(uint256[] perpetualIDs, Pairs[] ownerAndCashOut, address keeper, uint256 reward); event KeeperTransferred(address keeperAddress, uint256 liquidationFees); // ============================== Parameters =================================== event BaseURIUpdated(string _baseURI); event LockTimeUpdated(uint64 _lockTime); event KeeperFeesCapUpdated(uint256 _keeperFeesLiquidationCap, uint256 _keeperFeesClosingCap); event TargetAndLimitHAHedgeUpdated(uint64 _targetHAHedge, uint64 _limitHAHedge); event BoundsPerpetualUpdated(uint64 _maxLeverage, uint64 _maintenanceMargin); event HAFeesUpdated(uint64[] _xHAFees, uint64[] _yHAFees, uint8 deposit); event KeeperFeesLiquidationRatioUpdated(uint64 _keeperFeesLiquidationRatio); event KeeperFeesClosingUpdated(uint64[] xKeeperFeesClosing, uint64[] yKeeperFeesClosing); // =============================== Reward ====================================== event RewardAdded(uint256 _reward); event RewardPaid(address indexed _user, uint256 _reward); event RewardsDistributionUpdated(address indexed _rewardsDistributor); event RewardsDistributionDurationUpdated(uint256 _rewardsDuration, address indexed _rewardsDistributor); event Recovered(address indexed tokenAddress, address indexed to, uint256 amount); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal initializer { __Context_init_unchained(); __Pausable_init_unchained(); } function __Pausable_init_unchained() internal initializer { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } uint256[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721ReceiverUpgradeable { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../../utils/introspection/IERC165Upgradeable.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721Upgradeable is IERC165Upgradeable { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IERC165Upgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable { function __ERC165_init() internal initializer { __ERC165_init_unchained(); } function __ERC165_init_unchained() internal initializer { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165Upgradeable).interfaceId; } uint256[50] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @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 Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal 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: MIT pragma solidity ^0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library CountersUpgradeable { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } }
// 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: 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: 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: GPL-3.0 pragma solidity ^0.8.7; import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "../interfaces/IAccessControl.sol"; /** * @dev This contract is fully forked from OpenZeppelin `AccessControlUpgradeable`. * The only difference is the removal of the ERC165 implementation as it's not * needed in Angle. * * Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ abstract contract AccessControlUpgradeable is Initializable, IAccessControl { function __AccessControl_init() internal initializer { __AccessControl_init_unchained(); } function __AccessControl_init_unchained() internal initializer {} struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role, msg.sender); _; } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/ */ function _checkRole(bytes32 role, address account) internal view { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", StringsUpgradeable.toHexString(uint160(account), 20), " is missing role ", StringsUpgradeable.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external override { require(account == msg.sender, "71"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== */ function _setupRole(bytes32 role, address account) internal { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal { emit RoleAdminChanged(role, getRoleAdmin(role), adminRole); _roles[role].adminRole = adminRole; } function _grantRole(bytes32 role, address account) internal { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, msg.sender); } } function _revokeRole(bytes32 role, address account) internal { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, msg.sender); } } uint256[49] private __gap; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "./IAccessControl.sol"; /// @title IFeeManagerFunctions /// @author Angle Core Team /// @dev Interface for the `FeeManager` contract interface IFeeManagerFunctions is IAccessControl { // ================================= Keepers =================================== function updateUsersSLP() external; function updateHA() external; // ================================= Governance ================================ function deployCollateral( address[] memory governorList, address guardian, address _perpetualManager ) external; function setFees( uint256[] memory xArray, uint64[] memory yArray, uint8 typeChange ) external; function setHAFees(uint64 _haFeeDeposit, uint64 _haFeeWithdraw) external; } /// @title IFeeManager /// @author Angle Core Team /// @notice Previous interface with additionnal getters for public variables and mappings /// @dev We need these getters as they are used in other contracts of the protocol interface IFeeManager is IFeeManagerFunctions { function stableMaster() external view returns (address); function perpetualManager() external view returns (address); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "./IFeeManager.sol"; import "./IPerpetualManager.sol"; import "./IOracle.sol"; // Struct for the parameters associated to a strategy interacting with a collateral `PoolManager` // contract struct StrategyParams { // Timestamp of last report made by this strategy // It is also used to check if a strategy has been initialized uint256 lastReport; // Total amount the strategy is expected to have uint256 totalStrategyDebt; // The share of the total assets in the `PoolManager` contract that the `strategy` can access to. uint256 debtRatio; } /// @title IPoolManagerFunctions /// @author Angle Core Team /// @notice Interface for the collateral poolManager contracts handling each one type of collateral for /// a given stablecoin /// @dev Only the functions used in other contracts of the protocol are left here interface IPoolManagerFunctions { // ============================ Constructor ==================================== function deployCollateral( address[] memory governorList, address guardian, IPerpetualManager _perpetualManager, IFeeManager feeManager, IOracle oracle ) external; // ============================ Yield Farming ================================== function creditAvailable() external view returns (uint256); function debtOutstanding() external view returns (uint256); function report( uint256 _gain, uint256 _loss, uint256 _debtPayment ) external; // ============================ Governance ===================================== function addGovernor(address _governor) external; function removeGovernor(address _governor) external; function setGuardian(address _guardian, address guardian) external; function revokeGuardian(address guardian) external; function setFeeManager(IFeeManager _feeManager) external; // ============================= Getters ======================================= function getBalance() external view returns (uint256); function getTotalAsset() external view returns (uint256); } /// @title IPoolManager /// @author Angle Core Team /// @notice Previous interface with additionnal getters for public variables and mappings /// @dev Used in other contracts of the protocol interface IPoolManager is IPoolManagerFunctions { function stableMaster() external view returns (address); function perpetualManager() external view returns (address); function token() external view returns (address); function feeManager() external view returns (address); function totalDebt() external view returns (uint256); function strategies(address _strategy) external view returns (StrategyParams memory); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; /// @title IOracle /// @author Angle Core Team /// @notice Interface for Angle's oracle contracts reading oracle rates from both UniswapV3 and Chainlink /// from just UniswapV3 or from just Chainlink interface IOracle { function read() external view returns (uint256); function readAll() external view returns (uint256 lowerRate, uint256 upperRate); function readLower() external view returns (uint256); function readUpper() external view returns (uint256); function readQuote(uint256 baseAmount) external view returns (uint256); function readQuoteLower(uint256 baseAmount) external view returns (uint256); function inBase() external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "./IERC721.sol"; import "./IFeeManager.sol"; import "./IOracle.sol"; import "./IAccessControl.sol"; /// @title Interface of the contract managing perpetuals /// @author Angle Core Team /// @dev Front interface, meaning only user-facing functions interface IPerpetualManagerFront is IERC721Metadata { function openPerpetual( address owner, uint256 amountBrought, uint256 amountCommitted, uint256 maxOracleRate, uint256 minNetMargin ) external returns (uint256 perpetualID); function closePerpetual( uint256 perpetualID, address to, uint256 minCashOutAmount ) external; function addToPerpetual(uint256 perpetualID, uint256 amount) external; function removeFromPerpetual( uint256 perpetualID, uint256 amount, address to ) external; function liquidatePerpetuals(uint256[] memory perpetualIDs) external; function forceClosePerpetuals(uint256[] memory perpetualIDs) external; // ========================= External View Functions ============================= function getCashOutAmount(uint256 perpetualID, uint256 rate) external view returns (uint256, uint256); function isApprovedOrOwner(address spender, uint256 perpetualID) external view returns (bool); } /// @title Interface of the contract managing perpetuals /// @author Angle Core Team /// @dev This interface does not contain user facing functions, it just has functions that are /// interacted with in other parts of the protocol interface IPerpetualManagerFunctions is IAccessControl { // ================================= Governance ================================ function deployCollateral( address[] memory governorList, address guardian, IFeeManager feeManager, IOracle oracle_ ) external; function setFeeManager(IFeeManager feeManager_) external; function setHAFees( uint64[] memory _xHAFees, uint64[] memory _yHAFees, uint8 deposit ) external; function setTargetAndLimitHAHedge(uint64 _targetHAHedge, uint64 _limitHAHedge) external; function setKeeperFeesLiquidationRatio(uint64 _keeperFeesLiquidationRatio) external; function setKeeperFeesCap(uint256 _keeperFeesLiquidationCap, uint256 _keeperFeesClosingCap) external; function setKeeperFeesClosing(uint64[] memory _xKeeperFeesClosing, uint64[] memory _yKeeperFeesClosing) external; function setLockTime(uint64 _lockTime) external; function setBoundsPerpetual(uint64 _maxLeverage, uint64 _maintenanceMargin) external; function pause() external; function unpause() external; // ==================================== Keepers ================================ function setFeeKeeper(uint64 feeDeposit, uint64 feesWithdraw) external; // =============================== StableMaster ================================ function setOracle(IOracle _oracle) external; } /// @title IPerpetualManager /// @author Angle Core Team /// @notice Previous interface with additionnal getters for public variables interface IPerpetualManager is IPerpetualManagerFunctions { function poolManager() external view returns (address); function oracle() external view returns (address); function targetHAHedge() external view returns (uint64); function totalHedgeAmount() external view returns (uint256); } /// @title Interface of the contract managing perpetuals with claim function /// @author Angle Core Team /// @dev Front interface with rewards function, meaning only user-facing functions interface IPerpetualManagerFrontWithClaim is IPerpetualManagerFront, IPerpetualManager { function getReward(uint256 perpetualID) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./IStakingRewards.sol"; /// @title IRewardsDistributor /// @author Angle Core Team, inspired from Fei protocol /// (https://github.com/fei-protocol/fei-protocol-core/blob/master/contracts/staking/IRewardsDistributor.sol) /// @notice Rewards Distributor interface interface IRewardsDistributor { // ========================= Public Parameter Getter =========================== function rewardToken() external view returns (IERC20); // ======================== External User Available Function =================== function drip(IStakingRewards stakingContract) external returns (uint256); // ========================= Governor Functions ================================ function governorWithdrawRewardToken(uint256 amount, address governance) external; function governorRecover( address tokenAddress, address to, uint256 amount, IStakingRewards stakingContract ) external; function setUpdateFrequency(uint256 _frequency, IStakingRewards stakingContract) external; function setIncentiveAmount(uint256 _incentiveAmount, IStakingRewards stakingContract) external; function setAmountToDistribute(uint256 _amountToDistribute, IStakingRewards stakingContract) external; function setDuration(uint256 _duration, IStakingRewards stakingContract) external; function setStakingContract( address _stakingContract, uint256 _duration, uint256 _incentiveAmount, uint256 _dripFrequency, uint256 _amountToDistribute ) external; function setNewRewardsDistributor(address newRewardsDistributor) external; function removeStakingContract(IStakingRewards stakingContract) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; // Normally just importing `IPoolManager` should be sufficient, but for clarity here // we prefer to import all concerned interfaces import "./IPoolManager.sol"; import "./IOracle.sol"; import "./IPerpetualManager.sol"; import "./ISanToken.sol"; // Struct to handle all the parameters to manage the fees // related to a given collateral pool (associated to the stablecoin) struct MintBurnData { // Values of the thresholds to compute the minting fees // depending on HA hedge (scaled by `BASE_PARAMS`) uint64[] xFeeMint; // Values of the fees at thresholds (scaled by `BASE_PARAMS`) uint64[] yFeeMint; // Values of the thresholds to compute the burning fees // depending on HA hedge (scaled by `BASE_PARAMS`) uint64[] xFeeBurn; // Values of the fees at thresholds (scaled by `BASE_PARAMS`) uint64[] yFeeBurn; // Max proportion of collateral from users that can be covered by HAs // It is exactly the same as the parameter of the same name in `PerpetualManager`, whenever one is updated // the other changes accordingly uint64 targetHAHedge; // Minting fees correction set by the `FeeManager` contract: they are going to be multiplied // to the value of the fees computed using the hedge curve // Scaled by `BASE_PARAMS` uint64 bonusMalusMint; // Burning fees correction set by the `FeeManager` contract: they are going to be multiplied // to the value of the fees computed using the hedge curve // Scaled by `BASE_PARAMS` uint64 bonusMalusBurn; // Parameter used to limit the number of stablecoins that can be issued using the concerned collateral uint256 capOnStableMinted; } // Struct to handle all the variables and parameters to handle SLPs in the protocol // including the fraction of interests they receive or the fees to be distributed to // them struct SLPData { // Last timestamp at which the `sanRate` has been updated for SLPs uint256 lastBlockUpdated; // Fees accumulated from previous blocks and to be distributed to SLPs uint256 lockedInterests; // Max interests used to update the `sanRate` in a single block // Should be in collateral token base uint256 maxInterestsDistributed; // Amount of fees left aside for SLPs and that will be distributed // when the protocol is collateralized back again uint256 feesAside; // Part of the fees normally going to SLPs that is left aside // before the protocol is collateralized back again (depends on collateral ratio) // Updated by keepers and scaled by `BASE_PARAMS` uint64 slippageFee; // Portion of the fees from users minting and burning // that goes to SLPs (the rest goes to surplus) uint64 feesForSLPs; // Slippage factor that's applied to SLPs exiting (depends on collateral ratio) // If `slippage = BASE_PARAMS`, SLPs can get nothing, if `slippage = 0` they get their full claim // Updated by keepers and scaled by `BASE_PARAMS` uint64 slippage; // Portion of the interests from lending // that goes to SLPs (the rest goes to surplus) uint64 interestsForSLPs; } /// @title IStableMasterFunctions /// @author Angle Core Team /// @notice Interface for the `StableMaster` contract interface IStableMasterFunctions { function deploy( address[] memory _governorList, address _guardian, address _agToken ) external; // ============================== Lending ====================================== function accumulateInterest(uint256 gain) external; function signalLoss(uint256 loss) external; // ============================== HAs ========================================== function getStocksUsers() external view returns (uint256 maxCAmountInStable); function convertToSLP(uint256 amount, address user) external; // ============================== Keepers ====================================== function getCollateralRatio() external returns (uint256); function setFeeKeeper( uint64 feeMint, uint64 feeBurn, uint64 _slippage, uint64 _slippageFee ) external; // ============================== AgToken ====================================== function updateStocksUsers(uint256 amount, address poolManager) external; // ============================= Governance ==================================== function setCore(address newCore) external; function addGovernor(address _governor) external; function removeGovernor(address _governor) external; function setGuardian(address newGuardian, address oldGuardian) external; function revokeGuardian(address oldGuardian) external; function setCapOnStableAndMaxInterests( uint256 _capOnStableMinted, uint256 _maxInterestsDistributed, IPoolManager poolManager ) external; function setIncentivesForSLPs( uint64 _feesForSLPs, uint64 _interestsForSLPs, IPoolManager poolManager ) external; function setUserFees( IPoolManager poolManager, uint64[] memory _xFee, uint64[] memory _yFee, uint8 _mint ) external; function setTargetHAHedge(uint64 _targetHAHedge) external; function pause(bytes32 agent, IPoolManager poolManager) external; function unpause(bytes32 agent, IPoolManager poolManager) external; } /// @title IStableMaster /// @author Angle Core Team /// @notice Previous interface with additionnal getters for public variables and mappings interface IStableMaster is IStableMasterFunctions { function agToken() external view returns (address); function collateralMap(IPoolManager poolManager) external view returns ( IERC20 token, ISanToken sanToken, IPerpetualManager perpetualManager, IOracle oracle, uint256 stocksUsers, uint256 sanRate, uint256 collatBase, SLPData memory slpData, MintBurnData memory feeData ); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /// @title IStakingRewardsFunctions /// @author Angle Core Team /// @notice Interface for the staking rewards contract that interact with the `RewardsDistributor` contract interface IStakingRewardsFunctions { function notifyRewardAmount(uint256 reward) external; function recoverERC20( address tokenAddress, address to, uint256 tokenAmount ) external; function setNewRewardsDistribution(address newRewardsDistribution) external; } /// @title IStakingRewards /// @author Angle Core Team /// @notice Previous interface with additionnal getters for public variables interface IStakingRewards is IStakingRewardsFunctions { function rewardToken() external view returns (IERC20); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; /// @title FunctionUtils /// @author Angle Core Team /// @notice Contains all the utility functions that are needed in different places of the protocol /// @dev Functions in this contract should typically be pure functions /// @dev This contract is voluntarily a contract and not a library to save some gas cost every time it is used contract FunctionUtils { /// @notice Base that is used to compute ratios and floating numbers uint256 public constant BASE_TOKENS = 10**18; /// @notice Base that is used to define parameters that need to have a floating value (for instance parameters /// that are defined as ratios) uint256 public constant BASE_PARAMS = 10**9; /// @notice Computes the value of a linear by part function at a given point /// @param x Point of the function we want to compute /// @param xArray List of breaking points (in ascending order) that define the linear by part function /// @param yArray List of values at breaking points (not necessarily in ascending order) /// @dev The evolution of the linear by part function between two breaking points is linear /// @dev Before the first breaking point and after the last one, the function is constant with a value /// equal to the first or last value of the yArray /// @dev This function is relevant if `x` is between O and `BASE_PARAMS`. If `x` is greater than that, then /// everything will be as if `x` is equal to the greater element of the `xArray` function _piecewiseLinear( uint64 x, uint64[] memory xArray, uint64[] memory yArray ) internal pure returns (uint64) { if (x >= xArray[xArray.length - 1]) { return yArray[xArray.length - 1]; } else if (x <= xArray[0]) { return yArray[0]; } else { uint256 lower; uint256 upper = xArray.length - 1; uint256 mid; while (upper - lower > 1) { mid = lower + (upper - lower) / 2; if (xArray[mid] <= x) { lower = mid; } else { upper = mid; } } if (yArray[upper] > yArray[lower]) { // There is no risk of overflow here as in the product of the difference of `y` // with the difference of `x`, the product is inferior to `BASE_PARAMS**2` which does not // overflow for `uint64` return yArray[lower] + ((yArray[upper] - yArray[lower]) * (x - xArray[lower])) / (xArray[upper] - xArray[lower]); } else { return yArray[lower] - ((yArray[lower] - yArray[upper]) * (x - xArray[lower])) / (xArray[upper] - xArray[lower]); } } } /// @notice Checks if the input arrays given by governance to update the fee structure is valid /// @param xArray List of breaking points (in ascending order) that define the linear by part function /// @param yArray List of values at breaking points (not necessarily in ascending order) /// @dev This function is a way to avoid some governance attacks or errors /// @dev The modifier checks if the arrays have a non null length, if their length is the same, if the values /// in the `xArray` are in ascending order and if the values in the `xArray` and in the `yArray` are not superior /// to `BASE_PARAMS` modifier onlyCompatibleInputArrays(uint64[] memory xArray, uint64[] memory yArray) { require(xArray.length == yArray.length && xArray.length > 0, "5"); for (uint256 i = 0; i <= yArray.length - 1; i++) { require(yArray[i] <= uint64(BASE_PARAMS) && xArray[i] <= uint64(BASE_PARAMS), "6"); if (i > 0) { require(xArray[i] > xArray[i - 1], "7"); } } _; } /// @notice Checks if the new value given for the parameter is consistent (it should be inferior to 1 /// if it corresponds to a ratio) /// @param fees Value of the new parameter to check modifier onlyCompatibleFees(uint64 fees) { require(fees <= BASE_PARAMS, "4"); _; } /// @notice Checks if the new address given is not null /// @param newAddress Address to check /// @dev Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#missing-zero-address-validation modifier zeroCheck(address newAddress) { require(newAddress != address(0), "0"); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @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 ContextUpgradeable is Initializable { function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } uint256[50] private __gap; }
// 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 ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165Upgradeable { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// 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); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal 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: MIT pragma solidity ^0.8.0; /** * @dev String operations. */ library StringsUpgradeable { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; /// @title IAccessControl /// @author Forked from OpenZeppelin /// @notice Interface for `AccessControl` contracts interface IAccessControl { function hasRole(bytes32 role, address account) external view returns (bool); function getRoleAdmin(bytes32 role) external view returns (bytes32); function grantRole(bytes32 role, address account) external; function revokeRole(bytes32 role, address account) external; function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; interface IERC721 is IERC165 { function balanceOf(address owner) external view returns (uint256 balance); function ownerOf(uint256 tokenId) external view returns (address owner); function safeTransferFrom( address from, address to, uint256 tokenId ) external; function transferFrom( address from, address to, uint256 tokenId ) external; function approve(address to, uint256 tokenId) external; function getApproved(uint256 tokenId) external view returns (address operator); function setApprovalForAll(address operator, bool _approved) external; function isApprovedForAll(address owner, address operator) external view returns (bool); function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; } interface IERC721Metadata is IERC721 { function name() external view returns (string memory); function symbol() external view returns (string memory); function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; /// @title ISanToken /// @author Angle Core Team /// @notice Interface for Angle's `SanToken` contract that handles sanTokens, tokens that are given to SLPs /// contributing to a collateral for a given stablecoin interface ISanToken is IERC20Upgradeable { // ================================== StableMaster ============================= function mint(address account, uint256 amount) external; function burnFrom( uint256 amount, address burner, address sender ) external; function burnSelf(uint256 amount, address burner) external; function stableMaster() external view returns (address); function poolManager() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @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); }
{ "optimizer": { "enabled": true, "runs": 260 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"_baseURI","type":"string"}],"name":"BaseURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"_maxLeverage","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"_maintenanceMargin","type":"uint64"}],"name":"BoundsPerpetualUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64[]","name":"_xHAFees","type":"uint64[]"},{"indexed":false,"internalType":"uint64[]","name":"_yHAFees","type":"uint64[]"},{"indexed":false,"internalType":"uint8","name":"deposit","type":"uint8"}],"name":"HAFeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_keeperFeesLiquidationCap","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_keeperFeesClosingCap","type":"uint256"}],"name":"KeeperFeesCapUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64[]","name":"xKeeperFeesClosing","type":"uint64[]"},{"indexed":false,"internalType":"uint64[]","name":"yKeeperFeesClosing","type":"uint64[]"}],"name":"KeeperFeesClosingUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"_keeperFeesLiquidationRatio","type":"uint64"}],"name":"KeeperFeesLiquidationRatioUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"keeperAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidationFees","type":"uint256"}],"name":"KeeperTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"_lockTime","type":"uint64"}],"name":"LockTimeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_perpetualID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_closeAmount","type":"uint256"}],"name":"PerpetualClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_perpetualID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_entryRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_margin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_committedAmount","type":"uint256"}],"name":"PerpetualOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_perpetualID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_margin","type":"uint256"}],"name":"PerpetualUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"perpetualIDs","type":"uint256[]"},{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"netCashOutAmount","type":"uint256"}],"indexed":false,"internalType":"struct Pairs[]","name":"ownerAndCashOut","type":"tuple[]"},{"indexed":false,"internalType":"address","name":"keeper","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"PerpetualsForceClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_reward","type":"uint256"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_reward","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_rewardsDuration","type":"uint256"},{"indexed":true,"internalType":"address","name":"_rewardsDistributor","type":"address"}],"name":"RewardsDistributionDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_rewardsDistributor","type":"address"}],"name":"RewardsDistributionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"_targetHAHedge","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"_limitHAHedge","type":"uint64"}],"name":"TargetAndLimitHAHedgeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"BASE_PARAMS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BASE_TOKENS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARDIAN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POOLMANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addToPerpetual","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minCashOutAmount","type":"uint256"}],"name":"closePerpetual","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"governorList","type":"address[]"},{"internalType":"address","name":"guardian","type":"address"},{"internalType":"contract IFeeManager","name":"feeManager_","type":"address"},{"internalType":"contract IOracle","name":"oracle_","type":"address"}],"name":"deployCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"perpetualIDs","type":"uint256[]"}],"name":"forceClosePerpetuals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"}],"name":"getCashOutAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"haBonusMalusDeposit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"haBonusMalusWithdraw","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IPoolManager","name":"poolManager_","type":"address"},{"internalType":"contract IERC20","name":"rewardToken_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"isApprovedOrOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeperFeesClosingCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeperFeesLiquidationCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeperFeesLiquidationRatio","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"limitHAHedge","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"perpetualIDs","type":"uint256[]"}],"name":"liquidatePerpetuals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockTime","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maintenanceMargin","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLeverage","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"name":"notifyRewardAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"committedAmount","type":"uint256"},{"internalType":"uint256","name":"maxOracleRate","type":"uint256"},{"internalType":"uint256","name":"minNetMargin","type":"uint256"}],"name":"openPerpetual","outputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract IOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodFinish","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"perpetualData","outputs":[{"internalType":"uint256","name":"entryRate","type":"uint256"},{"internalType":"uint256","name":"entryTimestamp","type":"uint256"},{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"committedAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"perpetualRewardPerTokenPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolManager","outputs":[{"internalType":"contract IPoolManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"removeFromPerpetual","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsDistribution","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"perpetualID","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_maxLeverage","type":"uint64"},{"internalType":"uint64","name":"_maintenanceMargin","type":"uint64"}],"name":"setBoundsPerpetual","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"feeDeposit","type":"uint64"},{"internalType":"uint64","name":"feeWithdraw","type":"uint64"}],"name":"setFeeKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IFeeManager","name":"feeManager_","type":"address"}],"name":"setFeeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64[]","name":"_xHAFees","type":"uint64[]"},{"internalType":"uint64[]","name":"_yHAFees","type":"uint64[]"},{"internalType":"uint8","name":"deposit","type":"uint8"}],"name":"setHAFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_keeperFeesLiquidationCap","type":"uint256"},{"internalType":"uint256","name":"_keeperFeesClosingCap","type":"uint256"}],"name":"setKeeperFeesCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64[]","name":"_xKeeperFeesClosing","type":"uint64[]"},{"internalType":"uint64[]","name":"_yKeeperFeesClosing","type":"uint64[]"}],"name":"setKeeperFeesClosing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_keeperFeesLiquidationRatio","type":"uint64"}],"name":"setKeeperFeesLiquidationRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_lockTime","type":"uint64"}],"name":"setLockTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsDistribution","type":"address"}],"name":"setNewRewardsDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IOracle","name":"oracle_","type":"address"}],"name":"setOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardsDuration","type":"uint256"},{"internalType":"address","name":"_rewardsDistribution","type":"address"}],"name":"setRewardDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_targetHAHedge","type":"uint64"},{"internalType":"uint64","name":"_limitHAHedge","type":"uint64"}],"name":"setTargetAndLimitHAHedge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"targetHAHedge","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalHedgeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"perpetualID","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"xHAFeesDeposit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"xHAFeesWithdraw","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"xKeeperFeesClosing","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"yHAFeesDeposit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"yHAFeesWithdraw","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"yKeeperFeesClosing","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50602154610100900460ff16806200002c575060215460ff16155b620000945760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b602154610100900460ff16158015620000b7576021805461ffff19166101011790555b8015620000ca576021805461ff00191690555b50615f3580620000db6000396000f3fe608060405234801561001057600080fd5b50600436106104a15760003560e01c80637bd06a151161026d578063c0212c7211610151578063df136d65116100ce578063e985e9c511610092578063e985e9c514610a94578063ebe2b12b14610ace578063f301af4214610ad7578063f5d011c514610af7578063f7c618c114610b0a578063f902fad714610b1d57600080fd5b8063df136d6514610a2e578063df1b8bd314610a37578063e048684214610a46578063e2b01a5e14610a6e578063e5234c7a14610a8157600080fd5b8063d1aace9f11610115578063d1aace9f146109cf578063d547741f146109e2578063d5eb0581146109f5578063d7f6328e14610a08578063dc4c90d314610a1b57600080fd5b8063c0212c721461097a578063c1618dda1461098d578063c628a6f7146109a0578063c87b56dd146109b3578063c8f33c91146109c657600080fd5b806395d89b41116101ea578063ae3302c2116101ae578063ae3302c21461090b578063b126e7e514610925578063b3b1cb2714610938578063b88d4fde1461094b578063b8f368951461095e578063bcb01a801461096757600080fd5b806395d89b41146104ce5780639f48118f146108d2578063a217fddf146108dd578063a22cb465146108e5578063a62b2a3d146108f857600080fd5b8063873291bb11610231578063873291bb1461086f5780638c6dfaf7146108825780638d5e19f11461088b5780638e240144146108a557806391d14854146108bf57600080fd5b80637bd06a15146108185780637dc0d1d0146108215780638211477a14610834578063840a7698146108475780638456cb591461086757600080fd5b8063386a9525116103945780634d6ed8c4116103115780636c0360eb116102d55780636c0360eb146107bb5780636d59dae7146107c357806370a08231146107d65780637adbf973146107e95780637b0a47ee146107fc5780637b39ecf71461080557600080fd5b80634d6ed8c414610764578063515dc4801461077757806355f804b31461078a5780635c975abb1461079d5780636352211e146107a857600080fd5b8063430c208111610358578063430c208114610705578063472d35b91461071857806347c12e011461072b578063485cc9551461073e57806349a5d3ef1461075157600080fd5b8063386a9525146106bb5780633c6b16ab146106c45780633f4ba83a146106d75780633fc6df6e146106df57806342842e0e146106f257600080fd5b806323b872dd11610422578063324f3815116103e6578063324f38151461065557806336568abe1461066f5780633675441514610682578063367f21b41461069557806338050129146106a857600080fd5b806323b872dd146105e4578063248a9ca3146105f757806324d83b791461061a57806324ea54f41461062d5780632f2ff15d1461064257600080fd5b80630c016dc0116104695780630c016dc01461056e5780630d668087146105915780631171bda9146105ab578063142c3ba0146105be5780631c4b774b146105d157600080fd5b806301ffc9a7146104a657806306fdde03146104ce578063081812fc146104fc578063095ea7b3146105275780630bfab8a71461053c575b600080fd5b6104b96104b436600461549f565b610b72565b60405190151581526020015b60405180910390f35b6040805180820190915260098152680416e676c65506572760bc1b60208201525b6040516104c59190615a22565b61050f61050a366004615461565b610c4b565b6040516001600160a01b0390911681526020016104c5565b61053a610535366004615190565b610ca5565b005b600e5461055690600160c01b90046001600160401b031681565b6040516001600160401b0390911681526020016104c5565b610583600080516020615ec083398151915281565b6040519081526020016104c5565b600e5461055690600160801b90046001600160401b031681565b61053a6105b93660046150a2565b610d5c565b6105566105cc366004615461565b610e2f565b61053a6105df366004615461565b610e6c565b61053a6105f23660046150a2565b610ef1565b610583610605366004615461565b60009081526022602052604090206001015490565b61053a610628366004615561565b610f2b565b610583600080516020615ee083398151915281565b61053a61065036600461547a565b611046565b600d5461055690600160c01b90046001600160401b031681565b61053a61067d36600461547a565b61106c565b61053a6106903660046155d5565b6110b7565b61053a6106a336600461536a565b611133565b6105566106b6366004615461565b61133a565b61058360155481565b61053a6106d2366004615461565b61134a565b61053a6114e6565b60185461050f906001600160a01b031681565b61053a6107003660046150a2565b611507565b6104b9610713366004615190565b611522565b61053a61072636600461502f565b611535565b61053a610739366004615561565b611571565b61053a61074c366004615069565b6115d3565b61055661075f366004615461565b6118b5565b610583610772366004615461565b6118c5565b61053a6107853660046155f0565b6118f0565b61053a6107983660046154d9565b611a94565b60865460ff166104b9565b61050f6107b6366004615461565b611af0565b6104ef611afb565b61053a6107d13660046155a7565b611b89565b6105836107e436600461502f565b611dc4565b61053a6107f736600461502f565b611e08565b61058360145481565b61053a6108133660046152d3565b611e54565b610583600f5481565b60035461050f906001600160a01b031681565b61053a6108423660046153cd565b611f9e565b610583610855366004615461565b601b6020526000908152604090205481565b61053a6121ef565b61053a61087d36600461502f565b612210565b61058360105481565b600d5461055690600160801b90046001600160401b031681565b600e5461055690600160401b90046001600160401b031681565b6104b96108cd36600461547a565b612284565b610583633b9aca0081565b610583600081565b61053a6108f3366004615162565b6122af565b6105836109063660046151bc565b612364565b600d5461055690600160401b90046001600160401b031681565b61053a610933366004615200565b6125e7565b61053a6109463660046155d5565b6126be565b61053a6109593660046150e3565b61275e565b61058360015481565b61053a6109753660046152d3565b61279a565b600e54610556906001600160401b031681565b61055661099b366004615461565b612e08565b61053a6109ae3660046155f0565b612e18565b6104ef6109c1366004615461565b612e73565b61058360165481565b6105566109dd366004615461565b612fdb565b61053a6109f036600461547a565b612feb565b600d54610556906001600160401b031681565b610556610a16366004615461565b613011565b60065461050f906001600160a01b031681565b61058360175481565b610583670de0b6b3a764000081565b610a59610a54366004615561565b613021565b604080519283526020830191909152016104c5565b61053a610a7c36600461547a565b613077565b61053a610a8f36600461553a565b613114565b6104b9610aa2366004615069565b6001600160a01b0391821660009081526020808052604080832093909416825291909152205460ff1690565b61058360135481565b610583610ae5366004615461565b601c6020526000908152604090205481565b61053a610b053660046155f0565b6132bc565b60055461050f906001600160a01b031681565b610b52610b2b366004615461565b601a6020526000908152604090208054600182015460028301546003909301549192909184565b6040805194855260208501939093529183015260608201526080016104c5565b60006001600160e01b03198216636e44396d60e01b1480610ba357506001600160e01b03198216632303fc0360e01b145b80610bbe57506001600160e01b0319821663f7c618c160e01b145b80610bd957506001600160e01b0319821663aa283ab960e01b145b80610bf457506001600160e01b03198216637965db0b60e01b145b80610c0f57506001600160e01b03198216635b5e139f60e01b145b80610c2a57506001600160e01b031982166380ac58cd60e01b145b80610c4557506001600160e01b031982166301ffc9a760e01b145b92915050565b6000818152601d60205260408120546001600160a01b0316610c885760405162461bcd60e51b8152600401610c7f90615ae3565b60405180910390fd5b6000828152601f60205260409020546001600160a01b0316610c45565b6000610cb0826133cf565b9050806001600160a01b0316836001600160a01b03161415610cf95760405162461bcd60e51b8152602060048201526002602482015261333560f01b6044820152606401610c7f565b336001600160a01b0382161480610d3157506001600160a01b03811660009081526020808052604080832033845290915290205460ff165b610d4d5760405162461bcd60e51b8152600401610c7f90615b19565b610d578383613409565b505050565b6018546001600160a01b03163314610d865760405162461bcd60e51b8152600401610c7f90615afe565b6005546001600160a01b0384811691161415610dc95760405162461bcd60e51b8152602060048201526002602482015261032360f41b6044820152606401610c7f565b610ddd6001600160a01b0384168383613477565b816001600160a01b0316836001600160a01b03167ffff3b3844276f57024e0b42afec1a37f75db36511e43819a4f2a63ab7862b64883604051610e2291815260200190565b60405180910390a3505050565b600a8181548110610e3f57600080fd5b9060005260206000209060049182820401919006600802915054906101000a90046001600160401b031681565b60865460ff1615610e8f5760405162461bcd60e51b8152600401610c7f90615a6b565b6000818152601d60205260409020546001600160a01b0316610ec35760405162461bcd60e51b8152600401610c7f90615ae3565b6000818152601a602052604090208054600390910154610eee918391610ee99190615ceb565b6134da565b50565b3381610efd828261356b565b610f195760405162461bcd60e51b8152600401610c7f90615b19565b610f248585856135e8565b5050505050565b60865460ff1615610f4e5760405162461bcd60e51b8152600401610c7f90615a6b565b6000828152601a6020908152604080832081516080810183528154815260018201549381019390935260028101549183019190915260030154606082015290610f9561371f565b5090506000610fa58584846137a4565b91505080610f2457600654600854610fcc916001600160a01b0391821691339116876137eb565b6000858152601a602052604081206002018054869290610fed908490615b88565b925050819055507f10c4de39a7e804616cdc1b2dbf59fe6db0ed0d54ff69cef9c8fc024f79c7d47e858585604001516110269190615b88565b604080519283526020830191909152015b60405180910390a15050505050565b6000828152602260205260409020600101546110628133613829565b610d57838361388d565b6001600160a01b03811633146110a95760405162461bcd60e51b8152602060048201526002602482015261373160f01b6044820152606401610c7f565b6110b382826138f6565b5050565b600080516020615ee08339815191526110d08133613829565b600e805467ffffffffffffffff60801b1916600160801b6001600160401b038516908102919091179091556040519081527f0cedd128b637e635da421319ae981d7968b7a477c1fa3b10275fac22ecbd51a6906020015b60405180910390a15050565b600080516020615ee083398151915261114c8133613829565b828280518251148015611160575060008251115b6111905760405162461bcd60e51b81526020600482015260016024820152603560f81b6044820152606401610c7f565b60005b600182516111a19190615d39565b81116112de57633b9aca006001600160401b03168282815181106111c7576111c7615e4b565b60200260200101516001600160401b0316111580156112155750633b9aca006001600160401b031683828151811061120157611201615e4b565b60200260200101516001600160401b031611155b6112455760405162461bcd60e51b81526020600482015260016024820152601b60f91b6044820152606401610c7f565b80156112cc5782611257600183615d39565b8151811061126757611267615e4b565b60200260200101516001600160401b031683828151811061128a5761128a615e4b565b60200260200101516001600160401b0316116112cc5760405162461bcd60e51b81526020600482015260016024820152603760f81b6044820152606401610c7f565b806112d681615df0565b915050611193565b5084516112f2906011906020880190614dfc565b508351611306906012906020870190614dfc565b507f275781d4ec4992e53f64326606b9f7eb81a89baf476df8de6d0410fd218e7be3601160126040516110379291906159fd565b60118181548110610e3f57600080fd5b6018546001600160a01b031633146113745760405162461bcd60e51b8152600401610c7f90615afe565b61137c61395d565b601755601354421061139d576015546113959082615bcb565b6014556113df565b6000426013546113ad9190615d39565b90506000601454826113bf9190615ceb565b6015549091506113cf8285615b88565b6113d99190615bcb565b60145550505b6005546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b15801561142357600080fd5b505afa158015611437573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145b9190615521565b90506015548161146b9190615bcb565b60145411156114a15760405162461bcd60e51b8152602060048201526002602482015261191960f11b6044820152606401610c7f565b4260168190556015546114b391615b88565b6013556040518281527fde88a922e0d3b88b24e9623efeb464919c6bf9f66857a65e2bfcf2ce87a9433d90602001611127565b600080516020615ee08339815191526114ff8133613829565b610eee6139c5565b610d578383836040518060200160405280600081525061275e565b600061152e838361356b565b9392505050565b600080516020615ec083398151915261154e8133613829565b50600480546001600160a01b0319166001600160a01b0392909216919091179055565b600080516020615ee083398151915261158a8133613829565b600f839055601082905560408051848152602081018490527fa0aa01eac9422dea36b84eb0bbc758e72643fbdbc72a4fd205d51c738803598291015b60405180910390a1505050565b602154610100900460ff16806115ec575060215460ff16155b6116085760405162461bcd60e51b8152600401610c7f90615a95565b602154610100900460ff1615801561162a576021805461ffff19166101011790555b816001600160a01b0381166116515760405162461bcd60e51b8152600401610c7f90615a35565b611659613a58565b611661613ad3565b600680546001600160a01b0319166001600160a01b03861690811790915560408051637e062a3560e11b8152905163fc0c546a91600480820192602092909190829003018186803b1580156116b557600080fd5b505afa1580156116c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ed919061504c565b600860006101000a8154816001600160a01b0302191690836001600160a01b03160217905550836001600160a01b0316636ac5dc466040518163ffffffff1660e01b815260040160206040518083038186803b15801561174c57600080fd5b505afa158015611760573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611784919061504c565b600780546001600160a01b03199081166001600160a01b0393841617909155600580549091168583161790556008546040805163313ce56760e01b81529051919092169163313ce567916004808301926020929190829003018186803b1580156117ed57600080fd5b505afa158015611801573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118259190615623565b61183090600a615c40565b60005560065461185890600080516020615ec0833981519152906001600160a01b0316613b32565b61187e600080516020615ee0833981519152600080516020615ec0833981519152613b3c565b611896600080516020615ec083398151915280613b3c565b61189e613b90565b508015610d57576021805461ff0019169055505050565b600b8181548110610e3f57600080fd5b6000818152601a602052604081208054600390910154610c459184916118eb9190615ceb565b613be8565b600080516020615ee08339815191526119098133613829565b82633b9aca00816001600160401b031611156119375760405162461bcd60e51b8152600401610c7f90615a50565b82633b9aca00816001600160401b031611156119655760405162461bcd60e51b8152600401610c7f90615a50565b836001600160401b0316856001600160401b031611156119ab5760405162461bcd60e51b81526020600482015260016024820152600760fb1b6044820152606401610c7f565b600d80546fffffffffffffffffffffffffffffffff16600160c01b6001600160401b038781169190910267ffffffffffffffff60801b191691909117600160801b91881691820217909155600754604051635b749f3560e01b815260048101929092526001600160a01b031690635b749f3590602401600060405180830381600087803b158015611a3b57600080fd5b505af1158015611a4f573d6000803e3d6000fd5b5050604080516001600160401b03808a168252881660208201527f686faddec2d8b23f0f43c10006482b63941b927c9a98339cd78514b67139ad679350019050611037565b600080516020615ee0833981519152611aad8133613829565b8151611ac0906019906020850190614eb4565b507f6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41ad826040516111279190615a22565b6000610c45826133cf565b60198054611b0890615dbb565b80601f0160208091040260200160405190810160405280929190818152602001828054611b3490615dbb565b8015611b815780601f10611b5657610100808354040283529160200191611b81565b820191906000526020600020905b815481529060010190602001808311611b6457829003601f168201915b505050505081565b60865460ff1615611bac5760405162461bcd60e51b8152600401610c7f90615a6b565b3383611bb8828261356b565b611bd45760405162461bcd60e51b8152600401610c7f90615b19565b6000858152601a6020908152604080832081516080810183528154815260018201549381019390935260028101549183019190915260030154606082015290611c1b61371f565b509050600080611c2c8985856137a4565b915091508060001415611db957600e5460208501514291611c5e91600160801b9091046001600160401b031690615b88565b11158015611c6b57508188105b8015611c7a5750836040015188105b8015611cbf5750600d54600160401b90046001600160401b0316611c9e8984615d39565b611ca89190615ceb565b633b9aca008560600151611cbc9190615ceb565b11155b8015611d0c5750600d546040850151600160401b9091046001600160401b031690611ceb908a90615d39565b611cf59190615ceb565b633b9aca008560600151611d099190615ceb565b11155b611d3d5760405162461bcd60e51b8152602060048201526002602482015261333360f01b6044820152606401610c7f565b6000898152601a6020526040812060020180548a9290611d5e908490615d39565b925050819055507f10c4de39a7e804616cdc1b2dbf59fe6db0ed0d54ff69cef9c8fc024f79c7d47e89898660400151611d979190615d39565b6040805192835260208301919091520160405180910390a1611db98789613c4c565b505050505050505050565b60006001600160a01b038216611dec5760405162461bcd60e51b8152600401610c7f90615a35565b506001600160a01b03166000908152601e602052604090205490565b6007546001600160a01b03163314611e325760405162461bcd60e51b8152600401610c7f90615afe565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60865460ff1615611e775760405162461bcd60e51b8152600401610c7f90615a6b565b6000611e8161371f565b5090506000805b8351811015611f5a576000848281518110611ea557611ea5615e4b565b60200260200101519050611ed0816000908152601d60205260409020546001600160a01b0316151590565b15611f47576000818152601a602090815260408083208151608081018352815481526001820154938101939093526002810154918301919091526003015460608201529080611f208484896137a4565b915091508060011415611f4357611f3682613d9c565b611f409087615b88565b95505b5050505b5080611f5281615df0565b915050611e88565b5060408051338152602081018390527f4a9b62c74532d4448574775253ac495abc6f658b1284e9f28508a23135eeb641910160405180910390a1610d573382613c4c565b600080516020615ee0833981519152611fb78133613829565b838380518251148015611fcb575060008251115b611ffb5760405162461bcd60e51b81526020600482015260016024820152603560f81b6044820152606401610c7f565b60005b6001825161200c9190615d39565b811161214957633b9aca006001600160401b031682828151811061203257612032615e4b565b60200260200101516001600160401b0316111580156120805750633b9aca006001600160401b031683828151811061206c5761206c615e4b565b60200260200101516001600160401b031611155b6120b05760405162461bcd60e51b81526020600482015260016024820152601b60f91b6044820152606401610c7f565b801561213757826120c2600183615d39565b815181106120d2576120d2615e4b565b60200260200101516001600160401b03168382815181106120f5576120f5615e4b565b60200260200101516001600160401b0316116121375760405162461bcd60e51b81526020600482015260016024820152603760f81b6044820152606401610c7f565b8061214181615df0565b915050611ffe565b508360ff1660011415612183578551612169906009906020890190614dfc565b50845161217d90600a906020880190614dfc565b506121ac565b855161219690600b906020890190614dfc565b5084516121aa90600c906020880190614dfc565b505b7f03c94e5b4f32a4b9a2709b098207aebe4cc92c950987ee077776cc2300adcde28686866040516121df939291906159c4565b60405180910390a1505050505050565b600080516020615ee08339815191526122088133613829565b610eee613b90565b6018546001600160a01b0316331461223a5760405162461bcd60e51b8152600401610c7f90615afe565b601880546001600160a01b0319166001600160a01b0383169081179091556040517f1c794a043683a294127c95bc365bae91b63b651eb9884a2c9120afee2bb690b490600090a250565b60009182526022602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6001600160a01b0382163314156122ed5760405162461bcd60e51b8152602060048201526002602482015261199b60f11b6044820152606401610c7f565b336000818152602080805260408083206001600160a01b0387168085529252909120805460ff1916841515179055906001600160a01b03167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051612358911515815260200190565b60405180910390a35050565b600061237260865460ff1690565b1561238f5760405162461bcd60e51b8152600401610c7f90615a6b565b856001600160a01b0381166123b65760405162461bcd60e51b8152600401610c7f90615a35565b600085116123eb5760405162461bcd60e51b8152602060048201526002602482015261323760f01b6044820152606401610c7f565b60065460085461240a916001600160a01b0391821691339116896137eb565b600061241461371f565b9150508481111561244c5760405162461bcd60e51b8152602060048201526002602482015261064760f31b6044820152606401610c7f565b6000805461245a8389615ceb565b6124649190615bcb565b9050600061247389838a613ddf565b9050858110156124aa5760405162461bcd60e51b8152602060048201526002602482015261323960f01b6044820152606401610c7f565b600d546124c8908290600160401b90046001600160401b0316615ceb565b6124d6633b9aca008a615ceb565b11156125095760405162461bcd60e51b8152602060048201526002602482015261033360f41b6044820152606401610c7f565b612517600280546001019055565b6002549450612527856000613f95565b81600160008282546125399190615b88565b909155505060408051608081018252848152426020808301918252828401858152606084018d815260008b8152601a90935294909120925183559051600183015551600282015590516003909101556125928a86613fdb565b6040805186815260208101859052908101829052606081018990527f2af29ed8e180e9bfa65515c22e3af766d15e852ec59b9666d6eeaef8a97565929060800160405180910390a15050505095945050505050565b600080516020615ec08339815191526126008133613829565b60005b855181101561264f5761263d600080516020615ee083398151915287838151811061263057612630615e4b565b602002602001015161388d565b8061264781615df0565b915050612603565b50612668600080516020615ee08339815191528561388d565b60075461268d90600080516020615ee0833981519152906001600160a01b031661388d565b50600480546001600160a01b039384166001600160a01b031991821617909155600380549290931691161790555050565b600080516020615ee08339815191526126d78133613829565b81633b9aca00816001600160401b031611156127055760405162461bcd60e51b8152600401610c7f90615a50565b600e80546001600160c01b0316600160c01b6001600160401b038681168202929092179283905560405192041681527f264a4c2e5ed86659859b3c52d1b00a899950c0f3a637d68ca438cc0216dd89bf906020016115c6565b338261276a828261356b565b6127865760405162461bcd60e51b8152600401610c7f90615b19565b612792868686866140ab565b505050505050565b60865460ff16156127bd5760405162461bcd60e51b8152600401610c7f90615a6b565b6000806127c861371f565b915091506000600760009054906101000a90046001600160a01b03166001600160a01b031663344844db6040518163ffffffff1660e01b815260040160206040518083038186803b15801561281c57600080fd5b505afa158015612830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128549190615521565b600d54909150600090633b9aca009061287d90600160801b90046001600160401b031684615ceb565b6128879190615bcb565b600d54909150633b9aca00906128ad90600160c01b90046001600160401b031684615ceb565b6128b79190615bcb565b600154116128ec5760405162461bcd60e51b81526020600482015260026024820152610ccd60f21b6044820152606401610c7f565b600080600087516001600160401b0381111561290a5761290a615e61565b60405190808252806020026020018201604052801561294f57816020015b60408051808201909152600080825260208201528152602001906001900390816129285790505b50905060005b8851811015612b0b57600089828151811061297257612972615e4b565b6020908102919091018101516000818152601d9092526040909120549091506001600160a01b03168015612af6576000828152601a6020908152604080832081516080810183528154815260018201549381019390935260028101549183019190915260030154606082015290806129eb85848f6137a4565b915091508060011415612a1257612a0182613d9c565b612a0b908a615b88565b9850612adf565b600e5460208401514291612a3791600160801b9091046001600160401b031690615b88565b11612adf57612a4685846140f3565b60006001548b1115612a76578a633b9aca00600154612a659190615ceb565b612a6f9190615bcb565b9050612a7d565b50633b9aca005b600080612a8f8587606001518561414e565b9092509050612a9e818c615b88565b9a506040518060400160405280886001600160a01b03168152602001838152508a8a81518110612ad057612ad0615e4b565b60200260200101819052505050505b8960015411612af2575050505050612b0b565b5050505b50508080612b0390615df0565b915050612955565b5060008415612b4057612b1f856002615ceb565b633b9aca00600154612b319190615ceb565b612b3b9190615bcb565b612b43565b60005b9050633b9aca00612c59826011805480602002602001604051908101604052809291908181526020018280548015612bcc57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411612b895790505b50505050506012805480602002602001604051908101604052809291908181526020018280548015612c4f57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411612c0c5790505b50505050506142c2565b612c6c906001600160401b031685615ceb565b612c769190615bcb565b92506010548310612c8957601054612c8b565b825b92506000633b9aca00612ca089612710615ceb565b612caa9190615ceb565b600054600d548990612cd5906001600160401b03600160801b8204811691600160c01b900416615d50565b612ce0906005615d0a565b6001600160401b0316612cf39190615ceb565b612cfd9190615ceb565b612d079190615bcb565b9050808410612d165780612d18565b835b93507fb789efbabfeba5ae006c34c3b3c17f6b1cf34ab2ac684be93d1e64da000b5be78a8433612d488989615b88565b604051612d589493929190615918565b60405180910390a160005b8a51811015612de8576000848281518110612d8057612d80615e4b565b6020026020010151602001511115612dd657612dd6848281518110612da757612da7615e4b565b602002602001015160000151858381518110612dc557612dc5615e4b565b602002602001015160200151613c4c565b80612de081615df0565b915050612d63565b50612dfc33612df78787615b88565b613c4c565b50505050505050505050565b60098181548110610e3f57600080fd5b6004546001600160a01b03163314612e425760405162461bcd60e51b8152600401610c7f90615afe565b600e80546001600160401b03928316600160401b026001600160801b03199091169290931691909117919091179055565b6000818152601d60205260409020546060906001600160a01b0316612eaa5760405162461bcd60e51b8152600401610c7f90615ae3565b8160005b8115612ed45780612ebe81615df0565b9150612ecd9050600a83615bcb565b9150612eae565b6000816001600160401b03811115612eee57612eee615e61565b6040519080825280601f01601f191660200182016040528015612f18576020820181803683370190505b5090505b8415612f8357612f2d600183615d39565b9150612f3a600a86615e0b565b612f45906030615b88565b60f81b818381518110612f5a57612f5a615e4b565b60200101906001600160f81b031916908160001a905350612f7c600a86615bcb565b9450612f1c565b600060198054612f9290615dbb565b905011612fae5760405180602001604052806000815250612fd2565b601981604051602001612fc29291906157d3565b6040516020818303038152906040525b95945050505050565b60128181548110610e3f57600080fd5b6000828152602260205260409020600101546130078133613829565b610d5783836138f6565b600c8181548110610e3f57600080fd5b6000828152601a60209081526040808320815160808101835281548152600182015493810193909352600281015491830191909152600301546060820152819061306b818561460b565b92509250509250929050565b600080516020615ee08339815191526130908133613829565b816001600160a01b0381166130b75760405162461bcd60e51b8152600401610c7f90615a35565b6015849055601880546001600160a01b0319166001600160a01b0385169081179091556040518581527fe139be2fc520b685c93d718b643b5d8c42fc57b5724201180c5d765635467312906020015b60405180910390a250505050565b60865460ff16156131375760405162461bcd60e51b8152600401610c7f90615a6b565b3383613143828261356b565b61315f5760405162461bcd60e51b8152600401610c7f90615b19565b6000858152601a60209081526040808320815160808101835281548152600182015493810193909352600281015491830191909152600301546060820152906131a661371f565b5090506000806131b78985856137a4565b915091508060001415611db957600e54602085015142916131e991600160801b9091046001600160401b031690615b88565b111561321c5760405162461bcd60e51b8152602060048201526002602482015261333160f01b6044820152606401610c7f565b61322689856140f3565b600061324183866060015161323c6001546146b3565b61414e565b509050878110156132795760405162461bcd60e51b8152602060048201526002602482015261199960f11b6044820152606401610c7f565b604080518b8152602081018390527f2f06d076c30d294b959d7aa34f40d448e45f487492a47889f02831bb06fee6bf910160405180910390a1612dfc8982613c4c565b600080516020615ee08339815191526132d58133613829565b81633b9aca00816001600160401b031611156133035760405162461bcd60e51b8152600401610c7f90615a50565b61330d8385615d0a565b6001600160401b03166133256002633b9aca00615c40565b116133565760405162461bcd60e51b81526020600482015260016024820152600760fb1b6044820152606401610c7f565b600d80546001600160801b031916600160401b6001600160401b0387811691820267ffffffffffffffff1916929092179186169182179092556040805192835260208301919091527fb556fe5cb4a1a8243b8d5000bbefd6f8b868adcac2765cd4a30ac9320ff1a0b6910160405180910390a150505050565b6000818152601d60205260409020546001600160a01b0316806134045760405162461bcd60e51b8152600401610c7f90615ae3565b919050565b6000818152601f6020526040902080546001600160a01b0319166001600160a01b038416908117909155819061343e826133cf565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6040516001600160a01b038316602482015260448101829052610d5790849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526147ac565b6134e48282613f95565b6000828152601c60205260409020548015610d57576000838152601c60209081526040808320839055601d9091529020546005546001600160a01b039182169161353091168284613477565b806001600160a01b03167fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e04868360405161310691815260200190565b600080613577836133cf565b9050806001600160a01b0316846001600160a01b031614806135b257506000838152601f60205260409020546001600160a01b038581169116145b806135e057506001600160a01b038082166000908152602080805260408083209388168352929052205460ff165b949350505050565b826001600160a01b03166135fb826133cf565b6001600160a01b0316146136215760405162461bcd60e51b8152600401610c7f90615afe565b6001600160a01b03821661365c5760405162461bcd60e51b8152602060048201526002602482015261191b60f11b6044820152606401610c7f565b613667600082613409565b6001600160a01b0383166000908152601e60205260408120805460019290613690908490615d39565b90915550506001600160a01b0382166000908152601e602052604081208054600192906136be908490615b88565b90915550506000818152601d602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600354604080516341f654f760e01b8152815160009384936001600160a01b03909116926341f654f79260048083019392829003018186803b15801561376457600080fd5b505afa158015613778573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061379c9190615583565b915091509091565b60008060008060006137b6878761460b565b9150915081600014806137c95750806001145b156137dd576137d888886140f3565b600192505b50925090505b935093915050565b6040516001600160a01b03808516602483015283166044820152606481018290526138239085906323b872dd60e01b906084016134a3565b50505050565b6138338282612284565b6110b35761384b816001600160a01b0316601461487e565b61385683602061487e565b604051602001613867929190615871565b60408051601f198184030181529082905262461bcd60e51b8252610c7f91600401615a22565b6138978282612284565b6110b35760008281526022602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b6139008282612284565b156110b35760008281526022602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600060015460001415613971575060175490565b600154670de0b6b3a764000060145460165461398b614a19565b6139959190615d39565b61399f9190615ceb565b6139a99190615ceb565b6139b39190615bcb565b6017546139c09190615b88565b905090565b60865460ff16613a0e5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610c7f565b6086805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b602154610100900460ff1680613a71575060215460ff16155b613a8d5760405162461bcd60e51b8152600401610c7f90615a95565b602154610100900460ff16158015613aaf576021805461ffff19166101011790555b613ab7614a34565b613abf614a9e565b8015610eee576021805461ff001916905550565b602154610100900460ff1680613aec575060215460ff16155b613b085760405162461bcd60e51b8152600401610c7f90615a95565b602154610100900460ff16158015613b2a576021805461ffff19166101011790555b613abf614a34565b6110b3828261388d565b600082815260226020526040902060010154819060405184907fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff90600090a460009182526022602052604090912060010155565b60865460ff1615613bb35760405162461bcd60e51b8152600401610c7f90615a6b565b6086805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613a3b3390565b6000828152601c60209081526040808320548354601b90935290832054909190670de0b6b3a764000090613c1a61395d565b613c249190615d39565b613c2e9086615ceb565b613c389190615bcb565b613c429190615bcb565b61152e9190615b88565b60065460408051629032ff60e51b815290516000926001600160a01b0316916312065fe0916004808301926020929190829003018186803b158015613c9057600080fd5b505afa158015613ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cc89190615521565b9050818110158015613cda5750600082115b15613cfd57600654600854610d57916001600160a01b03918216911685856137eb565b8115610d57576000613d0f8284615d39565b600654600854919250613d30916001600160a01b03908116911686856137eb565b600754604051631a115ff160e01b8152600481018390526001600160a01b03868116602483015290911690631a115ff190604401600060405180830381600087803b158015613d7e57600080fd5b505af1158015613d92573d6000803e3d6000fd5b5050505050505050565b600e54600090633b9aca0090613dc290600160c01b90046001600160401b031684615ceb565b613dcc9190615bcb565b9050600f54811061340457600f54610c45565b600080613df884600154613df39190615b88565b6146b3565b9050633b9aca006001600160401b03821610613e3b5760405162461bcd60e51b8152602060048201526002602482015261323560f01b6044820152606401610c7f565b6000633b9aca00613f27836009805480602002602001604051908101604052809291908181526020018280548015613ec457602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411613e815790505b5050505050600a805480602002602001604051908101604052809291908181526020018280548015612c4f57600091825260209182902080546001600160401b03168452908202830192909160089101808411612c0c57905050505050506142c2565b600e54613f3d91906001600160401b0316615d0a565b6001600160401b0316613f509190615bcb565b9050633b9aca00613f618282615d39565b613f6b9086615ceb565b613f759190615bcb565b613f7f9085615d39565b9050613f8b8187615d39565b9695505050505050565b613f9d61395d565b601755613fa8614a19565b601655613fb58282613be8565b6000928352601c6020908152604080852092909255601754601b90915292209190915550565b6001600160a01b0382166000908152601e60205260408120805460019290614004908490615b88565b90915550506000818152601d602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a461407a6000838360405180602001604052806000815250614b13565b6110b35760405162461bcd60e51b81526020600482015260026024820152610c8d60f21b6044820152606401610c7f565b6140b68484846135e8565b6140c284848484614b13565b6138235760405162461bcd60e51b81526020600482015260026024820152610c8d60f21b6044820152606401610c7f565b8051606082015160009161410691615ceb565b905061411283826134da565b6000838152601b602052604081208190555461412e9082615bcb565b6001600082825461413f9190615d39565b90915550610d57905083614c35565b600080633b9aca0061423b84600b8054806020026020016040519081016040528092919081815260200182805480156141d857602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116141955790505b5050505050600c805480602002602001604051908101604052809291908181526020018280548015612c4f57600091825260209182902080546001600160401b03168452908202830192909160089101808411612c0c57905050505050506142c2565b600e546142589190600160401b90046001600160401b0316615d0a565b6001600160401b031661426b9190615bcb565b9050633b9aca0061427c8282615d39565b6142869086615ceb565b6142909190615bcb565b61429a9085615d39565b90508481106142ae575060009050836137e3565b6142b88186615d39565b9150935093915050565b600082600184516142d39190615d39565b815181106142e3576142e3615e4b565b60200260200101516001600160401b0316846001600160401b0316106143315781600184516143129190615d39565b8151811061432257614322615e4b565b6020026020010151905061152e565b8260008151811061434457614344615e4b565b60200260200101516001600160401b0316846001600160401b031611614377578160008151811061432257614322615e4b565b600080600185516143889190615d39565b905060005b60016143998484615d39565b11156144035760026143ab8484615d39565b6143b59190615bcb565b6143bf9084615b88565b9050866001600160401b03168682815181106143dd576143dd615e4b565b60200260200101516001600160401b0316116143fb5780925061438d565b80915061438d565b84838151811061441557614415615e4b565b60200260200101516001600160401b031685838151811061443857614438615e4b565b60200260200101516001600160401b031611156145325785838151811061446157614461615e4b565b602002602001015186838151811061447b5761447b615e4b565b602002602001015161448d9190615d50565b86848151811061449f5761449f615e4b565b6020026020010151886144b29190615d50565b8685815181106144c4576144c4615e4b565b60200260200101518785815181106144de576144de615e4b565b60200260200101516144f09190615d50565b6144fa9190615d0a565b6145049190615bdf565b85848151811061451657614516615e4b565b60200260200101516145289190615ba0565b935050505061152e565b85838151811061454457614544615e4b565b602002602001015186838151811061455e5761455e615e4b565b60200260200101516145709190615d50565b86848151811061458257614582615e4b565b6020026020010151886145959190615d50565b8684815181106145a7576145a7615e4b565b60200260200101518786815181106145c1576145c1615e4b565b60200260200101516145d39190615d50565b6145dd9190615d0a565b6145e79190615bdf565b8584815181106145f9576145f9615e4b565b60200260200101516145289190615d50565b600080600083856000015186606001516146259190615ceb565b61462f9190615bcb565b9050846040015185606001516146459190615b88565b811061465457600092506146ab565b80856040015186606001516146699190615b88565b6146739190615d39565b600d546060870151919450614693916001600160401b0390911690615ceb565b6146a1633b9aca0085615ceb565b116146ab57600191505b509250929050565b600080633b9aca00600d60109054906101000a90046001600160401b03166001600160401b0316600760009054906101000a90046001600160a01b03166001600160a01b031663344844db6040518163ffffffff1660e01b815260040160206040518083038186803b15801561472857600080fd5b505afa15801561473c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147609190615521565b61476a9190615ceb565b6147749190615bcb565b90508083101561479e578061478d633b9aca0085615ceb565b6147979190615bcb565b91506147a6565b633b9aca0091505b50919050565b6000614801826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614cf19092919063ffffffff16565b805190915015610d57578080602001905181019061481f9190615444565b610d575760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610c7f565b6060600061488d836002615ceb565b614898906002615b88565b6001600160401b038111156148af576148af615e61565b6040519080825280601f01601f1916602001820160405280156148d9576020820181803683370190505b509050600360fc1b816000815181106148f4576148f4615e4b565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061492357614923615e4b565b60200101906001600160f81b031916908160001a9053506000614947846002615ceb565b614952906001615b88565b90505b60018111156149ca576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061498657614986615e4b565b1a60f81b82828151811061499c5761499c615e4b565b60200101906001600160f81b031916908160001a90535060049490941c936149c381615da4565b9050614955565b50831561152e5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610c7f565b6000806013544210614a2d57601354610c45565b4292915050565b602154610100900460ff1680614a4d575060215460ff16155b614a695760405162461bcd60e51b8152600401610c7f90615a95565b602154610100900460ff16158015613abf576021805461ffff19166101011790558015610eee576021805461ff001916905550565b602154610100900460ff1680614ab7575060215460ff16155b614ad35760405162461bcd60e51b8152600401610c7f90615a95565b602154610100900460ff16158015614af5576021805461ffff19166101011790555b6086805460ff191690558015610eee576021805461ff001916905550565b60006001600160a01b0384163b15614c2a57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290614b579033908990889088906004016158e6565b602060405180830381600087803b158015614b7157600080fd5b505af1925050508015614ba1575060408051601f3d908101601f19168201909252614b9e918101906154bc565b60015b614c10573d808015614bcf576040519150601f19603f3d011682016040523d82523d6000602084013e614bd4565b606091505b508051614c085760405162461bcd60e51b81526020600482015260026024820152610c8d60f21b6044820152606401610c7f565b805181602001fd5b6001600160e01b031916630a85bd0160e11b1490506135e0565b506001949350505050565b6000614c40826133cf565b9050614c4d600083613409565b6001600160a01b0381166000908152601e60205260408120805460019290614c76908490615d39565b90915550506000828152601d6020908152604080832080546001600160a01b0319169055601a9091528082208281556001810183905560028101839055600301829055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b60606135e0848460008585843b614d4a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c7f565b600080866001600160a01b03168587604051614d6691906157b7565b60006040518083038185875af1925050503d8060008114614da3576040519150601f19603f3d011682016040523d82523d6000602084013e614da8565b606091505b5091509150614db8828286614dc3565b979650505050505050565b60608315614dd257508161152e565b825115614de25782518084602001fd5b8160405162461bcd60e51b8152600401610c7f9190615a22565b82805482825590600052602060002090600301600490048101928215614ea45791602002820160005b83821115614e6f57835183826101000a8154816001600160401b0302191690836001600160401b031602179055509260200192600801602081600701049283019260010302614e25565b8015614ea25782816101000a8154906001600160401b030219169055600801602081600701049283019260010302614e6f565b505b50614eb0929150614f28565b5090565b828054614ec090615dbb565b90600052602060002090601f016020900481019282614ee25760008555614ea4565b82601f10614efb57805160ff1916838001178555614ea4565b82800160010185558215614ea4579182015b82811115614ea4578251825591602001919060010190614f0d565b5b80821115614eb05760008155600101614f29565b60006001600160401b03831115614f5657614f56615e61565b614f69601f8401601f1916602001615b35565b9050828152838383011115614f7d57600080fd5b828260208301376000602084830101529392505050565b803561340481615e77565b600082601f830112614fb057600080fd5b81356020614fc5614fc083615b65565b615b35565b80838252828201915082860187848660051b8901011115614fe557600080fd5b60005b8581101561500b57614ff982615018565b84529284019290840190600101614fe8565b5090979650505050505050565b80356001600160401b038116811461340457600080fd5b60006020828403121561504157600080fd5b813561152e81615e77565b60006020828403121561505e57600080fd5b815161152e81615e77565b6000806040838503121561507c57600080fd5b823561508781615e77565b9150602083013561509781615e77565b809150509250929050565b6000806000606084860312156150b757600080fd5b83356150c281615e77565b925060208401356150d281615e77565b929592945050506040919091013590565b600080600080608085870312156150f957600080fd5b843561510481615e77565b9350602085013561511481615e77565b92506040850135915060608501356001600160401b0381111561513657600080fd5b8501601f8101871361514757600080fd5b61515687823560208401614f3d565b91505092959194509250565b6000806040838503121561517557600080fd5b823561518081615e77565b9150602083013561509781615e8c565b600080604083850312156151a357600080fd5b82356151ae81615e77565b946020939093013593505050565b600080600080600060a086880312156151d457600080fd5b85356151df81615e77565b97602087013597506040870135966060810135965060800135945092505050565b6000806000806080858703121561521657600080fd5b84356001600160401b0381111561522c57600080fd5b8501601f8101871361523d57600080fd5b8035602061524d614fc083615b65565b8083825282820191508285018b848660051b880101111561526d57600080fd5b600095505b8486101561529957803561528581615e77565b835260019590950194918301918301615272565b5097506152a99050888201614f94565b95505050506152ba60408601614f94565b91506152c860608601614f94565b905092959194509250565b600060208083850312156152e657600080fd5b82356001600160401b038111156152fc57600080fd5b8301601f8101851361530d57600080fd5b803561531b614fc082615b65565b80828252848201915084840188868560051b870101111561533b57600080fd5b600094505b8385101561535e578035835260019490940193918501918501615340565b50979650505050505050565b6000806040838503121561537d57600080fd5b82356001600160401b038082111561539457600080fd5b6153a086838701614f9f565b935060208501359150808211156153b657600080fd5b506153c385828601614f9f565b9150509250929050565b6000806000606084860312156153e257600080fd5b83356001600160401b03808211156153f957600080fd5b61540587838801614f9f565b9450602086013591508082111561541b57600080fd5b5061542886828701614f9f565b925050604084013561543981615eb0565b809150509250925092565b60006020828403121561545657600080fd5b815161152e81615e8c565b60006020828403121561547357600080fd5b5035919050565b6000806040838503121561548d57600080fd5b82359150602083013561509781615e77565b6000602082840312156154b157600080fd5b813561152e81615e9a565b6000602082840312156154ce57600080fd5b815161152e81615e9a565b6000602082840312156154eb57600080fd5b81356001600160401b0381111561550157600080fd5b8201601f8101841361551257600080fd5b6135e084823560208401614f3d565b60006020828403121561553357600080fd5b5051919050565b60008060006060848603121561554f57600080fd5b8335925060208401356150d281615e77565b6000806040838503121561557457600080fd5b50508035926020909101359150565b6000806040838503121561559657600080fd5b505080516020909101519092909150565b6000806000606084860312156155bc57600080fd5b8335925060208401359150604084013561543981615e77565b6000602082840312156155e757600080fd5b61152e82615018565b6000806040838503121561560357600080fd5b61560c83615018565b915061561a60208401615018565b90509250929050565b60006020828403121561563557600080fd5b815161152e81615eb0565b600081518084526020808501945080840160005b838110156156795781516001600160401b031687529582019590820190600101615654565b509495945050505050565b805480835260008281526020808220940193909190825b826003820110156156ea5781546001600160401b038082168852604082811c821660208a0152608083811c9092169089015260c09190911c60608801529095019460019091019060040161569b565b9054908281101561570b576001600160401b03821686526020909501946001015b8281101561572d576001600160401b03604083901c1686526020909501946001015b8281101561574f576001600160401b03608083901c1686526020909501946001015b828110156157655760c082901c86526020860195505b5093949350505050565b60008151808452615787816020860160208601615d78565b601f01601f19169290920160200192915050565b600081516157ad818560208601615d78565b9290920192915050565b600082516157c9818460208701615d78565b9190910192915050565b600080845481600182811c9150808316806157ef57607f831692505b602080841082141561580f57634e487b7160e01b86526022600452602486fd5b818015615823576001811461583457615861565b60ff19861689528489019650615861565b60008b81526020902060005b868110156158595781548b820152908501908301615840565b505084890196505b505050505050612fd2818561579b565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516158a9816017850160208801615d78565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516158da816028840160208801615d78565b01602801949350505050565b60006001600160a01b03808716835280861660208401525083604083015260806060830152613f8b608083018461576f565b6080808252855190820181905260009060209060a0840190828901845b8281101561595157815184529284019290840190600101615935565b5050508381038285015286518082528783019183019060005b8181101561599a57835180516001600160a01b03168452850151858401529284019260409092019160010161596a565b50506001600160a01b038716604086015292506159b5915050565b82606083015295945050505050565b6060815260006159d76060830186615640565b82810360208401526159e98186615640565b91505060ff83166040830152949350505050565b604081526000615a106040830185615684565b8281036020840152612fd28185615684565b60208152600061152e602083018461576f565b6020808252600190820152600360fc1b604082015260600190565b6020808252600190820152600d60fa1b604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252600190820152601960f91b604082015260600190565b6020808252600190820152603160f81b604082015260600190565b602080825260029082015261323160f01b604082015260600190565b604051601f8201601f191681016001600160401b0381118282101715615b5d57615b5d615e61565b604052919050565b60006001600160401b03821115615b7e57615b7e615e61565b5060051b60200190565b60008219821115615b9b57615b9b615e1f565b500190565b60006001600160401b03808316818516808303821115615bc257615bc2615e1f565b01949350505050565b600082615bda57615bda615e35565b500490565b60006001600160401b0380841680615bf957615bf9615e35565b92169190910492915050565b600181815b808511156146ab578160001904821115615c2657615c26615e1f565b80851615615c3357918102915b93841c9390800290615c0a565b600061152e60ff841683600082615c5957506001610c45565b81615c6657506000610c45565b8160018114615c7c5760028114615c8657615ca2565b6001915050610c45565b60ff841115615c9757615c97615e1f565b50506001821b610c45565b5060208310610133831016604e8410600b8410161715615cc5575081810a610c45565b615ccf8383615c05565b8060001904821115615ce357615ce3615e1f565b029392505050565b6000816000190483118215151615615d0557615d05615e1f565b500290565b60006001600160401b0380831681851681830481118215151615615d3057615d30615e1f565b02949350505050565b600082821015615d4b57615d4b615e1f565b500390565b60006001600160401b0383811690831681811015615d7057615d70615e1f565b039392505050565b60005b83811015615d93578181015183820152602001615d7b565b838111156138235750506000910152565b600081615db357615db3615e1f565b506000190190565b600181811c90821680615dcf57607f821691505b602082108114156147a657634e487b7160e01b600052602260045260246000fd5b6000600019821415615e0457615e04615e1f565b5060010190565b600082615e1a57615e1a615e35565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610eee57600080fd5b8015158114610eee57600080fd5b6001600160e01b031981168114610eee57600080fd5b60ff81168114610eee57600080fdfe5916f72c85af4ac6f7e34636ecc97619c4b2085da099a5d28f3e58436cfbe56255435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041a26469706673582212206a35e934a4939c3da2e9a75fb51b6129babcae1a26cd0fb89845202edc12f28d64736f6c63430008070033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106104a15760003560e01c80637bd06a151161026d578063c0212c7211610151578063df136d65116100ce578063e985e9c511610092578063e985e9c514610a94578063ebe2b12b14610ace578063f301af4214610ad7578063f5d011c514610af7578063f7c618c114610b0a578063f902fad714610b1d57600080fd5b8063df136d6514610a2e578063df1b8bd314610a37578063e048684214610a46578063e2b01a5e14610a6e578063e5234c7a14610a8157600080fd5b8063d1aace9f11610115578063d1aace9f146109cf578063d547741f146109e2578063d5eb0581146109f5578063d7f6328e14610a08578063dc4c90d314610a1b57600080fd5b8063c0212c721461097a578063c1618dda1461098d578063c628a6f7146109a0578063c87b56dd146109b3578063c8f33c91146109c657600080fd5b806395d89b41116101ea578063ae3302c2116101ae578063ae3302c21461090b578063b126e7e514610925578063b3b1cb2714610938578063b88d4fde1461094b578063b8f368951461095e578063bcb01a801461096757600080fd5b806395d89b41146104ce5780639f48118f146108d2578063a217fddf146108dd578063a22cb465146108e5578063a62b2a3d146108f857600080fd5b8063873291bb11610231578063873291bb1461086f5780638c6dfaf7146108825780638d5e19f11461088b5780638e240144146108a557806391d14854146108bf57600080fd5b80637bd06a15146108185780637dc0d1d0146108215780638211477a14610834578063840a7698146108475780638456cb591461086757600080fd5b8063386a9525116103945780634d6ed8c4116103115780636c0360eb116102d55780636c0360eb146107bb5780636d59dae7146107c357806370a08231146107d65780637adbf973146107e95780637b0a47ee146107fc5780637b39ecf71461080557600080fd5b80634d6ed8c414610764578063515dc4801461077757806355f804b31461078a5780635c975abb1461079d5780636352211e146107a857600080fd5b8063430c208111610358578063430c208114610705578063472d35b91461071857806347c12e011461072b578063485cc9551461073e57806349a5d3ef1461075157600080fd5b8063386a9525146106bb5780633c6b16ab146106c45780633f4ba83a146106d75780633fc6df6e146106df57806342842e0e146106f257600080fd5b806323b872dd11610422578063324f3815116103e6578063324f38151461065557806336568abe1461066f5780633675441514610682578063367f21b41461069557806338050129146106a857600080fd5b806323b872dd146105e4578063248a9ca3146105f757806324d83b791461061a57806324ea54f41461062d5780632f2ff15d1461064257600080fd5b80630c016dc0116104695780630c016dc01461056e5780630d668087146105915780631171bda9146105ab578063142c3ba0146105be5780631c4b774b146105d157600080fd5b806301ffc9a7146104a657806306fdde03146104ce578063081812fc146104fc578063095ea7b3146105275780630bfab8a71461053c575b600080fd5b6104b96104b436600461549f565b610b72565b60405190151581526020015b60405180910390f35b6040805180820190915260098152680416e676c65506572760bc1b60208201525b6040516104c59190615a22565b61050f61050a366004615461565b610c4b565b6040516001600160a01b0390911681526020016104c5565b61053a610535366004615190565b610ca5565b005b600e5461055690600160c01b90046001600160401b031681565b6040516001600160401b0390911681526020016104c5565b610583600080516020615ec083398151915281565b6040519081526020016104c5565b600e5461055690600160801b90046001600160401b031681565b61053a6105b93660046150a2565b610d5c565b6105566105cc366004615461565b610e2f565b61053a6105df366004615461565b610e6c565b61053a6105f23660046150a2565b610ef1565b610583610605366004615461565b60009081526022602052604090206001015490565b61053a610628366004615561565b610f2b565b610583600080516020615ee083398151915281565b61053a61065036600461547a565b611046565b600d5461055690600160c01b90046001600160401b031681565b61053a61067d36600461547a565b61106c565b61053a6106903660046155d5565b6110b7565b61053a6106a336600461536a565b611133565b6105566106b6366004615461565b61133a565b61058360155481565b61053a6106d2366004615461565b61134a565b61053a6114e6565b60185461050f906001600160a01b031681565b61053a6107003660046150a2565b611507565b6104b9610713366004615190565b611522565b61053a61072636600461502f565b611535565b61053a610739366004615561565b611571565b61053a61074c366004615069565b6115d3565b61055661075f366004615461565b6118b5565b610583610772366004615461565b6118c5565b61053a6107853660046155f0565b6118f0565b61053a6107983660046154d9565b611a94565b60865460ff166104b9565b61050f6107b6366004615461565b611af0565b6104ef611afb565b61053a6107d13660046155a7565b611b89565b6105836107e436600461502f565b611dc4565b61053a6107f736600461502f565b611e08565b61058360145481565b61053a6108133660046152d3565b611e54565b610583600f5481565b60035461050f906001600160a01b031681565b61053a6108423660046153cd565b611f9e565b610583610855366004615461565b601b6020526000908152604090205481565b61053a6121ef565b61053a61087d36600461502f565b612210565b61058360105481565b600d5461055690600160801b90046001600160401b031681565b600e5461055690600160401b90046001600160401b031681565b6104b96108cd36600461547a565b612284565b610583633b9aca0081565b610583600081565b61053a6108f3366004615162565b6122af565b6105836109063660046151bc565b612364565b600d5461055690600160401b90046001600160401b031681565b61053a610933366004615200565b6125e7565b61053a6109463660046155d5565b6126be565b61053a6109593660046150e3565b61275e565b61058360015481565b61053a6109753660046152d3565b61279a565b600e54610556906001600160401b031681565b61055661099b366004615461565b612e08565b61053a6109ae3660046155f0565b612e18565b6104ef6109c1366004615461565b612e73565b61058360165481565b6105566109dd366004615461565b612fdb565b61053a6109f036600461547a565b612feb565b600d54610556906001600160401b031681565b610556610a16366004615461565b613011565b60065461050f906001600160a01b031681565b61058360175481565b610583670de0b6b3a764000081565b610a59610a54366004615561565b613021565b604080519283526020830191909152016104c5565b61053a610a7c36600461547a565b613077565b61053a610a8f36600461553a565b613114565b6104b9610aa2366004615069565b6001600160a01b0391821660009081526020808052604080832093909416825291909152205460ff1690565b61058360135481565b610583610ae5366004615461565b601c6020526000908152604090205481565b61053a610b053660046155f0565b6132bc565b60055461050f906001600160a01b031681565b610b52610b2b366004615461565b601a6020526000908152604090208054600182015460028301546003909301549192909184565b6040805194855260208501939093529183015260608201526080016104c5565b60006001600160e01b03198216636e44396d60e01b1480610ba357506001600160e01b03198216632303fc0360e01b145b80610bbe57506001600160e01b0319821663f7c618c160e01b145b80610bd957506001600160e01b0319821663aa283ab960e01b145b80610bf457506001600160e01b03198216637965db0b60e01b145b80610c0f57506001600160e01b03198216635b5e139f60e01b145b80610c2a57506001600160e01b031982166380ac58cd60e01b145b80610c4557506001600160e01b031982166301ffc9a760e01b145b92915050565b6000818152601d60205260408120546001600160a01b0316610c885760405162461bcd60e51b8152600401610c7f90615ae3565b60405180910390fd5b6000828152601f60205260409020546001600160a01b0316610c45565b6000610cb0826133cf565b9050806001600160a01b0316836001600160a01b03161415610cf95760405162461bcd60e51b8152602060048201526002602482015261333560f01b6044820152606401610c7f565b336001600160a01b0382161480610d3157506001600160a01b03811660009081526020808052604080832033845290915290205460ff165b610d4d5760405162461bcd60e51b8152600401610c7f90615b19565b610d578383613409565b505050565b6018546001600160a01b03163314610d865760405162461bcd60e51b8152600401610c7f90615afe565b6005546001600160a01b0384811691161415610dc95760405162461bcd60e51b8152602060048201526002602482015261032360f41b6044820152606401610c7f565b610ddd6001600160a01b0384168383613477565b816001600160a01b0316836001600160a01b03167ffff3b3844276f57024e0b42afec1a37f75db36511e43819a4f2a63ab7862b64883604051610e2291815260200190565b60405180910390a3505050565b600a8181548110610e3f57600080fd5b9060005260206000209060049182820401919006600802915054906101000a90046001600160401b031681565b60865460ff1615610e8f5760405162461bcd60e51b8152600401610c7f90615a6b565b6000818152601d60205260409020546001600160a01b0316610ec35760405162461bcd60e51b8152600401610c7f90615ae3565b6000818152601a602052604090208054600390910154610eee918391610ee99190615ceb565b6134da565b50565b3381610efd828261356b565b610f195760405162461bcd60e51b8152600401610c7f90615b19565b610f248585856135e8565b5050505050565b60865460ff1615610f4e5760405162461bcd60e51b8152600401610c7f90615a6b565b6000828152601a6020908152604080832081516080810183528154815260018201549381019390935260028101549183019190915260030154606082015290610f9561371f565b5090506000610fa58584846137a4565b91505080610f2457600654600854610fcc916001600160a01b0391821691339116876137eb565b6000858152601a602052604081206002018054869290610fed908490615b88565b925050819055507f10c4de39a7e804616cdc1b2dbf59fe6db0ed0d54ff69cef9c8fc024f79c7d47e858585604001516110269190615b88565b604080519283526020830191909152015b60405180910390a15050505050565b6000828152602260205260409020600101546110628133613829565b610d57838361388d565b6001600160a01b03811633146110a95760405162461bcd60e51b8152602060048201526002602482015261373160f01b6044820152606401610c7f565b6110b382826138f6565b5050565b600080516020615ee08339815191526110d08133613829565b600e805467ffffffffffffffff60801b1916600160801b6001600160401b038516908102919091179091556040519081527f0cedd128b637e635da421319ae981d7968b7a477c1fa3b10275fac22ecbd51a6906020015b60405180910390a15050565b600080516020615ee083398151915261114c8133613829565b828280518251148015611160575060008251115b6111905760405162461bcd60e51b81526020600482015260016024820152603560f81b6044820152606401610c7f565b60005b600182516111a19190615d39565b81116112de57633b9aca006001600160401b03168282815181106111c7576111c7615e4b565b60200260200101516001600160401b0316111580156112155750633b9aca006001600160401b031683828151811061120157611201615e4b565b60200260200101516001600160401b031611155b6112455760405162461bcd60e51b81526020600482015260016024820152601b60f91b6044820152606401610c7f565b80156112cc5782611257600183615d39565b8151811061126757611267615e4b565b60200260200101516001600160401b031683828151811061128a5761128a615e4b565b60200260200101516001600160401b0316116112cc5760405162461bcd60e51b81526020600482015260016024820152603760f81b6044820152606401610c7f565b806112d681615df0565b915050611193565b5084516112f2906011906020880190614dfc565b508351611306906012906020870190614dfc565b507f275781d4ec4992e53f64326606b9f7eb81a89baf476df8de6d0410fd218e7be3601160126040516110379291906159fd565b60118181548110610e3f57600080fd5b6018546001600160a01b031633146113745760405162461bcd60e51b8152600401610c7f90615afe565b61137c61395d565b601755601354421061139d576015546113959082615bcb565b6014556113df565b6000426013546113ad9190615d39565b90506000601454826113bf9190615ceb565b6015549091506113cf8285615b88565b6113d99190615bcb565b60145550505b6005546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b15801561142357600080fd5b505afa158015611437573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145b9190615521565b90506015548161146b9190615bcb565b60145411156114a15760405162461bcd60e51b8152602060048201526002602482015261191960f11b6044820152606401610c7f565b4260168190556015546114b391615b88565b6013556040518281527fde88a922e0d3b88b24e9623efeb464919c6bf9f66857a65e2bfcf2ce87a9433d90602001611127565b600080516020615ee08339815191526114ff8133613829565b610eee6139c5565b610d578383836040518060200160405280600081525061275e565b600061152e838361356b565b9392505050565b600080516020615ec083398151915261154e8133613829565b50600480546001600160a01b0319166001600160a01b0392909216919091179055565b600080516020615ee083398151915261158a8133613829565b600f839055601082905560408051848152602081018490527fa0aa01eac9422dea36b84eb0bbc758e72643fbdbc72a4fd205d51c738803598291015b60405180910390a1505050565b602154610100900460ff16806115ec575060215460ff16155b6116085760405162461bcd60e51b8152600401610c7f90615a95565b602154610100900460ff1615801561162a576021805461ffff19166101011790555b816001600160a01b0381166116515760405162461bcd60e51b8152600401610c7f90615a35565b611659613a58565b611661613ad3565b600680546001600160a01b0319166001600160a01b03861690811790915560408051637e062a3560e11b8152905163fc0c546a91600480820192602092909190829003018186803b1580156116b557600080fd5b505afa1580156116c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ed919061504c565b600860006101000a8154816001600160a01b0302191690836001600160a01b03160217905550836001600160a01b0316636ac5dc466040518163ffffffff1660e01b815260040160206040518083038186803b15801561174c57600080fd5b505afa158015611760573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611784919061504c565b600780546001600160a01b03199081166001600160a01b0393841617909155600580549091168583161790556008546040805163313ce56760e01b81529051919092169163313ce567916004808301926020929190829003018186803b1580156117ed57600080fd5b505afa158015611801573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118259190615623565b61183090600a615c40565b60005560065461185890600080516020615ec0833981519152906001600160a01b0316613b32565b61187e600080516020615ee0833981519152600080516020615ec0833981519152613b3c565b611896600080516020615ec083398151915280613b3c565b61189e613b90565b508015610d57576021805461ff0019169055505050565b600b8181548110610e3f57600080fd5b6000818152601a602052604081208054600390910154610c459184916118eb9190615ceb565b613be8565b600080516020615ee08339815191526119098133613829565b82633b9aca00816001600160401b031611156119375760405162461bcd60e51b8152600401610c7f90615a50565b82633b9aca00816001600160401b031611156119655760405162461bcd60e51b8152600401610c7f90615a50565b836001600160401b0316856001600160401b031611156119ab5760405162461bcd60e51b81526020600482015260016024820152600760fb1b6044820152606401610c7f565b600d80546fffffffffffffffffffffffffffffffff16600160c01b6001600160401b038781169190910267ffffffffffffffff60801b191691909117600160801b91881691820217909155600754604051635b749f3560e01b815260048101929092526001600160a01b031690635b749f3590602401600060405180830381600087803b158015611a3b57600080fd5b505af1158015611a4f573d6000803e3d6000fd5b5050604080516001600160401b03808a168252881660208201527f686faddec2d8b23f0f43c10006482b63941b927c9a98339cd78514b67139ad679350019050611037565b600080516020615ee0833981519152611aad8133613829565b8151611ac0906019906020850190614eb4565b507f6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41ad826040516111279190615a22565b6000610c45826133cf565b60198054611b0890615dbb565b80601f0160208091040260200160405190810160405280929190818152602001828054611b3490615dbb565b8015611b815780601f10611b5657610100808354040283529160200191611b81565b820191906000526020600020905b815481529060010190602001808311611b6457829003601f168201915b505050505081565b60865460ff1615611bac5760405162461bcd60e51b8152600401610c7f90615a6b565b3383611bb8828261356b565b611bd45760405162461bcd60e51b8152600401610c7f90615b19565b6000858152601a6020908152604080832081516080810183528154815260018201549381019390935260028101549183019190915260030154606082015290611c1b61371f565b509050600080611c2c8985856137a4565b915091508060001415611db957600e5460208501514291611c5e91600160801b9091046001600160401b031690615b88565b11158015611c6b57508188105b8015611c7a5750836040015188105b8015611cbf5750600d54600160401b90046001600160401b0316611c9e8984615d39565b611ca89190615ceb565b633b9aca008560600151611cbc9190615ceb565b11155b8015611d0c5750600d546040850151600160401b9091046001600160401b031690611ceb908a90615d39565b611cf59190615ceb565b633b9aca008560600151611d099190615ceb565b11155b611d3d5760405162461bcd60e51b8152602060048201526002602482015261333360f01b6044820152606401610c7f565b6000898152601a6020526040812060020180548a9290611d5e908490615d39565b925050819055507f10c4de39a7e804616cdc1b2dbf59fe6db0ed0d54ff69cef9c8fc024f79c7d47e89898660400151611d979190615d39565b6040805192835260208301919091520160405180910390a1611db98789613c4c565b505050505050505050565b60006001600160a01b038216611dec5760405162461bcd60e51b8152600401610c7f90615a35565b506001600160a01b03166000908152601e602052604090205490565b6007546001600160a01b03163314611e325760405162461bcd60e51b8152600401610c7f90615afe565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60865460ff1615611e775760405162461bcd60e51b8152600401610c7f90615a6b565b6000611e8161371f565b5090506000805b8351811015611f5a576000848281518110611ea557611ea5615e4b565b60200260200101519050611ed0816000908152601d60205260409020546001600160a01b0316151590565b15611f47576000818152601a602090815260408083208151608081018352815481526001820154938101939093526002810154918301919091526003015460608201529080611f208484896137a4565b915091508060011415611f4357611f3682613d9c565b611f409087615b88565b95505b5050505b5080611f5281615df0565b915050611e88565b5060408051338152602081018390527f4a9b62c74532d4448574775253ac495abc6f658b1284e9f28508a23135eeb641910160405180910390a1610d573382613c4c565b600080516020615ee0833981519152611fb78133613829565b838380518251148015611fcb575060008251115b611ffb5760405162461bcd60e51b81526020600482015260016024820152603560f81b6044820152606401610c7f565b60005b6001825161200c9190615d39565b811161214957633b9aca006001600160401b031682828151811061203257612032615e4b565b60200260200101516001600160401b0316111580156120805750633b9aca006001600160401b031683828151811061206c5761206c615e4b565b60200260200101516001600160401b031611155b6120b05760405162461bcd60e51b81526020600482015260016024820152601b60f91b6044820152606401610c7f565b801561213757826120c2600183615d39565b815181106120d2576120d2615e4b565b60200260200101516001600160401b03168382815181106120f5576120f5615e4b565b60200260200101516001600160401b0316116121375760405162461bcd60e51b81526020600482015260016024820152603760f81b6044820152606401610c7f565b8061214181615df0565b915050611ffe565b508360ff1660011415612183578551612169906009906020890190614dfc565b50845161217d90600a906020880190614dfc565b506121ac565b855161219690600b906020890190614dfc565b5084516121aa90600c906020880190614dfc565b505b7f03c94e5b4f32a4b9a2709b098207aebe4cc92c950987ee077776cc2300adcde28686866040516121df939291906159c4565b60405180910390a1505050505050565b600080516020615ee08339815191526122088133613829565b610eee613b90565b6018546001600160a01b0316331461223a5760405162461bcd60e51b8152600401610c7f90615afe565b601880546001600160a01b0319166001600160a01b0383169081179091556040517f1c794a043683a294127c95bc365bae91b63b651eb9884a2c9120afee2bb690b490600090a250565b60009182526022602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6001600160a01b0382163314156122ed5760405162461bcd60e51b8152602060048201526002602482015261199b60f11b6044820152606401610c7f565b336000818152602080805260408083206001600160a01b0387168085529252909120805460ff1916841515179055906001600160a01b03167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051612358911515815260200190565b60405180910390a35050565b600061237260865460ff1690565b1561238f5760405162461bcd60e51b8152600401610c7f90615a6b565b856001600160a01b0381166123b65760405162461bcd60e51b8152600401610c7f90615a35565b600085116123eb5760405162461bcd60e51b8152602060048201526002602482015261323760f01b6044820152606401610c7f565b60065460085461240a916001600160a01b0391821691339116896137eb565b600061241461371f565b9150508481111561244c5760405162461bcd60e51b8152602060048201526002602482015261064760f31b6044820152606401610c7f565b6000805461245a8389615ceb565b6124649190615bcb565b9050600061247389838a613ddf565b9050858110156124aa5760405162461bcd60e51b8152602060048201526002602482015261323960f01b6044820152606401610c7f565b600d546124c8908290600160401b90046001600160401b0316615ceb565b6124d6633b9aca008a615ceb565b11156125095760405162461bcd60e51b8152602060048201526002602482015261033360f41b6044820152606401610c7f565b612517600280546001019055565b6002549450612527856000613f95565b81600160008282546125399190615b88565b909155505060408051608081018252848152426020808301918252828401858152606084018d815260008b8152601a90935294909120925183559051600183015551600282015590516003909101556125928a86613fdb565b6040805186815260208101859052908101829052606081018990527f2af29ed8e180e9bfa65515c22e3af766d15e852ec59b9666d6eeaef8a97565929060800160405180910390a15050505095945050505050565b600080516020615ec08339815191526126008133613829565b60005b855181101561264f5761263d600080516020615ee083398151915287838151811061263057612630615e4b565b602002602001015161388d565b8061264781615df0565b915050612603565b50612668600080516020615ee08339815191528561388d565b60075461268d90600080516020615ee0833981519152906001600160a01b031661388d565b50600480546001600160a01b039384166001600160a01b031991821617909155600380549290931691161790555050565b600080516020615ee08339815191526126d78133613829565b81633b9aca00816001600160401b031611156127055760405162461bcd60e51b8152600401610c7f90615a50565b600e80546001600160c01b0316600160c01b6001600160401b038681168202929092179283905560405192041681527f264a4c2e5ed86659859b3c52d1b00a899950c0f3a637d68ca438cc0216dd89bf906020016115c6565b338261276a828261356b565b6127865760405162461bcd60e51b8152600401610c7f90615b19565b612792868686866140ab565b505050505050565b60865460ff16156127bd5760405162461bcd60e51b8152600401610c7f90615a6b565b6000806127c861371f565b915091506000600760009054906101000a90046001600160a01b03166001600160a01b031663344844db6040518163ffffffff1660e01b815260040160206040518083038186803b15801561281c57600080fd5b505afa158015612830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128549190615521565b600d54909150600090633b9aca009061287d90600160801b90046001600160401b031684615ceb565b6128879190615bcb565b600d54909150633b9aca00906128ad90600160c01b90046001600160401b031684615ceb565b6128b79190615bcb565b600154116128ec5760405162461bcd60e51b81526020600482015260026024820152610ccd60f21b6044820152606401610c7f565b600080600087516001600160401b0381111561290a5761290a615e61565b60405190808252806020026020018201604052801561294f57816020015b60408051808201909152600080825260208201528152602001906001900390816129285790505b50905060005b8851811015612b0b57600089828151811061297257612972615e4b565b6020908102919091018101516000818152601d9092526040909120549091506001600160a01b03168015612af6576000828152601a6020908152604080832081516080810183528154815260018201549381019390935260028101549183019190915260030154606082015290806129eb85848f6137a4565b915091508060011415612a1257612a0182613d9c565b612a0b908a615b88565b9850612adf565b600e5460208401514291612a3791600160801b9091046001600160401b031690615b88565b11612adf57612a4685846140f3565b60006001548b1115612a76578a633b9aca00600154612a659190615ceb565b612a6f9190615bcb565b9050612a7d565b50633b9aca005b600080612a8f8587606001518561414e565b9092509050612a9e818c615b88565b9a506040518060400160405280886001600160a01b03168152602001838152508a8a81518110612ad057612ad0615e4b565b60200260200101819052505050505b8960015411612af2575050505050612b0b565b5050505b50508080612b0390615df0565b915050612955565b5060008415612b4057612b1f856002615ceb565b633b9aca00600154612b319190615ceb565b612b3b9190615bcb565b612b43565b60005b9050633b9aca00612c59826011805480602002602001604051908101604052809291908181526020018280548015612bcc57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411612b895790505b50505050506012805480602002602001604051908101604052809291908181526020018280548015612c4f57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411612c0c5790505b50505050506142c2565b612c6c906001600160401b031685615ceb565b612c769190615bcb565b92506010548310612c8957601054612c8b565b825b92506000633b9aca00612ca089612710615ceb565b612caa9190615ceb565b600054600d548990612cd5906001600160401b03600160801b8204811691600160c01b900416615d50565b612ce0906005615d0a565b6001600160401b0316612cf39190615ceb565b612cfd9190615ceb565b612d079190615bcb565b9050808410612d165780612d18565b835b93507fb789efbabfeba5ae006c34c3b3c17f6b1cf34ab2ac684be93d1e64da000b5be78a8433612d488989615b88565b604051612d589493929190615918565b60405180910390a160005b8a51811015612de8576000848281518110612d8057612d80615e4b565b6020026020010151602001511115612dd657612dd6848281518110612da757612da7615e4b565b602002602001015160000151858381518110612dc557612dc5615e4b565b602002602001015160200151613c4c565b80612de081615df0565b915050612d63565b50612dfc33612df78787615b88565b613c4c565b50505050505050505050565b60098181548110610e3f57600080fd5b6004546001600160a01b03163314612e425760405162461bcd60e51b8152600401610c7f90615afe565b600e80546001600160401b03928316600160401b026001600160801b03199091169290931691909117919091179055565b6000818152601d60205260409020546060906001600160a01b0316612eaa5760405162461bcd60e51b8152600401610c7f90615ae3565b8160005b8115612ed45780612ebe81615df0565b9150612ecd9050600a83615bcb565b9150612eae565b6000816001600160401b03811115612eee57612eee615e61565b6040519080825280601f01601f191660200182016040528015612f18576020820181803683370190505b5090505b8415612f8357612f2d600183615d39565b9150612f3a600a86615e0b565b612f45906030615b88565b60f81b818381518110612f5a57612f5a615e4b565b60200101906001600160f81b031916908160001a905350612f7c600a86615bcb565b9450612f1c565b600060198054612f9290615dbb565b905011612fae5760405180602001604052806000815250612fd2565b601981604051602001612fc29291906157d3565b6040516020818303038152906040525b95945050505050565b60128181548110610e3f57600080fd5b6000828152602260205260409020600101546130078133613829565b610d5783836138f6565b600c8181548110610e3f57600080fd5b6000828152601a60209081526040808320815160808101835281548152600182015493810193909352600281015491830191909152600301546060820152819061306b818561460b565b92509250509250929050565b600080516020615ee08339815191526130908133613829565b816001600160a01b0381166130b75760405162461bcd60e51b8152600401610c7f90615a35565b6015849055601880546001600160a01b0319166001600160a01b0385169081179091556040518581527fe139be2fc520b685c93d718b643b5d8c42fc57b5724201180c5d765635467312906020015b60405180910390a250505050565b60865460ff16156131375760405162461bcd60e51b8152600401610c7f90615a6b565b3383613143828261356b565b61315f5760405162461bcd60e51b8152600401610c7f90615b19565b6000858152601a60209081526040808320815160808101835281548152600182015493810193909352600281015491830191909152600301546060820152906131a661371f565b5090506000806131b78985856137a4565b915091508060001415611db957600e54602085015142916131e991600160801b9091046001600160401b031690615b88565b111561321c5760405162461bcd60e51b8152602060048201526002602482015261333160f01b6044820152606401610c7f565b61322689856140f3565b600061324183866060015161323c6001546146b3565b61414e565b509050878110156132795760405162461bcd60e51b8152602060048201526002602482015261199960f11b6044820152606401610c7f565b604080518b8152602081018390527f2f06d076c30d294b959d7aa34f40d448e45f487492a47889f02831bb06fee6bf910160405180910390a1612dfc8982613c4c565b600080516020615ee08339815191526132d58133613829565b81633b9aca00816001600160401b031611156133035760405162461bcd60e51b8152600401610c7f90615a50565b61330d8385615d0a565b6001600160401b03166133256002633b9aca00615c40565b116133565760405162461bcd60e51b81526020600482015260016024820152600760fb1b6044820152606401610c7f565b600d80546001600160801b031916600160401b6001600160401b0387811691820267ffffffffffffffff1916929092179186169182179092556040805192835260208301919091527fb556fe5cb4a1a8243b8d5000bbefd6f8b868adcac2765cd4a30ac9320ff1a0b6910160405180910390a150505050565b6000818152601d60205260409020546001600160a01b0316806134045760405162461bcd60e51b8152600401610c7f90615ae3565b919050565b6000818152601f6020526040902080546001600160a01b0319166001600160a01b038416908117909155819061343e826133cf565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6040516001600160a01b038316602482015260448101829052610d5790849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526147ac565b6134e48282613f95565b6000828152601c60205260409020548015610d57576000838152601c60209081526040808320839055601d9091529020546005546001600160a01b039182169161353091168284613477565b806001600160a01b03167fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e04868360405161310691815260200190565b600080613577836133cf565b9050806001600160a01b0316846001600160a01b031614806135b257506000838152601f60205260409020546001600160a01b038581169116145b806135e057506001600160a01b038082166000908152602080805260408083209388168352929052205460ff165b949350505050565b826001600160a01b03166135fb826133cf565b6001600160a01b0316146136215760405162461bcd60e51b8152600401610c7f90615afe565b6001600160a01b03821661365c5760405162461bcd60e51b8152602060048201526002602482015261191b60f11b6044820152606401610c7f565b613667600082613409565b6001600160a01b0383166000908152601e60205260408120805460019290613690908490615d39565b90915550506001600160a01b0382166000908152601e602052604081208054600192906136be908490615b88565b90915550506000818152601d602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600354604080516341f654f760e01b8152815160009384936001600160a01b03909116926341f654f79260048083019392829003018186803b15801561376457600080fd5b505afa158015613778573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061379c9190615583565b915091509091565b60008060008060006137b6878761460b565b9150915081600014806137c95750806001145b156137dd576137d888886140f3565b600192505b50925090505b935093915050565b6040516001600160a01b03808516602483015283166044820152606481018290526138239085906323b872dd60e01b906084016134a3565b50505050565b6138338282612284565b6110b35761384b816001600160a01b0316601461487e565b61385683602061487e565b604051602001613867929190615871565b60408051601f198184030181529082905262461bcd60e51b8252610c7f91600401615a22565b6138978282612284565b6110b35760008281526022602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b6139008282612284565b156110b35760008281526022602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600060015460001415613971575060175490565b600154670de0b6b3a764000060145460165461398b614a19565b6139959190615d39565b61399f9190615ceb565b6139a99190615ceb565b6139b39190615bcb565b6017546139c09190615b88565b905090565b60865460ff16613a0e5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610c7f565b6086805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b602154610100900460ff1680613a71575060215460ff16155b613a8d5760405162461bcd60e51b8152600401610c7f90615a95565b602154610100900460ff16158015613aaf576021805461ffff19166101011790555b613ab7614a34565b613abf614a9e565b8015610eee576021805461ff001916905550565b602154610100900460ff1680613aec575060215460ff16155b613b085760405162461bcd60e51b8152600401610c7f90615a95565b602154610100900460ff16158015613b2a576021805461ffff19166101011790555b613abf614a34565b6110b3828261388d565b600082815260226020526040902060010154819060405184907fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff90600090a460009182526022602052604090912060010155565b60865460ff1615613bb35760405162461bcd60e51b8152600401610c7f90615a6b565b6086805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613a3b3390565b6000828152601c60209081526040808320548354601b90935290832054909190670de0b6b3a764000090613c1a61395d565b613c249190615d39565b613c2e9086615ceb565b613c389190615bcb565b613c429190615bcb565b61152e9190615b88565b60065460408051629032ff60e51b815290516000926001600160a01b0316916312065fe0916004808301926020929190829003018186803b158015613c9057600080fd5b505afa158015613ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cc89190615521565b9050818110158015613cda5750600082115b15613cfd57600654600854610d57916001600160a01b03918216911685856137eb565b8115610d57576000613d0f8284615d39565b600654600854919250613d30916001600160a01b03908116911686856137eb565b600754604051631a115ff160e01b8152600481018390526001600160a01b03868116602483015290911690631a115ff190604401600060405180830381600087803b158015613d7e57600080fd5b505af1158015613d92573d6000803e3d6000fd5b5050505050505050565b600e54600090633b9aca0090613dc290600160c01b90046001600160401b031684615ceb565b613dcc9190615bcb565b9050600f54811061340457600f54610c45565b600080613df884600154613df39190615b88565b6146b3565b9050633b9aca006001600160401b03821610613e3b5760405162461bcd60e51b8152602060048201526002602482015261323560f01b6044820152606401610c7f565b6000633b9aca00613f27836009805480602002602001604051908101604052809291908181526020018280548015613ec457602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411613e815790505b5050505050600a805480602002602001604051908101604052809291908181526020018280548015612c4f57600091825260209182902080546001600160401b03168452908202830192909160089101808411612c0c57905050505050506142c2565b600e54613f3d91906001600160401b0316615d0a565b6001600160401b0316613f509190615bcb565b9050633b9aca00613f618282615d39565b613f6b9086615ceb565b613f759190615bcb565b613f7f9085615d39565b9050613f8b8187615d39565b9695505050505050565b613f9d61395d565b601755613fa8614a19565b601655613fb58282613be8565b6000928352601c6020908152604080852092909255601754601b90915292209190915550565b6001600160a01b0382166000908152601e60205260408120805460019290614004908490615b88565b90915550506000818152601d602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a461407a6000838360405180602001604052806000815250614b13565b6110b35760405162461bcd60e51b81526020600482015260026024820152610c8d60f21b6044820152606401610c7f565b6140b68484846135e8565b6140c284848484614b13565b6138235760405162461bcd60e51b81526020600482015260026024820152610c8d60f21b6044820152606401610c7f565b8051606082015160009161410691615ceb565b905061411283826134da565b6000838152601b602052604081208190555461412e9082615bcb565b6001600082825461413f9190615d39565b90915550610d57905083614c35565b600080633b9aca0061423b84600b8054806020026020016040519081016040528092919081815260200182805480156141d857602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116141955790505b5050505050600c805480602002602001604051908101604052809291908181526020018280548015612c4f57600091825260209182902080546001600160401b03168452908202830192909160089101808411612c0c57905050505050506142c2565b600e546142589190600160401b90046001600160401b0316615d0a565b6001600160401b031661426b9190615bcb565b9050633b9aca0061427c8282615d39565b6142869086615ceb565b6142909190615bcb565b61429a9085615d39565b90508481106142ae575060009050836137e3565b6142b88186615d39565b9150935093915050565b600082600184516142d39190615d39565b815181106142e3576142e3615e4b565b60200260200101516001600160401b0316846001600160401b0316106143315781600184516143129190615d39565b8151811061432257614322615e4b565b6020026020010151905061152e565b8260008151811061434457614344615e4b565b60200260200101516001600160401b0316846001600160401b031611614377578160008151811061432257614322615e4b565b600080600185516143889190615d39565b905060005b60016143998484615d39565b11156144035760026143ab8484615d39565b6143b59190615bcb565b6143bf9084615b88565b9050866001600160401b03168682815181106143dd576143dd615e4b565b60200260200101516001600160401b0316116143fb5780925061438d565b80915061438d565b84838151811061441557614415615e4b565b60200260200101516001600160401b031685838151811061443857614438615e4b565b60200260200101516001600160401b031611156145325785838151811061446157614461615e4b565b602002602001015186838151811061447b5761447b615e4b565b602002602001015161448d9190615d50565b86848151811061449f5761449f615e4b565b6020026020010151886144b29190615d50565b8685815181106144c4576144c4615e4b565b60200260200101518785815181106144de576144de615e4b565b60200260200101516144f09190615d50565b6144fa9190615d0a565b6145049190615bdf565b85848151811061451657614516615e4b565b60200260200101516145289190615ba0565b935050505061152e565b85838151811061454457614544615e4b565b602002602001015186838151811061455e5761455e615e4b565b60200260200101516145709190615d50565b86848151811061458257614582615e4b565b6020026020010151886145959190615d50565b8684815181106145a7576145a7615e4b565b60200260200101518786815181106145c1576145c1615e4b565b60200260200101516145d39190615d50565b6145dd9190615d0a565b6145e79190615bdf565b8584815181106145f9576145f9615e4b565b60200260200101516145289190615d50565b600080600083856000015186606001516146259190615ceb565b61462f9190615bcb565b9050846040015185606001516146459190615b88565b811061465457600092506146ab565b80856040015186606001516146699190615b88565b6146739190615d39565b600d546060870151919450614693916001600160401b0390911690615ceb565b6146a1633b9aca0085615ceb565b116146ab57600191505b509250929050565b600080633b9aca00600d60109054906101000a90046001600160401b03166001600160401b0316600760009054906101000a90046001600160a01b03166001600160a01b031663344844db6040518163ffffffff1660e01b815260040160206040518083038186803b15801561472857600080fd5b505afa15801561473c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147609190615521565b61476a9190615ceb565b6147749190615bcb565b90508083101561479e578061478d633b9aca0085615ceb565b6147979190615bcb565b91506147a6565b633b9aca0091505b50919050565b6000614801826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614cf19092919063ffffffff16565b805190915015610d57578080602001905181019061481f9190615444565b610d575760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610c7f565b6060600061488d836002615ceb565b614898906002615b88565b6001600160401b038111156148af576148af615e61565b6040519080825280601f01601f1916602001820160405280156148d9576020820181803683370190505b509050600360fc1b816000815181106148f4576148f4615e4b565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061492357614923615e4b565b60200101906001600160f81b031916908160001a9053506000614947846002615ceb565b614952906001615b88565b90505b60018111156149ca576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061498657614986615e4b565b1a60f81b82828151811061499c5761499c615e4b565b60200101906001600160f81b031916908160001a90535060049490941c936149c381615da4565b9050614955565b50831561152e5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610c7f565b6000806013544210614a2d57601354610c45565b4292915050565b602154610100900460ff1680614a4d575060215460ff16155b614a695760405162461bcd60e51b8152600401610c7f90615a95565b602154610100900460ff16158015613abf576021805461ffff19166101011790558015610eee576021805461ff001916905550565b602154610100900460ff1680614ab7575060215460ff16155b614ad35760405162461bcd60e51b8152600401610c7f90615a95565b602154610100900460ff16158015614af5576021805461ffff19166101011790555b6086805460ff191690558015610eee576021805461ff001916905550565b60006001600160a01b0384163b15614c2a57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290614b579033908990889088906004016158e6565b602060405180830381600087803b158015614b7157600080fd5b505af1925050508015614ba1575060408051601f3d908101601f19168201909252614b9e918101906154bc565b60015b614c10573d808015614bcf576040519150601f19603f3d011682016040523d82523d6000602084013e614bd4565b606091505b508051614c085760405162461bcd60e51b81526020600482015260026024820152610c8d60f21b6044820152606401610c7f565b805181602001fd5b6001600160e01b031916630a85bd0160e11b1490506135e0565b506001949350505050565b6000614c40826133cf565b9050614c4d600083613409565b6001600160a01b0381166000908152601e60205260408120805460019290614c76908490615d39565b90915550506000828152601d6020908152604080832080546001600160a01b0319169055601a9091528082208281556001810183905560028101839055600301829055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b60606135e0848460008585843b614d4a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c7f565b600080866001600160a01b03168587604051614d6691906157b7565b60006040518083038185875af1925050503d8060008114614da3576040519150601f19603f3d011682016040523d82523d6000602084013e614da8565b606091505b5091509150614db8828286614dc3565b979650505050505050565b60608315614dd257508161152e565b825115614de25782518084602001fd5b8160405162461bcd60e51b8152600401610c7f9190615a22565b82805482825590600052602060002090600301600490048101928215614ea45791602002820160005b83821115614e6f57835183826101000a8154816001600160401b0302191690836001600160401b031602179055509260200192600801602081600701049283019260010302614e25565b8015614ea25782816101000a8154906001600160401b030219169055600801602081600701049283019260010302614e6f565b505b50614eb0929150614f28565b5090565b828054614ec090615dbb565b90600052602060002090601f016020900481019282614ee25760008555614ea4565b82601f10614efb57805160ff1916838001178555614ea4565b82800160010185558215614ea4579182015b82811115614ea4578251825591602001919060010190614f0d565b5b80821115614eb05760008155600101614f29565b60006001600160401b03831115614f5657614f56615e61565b614f69601f8401601f1916602001615b35565b9050828152838383011115614f7d57600080fd5b828260208301376000602084830101529392505050565b803561340481615e77565b600082601f830112614fb057600080fd5b81356020614fc5614fc083615b65565b615b35565b80838252828201915082860187848660051b8901011115614fe557600080fd5b60005b8581101561500b57614ff982615018565b84529284019290840190600101614fe8565b5090979650505050505050565b80356001600160401b038116811461340457600080fd5b60006020828403121561504157600080fd5b813561152e81615e77565b60006020828403121561505e57600080fd5b815161152e81615e77565b6000806040838503121561507c57600080fd5b823561508781615e77565b9150602083013561509781615e77565b809150509250929050565b6000806000606084860312156150b757600080fd5b83356150c281615e77565b925060208401356150d281615e77565b929592945050506040919091013590565b600080600080608085870312156150f957600080fd5b843561510481615e77565b9350602085013561511481615e77565b92506040850135915060608501356001600160401b0381111561513657600080fd5b8501601f8101871361514757600080fd5b61515687823560208401614f3d565b91505092959194509250565b6000806040838503121561517557600080fd5b823561518081615e77565b9150602083013561509781615e8c565b600080604083850312156151a357600080fd5b82356151ae81615e77565b946020939093013593505050565b600080600080600060a086880312156151d457600080fd5b85356151df81615e77565b97602087013597506040870135966060810135965060800135945092505050565b6000806000806080858703121561521657600080fd5b84356001600160401b0381111561522c57600080fd5b8501601f8101871361523d57600080fd5b8035602061524d614fc083615b65565b8083825282820191508285018b848660051b880101111561526d57600080fd5b600095505b8486101561529957803561528581615e77565b835260019590950194918301918301615272565b5097506152a99050888201614f94565b95505050506152ba60408601614f94565b91506152c860608601614f94565b905092959194509250565b600060208083850312156152e657600080fd5b82356001600160401b038111156152fc57600080fd5b8301601f8101851361530d57600080fd5b803561531b614fc082615b65565b80828252848201915084840188868560051b870101111561533b57600080fd5b600094505b8385101561535e578035835260019490940193918501918501615340565b50979650505050505050565b6000806040838503121561537d57600080fd5b82356001600160401b038082111561539457600080fd5b6153a086838701614f9f565b935060208501359150808211156153b657600080fd5b506153c385828601614f9f565b9150509250929050565b6000806000606084860312156153e257600080fd5b83356001600160401b03808211156153f957600080fd5b61540587838801614f9f565b9450602086013591508082111561541b57600080fd5b5061542886828701614f9f565b925050604084013561543981615eb0565b809150509250925092565b60006020828403121561545657600080fd5b815161152e81615e8c565b60006020828403121561547357600080fd5b5035919050565b6000806040838503121561548d57600080fd5b82359150602083013561509781615e77565b6000602082840312156154b157600080fd5b813561152e81615e9a565b6000602082840312156154ce57600080fd5b815161152e81615e9a565b6000602082840312156154eb57600080fd5b81356001600160401b0381111561550157600080fd5b8201601f8101841361551257600080fd5b6135e084823560208401614f3d565b60006020828403121561553357600080fd5b5051919050565b60008060006060848603121561554f57600080fd5b8335925060208401356150d281615e77565b6000806040838503121561557457600080fd5b50508035926020909101359150565b6000806040838503121561559657600080fd5b505080516020909101519092909150565b6000806000606084860312156155bc57600080fd5b8335925060208401359150604084013561543981615e77565b6000602082840312156155e757600080fd5b61152e82615018565b6000806040838503121561560357600080fd5b61560c83615018565b915061561a60208401615018565b90509250929050565b60006020828403121561563557600080fd5b815161152e81615eb0565b600081518084526020808501945080840160005b838110156156795781516001600160401b031687529582019590820190600101615654565b509495945050505050565b805480835260008281526020808220940193909190825b826003820110156156ea5781546001600160401b038082168852604082811c821660208a0152608083811c9092169089015260c09190911c60608801529095019460019091019060040161569b565b9054908281101561570b576001600160401b03821686526020909501946001015b8281101561572d576001600160401b03604083901c1686526020909501946001015b8281101561574f576001600160401b03608083901c1686526020909501946001015b828110156157655760c082901c86526020860195505b5093949350505050565b60008151808452615787816020860160208601615d78565b601f01601f19169290920160200192915050565b600081516157ad818560208601615d78565b9290920192915050565b600082516157c9818460208701615d78565b9190910192915050565b600080845481600182811c9150808316806157ef57607f831692505b602080841082141561580f57634e487b7160e01b86526022600452602486fd5b818015615823576001811461583457615861565b60ff19861689528489019650615861565b60008b81526020902060005b868110156158595781548b820152908501908301615840565b505084890196505b505050505050612fd2818561579b565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516158a9816017850160208801615d78565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516158da816028840160208801615d78565b01602801949350505050565b60006001600160a01b03808716835280861660208401525083604083015260806060830152613f8b608083018461576f565b6080808252855190820181905260009060209060a0840190828901845b8281101561595157815184529284019290840190600101615935565b5050508381038285015286518082528783019183019060005b8181101561599a57835180516001600160a01b03168452850151858401529284019260409092019160010161596a565b50506001600160a01b038716604086015292506159b5915050565b82606083015295945050505050565b6060815260006159d76060830186615640565b82810360208401526159e98186615640565b91505060ff83166040830152949350505050565b604081526000615a106040830185615684565b8281036020840152612fd28185615684565b60208152600061152e602083018461576f565b6020808252600190820152600360fc1b604082015260600190565b6020808252600190820152600d60fa1b604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252600190820152601960f91b604082015260600190565b6020808252600190820152603160f81b604082015260600190565b602080825260029082015261323160f01b604082015260600190565b604051601f8201601f191681016001600160401b0381118282101715615b5d57615b5d615e61565b604052919050565b60006001600160401b03821115615b7e57615b7e615e61565b5060051b60200190565b60008219821115615b9b57615b9b615e1f565b500190565b60006001600160401b03808316818516808303821115615bc257615bc2615e1f565b01949350505050565b600082615bda57615bda615e35565b500490565b60006001600160401b0380841680615bf957615bf9615e35565b92169190910492915050565b600181815b808511156146ab578160001904821115615c2657615c26615e1f565b80851615615c3357918102915b93841c9390800290615c0a565b600061152e60ff841683600082615c5957506001610c45565b81615c6657506000610c45565b8160018114615c7c5760028114615c8657615ca2565b6001915050610c45565b60ff841115615c9757615c97615e1f565b50506001821b610c45565b5060208310610133831016604e8410600b8410161715615cc5575081810a610c45565b615ccf8383615c05565b8060001904821115615ce357615ce3615e1f565b029392505050565b6000816000190483118215151615615d0557615d05615e1f565b500290565b60006001600160401b0380831681851681830481118215151615615d3057615d30615e1f565b02949350505050565b600082821015615d4b57615d4b615e1f565b500390565b60006001600160401b0383811690831681811015615d7057615d70615e1f565b039392505050565b60005b83811015615d93578181015183820152602001615d7b565b838111156138235750506000910152565b600081615db357615db3615e1f565b506000190190565b600181811c90821680615dcf57607f821691505b602082108114156147a657634e487b7160e01b600052602260045260246000fd5b6000600019821415615e0457615e04615e1f565b5060010190565b600082615e1a57615e1a615e35565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610eee57600080fd5b8015158114610eee57600080fd5b6001600160e01b031981168114610eee57600080fd5b60ff81168114610eee57600080fdfe5916f72c85af4ac6f7e34636ecc97619c4b2085da099a5d28f3e58436cfbe56255435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041a26469706673582212206a35e934a4939c3da2e9a75fb51b6129babcae1a26cd0fb89845202edc12f28d64736f6c63430008070033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.