Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Initialize | 14717641 | 1001 days ago | IN | 0 ETH | 0.01394617 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
PoolManager
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 "./PoolManagerInternal.sol"; /// @title PoolManager /// @author Angle Core Team /// @notice The `PoolManager` contract corresponds to a collateral pool of the protocol for a stablecoin, /// it manages a single ERC20 token. It is responsible for interacting with the strategies enabling the protocol /// to get yield on its collateral /// @dev This file contains the functions that are callable by governance or by other contracts of the protocol /// @dev References to this contract are called `PoolManager` contract PoolManager is PoolManagerInternal, IPoolManagerFunctions { using SafeERC20 for IERC20; // ============================ Constructor ==================================== /// @notice Constructor of the `PoolManager` contract /// @param _token Address of the collateral /// @param _stableMaster Reference to the master stablecoin (`StableMaster`) interface function initialize(address _token, IStableMaster _stableMaster) external initializer zeroCheck(_token) zeroCheck(address(_stableMaster)) { __AccessControl_init(); // Creating the correct references stableMaster = _stableMaster; token = IERC20(_token); // Access Control // The roles in this contract can only be modified from the `StableMaster` // For the moment `StableMaster` never uses the `GOVERNOR_ROLE` _setupRole(STABLEMASTER_ROLE, address(stableMaster)); _setRoleAdmin(STABLEMASTER_ROLE, STABLEMASTER_ROLE); _setRoleAdmin(GOVERNOR_ROLE, STABLEMASTER_ROLE); _setRoleAdmin(GUARDIAN_ROLE, STABLEMASTER_ROLE); // No admin is set for `STRATEGY_ROLE`, checks are made in the appropriate functions // `addStrategy` and `revokeStrategy` } /* /// @custom:oz-upgrades-unsafe-allow constructor constructor() initializer {} */ // ========================= `StableMaster` Functions ========================== /// @notice Changes the references to contracts from this protocol with which this collateral `PoolManager` interacts /// and propagates some references to the `perpetualManager` and `feeManager` contracts /// @param governorList List of the governor addresses of protocol /// @param guardian Address of the guardian of the protocol (it can be revoked) /// @param _perpetualManager New reference to the `PerpetualManager` contract containing all the logic for HAs /// @param _feeManager Reference to the `FeeManager` contract that will serve for the `PerpetualManager` contract /// @param _oracle Reference to the `Oracle` contract that will serve for the `PerpetualManager` contract function deployCollateral( address[] memory governorList, address guardian, IPerpetualManager _perpetualManager, IFeeManager _feeManager, IOracle _oracle ) external override onlyRole(STABLEMASTER_ROLE) { // These references need to be stored to be able to propagate changes and maintain // the protocol's integrity when changes are posted from the `StableMaster` perpetualManager = _perpetualManager; feeManager = _feeManager; // Access control for (uint256 i = 0; i < governorList.length; i++) { _grantRole(GOVERNOR_ROLE, governorList[i]); _grantRole(GUARDIAN_ROLE, governorList[i]); } _grantRole(GUARDIAN_ROLE, guardian); // Propagates the changes to the other involved contracts perpetualManager.deployCollateral(governorList, guardian, _feeManager, _oracle); _feeManager.deployCollateral(governorList, guardian, address(_perpetualManager)); // `StableMaster` and `PerpetualManager` need to have approval to directly transfer some of // this contract's tokens token.safeIncreaseAllowance(address(stableMaster), type(uint256).max); token.safeIncreaseAllowance(address(_perpetualManager), type(uint256).max); } /// @notice Adds a new governor address and echoes it to other contracts /// @param _governor New governor address function addGovernor(address _governor) external override onlyRole(STABLEMASTER_ROLE) { // Access control for this contract _grantRole(GOVERNOR_ROLE, _governor); // Echoes the change to other contracts interacting with this collateral `PoolManager` // Since the other contracts interacting with this `PoolManager` do not have governor roles, // we just need it to set the new governor as guardian in these contracts _addGuardian(_governor); } /// @notice Removes a governor address and echoes it to other contracts /// @param _governor Governor address to remove function removeGovernor(address _governor) external override onlyRole(STABLEMASTER_ROLE) { // Access control for this contract _revokeRole(GOVERNOR_ROLE, _governor); _revokeGuardian(_governor); } /// @notice Changes the guardian address and echoes it to other contracts that interact with this `PoolManager` /// @param _guardian New guardian address /// @param guardian Old guardian address to revoke function setGuardian(address _guardian, address guardian) external override onlyRole(STABLEMASTER_ROLE) { _revokeGuardian(guardian); _addGuardian(_guardian); } /// @notice Revokes the guardian address and echoes the change to other contracts that interact with this `PoolManager` /// @param guardian Address of the guardian to revoke function revokeGuardian(address guardian) external override onlyRole(STABLEMASTER_ROLE) { _revokeGuardian(guardian); } /// @notice Allows to propagate the change of keeper for the collateral/stablecoin pair /// @param _feeManager New `FeeManager` contract function setFeeManager(IFeeManager _feeManager) external override onlyRole(STABLEMASTER_ROLE) { // Changing the reference in the `PerpetualManager` contract where keepers are involved feeManager = _feeManager; perpetualManager.setFeeManager(_feeManager); } // ============================= Yield Farming ================================= /// @notice Provides an estimated Annual Percentage Rate for SLPs based on lending to other protocols /// @dev This function is an estimation and is made for external use only /// @dev This does not take into account transaction fees which accrue to SLPs too /// @dev This can be manipulated by a flash loan attack (SLP deposit/ withdraw) via `_getTotalAsset` /// when entering you should make sure this hasn't be called by a flash loan and look /// at a mean of past APR. /// @dev Returned APR is in base 18 function estimatedAPR() external view returns (uint256 apr) { apr = 0; (, ISanToken sanTokenForAPR, , , , uint256 sanRate, , SLPData memory slpData, ) = stableMaster.collateralMap( IPoolManager(address(this)) ); uint256 supply = sanTokenForAPR.totalSupply(); // `sanRate` should never be equal to 0 if (supply == 0) return type(uint256).max; for (uint256 i = 0; i < strategyList.length; i++) { apr = apr + (strategies[strategyList[i]].debtRatio * IStrategy(strategyList[i]).estimatedAPR()) / BASE_PARAMS; } apr = (apr * (BASE_PARAMS - interestsForSurplus) * slpData.interestsForSLPs * _getTotalAsset()) / sanRate / supply; } /// @notice Tells a strategy how much it can borrow from this `PoolManager` /// @return Amount of token a strategy has access to as a credit line /// @dev Since this function is a view function, there is no need to have an access control logic /// even though it will just be relevant for a strategy /// @dev Manipulating `_getTotalAsset` with a flashloan will only /// result in tokens being transferred at the cost of the caller function creditAvailable() external view override returns (uint256) { StrategyParams storage params = strategies[msg.sender]; uint256 target = (_getTotalAsset() * params.debtRatio) / BASE_PARAMS; if (target < params.totalStrategyDebt) return 0; return Math.min(target - params.totalStrategyDebt, _getBalance()); } /// @notice Tells a strategy how much it owes to this `PoolManager` /// @return Amount of token a strategy has to reimburse /// @dev Manipulating `_getTotalAsset` with a flashloan will only /// result in tokens being transferred at the cost of the caller function debtOutstanding() external view override returns (uint256) { StrategyParams storage params = strategies[msg.sender]; uint256 target = (_getTotalAsset() * params.debtRatio) / BASE_PARAMS; if (target > params.totalStrategyDebt) return 0; return (params.totalStrategyDebt - target); } /// @notice Reports the gains or loss made by a strategy /// @param gain Amount strategy has realized as a gain on its investment since its /// last report, and is free to be given back to `PoolManager` as earnings /// @param loss Amount strategy has realized as a loss on its investment since its /// last report, and should be accounted for on the `PoolManager`'s balance sheet. /// The loss will reduce the `debtRatio`. The next time the strategy will harvest, /// it will pay back the debt in an attempt to adjust to the new debt limit. /// @param debtPayment Amount strategy has made available to cover outstanding debt /// @dev This is the main contact point where the strategy interacts with the `PoolManager` /// @dev The strategy reports back what it has free, then the `PoolManager` contract "decides" /// whether to take some back or give it more. Note that the most it can /// take is `gain + _debtPayment`, and the most it can give is all of the /// remaining reserves. Anything outside of those bounds is abnormal behavior. function report( uint256 gain, uint256 loss, uint256 debtPayment ) external override onlyRole(STRATEGY_ROLE) { require(token.balanceOf(msg.sender) >= gain + debtPayment, "72"); StrategyParams storage params = strategies[msg.sender]; // Updating parameters in the `perpetualManager` // This needs to be done now because it has implications in `_getTotalAsset()` params.totalStrategyDebt = params.totalStrategyDebt + gain - loss; totalDebt = totalDebt + gain - loss; params.lastReport = block.timestamp; // Warning: `_getTotalAsset` could be manipulated by flashloan attacks. // It may allow external users to transfer funds into strategy or remove funds // from the strategy. Yet, as it does not impact the profit or loss and as attackers // have no interest in making such txs to have a direct profit, we let it as is. // The only issue is if the strategy is compromised; in this case governance // should revoke the strategy uint256 target = ((_getTotalAsset()) * params.debtRatio) / BASE_PARAMS; if (target > params.totalStrategyDebt) { // If the strategy has some credit left, tokens can be transferred to this strategy uint256 available = Math.min(target - params.totalStrategyDebt, _getBalance()); params.totalStrategyDebt = params.totalStrategyDebt + available; totalDebt = totalDebt + available; if (available > 0) { token.safeTransfer(msg.sender, available); } } else { uint256 available = Math.min(params.totalStrategyDebt - target, debtPayment + gain); params.totalStrategyDebt = params.totalStrategyDebt - available; totalDebt = totalDebt - available; if (available > 0) { token.safeTransferFrom(msg.sender, address(this), available); } } emit StrategyReported(msg.sender, gain, loss, debtPayment, params.totalStrategyDebt); // Handle gains before losses if (gain > 0) { uint256 gainForSurplus = (gain * interestsForSurplus) / BASE_PARAMS; uint256 adminDebtPre = adminDebt; // Depending on the current admin debt distribute the necessary gain from the strategies if (adminDebtPre == 0) interestsAccumulated += gainForSurplus; else if (adminDebtPre <= gainForSurplus) { interestsAccumulated += gainForSurplus - adminDebtPre; adminDebt = 0; } else adminDebt -= gainForSurplus; stableMaster.accumulateInterest(gain - gainForSurplus); emit FeesDistributed(gain); } // Handle eventual losses if (loss > 0) { uint256 lossForSurplus = (loss * interestsForSurplus) / BASE_PARAMS; uint256 interestsAccumulatedPreLoss = interestsAccumulated; // If the loss can not be entirely soaked by the interests to be distributed then // the protocol keeps track of the debt if (lossForSurplus > interestsAccumulatedPreLoss) { interestsAccumulated = 0; adminDebt += lossForSurplus - interestsAccumulatedPreLoss; } else interestsAccumulated -= lossForSurplus; // The rest is incurred to SLPs stableMaster.signalLoss(loss - lossForSurplus); } } // =========================== Governor Functions ============================== /// @notice Allows to recover any ERC20 token, including the token handled by this contract, and to send it /// to a contract /// @param tokenAddress Address of the token to recover /// @param to Address of the contract to send collateral to /// @param amountToRecover Amount of collateral to transfer /// @dev As this function can be used to transfer funds to another contract, it has to be a `GOVERNOR` function /// @dev In case the concerned token is the specific token handled by this contract, this function checks that the /// amount entered is not too big and approximates the surplus of the protocol /// @dev To esimate the amount of user claims on the concerned collateral, this function uses the `stocksUsers` for /// this collateral, but this is just an approximation as users can claim the collateral of their choice provided /// that they own a stablecoin /// @dev The sanity check excludes the HA claims: to get a sense of it, this function would need to compute the cash out /// amount of all the perpetuals, and this cannot be done on-chain in a cheap manner /// @dev Overall, even though there is a sanity check, this function relies on the fact that governance is not corrupted /// in this protocol and will not try to withdraw too much funds function recoverERC20( address tokenAddress, address to, uint256 amountToRecover ) external onlyRole(GOVERNOR_ROLE) { if (tokenAddress == address(token)) { // Fetching info from the `StableMaster` ( , ISanToken sanToken, , IOracle oracle, uint256 stocksUsers, uint256 sanRate, uint256 collatBase, , ) = IStableMaster(stableMaster).collateralMap(IPoolManager(address(this))); // Checking if there are enough reserves for the amount to withdraw require( _getTotalAsset() >= amountToRecover + (sanToken.totalSupply() * sanRate) / BASE_TOKENS + (stocksUsers * collatBase) / oracle.readUpper() + interestsAccumulated, "66" ); token.safeTransfer(to, amountToRecover); } else { IERC20(tokenAddress).safeTransfer(to, amountToRecover); } emit Recovered(tokenAddress, to, amountToRecover); } /// @notice Adds a strategy to the `PoolManager` /// @param strategy The address of the strategy to add /// @param _debtRatio The share of the total assets that the strategy has access to /// @dev Multiple checks are made. For instance, the contract must not already belong to the `PoolManager` /// and the underlying token of the strategy has to be consistent with the `PoolManager` contracts /// @dev This function is a `governor` function and not a `guardian` one because a `guardian` could add a strategy /// enabling the withdraw of the funds of the protocol /// @dev The `_debtRatio` should be expressed in `BASE_PARAMS` function addStrategy(address strategy, uint256 _debtRatio) external onlyRole(GOVERNOR_ROLE) zeroCheck(strategy) { StrategyParams storage params = strategies[strategy]; require(params.lastReport == 0, "73"); require(address(this) == IStrategy(strategy).poolManager(), "74"); // Using current code, this condition should always be verified as in the constructor // of the strategy the `want()` is set to the token of this `PoolManager` require(address(token) == IStrategy(strategy).want(), "75"); require(debtRatio + _debtRatio <= BASE_PARAMS, "76"); // Add strategy to approved strategies params.lastReport = 1; params.totalStrategyDebt = 0; params.debtRatio = _debtRatio; _grantRole(STRATEGY_ROLE, strategy); // Update global parameters debtRatio += _debtRatio; emit StrategyAdded(strategy, debtRatio); strategyList.push(strategy); } // =========================== Guardian Functions ============================== /// @notice Sets a new surplus distributor to which surplus from the protocol will be pushed /// @param newSurplusConverter Address to which the role needs to be granted /// @dev It is as if the `GUARDIAN_ROLE` was admin of the `SURPLUS_DISTRIBUTOR_ROLE` /// @dev The address can be the zero address in case the protocol revokes the `surplusConverter` function setSurplusConverter(address newSurplusConverter) external onlyRole(GUARDIAN_ROLE) { address oldSurplusConverter = surplusConverter; surplusConverter = newSurplusConverter; emit SurplusConverterUpdated(newSurplusConverter, oldSurplusConverter); } /// @notice Sets the share of the interests going directly to the surplus /// @param _interestsForSurplus New value of the interests going directly to the surplus for buybacks /// @dev Guardian should make sure the incentives for SLPs are still high enough for them to enter the protocol function setInterestsForSurplus(uint64 _interestsForSurplus) external onlyRole(GUARDIAN_ROLE) onlyCompatibleFees(_interestsForSurplus) { interestsForSurplus = _interestsForSurplus; emit InterestsForSurplusUpdated(_interestsForSurplus); } /// @notice Modifies the funds a strategy has access to /// @param strategy The address of the Strategy /// @param _debtRatio The share of the total assets that the strategy has access to /// @dev The update has to be such that the `debtRatio` does not exceeds the 100% threshold /// as this `PoolManager` cannot lend collateral that it doesn't not own. /// @dev `_debtRatio` is stored as a uint256 but as any parameter of the protocol, it should be expressed /// in `BASE_PARAMS` function updateStrategyDebtRatio(address strategy, uint256 _debtRatio) external onlyRole(GUARDIAN_ROLE) { _updateStrategyDebtRatio(strategy, _debtRatio); } /// @notice Triggers an emergency exit for a strategy and then harvests it to fetch all the funds /// @param strategy The address of the `Strategy` function setStrategyEmergencyExit(address strategy) external onlyRole(GUARDIAN_ROLE) { _updateStrategyDebtRatio(strategy, 0); IStrategy(strategy).setEmergencyExit(); IStrategy(strategy).harvest(); } /// @notice Revokes a strategy /// @param strategy The address of the strategy to revoke /// @dev This should only be called after the following happened in order: the `strategy.debtRatio` has been set to 0, /// `harvest` has been called enough times to recover all capital gain/losses. function revokeStrategy(address strategy) external onlyRole(GUARDIAN_ROLE) { StrategyParams storage params = strategies[strategy]; require(params.debtRatio == 0, "77"); require(params.totalStrategyDebt == 0, "77"); uint256 strategyListLength = strategyList.length; require(params.lastReport != 0 && strategyListLength >= 1, "78"); // It has already been checked whether the strategy was a valid strategy for (uint256 i = 0; i < strategyListLength - 1; i++) { if (strategyList[i] == strategy) { strategyList[i] = strategyList[strategyListLength - 1]; break; } } strategyList.pop(); // Update global parameters debtRatio -= params.debtRatio; delete strategies[strategy]; _revokeRole(STRATEGY_ROLE, strategy); emit StrategyRevoked(strategy); } /// @notice Withdraws a given amount from a strategy /// @param strategy The address of the strategy /// @param amount The amount to withdraw /// @dev This function tries to recover `amount` from the strategy, but it may not go through /// as we may not be able to withdraw from the lending protocol the full amount /// @dev In this last case we only update the parameters by setting the loss as the gap between /// what has been asked and what has been returned. function withdrawFromStrategy(IStrategy strategy, uint256 amount) external onlyRole(GUARDIAN_ROLE) { StrategyParams storage params = strategies[address(strategy)]; require(params.lastReport != 0, "78"); uint256 loss; (amount, loss) = strategy.withdraw(amount); // Handling eventual losses params.totalStrategyDebt = params.totalStrategyDebt - loss - amount; totalDebt = totalDebt - loss - amount; emit StrategyReported(address(strategy), 0, loss, amount - loss, params.totalStrategyDebt); // Handle eventual losses // With the strategy we are using in current tests, it is going to be impossible to have // a positive loss by calling strategy.withdraw, this function indeed calls _liquidatePosition // which output value is always zero if (loss > 0) stableMaster.signalLoss(loss); } // =================== Surplus Distributor Function ============================ /// @notice Allows to push interests revenue accumulated by the protocol to the `surplusConverter` to do buybacks /// or another form of redistribution to ANGLE or veANGLE token holders /// @dev This function is permissionless and anyone can transfer the `interestsAccumulated` by the protocol /// to the `surplusConverter` function pushSurplus() external { // If the `surplusConverter` has not been initialized, surplus should not be distributed // Storing the `surplusConverter` in an intermediate variable to avoid multiple reads in // storage address surplusConverterMem = surplusConverter; require(surplusConverterMem != address(0), "0"); uint256 amount = interestsAccumulated; interestsAccumulated = 0; // Storing the `token` in memory to avoid duplicate reads in storage IERC20 tokenMem = token; tokenMem.safeTransfer(surplusConverterMem, amount); emit Recovered(address(tokenMem), surplusConverterMem, amount); } // ======================== Getters - View Functions =========================== /// @notice Gets the current balance of this `PoolManager` contract /// @return The amount of the underlying collateral that the contract currently owns /// @dev This balance does not take into account what has been lent to strategies function getBalance() external view override returns (uint256) { return _getBalance(); } /// @notice Gets the total amount of collateral that is controlled by this `PoolManager` contract /// @return The amount of collateral owned by this contract plus the amount that has been lent to strategies /// @dev This is the value that is used to compute the debt ratio for a given strategy function getTotalAsset() external view override returns (uint256) { return _getTotalAsset(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface 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); }
// 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: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @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 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 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: MIT pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a / b + (a % b == 0 ? 0 : 1); } }
// 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; /// @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: 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; /// @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 "./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; 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: 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 "./IAccessControl.sol"; /// @title IStrategy /// @author Inspired by Yearn with slight changes from Angle Core Team /// @notice Interface for yield farming strategies interface IStrategy is IAccessControl { function estimatedAPR() external view returns (uint256); function poolManager() external view returns (address); function want() external view returns (address); function isActive() external view returns (bool); function estimatedTotalAssets() external view returns (uint256); function harvestTrigger(uint256 callCost) external view returns (bool); function harvest() external; function withdraw(uint256 _amountNeeded) external returns (uint256 amountFreed, uint256 _loss); function setEmergencyExit() external; function addGuardian(address _guardian) external; function revokeGuardian(address _guardian) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; import "../external/AccessControlUpgradeable.sol"; import "../interfaces/IFeeManager.sol"; import "../interfaces/IPoolManager.sol"; import "../interfaces/ISanToken.sol"; import "../interfaces/IPerpetualManager.sol"; import "../interfaces/IStableMaster.sol"; import "../interfaces/IStrategy.sol"; import "../utils/FunctionUtils.sol"; /// @title PoolManagerEvents /// @author Angle Core Team /// @notice The `PoolManager` contract corresponds to a collateral pool of the protocol for a stablecoin, /// it manages a single ERC20 token. It is responsible for interacting with the strategies enabling the protocol /// to get yield on its collateral /// @dev This contract contains all the events of the `PoolManager` Contract contract PoolManagerEvents { event FeesDistributed(uint256 amountDistributed); event Recovered(address indexed token, address indexed to, uint256 amount); event StrategyAdded(address indexed strategy, uint256 debtRatio); event InterestsForSurplusUpdated(uint64 _interestsForSurplus); event SurplusConverterUpdated(address indexed newSurplusConverter, address indexed oldSurplusConverter); event StrategyRevoked(address indexed strategy); event StrategyReported( address indexed strategy, uint256 gain, uint256 loss, uint256 debtPayment, uint256 totalDebt ); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "./PoolManagerStorageV3.sol"; /// @title PoolManagerInternal /// @author Angle Core Team /// @notice The `PoolManager` contract corresponds to a collateral pool of the protocol for a stablecoin, /// it manages a single ERC20 token. It is responsible for interacting with the strategies enabling the protocol /// to get yield on its collateral /// @dev This file contains all the internal functions of the `PoolManager` contract contract PoolManagerInternal is PoolManagerStorageV3 { using SafeERC20 for IERC20; // Roles need to be defined here because there are some internal access control functions // in the `PoolManagerInternal` file /// @notice Role for `StableMaster` only bytes32 public constant STABLEMASTER_ROLE = keccak256("STABLEMASTER_ROLE"); /// @notice Role for governors only bytes32 public constant GOVERNOR_ROLE = keccak256("GOVERNOR_ROLE"); /// @notice Role for guardians and governors bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE"); /// @notice Role for `Strategy` only bytes32 public constant STRATEGY_ROLE = keccak256("STRATEGY_ROLE"); // ======================= Access Control and Governance ======================= /// @notice Adds a new guardian address and echoes the change to the contracts /// that interact with this collateral `PoolManager` /// @param _guardian New guardian address function _addGuardian(address _guardian) internal { // Granting the new role // Access control for this contract _grantRole(GUARDIAN_ROLE, _guardian); // Propagating the new role in other contract perpetualManager.grantRole(GUARDIAN_ROLE, _guardian); feeManager.grantRole(GUARDIAN_ROLE, _guardian); uint256 strategyListLength = strategyList.length; for (uint256 i = 0; i < strategyListLength; i++) { IStrategy(strategyList[i]).addGuardian(_guardian); } } /// @notice Revokes the guardian role and propagates the change to other contracts /// @param guardian Old guardian address to revoke function _revokeGuardian(address guardian) internal { _revokeRole(GUARDIAN_ROLE, guardian); perpetualManager.revokeRole(GUARDIAN_ROLE, guardian); feeManager.revokeRole(GUARDIAN_ROLE, guardian); uint256 strategyListLength = strategyList.length; for (uint256 i = 0; i < strategyListLength; i++) { IStrategy(strategyList[i]).revokeGuardian(guardian); } } // ============================= Yield Farming ================================= /// @notice Internal version of `updateStrategyDebtRatio` /// @dev Updates the debt ratio for a strategy function _updateStrategyDebtRatio(address strategy, uint256 _debtRatio) internal { StrategyParams storage params = strategies[strategy]; require(params.lastReport != 0, "78"); debtRatio = debtRatio + _debtRatio - params.debtRatio; require(debtRatio <= BASE_PARAMS, "76"); params.debtRatio = _debtRatio; emit StrategyAdded(strategy, debtRatio); } // ============================ Utils ========================================== /// @notice Returns this `PoolManager`'s reserve of collateral (not including what has been lent) function _getBalance() internal view returns (uint256) { return token.balanceOf(address(this)); } /// @notice Returns the amount of assets owned by this `PoolManager` /// @dev This sums the current balance of the contract to what has been given to strategies /// @dev This amount can be manipulated by flash loans function _getTotalAsset() internal view returns (uint256) { return _getBalance() + totalDebt; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "./PoolManagerEvents.sol"; /// @title PoolManagerStorageV1 /// @author Angle Core Team /// @notice The `PoolManager` contract corresponds to a collateral pool of the protocol for a stablecoin, /// it manages a single ERC20 token. It is responsible for interacting with the strategies enabling the protocol /// to get yield on its collateral /// @dev This file contains most of the variables and parameters stored for this contract. It does not contain all /// as the storage file has been split into multiple files to avoid clashes when upgrading the smart contract contract PoolManagerStorageV1 is PoolManagerEvents, FunctionUtils { // ================ References to contracts that cannot be modified ============ /// @notice Interface for the underlying token accepted by this contract IERC20 public token; /// @notice Reference to the `PerpetualManager` for this collateral/stablecoin pair /// `PerpetualManager` is an upgradeable contract, there is therefore no need to be able to update this reference IPerpetualManager public perpetualManager; /// @notice Reference to the `StableMaster` contract corresponding to this `PoolManager` IStableMaster public stableMaster; // ============== References to contracts that can be modified ================= /// @notice FeeManager contract for this collateral/stablecoin pair /// This reference can be updated by the `StableMaster` and change is going to be propagated /// to the `PerpetualManager` from this contract IFeeManager public feeManager; // ============================= Yield Farming ================================= /// @notice Funds currently given to strategies uint256 public totalDebt; /// @notice Proportion of the funds managed dedicated to strategies /// Has to be between 0 and `BASE_PARAMS` uint256 public debtRatio; /// The struct `StrategyParams` is defined in the interface `IPoolManager` /// @notice Mapping between the address of a strategy contract and its corresponding details mapping(address => StrategyParams) public strategies; /// @notice List of the current strategies address[] public strategyList; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "./PoolManagerStorageV1.sol"; /// @title PoolManagerStorageV2 /// @author Angle Core Team /// @notice The `PoolManager` contract corresponds to a collateral pool of the protocol for a stablecoin, /// it manages a single ERC20 token. It is responsible for interacting with the strategies enabling the protocol /// to get yield on its collateral /// @dev This file imports the `AccessControlUpgradeable` contract PoolManagerStorageV2 is PoolManagerStorageV1, AccessControlUpgradeable { }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "./PoolManagerStorageV2.sol"; /// @title PoolManagerStorageV3 /// @author Angle Core Team /// @notice The `PoolManager` contract corresponds to a collateral pool of the protocol for a stablecoin, /// it manages a single ERC20 token. It is responsible for interacting with the strategies enabling the protocol /// to get yield on its collateral /// @dev This file contains the last variables and parameters stored for this contract. The reason for not storing them /// directly in `PoolManagerStorageV1` is that theywere introduced after a first deployment and may have introduced a /// storage clash when upgrading contract PoolManagerStorageV3 is PoolManagerStorageV2 { /// @notice Address of the surplus distributor allowed to distribute rewards address public surplusConverter; /// @notice Share of the interests going to surplus and share going to SLPs uint64 public interestsForSurplus; /// @notice Interests accumulated by the protocol and to be distributed through ANGLE or veANGLE /// token holders uint256 public interestsAccumulated; /// @notice Debt that must be paid by admins after a loss on a strategy uint256 public adminDebt; }
// 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"); _; } }
{ "evmVersion": "london", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 1000000 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amountDistributed","type":"uint256"}],"name":"FeesDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"_interestsForSurplus","type":"uint64"}],"name":"InterestsForSurplusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","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":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":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"debtRatio","type":"uint256"}],"name":"StrategyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"gain","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loss","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtPayment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalDebt","type":"uint256"}],"name":"StrategyReported","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"StrategyRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newSurplusConverter","type":"address"},{"indexed":true,"internalType":"address","name":"oldSurplusConverter","type":"address"}],"name":"SurplusConverterUpdated","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":"GOVERNOR_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":"STABLEMASTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STRATEGY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_governor","type":"address"}],"name":"addGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"strategy","type":"address"},{"internalType":"uint256","name":"_debtRatio","type":"uint256"}],"name":"addStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"adminDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creditAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"debtOutstanding","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"debtRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"governorList","type":"address[]"},{"internalType":"address","name":"guardian","type":"address"},{"internalType":"contract IPerpetualManager","name":"_perpetualManager","type":"address"},{"internalType":"contract IFeeManager","name":"_feeManager","type":"address"},{"internalType":"contract IOracle","name":"_oracle","type":"address"}],"name":"deployCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"estimatedAPR","outputs":[{"internalType":"uint256","name":"apr","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeManager","outputs":[{"internalType":"contract IFeeManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[{"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":"address","name":"_token","type":"address"},{"internalType":"contract IStableMaster","name":"_stableMaster","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestsAccumulated","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestsForSurplus","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"perpetualManager","outputs":[{"internalType":"contract IPerpetualManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pushSurplus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amountToRecover","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_governor","type":"address"}],"name":"removeGovernor","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":"uint256","name":"gain","type":"uint256"},{"internalType":"uint256","name":"loss","type":"uint256"},{"internalType":"uint256","name":"debtPayment","type":"uint256"}],"name":"report","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"}],"name":"revokeGuardian","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":[{"internalType":"address","name":"strategy","type":"address"}],"name":"revokeStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IFeeManager","name":"_feeManager","type":"address"}],"name":"setFeeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_guardian","type":"address"},{"internalType":"address","name":"guardian","type":"address"}],"name":"setGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_interestsForSurplus","type":"uint64"}],"name":"setInterestsForSurplus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"strategy","type":"address"}],"name":"setStrategyEmergencyExit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSurplusConverter","type":"address"}],"name":"setSurplusConverter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stableMaster","outputs":[{"internalType":"contract IStableMaster","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"strategies","outputs":[{"internalType":"uint256","name":"lastReport","type":"uint256"},{"internalType":"uint256","name":"totalStrategyDebt","type":"uint256"},{"internalType":"uint256","name":"debtRatio","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"strategyList","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"surplusConverter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"strategy","type":"address"},{"internalType":"uint256","name":"_debtRatio","type":"uint256"}],"name":"updateStrategyDebtRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStrategy","name":"strategy","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawFromStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50614b11806100206000396000f3fe608060405234801561001057600080fd5b506004361061030a5760003560e01c806391d148541161019c578063c9411e22116100ee578063df1b8bd311610097578063fb6d442011610071578063fb6d442014610736578063fc0c546a14610756578063fc7b9c181461077657600080fd5b8063df1b8bd31461070b578063eecdac881461071a578063f0d3dc831461072d57600080fd5b8063d0fb0203116100c8578063d0fb0203146106c5578063d547741f146106e5578063d965ce9a146106f857600080fd5b8063c9411e2214610682578063ccc5749014610695578063cea55f57146106bc57600080fd5b8063a267526b11610150578063b53d09581161012a578063b53d095814610654578063bb994d4814610667578063bf3759b51461067a57600080fd5b8063a267526b14610625578063ae11e4c914610638578063af648c3d1461064157600080fd5b80639f48118f116101815780639f48118f146105ff578063a1d9bafc1461060a578063a217fddf1461061d57600080fd5b806391d14854146105965780639645150c146105ec57600080fd5b806336568abe11610260578063580b7c2e116102095780636ac5dc46116101e35780636ac5dc461461051e5780637c6a4f241461053e5780638e2e944f1461055157600080fd5b8063580b7c2e146104aa5780635a5cd45e146104d15780635d34082b146104d957600080fd5b8063472d35b91161023a578063472d35b914610471578063485cc955146104845780634c8b9f8d1461049757600080fd5b806336568abe1461040157806339ebf823146104145780633c4a25d01461045e57600080fd5b8063248a9ca3116102c25780632f2ff15d1161029c5780632f2ff15d146103c85780632f92d261146103db57806333c509d1146103ee57600080fd5b8063248a9ca31461037657806324ea54f4146103995780632768385d146103c057600080fd5b80631171bda9116102f35780631171bda91461035157806312065fe01461036657806319106b671461036e57600080fd5b80631112d6541461030f578063112c1f9b14610349575b600080fd5b6103367f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b5381565b6040519081526020015b60405180910390f35b61033661077f565b61036461035f3660046142a9565b6107f5565b005b610336610b9d565b610364610bac565b61033661038436600461441d565b60009081526009602052604090206001015490565b6103367f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a504181565b610336610cc5565b6103646103d6366004614436565b610ccf565b6103646103e9366004614236565b610cfa565b6103646103fc366004614270565b610df4565b61036461040f366004614436565b610e31565b610443610422366004614236565b60066020526000908152604090208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610340565b61036461046c366004614236565b610ebe565b61036461047f366004614236565b610f1c565b610364610492366004614270565b610fe3565b6103646104a5366004614624565b61133c565b6103367f928286c473ded01ff8bf61a1986f14a0579066072fa8261442d9fea514d93a4c81565b610336611469565b6001546104f99073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610340565b6002546104f99073ffffffffffffffffffffffffffffffffffffffff1681565b61036461054c3660046142ea565b6117be565b603b5461057d9074010000000000000000000000000000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610340565b6105dc6105a4366004614436565b600091825260096020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6040519015158152602001610340565b6103646105fa366004614236565b6117f3565b610336633b9aca0081565b6103646106183660046145f8565b611895565b610336600081565b6104f961063336600461441d565b611e14565b610336603c5481565b61036461064f366004614236565b611e4b565b6103646106623660046142ea565b611e7f565b610364610675366004614236565b61211b565b6103366124df565b6103646106903660046142ea565b61253e565b6103367f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b61033660055481565b6003546104f99073ffffffffffffffffffffffffffffffffffffffff1681565b6103646106f3366004614436565b612a21565b610364610706366004614316565b612a47565b610336670de0b6b3a764000081565b610364610728366004614236565b612d2d565b610336603d5481565b603b546104f99073ffffffffffffffffffffffffffffffffffffffff1681565b6000546104f99073ffffffffffffffffffffffffffffffffffffffff1681565b61033660045481565b33600090815260066020526040812060028101548290633b9aca00906107a3612d82565b6107ad91906148f9565b6107b791906148be565b905081600101548110156107ce5760009250505090565b6107ee8260010154826107e19190614936565b6107e9612d99565b612e3b565b9250505090565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556108208133612e53565b60005473ffffffffffffffffffffffffffffffffffffffff85811691161415610b0f576002546040517fba8b7223000000000000000000000000000000000000000000000000000000008152306004820152600091829182918291829173ffffffffffffffffffffffffffffffffffffffff169063ba8b72239060240160006040518083038186803b1580156108b557600080fd5b505afa1580156108c9573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261090f919081019061445b565b5050965096509650965050955050603c548473ffffffffffffffffffffffffffffffffffffffff1663442133bd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561096657600080fd5b505afa15801561097a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099e91906145bb565b6109a883866148f9565b6109b291906148be565b670de0b6b3a7640000848873ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610a0257600080fd5b505afa158015610a16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3a91906145bb565b610a4491906148f9565b610a4e91906148be565b610a58908a6148a6565b610a6291906148a6565b610a6c91906148a6565b610a74612d82565b1015610ae1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f363600000000000000000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600054610b059073ffffffffffffffffffffffffffffffffffffffff168989612f25565b5050505050610b30565b610b3073ffffffffffffffffffffffffffffffffffffffff85168484612f25565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167ffff3b3844276f57024e0b42afec1a37f75db36511e43819a4f2a63ab7862b64884604051610b8f91815260200190565b60405180910390a350505050565b6000610ba7612d99565b905090565b603b5473ffffffffffffffffffffffffffffffffffffffff1680610c2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600160248201527f30000000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b603c8054600091829055905473ffffffffffffffffffffffffffffffffffffffff16610c59818484612f25565b8273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167ffff3b3844276f57024e0b42afec1a37f75db36511e43819a4f2a63ab7862b64884604051610cb891815260200190565b60405180910390a3505050565b6000610ba7612d82565b600082815260096020526040902060010154610ceb8133612e53565b610cf58383612ff9565b505050565b7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041610d258133612e53565b610d308260006130b6565b8173ffffffffffffffffffffffffffffffffffffffff1663fcf2d0ad6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610d7857600080fd5b505af1158015610d8c573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff16634641257d6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610dd857600080fd5b505af1158015610dec573d6000803e3d6000fd5b505050505050565b7f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53610e1f8133612e53565b610e288261322c565b610cf583613470565b73ffffffffffffffffffffffffffffffffffffffff81163314610eb0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37310000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b610eba82826136b4565b5050565b7f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53610ee98133612e53565b610f137f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5583612ff9565b610eba82613470565b7f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53610f478133612e53565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8481169182179092556001546040517f472d35b900000000000000000000000000000000000000000000000000000000815260048101929092529091169063472d35b990602401600060405180830381600087803b158015610dd857600080fd5b600854610100900460ff1680610ffc575060085460ff16155b611088576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ad8565b600854610100900460ff161580156110c757600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000166101011790555b8273ffffffffffffffffffffffffffffffffffffffff8116611145576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600160248201527f30000000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b8273ffffffffffffffffffffffffffffffffffffffff81166111c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600160248201527f30000000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b6111cb61376f565b6002805473ffffffffffffffffffffffffffffffffffffffff8087167fffffffffffffffffffffffff000000000000000000000000000000000000000092831681179093556000805491891691909216179055611249907f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b539061388d565b6112737f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b5380613897565b6112bd7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f557f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53613897565b6113077f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a50417f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53613897565b50508015610cf557600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055505050565b7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a50416113678133612e53565b81633b9aca008167ffffffffffffffff1611156113e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600160248201527f34000000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b603b80547fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000067ffffffffffffffff8616908102919091179091556040519081527ffc758ec4944790c229f9320c389bbbb662de11b31936338e0b6359633d8252a29060200160405180910390a1505050565b6002546040517fba8b722300000000000000000000000000000000000000000000000000000000815230600482015260009182918291829173ffffffffffffffffffffffffffffffffffffffff9091169063ba8b72239060240160006040518083038186803b1580156114db57600080fd5b505afa1580156114ef573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611535919081019061445b565b50975050965050505093505060008373ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561158957600080fd5b505afa15801561159d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c191906145bb565b9050806115f2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff94505050505090565b60005b60075481101561173c57633b9aca006007828154811061161757611617614a45565b60009182526020918290200154604080517f5a5cd45e000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff90921692635a5cd45e92600480840193829003018186803b15801561168657600080fd5b505afa15801561169a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116be91906145bb565b60066000600785815481106116d5576116d5614a45565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff16835282019290925260400190206002015461171491906148f9565b61171e91906148be565b61172890876148a6565b955080611734816149ae565b9150506115f5565b508083611747612d82565b60e0850151603b5467ffffffffffffffff918216916117839174010000000000000000000000000000000000000000900416633b9aca00614936565b61178d908a6148f9565b61179791906148f9565b6117a191906148f9565b6117ab91906148be565b6117b591906148be565b94505050505090565b7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a50416117e98133612e53565b610cf583836130b6565b7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a504161181e8133612e53565b603b805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff00000000000000000000000000000000000000008316811790935560405191169182917f36c96a1bbba632dc500787b9d915ec93cac3f4be4af3e6855403f9cbcac3893d90600090a3505050565b7f928286c473ded01ff8bf61a1986f14a0579066072fa8261442d9fea514d93a4c6118c08133612e53565b6118ca82856148a6565b6000546040517f70a0823100000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a082319060240160206040518083038186803b15801561193357600080fd5b505afa158015611947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196b91906145bb565b10156119d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37320000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b336000908152600660205260409020600181015484906119f49087906148a6565b6119fe9190614936565b60018201556004548490611a139087906148a6565b611a1d9190614936565b6004554281556002810154600090633b9aca0090611a39612d82565b611a4391906148f9565b611a4d91906148be565b90508160010154811115611ac8576000611a708360010154836107e19190614936565b9050808360010154611a8291906148a6565b6001840155600454611a959082906148a6565b6004558015611ac257600054611ac29073ffffffffffffffffffffffffffffffffffffffff163383612f25565b50611b3c565b6000611ae7828460010154611add9190614936565b6107e989886148a6565b9050808360010154611af99190614936565b6001840155600454611b0c908290614936565b6004558015611b3a57600054611b3a9073ffffffffffffffffffffffffffffffffffffffff163330846138eb565b505b60018201546040805188815260208101889052908101869052606081019190915233907ff106b42df1ee4f4cdf6104dd274c895b074a7162dc67ce53c1de471237c2999c9060800160405180910390a28515611cf957603b54600090633b9aca0090611bca9074010000000000000000000000000000000000000000900467ffffffffffffffff16896148f9565b611bd491906148be565b603d5490915080611bfc5781603c6000828254611bf191906148a6565b90915550611c459050565b818111611c2d57611c0d8183614936565b603c6000828254611c1e91906148a6565b90915550506000603d55611c45565b81603d6000828254611c3f9190614936565b90915550505b60025473ffffffffffffffffffffffffffffffffffffffff1663087264c9611c6d848b614936565b6040518263ffffffff1660e01b8152600401611c8b91815260200190565b600060405180830381600087803b158015611ca557600080fd5b505af1158015611cb9573d6000803e3d6000fd5b505050507f8959421a1320789a49eeec01a4750caf8a30733c3db14f000d84484df89300f988604051611cee91815260200190565b60405180910390a150505b8415610dec57603b54600090633b9aca0090611d379074010000000000000000000000000000000000000000900467ffffffffffffffff16886148f9565b611d4191906148be565b603c5490915080821115611d7a576000603c55611d5e8183614936565b603d6000828254611d6f91906148a6565b90915550611d929050565b81603c6000828254611d8c9190614936565b90915550505b60025473ffffffffffffffffffffffffffffffffffffffff1663252c9406611dba848a614936565b6040518263ffffffff1660e01b8152600401611dd891815260200190565b600060405180830381600087803b158015611df257600080fd5b505af1158015611e06573d6000803e3d6000fd5b505050505050505050505050565b60078181548110611e2457600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b7f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53611e768133612e53565b610eba8261322c565b7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041611eaa8133612e53565b73ffffffffffffffffffffffffffffffffffffffff831660009081526006602052604090208054611f37576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37380000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b6040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810184905260009073ffffffffffffffffffffffffffffffffffffffff861690632e1a7d4d906024016040805180830381600087803b158015611fa157600080fd5b505af1158015611fb5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd991906145d4565b600184015491955091508490611ff0908390614936565b611ffa9190614936565b6001830155600454849061200f908390614936565b6120199190614936565b60045573ffffffffffffffffffffffffffffffffffffffff85167ff106b42df1ee4f4cdf6104dd274c895b074a7162dc67ce53c1de471237c2999c6000836120618189614936565b600187015460408051948552602085019390935291830152606082015260800160405180910390a28015612114576002546040517f252c94060000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff9091169063252c940690602401600060405180830381600087803b1580156120fb57600080fd5b505af115801561210f573d6000803e3d6000fd5b505050505b5050505050565b7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a50416121468133612e53565b73ffffffffffffffffffffffffffffffffffffffff821660009081526006602052604090206002810154156121d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37370000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b600181015415612243576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37370000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b600754815415801590612257575060018110155b6122bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37380000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b60005b6122cb600183614936565b8110156123d9578473ffffffffffffffffffffffffffffffffffffffff16600782815481106122fc576122fc614a45565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1614156123c7576007612331600184614936565b8154811061234157612341614a45565b6000918252602090912001546007805473ffffffffffffffffffffffffffffffffffffffff909216918390811061237a5761237a614a45565b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506123d9565b806123d1816149ae565b9150506122c0565b5060078054806123eb576123eb614a16565b6001900381819060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905590558160020154600560008282546124369190614936565b909155505073ffffffffffffffffffffffffffffffffffffffff8416600090815260066020526040812081815560018101829055600201556124987f928286c473ded01ff8bf61a1986f14a0579066072fa8261442d9fea514d93a4c856136b4565b60405173ffffffffffffffffffffffffffffffffffffffff8516907f4201c688d84c01154d321afa0c72f1bffe9eef53005c9de9d035074e71e9b32a90600090a250505050565b33600090815260066020526040812060028101548290633b9aca0090612503612d82565b61250d91906148f9565b61251791906148be565b9050816001015481111561252e5760009250505090565b8082600101546107ee9190614936565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556125698133612e53565b8273ffffffffffffffffffffffffffffffffffffffff81166125e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600160248201527f30000000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600660205260409020805415612675576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37330000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b8473ffffffffffffffffffffffffffffffffffffffff1663dc4c90d36040518163ffffffff1660e01b815260040160206040518083038186803b1580156126bb57600080fd5b505afa1580156126cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f39190614253565b73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614612787576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37340000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b8473ffffffffffffffffffffffffffffffffffffffff16631f1fcd516040518163ffffffff1660e01b815260040160206040518083038186803b1580156127cd57600080fd5b505afa1580156127e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128059190614253565b60005473ffffffffffffffffffffffffffffffffffffffff908116911614612889576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37350000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b633b9aca008460055461289c91906148a6565b1115612904576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37360000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b6001808255600090820155600281018490556129407f928286c473ded01ff8bf61a1986f14a0579066072fa8261442d9fea514d93a4c86612ff9565b836005600082825461295291906148a6565b909155505060055460405190815273ffffffffffffffffffffffffffffffffffffffff8616907f2f564a83158ad1831793ad3e69257b52f39ece5d49cb0d8746708ecb9ef964da9060200160405180910390a25050600780546001810182556000919091527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff94909416939093179092555050565b600082815260096020526040902060010154612a3d8133612e53565b610cf583836136b4565b7f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53612a728133612e53565b6001805473ffffffffffffffffffffffffffffffffffffffff8087167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255600380549286169290911691909117905560005b8651811015612b5e57612b167f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55888381518110612b0957612b09614a45565b6020026020010151612ff9565b612b4c7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041888381518110612b0957612b09614a45565b80612b56816149ae565b915050612aca565b50612b897f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a504186612ff9565b6001546040517fb126e7e500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063b126e7e590612be590899089908890889060040161476f565b600060405180830381600087803b158015612bff57600080fd5b505af1158015612c13573d6000803e3d6000fd5b50506040517f8d40452700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86169250638d4045279150612c6d9089908990899060040161472f565b600060405180830381600087803b158015612c8757600080fd5b505af1158015612c9b573d6000803e3d6000fd5b5050600254600054612ce9935073ffffffffffffffffffffffffffffffffffffffff9081169250167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61394f565b600054610dec9073ffffffffffffffffffffffffffffffffffffffff16857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61394f565b7f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53612d588133612e53565b611e767f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55836136b4565b6000600454612d8f612d99565b610ba791906148a6565b600080546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a082319060240160206040518083038186803b158015612e0357600080fd5b505afa158015612e17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba791906145bb565b6000818310612e4a5781612e4c565b825b9392505050565b600082815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610eba57612eab8173ffffffffffffffffffffffffffffffffffffffff166014613a5c565b612eb6836020613a5c565b604051602001612ec79291906146ae565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a0000000000000000000000000000000000000000000000000000000008252610ad8916004016147b8565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610cf59084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613c9f565b600082815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610eba57600082815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b73ffffffffffffffffffffffffffffffffffffffff821660009081526006602052604090208054613143576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37380000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b80600201548260055461315691906148a6565b6131609190614936565b6005819055633b9aca0010156131d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37360000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b6002810182905560055460405190815273ffffffffffffffffffffffffffffffffffffffff8416907f2f564a83158ad1831793ad3e69257b52f39ece5d49cb0d8746708ecb9ef964da9060200160405180910390a2505050565b6132567f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041826136b4565b6001546040517fd547741f0000000000000000000000000000000000000000000000000000000081527f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041600482015273ffffffffffffffffffffffffffffffffffffffff83811660248301529091169063d547741f90604401600060405180830381600087803b1580156132e957600080fd5b505af11580156132fd573d6000803e3d6000fd5b50506003546040517fd547741f0000000000000000000000000000000000000000000000000000000081527f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041600482015273ffffffffffffffffffffffffffffffffffffffff8581166024830152909116925063d547741f9150604401600060405180830381600087803b15801561339457600080fd5b505af11580156133a8573d6000803e3d6000fd5b50506007549150600090505b81811015610cf557600781815481106133cf576133cf614a45565b6000918252602090912001546040517faf648c3d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301529091169063af648c3d90602401600060405180830381600087803b15801561344557600080fd5b505af1158015613459573d6000803e3d6000fd5b505050508080613468906149ae565b9150506133b4565b61349a7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a504182612ff9565b6001546040517f2f2ff15d0000000000000000000000000000000000000000000000000000000081527f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015290911690632f2ff15d90604401600060405180830381600087803b15801561352d57600080fd5b505af1158015613541573d6000803e3d6000fd5b50506003546040517f2f2ff15d0000000000000000000000000000000000000000000000000000000081527f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041600482015273ffffffffffffffffffffffffffffffffffffffff85811660248301529091169250632f2ff15d9150604401600060405180830381600087803b1580156135d857600080fd5b505af11580156135ec573d6000803e3d6000fd5b50506007549150600090505b81811015610cf5576007818154811061361357613613614a45565b6000918252602090912001546040517fa526d83b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301529091169063a526d83b90602401600060405180830381600087803b15801561368957600080fd5b505af115801561369d573d6000803e3d6000fd5b5050505080806136ac906149ae565b9150506135f8565b600082815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610eba57600082815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600854610100900460ff1680613788575060085460ff16155b613814576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ad8565b600854610100900460ff1615801561385357600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000166101011790555b61385b613dab565b801561388a57600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b50565b610eba8282612ff9565b600082815260096020526040902060010154819060405184907fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff90600090a460009182526009602052604090912060010155565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526139499085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612f77565b50505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e9060440160206040518083038186803b1580156139c157600080fd5b505afa1580156139d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139f991906145bb565b613a0391906148a6565b60405173ffffffffffffffffffffffffffffffffffffffff85166024820152604481018290529091506139499085907f095ea7b30000000000000000000000000000000000000000000000000000000090606401612f77565b60606000613a6b8360026148f9565b613a769060026148a6565b67ffffffffffffffff811115613a8e57613a8e614a74565b6040519080825280601f01601f191660200182016040528015613ab8576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110613aef57613aef614a45565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110613b5257613b52614a45565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000613b8e8460026148f9565b613b999060016148a6565b90505b6001811115613c36577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110613bda57613bda614a45565b1a60f81b828281518110613bf057613bf0614a45565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93613c2f81614979565b9050613b9c565b508315612e4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610ad8565b6000613d01826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16613ebf9092919063ffffffff16565b805190915015610cf55780806020019051810190613d1f91906143fb565b610cf5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610ad8565b600854610100900460ff1680613dc4575060085460ff16155b613e50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ad8565b600854610100900460ff1615801561385b57600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016610101179055801561388a57600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905550565b6060613ece8484600085613ed6565b949350505050565b606082471015613f68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610ad8565b843b613fd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ad8565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051613ff99190614692565b60006040518083038185875af1925050503d8060008114614036576040519150601f19603f3d011682016040523d82523d6000602084013e61403b565b606091505b509150915061404b828286614056565b979650505050505050565b60608315614065575081612e4c565b8251156140755782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ad891906147b8565b80356140b481614aa3565b919050565b600082601f8301126140ca57600080fd5b815160206140df6140da83614882565b614833565b80838252828201915082860187848660051b89010111156140ff57600080fd5b60005b8581101561412757815161411581614ac5565b84529284019290840190600101614102565b5090979650505050505050565b6000610100828403121561414757600080fd5b61414f614809565b9050815167ffffffffffffffff8082111561416957600080fd5b614175858386016140b9565b8352602084015191508082111561418b57600080fd5b614197858386016140b9565b602084015260408401519150808211156141b057600080fd5b6141bc858386016140b9565b604084015260608401519150808211156141d557600080fd5b506141e2848285016140b9565b6060830152506141f46080830161422b565b608082015261420560a0830161422b565b60a082015261421660c0830161422b565b60c082015260e082015160e082015292915050565b80516140b481614ac5565b60006020828403121561424857600080fd5b8135612e4c81614aa3565b60006020828403121561426557600080fd5b8151612e4c81614aa3565b6000806040838503121561428357600080fd5b823561428e81614aa3565b9150602083013561429e81614aa3565b809150509250929050565b6000806000606084860312156142be57600080fd5b83356142c981614aa3565b925060208401356142d981614aa3565b929592945050506040919091013590565b600080604083850312156142fd57600080fd5b823561430881614aa3565b946020939093013593505050565b600080600080600060a0868803121561432e57600080fd5b853567ffffffffffffffff81111561434557600080fd5b8601601f8101881361435657600080fd5b803560206143666140da83614882565b8083825282820191508285018c848660051b880101111561438657600080fd5b600095505b848610156143b257803561439e81614aa3565b83526001959095019491830191830161438b565b5098506143c290508982016140a9565b96505050506143d3604087016140a9565b92506143e1606087016140a9565b91506143ef608087016140a9565b90509295509295909350565b60006020828403121561440d57600080fd5b81518015158114612e4c57600080fd5b60006020828403121561442f57600080fd5b5035919050565b6000806040838503121561444957600080fd5b82359150602083013561429e81614aa3565b6000806000806000806000806000898b0361020081121561447b57600080fd5b8a5161448681614aa3565b60208c0151909a5061449781614aa3565b60408c01519099506144a881614aa3565b60608c01519098506144b981614aa3565b8097505060808b0151955060a08b0151945060c08b01519350610100807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff208301121561450457600080fd5b61450c614809565b915060e08c01518252808c01516020830152506101208b015160408201526101408b015160608201526101608b015161454481614ac5565b60808201526101808b015161455881614ac5565b60a082015261456a6101a08c0161422b565b60c082015261457c6101c08c0161422b565b60e08201526101e08b015190925067ffffffffffffffff81111561459f57600080fd5b6145ab8c828d01614134565b9150509295985092959850929598565b6000602082840312156145cd57600080fd5b5051919050565b600080604083850312156145e757600080fd5b505080516020909101519092909150565b60008060006060848603121561460d57600080fd5b505081359360208301359350604090920135919050565b60006020828403121561463657600080fd5b8135612e4c81614ac5565b600081518084526020808501945080840160005b8381101561468757815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614655565b509495945050505050565b600082516146a481846020870161494d565b9190910192915050565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516146e681601785016020880161494d565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835161472381602884016020880161494d565b01602801949350505050565b6060815260006147426060830186614641565b73ffffffffffffffffffffffffffffffffffffffff94851660208401529290931660409091015292915050565b6080815260006147826080830187614641565b73ffffffffffffffffffffffffffffffffffffffff95861660208401529385166040830152509216606090920191909152919050565b60208152600082518060208401526147d781604085016020870161494d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b604051610100810167ffffffffffffffff8111828210171561482d5761482d614a74565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561487a5761487a614a74565b604052919050565b600067ffffffffffffffff82111561489c5761489c614a74565b5060051b60200190565b600082198211156148b9576148b96149e7565b500190565b6000826148f4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614931576149316149e7565b500290565b600082821015614948576149486149e7565b500390565b60005b83811015614968578181015183820152602001614950565b838111156139495750506000910152565b600081614988576149886149e7565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156149e0576149e06149e7565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461388a57600080fd5b67ffffffffffffffff8116811461388a57600080fdfea264697066735822122043e08a6653b827e0baa057c6f4def796677dbd170d546615b605cc99b8549da464736f6c63430008070033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061030a5760003560e01c806391d148541161019c578063c9411e22116100ee578063df1b8bd311610097578063fb6d442011610071578063fb6d442014610736578063fc0c546a14610756578063fc7b9c181461077657600080fd5b8063df1b8bd31461070b578063eecdac881461071a578063f0d3dc831461072d57600080fd5b8063d0fb0203116100c8578063d0fb0203146106c5578063d547741f146106e5578063d965ce9a146106f857600080fd5b8063c9411e2214610682578063ccc5749014610695578063cea55f57146106bc57600080fd5b8063a267526b11610150578063b53d09581161012a578063b53d095814610654578063bb994d4814610667578063bf3759b51461067a57600080fd5b8063a267526b14610625578063ae11e4c914610638578063af648c3d1461064157600080fd5b80639f48118f116101815780639f48118f146105ff578063a1d9bafc1461060a578063a217fddf1461061d57600080fd5b806391d14854146105965780639645150c146105ec57600080fd5b806336568abe11610260578063580b7c2e116102095780636ac5dc46116101e35780636ac5dc461461051e5780637c6a4f241461053e5780638e2e944f1461055157600080fd5b8063580b7c2e146104aa5780635a5cd45e146104d15780635d34082b146104d957600080fd5b8063472d35b91161023a578063472d35b914610471578063485cc955146104845780634c8b9f8d1461049757600080fd5b806336568abe1461040157806339ebf823146104145780633c4a25d01461045e57600080fd5b8063248a9ca3116102c25780632f2ff15d1161029c5780632f2ff15d146103c85780632f92d261146103db57806333c509d1146103ee57600080fd5b8063248a9ca31461037657806324ea54f4146103995780632768385d146103c057600080fd5b80631171bda9116102f35780631171bda91461035157806312065fe01461036657806319106b671461036e57600080fd5b80631112d6541461030f578063112c1f9b14610349575b600080fd5b6103367f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b5381565b6040519081526020015b60405180910390f35b61033661077f565b61036461035f3660046142a9565b6107f5565b005b610336610b9d565b610364610bac565b61033661038436600461441d565b60009081526009602052604090206001015490565b6103367f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a504181565b610336610cc5565b6103646103d6366004614436565b610ccf565b6103646103e9366004614236565b610cfa565b6103646103fc366004614270565b610df4565b61036461040f366004614436565b610e31565b610443610422366004614236565b60066020526000908152604090208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610340565b61036461046c366004614236565b610ebe565b61036461047f366004614236565b610f1c565b610364610492366004614270565b610fe3565b6103646104a5366004614624565b61133c565b6103367f928286c473ded01ff8bf61a1986f14a0579066072fa8261442d9fea514d93a4c81565b610336611469565b6001546104f99073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610340565b6002546104f99073ffffffffffffffffffffffffffffffffffffffff1681565b61036461054c3660046142ea565b6117be565b603b5461057d9074010000000000000000000000000000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610340565b6105dc6105a4366004614436565b600091825260096020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6040519015158152602001610340565b6103646105fa366004614236565b6117f3565b610336633b9aca0081565b6103646106183660046145f8565b611895565b610336600081565b6104f961063336600461441d565b611e14565b610336603c5481565b61036461064f366004614236565b611e4b565b6103646106623660046142ea565b611e7f565b610364610675366004614236565b61211b565b6103366124df565b6103646106903660046142ea565b61253e565b6103367f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b61033660055481565b6003546104f99073ffffffffffffffffffffffffffffffffffffffff1681565b6103646106f3366004614436565b612a21565b610364610706366004614316565b612a47565b610336670de0b6b3a764000081565b610364610728366004614236565b612d2d565b610336603d5481565b603b546104f99073ffffffffffffffffffffffffffffffffffffffff1681565b6000546104f99073ffffffffffffffffffffffffffffffffffffffff1681565b61033660045481565b33600090815260066020526040812060028101548290633b9aca00906107a3612d82565b6107ad91906148f9565b6107b791906148be565b905081600101548110156107ce5760009250505090565b6107ee8260010154826107e19190614936565b6107e9612d99565b612e3b565b9250505090565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556108208133612e53565b60005473ffffffffffffffffffffffffffffffffffffffff85811691161415610b0f576002546040517fba8b7223000000000000000000000000000000000000000000000000000000008152306004820152600091829182918291829173ffffffffffffffffffffffffffffffffffffffff169063ba8b72239060240160006040518083038186803b1580156108b557600080fd5b505afa1580156108c9573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261090f919081019061445b565b5050965096509650965050955050603c548473ffffffffffffffffffffffffffffffffffffffff1663442133bd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561096657600080fd5b505afa15801561097a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099e91906145bb565b6109a883866148f9565b6109b291906148be565b670de0b6b3a7640000848873ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610a0257600080fd5b505afa158015610a16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3a91906145bb565b610a4491906148f9565b610a4e91906148be565b610a58908a6148a6565b610a6291906148a6565b610a6c91906148a6565b610a74612d82565b1015610ae1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f363600000000000000000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600054610b059073ffffffffffffffffffffffffffffffffffffffff168989612f25565b5050505050610b30565b610b3073ffffffffffffffffffffffffffffffffffffffff85168484612f25565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167ffff3b3844276f57024e0b42afec1a37f75db36511e43819a4f2a63ab7862b64884604051610b8f91815260200190565b60405180910390a350505050565b6000610ba7612d99565b905090565b603b5473ffffffffffffffffffffffffffffffffffffffff1680610c2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600160248201527f30000000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b603c8054600091829055905473ffffffffffffffffffffffffffffffffffffffff16610c59818484612f25565b8273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167ffff3b3844276f57024e0b42afec1a37f75db36511e43819a4f2a63ab7862b64884604051610cb891815260200190565b60405180910390a3505050565b6000610ba7612d82565b600082815260096020526040902060010154610ceb8133612e53565b610cf58383612ff9565b505050565b7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041610d258133612e53565b610d308260006130b6565b8173ffffffffffffffffffffffffffffffffffffffff1663fcf2d0ad6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610d7857600080fd5b505af1158015610d8c573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff16634641257d6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610dd857600080fd5b505af1158015610dec573d6000803e3d6000fd5b505050505050565b7f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53610e1f8133612e53565b610e288261322c565b610cf583613470565b73ffffffffffffffffffffffffffffffffffffffff81163314610eb0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37310000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b610eba82826136b4565b5050565b7f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53610ee98133612e53565b610f137f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5583612ff9565b610eba82613470565b7f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53610f478133612e53565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8481169182179092556001546040517f472d35b900000000000000000000000000000000000000000000000000000000815260048101929092529091169063472d35b990602401600060405180830381600087803b158015610dd857600080fd5b600854610100900460ff1680610ffc575060085460ff16155b611088576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ad8565b600854610100900460ff161580156110c757600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000166101011790555b8273ffffffffffffffffffffffffffffffffffffffff8116611145576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600160248201527f30000000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b8273ffffffffffffffffffffffffffffffffffffffff81166111c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600160248201527f30000000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b6111cb61376f565b6002805473ffffffffffffffffffffffffffffffffffffffff8087167fffffffffffffffffffffffff000000000000000000000000000000000000000092831681179093556000805491891691909216179055611249907f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b539061388d565b6112737f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b5380613897565b6112bd7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f557f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53613897565b6113077f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a50417f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53613897565b50508015610cf557600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055505050565b7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a50416113678133612e53565b81633b9aca008167ffffffffffffffff1611156113e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600160248201527f34000000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b603b80547fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000067ffffffffffffffff8616908102919091179091556040519081527ffc758ec4944790c229f9320c389bbbb662de11b31936338e0b6359633d8252a29060200160405180910390a1505050565b6002546040517fba8b722300000000000000000000000000000000000000000000000000000000815230600482015260009182918291829173ffffffffffffffffffffffffffffffffffffffff9091169063ba8b72239060240160006040518083038186803b1580156114db57600080fd5b505afa1580156114ef573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611535919081019061445b565b50975050965050505093505060008373ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561158957600080fd5b505afa15801561159d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c191906145bb565b9050806115f2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff94505050505090565b60005b60075481101561173c57633b9aca006007828154811061161757611617614a45565b60009182526020918290200154604080517f5a5cd45e000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff90921692635a5cd45e92600480840193829003018186803b15801561168657600080fd5b505afa15801561169a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116be91906145bb565b60066000600785815481106116d5576116d5614a45565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff16835282019290925260400190206002015461171491906148f9565b61171e91906148be565b61172890876148a6565b955080611734816149ae565b9150506115f5565b508083611747612d82565b60e0850151603b5467ffffffffffffffff918216916117839174010000000000000000000000000000000000000000900416633b9aca00614936565b61178d908a6148f9565b61179791906148f9565b6117a191906148f9565b6117ab91906148be565b6117b591906148be565b94505050505090565b7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a50416117e98133612e53565b610cf583836130b6565b7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a504161181e8133612e53565b603b805473ffffffffffffffffffffffffffffffffffffffff8481167fffffffffffffffffffffffff00000000000000000000000000000000000000008316811790935560405191169182917f36c96a1bbba632dc500787b9d915ec93cac3f4be4af3e6855403f9cbcac3893d90600090a3505050565b7f928286c473ded01ff8bf61a1986f14a0579066072fa8261442d9fea514d93a4c6118c08133612e53565b6118ca82856148a6565b6000546040517f70a0823100000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a082319060240160206040518083038186803b15801561193357600080fd5b505afa158015611947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196b91906145bb565b10156119d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37320000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b336000908152600660205260409020600181015484906119f49087906148a6565b6119fe9190614936565b60018201556004548490611a139087906148a6565b611a1d9190614936565b6004554281556002810154600090633b9aca0090611a39612d82565b611a4391906148f9565b611a4d91906148be565b90508160010154811115611ac8576000611a708360010154836107e19190614936565b9050808360010154611a8291906148a6565b6001840155600454611a959082906148a6565b6004558015611ac257600054611ac29073ffffffffffffffffffffffffffffffffffffffff163383612f25565b50611b3c565b6000611ae7828460010154611add9190614936565b6107e989886148a6565b9050808360010154611af99190614936565b6001840155600454611b0c908290614936565b6004558015611b3a57600054611b3a9073ffffffffffffffffffffffffffffffffffffffff163330846138eb565b505b60018201546040805188815260208101889052908101869052606081019190915233907ff106b42df1ee4f4cdf6104dd274c895b074a7162dc67ce53c1de471237c2999c9060800160405180910390a28515611cf957603b54600090633b9aca0090611bca9074010000000000000000000000000000000000000000900467ffffffffffffffff16896148f9565b611bd491906148be565b603d5490915080611bfc5781603c6000828254611bf191906148a6565b90915550611c459050565b818111611c2d57611c0d8183614936565b603c6000828254611c1e91906148a6565b90915550506000603d55611c45565b81603d6000828254611c3f9190614936565b90915550505b60025473ffffffffffffffffffffffffffffffffffffffff1663087264c9611c6d848b614936565b6040518263ffffffff1660e01b8152600401611c8b91815260200190565b600060405180830381600087803b158015611ca557600080fd5b505af1158015611cb9573d6000803e3d6000fd5b505050507f8959421a1320789a49eeec01a4750caf8a30733c3db14f000d84484df89300f988604051611cee91815260200190565b60405180910390a150505b8415610dec57603b54600090633b9aca0090611d379074010000000000000000000000000000000000000000900467ffffffffffffffff16886148f9565b611d4191906148be565b603c5490915080821115611d7a576000603c55611d5e8183614936565b603d6000828254611d6f91906148a6565b90915550611d929050565b81603c6000828254611d8c9190614936565b90915550505b60025473ffffffffffffffffffffffffffffffffffffffff1663252c9406611dba848a614936565b6040518263ffffffff1660e01b8152600401611dd891815260200190565b600060405180830381600087803b158015611df257600080fd5b505af1158015611e06573d6000803e3d6000fd5b505050505050505050505050565b60078181548110611e2457600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b7f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53611e768133612e53565b610eba8261322c565b7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041611eaa8133612e53565b73ffffffffffffffffffffffffffffffffffffffff831660009081526006602052604090208054611f37576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37380000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b6040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810184905260009073ffffffffffffffffffffffffffffffffffffffff861690632e1a7d4d906024016040805180830381600087803b158015611fa157600080fd5b505af1158015611fb5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd991906145d4565b600184015491955091508490611ff0908390614936565b611ffa9190614936565b6001830155600454849061200f908390614936565b6120199190614936565b60045573ffffffffffffffffffffffffffffffffffffffff85167ff106b42df1ee4f4cdf6104dd274c895b074a7162dc67ce53c1de471237c2999c6000836120618189614936565b600187015460408051948552602085019390935291830152606082015260800160405180910390a28015612114576002546040517f252c94060000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff9091169063252c940690602401600060405180830381600087803b1580156120fb57600080fd5b505af115801561210f573d6000803e3d6000fd5b505050505b5050505050565b7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a50416121468133612e53565b73ffffffffffffffffffffffffffffffffffffffff821660009081526006602052604090206002810154156121d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37370000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b600181015415612243576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37370000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b600754815415801590612257575060018110155b6122bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37380000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b60005b6122cb600183614936565b8110156123d9578473ffffffffffffffffffffffffffffffffffffffff16600782815481106122fc576122fc614a45565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1614156123c7576007612331600184614936565b8154811061234157612341614a45565b6000918252602090912001546007805473ffffffffffffffffffffffffffffffffffffffff909216918390811061237a5761237a614a45565b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506123d9565b806123d1816149ae565b9150506122c0565b5060078054806123eb576123eb614a16565b6001900381819060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905590558160020154600560008282546124369190614936565b909155505073ffffffffffffffffffffffffffffffffffffffff8416600090815260066020526040812081815560018101829055600201556124987f928286c473ded01ff8bf61a1986f14a0579066072fa8261442d9fea514d93a4c856136b4565b60405173ffffffffffffffffffffffffffffffffffffffff8516907f4201c688d84c01154d321afa0c72f1bffe9eef53005c9de9d035074e71e9b32a90600090a250505050565b33600090815260066020526040812060028101548290633b9aca0090612503612d82565b61250d91906148f9565b61251791906148be565b9050816001015481111561252e5760009250505090565b8082600101546107ee9190614936565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556125698133612e53565b8273ffffffffffffffffffffffffffffffffffffffff81166125e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600160248201527f30000000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600660205260409020805415612675576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37330000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b8473ffffffffffffffffffffffffffffffffffffffff1663dc4c90d36040518163ffffffff1660e01b815260040160206040518083038186803b1580156126bb57600080fd5b505afa1580156126cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f39190614253565b73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614612787576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37340000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b8473ffffffffffffffffffffffffffffffffffffffff16631f1fcd516040518163ffffffff1660e01b815260040160206040518083038186803b1580156127cd57600080fd5b505afa1580156127e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128059190614253565b60005473ffffffffffffffffffffffffffffffffffffffff908116911614612889576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37350000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b633b9aca008460055461289c91906148a6565b1115612904576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37360000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b6001808255600090820155600281018490556129407f928286c473ded01ff8bf61a1986f14a0579066072fa8261442d9fea514d93a4c86612ff9565b836005600082825461295291906148a6565b909155505060055460405190815273ffffffffffffffffffffffffffffffffffffffff8616907f2f564a83158ad1831793ad3e69257b52f39ece5d49cb0d8746708ecb9ef964da9060200160405180910390a25050600780546001810182556000919091527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff94909416939093179092555050565b600082815260096020526040902060010154612a3d8133612e53565b610cf583836136b4565b7f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53612a728133612e53565b6001805473ffffffffffffffffffffffffffffffffffffffff8087167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255600380549286169290911691909117905560005b8651811015612b5e57612b167f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55888381518110612b0957612b09614a45565b6020026020010151612ff9565b612b4c7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041888381518110612b0957612b09614a45565b80612b56816149ae565b915050612aca565b50612b897f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a504186612ff9565b6001546040517fb126e7e500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063b126e7e590612be590899089908890889060040161476f565b600060405180830381600087803b158015612bff57600080fd5b505af1158015612c13573d6000803e3d6000fd5b50506040517f8d40452700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86169250638d4045279150612c6d9089908990899060040161472f565b600060405180830381600087803b158015612c8757600080fd5b505af1158015612c9b573d6000803e3d6000fd5b5050600254600054612ce9935073ffffffffffffffffffffffffffffffffffffffff9081169250167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61394f565b600054610dec9073ffffffffffffffffffffffffffffffffffffffff16857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61394f565b7f42e87691d7920cf38a77ca8920f5a4c84f1b5ae359a91577fea4018facdd7b53612d588133612e53565b611e767f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55836136b4565b6000600454612d8f612d99565b610ba791906148a6565b600080546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a082319060240160206040518083038186803b158015612e0357600080fd5b505afa158015612e17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba791906145bb565b6000818310612e4a5781612e4c565b825b9392505050565b600082815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610eba57612eab8173ffffffffffffffffffffffffffffffffffffffff166014613a5c565b612eb6836020613a5c565b604051602001612ec79291906146ae565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a0000000000000000000000000000000000000000000000000000000008252610ad8916004016147b8565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610cf59084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613c9f565b600082815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610eba57600082815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b73ffffffffffffffffffffffffffffffffffffffff821660009081526006602052604090208054613143576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37380000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b80600201548260055461315691906148a6565b6131609190614936565b6005819055633b9aca0010156131d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f37360000000000000000000000000000000000000000000000000000000000006044820152606401610ad8565b6002810182905560055460405190815273ffffffffffffffffffffffffffffffffffffffff8416907f2f564a83158ad1831793ad3e69257b52f39ece5d49cb0d8746708ecb9ef964da9060200160405180910390a2505050565b6132567f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041826136b4565b6001546040517fd547741f0000000000000000000000000000000000000000000000000000000081527f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041600482015273ffffffffffffffffffffffffffffffffffffffff83811660248301529091169063d547741f90604401600060405180830381600087803b1580156132e957600080fd5b505af11580156132fd573d6000803e3d6000fd5b50506003546040517fd547741f0000000000000000000000000000000000000000000000000000000081527f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041600482015273ffffffffffffffffffffffffffffffffffffffff8581166024830152909116925063d547741f9150604401600060405180830381600087803b15801561339457600080fd5b505af11580156133a8573d6000803e3d6000fd5b50506007549150600090505b81811015610cf557600781815481106133cf576133cf614a45565b6000918252602090912001546040517faf648c3d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301529091169063af648c3d90602401600060405180830381600087803b15801561344557600080fd5b505af1158015613459573d6000803e3d6000fd5b505050508080613468906149ae565b9150506133b4565b61349a7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a504182612ff9565b6001546040517f2f2ff15d0000000000000000000000000000000000000000000000000000000081527f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015290911690632f2ff15d90604401600060405180830381600087803b15801561352d57600080fd5b505af1158015613541573d6000803e3d6000fd5b50506003546040517f2f2ff15d0000000000000000000000000000000000000000000000000000000081527f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041600482015273ffffffffffffffffffffffffffffffffffffffff85811660248301529091169250632f2ff15d9150604401600060405180830381600087803b1580156135d857600080fd5b505af11580156135ec573d6000803e3d6000fd5b50506007549150600090505b81811015610cf5576007818154811061361357613613614a45565b6000918252602090912001546040517fa526d83b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301529091169063a526d83b90602401600060405180830381600087803b15801561368957600080fd5b505af115801561369d573d6000803e3d6000fd5b5050505080806136ac906149ae565b9150506135f8565b600082815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610eba57600082815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600854610100900460ff1680613788575060085460ff16155b613814576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ad8565b600854610100900460ff1615801561385357600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000166101011790555b61385b613dab565b801561388a57600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b50565b610eba8282612ff9565b600082815260096020526040902060010154819060405184907fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff90600090a460009182526009602052604090912060010155565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526139499085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612f77565b50505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e9060440160206040518083038186803b1580156139c157600080fd5b505afa1580156139d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139f991906145bb565b613a0391906148a6565b60405173ffffffffffffffffffffffffffffffffffffffff85166024820152604481018290529091506139499085907f095ea7b30000000000000000000000000000000000000000000000000000000090606401612f77565b60606000613a6b8360026148f9565b613a769060026148a6565b67ffffffffffffffff811115613a8e57613a8e614a74565b6040519080825280601f01601f191660200182016040528015613ab8576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110613aef57613aef614a45565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110613b5257613b52614a45565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000613b8e8460026148f9565b613b999060016148a6565b90505b6001811115613c36577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110613bda57613bda614a45565b1a60f81b828281518110613bf057613bf0614a45565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93613c2f81614979565b9050613b9c565b508315612e4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610ad8565b6000613d01826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16613ebf9092919063ffffffff16565b805190915015610cf55780806020019051810190613d1f91906143fb565b610cf5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610ad8565b600854610100900460ff1680613dc4575060085460ff16155b613e50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ad8565b600854610100900460ff1615801561385b57600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016610101179055801561388a57600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905550565b6060613ece8484600085613ed6565b949350505050565b606082471015613f68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610ad8565b843b613fd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ad8565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051613ff99190614692565b60006040518083038185875af1925050503d8060008114614036576040519150601f19603f3d011682016040523d82523d6000602084013e61403b565b606091505b509150915061404b828286614056565b979650505050505050565b60608315614065575081612e4c565b8251156140755782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ad891906147b8565b80356140b481614aa3565b919050565b600082601f8301126140ca57600080fd5b815160206140df6140da83614882565b614833565b80838252828201915082860187848660051b89010111156140ff57600080fd5b60005b8581101561412757815161411581614ac5565b84529284019290840190600101614102565b5090979650505050505050565b6000610100828403121561414757600080fd5b61414f614809565b9050815167ffffffffffffffff8082111561416957600080fd5b614175858386016140b9565b8352602084015191508082111561418b57600080fd5b614197858386016140b9565b602084015260408401519150808211156141b057600080fd5b6141bc858386016140b9565b604084015260608401519150808211156141d557600080fd5b506141e2848285016140b9565b6060830152506141f46080830161422b565b608082015261420560a0830161422b565b60a082015261421660c0830161422b565b60c082015260e082015160e082015292915050565b80516140b481614ac5565b60006020828403121561424857600080fd5b8135612e4c81614aa3565b60006020828403121561426557600080fd5b8151612e4c81614aa3565b6000806040838503121561428357600080fd5b823561428e81614aa3565b9150602083013561429e81614aa3565b809150509250929050565b6000806000606084860312156142be57600080fd5b83356142c981614aa3565b925060208401356142d981614aa3565b929592945050506040919091013590565b600080604083850312156142fd57600080fd5b823561430881614aa3565b946020939093013593505050565b600080600080600060a0868803121561432e57600080fd5b853567ffffffffffffffff81111561434557600080fd5b8601601f8101881361435657600080fd5b803560206143666140da83614882565b8083825282820191508285018c848660051b880101111561438657600080fd5b600095505b848610156143b257803561439e81614aa3565b83526001959095019491830191830161438b565b5098506143c290508982016140a9565b96505050506143d3604087016140a9565b92506143e1606087016140a9565b91506143ef608087016140a9565b90509295509295909350565b60006020828403121561440d57600080fd5b81518015158114612e4c57600080fd5b60006020828403121561442f57600080fd5b5035919050565b6000806040838503121561444957600080fd5b82359150602083013561429e81614aa3565b6000806000806000806000806000898b0361020081121561447b57600080fd5b8a5161448681614aa3565b60208c0151909a5061449781614aa3565b60408c01519099506144a881614aa3565b60608c01519098506144b981614aa3565b8097505060808b0151955060a08b0151945060c08b01519350610100807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff208301121561450457600080fd5b61450c614809565b915060e08c01518252808c01516020830152506101208b015160408201526101408b015160608201526101608b015161454481614ac5565b60808201526101808b015161455881614ac5565b60a082015261456a6101a08c0161422b565b60c082015261457c6101c08c0161422b565b60e08201526101e08b015190925067ffffffffffffffff81111561459f57600080fd5b6145ab8c828d01614134565b9150509295985092959850929598565b6000602082840312156145cd57600080fd5b5051919050565b600080604083850312156145e757600080fd5b505080516020909101519092909150565b60008060006060848603121561460d57600080fd5b505081359360208301359350604090920135919050565b60006020828403121561463657600080fd5b8135612e4c81614ac5565b600081518084526020808501945080840160005b8381101561468757815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614655565b509495945050505050565b600082516146a481846020870161494d565b9190910192915050565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516146e681601785016020880161494d565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835161472381602884016020880161494d565b01602801949350505050565b6060815260006147426060830186614641565b73ffffffffffffffffffffffffffffffffffffffff94851660208401529290931660409091015292915050565b6080815260006147826080830187614641565b73ffffffffffffffffffffffffffffffffffffffff95861660208401529385166040830152509216606090920191909152919050565b60208152600082518060208401526147d781604085016020870161494d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b604051610100810167ffffffffffffffff8111828210171561482d5761482d614a74565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561487a5761487a614a74565b604052919050565b600067ffffffffffffffff82111561489c5761489c614a74565b5060051b60200190565b600082198211156148b9576148b96149e7565b500190565b6000826148f4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614931576149316149e7565b500290565b600082821015614948576149486149e7565b500390565b60005b83811015614968578181015183820152602001614950565b838111156139495750506000910152565b600081614988576149886149e7565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156149e0576149e06149e7565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461388a57600080fd5b67ffffffffffffffff8116811461388a57600080fdfea264697066735822122043e08a6653b827e0baa057c6f4def796677dbd170d546615b605cc99b8549da464736f6c63430008070033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.