Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
StableMasterFront
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 "./StableMaster.sol"; /// @title StableMasterFront /// @author Angle Core Team /// @notice `StableMaster` is the contract handling all the collateral types accepted for a given stablecoin /// It does all the accounting and is the point of entry in the protocol for stable holders and seekers as well as SLPs /// @dev This file contains the front end, that is all external functions associated to the given stablecoin contract StableMasterFront is StableMaster { using SafeERC20 for IERC20; // ============================ CONSTRUCTORS AND DEPLOYERS ===================== /// @notice Initializes the `StableMaster` contract /// @param core_ Address of the `Core` contract handling all the different `StableMaster` contracts function initialize(address core_) external zeroCheck(core_) initializer { __AccessControl_init(); // Access control _core = ICore(core_); _setupRole(CORE_ROLE, core_); // `Core` is admin of all roles _setRoleAdmin(CORE_ROLE, CORE_ROLE); _setRoleAdmin(GOVERNOR_ROLE, CORE_ROLE); _setRoleAdmin(GUARDIAN_ROLE, CORE_ROLE); // All the roles that are specific to a given collateral can be changed by the governor // in the `deployCollateral`, `revokeCollateral` and `setFeeManager` functions by updating the `contractMap` } /// @custom:oz-upgrades-unsafe-allow constructor constructor() initializer {} // ============================= USERS ========================================= /// @notice Lets a user send collateral to the system to mint stablecoins /// @param amount Amount of collateral sent /// @param user Address of the contract or the person to give the minted tokens to /// @param poolManager Address of the `PoolManager` of the required collateral /// @param minStableAmount Minimum amount of stablecoins the user wants to get with this transaction /// @dev This function works as a swap from a user perspective from collateral to stablecoins /// @dev It is impossible to mint tokens and to have them sent to the zero address: there /// would be an issue with the `_mint` function called by the `AgToken` contract /// @dev The parameter `minStableAmount` serves as a slippage protection for users /// @dev From a user perspective, this function is equivalent to a swap between collateral and /// stablecoins function mint( uint256 amount, address user, IPoolManager poolManager, uint256 minStableAmount ) external { Collateral storage col = collateralMap[poolManager]; _contractMapCheck(col); // Checking if the contract is paused for this agent _whenNotPaused(STABLE, address(poolManager)); // No overflow check are needed for the amount since it's never casted to `int` and Solidity 0.8.0 // automatically handles overflows col.token.safeTransferFrom(msg.sender, address(poolManager), amount); // Getting a quote for the amount of stablecoins to issue // We read the lowest oracle value we get for this collateral/stablecoin pair: it's the one // that is most at the advantage of the protocol // Decimals are handled directly in the oracle contract uint256 amountForUserInStable = col.oracle.readQuoteLower(amount); // Getting the fees paid for this transaction, expressed in `BASE_PARAMS` // Floor values are taken for fees computation, as what is earned by users is lost by SLP // when calling `_updateSanRate` and vice versa uint256 fees = _computeFeeMint(amountForUserInStable, col); // Computing the net amount that will be taken into account for this user by deducing fees amountForUserInStable = (amountForUserInStable * (BASE_PARAMS - fees)) / BASE_PARAMS; // Checking if the user got more stablecoins than the least amount specified in the parameters of the // function require(amountForUserInStable >= minStableAmount, "15"); // Updating the `stocksUsers` for this collateral, that is the amount of collateral that was // brought by users col.stocksUsers += amountForUserInStable; // Checking if stablecoins can still be issued using this collateral type require(col.stocksUsers <= col.feeData.capOnStableMinted, "16"); // Event needed to track `col.stocksUsers` off-chain emit MintedStablecoins(address(poolManager), amount, amountForUserInStable); // Distributing the fees taken to SLPs // The `fees` variable computed above is a proportion expressed in `BASE_PARAMS`. // To compute the amount of fees in collateral value, we can directly use the `amount` of collateral // entered by the user // Not all the fees are distributed to SLPs, a portion determined by `col.slpData.feesForSLPs` goes to surplus _updateSanRate((amount * fees * col.slpData.feesForSLPs) / (BASE_PARAMS**2), col); // Minting agToken.mint(user, amountForUserInStable); } /// @notice Lets a user burn agTokens (stablecoins) and receive the collateral specified by the `poolManager` /// in exchange /// @param amount Amount of stable asset burnt /// @param burner Address from which the agTokens will be burnt /// @param dest Address where collateral is going to be /// @param poolManager Collateral type requested by the user burning /// @param minCollatAmount Minimum amount of collateral that the user is willing to get for this transaction /// @dev The `msg.sender` should have approval to burn from the `burner` or the `msg.sender` should be the `burner` /// @dev If there are not enough reserves this transaction will revert and the user will have to come back to the /// protocol with a correct amount. Checking for the reserves currently available in the `PoolManager` /// is something that should be handled by the front interacting with this contract /// @dev In case there are not enough reserves, strategies should be harvested or their debt ratios should be adjusted /// by governance to make sure that users, HAs or SLPs withdrawing always have free collateral they can use /// @dev From a user perspective, this function is equivalent to a swap from stablecoins to collateral function burn( uint256 amount, address burner, address dest, IPoolManager poolManager, uint256 minCollatAmount ) external { // Searching collateral data Collateral storage col = collateralMap[poolManager]; // Checking the collateral requested _contractMapCheck(col); _whenNotPaused(STABLE, address(poolManager)); // Checking if the amount is not going to make the `stocksUsers` negative // A situation like that is likely to happen if users mint using one collateral type and in volume redeem // another collateral type // In this situation, governance should rapidly react to pause the pool and then rebalance the `stocksUsers` // between different collateral types, or at least rebalance what is stored in the reserves through // the `recoverERC20` function followed by a swap and then a transfer require(amount <= col.stocksUsers, "17"); // Burning the tokens will revert if there are not enough tokens in balance or if the `msg.sender` // does not have approval from the burner // A reentrancy attack is potentially possible here as state variables are written after the burn, // but as the `AgToken` is a protocol deployed contract, it can be trusted. Still, `AgToken` is // upgradeable by governance, the following could become risky in case of a governance attack if (burner == msg.sender) { agToken.burnSelf(amount, burner); } else { agToken.burnFrom(amount, burner, msg.sender); } // Getting the highest possible oracle value uint256 oracleValue = col.oracle.readUpper(); // Converting amount of agTokens in collateral and computing how much should be reimbursed to the user // Amount is in `BASE_TOKENS` and the outputted collateral amount should be in collateral base uint256 amountInC = (amount * col.collatBase) / oracleValue; // Computing how much of collateral can be redeemed by the user after taking fees // The value of the fees here is `_computeFeeBurn(amount,col)` (it is a proportion expressed in `BASE_PARAMS`) // The real value of what can be redeemed by the user is `amountInC * (BASE_PARAMS - fees) / BASE_PARAMS`, // but we prefer to avoid doing multiplications after divisions uint256 redeemInC = (amount * (BASE_PARAMS - _computeFeeBurn(amount, col)) * col.collatBase) / (oracleValue * BASE_PARAMS); require(redeemInC >= minCollatAmount, "15"); // Updating the `stocksUsers` that is the amount of collateral that was brought by users col.stocksUsers -= amount; // Event needed to track `col.stocksUsers` off-chain emit BurntStablecoins(address(poolManager), amount, redeemInC); // Computing the exact amount of fees from this transaction and accumulating it for SLPs _updateSanRate(((amountInC - redeemInC) * col.slpData.feesForSLPs) / BASE_PARAMS, col); col.token.safeTransferFrom(address(poolManager), dest, redeemInC); } // ============================== SLPs ========================================= /// @notice Lets a SLP enter the protocol by sending collateral to the system in exchange of sanTokens /// @param user Address of the SLP to send sanTokens to /// @param amount Amount of collateral sent /// @param poolManager Address of the `PoolManager` of the required collateral function deposit( uint256 amount, address user, IPoolManager poolManager ) external { // Searching collateral data Collateral storage col = collateralMap[poolManager]; _contractMapCheck(col); _whenNotPaused(SLP, address(poolManager)); _updateSanRate(0, col); // No overflow check needed for the amount since it's never casted to int and Solidity versions above 0.8.0 // automatically handle overflows col.token.safeTransferFrom(msg.sender, address(poolManager), amount); col.sanToken.mint(user, (amount * BASE_TOKENS) / col.sanRate); } /// @notice Lets a SLP burn of sanTokens and receive the corresponding collateral back in exchange at the /// current exchange rate between sanTokens and collateral /// @param amount Amount of sanTokens burnt by the SLP /// @param burner Address that will burn its sanTokens /// @param dest Address that will receive the collateral /// @param poolManager Address of the `PoolManager` of the required collateral /// @dev The `msg.sender` should have approval to burn from the `burner` or the `msg.sender` should be the `burner` /// @dev This transaction will fail if the `PoolManager` does not have enough reserves, the front will however be here /// to notify them that they cannot withdraw /// @dev In case there are not enough reserves, strategies should be harvested or their debt ratios should be adjusted /// by governance to make sure that users, HAs or SLPs withdrawing always have free collateral they can use function withdraw( uint256 amount, address burner, address dest, IPoolManager poolManager ) external { Collateral storage col = collateralMap[poolManager]; _contractMapCheck(col); _whenNotPaused(SLP, address(poolManager)); _updateSanRate(0, col); if (burner == msg.sender) { col.sanToken.burnSelf(amount, burner); } else { col.sanToken.burnFrom(amount, burner, msg.sender); } // Computing the amount of collateral to give back to the SLP depending on slippage and on the `sanRate` uint256 redeemInC = (amount * (BASE_PARAMS - col.slpData.slippage) * col.sanRate) / (BASE_TOKENS * BASE_PARAMS); col.token.safeTransferFrom(address(poolManager), dest, redeemInC); } }
// 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; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); uint256 currentAllowance = _allowances[sender][_msgSender()]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); unchecked { _approve(sender, _msgSender(), currentAllowance - amount); } return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { uint256 currentAllowance = _allowances[_msgSender()][spender]; require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(_msgSender(), spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `sender` to `recipient`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); uint256 senderBalance = _balances[sender]; require(senderBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[sender] = senderBalance - amount; } _balances[recipient] += amount; emit Transfer(sender, recipient, amount); _afterTokenTransfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; } _totalSupply -= amount; emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @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 Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @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.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-upgradeable/token/ERC20/IERC20Upgradeable.sol"; /// @title IAgToken /// @author Angle Core Team /// @notice Interface for the stablecoins `AgToken` contracts /// @dev The only functions that are left in the interface are the functions which are used /// at another point in the protocol by a different contract interface IAgToken is IERC20Upgradeable { // ======================= `StableMaster` functions ============================ function mint(address account, uint256 amount) external; function burnFrom( uint256 amount, address burner, address sender ) external; function burnSelf(uint256 amount, address burner) external; // ========================= External function ================================= function stableMaster() external view returns (address); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; /// @title ICollateralSettler /// @author Angle Core Team /// @notice Interface for the collateral settlement contracts interface ICollateralSettler { function triggerSettlement( uint256 _oracleValue, uint256 _sanRate, uint256 _stocksUsers ) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "./IStableMaster.sol"; /// @title ICore /// @author Angle Core Team /// @dev Interface for the functions of the `Core` contract interface ICore { function revokeStableMaster(address stableMaster) external; function addGovernor(address _governor) external; function removeGovernor(address _governor) external; function setGuardian(address _guardian) external; function revokeGuardian() external; function governorList() external view returns (address[] memory); function stablecoinList() external view returns (address[] memory); function guardian() external view returns (address); }
// 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); }
// 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 "./StableMasterInternal.sol"; /// @title StableMaster /// @author Angle Core Team /// @notice `StableMaster` is the contract handling all the collateral types accepted for a given stablecoin /// It does all the accounting and is the point of entry in the protocol for stable holders and seekers as well as SLPs /// @dev This file contains the core functions of the `StableMaster` contract contract StableMaster is StableMasterInternal, IStableMasterFunctions, AccessControlUpgradeable { using SafeERC20 for IERC20; /// @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 `Core` only, used to propagate guardian and governors bytes32 public constant CORE_ROLE = keccak256("CORE_ROLE"); bytes32 public constant STABLE = keccak256("STABLE"); bytes32 public constant SLP = keccak256("SLP"); // ============================ DEPLOYER ======================================= /// @notice Creates the access control logic for the governor and guardian addresses /// @param governorList List of the governor addresses of the protocol /// @param guardian Guardian address of the protocol /// @param _agToken Reference to the `AgToken`, that is the ERC20 token handled by the `StableMaster` /// @dev This function is called by the `Core` when a stablecoin is deployed to maintain consistency /// across the governor and guardian roles /// @dev When this function is called by the `Core`, it has already been checked that the `stableMaster` /// corresponding to the `agToken` was this `stableMaster` function deploy( address[] memory governorList, address guardian, address _agToken ) external override onlyRole(CORE_ROLE) { for (uint256 i = 0; i < governorList.length; i++) { _grantRole(GOVERNOR_ROLE, governorList[i]); _grantRole(GUARDIAN_ROLE, governorList[i]); } _grantRole(GUARDIAN_ROLE, guardian); agToken = IAgToken(_agToken); // Since there is only one address that can be the `AgToken`, and since `AgToken` // is not to be admin of any role, we do not define any access control role for it } // ============================ STRATEGIES ===================================== /// @notice Takes into account the gains made while lending and distributes it to SLPs by updating the `sanRate` /// @param gain Interests accumulated from lending /// @dev This function is called by a `PoolManager` contract having some yield farming strategies associated /// @dev To prevent flash loans, the `sanRate` is not directly updated, it is updated at the blocks that follow function accumulateInterest(uint256 gain) external override { // Searching collateral data Collateral storage col = collateralMap[IPoolManager(msg.sender)]; _contractMapCheck(col); // A part of the gain goes to SLPs, the rest to the surplus of the protocol _updateSanRate((gain * col.slpData.interestsForSLPs) / BASE_PARAMS, col); } /// @notice Takes into account a loss made by a yield farming strategy /// @param loss Loss made by the yield farming strategy /// @dev This function is called by a `PoolManager` contract having some yield farming strategies associated /// @dev Fees are not accumulated for this function before being distributed: everything is directly used to /// update the `sanRate` function signalLoss(uint256 loss) external override { // Searching collateral data IPoolManager poolManager = IPoolManager(msg.sender); Collateral storage col = collateralMap[poolManager]; _contractMapCheck(col); uint256 sanMint = col.sanToken.totalSupply(); if (sanMint != 0) { // Updating the `sanRate` and the `lockedInterests` by taking into account a loss if (col.sanRate * sanMint + col.slpData.lockedInterests * BASE_TOKENS > loss * BASE_TOKENS) { // The loss is first taken from the `lockedInterests` uint256 withdrawFromLoss = col.slpData.lockedInterests; if (withdrawFromLoss >= loss) { withdrawFromLoss = loss; } col.slpData.lockedInterests -= withdrawFromLoss; col.sanRate -= ((loss - withdrawFromLoss) * BASE_TOKENS) / sanMint; } else { // Normally it should be set to 0, but this would imply that no SLP can enter afterwards // we therefore set it to 1 (equivalent to 10**(-18)) col.sanRate = 1; col.slpData.lockedInterests = 0; // As it is a critical time, governance pauses SLPs to solve the situation _pause(keccak256(abi.encodePacked(SLP, address(poolManager)))); } emit SanRateUpdated(address(col.token), col.sanRate); } } // ============================== HAs ========================================== /// @notice Transforms a HA position into a SLP Position /// @param amount The amount to transform /// @param user Address to mint sanTokens to /// @dev Can only be called by a `PerpetualManager` contract /// @dev This is typically useful when a HA wishes to cash out but there is not enough collateral /// in reserves function convertToSLP(uint256 amount, address user) external override { // Data about the `PerpetualManager` calling the function is fetched using the `contractMap` IPoolManager poolManager = _contractMap[msg.sender]; Collateral storage col = collateralMap[poolManager]; _contractMapCheck(col); // If SLPs are paused, in this situation, then this transaction should revert // In this extremely rare case, governance should take action and also pause HAs _whenNotPaused(SLP, address(poolManager)); _updateSanRate(0, col); col.sanToken.mint(user, (amount * BASE_TOKENS) / col.sanRate); } /// @notice Sets the proportion of `stocksUsers` available for perpetuals /// @param _targetHAHedge New value of the hedge ratio that the protocol wants to arrive to /// @dev Can only be called by the `PerpetualManager` function setTargetHAHedge(uint64 _targetHAHedge) external override { // Data about the `PerpetualManager` calling the function is fetched using the `contractMap` IPoolManager poolManager = _contractMap[msg.sender]; Collateral storage col = collateralMap[poolManager]; _contractMapCheck(col); col.feeData.targetHAHedge = _targetHAHedge; // No need to issue an event here, one has already been issued by the corresponding `PerpetualManager` } // ============================ VIEW FUNCTIONS ================================= /// @notice Transmits to the `PerpetualManager` the max amount of collateral (in stablecoin value) HAs can hedge /// @return _stocksUsers All stablecoins currently assigned to the pool of the caller /// @dev This function will not return something relevant if it is not called by a `PerpetualManager` function getStocksUsers() external view override returns (uint256 _stocksUsers) { _stocksUsers = collateralMap[_contractMap[msg.sender]].stocksUsers; } /// @notice Returns the collateral ratio for this stablecoin /// @dev The ratio returned is scaled by `BASE_PARAMS` since the value is used to /// in the `FeeManager` contrat to be compared with the values in `xArrays` expressed in `BASE_PARAMS` function getCollateralRatio() external view override returns (uint256) { uint256 mints = agToken.totalSupply(); if (mints == 0) { // If nothing has been minted, the collateral ratio is infinity return type(uint256).max; } uint256 val; for (uint256 i = 0; i < _managerList.length; i++) { // Oracle needs to be called for each collateral to compute the collateral ratio val += collateralMap[_managerList[i]].oracle.readQuote(_managerList[i].getTotalAsset()); } return (val * BASE_PARAMS) / mints; } // ============================== KEEPERS ====================================== /// @notice Updates all the fees not depending on personal agents inputs via a keeper calling the corresponding /// function in the `FeeManager` contract /// @param _bonusMalusMint New corrector of user mint fees for this collateral. These fees will correct /// the mint fees from users that just depend on the hedge curve by HAs by introducing other dependencies. /// In normal times they will be equal to `BASE_PARAMS` meaning fees will just depend on the hedge ratio /// @param _bonusMalusBurn New corrector of user burn fees, depending on collateral ratio /// @param _slippage New global slippage (the SLP fees from withdrawing) factor /// @param _slippageFee New global slippage fee (the non distributed accumulated fees) factor function setFeeKeeper( uint64 _bonusMalusMint, uint64 _bonusMalusBurn, uint64 _slippage, uint64 _slippageFee ) external override { // Fetching data about the `FeeManager` contract calling this function // It is stored in the `_contractMap` Collateral storage col = collateralMap[_contractMap[msg.sender]]; _contractMapCheck(col); col.feeData.bonusMalusMint = _bonusMalusMint; col.feeData.bonusMalusBurn = _bonusMalusBurn; col.slpData.slippage = _slippage; col.slpData.slippageFee = _slippageFee; // An event is already emitted in the `FeeManager` contract } // ============================== AgToken ====================================== /// @notice Allows the `agToken` contract to update the `stocksUsers` for a given collateral after a burn /// with no redeem /// @param amount Amount by which `stocksUsers` should decrease /// @param poolManager Reference to `PoolManager` for which `stocksUsers` needs to be updated /// @dev This function can be called by the `agToken` contract after a burn of agTokens for which no collateral has been /// redeemed function updateStocksUsers(uint256 amount, address poolManager) external override { require(msg.sender == address(agToken), "3"); Collateral storage col = collateralMap[IPoolManager(poolManager)]; _contractMapCheck(col); require(col.stocksUsers >= amount, "4"); col.stocksUsers -= amount; emit StocksUsersUpdated(address(col.token), col.stocksUsers); } // ================================= GOVERNANCE ================================ // =============================== Core Functions ============================== /// @notice Changes the `Core` contract /// @param newCore New core address /// @dev This function can only be called by the `Core` contract function setCore(address newCore) external override onlyRole(CORE_ROLE) { // Access control for this contract _revokeRole(CORE_ROLE, address(_core)); _grantRole(CORE_ROLE, newCore); _core = ICore(newCore); } /// @notice Adds a new governor address /// @param governor New governor address /// @dev This function propagates changes from `Core` to other contracts /// @dev Propagating changes like that allows to maintain the protocol's integrity function addGovernor(address governor) external override onlyRole(CORE_ROLE) { // Access control for this contract _grantRole(GOVERNOR_ROLE, governor); _grantRole(GUARDIAN_ROLE, governor); for (uint256 i = 0; i < _managerList.length; i++) { // The `PoolManager` will echo the changes across all the corresponding contracts _managerList[i].addGovernor(governor); } } /// @notice Removes a governor address which loses its role /// @param governor Governor address to remove /// @dev This function propagates changes from `Core` to other contracts /// @dev Propagating changes like that allows to maintain the protocol's integrity /// @dev It has already been checked in the `Core` that this address could be removed /// and that it would not put the protocol in a situation with no governor at all function removeGovernor(address governor) external override onlyRole(CORE_ROLE) { // Access control for this contract _revokeRole(GOVERNOR_ROLE, governor); _revokeRole(GUARDIAN_ROLE, governor); for (uint256 i = 0; i < _managerList.length; i++) { // The `PoolManager` will echo the changes across all the corresponding contracts _managerList[i].removeGovernor(governor); } } /// @notice Changes the guardian address /// @param newGuardian New guardian address /// @param oldGuardian Old guardian address /// @dev This function propagates changes from `Core` to other contracts /// @dev The zero check for the guardian address has already been performed by the `Core` /// contract function setGuardian(address newGuardian, address oldGuardian) external override onlyRole(CORE_ROLE) { _revokeRole(GUARDIAN_ROLE, oldGuardian); _grantRole(GUARDIAN_ROLE, newGuardian); for (uint256 i = 0; i < _managerList.length; i++) { _managerList[i].setGuardian(newGuardian, oldGuardian); } } /// @notice Revokes the guardian address /// @param oldGuardian Guardian address to revoke /// @dev This function propagates changes from `Core` to other contracts function revokeGuardian(address oldGuardian) external override onlyRole(CORE_ROLE) { _revokeRole(GUARDIAN_ROLE, oldGuardian); for (uint256 i = 0; i < _managerList.length; i++) { _managerList[i].revokeGuardian(oldGuardian); } } // ============================= Governor Functions ============================ /// @notice Deploys a new collateral by creating the correct references in the corresponding contracts /// @param poolManager Contract managing and storing this collateral for this stablecoin /// @param perpetualManager Contract managing HA perpetuals for this stablecoin /// @param oracle Reference to the oracle that will give the price of the collateral with respect to the stablecoin /// @param sanToken Reference to the sanTokens associated to the collateral /// @dev All the references in parameters should correspond to contracts that have already been deployed and /// initialized with appropriate references /// @dev After calling this function, governance should initialize all parameters corresponding to this new collateral function deployCollateral( IPoolManager poolManager, IPerpetualManager perpetualManager, IFeeManager feeManager, IOracle oracle, ISanToken sanToken ) external onlyRole(GOVERNOR_ROLE) { // If the `sanToken`, `poolManager`, `perpetualManager` and `feeManager` were zero // addresses, the following require would fail // The only elements that are checked here are those that are defined in the constructors/initializers // of the concerned contracts require( sanToken.stableMaster() == address(this) && sanToken.poolManager() == address(poolManager) && poolManager.stableMaster() == address(this) && perpetualManager.poolManager() == address(poolManager) && // If the `feeManager` is not initialized with the correct `poolManager` then this function // will revert when `poolManager.deployCollateral` will be executed feeManager.stableMaster() == address(this), "9" ); // Checking if the base of the tokens and of the oracle are not similar with one another address token = poolManager.token(); uint256 collatBase = 10**(IERC20Metadata(token).decimals()); // If the address of the oracle was the zero address, the following would revert require(oracle.inBase() == collatBase, "11"); // Checking if the collateral has not already been deployed Collateral storage col = collateralMap[poolManager]; require(address(col.token) == address(0), "13"); // Creating the correct references col.token = IERC20(token); col.sanToken = sanToken; col.perpetualManager = perpetualManager; col.oracle = oracle; // Initializing with the correct values col.sanRate = BASE_TOKENS; col.collatBase = collatBase; // Adding the correct references in the `contractMap` we use in order not to have to pass addresses when // calling the `StableMaster` from the `PerpetualManager` contract, or the `FeeManager` contract // This is equivalent to granting Access Control roles for these contracts _contractMap[address(perpetualManager)] = poolManager; _contractMap[address(feeManager)] = poolManager; _managerList.push(poolManager); // Pausing agents at deployment to leave governance time to set parameters // The `PerpetualManager` contract is automatically paused after being initialized, so HAs will not be able to // interact with the protocol _pause(keccak256(abi.encodePacked(SLP, address(poolManager)))); _pause(keccak256(abi.encodePacked(STABLE, address(poolManager)))); // Fetching the governor list and the guardian to initialize the `poolManager` correctly address[] memory governorList = _core.governorList(); address guardian = _core.guardian(); // Propagating the deployment and passing references to the corresponding contracts poolManager.deployCollateral(governorList, guardian, perpetualManager, feeManager, oracle); emit CollateralDeployed(address(poolManager), address(perpetualManager), address(sanToken), address(oracle)); } /// @notice Removes a collateral from the list of accepted collateral types and pauses all actions associated /// to this collateral /// @param poolManager Reference to the contract managing this collateral for this stablecoin in the protocol /// @param settlementContract Settlement contract that will be used to close everyone's positions and to let /// users, SLPs and HAs redeem if not all a portion of their claim /// @dev Since this function has the ability to transfer the contract's funds to another contract, it should /// only be accessible to the governor /// @dev Before calling this function, governance should make sure that all the collateral lent to strategies /// has been withdrawn function revokeCollateral(IPoolManager poolManager, ICollateralSettler settlementContract) external onlyRole(GOVERNOR_ROLE) { // Checking if the `poolManager` given here is well in the list of managers and taking advantage of that to remove // the `poolManager` from the list uint256 indexMet; uint256 managerListLength = _managerList.length; require(managerListLength >= 1, "10"); for (uint256 i = 0; i < managerListLength - 1; i++) { if (_managerList[i] == poolManager) { indexMet = 1; _managerList[i] = _managerList[managerListLength - 1]; break; } } require(indexMet == 1 || _managerList[managerListLength - 1] == poolManager, "10"); _managerList.pop(); Collateral memory col = collateralMap[poolManager]; // Deleting the references of the associated contracts: `perpetualManager` and `keeper` in the // `_contractMap` and `poolManager` from the `collateralMap` delete _contractMap[poolManager.feeManager()]; delete _contractMap[address(col.perpetualManager)]; delete collateralMap[poolManager]; emit CollateralRevoked(address(poolManager)); // Pausing entry (and exits for HAs) col.perpetualManager.pause(); // No need to pause `SLP` and `STABLE_HOLDERS` as deleting the entry associated to the `poolManager` // in the `collateralMap` will make everything revert // Transferring the whole balance to global settlement uint256 balance = col.token.balanceOf(address(poolManager)); col.token.safeTransferFrom(address(poolManager), address(settlementContract), balance); // Settlement works with a fixed oracle value for HAs, it needs to be computed here uint256 oracleValue = col.oracle.readLower(); // Notifying the global settlement contract with the properties of the contract to settle // In case of global shutdown, there would be one settlement contract per collateral type // Not using the `lockedInterests` to update the value of the sanRate settlementContract.triggerSettlement(oracleValue, col.sanRate, col.stocksUsers); } // ============================= Guardian Functions ============================ /// @notice Pauses an agent's actions within this contract for a given collateral type for this stablecoin /// @param agent Bytes representing the agent (`SLP` or `STABLE`) and the collateral type that is going to /// be paused. To get the `bytes32` from a string, we use in Solidity a `keccak256` function /// @param poolManager Reference to the contract managing this collateral for this stablecoin in the protocol and /// for which `agent` needs to be paused /// @dev If agent is `STABLE`, it is going to be impossible for users to mint stablecoins using collateral or to burn /// their stablecoins /// @dev If agent is `SLP`, it is going to be impossible for SLPs to deposit collateral and receive /// sanTokens in exchange, or to withdraw collateral from their sanTokens function pause(bytes32 agent, IPoolManager poolManager) external override onlyRole(GUARDIAN_ROLE) { Collateral storage col = collateralMap[poolManager]; // Checking for the `poolManager` _contractMapCheck(col); _pause(keccak256(abi.encodePacked(agent, address(poolManager)))); } /// @notice Unpauses an agent's action for a given collateral type for this stablecoin /// @param agent Agent (`SLP` or `STABLE`) to unpause the action of /// @param poolManager Reference to the associated `PoolManager` /// @dev Before calling this function, the agent should have been paused for this collateral function unpause(bytes32 agent, IPoolManager poolManager) external override onlyRole(GUARDIAN_ROLE) { Collateral storage col = collateralMap[poolManager]; // Checking for the `poolManager` _contractMapCheck(col); _unpause(keccak256(abi.encodePacked(agent, address(poolManager)))); } /// @notice Updates the `stocksUsers` for a given pair of collateral /// @param amount Amount of `stocksUsers` to transfer from a pool to another /// @param poolManagerUp Reference to `PoolManager` for which `stocksUsers` needs to increase /// @param poolManagerDown Reference to `PoolManager` for which `stocksUsers` needs to decrease /// @dev This function can be called in case where the reserves of the protocol for each collateral do not exactly /// match what is stored in the `stocksUsers` because of increases or decreases in collateral prices at times /// in which the protocol was not fully hedged by HAs /// @dev With this function, governance can allow/prevent more HAs coming in a pool while preventing/allowing HAs /// from other pools because the accounting variable of `stocksUsers` does not really match function rebalanceStocksUsers( uint256 amount, IPoolManager poolManagerUp, IPoolManager poolManagerDown ) external onlyRole(GUARDIAN_ROLE) { Collateral storage colUp = collateralMap[poolManagerUp]; Collateral storage colDown = collateralMap[poolManagerDown]; // Checking for the `poolManager` _contractMapCheck(colUp); _contractMapCheck(colDown); // The invariant `col.stocksUsers <= col.capOnStableMinted` should remain true even after a // governance update require(colUp.stocksUsers + amount <= colUp.feeData.capOnStableMinted, "8"); colDown.stocksUsers -= amount; colUp.stocksUsers += amount; emit StocksUsersUpdated(address(colUp.token), colUp.stocksUsers); emit StocksUsersUpdated(address(colDown.token), colDown.stocksUsers); } /// @notice Propagates the change of oracle for one collateral to all the contracts which need to have /// the correct oracle reference /// @param _oracle New oracle contract for the pair collateral/stablecoin /// @param poolManager Reference to the `PoolManager` contract associated to the collateral function setOracle(IOracle _oracle, IPoolManager poolManager) external onlyRole(GOVERNOR_ROLE) zeroCheck(address(_oracle)) { Collateral storage col = collateralMap[poolManager]; // Checking for the `poolManager` _contractMapCheck(col); require(col.oracle != _oracle, "12"); // The `inBase` of the new oracle should be the same as the `_collatBase` stored for this collateral require(col.collatBase == _oracle.inBase(), "11"); col.oracle = _oracle; emit OracleUpdated(address(poolManager), address(_oracle)); col.perpetualManager.setOracle(_oracle); } /// @notice Changes the parameters to cap the number of stablecoins you can issue using one /// collateral type and the maximum interests you can distribute to SLPs in a sanRate update /// in a block /// @param _capOnStableMinted New value of the cap /// @param _maxInterestsDistributed Maximum amount of interests distributed to SLPs in a block /// @param poolManager Reference to the `PoolManager` contract associated to the collateral function setCapOnStableAndMaxInterests( uint256 _capOnStableMinted, uint256 _maxInterestsDistributed, IPoolManager poolManager ) external override onlyRole(GUARDIAN_ROLE) { Collateral storage col = collateralMap[poolManager]; // Checking for the `poolManager` _contractMapCheck(col); // The invariant `col.stocksUsers <= col.capOnStableMinted` should remain true even after a // governance update require(_capOnStableMinted >= col.stocksUsers, "8"); col.feeData.capOnStableMinted = _capOnStableMinted; col.slpData.maxInterestsDistributed = _maxInterestsDistributed; emit CapOnStableAndMaxInterestsUpdated(address(poolManager), _capOnStableMinted, _maxInterestsDistributed); } /// @notice Sets a new `FeeManager` contract and removes the old one which becomes useless /// @param newFeeManager New `FeeManager` contract /// @param oldFeeManager Old `FeeManager` contract /// @param poolManager Reference to the contract managing this collateral for this stablecoin in the protocol /// and associated to the `FeeManager` to update function setFeeManager( address newFeeManager, address oldFeeManager, IPoolManager poolManager ) external onlyRole(GUARDIAN_ROLE) zeroCheck(newFeeManager) { Collateral storage col = collateralMap[poolManager]; // Checking for the `poolManager` _contractMapCheck(col); require(_contractMap[oldFeeManager] == poolManager, "10"); require(newFeeManager != oldFeeManager, "14"); delete _contractMap[oldFeeManager]; _contractMap[newFeeManager] = poolManager; emit FeeManagerUpdated(address(poolManager), newFeeManager); poolManager.setFeeManager(IFeeManager(newFeeManager)); } /// @notice Sets the proportion of fees from burn/mint of users and the proportion /// of lending interests going to SLPs /// @param _feesForSLPs New proportion of mint/burn fees going to SLPs /// @param _interestsForSLPs New proportion of interests from lending going to SLPs /// @dev The higher these proportions the bigger the APY for SLPs /// @dev These proportions should be inferior to `BASE_PARAMS` function setIncentivesForSLPs( uint64 _feesForSLPs, uint64 _interestsForSLPs, IPoolManager poolManager ) external override onlyRole(GUARDIAN_ROLE) onlyCompatibleFees(_feesForSLPs) onlyCompatibleFees(_interestsForSLPs) { Collateral storage col = collateralMap[poolManager]; _contractMapCheck(col); col.slpData.feesForSLPs = _feesForSLPs; col.slpData.interestsForSLPs = _interestsForSLPs; emit SLPsIncentivesUpdated(address(poolManager), _feesForSLPs, _interestsForSLPs); } /// @notice Sets the x array (ie ratios between amount hedged by HAs and amount to hedge) /// and the y array (ie values of fees at thresholds) used to compute mint and burn fees for users /// @param poolManager Reference to the `PoolManager` handling the collateral /// @param _xFee Thresholds of hedge ratios /// @param _yFee Values of the fees at thresholds /// @param _mint Whether mint fees or burn fees should be updated /// @dev The evolution of the fees between two thresholds is linear /// @dev The length of the two arrays should be the same /// @dev The values of `_xFee` should be in ascending order /// @dev For mint fees, values in the y-array below should normally be decreasing: the higher the `x` the cheaper /// it should be for stable seekers to come in as a high `x` corresponds to a high demand for volatility and hence /// to a situation where all the collateral can be hedged /// @dev For burn fees, values in the array below should normally be decreasing: the lower the `x` the cheaper it should /// be for stable seekers to go out, as a low `x` corresponds to low demand for volatility and hence /// to a situation where the protocol has a hard time covering its collateral function setUserFees( IPoolManager poolManager, uint64[] memory _xFee, uint64[] memory _yFee, uint8 _mint ) external override onlyRole(GUARDIAN_ROLE) onlyCompatibleInputArrays(_xFee, _yFee) { Collateral storage col = collateralMap[poolManager]; _contractMapCheck(col); if (_mint > 0) { col.feeData.xFeeMint = _xFee; col.feeData.yFeeMint = _yFee; } else { col.feeData.xFeeBurn = _xFee; col.feeData.yFeeBurn = _yFee; } emit FeeArrayUpdated(address(poolManager), _xFee, _yFee, _mint); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "../external/AccessControlUpgradeable.sol"; import "../interfaces/IAgToken.sol"; import "../interfaces/ICollateralSettler.sol"; import "../interfaces/ICore.sol"; import "../interfaces/IFeeManager.sol"; import "../interfaces/IOracle.sol"; import "../interfaces/IPerpetualManager.sol"; import "../interfaces/IPoolManager.sol"; import "../interfaces/ISanToken.sol"; import "../interfaces/IStableMaster.sol"; import "../utils/FunctionUtils.sol"; import "../utils/PausableMapUpgradeable.sol"; /// @title StableMasterEvents /// @author Angle Core Team /// @notice `StableMaster` is the contract handling all the collateral types accepted for a given stablecoin /// It does all the accounting and is the point of entry in the protocol for stable holders and seekers as well as SLPs /// @dev This file contains all the events of the `StableMaster` contract contract StableMasterEvents { event SanRateUpdated(address indexed _token, uint256 _newSanRate); event StocksUsersUpdated(address indexed _poolManager, uint256 _stocksUsers); event MintedStablecoins(address indexed _poolManager, uint256 amount, uint256 amountForUserInStable); event BurntStablecoins(address indexed _poolManager, uint256 amount, uint256 redeemInC); // ============================= Governors ===================================== event CollateralDeployed( address indexed _poolManager, address indexed _perpetualManager, address indexed _sanToken, address _oracle ); event CollateralRevoked(address indexed _poolManager); // ========================= Parameters update ================================= event OracleUpdated(address indexed _poolManager, address indexed _oracle); event FeeManagerUpdated(address indexed _poolManager, address indexed newFeeManager); event CapOnStableAndMaxInterestsUpdated( address indexed _poolManager, uint256 _capOnStableMinted, uint256 _maxInterestsDistributed ); event SLPsIncentivesUpdated(address indexed _poolManager, uint64 _feesForSLPs, uint64 _interestsForSLPs); event FeeArrayUpdated(address indexed _poolManager, uint64[] _xFee, uint64[] _yFee, uint8 _type); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "./StableMasterStorage.sol"; /// @title StableMasterInternal /// @author Angle Core Team /// @notice `StableMaster` is the contract handling all the collateral types accepted for a given stablecoin /// It does all the accounting and is the point of entry in the protocol for stable holders and seekers as well as SLPs /// @dev This file contains all the internal function of the `StableMaster` contract contract StableMasterInternal is StableMasterStorage, PausableMapUpgradeable { /// @notice Checks if the `msg.sender` calling the contract has the right to do it /// @param col Struct for the collateral associated to the caller address /// @dev Since the `StableMaster` contract uses a `contractMap` that stores addresses of some verified /// protocol's contracts in it, and since the roles corresponding to these addresses are never admin roles /// it is cheaper not to use for these contracts OpenZeppelin's access control logic /// @dev A non null associated token address is what is used to check if a `PoolManager` has well been initialized /// @dev We could set `PERPETUALMANAGER_ROLE`, `POOLMANAGER_ROLE` and `FEEMANAGER_ROLE` for this /// contract, but this would actually be inefficient function _contractMapCheck(Collateral storage col) internal view { require(address(col.token) != address(0), "3"); } /// @notice Checks if the protocol has been paused for an agent and for a given collateral type for this /// stablecoin /// @param agent Name of the agent to check, it is either going to be `STABLE` or `SLP` /// @param poolManager `PoolManager` contract for which to check pauses function _whenNotPaused(bytes32 agent, address poolManager) internal view { require(!paused[keccak256(abi.encodePacked(agent, poolManager))], "18"); } /// @notice Updates the `sanRate` that is the exchange rate between sanTokens given to SLPs and collateral or /// accumulates fees to be distributed to SLPs before doing it at next block /// @param toShare Amount of interests that needs to be redistributed to the SLPs through the `sanRate` /// @param col Struct for the collateral of interest here which values are going to be updated /// @dev This function can only increase the `sanRate` and is not used to take into account a loss made through /// lending or another yield farming strategy: this is done in the `signalLoss` function /// @dev The `sanRate` is only be updated from the fees accumulated from previous blocks and the fees to share to SLPs /// are just accumulated to be distributed at next block /// @dev A flashloan attack could consist in seeing fees to be distributed, deposit, increase the `sanRate` and then /// withdraw: what is done with the `lockedInterests` parameter is a way to mitigate that /// @dev Another solution against flash loans would be to have a non null `slippage` at all times: this is far from ideal /// for SLPs in the first place function _updateSanRate(uint256 toShare, Collateral storage col) internal { uint256 _lockedInterests = col.slpData.lockedInterests; // Checking if the `sanRate` has been updated in the current block using past block fees // This is a way to prevent flash loans attacks when an important amount of fees are going to be distributed // in a block: fees are stored but will just be distributed to SLPs who will be here during next blocks if (block.timestamp != col.slpData.lastBlockUpdated && _lockedInterests > 0) { uint256 sanMint = col.sanToken.totalSupply(); if (sanMint != 0) { // Checking if the update is too important and should be made in multiple blocks if (_lockedInterests > col.slpData.maxInterestsDistributed) { // `sanRate` is expressed in `BASE_TOKENS` col.sanRate += (col.slpData.maxInterestsDistributed * BASE_TOKENS) / sanMint; _lockedInterests -= col.slpData.maxInterestsDistributed; } else { col.sanRate += (_lockedInterests * BASE_TOKENS) / sanMint; _lockedInterests = 0; } emit SanRateUpdated(address(col.token), col.sanRate); } else { _lockedInterests = 0; } } // Adding the fees to be distributed at next block if (toShare != 0) { if ((col.slpData.slippageFee == 0) && (col.slpData.feesAside != 0)) { // If the collateral ratio is big enough, all the fees or gains will be used to update the `sanRate` // If there were fees or lending gains that had been put aside, they will be added in this case to the // update of the `sanRate` toShare += col.slpData.feesAside; col.slpData.feesAside = 0; } else if (col.slpData.slippageFee != 0) { // Computing the fraction of fees and gains that should be left aside if the collateral ratio is too small uint256 aside = (toShare * col.slpData.slippageFee) / BASE_PARAMS; toShare -= aside; // The amount of fees left aside should be rounded above col.slpData.feesAside += aside; } // Updating the amount of fees to be distributed next block _lockedInterests += toShare; } col.slpData.lockedInterests = _lockedInterests; col.slpData.lastBlockUpdated = block.timestamp; } /// @notice Computes the current fees to be taken when minting using `amount` of collateral /// @param amount Amount of collateral in the transaction to get stablecoins /// @param col Struct for the collateral of interest /// @return feeMint Mint Fees taken to users expressed in collateral /// @dev Fees depend on the hedge ratio that is the ratio between what is hedged by HAs and what should be hedged /// @dev The more is hedged by HAs, the smaller fees are expected to be /// @dev Fees are also corrected by the `bonusMalusMint` parameter which induces a dependence in collateral ratio function _computeFeeMint(uint256 amount, Collateral storage col) internal view returns (uint256 feeMint) { uint64 feeMint64; if (col.feeData.xFeeMint.length == 1) { // This is done to avoid an external call in the case where the fees are constant regardless of the collateral // ratio feeMint64 = col.feeData.yFeeMint[0]; } else { uint64 hedgeRatio = _computeHedgeRatio(amount + col.stocksUsers, col); // Computing the fees based on the spread feeMint64 = _piecewiseLinear(hedgeRatio, col.feeData.xFeeMint, col.feeData.yFeeMint); } // Fees could in some occasions depend on other factors like collateral ratio // Keepers are the ones updating this part of the fees feeMint = (feeMint64 * col.feeData.bonusMalusMint) / BASE_PARAMS; } /// @notice Computes the current fees to be taken when burning stablecoins /// @param amount Amount of collateral corresponding to the stablecoins burnt in the transaction /// @param col Struct for the collateral of interest /// @return feeBurn Burn fees taken to users expressed in collateral /// @dev The amount is obtained after the amount of agTokens sent is converted in collateral /// @dev Fees depend on the hedge ratio that is the ratio between what is hedged by HAs and what should be hedged /// @dev The more is hedged by HAs, the higher fees are expected to be /// @dev Fees are also corrected by the `bonusMalusBurn` parameter which induces a dependence in collateral ratio function _computeFeeBurn(uint256 amount, Collateral storage col) internal view returns (uint256 feeBurn) { uint64 feeBurn64; if (col.feeData.xFeeBurn.length == 1) { // Avoiding an external call if fees are constant feeBurn64 = col.feeData.yFeeBurn[0]; } else { uint64 hedgeRatio = _computeHedgeRatio(col.stocksUsers - amount, col); // Computing the fees based on the spread feeBurn64 = _piecewiseLinear(hedgeRatio, col.feeData.xFeeBurn, col.feeData.yFeeBurn); } // Fees could in some occasions depend on other factors like collateral ratio // Keepers are the ones updating this part of the fees feeBurn = (feeBurn64 * col.feeData.bonusMalusBurn) / BASE_PARAMS; } /// @notice Computes the hedge ratio that is the ratio between the amount of collateral hedged by HAs /// divided by the amount that should be hedged /// @param newStocksUsers Value of the collateral from users to hedge /// @param col Struct for the collateral of interest /// @return ratio Ratio between what's hedged divided what's to hedge /// @dev This function is typically called to compute mint or burn fees /// @dev It seeks from the `PerpetualManager` contract associated to the collateral the total amount /// already hedged by HAs and compares it to the amount to hedge function _computeHedgeRatio(uint256 newStocksUsers, Collateral storage col) internal view returns (uint64 ratio) { // Fetching the amount hedged by HAs from the corresponding `perpetualManager` contract uint256 totalHedgeAmount = col.perpetualManager.totalHedgeAmount(); newStocksUsers = (col.feeData.targetHAHedge * newStocksUsers) / BASE_PARAMS; if (newStocksUsers > totalHedgeAmount) ratio = uint64((totalHedgeAmount * BASE_PARAMS) / newStocksUsers); else ratio = uint64(BASE_PARAMS); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; import "./StableMasterEvents.sol"; /// @title StableMasterStorage /// @author Angle Core Team /// @notice `StableMaster` is the contract handling all the collateral types accepted for a given stablecoin /// It does all the accounting and is the point of entry in the protocol for stable holders and seekers as well as SLPs /// @dev This file contains all the variables and parameters used in the `StableMaster` contract contract StableMasterStorage is StableMasterEvents, FunctionUtils { // All the details about a collateral that are going to be stored in `StableMaster` struct Collateral { // Interface for the token accepted by the underlying `PoolManager` contract IERC20 token; // Reference to the `SanToken` for the pool ISanToken sanToken; // Reference to the `PerpetualManager` for the pool IPerpetualManager perpetualManager; // Adress of the oracle for the change rate between // collateral and the corresponding stablecoin IOracle oracle; // Amount of collateral in the reserves that comes from users // converted in stablecoin value. Updated at minting and burning. // A `stocksUsers` of 10 for a collateral type means that overall the balance of the collateral from users // that minted/burnt stablecoins using this collateral is worth 10 of stablecoins uint256 stocksUsers; // Exchange rate between sanToken and collateral uint256 sanRate; // Base used in the collateral implementation (ERC20 decimal) uint256 collatBase; // Parameters for SLPs and update of the `sanRate` SLPData slpData; // All the fees parameters MintBurnData feeData; } // ============================ Variables and References ===================================== /// @notice Maps a `PoolManager` contract handling a collateral for this stablecoin to the properties of the struct above mapping(IPoolManager => Collateral) public collateralMap; /// @notice Reference to the `AgToken` used in this `StableMaster` /// This reference cannot be changed IAgToken public agToken; // Maps a contract to an address corresponding to the `IPoolManager` address // It is typically used to avoid passing in parameters the address of the `PerpetualManager` when `PerpetualManager` // is calling `StableMaster` to get information // It is the Access Control equivalent for the `SanToken`, `PoolManager`, `PerpetualManager` and `FeeManager` // contracts associated to this `StableMaster` mapping(address => IPoolManager) internal _contractMap; // List of all collateral managers IPoolManager[] internal _managerList; // Reference to the `Core` contract of the protocol ICore internal _core; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.7; /// @title FunctionUtils /// @author Angle Core Team /// @notice Contains all the utility functions that are needed in different places of the protocol /// @dev Functions in this contract should typically be pure functions /// @dev This contract is voluntarily a contract and not a library to save some gas cost every time it is used contract FunctionUtils { /// @notice Base that is used to compute ratios and floating numbers uint256 public constant BASE_TOKENS = 10**18; /// @notice Base that is used to define parameters that need to have a floating value (for instance parameters /// that are defined as ratios) uint256 public constant BASE_PARAMS = 10**9; /// @notice Computes the value of a linear by part function at a given point /// @param x Point of the function we want to compute /// @param xArray List of breaking points (in ascending order) that define the linear by part function /// @param yArray List of values at breaking points (not necessarily in ascending order) /// @dev The evolution of the linear by part function between two breaking points is linear /// @dev Before the first breaking point and after the last one, the function is constant with a value /// equal to the first or last value of the yArray /// @dev This function is relevant if `x` is between O and `BASE_PARAMS`. If `x` is greater than that, then /// everything will be as if `x` is equal to the greater element of the `xArray` function _piecewiseLinear( uint64 x, uint64[] memory xArray, uint64[] memory yArray ) internal pure returns (uint64) { if (x >= xArray[xArray.length - 1]) { return yArray[xArray.length - 1]; } else if (x <= xArray[0]) { return yArray[0]; } else { uint256 lower; uint256 upper = xArray.length - 1; uint256 mid; while (upper - lower > 1) { mid = lower + (upper - lower) / 2; if (xArray[mid] <= x) { lower = mid; } else { upper = mid; } } if (yArray[upper] > yArray[lower]) { // There is no risk of overflow here as in the product of the difference of `y` // with the difference of `x`, the product is inferior to `BASE_PARAMS**2` which does not // overflow for `uint64` return yArray[lower] + ((yArray[upper] - yArray[lower]) * (x - xArray[lower])) / (xArray[upper] - xArray[lower]); } else { return yArray[lower] - ((yArray[lower] - yArray[upper]) * (x - xArray[lower])) / (xArray[upper] - xArray[lower]); } } } /// @notice Checks if the input arrays given by governance to update the fee structure is valid /// @param xArray List of breaking points (in ascending order) that define the linear by part function /// @param yArray List of values at breaking points (not necessarily in ascending order) /// @dev This function is a way to avoid some governance attacks or errors /// @dev The modifier checks if the arrays have a non null length, if their length is the same, if the values /// in the `xArray` are in ascending order and if the values in the `xArray` and in the `yArray` are not superior /// to `BASE_PARAMS` modifier onlyCompatibleInputArrays(uint64[] memory xArray, uint64[] memory yArray) { require(xArray.length == yArray.length && xArray.length > 0, "5"); for (uint256 i = 0; i <= yArray.length - 1; i++) { require(yArray[i] <= uint64(BASE_PARAMS) && xArray[i] <= uint64(BASE_PARAMS), "6"); if (i > 0) { require(xArray[i] > xArray[i - 1], "7"); } } _; } /// @notice Checks if the new value given for the parameter is consistent (it should be inferior to 1 /// if it corresponds to a ratio) /// @param fees Value of the new parameter to check modifier onlyCompatibleFees(uint64 fees) { require(fees <= BASE_PARAMS, "4"); _; } /// @notice Checks if the new address given is not null /// @param newAddress Address to check /// @dev Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#missing-zero-address-validation modifier zeroCheck(address newAddress) { require(newAddress != address(0), "0"); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; /// @title PausableMap /// @author Angle Core Team after a fork from OpenZeppelin's similar Pausable Contracts /// @notice Contract module which allows children to implement an emergency stop /// mechanism that can be triggered by an authorized account. /// @notice It generalizes Pausable from OpenZeppelin by allowing to specify a bytes32 that /// should be stopped /// @dev This module is used through inheritance /// @dev In Angle's protocol, this contract is mainly used in `StableMasterFront` /// to prevent SLPs and new stable holders from coming in /// @dev The modifiers `whenNotPaused` and `whenPaused` from the original OpenZeppelin contracts were removed /// to save some space and because they are not used in the `StableMaster` contract where this contract /// is imported contract PausableMapUpgradeable { /// @dev Emitted when the pause is triggered for `name` event Paused(bytes32 name); /// @dev Emitted when the pause is lifted for `name` event Unpaused(bytes32 name); /// @dev Mapping between a name and a boolean representing the paused state mapping(bytes32 => bool) public paused; /// @notice Triggers stopped state for `name` /// @param name Name for which to pause the contract /// @dev The contract must not be paused for `name` function _pause(bytes32 name) internal { require(!paused[name], "18"); paused[name] = true; emit Paused(name); } /// @notice Returns to normal state for `name` /// @param name Name for which to unpause the contract /// @dev The contract must be paused for `name` function _unpause(bytes32 name) internal { require(paused[name], "19"); paused[name] = false; emit Unpaused(name); } }
{ "evmVersion": "london", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 830 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_poolManager","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemInC","type":"uint256"}],"name":"BurntStablecoins","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_poolManager","type":"address"},{"indexed":false,"internalType":"uint256","name":"_capOnStableMinted","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_maxInterestsDistributed","type":"uint256"}],"name":"CapOnStableAndMaxInterestsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_poolManager","type":"address"},{"indexed":true,"internalType":"address","name":"_perpetualManager","type":"address"},{"indexed":true,"internalType":"address","name":"_sanToken","type":"address"},{"indexed":false,"internalType":"address","name":"_oracle","type":"address"}],"name":"CollateralDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_poolManager","type":"address"}],"name":"CollateralRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_poolManager","type":"address"},{"indexed":false,"internalType":"uint64[]","name":"_xFee","type":"uint64[]"},{"indexed":false,"internalType":"uint64[]","name":"_yFee","type":"uint64[]"},{"indexed":false,"internalType":"uint8","name":"_type","type":"uint8"}],"name":"FeeArrayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_poolManager","type":"address"},{"indexed":true,"internalType":"address","name":"newFeeManager","type":"address"}],"name":"FeeManagerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_poolManager","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountForUserInStable","type":"uint256"}],"name":"MintedStablecoins","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_poolManager","type":"address"},{"indexed":true,"internalType":"address","name":"_oracle","type":"address"}],"name":"OracleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"name","type":"bytes32"}],"name":"Paused","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":"_poolManager","type":"address"},{"indexed":false,"internalType":"uint64","name":"_feesForSLPs","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"_interestsForSLPs","type":"uint64"}],"name":"SLPsIncentivesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_newSanRate","type":"uint256"}],"name":"SanRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_poolManager","type":"address"},{"indexed":false,"internalType":"uint256","name":"_stocksUsers","type":"uint256"}],"name":"StocksUsersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"name","type":"bytes32"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"BASE_PARAMS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BASE_TOKENS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CORE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"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":"SLP","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STABLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"gain","type":"uint256"}],"name":"accumulateInterest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"governor","type":"address"}],"name":"addGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"agToken","outputs":[{"internalType":"contract IAgToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"burner","type":"address"},{"internalType":"address","name":"dest","type":"address"},{"internalType":"contract IPoolManager","name":"poolManager","type":"address"},{"internalType":"uint256","name":"minCollatAmount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPoolManager","name":"","type":"address"}],"name":"collateralMap","outputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"contract ISanToken","name":"sanToken","type":"address"},{"internalType":"contract IPerpetualManager","name":"perpetualManager","type":"address"},{"internalType":"contract IOracle","name":"oracle","type":"address"},{"internalType":"uint256","name":"stocksUsers","type":"uint256"},{"internalType":"uint256","name":"sanRate","type":"uint256"},{"internalType":"uint256","name":"collatBase","type":"uint256"},{"components":[{"internalType":"uint256","name":"lastBlockUpdated","type":"uint256"},{"internalType":"uint256","name":"lockedInterests","type":"uint256"},{"internalType":"uint256","name":"maxInterestsDistributed","type":"uint256"},{"internalType":"uint256","name":"feesAside","type":"uint256"},{"internalType":"uint64","name":"slippageFee","type":"uint64"},{"internalType":"uint64","name":"feesForSLPs","type":"uint64"},{"internalType":"uint64","name":"slippage","type":"uint64"},{"internalType":"uint64","name":"interestsForSLPs","type":"uint64"}],"internalType":"struct SLPData","name":"slpData","type":"tuple"},{"components":[{"internalType":"uint64[]","name":"xFeeMint","type":"uint64[]"},{"internalType":"uint64[]","name":"yFeeMint","type":"uint64[]"},{"internalType":"uint64[]","name":"xFeeBurn","type":"uint64[]"},{"internalType":"uint64[]","name":"yFeeBurn","type":"uint64[]"},{"internalType":"uint64","name":"targetHAHedge","type":"uint64"},{"internalType":"uint64","name":"bonusMalusMint","type":"uint64"},{"internalType":"uint64","name":"bonusMalusBurn","type":"uint64"},{"internalType":"uint256","name":"capOnStableMinted","type":"uint256"}],"internalType":"struct MintBurnData","name":"feeData","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"convertToSLP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"governorList","type":"address[]"},{"internalType":"address","name":"guardian","type":"address"},{"internalType":"address","name":"_agToken","type":"address"}],"name":"deploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPoolManager","name":"poolManager","type":"address"},{"internalType":"contract IPerpetualManager","name":"perpetualManager","type":"address"},{"internalType":"contract IFeeManager","name":"feeManager","type":"address"},{"internalType":"contract IOracle","name":"oracle","type":"address"},{"internalType":"contract ISanToken","name":"sanToken","type":"address"}],"name":"deployCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"contract IPoolManager","name":"poolManager","type":"address"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCollateralRatio","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":"getStocksUsers","outputs":[{"internalType":"uint256","name":"_stocksUsers","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":"core_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"contract IPoolManager","name":"poolManager","type":"address"},{"internalType":"uint256","name":"minStableAmount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"agent","type":"bytes32"},{"internalType":"contract IPoolManager","name":"poolManager","type":"address"}],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"contract IPoolManager","name":"poolManagerUp","type":"address"},{"internalType":"contract IPoolManager","name":"poolManagerDown","type":"address"}],"name":"rebalanceStocksUsers","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":"contract IPoolManager","name":"poolManager","type":"address"},{"internalType":"contract ICollateralSettler","name":"settlementContract","type":"address"}],"name":"revokeCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"oldGuardian","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":"uint256","name":"_capOnStableMinted","type":"uint256"},{"internalType":"uint256","name":"_maxInterestsDistributed","type":"uint256"},{"internalType":"contract IPoolManager","name":"poolManager","type":"address"}],"name":"setCapOnStableAndMaxInterests","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newCore","type":"address"}],"name":"setCore","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_bonusMalusMint","type":"uint64"},{"internalType":"uint64","name":"_bonusMalusBurn","type":"uint64"},{"internalType":"uint64","name":"_slippage","type":"uint64"},{"internalType":"uint64","name":"_slippageFee","type":"uint64"}],"name":"setFeeKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFeeManager","type":"address"},{"internalType":"address","name":"oldFeeManager","type":"address"},{"internalType":"contract IPoolManager","name":"poolManager","type":"address"}],"name":"setFeeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newGuardian","type":"address"},{"internalType":"address","name":"oldGuardian","type":"address"}],"name":"setGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_feesForSLPs","type":"uint64"},{"internalType":"uint64","name":"_interestsForSLPs","type":"uint64"},{"internalType":"contract IPoolManager","name":"poolManager","type":"address"}],"name":"setIncentivesForSLPs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IOracle","name":"_oracle","type":"address"},{"internalType":"contract IPoolManager","name":"poolManager","type":"address"}],"name":"setOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_targetHAHedge","type":"uint64"}],"name":"setTargetHAHedge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPoolManager","name":"poolManager","type":"address"},{"internalType":"uint64[]","name":"_xFee","type":"uint64[]"},{"internalType":"uint64[]","name":"_yFee","type":"uint64[]"},{"internalType":"uint8","name":"_mint","type":"uint8"}],"name":"setUserFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"loss","type":"uint256"}],"name":"signalLoss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"agent","type":"bytes32"},{"internalType":"contract IPoolManager","name":"poolManager","type":"address"}],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"poolManager","type":"address"}],"name":"updateStocksUsers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"burner","type":"address"},{"internalType":"address","name":"dest","type":"address"},{"internalType":"contract IPoolManager","name":"poolManager","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50600654610100900460ff16806200002c575060065460ff16155b620000945760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b600654610100900460ff16158015620000b7576006805461ffff19166101011790555b8015620000ca576006805461ff00191690555b50615fdd80620000db6000396000f3fe608060405234801561001057600080fd5b50600436106102ff5760003560e01c80635c38eb3a1161019c578063ba8b7223116100ee578063d547741f11610097578063ee565a6311610071578063ee565a63146106b2578063eecdac88146106dd578063f36246d1146106f057600080fd5b8063d547741f1461067d578063df1b8bd314610690578063ec5b1bee1461069f57600080fd5b8063cbb3edd2116100c8578063cbb3edd21461063b578063ccc574901461064e578063cd377c531461067557600080fd5b8063ba8b7223146105ed578063be8c31ff14610615578063c4d66de81461062857600080fd5b806391d14854116101505780639f48118f1161012a5780639f48118f146105c7578063a217fddf146105d2578063af648c3d146105da57600080fd5b806391d148541461056e5780639af2dcae146105915780639e9e4666146105a457600080fd5b806380009630116101815780638000963014610535578063892cfc161461054857806391a9ca481461055b57600080fd5b80635c38eb3a1461050f5780636d1042161461052257600080fd5b8063252c94061161025557806336568abe1161020957806359de6866116101e357806359de6866146104d65780635a3c10f1146104e95780635b749f35146104fc57600080fd5b806336568abe146104895780633c4a25d01461049c57806354d9f653146104af57600080fd5b80632f2ff15d1161023a5780632f2ff15d1461043657806333c509d114610449578063344844db1461045c57600080fd5b8063252c9406146104105780632e2d29841461042357600080fd5b806322ac5c9a116102b757806324ea54f41161029157806324ea54f4146103c15780632509f1b9146103d6578063251ad873146103fd57600080fd5b806322ac5c9a1461036557806323e103a814610378578063248a9ca31461038b57600080fd5b8063074efa78116102e8578063074efa781461032c578063087264c91461033f5780631a115ff11461035257600080fd5b8063050f53fe14610304578063074ee44614610319575b600080fd5b610317610312366004615498565b610705565b005b610317610327366004615796565b6107e1565b61031761033a3660046153ad565b610a85565b61031761034d36600461557c565b610c5f565b610317610360366004615595565b610cb4565b610317610373366004615642565b610dce565b6103176103863660046156cc565b6116f7565b6103ae61039936600461557c565b60009081526007602052604090206001015490565b6040519081526020015b60405180910390f35b6103ae600080516020615f8883398151915281565b6103ae7fe0136b3661826a483734248681e4f59ae66bc6065ceb43fdd469ecb22c21d74581565b61031761040b366004615595565b6118ba565b61031761041e36600461557c565b6119b5565b61031761043136600461576f565b611bbe565b610317610444366004615595565b611c2b565b610317610457366004615374565b611c56565b336000908152600260209081526040808320546001600160a01b03168352908290529020600401546103ae565b610317610497366004615595565b611d42565b6103176104aa36600461533a565b611d89565b6103ae7ffb286912c6eadba541f23a3bb3e83373ab139b6e65d84e2a473c186efc2b464281565b6103176104e4366004615595565b611e7f565b6103176104f73660046157de565b611f05565b61031761050a36600461580c565b611fd0565b61031761051d366004615374565b612025565b610317610530366004615714565b612250565b61031761054336600461533a565b612596565b610317610556366004615374565b61260f565b610317610569366004615853565b612f29565b61058161057c366004615595565b613005565b60405190151581526020016103b8565b61031761059f36600461576f565b613032565b6105816105b236600461557c565b60056020526000908152604090205460ff1681565b6103ae633b9aca0081565b6103ae600081565b6103176105e836600461533a565b61318d565b6106006105fb36600461533a565b613259565b6040516103b899989796959493929190615b23565b6103176106233660046155ba565b613586565b61031761063636600461533a565b613809565b610317610649366004615595565b6139a9565b6103ae7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6103ae613a14565b61031761068b366004615595565b613c4a565b6103ae670de0b6b3a764000081565b6103176106ad366004615827565b613c70565b6001546106c5906001600160a01b031681565b6040516001600160a01b0390911681526020016103b8565b6103176106eb36600461533a565b613ddc565b6103ae600080516020615f6883398151915281565b600080516020615f6883398151915261071e8133613ed2565b60005b84518110156107a35761076d7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5586838151811061076057610760615f17565b6020026020010151613f36565b610791600080516020615f8883398151915286838151811061076057610760615f17565b8061079b81615eba565b915050610721565b506107bc600080516020615f8883398151915284613f36565b50600180546001600160a01b0319166001600160a01b03929092169190911790555050565b6001600160a01b038216600090815260208190526040902061080281613f9f565b61082c7ffb286912c6eadba541f23a3bb3e83373ab139b6e65d84e2a473c186efc2b464284613fdd565b8054610843906001600160a01b031633858861406a565b6003810154604051633593ba7b60e01b8152600481018790526000916001600160a01b031690633593ba7b9060240160206040518083038186803b15801561088a57600080fd5b505afa15801561089e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c291906156b3565b905060006108d082846140d9565b9050633b9aca006108e18282615e38565b6108eb9084615dea565b6108f59190615cc2565b9150838210156109315760405162461bcd60e51b8152602060048201526002602482015261313560f01b60448201526064015b60405180910390fd5b818360040160008282546109459190615c7f565b90915550506011830154600484015411156109875760405162461bcd60e51b8152602060048201526002602482015261189b60f11b6044820152606401610928565b60408051888152602081018490526001600160a01b038716917ff0543d9ab673fd2b6789938fb372d27b43b955c1a90eb8a982bc4aa50687962c910160405180910390a2610a166109dd6002633b9aca00615d3f565b600b850154600160401b90046001600160401b03166109fc848b615dea565b610a069190615dea565b610a109190615cc2565b846142a2565b6001546040516340c10f1960e01b81526001600160a01b03888116600483015260248201859052909116906340c10f1990604401600060405180830381600087803b158015610a6457600080fd5b505af1158015610a78573d6000803e3d6000fd5b5050505050505050505050565b600080516020615f88833981519152610a9e8133613ed2565b836001600160a01b038116610ad95760405162461bcd60e51b81526020600482015260016024820152600360fc1b6044820152606401610928565b6001600160a01b0383166000908152602081905260409020610afa81613f9f565b6001600160a01b03858116600090815260026020526040902054811690851614610b4b5760405162461bcd60e51b8152602060048201526002602482015261031360f41b6044820152606401610928565b846001600160a01b0316866001600160a01b03161415610b925760405162461bcd60e51b81526020600482015260026024820152610c4d60f21b6044820152606401610928565b6001600160a01b0380861660009081526002602052604080822080546001600160a01b03199081169091558984168084528284208054958a1695909216851790915590519092917fe139a19f7890c89603e0d013fb99aed7d286ef55ef5a092ddd2980a3afd2138d91a360405163472d35b960e01b81526001600160a01b03878116600483015285169063472d35b990602401600060405180830381600087803b158015610c3f57600080fd5b505af1158015610c53573d6000803e3d6000fd5b50505050505050505050565b336000908152602081905260409020610c7781613f9f565b600b810154610cb090633b9aca0090610ca090600160c01b90046001600160401b031685615dea565b610caa9190615cc2565b826142a2565b5050565b336000908152600260209081526040808320546001600160a01b031680845291839052909120610ce381613f9f565b610d0d7fe0136b3661826a483734248681e4f59ae66bc6065ceb43fdd469ecb22c21d74583613fdd565b610d186000826142a2565b600181015460058201546001600160a01b03909116906340c10f19908590610d48670de0b6b3a764000089615dea565b610d529190615cc2565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015610db057600080fd5b505af1158015610dc4573d6000803e3d6000fd5b5050505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610df98133613ed2565b306001600160a01b0316826001600160a01b0316636ac5dc466040518163ffffffff1660e01b815260040160206040518083038186803b158015610e3c57600080fd5b505afa158015610e50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e749190615357565b6001600160a01b0316148015610f0b5750856001600160a01b0316826001600160a01b031663dc4c90d36040518163ffffffff1660e01b815260040160206040518083038186803b158015610ec857600080fd5b505afa158015610edc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f009190615357565b6001600160a01b0316145b8015610f985750306001600160a01b0316866001600160a01b0316636ac5dc466040518163ffffffff1660e01b815260040160206040518083038186803b158015610f5557600080fd5b505afa158015610f69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8d9190615357565b6001600160a01b0316145b80156110255750856001600160a01b0316856001600160a01b031663dc4c90d36040518163ffffffff1660e01b815260040160206040518083038186803b158015610fe257600080fd5b505afa158015610ff6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061101a9190615357565b6001600160a01b0316145b80156110b25750306001600160a01b0316846001600160a01b0316636ac5dc466040518163ffffffff1660e01b815260040160206040518083038186803b15801561106f57600080fd5b505afa158015611083573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a79190615357565b6001600160a01b0316145b6110e25760405162461bcd60e51b81526020600482015260016024820152603960f81b6044820152606401610928565b6000866001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561111d57600080fd5b505afa158015611131573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111559190615357565b90506000816001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561119257600080fd5b505afa1580156111a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ca91906158a7565b6111d590600a615d3f565b905080856001600160a01b0316639aefb5c36040518163ffffffff1660e01b815260040160206040518083038186803b15801561121157600080fd5b505afa158015611225573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124991906156b3565b1461127b5760405162461bcd60e51b8152602060048201526002602482015261313160f01b6044820152606401610928565b6001600160a01b0380891660009081526020819052604090208054909116156112cb5760405162461bcd60e51b8152602060048201526002602482015261313360f01b6044820152606401610928565b828160000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550848160010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550878160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550858160030160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550670de0b6b3a7640000816005018190555081816006018190555088600260008a6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508860026000896001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055506003899080600181540180825580915050600190039060005260206000200160009091909190916101000a8154816001600160a01b0302191690836001600160a01b031602179055506114d27fe0136b3661826a483734248681e4f59ae66bc6065ceb43fdd469ecb22c21d7458a6040516020016114b792919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b604051602081830303815290604052805190602001206144fd565b6115237ffb286912c6eadba541f23a3bb3e83373ab139b6e65d84e2a473c186efc2b46428a6040516020016114b792919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b6000600460009054906101000a90046001600160a01b03166001600160a01b031663a6d7fe2d6040518163ffffffff1660e01b815260040160006040518083038186803b15801561157357600080fd5b505afa158015611587573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115af91908101906153f8565b90506000600460009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561160157600080fd5b505afa158015611615573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116399190615357565b604051636cb2e74d60e11b81529091506001600160a01b038c169063d965ce9a9061167090859085908f908f908f90600401615a71565b600060405180830381600087803b15801561168a57600080fd5b505af115801561169e573d6000803e3d6000fd5b50506040516001600160a01b038b81168252808b1693508d811692508e16907f129e7033df7c6cf5b088a92e04f596efded950692229dda217a8054d40bb02929060200160405180910390a45050505050505050505050565b6001600160a01b038116600090815260208190526040902061171881613f9f565b6117427fe0136b3661826a483734248681e4f59ae66bc6065ceb43fdd469ecb22c21d74583613fdd565b61174d6000826142a2565b6001600160a01b0384163314156117cb5760018101546040516315a38ec760e11b8152600481018790526001600160a01b03868116602483015290911690632b471d8e90604401600060405180830381600087803b1580156117ae57600080fd5b505af11580156117c2573d6000803e3d6000fd5b5050505061183a565b6001810154604051630d43af8160e21b8152600481018790526001600160a01b0386811660248301523360448301529091169063350ebe0490606401600060405180830381600087803b15801561182157600080fd5b505af1158015611835573d6000803e3d6000fd5b505050505b6000611852633b9aca00670de0b6b3a7640000615dea565b6005830154600b84015461187a90600160801b90046001600160401b0316633b9aca00615e38565b6118849089615dea565b61188e9190615dea565b6118989190615cc2565b82549091506118b2906001600160a01b031684868461406a565b505050505050565b6001546001600160a01b031633146118f85760405162461bcd60e51b81526020600482015260016024820152603360f81b6044820152606401610928565b6001600160a01b038116600090815260208190526040902061191981613f9f565b82816004015410156119515760405162461bcd60e51b81526020600482015260016024820152600d60fa1b6044820152606401610928565b828160040160008282546119659190615e38565b9091555050805460048201546040519081526001600160a01b03909116907f72e0daee492d85727eb3f32c69303a6dd57af5bd2b127a04641de5d70e1494de9060200160405180910390a2505050565b3360008181526020819052604090206119cd81613f9f565b6001810154604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b158015611a1457600080fd5b505afa158015611a28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4c91906156b3565b90508015611bb857611a66670de0b6b3a764000085615dea565b6008830154611a7e90670de0b6b3a764000090615dea565b828460050154611a8e9190615dea565b611a989190615c7f565b1115611b11576008820154848110611aad5750835b80836007016001016000828254611ac49190615e38565b90915550829050670de0b6b3a7640000611ade8388615e38565b611ae89190615dea565b611af29190615cc2565b836005016000828254611b059190615e38565b90915550611b71915050565b6001600583015560006008830155604051611b71906114b7907fe0136b3661826a483734248681e4f59ae66bc6065ceb43fdd469ecb22c21d74590869060200191825260601b6bffffffffffffffffffffffff1916602082015260340190565b815460058301546040519081526001600160a01b03909116907faa959327c96abe1dbec8186dbe4bb630ffa7f1a65ad98780481f14757004498e9060200160405180910390a25b50505050565b6001600160a01b0381166000908152602081905260409020611bdf81613f9f565b611c097fe0136b3661826a483734248681e4f59ae66bc6065ceb43fdd469ecb22c21d74583613fdd565b611c146000826142a2565b8054610d18906001600160a01b031633848761406a565b600082815260076020526040902060010154611c478133613ed2565b611c518383613f36565b505050565b600080516020615f68833981519152611c6f8133613ed2565b611c87600080516020615f8883398151915283614597565b611c9f600080516020615f8883398151915284613f36565b60005b600354811015611bb85760038181548110611cbf57611cbf615f17565b6000918252602090912001546040516333c509d160e01b81526001600160a01b0386811660048301528581166024830152909116906333c509d190604401600060405180830381600087803b158015611d1757600080fd5b505af1158015611d2b573d6000803e3d6000fd5b505050508080611d3a90615eba565b915050611ca2565b6001600160a01b0381163314611d7f5760405162461bcd60e51b8152602060048201526002602482015261373160f01b6044820152606401610928565b610cb08282614597565b600080516020615f68833981519152611da28133613ed2565b611dcc7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5583613f36565b611de4600080516020615f8883398151915283613f36565b60005b600354811015611c515760038181548110611e0457611e04615f17565b6000918252602090912001546040516303c4a25d60e41b81526001600160a01b03858116600483015290911690633c4a25d090602401600060405180830381600087803b158015611e5457600080fd5b505af1158015611e68573d6000803e3d6000fd5b505050508080611e7790615eba565b915050611de7565b600080516020615f88833981519152611e988133613ed2565b6001600160a01b0382166000908152602081905260409020611eb981613f9f565b611bb88484604051602001611eea92919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b604051602081830303815290604052805190602001206145fe565b600080516020615f88833981519152611f1e8133613ed2565b6001600160a01b0382166000908152602081905260409020611f3f81613f9f565b8060040154851015611f775760405162461bcd60e51b81526020600482015260016024820152600760fb1b6044820152606401610928565b601181018590556009810184905560408051868152602081018690526001600160a01b038516917faa2226ff9a1d81d234d2d96d4a86cc03d1b9165cda2f2591c1df913002201f22910160405180910390a25050505050565b336000908152600260209081526040808320546001600160a01b031680845291839052909120611fff81613f9f565b601001805467ffffffffffffffff19166001600160401b03939093169290921790915550565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556120508133613ed2565b826001600160a01b03811661208b5760405162461bcd60e51b81526020600482015260016024820152600360fc1b6044820152606401610928565b6001600160a01b03831660009081526020819052604090206120ac81613f9f565b60038101546001600160a01b03868116911614156120f15760405162461bcd60e51b8152602060048201526002602482015261189960f11b6044820152606401610928565b846001600160a01b0316639aefb5c36040518163ffffffff1660e01b815260040160206040518083038186803b15801561212a57600080fd5b505afa15801561213e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216291906156b3565b8160060154146121995760405162461bcd60e51b8152602060048201526002602482015261313160f01b6044820152606401610928565b6003810180546001600160a01b0319166001600160a01b0387811691821790925560405190918616907f078c3b417dadf69374a59793b829c52001247130433427049317bde56607b1b790600090a36002810154604051637adbf97360e01b81526001600160a01b03878116600483015290911690637adbf97390602401600060405180830381600087803b15801561223157600080fd5b505af1158015612245573d6000803e3d6000fd5b505050505050505050565b6001600160a01b038216600090815260208190526040902061227181613f9f565b61229b7ffb286912c6eadba541f23a3bb3e83373ab139b6e65d84e2a473c186efc2b464284613fdd565b80600401548611156122d45760405162461bcd60e51b8152602060048201526002602482015261313760f01b6044820152606401610928565b6001600160a01b038516331415612350576001546040516315a38ec760e11b8152600481018890526001600160a01b03878116602483015290911690632b471d8e90604401600060405180830381600087803b15801561233357600080fd5b505af1158015612347573d6000803e3d6000fd5b505050506123bd565b600154604051630d43af8160e21b8152600481018890526001600160a01b0387811660248301523360448301529091169063350ebe0490606401600060405180830381600087803b1580156123a457600080fd5b505af11580156123b8573d6000803e3d6000fd5b505050505b60038101546040805163442133bd60e01b815290516000926001600160a01b03169163442133bd916004808301926020929190829003018186803b15801561240457600080fd5b505afa158015612418573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243c91906156b3565b90506000818360060154896124519190615dea565b61245b9190615cc2565b9050600061246d633b9aca0084615dea565b846006015461247c8b87614689565b61248a90633b9aca00615e38565b612494908c615dea565b61249e9190615dea565b6124a89190615cc2565b9050848110156124df5760405162461bcd60e51b8152602060048201526002602482015261313560f01b6044820152606401610928565b888460040160008282546124f39190615e38565b9091555050604080518a8152602081018390526001600160a01b038816917f6acf1c7b1f88ba23f81a749aacb5bcaabf5095176f3eee66e251bbabd59544ed910160405180910390a2600b84015461257f90633b9aca0090600160401b90046001600160401b03166125658486615e38565b61256f9190615dea565b6125799190615cc2565b856142a2565b8354612245906001600160a01b031687898461406a565b600080516020615f688339815191526125af8133613ed2565b6004546125d490600080516020615f68833981519152906001600160a01b0316614597565b6125ec600080516020615f6883398151915283613f36565b50600480546001600160a01b0319166001600160a01b0392909216919091179055565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561263a8133613ed2565b60035460009060018110156126765760405162461bcd60e51b8152602060048201526002602482015261031360f41b6044820152606401610928565b60005b612684600183615e38565b81101561275457856001600160a01b0316600382815481106126a8576126a8615f17565b6000918252602090912001546001600160a01b03161415612742576001925060036126d38484615e38565b815481106126e3576126e3615f17565b600091825260209091200154600380546001600160a01b03909216918390811061270f5761270f615f17565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550612754565b8061274c81615eba565b915050612679565b50816001148061279d57506001600160a01b0385166003612776600184615e38565b8154811061278657612786615f17565b6000918252602090912001546001600160a01b0316145b6127ce5760405162461bcd60e51b8152602060048201526002602482015261031360f41b6044820152606401610928565b60038054806127df576127df615f01565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0387811683528282526040808420815161012080820184528254851682526001830154851682870152600283015485168285015260038301549094166060808301919091526004830154608080840191909152600584015460a080850191909152600685015460c08086019190915286516101008181018952600788015482526008880154828c01526009880154828a0152600a88015495820195909552600b8701546001600160401b0380821695830195909552600160401b8104851693820193909352600160801b8304841691810191909152600160c01b90910490911660e0828101919091528301528351600c840180549788028201870190955280820187815292969395918701949093909284929091849184018282801561298357602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116129405790505b5050505050815260200160018201805480602002602001604051908101604052809291908181526020018280548015612a0d57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116129ca5790505b5050505050815260200160028201805480602002602001604051908101604052809291908181526020018280548015612a9757602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411612a545790505b5050505050815260200160038201805480602002602001604051908101604052809291908181526020018280548015612b2157602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411612ade5790505b50505091835250506004828101546001600160401b03808216602080860191909152600160401b83048216604080870191909152600160801b909304909116606085015260059094015460809093019290925292909352825163d0fb020360e01b81529251949550600294600094506001600160a01b038c169363d0fb020393818101939291829003018186803b158015612bbb57600080fd5b505afa158015612bcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf39190615357565b6001600160a01b0390811682526020808301939093526040918201600090812080546001600160a01b031990811690915585840151831682526002808652848320805483169055928b1682529381905291822080548416815560018101805485169055908101805484169055600381018054909316909255600482018190556005820181905560068201819055600782018190556008820181905560098201819055600a8201819055600b8201819055600c820181612cb282826151a8565b612cc06001830160006151a8565b612cce6002830160006151a8565b612cdc6003830160006151a8565b506004810180547fffffffffffffffff000000000000000000000000000000000000000000000000169055600060059091018190556040516001600160a01b038a1693507f10d8ed8cba916885e339cb21deefb3842b3f417eac81a7f34b2978b4ecc2040f9250a280604001516001600160a01b0316638456cb596040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612d8357600080fd5b505af1158015612d97573d6000803e3d6000fd5b505082516040516370a0823160e01b81526001600160a01b038a811660048301526000945090911691506370a082319060240160206040518083038186803b158015612de257600080fd5b505afa158015612df6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e1a91906156b3565b8251909150612e34906001600160a01b031688888461406a565b600082606001516001600160a01b03166392611e336040518163ffffffff1660e01b815260040160206040518083038186803b158015612e7357600080fd5b505afa158015612e87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eab91906156b3565b60a08401516080850151604051630462bc3f60e51b815260048101849052602481019290925260448201529091506001600160a01b03881690638c5787e090606401600060405180830381600087803b158015612f0757600080fd5b505af1158015612f1b573d6000803e3d6000fd5b505050505050505050505050565b336000908152600260209081526040808320546001600160a01b03168352908290529020612f5681613f9f565b6010810180547fffffffffffffffff00000000000000000000000000000000ffffffffffffffff16600160401b6001600160401b03978816027fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff1617600160801b9587168602179055600b0180547fffffffffffffffff0000000000000000ffffffffffffffff00000000000000001692851690930267ffffffffffffffff1916919091179216919091179055565b60008281526007602090815260408083206001600160a01b038516845290915290205460ff165b92915050565b600080516020615f8883398151915261304b8133613ed2565b6001600160a01b038084166000908152602081905260408082209285168252902061307582613f9f565b61307e81613f9f565b60118201546004830154613093908890615c7f565b11156130c55760405162461bcd60e51b81526020600482015260016024820152600760fb1b6044820152606401610928565b858160040160008282546130d99190615e38565b92505081905550858260040160008282546130f49190615c7f565b9091555050815460048301546040519081526001600160a01b03909116907f72e0daee492d85727eb3f32c69303a6dd57af5bd2b127a04641de5d70e1494de9060200160405180910390a2805460048201546040519081526001600160a01b03909116907f72e0daee492d85727eb3f32c69303a6dd57af5bd2b127a04641de5d70e1494de9060200160405180910390a2505050505050565b600080516020615f688339815191526131a68133613ed2565b6131be600080516020615f8883398151915283614597565b60005b600354811015611c5157600381815481106131de576131de615f17565b60009182526020909120015460405163af648c3d60e01b81526001600160a01b0385811660048301529091169063af648c3d90602401600060405180830381600087803b15801561322e57600080fd5b505af1158015613242573d6000803e3d6000fd5b50505050808061325190615eba565b9150506131c1565b60006020818152918152604090819020805460018201546002830154600384015460048501546005860154600687015488516101008082018b5260078a0154825260088a0154828d015260098a0154828c0152600a8a01546060830152600b8a01546001600160401b038082166080850152600160401b8204811660a0850152600160801b8204811660c0850152600160c01b9091041660e08301528a51600c8b0180549d8e028201610120908101909d529181018d81526001600160a01b039a8b169d998b169c988b169b9a909716999598949793969295949093919284929091849184018282801561339e57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b03168152602001906008019060208260070104928301926001038202915080841161335b5790505b505050505081526020016001820180548060200260200160405190810160405280929190818152602001828054801561342857602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116133e55790505b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156134b257602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b03168152602001906008019060208260070104928301926001038202915080841161346f5790505b505050505081526020016003820180548060200260200160405190810160405280929190818152602001828054801561353c57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116134f95790505b505050918352505060048201546001600160401b038082166020840152600160401b820481166040840152600160801b909104166060820152600590910154608090910152905089565b600080516020615f8883398151915261359f8133613ed2565b8383805182511480156135b3575060008251115b6135e35760405162461bcd60e51b81526020600482015260016024820152603560f81b6044820152606401610928565b60005b600182516135f49190615e38565b811161373157633b9aca006001600160401b031682828151811061361a5761361a615f17565b60200260200101516001600160401b0316111580156136685750633b9aca006001600160401b031683828151811061365457613654615f17565b60200260200101516001600160401b031611155b6136985760405162461bcd60e51b81526020600482015260016024820152601b60f91b6044820152606401610928565b801561371f57826136aa600183615e38565b815181106136ba576136ba615f17565b60200260200101516001600160401b03168382815181106136dd576136dd615f17565b60200260200101516001600160401b03161161371f5760405162461bcd60e51b81526020600482015260016024820152603760f81b6044820152606401610928565b8061372981615eba565b9150506135e6565b506001600160a01b038716600090815260208190526040902061375381613f9f565b60ff85161561378d57865161377190600c83019060208a01906151cd565b50855161378790600d83019060208901906151cd565b506137ba565b86516137a290600e83019060208a01906151cd565b5085516137b890600f83019060208901906151cd565b505b876001600160a01b03167f81d92f91000563c9b4868d5b791e00eb2c2e9b194b09df5608c862bda78c0b9d8888886040516137f793929190615aea565b60405180910390a25050505050505050565b806001600160a01b0381166138445760405162461bcd60e51b81526020600482015260016024820152600360fc1b6044820152606401610928565b600654610100900460ff168061385d575060065460ff16155b6138c05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610928565b600654610100900460ff161580156138e2576006805461ffff19166101011790555b6138ea614807565b600480546001600160a01b0319166001600160a01b03851617905561391d600080516020615f68833981519152846148c1565b613935600080516020615f68833981519152806148cb565b61396d7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55600080516020615f688339815191526148cb565b613993600080516020615f88833981519152600080516020615f688339815191526148cb565b8015611c51576006805461ff0019169055505050565b600080516020615f888339815191526139c28133613ed2565b6001600160a01b03821660009081526020819052604090206139e381613f9f565b611bb884846040516020016114b792919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b600080600160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015613a6557600080fd5b505afa158015613a79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a9d91906156b3565b905080613aad5760001991505090565b6000805b600354811015613c295760008060038381548110613ad157613ad1615f17565b60009182526020808320909101546001600160a01b0390811684529083019390935260409091019020600390810154815492169163240fd5ab919084908110613b1c57613b1c615f17565b6000918252602091829020015460408051632768385d60e01b815290516001600160a01b0390921692632768385d92600480840193829003018186803b158015613b6557600080fd5b505afa158015613b79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b9d91906156b3565b6040518263ffffffff1660e01b8152600401613bbb91815260200190565b60206040518083038186803b158015613bd357600080fd5b505afa158015613be7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c0b91906156b3565b613c159083615c7f565b915080613c2181615eba565b915050613ab1565b5081613c39633b9aca0083615dea565b613c439190615cc2565b9250505090565b600082815260076020526040902060010154613c668133613ed2565b611c518383614597565b600080516020615f88833981519152613c898133613ed2565b83633b9aca00816001600160401b03161115613ccb5760405162461bcd60e51b81526020600482015260016024820152600d60fa1b6044820152606401610928565b83633b9aca00816001600160401b03161115613d0d5760405162461bcd60e51b81526020600482015260016024820152600d60fa1b6044820152606401610928565b6001600160a01b0384166000908152602081905260409020613d2e81613f9f565b600b8101805477ffffffffffffffff0000000000000000ffffffffffffffff16600160401b6001600160401b038a811691820277ffffffffffffffffffffffffffffffffffffffffffffffff1692909217600160c01b928a16928302179092556040805192835260208301919091526001600160a01b038716917f1131c4b35ab7476b5e63eeda716dfe137c676f01395ab743a39ac34b099be9e2910160405180910390a250505050505050565b600080516020615f68833981519152613df58133613ed2565b613e1f7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5583614597565b613e37600080516020615f8883398151915283614597565b60005b600354811015611c515760038181548110613e5757613e57615f17565b600091825260209091200154604051631dd9b59160e31b81526001600160a01b0385811660048301529091169063eecdac8890602401600060405180830381600087803b158015613ea757600080fd5b505af1158015613ebb573d6000803e3d6000fd5b505050508080613eca90615eba565b915050613e3a565b613edc8282613005565b610cb057613ef4816001600160a01b0316601461491f565b613eff83602061491f565b604051602001613f109291906159f0565b60408051601f198184030181529082905262461bcd60e51b825261092891600401615bf9565b613f408282613005565b610cb05760008281526007602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b80546001600160a01b0316613fda5760405162461bcd60e51b81526020600482015260016024820152603360f81b6044820152606401610928565b50565b60056000838360405160200161400f92919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b60408051601f198184030181529181528151602092830120835290820192909252016000205460ff1615610cb05760405162461bcd60e51b8152602060048201526002602482015261062760f31b6044820152606401610928565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b179052611bb8908590614ace565b600c81015460009081906001141561413057600d8301805460009061410057614100615f17565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b03169050614262565b600061414b8460040154866141459190615c7f565b85614bb3565b905061425e8185600c016000018054806020026020016040519081016040528092919081815260200182805480156141d457602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116141915790505b50505050600d8801805460408051602080840282018101909252828152935083018282801561425457602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116142115790505b5050505050614ca3565b9150505b6010830154633b9aca009061428790600160401b90046001600160401b031683615e09565b6001600160401b031661429a9190615cc2565b949350505050565b6008810154600782015442148015906142bb5750600081115b15614431576001820154604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b15801561430757600080fd5b505afa15801561431b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061433f91906156b3565b9050801561442a5760098301548211156143a5576009830154819061436d90670de0b6b3a764000090615dea565b6143779190615cc2565b83600501600082825461438a9190615c7f565b9091555050600983015461439e9083615e38565b91506143df565b806143b8670de0b6b3a764000084615dea565b6143c29190615cc2565b8360050160008282546143d59190615c7f565b9091555060009250505b825460058401546040519081526001600160a01b03909116907faa959327c96abe1dbec8186dbe4bb630ffa7f1a65ad98780481f14757004498e9060200160405180910390a261442f565b600091505b505b82156144ee57600b8201546001600160401b03161580156144555750600a82015415155b1561447757600a8201546144699084615c7f565b6000600a84015592506144e1565b600b8201546001600160401b0316156144e157600b820154600090633b9aca00906144ab906001600160401b031686615dea565b6144b59190615cc2565b90506144c18185615e38565b9350808360070160030160008282546144da9190615c7f565b9091555050505b6144eb8382615c7f565b90505b60088201554260079091015550565b60008181526005602052604090205460ff16156145415760405162461bcd60e51b8152602060048201526002602482015261062760f31b6044820152606401610928565b60008181526005602052604090819020805460ff19166001179055517f0cb09dc71d57eeec2046f6854976717e4874a3cf2d6ddeddde337e5b6de6ba319061458c9083815260200190565b60405180910390a150565b6145a18282613005565b15610cb05760008281526007602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60008181526005602052604090205460ff166146415760405162461bcd60e51b8152602060048201526002602482015261313960f01b6044820152606401610928565b60008181526005602052604090819020805460ff19169055517fd05bfc2250abb0f8fd265a54c53a24359c5484af63cad2e4ce87c78ab751395a9061458c9083815260200190565b600e8101546000908190600114156146e057600f830180546000906146b0576146b0615f17565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b031690506147e2565b60006146f58585600401546141459190615e38565b90506147de8185600c0160020180548060200260200160405190810160405280929190818152602001828054801561477e57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b03168152602001906008019060208260070104928301926001038202915080841161473b5790505b50505050600f8801805460408051602080840282018101909252828152935083018282801561425457600091825260209182902080546001600160401b031684529082028301929091600891018084116142115790505050505050614ca3565b9150505b6010830154633b9aca009061428790600160801b90046001600160401b031683615e09565b600654610100900460ff1680614820575060065460ff16155b6148835760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610928565b600654610100900460ff161580156148a5576006805461ffff19166101011790555b6148ad614fec565b8015613fda576006805461ff001916905550565b610cb08282613f36565b600082815260076020526040902060010154819060405184907fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff90600090a460009182526007602052604090912060010155565b6060600061492e836002615dea565b614939906002615c7f565b6001600160401b0381111561495057614950615f2d565b6040519080825280601f01601f19166020018201604052801561497a576020820181803683370190505b509050600360fc1b8160008151811061499557614995615f17565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106149c4576149c4615f17565b60200101906001600160f81b031916908160001a90535060006149e8846002615dea565b6149f3906001615c7f565b90505b6001811115614a78577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110614a3457614a34615f17565b1a60f81b828281518110614a4a57614a4a615f17565b60200101906001600160f81b031916908160001a90535060049490941c93614a7181615ea3565b90506149f6565b508315614ac75760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610928565b9392505050565b6000614b23826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661509d9092919063ffffffff16565b805190915015611c515780806020019051810190614b41919061555a565b611c515760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610928565b6000808260020160009054906101000a90046001600160a01b03166001600160a01b031663b8f368956040518163ffffffff1660e01b815260040160206040518083038186803b158015614c0657600080fd5b505afa158015614c1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c3e91906156b3565b6010840154909150633b9aca0090614c609086906001600160401b0316615dea565b614c6a9190615cc2565b935080841115614c945783614c83633b9aca0083615dea565b614c8d9190615cc2565b9150614c9c565b633b9aca0091505b5092915050565b60008260018451614cb49190615e38565b81518110614cc457614cc4615f17565b60200260200101516001600160401b0316846001600160401b031610614d12578160018451614cf39190615e38565b81518110614d0357614d03615f17565b60200260200101519050614ac7565b82600081518110614d2557614d25615f17565b60200260200101516001600160401b0316846001600160401b031611614d585781600081518110614d0357614d03615f17565b60008060018551614d699190615e38565b905060005b6001614d7a8484615e38565b1115614de4576002614d8c8484615e38565b614d969190615cc2565b614da09084615c7f565b9050866001600160401b0316868281518110614dbe57614dbe615f17565b60200260200101516001600160401b031611614ddc57809250614d6e565b809150614d6e565b848381518110614df657614df6615f17565b60200260200101516001600160401b0316858381518110614e1957614e19615f17565b60200260200101516001600160401b03161115614f1357858381518110614e4257614e42615f17565b6020026020010151868381518110614e5c57614e5c615f17565b6020026020010151614e6e9190615e4f565b868481518110614e8057614e80615f17565b602002602001015188614e939190615e4f565b868581518110614ea557614ea5615f17565b6020026020010151878581518110614ebf57614ebf615f17565b6020026020010151614ed19190615e4f565b614edb9190615e09565b614ee59190615cd6565b858481518110614ef757614ef7615f17565b6020026020010151614f099190615c97565b9350505050614ac7565b858381518110614f2557614f25615f17565b6020026020010151868381518110614f3f57614f3f615f17565b6020026020010151614f519190615e4f565b868481518110614f6357614f63615f17565b602002602001015188614f769190615e4f565b868481518110614f8857614f88615f17565b6020026020010151878681518110614fa257614fa2615f17565b6020026020010151614fb49190615e4f565b614fbe9190615e09565b614fc89190615cd6565b858481518110614fda57614fda615f17565b6020026020010151614f099190615e4f565b600654610100900460ff1680615005575060065460ff16155b6150685760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610928565b600654610100900460ff161580156148ad576006805461ffff19166101011790558015613fda576006805461ff001916905550565b606061429a848460008585843b6150f65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610928565b600080866001600160a01b0316858760405161511291906159d4565b60006040518083038185875af1925050503d806000811461514f576040519150601f19603f3d011682016040523d82523d6000602084013e615154565b606091505b509150915061516482828661516f565b979650505050505050565b6060831561517e575081614ac7565b82511561518e5782518084602001fd5b8160405162461bcd60e51b81526004016109289190615bf9565b508054600082556003016004900490600052602060002090810190613fda9190615285565b828054828255906000526020600020906003016004900481019282156152755791602002820160005b8382111561524057835183826101000a8154816001600160401b0302191690836001600160401b0316021790555092602001926008016020816007010492830192600103026151f6565b80156152735782816101000a8154906001600160401b030219169055600801602081600701049283019260010302615240565b505b50615281929150615285565b5090565b5b808211156152815760008155600101615286565b80356152a581615f43565b919050565b600082601f8301126152bb57600080fd5b813560206152d06152cb83615c5c565b615c2c565b80838252828201915082860187848660051b89010111156152f057600080fd5b60005b858110156153165761530482615323565b845292840192908401906001016152f3565b5090979650505050505050565b80356001600160401b03811681146152a557600080fd5b60006020828403121561534c57600080fd5b8135614ac781615f43565b60006020828403121561536957600080fd5b8151614ac781615f43565b6000806040838503121561538757600080fd5b823561539281615f43565b915060208301356153a281615f43565b809150509250929050565b6000806000606084860312156153c257600080fd5b83356153cd81615f43565b925060208401356153dd81615f43565b915060408401356153ed81615f43565b809150509250925092565b6000602080838503121561540b57600080fd5b82516001600160401b0381111561542157600080fd5b8301601f8101851361543257600080fd5b80516154406152cb82615c5c565b80828252848201915084840188868560051b870101111561546057600080fd5b600094505b8385101561548c57805161547881615f43565b835260019490940193918501918501615465565b50979650505050505050565b6000806000606084860312156154ad57600080fd5b83356001600160401b038111156154c357600080fd5b8401601f810186136154d457600080fd5b803560206154e46152cb83615c5c565b8083825282820191508285018a848660051b880101111561550457600080fd5b600095505b8486101561553057803561551c81615f43565b835260019590950194918301918301615509565b509650615540905087820161529a565b94505050506155516040850161529a565b90509250925092565b60006020828403121561556c57600080fd5b81518015158114614ac757600080fd5b60006020828403121561558e57600080fd5b5035919050565b600080604083850312156155a857600080fd5b8235915060208301356153a281615f43565b600080600080608085870312156155d057600080fd5b84356155db81615f43565b935060208501356001600160401b03808211156155f757600080fd5b615603888389016152aa565b9450604087013591508082111561561957600080fd5b50615626878288016152aa565b925050606085013561563781615f58565b939692955090935050565b600080600080600060a0868803121561565a57600080fd5b853561566581615f43565b9450602086013561567581615f43565b9350604086013561568581615f43565b9250606086013561569581615f43565b915060808601356156a581615f43565b809150509295509295909350565b6000602082840312156156c557600080fd5b5051919050565b600080600080608085870312156156e257600080fd5b8435935060208501356156f481615f43565b9250604085013561570481615f43565b9150606085013561563781615f43565b600080600080600060a0868803121561572c57600080fd5b85359450602086013561573e81615f43565b9350604086013561574e81615f43565b9250606086013561575e81615f43565b949793965091946080013592915050565b60008060006060848603121561578457600080fd5b8335925060208401356153dd81615f43565b600080600080608085870312156157ac57600080fd5b8435935060208501356157be81615f43565b925060408501356157ce81615f43565b9396929550929360600135925050565b6000806000606084860312156157f357600080fd5b833592506020840135915060408401356153ed81615f43565b60006020828403121561581e57600080fd5b614ac782615323565b60008060006060848603121561583c57600080fd5b61584584615323565b92506153dd60208501615323565b6000806000806080858703121561586957600080fd5b61587285615323565b935061588060208601615323565b925061588e60408601615323565b915061589c60608601615323565b905092959194509250565b6000602082840312156158b957600080fd5b8151614ac781615f58565b600081518084526020808501945080840160005b838110156158fd5781516001600160401b0316875295820195908201906001016158d8565b509495945050505050565b6000610100825181855261591e828601826158c4565b9150506020830151848203602086015261593882826158c4565b9150506040830151848203604086015261595282826158c4565b9150506060830151848203606086015261596c82826158c4565b915050608083015161598960808601826001600160401b03169052565b5060a08301516159a460a08601826001600160401b03169052565b5060c08301516159bf60c08601826001600160401b03169052565b5060e083015160e08501528091505092915050565b600082516159e6818460208701615e77565b9190910192915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615a28816017850160208801615e77565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351615a65816028840160208801615e77565b01602801949350505050565b60a0808252865190820181905260009060209060c0840190828a01845b82811015615ab35781516001600160a01b031684529284019290840190600101615a8e565b5050506001600160a01b03978816918401919091529486166040830152509184166060830152909216608090920191909152919050565b606081526000615afd60608301866158c4565b8281036020840152615b0f81866158c4565b91505060ff83166040830152949350505050565b60006102006001600160a01b03808d168452808c166020850152808b166040850152808a166060850152508760808401528660a08401528560c0840152845160e084015260208501516101008401526040850151610120840152606085015161014084015260808501516001600160401b038082166101608601528060a0880151166101808601528060c0880151166101a0860152505060e0850151615bd56101c08501826001600160401b03169052565b50806101e0840152615be981840185615908565b9c9b505050505050505050505050565b6020815260008251806020840152615c18816040850160208701615e77565b601f01601f19169190910160400192915050565b604051601f8201601f191681016001600160401b0381118282101715615c5457615c54615f2d565b604052919050565b60006001600160401b03821115615c7557615c75615f2d565b5060051b60200190565b60008219821115615c9257615c92615ed5565b500190565b60006001600160401b03808316818516808303821115615cb957615cb9615ed5565b01949350505050565b600082615cd157615cd1615eeb565b500490565b60006001600160401b0380841680615cf057615cf0615eeb565b92169190910492915050565b600181815b80851115615d37578160001904821115615d1d57615d1d615ed5565b80851615615d2a57918102915b93841c9390800290615d01565b509250929050565b6000614ac760ff841683600082615d585750600161302c565b81615d655750600061302c565b8160018114615d7b5760028114615d8557615da1565b600191505061302c565b60ff841115615d9657615d96615ed5565b50506001821b61302c565b5060208310610133831016604e8410600b8410161715615dc4575081810a61302c565b615dce8383615cfc565b8060001904821115615de257615de2615ed5565b029392505050565b6000816000190483118215151615615e0457615e04615ed5565b500290565b60006001600160401b0380831681851681830481118215151615615e2f57615e2f615ed5565b02949350505050565b600082821015615e4a57615e4a615ed5565b500390565b60006001600160401b0383811690831681811015615e6f57615e6f615ed5565b039392505050565b60005b83811015615e92578181015183820152602001615e7a565b83811115611bb85750506000910152565b600081615eb257615eb2615ed5565b506000190190565b6000600019821415615ece57615ece615ed5565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114613fda57600080fd5b60ff81168114613fda57600080fdfe502d3d275257923b2bea6ea25d9631f12369fb532871f13eb85eb09dc0fb484255435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041a2646970667358221220fc0954c09bd004c0cf6f4c5b7926ec39df1969875ddca840ece9b5a7217e371c64736f6c63430008070033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102ff5760003560e01c80635c38eb3a1161019c578063ba8b7223116100ee578063d547741f11610097578063ee565a6311610071578063ee565a63146106b2578063eecdac88146106dd578063f36246d1146106f057600080fd5b8063d547741f1461067d578063df1b8bd314610690578063ec5b1bee1461069f57600080fd5b8063cbb3edd2116100c8578063cbb3edd21461063b578063ccc574901461064e578063cd377c531461067557600080fd5b8063ba8b7223146105ed578063be8c31ff14610615578063c4d66de81461062857600080fd5b806391d14854116101505780639f48118f1161012a5780639f48118f146105c7578063a217fddf146105d2578063af648c3d146105da57600080fd5b806391d148541461056e5780639af2dcae146105915780639e9e4666146105a457600080fd5b806380009630116101815780638000963014610535578063892cfc161461054857806391a9ca481461055b57600080fd5b80635c38eb3a1461050f5780636d1042161461052257600080fd5b8063252c94061161025557806336568abe1161020957806359de6866116101e357806359de6866146104d65780635a3c10f1146104e95780635b749f35146104fc57600080fd5b806336568abe146104895780633c4a25d01461049c57806354d9f653146104af57600080fd5b80632f2ff15d1161023a5780632f2ff15d1461043657806333c509d114610449578063344844db1461045c57600080fd5b8063252c9406146104105780632e2d29841461042357600080fd5b806322ac5c9a116102b757806324ea54f41161029157806324ea54f4146103c15780632509f1b9146103d6578063251ad873146103fd57600080fd5b806322ac5c9a1461036557806323e103a814610378578063248a9ca31461038b57600080fd5b8063074efa78116102e8578063074efa781461032c578063087264c91461033f5780631a115ff11461035257600080fd5b8063050f53fe14610304578063074ee44614610319575b600080fd5b610317610312366004615498565b610705565b005b610317610327366004615796565b6107e1565b61031761033a3660046153ad565b610a85565b61031761034d36600461557c565b610c5f565b610317610360366004615595565b610cb4565b610317610373366004615642565b610dce565b6103176103863660046156cc565b6116f7565b6103ae61039936600461557c565b60009081526007602052604090206001015490565b6040519081526020015b60405180910390f35b6103ae600080516020615f8883398151915281565b6103ae7fe0136b3661826a483734248681e4f59ae66bc6065ceb43fdd469ecb22c21d74581565b61031761040b366004615595565b6118ba565b61031761041e36600461557c565b6119b5565b61031761043136600461576f565b611bbe565b610317610444366004615595565b611c2b565b610317610457366004615374565b611c56565b336000908152600260209081526040808320546001600160a01b03168352908290529020600401546103ae565b610317610497366004615595565b611d42565b6103176104aa36600461533a565b611d89565b6103ae7ffb286912c6eadba541f23a3bb3e83373ab139b6e65d84e2a473c186efc2b464281565b6103176104e4366004615595565b611e7f565b6103176104f73660046157de565b611f05565b61031761050a36600461580c565b611fd0565b61031761051d366004615374565b612025565b610317610530366004615714565b612250565b61031761054336600461533a565b612596565b610317610556366004615374565b61260f565b610317610569366004615853565b612f29565b61058161057c366004615595565b613005565b60405190151581526020016103b8565b61031761059f36600461576f565b613032565b6105816105b236600461557c565b60056020526000908152604090205460ff1681565b6103ae633b9aca0081565b6103ae600081565b6103176105e836600461533a565b61318d565b6106006105fb36600461533a565b613259565b6040516103b899989796959493929190615b23565b6103176106233660046155ba565b613586565b61031761063636600461533a565b613809565b610317610649366004615595565b6139a9565b6103ae7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6103ae613a14565b61031761068b366004615595565b613c4a565b6103ae670de0b6b3a764000081565b6103176106ad366004615827565b613c70565b6001546106c5906001600160a01b031681565b6040516001600160a01b0390911681526020016103b8565b6103176106eb36600461533a565b613ddc565b6103ae600080516020615f6883398151915281565b600080516020615f6883398151915261071e8133613ed2565b60005b84518110156107a35761076d7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5586838151811061076057610760615f17565b6020026020010151613f36565b610791600080516020615f8883398151915286838151811061076057610760615f17565b8061079b81615eba565b915050610721565b506107bc600080516020615f8883398151915284613f36565b50600180546001600160a01b0319166001600160a01b03929092169190911790555050565b6001600160a01b038216600090815260208190526040902061080281613f9f565b61082c7ffb286912c6eadba541f23a3bb3e83373ab139b6e65d84e2a473c186efc2b464284613fdd565b8054610843906001600160a01b031633858861406a565b6003810154604051633593ba7b60e01b8152600481018790526000916001600160a01b031690633593ba7b9060240160206040518083038186803b15801561088a57600080fd5b505afa15801561089e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c291906156b3565b905060006108d082846140d9565b9050633b9aca006108e18282615e38565b6108eb9084615dea565b6108f59190615cc2565b9150838210156109315760405162461bcd60e51b8152602060048201526002602482015261313560f01b60448201526064015b60405180910390fd5b818360040160008282546109459190615c7f565b90915550506011830154600484015411156109875760405162461bcd60e51b8152602060048201526002602482015261189b60f11b6044820152606401610928565b60408051888152602081018490526001600160a01b038716917ff0543d9ab673fd2b6789938fb372d27b43b955c1a90eb8a982bc4aa50687962c910160405180910390a2610a166109dd6002633b9aca00615d3f565b600b850154600160401b90046001600160401b03166109fc848b615dea565b610a069190615dea565b610a109190615cc2565b846142a2565b6001546040516340c10f1960e01b81526001600160a01b03888116600483015260248201859052909116906340c10f1990604401600060405180830381600087803b158015610a6457600080fd5b505af1158015610a78573d6000803e3d6000fd5b5050505050505050505050565b600080516020615f88833981519152610a9e8133613ed2565b836001600160a01b038116610ad95760405162461bcd60e51b81526020600482015260016024820152600360fc1b6044820152606401610928565b6001600160a01b0383166000908152602081905260409020610afa81613f9f565b6001600160a01b03858116600090815260026020526040902054811690851614610b4b5760405162461bcd60e51b8152602060048201526002602482015261031360f41b6044820152606401610928565b846001600160a01b0316866001600160a01b03161415610b925760405162461bcd60e51b81526020600482015260026024820152610c4d60f21b6044820152606401610928565b6001600160a01b0380861660009081526002602052604080822080546001600160a01b03199081169091558984168084528284208054958a1695909216851790915590519092917fe139a19f7890c89603e0d013fb99aed7d286ef55ef5a092ddd2980a3afd2138d91a360405163472d35b960e01b81526001600160a01b03878116600483015285169063472d35b990602401600060405180830381600087803b158015610c3f57600080fd5b505af1158015610c53573d6000803e3d6000fd5b50505050505050505050565b336000908152602081905260409020610c7781613f9f565b600b810154610cb090633b9aca0090610ca090600160c01b90046001600160401b031685615dea565b610caa9190615cc2565b826142a2565b5050565b336000908152600260209081526040808320546001600160a01b031680845291839052909120610ce381613f9f565b610d0d7fe0136b3661826a483734248681e4f59ae66bc6065ceb43fdd469ecb22c21d74583613fdd565b610d186000826142a2565b600181015460058201546001600160a01b03909116906340c10f19908590610d48670de0b6b3a764000089615dea565b610d529190615cc2565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015610db057600080fd5b505af1158015610dc4573d6000803e3d6000fd5b5050505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610df98133613ed2565b306001600160a01b0316826001600160a01b0316636ac5dc466040518163ffffffff1660e01b815260040160206040518083038186803b158015610e3c57600080fd5b505afa158015610e50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e749190615357565b6001600160a01b0316148015610f0b5750856001600160a01b0316826001600160a01b031663dc4c90d36040518163ffffffff1660e01b815260040160206040518083038186803b158015610ec857600080fd5b505afa158015610edc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f009190615357565b6001600160a01b0316145b8015610f985750306001600160a01b0316866001600160a01b0316636ac5dc466040518163ffffffff1660e01b815260040160206040518083038186803b158015610f5557600080fd5b505afa158015610f69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8d9190615357565b6001600160a01b0316145b80156110255750856001600160a01b0316856001600160a01b031663dc4c90d36040518163ffffffff1660e01b815260040160206040518083038186803b158015610fe257600080fd5b505afa158015610ff6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061101a9190615357565b6001600160a01b0316145b80156110b25750306001600160a01b0316846001600160a01b0316636ac5dc466040518163ffffffff1660e01b815260040160206040518083038186803b15801561106f57600080fd5b505afa158015611083573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a79190615357565b6001600160a01b0316145b6110e25760405162461bcd60e51b81526020600482015260016024820152603960f81b6044820152606401610928565b6000866001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561111d57600080fd5b505afa158015611131573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111559190615357565b90506000816001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561119257600080fd5b505afa1580156111a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ca91906158a7565b6111d590600a615d3f565b905080856001600160a01b0316639aefb5c36040518163ffffffff1660e01b815260040160206040518083038186803b15801561121157600080fd5b505afa158015611225573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124991906156b3565b1461127b5760405162461bcd60e51b8152602060048201526002602482015261313160f01b6044820152606401610928565b6001600160a01b0380891660009081526020819052604090208054909116156112cb5760405162461bcd60e51b8152602060048201526002602482015261313360f01b6044820152606401610928565b828160000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550848160010160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550878160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550858160030160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550670de0b6b3a7640000816005018190555081816006018190555088600260008a6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508860026000896001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055506003899080600181540180825580915050600190039060005260206000200160009091909190916101000a8154816001600160a01b0302191690836001600160a01b031602179055506114d27fe0136b3661826a483734248681e4f59ae66bc6065ceb43fdd469ecb22c21d7458a6040516020016114b792919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b604051602081830303815290604052805190602001206144fd565b6115237ffb286912c6eadba541f23a3bb3e83373ab139b6e65d84e2a473c186efc2b46428a6040516020016114b792919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b6000600460009054906101000a90046001600160a01b03166001600160a01b031663a6d7fe2d6040518163ffffffff1660e01b815260040160006040518083038186803b15801561157357600080fd5b505afa158015611587573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115af91908101906153f8565b90506000600460009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561160157600080fd5b505afa158015611615573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116399190615357565b604051636cb2e74d60e11b81529091506001600160a01b038c169063d965ce9a9061167090859085908f908f908f90600401615a71565b600060405180830381600087803b15801561168a57600080fd5b505af115801561169e573d6000803e3d6000fd5b50506040516001600160a01b038b81168252808b1693508d811692508e16907f129e7033df7c6cf5b088a92e04f596efded950692229dda217a8054d40bb02929060200160405180910390a45050505050505050505050565b6001600160a01b038116600090815260208190526040902061171881613f9f565b6117427fe0136b3661826a483734248681e4f59ae66bc6065ceb43fdd469ecb22c21d74583613fdd565b61174d6000826142a2565b6001600160a01b0384163314156117cb5760018101546040516315a38ec760e11b8152600481018790526001600160a01b03868116602483015290911690632b471d8e90604401600060405180830381600087803b1580156117ae57600080fd5b505af11580156117c2573d6000803e3d6000fd5b5050505061183a565b6001810154604051630d43af8160e21b8152600481018790526001600160a01b0386811660248301523360448301529091169063350ebe0490606401600060405180830381600087803b15801561182157600080fd5b505af1158015611835573d6000803e3d6000fd5b505050505b6000611852633b9aca00670de0b6b3a7640000615dea565b6005830154600b84015461187a90600160801b90046001600160401b0316633b9aca00615e38565b6118849089615dea565b61188e9190615dea565b6118989190615cc2565b82549091506118b2906001600160a01b031684868461406a565b505050505050565b6001546001600160a01b031633146118f85760405162461bcd60e51b81526020600482015260016024820152603360f81b6044820152606401610928565b6001600160a01b038116600090815260208190526040902061191981613f9f565b82816004015410156119515760405162461bcd60e51b81526020600482015260016024820152600d60fa1b6044820152606401610928565b828160040160008282546119659190615e38565b9091555050805460048201546040519081526001600160a01b03909116907f72e0daee492d85727eb3f32c69303a6dd57af5bd2b127a04641de5d70e1494de9060200160405180910390a2505050565b3360008181526020819052604090206119cd81613f9f565b6001810154604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b158015611a1457600080fd5b505afa158015611a28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4c91906156b3565b90508015611bb857611a66670de0b6b3a764000085615dea565b6008830154611a7e90670de0b6b3a764000090615dea565b828460050154611a8e9190615dea565b611a989190615c7f565b1115611b11576008820154848110611aad5750835b80836007016001016000828254611ac49190615e38565b90915550829050670de0b6b3a7640000611ade8388615e38565b611ae89190615dea565b611af29190615cc2565b836005016000828254611b059190615e38565b90915550611b71915050565b6001600583015560006008830155604051611b71906114b7907fe0136b3661826a483734248681e4f59ae66bc6065ceb43fdd469ecb22c21d74590869060200191825260601b6bffffffffffffffffffffffff1916602082015260340190565b815460058301546040519081526001600160a01b03909116907faa959327c96abe1dbec8186dbe4bb630ffa7f1a65ad98780481f14757004498e9060200160405180910390a25b50505050565b6001600160a01b0381166000908152602081905260409020611bdf81613f9f565b611c097fe0136b3661826a483734248681e4f59ae66bc6065ceb43fdd469ecb22c21d74583613fdd565b611c146000826142a2565b8054610d18906001600160a01b031633848761406a565b600082815260076020526040902060010154611c478133613ed2565b611c518383613f36565b505050565b600080516020615f68833981519152611c6f8133613ed2565b611c87600080516020615f8883398151915283614597565b611c9f600080516020615f8883398151915284613f36565b60005b600354811015611bb85760038181548110611cbf57611cbf615f17565b6000918252602090912001546040516333c509d160e01b81526001600160a01b0386811660048301528581166024830152909116906333c509d190604401600060405180830381600087803b158015611d1757600080fd5b505af1158015611d2b573d6000803e3d6000fd5b505050508080611d3a90615eba565b915050611ca2565b6001600160a01b0381163314611d7f5760405162461bcd60e51b8152602060048201526002602482015261373160f01b6044820152606401610928565b610cb08282614597565b600080516020615f68833981519152611da28133613ed2565b611dcc7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5583613f36565b611de4600080516020615f8883398151915283613f36565b60005b600354811015611c515760038181548110611e0457611e04615f17565b6000918252602090912001546040516303c4a25d60e41b81526001600160a01b03858116600483015290911690633c4a25d090602401600060405180830381600087803b158015611e5457600080fd5b505af1158015611e68573d6000803e3d6000fd5b505050508080611e7790615eba565b915050611de7565b600080516020615f88833981519152611e988133613ed2565b6001600160a01b0382166000908152602081905260409020611eb981613f9f565b611bb88484604051602001611eea92919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b604051602081830303815290604052805190602001206145fe565b600080516020615f88833981519152611f1e8133613ed2565b6001600160a01b0382166000908152602081905260409020611f3f81613f9f565b8060040154851015611f775760405162461bcd60e51b81526020600482015260016024820152600760fb1b6044820152606401610928565b601181018590556009810184905560408051868152602081018690526001600160a01b038516917faa2226ff9a1d81d234d2d96d4a86cc03d1b9165cda2f2591c1df913002201f22910160405180910390a25050505050565b336000908152600260209081526040808320546001600160a01b031680845291839052909120611fff81613f9f565b601001805467ffffffffffffffff19166001600160401b03939093169290921790915550565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556120508133613ed2565b826001600160a01b03811661208b5760405162461bcd60e51b81526020600482015260016024820152600360fc1b6044820152606401610928565b6001600160a01b03831660009081526020819052604090206120ac81613f9f565b60038101546001600160a01b03868116911614156120f15760405162461bcd60e51b8152602060048201526002602482015261189960f11b6044820152606401610928565b846001600160a01b0316639aefb5c36040518163ffffffff1660e01b815260040160206040518083038186803b15801561212a57600080fd5b505afa15801561213e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216291906156b3565b8160060154146121995760405162461bcd60e51b8152602060048201526002602482015261313160f01b6044820152606401610928565b6003810180546001600160a01b0319166001600160a01b0387811691821790925560405190918616907f078c3b417dadf69374a59793b829c52001247130433427049317bde56607b1b790600090a36002810154604051637adbf97360e01b81526001600160a01b03878116600483015290911690637adbf97390602401600060405180830381600087803b15801561223157600080fd5b505af1158015612245573d6000803e3d6000fd5b505050505050505050565b6001600160a01b038216600090815260208190526040902061227181613f9f565b61229b7ffb286912c6eadba541f23a3bb3e83373ab139b6e65d84e2a473c186efc2b464284613fdd565b80600401548611156122d45760405162461bcd60e51b8152602060048201526002602482015261313760f01b6044820152606401610928565b6001600160a01b038516331415612350576001546040516315a38ec760e11b8152600481018890526001600160a01b03878116602483015290911690632b471d8e90604401600060405180830381600087803b15801561233357600080fd5b505af1158015612347573d6000803e3d6000fd5b505050506123bd565b600154604051630d43af8160e21b8152600481018890526001600160a01b0387811660248301523360448301529091169063350ebe0490606401600060405180830381600087803b1580156123a457600080fd5b505af11580156123b8573d6000803e3d6000fd5b505050505b60038101546040805163442133bd60e01b815290516000926001600160a01b03169163442133bd916004808301926020929190829003018186803b15801561240457600080fd5b505afa158015612418573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243c91906156b3565b90506000818360060154896124519190615dea565b61245b9190615cc2565b9050600061246d633b9aca0084615dea565b846006015461247c8b87614689565b61248a90633b9aca00615e38565b612494908c615dea565b61249e9190615dea565b6124a89190615cc2565b9050848110156124df5760405162461bcd60e51b8152602060048201526002602482015261313560f01b6044820152606401610928565b888460040160008282546124f39190615e38565b9091555050604080518a8152602081018390526001600160a01b038816917f6acf1c7b1f88ba23f81a749aacb5bcaabf5095176f3eee66e251bbabd59544ed910160405180910390a2600b84015461257f90633b9aca0090600160401b90046001600160401b03166125658486615e38565b61256f9190615dea565b6125799190615cc2565b856142a2565b8354612245906001600160a01b031687898461406a565b600080516020615f688339815191526125af8133613ed2565b6004546125d490600080516020615f68833981519152906001600160a01b0316614597565b6125ec600080516020615f6883398151915283613f36565b50600480546001600160a01b0319166001600160a01b0392909216919091179055565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561263a8133613ed2565b60035460009060018110156126765760405162461bcd60e51b8152602060048201526002602482015261031360f41b6044820152606401610928565b60005b612684600183615e38565b81101561275457856001600160a01b0316600382815481106126a8576126a8615f17565b6000918252602090912001546001600160a01b03161415612742576001925060036126d38484615e38565b815481106126e3576126e3615f17565b600091825260209091200154600380546001600160a01b03909216918390811061270f5761270f615f17565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550612754565b8061274c81615eba565b915050612679565b50816001148061279d57506001600160a01b0385166003612776600184615e38565b8154811061278657612786615f17565b6000918252602090912001546001600160a01b0316145b6127ce5760405162461bcd60e51b8152602060048201526002602482015261031360f41b6044820152606401610928565b60038054806127df576127df615f01565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0387811683528282526040808420815161012080820184528254851682526001830154851682870152600283015485168285015260038301549094166060808301919091526004830154608080840191909152600584015460a080850191909152600685015460c08086019190915286516101008181018952600788015482526008880154828c01526009880154828a0152600a88015495820195909552600b8701546001600160401b0380821695830195909552600160401b8104851693820193909352600160801b8304841691810191909152600160c01b90910490911660e0828101919091528301528351600c840180549788028201870190955280820187815292969395918701949093909284929091849184018282801561298357602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116129405790505b5050505050815260200160018201805480602002602001604051908101604052809291908181526020018280548015612a0d57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116129ca5790505b5050505050815260200160028201805480602002602001604051908101604052809291908181526020018280548015612a9757602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411612a545790505b5050505050815260200160038201805480602002602001604051908101604052809291908181526020018280548015612b2157602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411612ade5790505b50505091835250506004828101546001600160401b03808216602080860191909152600160401b83048216604080870191909152600160801b909304909116606085015260059094015460809093019290925292909352825163d0fb020360e01b81529251949550600294600094506001600160a01b038c169363d0fb020393818101939291829003018186803b158015612bbb57600080fd5b505afa158015612bcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf39190615357565b6001600160a01b0390811682526020808301939093526040918201600090812080546001600160a01b031990811690915585840151831682526002808652848320805483169055928b1682529381905291822080548416815560018101805485169055908101805484169055600381018054909316909255600482018190556005820181905560068201819055600782018190556008820181905560098201819055600a8201819055600b8201819055600c820181612cb282826151a8565b612cc06001830160006151a8565b612cce6002830160006151a8565b612cdc6003830160006151a8565b506004810180547fffffffffffffffff000000000000000000000000000000000000000000000000169055600060059091018190556040516001600160a01b038a1693507f10d8ed8cba916885e339cb21deefb3842b3f417eac81a7f34b2978b4ecc2040f9250a280604001516001600160a01b0316638456cb596040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612d8357600080fd5b505af1158015612d97573d6000803e3d6000fd5b505082516040516370a0823160e01b81526001600160a01b038a811660048301526000945090911691506370a082319060240160206040518083038186803b158015612de257600080fd5b505afa158015612df6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e1a91906156b3565b8251909150612e34906001600160a01b031688888461406a565b600082606001516001600160a01b03166392611e336040518163ffffffff1660e01b815260040160206040518083038186803b158015612e7357600080fd5b505afa158015612e87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eab91906156b3565b60a08401516080850151604051630462bc3f60e51b815260048101849052602481019290925260448201529091506001600160a01b03881690638c5787e090606401600060405180830381600087803b158015612f0757600080fd5b505af1158015612f1b573d6000803e3d6000fd5b505050505050505050505050565b336000908152600260209081526040808320546001600160a01b03168352908290529020612f5681613f9f565b6010810180547fffffffffffffffff00000000000000000000000000000000ffffffffffffffff16600160401b6001600160401b03978816027fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff1617600160801b9587168602179055600b0180547fffffffffffffffff0000000000000000ffffffffffffffff00000000000000001692851690930267ffffffffffffffff1916919091179216919091179055565b60008281526007602090815260408083206001600160a01b038516845290915290205460ff165b92915050565b600080516020615f8883398151915261304b8133613ed2565b6001600160a01b038084166000908152602081905260408082209285168252902061307582613f9f565b61307e81613f9f565b60118201546004830154613093908890615c7f565b11156130c55760405162461bcd60e51b81526020600482015260016024820152600760fb1b6044820152606401610928565b858160040160008282546130d99190615e38565b92505081905550858260040160008282546130f49190615c7f565b9091555050815460048301546040519081526001600160a01b03909116907f72e0daee492d85727eb3f32c69303a6dd57af5bd2b127a04641de5d70e1494de9060200160405180910390a2805460048201546040519081526001600160a01b03909116907f72e0daee492d85727eb3f32c69303a6dd57af5bd2b127a04641de5d70e1494de9060200160405180910390a2505050505050565b600080516020615f688339815191526131a68133613ed2565b6131be600080516020615f8883398151915283614597565b60005b600354811015611c5157600381815481106131de576131de615f17565b60009182526020909120015460405163af648c3d60e01b81526001600160a01b0385811660048301529091169063af648c3d90602401600060405180830381600087803b15801561322e57600080fd5b505af1158015613242573d6000803e3d6000fd5b50505050808061325190615eba565b9150506131c1565b60006020818152918152604090819020805460018201546002830154600384015460048501546005860154600687015488516101008082018b5260078a0154825260088a0154828d015260098a0154828c0152600a8a01546060830152600b8a01546001600160401b038082166080850152600160401b8204811660a0850152600160801b8204811660c0850152600160c01b9091041660e08301528a51600c8b0180549d8e028201610120908101909d529181018d81526001600160a01b039a8b169d998b169c988b169b9a909716999598949793969295949093919284929091849184018282801561339e57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b03168152602001906008019060208260070104928301926001038202915080841161335b5790505b505050505081526020016001820180548060200260200160405190810160405280929190818152602001828054801561342857602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116133e55790505b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156134b257602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b03168152602001906008019060208260070104928301926001038202915080841161346f5790505b505050505081526020016003820180548060200260200160405190810160405280929190818152602001828054801561353c57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116134f95790505b505050918352505060048201546001600160401b038082166020840152600160401b820481166040840152600160801b909104166060820152600590910154608090910152905089565b600080516020615f8883398151915261359f8133613ed2565b8383805182511480156135b3575060008251115b6135e35760405162461bcd60e51b81526020600482015260016024820152603560f81b6044820152606401610928565b60005b600182516135f49190615e38565b811161373157633b9aca006001600160401b031682828151811061361a5761361a615f17565b60200260200101516001600160401b0316111580156136685750633b9aca006001600160401b031683828151811061365457613654615f17565b60200260200101516001600160401b031611155b6136985760405162461bcd60e51b81526020600482015260016024820152601b60f91b6044820152606401610928565b801561371f57826136aa600183615e38565b815181106136ba576136ba615f17565b60200260200101516001600160401b03168382815181106136dd576136dd615f17565b60200260200101516001600160401b03161161371f5760405162461bcd60e51b81526020600482015260016024820152603760f81b6044820152606401610928565b8061372981615eba565b9150506135e6565b506001600160a01b038716600090815260208190526040902061375381613f9f565b60ff85161561378d57865161377190600c83019060208a01906151cd565b50855161378790600d83019060208901906151cd565b506137ba565b86516137a290600e83019060208a01906151cd565b5085516137b890600f83019060208901906151cd565b505b876001600160a01b03167f81d92f91000563c9b4868d5b791e00eb2c2e9b194b09df5608c862bda78c0b9d8888886040516137f793929190615aea565b60405180910390a25050505050505050565b806001600160a01b0381166138445760405162461bcd60e51b81526020600482015260016024820152600360fc1b6044820152606401610928565b600654610100900460ff168061385d575060065460ff16155b6138c05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610928565b600654610100900460ff161580156138e2576006805461ffff19166101011790555b6138ea614807565b600480546001600160a01b0319166001600160a01b03851617905561391d600080516020615f68833981519152846148c1565b613935600080516020615f68833981519152806148cb565b61396d7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55600080516020615f688339815191526148cb565b613993600080516020615f88833981519152600080516020615f688339815191526148cb565b8015611c51576006805461ff0019169055505050565b600080516020615f888339815191526139c28133613ed2565b6001600160a01b03821660009081526020819052604090206139e381613f9f565b611bb884846040516020016114b792919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b600080600160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015613a6557600080fd5b505afa158015613a79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a9d91906156b3565b905080613aad5760001991505090565b6000805b600354811015613c295760008060038381548110613ad157613ad1615f17565b60009182526020808320909101546001600160a01b0390811684529083019390935260409091019020600390810154815492169163240fd5ab919084908110613b1c57613b1c615f17565b6000918252602091829020015460408051632768385d60e01b815290516001600160a01b0390921692632768385d92600480840193829003018186803b158015613b6557600080fd5b505afa158015613b79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b9d91906156b3565b6040518263ffffffff1660e01b8152600401613bbb91815260200190565b60206040518083038186803b158015613bd357600080fd5b505afa158015613be7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c0b91906156b3565b613c159083615c7f565b915080613c2181615eba565b915050613ab1565b5081613c39633b9aca0083615dea565b613c439190615cc2565b9250505090565b600082815260076020526040902060010154613c668133613ed2565b611c518383614597565b600080516020615f88833981519152613c898133613ed2565b83633b9aca00816001600160401b03161115613ccb5760405162461bcd60e51b81526020600482015260016024820152600d60fa1b6044820152606401610928565b83633b9aca00816001600160401b03161115613d0d5760405162461bcd60e51b81526020600482015260016024820152600d60fa1b6044820152606401610928565b6001600160a01b0384166000908152602081905260409020613d2e81613f9f565b600b8101805477ffffffffffffffff0000000000000000ffffffffffffffff16600160401b6001600160401b038a811691820277ffffffffffffffffffffffffffffffffffffffffffffffff1692909217600160c01b928a16928302179092556040805192835260208301919091526001600160a01b038716917f1131c4b35ab7476b5e63eeda716dfe137c676f01395ab743a39ac34b099be9e2910160405180910390a250505050505050565b600080516020615f68833981519152613df58133613ed2565b613e1f7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5583614597565b613e37600080516020615f8883398151915283614597565b60005b600354811015611c515760038181548110613e5757613e57615f17565b600091825260209091200154604051631dd9b59160e31b81526001600160a01b0385811660048301529091169063eecdac8890602401600060405180830381600087803b158015613ea757600080fd5b505af1158015613ebb573d6000803e3d6000fd5b505050508080613eca90615eba565b915050613e3a565b613edc8282613005565b610cb057613ef4816001600160a01b0316601461491f565b613eff83602061491f565b604051602001613f109291906159f0565b60408051601f198184030181529082905262461bcd60e51b825261092891600401615bf9565b613f408282613005565b610cb05760008281526007602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b80546001600160a01b0316613fda5760405162461bcd60e51b81526020600482015260016024820152603360f81b6044820152606401610928565b50565b60056000838360405160200161400f92919091825260601b6bffffffffffffffffffffffff1916602082015260340190565b60408051601f198184030181529181528151602092830120835290820192909252016000205460ff1615610cb05760405162461bcd60e51b8152602060048201526002602482015261062760f31b6044820152606401610928565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b179052611bb8908590614ace565b600c81015460009081906001141561413057600d8301805460009061410057614100615f17565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b03169050614262565b600061414b8460040154866141459190615c7f565b85614bb3565b905061425e8185600c016000018054806020026020016040519081016040528092919081815260200182805480156141d457602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116141915790505b50505050600d8801805460408051602080840282018101909252828152935083018282801561425457602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116142115790505b5050505050614ca3565b9150505b6010830154633b9aca009061428790600160401b90046001600160401b031683615e09565b6001600160401b031661429a9190615cc2565b949350505050565b6008810154600782015442148015906142bb5750600081115b15614431576001820154604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b15801561430757600080fd5b505afa15801561431b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061433f91906156b3565b9050801561442a5760098301548211156143a5576009830154819061436d90670de0b6b3a764000090615dea565b6143779190615cc2565b83600501600082825461438a9190615c7f565b9091555050600983015461439e9083615e38565b91506143df565b806143b8670de0b6b3a764000084615dea565b6143c29190615cc2565b8360050160008282546143d59190615c7f565b9091555060009250505b825460058401546040519081526001600160a01b03909116907faa959327c96abe1dbec8186dbe4bb630ffa7f1a65ad98780481f14757004498e9060200160405180910390a261442f565b600091505b505b82156144ee57600b8201546001600160401b03161580156144555750600a82015415155b1561447757600a8201546144699084615c7f565b6000600a84015592506144e1565b600b8201546001600160401b0316156144e157600b820154600090633b9aca00906144ab906001600160401b031686615dea565b6144b59190615cc2565b90506144c18185615e38565b9350808360070160030160008282546144da9190615c7f565b9091555050505b6144eb8382615c7f565b90505b60088201554260079091015550565b60008181526005602052604090205460ff16156145415760405162461bcd60e51b8152602060048201526002602482015261062760f31b6044820152606401610928565b60008181526005602052604090819020805460ff19166001179055517f0cb09dc71d57eeec2046f6854976717e4874a3cf2d6ddeddde337e5b6de6ba319061458c9083815260200190565b60405180910390a150565b6145a18282613005565b15610cb05760008281526007602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60008181526005602052604090205460ff166146415760405162461bcd60e51b8152602060048201526002602482015261313960f01b6044820152606401610928565b60008181526005602052604090819020805460ff19169055517fd05bfc2250abb0f8fd265a54c53a24359c5484af63cad2e4ce87c78ab751395a9061458c9083815260200190565b600e8101546000908190600114156146e057600f830180546000906146b0576146b0615f17565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b031690506147e2565b60006146f58585600401546141459190615e38565b90506147de8185600c0160020180548060200260200160405190810160405280929190818152602001828054801561477e57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b03168152602001906008019060208260070104928301926001038202915080841161473b5790505b50505050600f8801805460408051602080840282018101909252828152935083018282801561425457600091825260209182902080546001600160401b031684529082028301929091600891018084116142115790505050505050614ca3565b9150505b6010830154633b9aca009061428790600160801b90046001600160401b031683615e09565b600654610100900460ff1680614820575060065460ff16155b6148835760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610928565b600654610100900460ff161580156148a5576006805461ffff19166101011790555b6148ad614fec565b8015613fda576006805461ff001916905550565b610cb08282613f36565b600082815260076020526040902060010154819060405184907fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff90600090a460009182526007602052604090912060010155565b6060600061492e836002615dea565b614939906002615c7f565b6001600160401b0381111561495057614950615f2d565b6040519080825280601f01601f19166020018201604052801561497a576020820181803683370190505b509050600360fc1b8160008151811061499557614995615f17565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106149c4576149c4615f17565b60200101906001600160f81b031916908160001a90535060006149e8846002615dea565b6149f3906001615c7f565b90505b6001811115614a78577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110614a3457614a34615f17565b1a60f81b828281518110614a4a57614a4a615f17565b60200101906001600160f81b031916908160001a90535060049490941c93614a7181615ea3565b90506149f6565b508315614ac75760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610928565b9392505050565b6000614b23826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661509d9092919063ffffffff16565b805190915015611c515780806020019051810190614b41919061555a565b611c515760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610928565b6000808260020160009054906101000a90046001600160a01b03166001600160a01b031663b8f368956040518163ffffffff1660e01b815260040160206040518083038186803b158015614c0657600080fd5b505afa158015614c1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c3e91906156b3565b6010840154909150633b9aca0090614c609086906001600160401b0316615dea565b614c6a9190615cc2565b935080841115614c945783614c83633b9aca0083615dea565b614c8d9190615cc2565b9150614c9c565b633b9aca0091505b5092915050565b60008260018451614cb49190615e38565b81518110614cc457614cc4615f17565b60200260200101516001600160401b0316846001600160401b031610614d12578160018451614cf39190615e38565b81518110614d0357614d03615f17565b60200260200101519050614ac7565b82600081518110614d2557614d25615f17565b60200260200101516001600160401b0316846001600160401b031611614d585781600081518110614d0357614d03615f17565b60008060018551614d699190615e38565b905060005b6001614d7a8484615e38565b1115614de4576002614d8c8484615e38565b614d969190615cc2565b614da09084615c7f565b9050866001600160401b0316868281518110614dbe57614dbe615f17565b60200260200101516001600160401b031611614ddc57809250614d6e565b809150614d6e565b848381518110614df657614df6615f17565b60200260200101516001600160401b0316858381518110614e1957614e19615f17565b60200260200101516001600160401b03161115614f1357858381518110614e4257614e42615f17565b6020026020010151868381518110614e5c57614e5c615f17565b6020026020010151614e6e9190615e4f565b868481518110614e8057614e80615f17565b602002602001015188614e939190615e4f565b868581518110614ea557614ea5615f17565b6020026020010151878581518110614ebf57614ebf615f17565b6020026020010151614ed19190615e4f565b614edb9190615e09565b614ee59190615cd6565b858481518110614ef757614ef7615f17565b6020026020010151614f099190615c97565b9350505050614ac7565b858381518110614f2557614f25615f17565b6020026020010151868381518110614f3f57614f3f615f17565b6020026020010151614f519190615e4f565b868481518110614f6357614f63615f17565b602002602001015188614f769190615e4f565b868481518110614f8857614f88615f17565b6020026020010151878681518110614fa257614fa2615f17565b6020026020010151614fb49190615e4f565b614fbe9190615e09565b614fc89190615cd6565b858481518110614fda57614fda615f17565b6020026020010151614f099190615e4f565b600654610100900460ff1680615005575060065460ff16155b6150685760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610928565b600654610100900460ff161580156148ad576006805461ffff19166101011790558015613fda576006805461ff001916905550565b606061429a848460008585843b6150f65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610928565b600080866001600160a01b0316858760405161511291906159d4565b60006040518083038185875af1925050503d806000811461514f576040519150601f19603f3d011682016040523d82523d6000602084013e615154565b606091505b509150915061516482828661516f565b979650505050505050565b6060831561517e575081614ac7565b82511561518e5782518084602001fd5b8160405162461bcd60e51b81526004016109289190615bf9565b508054600082556003016004900490600052602060002090810190613fda9190615285565b828054828255906000526020600020906003016004900481019282156152755791602002820160005b8382111561524057835183826101000a8154816001600160401b0302191690836001600160401b0316021790555092602001926008016020816007010492830192600103026151f6565b80156152735782816101000a8154906001600160401b030219169055600801602081600701049283019260010302615240565b505b50615281929150615285565b5090565b5b808211156152815760008155600101615286565b80356152a581615f43565b919050565b600082601f8301126152bb57600080fd5b813560206152d06152cb83615c5c565b615c2c565b80838252828201915082860187848660051b89010111156152f057600080fd5b60005b858110156153165761530482615323565b845292840192908401906001016152f3565b5090979650505050505050565b80356001600160401b03811681146152a557600080fd5b60006020828403121561534c57600080fd5b8135614ac781615f43565b60006020828403121561536957600080fd5b8151614ac781615f43565b6000806040838503121561538757600080fd5b823561539281615f43565b915060208301356153a281615f43565b809150509250929050565b6000806000606084860312156153c257600080fd5b83356153cd81615f43565b925060208401356153dd81615f43565b915060408401356153ed81615f43565b809150509250925092565b6000602080838503121561540b57600080fd5b82516001600160401b0381111561542157600080fd5b8301601f8101851361543257600080fd5b80516154406152cb82615c5c565b80828252848201915084840188868560051b870101111561546057600080fd5b600094505b8385101561548c57805161547881615f43565b835260019490940193918501918501615465565b50979650505050505050565b6000806000606084860312156154ad57600080fd5b83356001600160401b038111156154c357600080fd5b8401601f810186136154d457600080fd5b803560206154e46152cb83615c5c565b8083825282820191508285018a848660051b880101111561550457600080fd5b600095505b8486101561553057803561551c81615f43565b835260019590950194918301918301615509565b509650615540905087820161529a565b94505050506155516040850161529a565b90509250925092565b60006020828403121561556c57600080fd5b81518015158114614ac757600080fd5b60006020828403121561558e57600080fd5b5035919050565b600080604083850312156155a857600080fd5b8235915060208301356153a281615f43565b600080600080608085870312156155d057600080fd5b84356155db81615f43565b935060208501356001600160401b03808211156155f757600080fd5b615603888389016152aa565b9450604087013591508082111561561957600080fd5b50615626878288016152aa565b925050606085013561563781615f58565b939692955090935050565b600080600080600060a0868803121561565a57600080fd5b853561566581615f43565b9450602086013561567581615f43565b9350604086013561568581615f43565b9250606086013561569581615f43565b915060808601356156a581615f43565b809150509295509295909350565b6000602082840312156156c557600080fd5b5051919050565b600080600080608085870312156156e257600080fd5b8435935060208501356156f481615f43565b9250604085013561570481615f43565b9150606085013561563781615f43565b600080600080600060a0868803121561572c57600080fd5b85359450602086013561573e81615f43565b9350604086013561574e81615f43565b9250606086013561575e81615f43565b949793965091946080013592915050565b60008060006060848603121561578457600080fd5b8335925060208401356153dd81615f43565b600080600080608085870312156157ac57600080fd5b8435935060208501356157be81615f43565b925060408501356157ce81615f43565b9396929550929360600135925050565b6000806000606084860312156157f357600080fd5b833592506020840135915060408401356153ed81615f43565b60006020828403121561581e57600080fd5b614ac782615323565b60008060006060848603121561583c57600080fd5b61584584615323565b92506153dd60208501615323565b6000806000806080858703121561586957600080fd5b61587285615323565b935061588060208601615323565b925061588e60408601615323565b915061589c60608601615323565b905092959194509250565b6000602082840312156158b957600080fd5b8151614ac781615f58565b600081518084526020808501945080840160005b838110156158fd5781516001600160401b0316875295820195908201906001016158d8565b509495945050505050565b6000610100825181855261591e828601826158c4565b9150506020830151848203602086015261593882826158c4565b9150506040830151848203604086015261595282826158c4565b9150506060830151848203606086015261596c82826158c4565b915050608083015161598960808601826001600160401b03169052565b5060a08301516159a460a08601826001600160401b03169052565b5060c08301516159bf60c08601826001600160401b03169052565b5060e083015160e08501528091505092915050565b600082516159e6818460208701615e77565b9190910192915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615a28816017850160208801615e77565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351615a65816028840160208801615e77565b01602801949350505050565b60a0808252865190820181905260009060209060c0840190828a01845b82811015615ab35781516001600160a01b031684529284019290840190600101615a8e565b5050506001600160a01b03978816918401919091529486166040830152509184166060830152909216608090920191909152919050565b606081526000615afd60608301866158c4565b8281036020840152615b0f81866158c4565b91505060ff83166040830152949350505050565b60006102006001600160a01b03808d168452808c166020850152808b166040850152808a166060850152508760808401528660a08401528560c0840152845160e084015260208501516101008401526040850151610120840152606085015161014084015260808501516001600160401b038082166101608601528060a0880151166101808601528060c0880151166101a0860152505060e0850151615bd56101c08501826001600160401b03169052565b50806101e0840152615be981840185615908565b9c9b505050505050505050505050565b6020815260008251806020840152615c18816040850160208701615e77565b601f01601f19169190910160400192915050565b604051601f8201601f191681016001600160401b0381118282101715615c5457615c54615f2d565b604052919050565b60006001600160401b03821115615c7557615c75615f2d565b5060051b60200190565b60008219821115615c9257615c92615ed5565b500190565b60006001600160401b03808316818516808303821115615cb957615cb9615ed5565b01949350505050565b600082615cd157615cd1615eeb565b500490565b60006001600160401b0380841680615cf057615cf0615eeb565b92169190910492915050565b600181815b80851115615d37578160001904821115615d1d57615d1d615ed5565b80851615615d2a57918102915b93841c9390800290615d01565b509250929050565b6000614ac760ff841683600082615d585750600161302c565b81615d655750600061302c565b8160018114615d7b5760028114615d8557615da1565b600191505061302c565b60ff841115615d9657615d96615ed5565b50506001821b61302c565b5060208310610133831016604e8410600b8410161715615dc4575081810a61302c565b615dce8383615cfc565b8060001904821115615de257615de2615ed5565b029392505050565b6000816000190483118215151615615e0457615e04615ed5565b500290565b60006001600160401b0380831681851681830481118215151615615e2f57615e2f615ed5565b02949350505050565b600082821015615e4a57615e4a615ed5565b500390565b60006001600160401b0383811690831681811015615e6f57615e6f615ed5565b039392505050565b60005b83811015615e92578181015183820152602001615e7a565b83811115611bb85750506000910152565b600081615eb257615eb2615ed5565b506000190190565b6000600019821415615ece57615ece615ed5565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114613fda57600080fd5b60ff81168114613fda57600080fdfe502d3d275257923b2bea6ea25d9631f12369fb532871f13eb85eb09dc0fb484255435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041a2646970667358221220fc0954c09bd004c0cf6f4c5b7926ec39df1969875ddca840ece9b5a7217e371c64736f6c63430008070033
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.