Polygon Sponsored slots available. Book your slot here!
More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Transfer Ownersh... | 19124586 | 1315 days ago | IN | 0 POL | 0.00006284 |
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
19124280 | 1315 days ago | Contract Creation | 0 POL |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Angel
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity)
/** *Submitted for verification at polygonscan.com on 2021-09-15 */ /** *Submitted for verification at polygonscan.com on 2021-09-15 */ /** *Submitted for verification at polygonscan.com on 2021-09-14 */ // File: @openzeppelin/contracts/utils/Context.sol pragma solidity >=0.6.0 <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 GSN 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 payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } // File: @openzeppelin/contracts/utils/Address.sol pragma solidity >=0.6.2 <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; // solhint-disable-next-line no-inline-assembly 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"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (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"); // solhint-disable-next-line avoid-low-level-calls (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"); // solhint-disable-next-line avoid-low-level-calls (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"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // File: @openzeppelin/contracts/math/SafeMath.sol pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } } // File: @openzeppelin/contracts/token/ERC20/IERC20.sol pragma solidity >=0.6.0 <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); } // File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol pragma solidity >=0.6.0 <0.8.0; /** * @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 SafeMath for uint256; 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' // solhint-disable-next-line max-line-length 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).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _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 // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } // File: @openzeppelin/contracts/access/Ownable.sol pragma solidity >=0.6.0 <0.8.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } // File: contracts/ERC20.sol pragma solidity >=0.6.0 <0.8.0; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) public { _name = name_; _symbol = symbol_; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual 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 {_setupDecimals} is * called. * * 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 returns (uint8) { return _decimals; } /** * @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); _approve( sender, _msgSender(), _allowances[sender][_msgSender()].sub( amount, "ERC20: transfer amount exceeds allowance" ) ); 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].add(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) { _approve( _msgSender(), spender, _allowances[_msgSender()][spender].sub( subtractedValue, "ERC20: decreased allowance below zero" ) ); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is 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); _balances[sender] = _balances[sender].sub( amount, "ERC20: transfer amount exceeds balance" ); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(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: * * - `to` 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 = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(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); // assign amount as total amount when amount is UINT_MAX if (amount == type(uint256).max) amount = _balances[account]; _balances[account] = _balances[account].sub( amount, "ERC20: burn amount exceeds balance" ); _totalSupply = _totalSupply.sub(amount); emit Transfer(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 Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal virtual { _decimals = decimals_; } /** * @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 to 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 {} } // File: @openzeppelin/contracts/drafts/EIP712.sol pragma solidity >=0.6.0 <0.8.0; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * _Available since v3.4._ */ abstract contract EIP712 { /* solhint-disable var-name-mixedcase */ // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; uint256 private immutable _CACHED_CHAIN_ID; bytes32 private immutable _HASHED_NAME; bytes32 private immutable _HASHED_VERSION; bytes32 private immutable _TYPE_HASH; /* solhint-enable var-name-mixedcase */ /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) internal { bytes32 hashedName = keccak256(bytes(name)); bytes32 hashedVersion = keccak256(bytes(version)); bytes32 typeHash = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); _HASHED_NAME = hashedName; _HASHED_VERSION = hashedVersion; _CACHED_CHAIN_ID = _getChainId(); _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion); _TYPE_HASH = typeHash; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view virtual returns (bytes32) { if (_getChainId() == _CACHED_CHAIN_ID) { return _CACHED_DOMAIN_SEPARATOR; } else { return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION); } } function _buildDomainSeparator(bytes32 typeHash, bytes32 name, bytes32 version) private view returns (bytes32) { return keccak256( abi.encode( typeHash, name, version, _getChainId(), address(this) ) ); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), structHash)); } function _getChainId() private view returns (uint256 chainId) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 // solhint-disable-next-line no-inline-assembly assembly { chainId := chainid() } } } // File: @openzeppelin/contracts/utils/Counters.sol pragma solidity >=0.6.0 <0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath} * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never * directly accessed. */ library Counters { using SafeMath for uint256; struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { // The {SafeMath} overflow check can be skipped here, see the comment at the top counter._value += 1; } function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } } // File: @openzeppelin/contracts/cryptography/ECDSA.sol pragma solidity >=0.6.0 <0.8.0; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length if (signature.length != 65) { revert("ECDSA: invalid signature length"); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return recover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover-bytes32-bytes-} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ECDSA: invalid signature 's' value"); require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value"); // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); require(signer != address(0), "ECDSA: invalid signature"); return signer; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * replicates the behavior of the * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`] * JSON-RPC method. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } } // File: @openzeppelin/contracts/drafts/IERC20Permit.sol pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over `owner`'s tokens, * given `owner`'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for `permit`, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); } // File: contracts/ERC20Permit.sol pragma solidity >=0.6.5 <0.8.0; /** * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * _Available since v3.4._ */ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 { using Counters for Counters.Counter; mapping(address => Counters.Counter) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 private immutable _PERMIT_TYPEHASH = keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ); /** * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. * * It's a good idea to use the same `name` that is defined as the ERC20 token name. */ constructor(string memory name) internal EIP712(name, "1") {} /** * @dev See {IERC20Permit-permit}. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { // solhint-disable-next-line not-rely-on-time require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); bytes32 structHash = keccak256( abi.encode( _PERMIT_TYPEHASH, owner, spender, value, _nonces[owner].current(), deadline ) ); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); require(signer == owner, "ERC20Permit: invalid signature"); _nonces[owner].increment(); _approve(owner, spender, value); } /** * @dev See {IERC20Permit-nonces}. */ function nonces(address owner) public view override returns (uint256) { return _nonces[owner].current(); } /** * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view override returns (bytes32) { return _domainSeparatorV4(); } } // File: contracts/FountainToken.sol pragma solidity 0.6.12; pragma experimental ABIEncoderV2; contract FountainToken is ERC20Permit { constructor(string memory name_, string memory symbol_) public ERC20(name_, symbol_) ERC20Permit(name_) {} function transferFromWithPermit( address owner, address recipient, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external returns (bool) { permit(owner, msg.sender, value, deadline, v, r, s); return transferFrom(owner, recipient, value); } } // File: contracts/interfaces/IFountainFactory.sol pragma solidity 0.6.12; interface IFountainFactory { // Getter function archangel() external view returns (address); function isValid(address fountain) external view returns (bool); function fountainOf(address token) external view returns (address); function create(address token) external returns (address); } // File: contracts/interfaces/IAngel.sol pragma solidity 0.6.12; interface IAngel { struct UserInfo { uint256 amount; uint256 rewardDebt; } struct PoolInfo { uint128 accGracePerShare; uint64 lastRewardTime; uint64 allocPoint; } function poolLength() external view returns (uint256); function updatePool(uint256 pid) external returns (IAngel.PoolInfo memory); function userInfo(uint256 _pid, address _user) external view returns (uint256, uint256); function deposit(uint256 pid, uint256 amount, address to) external; function withdraw(uint256 pid, uint256 amount, address to) external; function harvest(uint256 pid, address from, address to) external; function emergencyWithdraw(uint256 pid, address to) external; function owner() external view returns (address); function lpToken(uint256 pid) external view returns (address); } // File: @openzeppelin/contracts/utils/ReentrancyGuard.sol pragma solidity >=0.6.0 <0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor () internal { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } } // File: contracts/utils/ErrorMsg.sol pragma solidity 0.6.12; abstract contract ErrorMsg { function _requireMsg( bool condition, string memory functionName, string memory reason ) internal pure { if (!condition) _revertMsg(functionName, reason); } function _requireMsg(bool condition, string memory functionName) internal pure { if (!condition) _revertMsg(functionName); } function _revertMsg(string memory functionName, string memory reason) internal pure { revert(string(abi.encodePacked(functionName, ": ", reason))); } function _revertMsg(string memory functionName) internal pure { _revertMsg(functionName, "Unspecified"); } } // File: contracts/FountainBase.sol pragma solidity 0.6.12; /// @title Staking vault of lpTokens abstract contract FountainBase is FountainToken, ReentrancyGuard, ErrorMsg { using SafeERC20 for IERC20; using SafeMath for uint256; /// @notice The staking token of this Fountain IERC20 public immutable stakingToken; IFountainFactory public immutable factory; /// @notice The information of angel that is cached in Fountain struct AngelInfo { bool isSet; uint256 pid; uint256 totalBalance; } /// @dev The angels that user joined mapping(address => IAngel[]) private _joinedAngels; /// @dev The information of angels mapping(IAngel => AngelInfo) private _angelInfos; event Join(address user, address angel); event Quit(address user, address angel); event RageQuit(address user, address angel); event Deposit(address indexed user, uint256 amount, address indexed to); event Withdraw(address indexed user, uint256 amount, address indexed to); event EmergencyWithdraw( address indexed user, uint256 amount, address indexed to ); event Harvest(address indexed user); constructor(IERC20 token) public { stakingToken = token; IFountainFactory f = IFountainFactory(msg.sender); factory = f; } // Getters /// @notice Return the angels that user joined. /// @param user The user address. /// @return The angel list. function joinedAngel(address user) public view returns (IAngel[] memory) { return _joinedAngels[user]; } /// @notice Return the information of the angel. The fountain needs to be /// added by angel. /// @param angel The angel to be queried. /// @return The pid in angel. /// @return The total balance deposited in angel. function angelInfo(IAngel angel) external view returns (uint256, uint256) { AngelInfo storage info = _angelInfos[angel]; _requireMsg(info.isSet, "angelInfo", "angel not set"); return (info.pid, info.totalBalance); } /// Angel action /// @notice Angel may set their own pid that matches the staking token /// of the Fountain. /// @param pid The pid to be assigned. function setPoolId(uint256 pid) external { IAngel angel = IAngel(_msgSender()); AngelInfo storage info = _angelInfos[angel]; _requireMsg(!info.isSet, "setPoolId", "angel is set"); _requireMsg( angel.lpToken(pid) == address(stakingToken), "setPoolId", "token not matched" ); info.isSet = true; info.pid = pid; } // User action /// @notice User may deposit their lp token. FTN token will be minted. /// Fountain will call angel's deposit to update user information, but the tokens /// stay in Fountain. /// @param amount The amount to be deposited. function deposit(uint256 amount) external nonReentrant { // Transfer user staking token uint256 balance = _deposit(amount); // Mint token _mint(_msgSender(), balance); emit Deposit(_msgSender(), balance, _msgSender()); } // User action /// @notice User may deposit their lp token for others. FTN token will be minted. /// Fountain will call angel's deposit to update user information, but the tokens /// stay in Fountain. /// @param amount The amount to be deposited. /// @param to The address to be deposited. function depositTo(uint256 amount, address to) external nonReentrant { // Transfer user staking token uint256 balance = _deposit(amount); // Mint token _mint(to, balance); emit Deposit(_msgSender(), balance, to); } /// @notice User may withdraw their lp token. FTN token will be burned. /// Fountain will call angel's withdraw to update user information, but the tokens /// will be transferred from Fountain. /// @param amount The amount to be withdrawn. function withdraw(uint256 amount) external nonReentrant { uint256 balance = _withdraw(amount, _msgSender()); // Burn token _burn(_msgSender(), balance); emit Withdraw(_msgSender(), balance, _msgSender()); } /// @notice User may withdraw their lp token. FTN token will be burned. /// Fountain will call angel's withdraw to update user information, but the tokens /// will be transferred from Fountain. /// @param amount The amount to be withdrawn. /// @param to The address to sent the withdrawn balance to. function withdrawTo(uint256 amount, address to) external nonReentrant { uint256 balance = _withdraw(amount, to); // Burn token _burn(_msgSender(), balance); emit Withdraw(_msgSender(), balance, to); } /// @notice User may harvest from any angel. /// @param angel The angel to be harvest from. function harvest(IAngel angel) external nonReentrant { _harvestAngel(angel, _msgSender(), _msgSender()); emit Harvest(_msgSender()); } /// @notice User may harvest from all the joined angels. function harvestAll() external nonReentrant { // Call joined angel IAngel[] storage angels = _joinedAngels[_msgSender()]; for (uint256 i = 0; i < angels.length; i++) { IAngel angel = angels[i]; _harvestAngel(angel, _msgSender(), _msgSender()); } emit Harvest(_msgSender()); } /// @notice Emergency withdraw all tokens. function emergencyWithdraw() external nonReentrant { uint256 amount = balanceOf(_msgSender()); uint256 balance = _withdraw(amount, _msgSender()); // Burn token _burn(_msgSender(), type(uint256).max); emit EmergencyWithdraw(_msgSender(), balance, _msgSender()); } /// @notice Join the given angel's program. /// @param angel The angel to be joined. function joinAngel(IAngel angel) external nonReentrant { _joinAngel(angel, _msgSender()); } /// @notice Join the given angels' program. /// @param angels The angels to be joined. function joinAngels(IAngel[] calldata angels) external nonReentrant { for (uint256 i = 0; i < angels.length; i++) { _joinAngel(angels[i], _msgSender()); } } /// @notice Quit the given angel's program. /// @param angel The angel to be quited. function quitAngel(IAngel angel) external nonReentrant { _quitAngel(angel); emit Quit(_msgSender(), address(angel)); // Update user info at angel _withdrawAngel(_msgSender(), angel, balanceOf(_msgSender())); } /// @notice Quit all angels' program. function quitAllAngel() external nonReentrant { IAngel[] storage angels = _joinedAngels[_msgSender()]; for (uint256 i = 0; i < angels.length; i++) { IAngel angel = angels[i]; emit Quit(_msgSender(), address(angel)); // Update user info at angel _withdrawAngel(_msgSender(), angel, balanceOf(_msgSender())); } delete _joinedAngels[_msgSender()]; } /// @notice Quit an angel's program with emergencyWithdraw /// @param angel The angel to be quited. function rageQuitAngel(IAngel angel) external nonReentrant { _quitAngel(angel); emit RageQuit(_msgSender(), address(angel)); // Update user info at angel _emergencyWithdrawAngel(_msgSender(), angel); } /// @notice Apply nonReentrant to transfer. function transfer(address recipient, uint256 amount) public override nonReentrant returns (bool) { return super.transfer(recipient, amount); } /// @notice Apply nonReentrant to transferFrom. function transferFrom( address sender, address recipient, uint256 amount ) public override nonReentrant returns (bool) { return super.transferFrom(sender, recipient, amount); } /// @notice Withdraw for the sender and deposit for the receiver /// when token amount changes. When the amount is UINT256_MAX, /// trigger emergencyWithdraw instead of withdraw. function _beforeTokenTransfer( address from, address to, uint256 amount ) internal override { if (from != address(0)) { IAngel[] storage angels = _joinedAngels[from]; if (amount < type(uint256).max) { for (uint256 i = 0; i < angels.length; i++) { IAngel angel = angels[i]; _withdrawAngel(from, angel, amount); } } else { for (uint256 i = 0; i < angels.length; i++) { IAngel angel = angels[i]; _emergencyWithdrawAngel(from, angel); } } } if (to != address(0)) { IAngel[] storage angels = _joinedAngels[to]; for (uint256 i = 0; i < angels.length; i++) { IAngel angel = angels[i]; _depositAngel(to, angel, amount); } } } /// @notice Return the actual token amount deposited to Fountain to prevent /// inconsistency of desired amount and transferred amount. function _deposit(uint256 amount) internal returns (uint256) { uint256 balance = stakingToken.balanceOf(address(this)); stakingToken.safeTransferFrom(_msgSender(), address(this), amount); return stakingToken.balanceOf(address(this)).sub(balance); } /// @notice Return the actual token amount withdrawn from Fountain to prevent /// inconsistency of desired amount and transferred amount. function _withdraw(uint256 amount, address to) internal returns (uint256) { // Withdraw entire balance if amount == UINT256_MAX amount = amount == type(uint256).max ? balanceOf(_msgSender()) : amount; uint256 balance = stakingToken.balanceOf(address(this)); stakingToken.safeTransfer(to, amount); return balance.sub(stakingToken.balanceOf(address(this))); } /// @notice The total staked amount should be updated in angelInfo when /// token is being deposited/withdrawn. function _depositAngel( address user, IAngel angel, uint256 amount ) internal { AngelInfo storage info = _angelInfos[angel]; _requireMsg(info.isSet, "_depositAngel", "not added by angel"); angel.deposit(info.pid, amount, user); info.totalBalance = info.totalBalance.add(amount); } function _withdrawAngel( address user, IAngel angel, uint256 amount ) internal { AngelInfo storage info = _angelInfos[angel]; _requireMsg(info.isSet, "_withdrawAngel", "not added by angel"); angel.withdraw(info.pid, amount, user); info.totalBalance = info.totalBalance.sub(amount); } function _harvestAngel( IAngel angel, address from, address to ) internal { AngelInfo storage info = _angelInfos[angel]; _requireMsg(info.isSet, "_harvestAngel", "not added by angel"); angel.harvest(info.pid, from, to); } function _emergencyWithdrawAngel(address user, IAngel angel) internal { AngelInfo storage info = _angelInfos[angel]; _requireMsg(info.isSet, "_emergencyAngel", "not added by angel"); uint256 amount = balanceOf(user); angel.emergencyWithdraw(info.pid, user); info.totalBalance = info.totalBalance.sub(amount); } function _joinAngel(IAngel angel, address user) internal { IAngel[] storage angels = _joinedAngels[user]; for (uint256 i = 0; i < angels.length; i++) { _requireMsg(angels[i] != angel, "_joinAngel", "angel joined"); } angels.push(angel); emit Join(user, address(angel)); // Update user info at angel _depositAngel(user, angel, balanceOf(user)); } function _quitAngel(IAngel angel) internal { IAngel[] storage angels = _joinedAngels[_msgSender()]; uint256 len = angels.length; if (angels[len - 1] == angel) { angels.pop(); } else { for (uint256 i = 0; i < len - 1; i++) { if (angels[i] == angel) { angels[i] = angels[len - 1]; angels.pop(); break; } } } _requireMsg(angels.length != len, "_quitAngel", "unjoined angel"); } } // File: contracts/JoinPermit.sol pragma solidity 0.6.12; /// @title Staking vault of lpTokens abstract contract JoinPermit is FountainBase { using Counters for Counters.Counter; mapping(address => mapping(address => uint256)) private _timeLimits; mapping(address => Counters.Counter) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 private constant _JOIN_PERMIT_TYPEHASH = keccak256( "JoinPermit(address user,address sender,uint256 timeLimit,uint256 nonce,uint256 deadline)" ); /** * @dev Emitted when the time limit of a `sender` for an `user` is set by * a call to {approve}. `timeLimit` is the new time limit. */ event JoinApproval( address indexed user, address indexed sender, uint256 timeLimit ); /// @notice Examine if the time limit is not expired. modifier canJoinFor(address user) { _requireMsg( block.timestamp <= _timeLimits[user][_msgSender()], "general", "join not allowed" ); _; } // Getter /// @notice Return the time limit user approved to the sender. /// @param user The user address. /// @param sender The sender address. /// @return The time limit. function joinTimeLimit(address user, address sender) external view returns (uint256) { return _timeLimits[user][sender]; } /// @notice Approve sender to join before timeLimit. /// @param sender The sender address. /// @param timeLimit The time limit to be approved. function joinApprove(address sender, uint256 timeLimit) external returns (bool) { _joinApprove(_msgSender(), sender, timeLimit); return true; } /// @notice Approve sender to join for user before timeLimit. /// @param user The user address. /// @param sender The sender address. /// @param timeLimit The time limit to be approved. /// @param deadline The permit available deadline. /// @param v Signature v. /// @param r Signature r. /// @param s Signature s. function joinPermit( address user, address sender, uint256 timeLimit, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public { // solhint-disable-next-line not-rely-on-time _requireMsg( block.timestamp <= deadline, "joinPermit", "expired deadline" ); bytes32 structHash = keccak256( abi.encode( _JOIN_PERMIT_TYPEHASH, user, sender, timeLimit, _nonces[user].current(), deadline ) ); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); _requireMsg(signer == user, "joinPermit", "invalid signature"); _nonces[user].increment(); _joinApprove(user, sender, timeLimit); } function joinNonces(address user) external view returns (uint256) { return _nonces[user].current(); } /// @notice User may join angel for permitted user. /// @param angel The angel address. /// @param user The user address. function joinAngelFor(IAngel angel, address user) public canJoinFor(user) nonReentrant { _joinAngel(angel, user); } /// @notice User may join angels for permitted user. /// @param angels The angel addresses. /// @param user The user address. function joinAngelsFor(IAngel[] memory angels, address user) public canJoinFor(user) nonReentrant { for (uint256 i = 0; i < angels.length; i++) { _joinAngel(angels[i], user); } } /// @notice Perform joinFor after permit. /// @param angel The angel address. /// @param user The user address. /// @param timeLimit The time limit to be approved. Will set to current /// time if set as 1 (for one time usage) /// @param deadline The permit available deadline. /// @param v Signature v. /// @param r Signature r. /// @param s Signature s. function joinAngelForWithPermit( IAngel angel, address user, uint256 timeLimit, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external { joinPermit(user, _msgSender(), timeLimit, deadline, v, r, s); joinAngelFor(angel, user); } /// @notice Perform joinForMany after permit. /// @param angels The angel addresses. /// @param user The user address. /// @param timeLimit The time limit to be approved. Will set to current /// time if set as 1 (for one time usage) /// @param deadline The permit available deadline. /// @param v Signature v. /// @param r Signature r. /// @param s Signature s. function joinAngelsForWithPermit( IAngel[] calldata angels, address user, uint256 timeLimit, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external { joinPermit(user, _msgSender(), timeLimit, deadline, v, r, s); joinAngelsFor(angels, user); } function _joinApprove( address user, address sender, uint256 timeLimit ) internal { _requireMsg( user != address(0), "_joinApprove", "approve from the zero address" ); _requireMsg( sender != address(0), "_joinApprove", "approve to the zero address" ); if (timeLimit == 1) timeLimit = block.timestamp; _timeLimits[user][sender] = timeLimit; emit JoinApproval(user, sender, timeLimit); } } // File: contracts/HarvestPermit.sol pragma solidity 0.6.12; /// @title Staking vault of lpTokens abstract contract HarvestPermit is FountainBase { using Counters for Counters.Counter; mapping(address => mapping(address => uint256)) private _timeLimits; mapping(address => Counters.Counter) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 private constant _HARVEST_PERMIT_TYPEHASH = keccak256( "HarvestPermit(address owner,address sender,uint256 timeLimit,uint256 nonce,uint256 deadline)" ); /** * @dev Emitted when the time limit of a `sender` for an `owner` is set by * a call to {approve}. `timeLimit` is the new time limit. */ event HarvestApproval( address indexed owner, address indexed sender, uint256 timeLimit ); /// @notice Examine if the time limit is not expired. modifier canHarvestFrom(address owner) { _requireMsg( block.timestamp <= _timeLimits[owner][_msgSender()], "general", "harvest not allowed" ); _; } // Getter /// @notice Return the time limit owner approved to the sender. /// @param owner The owner address. /// @param sender The sender address. /// @return The time limit. function harvestTimeLimit(address owner, address sender) external view returns (uint256) { return _timeLimits[owner][sender]; } /// @notice Approve sender to harvest before timeLimit. /// @param sender The sender address. /// @param timeLimit The time limit to be approved. function harvestApprove(address sender, uint256 timeLimit) external returns (bool) { _harvestApprove(_msgSender(), sender, timeLimit); return true; } /// @notice Approve sender to harvest for owner before timeLimit. /// @param owner The owner address. /// @param sender The sender address. /// @param timeLimit The time limit to be approved. /// @param deadline The permit available deadline. /// @param v Signature v. /// @param r Signature r. /// @param s Signature s. function harvestPermit( address owner, address sender, uint256 timeLimit, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public { // solhint-disable-next-line not-rely-on-time _requireMsg( block.timestamp <= deadline, "harvestPermit", "expired deadline" ); bytes32 structHash = keccak256( abi.encode( _HARVEST_PERMIT_TYPEHASH, owner, sender, timeLimit, _nonces[owner].current(), deadline ) ); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); _requireMsg(signer == owner, "harvestPermit", "invalid signature"); _nonces[owner].increment(); _harvestApprove(owner, sender, timeLimit); } function harvestNonces(address owner) external view returns (uint256) { return _nonces[owner].current(); } /// @notice User may harvest from any angel for permitted user. /// @param angel The angel address. /// @param from The owner address. /// @param to The recipient address. function harvestFrom( IAngel angel, address from, address to ) public canHarvestFrom(from) nonReentrant { _harvestAngel(angel, from, to); emit Harvest(from); } /// @notice User may harvest from all the joined angels for permitted user. /// @param from The owner address. /// @param to The recipient address. function harvestAllFrom(address from, address to) public canHarvestFrom(from) nonReentrant { IAngel[] memory angels = joinedAngel(from); for (uint256 i = 0; i < angels.length; i++) { IAngel angel = angels[i]; _harvestAngel(angel, from, to); } emit Harvest(from); } /// @notice Perform harvestFrom after permit. /// @param angel The angel address. /// @param from The owner address. /// @param to The recipient address. /// @param timeLimit The time limit to be approved. /// @param deadline The permit available deadline. /// @param v Signature v. /// @param r Signature r. /// @param s Signature s. function harvestFromWithPermit( IAngel angel, address from, address to, uint256 timeLimit, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external { harvestPermit(from, _msgSender(), timeLimit, deadline, v, r, s); harvestFrom(angel, from, to); } /// @notice Perform harvestAllFrom after permit. /// @param from The owner address. /// @param to The recipient address. /// @param timeLimit The time limit to be approved. /// @param deadline The permit available deadline. /// @param v Signature v. /// @param r Signature r. /// @param s Signature s. function harvestAllFromWithPermit( address from, address to, uint256 timeLimit, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external { harvestPermit(from, _msgSender(), timeLimit, deadline, v, r, s); harvestAllFrom(from, to); } function _harvestApprove( address owner, address sender, uint256 timeLimit ) internal { _requireMsg( owner != address(0), "_harvestApprove", "approve from the zero address" ); _requireMsg( sender != address(0), "_harvestApprove", "approve to the zero address" ); _timeLimits[owner][sender] = timeLimit; emit HarvestApproval(owner, sender, timeLimit); } } /** * @dev Interface of the ERC3156 FlashLender, as defined in * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. */ interface IERC3156FlashLender { /** * @dev The amount of currency available to be lended. * @param token The loan currency. * @return The amount of `token` that can be borrowed. */ function maxFlashLoan(address token) external view returns (uint256); /** * @dev The fee to be charged for a given loan. * @param token The loan currency. * @param amount The amount of tokens lent. * @return The amount of `token` to be charged for the loan, on top of the returned principal. */ function flashFee(address token, uint256 amount) external view returns (uint256); /** * @dev Initiate a flash loan. * @param receiver The receiver of the tokens in the loan, and the receiver of the callback. * @param token The loan currency. * @param amount The amount of tokens lent. * @param data Arbitrary data structure, intended to contain user-defined parameters. */ function flashLoan( IERC3156FlashBorrower receiver, address token, uint256 amount, bytes calldata data ) external returns (bool); } // File: contracts/interfaces/IFlashLender.sol pragma solidity 0.6.12; interface IFlashLender is IERC3156FlashLender { function flashLoanFeeCollector() external view returns (address); function setFlashLoanFee(uint256) external; } // File: contracts/ERC20FlashLoan.sol pragma solidity 0.6.12; contract ERC20FlashLoan is IFlashLender { using SafeERC20 for IERC20; using SafeMath for uint256; IERC20 public immutable lendingToken; uint256 public flashLoanFee; uint256 public constant FEE_BASE = 1e4; uint256 public constant FEE_BASE_OFFSET = FEE_BASE / 2; bytes32 private constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan"); constructor(IERC20 token, uint256 fee) public { require(fee <= FEE_BASE, "fee rate exceeded"); lendingToken = token; flashLoanFee = fee; } /** * @dev The amount of currency available to be lended. * @param token The loan currency. * @return The amount of `token` that can be borrowed. */ function maxFlashLoan(address token) external view override returns (uint256) { return token == address(lendingToken) ? lendingToken.balanceOf(address(this)) : 0; } /** * @dev The fee to be charged for a given loan. * @param token The loan currency. * @param amount The amount of tokens lent. * @return The amount of `token` to be charged for the loan, on top of the returned principal. */ function flashFee(address token, uint256 amount) public view override returns (uint256) { require(token == address(lendingToken), "wrong token"); // The fee will be rounded half up return (amount.mul(flashLoanFee).add(FEE_BASE_OFFSET)).div(FEE_BASE); } /** * @dev Initiate a flash loan. * @param receiver The receiver of the tokens in the loan, and the receiver of the callback. * @param token The loan currency. * @param amount The amount of tokens lent. * @param data Arbitrary data structure, intended to contain user-defined parameters. */ function flashLoan( IERC3156FlashBorrower receiver, address token, uint256 amount, bytes calldata data ) external override returns (bool) { uint256 balance = IERC20(token).balanceOf(address(this)); uint256 fee = flashFee(token, amount); // send token to receiver lendingToken.safeTransfer(address(receiver), amount); require( receiver.onFlashLoan(msg.sender, token, amount, fee, data) == _RETURN_VALUE, "invalid return value" ); uint256 currentAllowance = lendingToken.allowance(address(receiver), address(this)); uint256 totalDebt = amount.add(fee); require( currentAllowance >= totalDebt, "allowance does not allow refund" ); // get token from receiver lendingToken.safeTransferFrom( address(receiver), address(this), totalDebt ); address collector = flashLoanFeeCollector(); if (collector != address(0)) lendingToken.safeTransfer(collector, fee); require( IERC20(token).balanceOf(address(this)) >= balance, "balance decreased" ); return true; } function flashLoanFeeCollector() public view virtual override returns (address) { this; return address(0); } function setFlashLoanFee(uint256 fee) public virtual override { require(fee <= FEE_BASE, "fee rate exceeded"); flashLoanFee = fee; } } // File: contracts/libraries/boringcrypto/BoringBatchable.sol // Audit on 5-Jan-2021 by Keno and BoringCrypto // P1 - P3: OK pragma solidity 0.6.12; // solhint-disable avoid-low-level-calls // T1 - T4: OK contract BaseBoringBatchable { function _getRevertMsg(bytes memory _returnData) internal pure returns (string memory) { // If the _res length is less than 68, then the transaction failed silently (without a revert message) if (_returnData.length < 68) return "Transaction reverted silently"; assembly { // Slice the sighash. _returnData := add(_returnData, 0x04) } return abi.decode(_returnData, (string)); // All that remains is the revert string } // F3 - F9: OK // F1: External is ok here because this is the batch function, adding it to a batch makes no sense // F2: Calls in the batch may be payable, delegatecall operates in the same context, so each call in the batch has access to msg.value // C1 - C21: OK // C3: The length of the loop is fully under user control, so can't be exploited // C7: Delegatecall is only used on the same contract, so it's safe function batch(bytes[] calldata calls, bool revertOnFail) external payable returns (bool[] memory successes, bytes[] memory results) { // Interactions successes = new bool[](calls.length); results = new bytes[](calls.length); for (uint256 i = 0; i < calls.length; i++) { (bool success, bytes memory result) = address(this).delegatecall(calls[i]); require(success || !revertOnFail, _getRevertMsg(result)); successes[i] = success; results[i] = result; } } } // T1 - T4: OK contract BoringBatchable is BaseBoringBatchable { // F1 - F9: OK // F6: Parameters can be used front-run the permit and the user's permit will fail (due to nonce or other revert) // if part of a batch this could be used to grief once as the second call would not need the permit // C1 - C21: OK function permitToken( IERC20Permit token, address from, address to, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public { // Interactions // X1 - X5 token.permit(from, to, amount, deadline, v, r, s); } } // File: contracts/libraries/boringcrypto/libraries/BoringMath.sol pragma solidity 0.6.12; // a library for performing overflow-safe math, updated with awesomeness from of DappHub (https://github.com/dapphub/ds-math) library BoringMath { function add(uint256 a, uint256 b) internal pure returns (uint256 c) {require((c = a + b) >= b, "BoringMath: Add Overflow");} function sub(uint256 a, uint256 b) internal pure returns (uint256 c) {require((c = a - b) <= a, "BoringMath: Underflow");} function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {require(b == 0 || (c = a * b)/b == a, "BoringMath: Mul Overflow");} function to128(uint256 a) internal pure returns (uint128 c) { require(a <= uint128(-1), "BoringMath: uint128 Overflow"); c = uint128(a); } function to64(uint256 a) internal pure returns (uint64 c) { require(a <= uint64(-1), "BoringMath: uint64 Overflow"); c = uint64(a); } function to32(uint256 a) internal pure returns (uint32 c) { require(a <= uint32(-1), "BoringMath: uint32 Overflow"); c = uint32(a); } } library BoringMath128 { function add(uint128 a, uint128 b) internal pure returns (uint128 c) {require((c = a + b) >= b, "BoringMath: Add Overflow");} function sub(uint128 a, uint128 b) internal pure returns (uint128 c) {require((c = a - b) <= a, "BoringMath: Underflow");} } library BoringMath64 { function add(uint64 a, uint64 b) internal pure returns (uint64 c) {require((c = a + b) >= b, "BoringMath: Add Overflow");} function sub(uint64 a, uint64 b) internal pure returns (uint64 c) {require((c = a - b) <= a, "BoringMath: Underflow");} } library BoringMath32 { function add(uint32 a, uint32 b) internal pure returns (uint32 c) {require((c = a + b) >= b, "BoringMath: Add Overflow");} function sub(uint32 a, uint32 b) internal pure returns (uint32 c) {require((c = a - b) <= a, "BoringMath: Underflow");} } // File: @openzeppelin/contracts/math/Math.sol pragma solidity >=0.6.0 <0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } } // File: contracts/Fountain.sol pragma solidity 0.6.12; /// @title The fountain contract Fountain is HarvestPermit, JoinPermit, ERC20FlashLoan, BoringBatchable { modifier onlyArchangel { _requireMsg( _msgSender() == factory.archangel(), "general", "not from archangel" ); _; } constructor( IERC20 token, string memory name_, string memory symbol_, uint256 flashLoanFee ) public FountainToken(name_, symbol_) FountainBase(token) ERC20FlashLoan(token, flashLoanFee) {} /// @notice Fetch the token from fountain. Can only be called by Archangel. /// Will only fetch the extra part if the token is the staking token. Otherwise /// the entire balance will be fetched. /// @param token The token address. /// @param to The receiver. /// @return The transferred amount. function rescueERC20(IERC20 token, address to) external onlyArchangel returns (uint256) { uint256 amount; if (token == stakingToken) { amount = token.balanceOf(address(this)).sub(totalSupply()); } else { amount = token.balanceOf(address(this)); } token.safeTransfer(to, amount); return amount; } /// @notice Set the fee rate for flash loan. can only be set by Archangel. /// @param fee The fee rate. function setFlashLoanFee(uint256 fee) public override onlyArchangel { super.setFlashLoanFee(fee); } } // File: contracts/FountainFactory.sol pragma solidity 0.6.12; /// @title The factory of Fountain contract FountainFactory is ErrorMsg { IArchangel public immutable archangel; /// @dev Token and Fountain should be 1-1 and only mapping(IERC20 => Fountain) private _fountains; mapping(Fountain => IERC20) private _stakings; event Created(address to); constructor() public { archangel = IArchangel(msg.sender); } // Getters /// @notice Check if fountain is valid. /// @param fountain The fountain to be verified. /// @return Is valid or not. function isValid(Fountain fountain) external view returns (bool) { return (address(_stakings[fountain]) != address(0)); } /// @notice Get the fountain of given token. /// @param token The token address. /// @return The fountain. function fountainOf(IERC20 token) external view returns (Fountain) { return _fountains[token]; } /// @notice Create Fountain for token. Notice that fountain with tokens that /// has floating amount (including Inflationary/Deflationary tokens, Interest /// tokens, Rebase tokens), might leads to error according to the design /// policy of fountain. /// @param token The token address to be created. /// @return The created fountain. function create(ERC20 token) external returns (Fountain) { _requireMsg( address(_fountains[token]) == address(0), "create", "fountain existed" ); string memory name = _concat("Fountain ", token.name()); string memory symbol = _concat("FTN-", token.symbol()); Fountain fountain = new Fountain(token, name, symbol, archangel.defaultFlashLoanFee()); _fountains[token] = fountain; _stakings[fountain] = token; emit Created(address(fountain)); } function _concat(string memory a, string memory b) internal pure returns (string memory) { return string(abi.encodePacked(a, b)); } } // File: contracts/interfaces/IFountain.sol pragma solidity 0.6.12; interface IFountain is IERC20, IERC20Permit { // Getter function stakingToken() external view returns (address); function factory() external view returns (address); function archangel() external view returns (address); function joinedAngel(address user) external view returns (address[] memory); function angelInfo(address angel) external view returns (uint256, uint256); function joinTimeLimit(address owner, address sender) external view returns (uint256); function joinNonces(address owner) external view returns (uint256); function harvestTimeLimit(address owner, address sender) external view returns (uint256); function harvestNonces(address owner) external view returns (uint256); function setPoolId(uint256 pid) external; function deposit(uint256 amount) external; function depositTo(uint256 amount, address to) external; function withdraw(uint256 amount) external; function withdrawTo(uint256 amount, address to) external; function harvest(address angel) external; function harvestAll() external; function emergencyWithdraw() external; function joinAngel(address angel) external; function joinAngels(address[] calldata angels) external; function quitAngel(address angel) external; function rageQuitAngel(address angel) external; function quitAllAngel() external; function transferFromWithPermit(address owner, address recipient, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external returns (bool); function joinApprove(address sender, uint256 timeLimit) external returns (bool); function joinPermit( address user, address sender, uint256 timeLimit, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; function joinAngelFor(address angel, address user) external; function joinAngelsFor(address[] calldata angels, address user) external; function joinAngelForWithPermit( address angel, address user, uint256 timeLimit, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; function joinAngelsForWithPermit( address[] calldata angels, address user, uint256 timeLimit, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; function harvestApprove(address sender, uint256 timeLimit) external returns (bool); function harvestPermit( address owner, address sender, uint256 timeLimit, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; function harvestFrom(address angel, address from, address to) external; function harvestAllFrom(address from, address to) external; function harvestFromWithPermit( address angel, address from, address to, uint256 timeLimit, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; function harvestAllFromWithPermit( address from, address to, uint256 timeLimit, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; } // File: contracts/interfaces/IAngelFactory.sol pragma solidity 0.6.12; interface IAngelFactory { // Getters function archangel() external view returns (address); function isValid(address angel) external view returns (bool); function rewardOf(address angel) external view returns (address); function create(address rewardToken) external returns (address); } // File: contracts/interfaces/IMasterChef.sol pragma solidity 0.6.12; interface IMasterChef { using BoringERC20 for IERC20; struct UserInfo { uint256 amount; // How many LP tokens the user has provided. uint256 rewardDebt; // Reward debt. See explanation below. } struct PoolInfo { IERC20 lpToken; // Address of LP token contract. uint256 allocPoint; // How many allocation points assigned to this pool. SUSHI to distribute per block. uint256 lastRewardBlock; // Last block number that SUSHI distribution occurs. uint256 accSushiPerShare; // Accumulated SUSHI per share, times 1e12. See below. } function poolInfo(uint256 pid) external view returns (IMasterChef.PoolInfo memory); function totalAllocPoint() external view returns (uint256); function deposit(uint256 _pid, uint256 _amount) external; } // File: contracts/interfaces/IRewarder.sol pragma solidity 0.6.12; interface IRewarder { using BoringERC20 for IERC20; function onGraceReward( uint256 pid, address user, address recipient, uint256 graceAmount, uint256 newLpAmount ) external; function pendingTokens( uint256 pid, address user, uint256 graceAmount ) external view returns (IERC20[] memory, uint256[] memory); } // File: contracts/libraries/SignedSafeMath.sol pragma solidity >=0.6.0 <0.8.0; /** * @title SignedSafeMath * @dev Signed math operations with safety checks that revert on error. */ library SignedSafeMath { int256 private constant _INT256_MIN = -2**255; /** * @dev Returns the multiplication of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(int256 a, int256 b) internal pure returns (int256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } require( !(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow" ); int256 c = a * b; require(c / a == b, "SignedSafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two signed integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(int256 a, int256 b) internal pure returns (int256) { require(b != 0, "SignedSafeMath: division by zero"); require( !(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow" ); int256 c = a / b; return c; } /** * @dev Returns the subtraction of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(int256 a, int256 b) internal pure returns (int256) { int256 c = a - b; require( (b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow" ); return c; } /** * @dev Returns the addition of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(int256 a, int256 b) internal pure returns (int256) { int256 c = a + b; require( (b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow" ); return c; } /** * @dev Returns the unsigned integer of the positive signed integer, * reverting on negative integer. * Not from openzeppelin/contracts * * Requirements: * * - Integer cannot be negative. */ function toUInt256(int256 a) internal pure returns (uint256) { require(a >= 0, "Integer < 0"); return uint256(a); } } // File: contracts/libraries/boringcrypto/BoringOwnable.sol // Audit on 5-Jan-2021 by Keno and BoringCrypto // P1 - P3: OK pragma solidity 0.6.12; // Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol + Claimable.sol // Edited by BoringCrypto // T1 - T4: OK contract BoringOwnableData { // V1 - V5: OK address public owner; // V1 - V5: OK address public pendingOwner; } // T1 - T4: OK contract BoringOwnable is BoringOwnableData { // E1: OK event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); constructor () public { owner = msg.sender; emit OwnershipTransferred(address(0), msg.sender); } // F1 - F9: OK // C1 - C21: OK function transferOwnership(address newOwner, bool direct, bool renounce) public onlyOwner { if (direct) { // Checks require(newOwner != address(0) || renounce, "Ownable: zero address"); // Effects emit OwnershipTransferred(owner, newOwner); owner = newOwner; pendingOwner = address(0); } else { // Effects pendingOwner = newOwner; } } // F1 - F9: OK // C1 - C21: OK function claimOwnership() public { address _pendingOwner = pendingOwner; // Checks require(msg.sender == _pendingOwner, "Ownable: caller != pending owner"); // Effects emit OwnershipTransferred(owner, _pendingOwner); owner = _pendingOwner; pendingOwner = address(0); } // M1 - M5: OK // C1 - C21: OK modifier onlyOwner() { require(msg.sender == owner, "Ownable: caller is not the owner"); _; } } // File: contracts/libraries/boringcrypto/libraries/BoringERC20.sol pragma solidity 0.6.12; library BoringERC20 { function safeSymbol(IERC20 token) internal view returns (string memory) { (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(0x95d89b41)); return success && data.length > 0 ? abi.decode(data, (string)) : "???"; } function safeName(IERC20 token) internal view returns (string memory) { (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(0x06fdde03)); return success && data.length > 0 ? abi.decode(data, (string)) : "???"; } function safeDecimals(IERC20 token) internal view returns (uint8) { (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(0x313ce567)); return success && data.length == 32 ? abi.decode(data, (uint8)) : 18; } function safeTransfer( IERC20 token, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(0xa9059cbb, to, amount)); require( success && (data.length == 0 || abi.decode(data, (bool))), "BoringERC20: Transfer failed" ); } function safeTransferFrom( IERC20 token, address from, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(token).call( abi.encodeWithSelector(0x23b872dd, from, to, amount) ); require( success && (data.length == 0 || abi.decode(data, (bool))), "BoringERC20: TransferFrom failed" ); } } // File: contracts/AngelBase.sol pragma solidity 0.6.12; /// @notice Angel is a forked version of MiniChefV2 from SushiSwap with /// minimal modifications to interact with fountain in Trevi. The staking /// tokens are managed in fountain instead of here. Migrate related functions /// withdrawAndHarvest are removed. contract AngelBase is BoringOwnable, BoringBatchable, ErrorMsg { using BoringMath for uint256; using BoringMath128 for uint128; using BoringERC20 for IERC20; using SignedSafeMath for int256; /// @notice Info of each MCV2 user. /// `amount` LP token amount the user has provided. /// `rewardDebt` The amount of GRACE entitled to the user. struct UserInfo { uint256 amount; int256 rewardDebt; } /// @notice Info of each MCV2 pool. /// `allocPoint` The amount of allocation points assigned to the pool. /// Also known as the amount of GRACE to distribute per block. struct PoolInfo { uint128 accGracePerShare; uint64 lastRewardTime; uint64 allocPoint; } /// @notice Address of GRACE contract. IERC20 public immutable GRACE; // @notice The migrator contract. It has a lot of power. Can only be set through governance (owner). /// @notice Info of each MCV2 pool. PoolInfo[] public poolInfo; /// @notice Address of the LP token for each MCV2 pool. IERC20[] public lpToken; /// @notice Address of each `IRewarder` contract in MCV2. IRewarder[] public rewarder; /// @notice Info of each user that stakes LP tokens. mapping(uint256 => mapping(address => UserInfo)) public userInfo; /// @dev Total allocation points. Must be the sum of all allocation points in all pools. uint256 public totalAllocPoint; uint256 public gracePerSecond; uint256 private constant ACC_GRACE_PRECISION = 1e12; ////////////////////////// New IArchangel public immutable archangel; IAngelFactory public immutable factory; uint256 public endTime; uint256 private _skipOwnerMassUpdateUntil; event Deposit( address indexed user, uint256 indexed pid, uint256 amount, address indexed to ); event Withdraw( address indexed user, uint256 indexed pid, uint256 amount, address indexed to ); event EmergencyWithdraw( address indexed user, uint256 indexed pid, uint256 amount, address indexed to ); event Harvest(address indexed user, uint256 indexed pid, uint256 amount); event LogPoolAddition( uint256 indexed pid, uint256 allocPoint, IERC20 indexed lpToken, IRewarder indexed rewarder ); event LogSetPool( uint256 indexed pid, uint256 allocPoint, IRewarder indexed rewarder, bool overwrite ); event LogUpdatePool( uint256 indexed pid, uint64 lastRewardTime, uint256 lpSupply, uint256 accGracePerShare ); event LogGracePerSecondAndEndTime(uint256 gracePerSecond, uint256 endTime); event RewarderExecFail(address rewarder, uint256 pid, address user); modifier onlyFountain(uint256 pid) { _requireMsg( msg.sender == archangel.getFountain(address(lpToken[pid])), "General", "not called by correct fountain" ); _; } modifier ownerMassUpdate() { if (block.timestamp > _skipOwnerMassUpdateUntil) massUpdatePoolsNonZero(); _; _skipOwnerMassUpdateUntil = block.timestamp; } /// @param _grace The GRACE token contract address. constructor(IERC20 _grace) public { GRACE = _grace; IAngelFactory _f = IAngelFactory(msg.sender); factory = _f; archangel = IArchangel(_f.archangel()); } /// @notice Returns the number of MCV2 pools. function poolLength() public view returns (uint256 pools) { pools = poolInfo.length; } function lastTimeRewardApplicable() public view returns (uint256) { return Math.min(block.timestamp, endTime); } /// @notice Add a new LP to the pool. Can only be called by the owner. /// DO NOT add the same LP token more than once. Rewards will be messed up if you do. /// @param allocPoint AP of the new pool. /// @param _lpToken Address of the LP ERC-20 token. /// @param _rewarder Address of the rewarder delegate. function add( uint256 allocPoint, IERC20 _lpToken, IRewarder _rewarder ) external onlyOwner ownerMassUpdate { uint256 pid = lpToken.length; totalAllocPoint = totalAllocPoint.add(allocPoint); lpToken.push(_lpToken); rewarder.push(_rewarder); poolInfo.push( PoolInfo({ allocPoint: allocPoint.to64(), lastRewardTime: block.timestamp.to64(), accGracePerShare: 0 }) ); emit LogPoolAddition(pid, allocPoint, _lpToken, _rewarder); ////////////////////////// New // Update pid in fountain IFountain fountain = IFountain(archangel.getFountain(address(_lpToken))); fountain.setPoolId(pid); } /// @notice Update the given pool's GRACE allocation point and `IRewarder` contract. Can only be called by the owner. /// @param _pid The index of the pool. See `poolInfo`. /// @param _allocPoint New AP of the pool. /// @param _rewarder Address of the rewarder delegate. /// @param overwrite True if _rewarder should be `set`. Otherwise `_rewarder` is ignored. function set( uint256 _pid, uint256 _allocPoint, IRewarder _rewarder, bool overwrite ) external onlyOwner ownerMassUpdate { updatePool(_pid); totalAllocPoint = totalAllocPoint.sub(poolInfo[_pid].allocPoint).add( _allocPoint ); poolInfo[_pid].allocPoint = _allocPoint.to64(); if (overwrite) { rewarder[_pid] = _rewarder; } emit LogSetPool( _pid, _allocPoint, overwrite ? _rewarder : rewarder[_pid], overwrite ); } /// @notice Add extra amount of GRACE to be distributed and the end time. Can only be called by the owner. /// @param _amount The extra amount of GRACE to be distributed. /// @param _endTime UNIX timestamp that indicates the end of the calculating period. function addGraceReward(uint256 _amount, uint256 _endTime) external onlyOwner ownerMassUpdate { _requireMsg( _amount > 0, "addGraceReward", "grace amount should be greater than 0" ); _requireMsg( _endTime > block.timestamp, "addGraceReward", "end time should be in the future" ); uint256 duration = _endTime.sub(block.timestamp); uint256 newGracePerSecond; if (block.timestamp >= endTime) { newGracePerSecond = _amount / duration; } else { uint256 remaining = endTime.sub(block.timestamp); uint256 leftover = remaining.mul(gracePerSecond); newGracePerSecond = leftover.add(_amount) / duration; } _requireMsg( newGracePerSecond <= type(uint128).max, "addGraceReward", "new grace per second exceeds uint128" ); gracePerSecond = newGracePerSecond; endTime = _endTime; emit LogGracePerSecondAndEndTime(gracePerSecond, endTime); GRACE.safeTransferFrom(msg.sender, address(this), _amount); } /// @notice Set the grace per second to be distributed. Can only be called by the owner. /// @param _gracePerSecond The amount of Grace to be distributed per second. function setGracePerSecond(uint256 _gracePerSecond, uint256 _endTime) external onlyOwner ownerMassUpdate { _requireMsg( _gracePerSecond <= type(uint128).max, "setGracePerSecond", "new grace per second exceeds uint128" ); _requireMsg( _endTime > block.timestamp, "setGracePerSecond", "end time should be in the future" ); uint256 duration = _endTime.sub(block.timestamp); uint256 rewardNeeded = _gracePerSecond.mul(duration); uint256 shortage; if (block.timestamp >= endTime) { shortage = rewardNeeded; } else { uint256 remaining = endTime.sub(block.timestamp); uint256 leftover = remaining.mul(gracePerSecond); if (rewardNeeded > leftover) shortage = rewardNeeded.sub(leftover); } gracePerSecond = _gracePerSecond; endTime = _endTime; emit LogGracePerSecondAndEndTime(gracePerSecond, endTime); if (shortage > 0) GRACE.safeTransferFrom(msg.sender, address(this), shortage); } /// @notice View function to see pending GRACE on frontend. /// @param _pid The index of the pool. See `poolInfo`. /// @param _user Address of user. /// @return pending GRACE reward for a given user. function pendingGrace(uint256 _pid, address _user) external view returns (uint256 pending) { PoolInfo memory pool = poolInfo[_pid]; UserInfo storage user = userInfo[_pid][_user]; uint256 accGracePerShare = pool.accGracePerShare; ////////////////////////// New // uint256 lpSupply = lpToken[_pid].balanceOf(address(this)); // Need to get the lpSupply from fountain IFountain fountain = IFountain(archangel.getFountain(address(lpToken[_pid]))); (, uint256 lpSupply) = fountain.angelInfo(address(this)); uint256 _lastTimeRewardApplicable = lastTimeRewardApplicable(); if ( lpSupply != 0 && pool.allocPoint > 0 && _lastTimeRewardApplicable > pool.lastRewardTime ) { uint256 time = _lastTimeRewardApplicable.sub(pool.lastRewardTime); uint256 graceReward = time.mul(gracePerSecond).mul(pool.allocPoint) / totalAllocPoint; accGracePerShare = accGracePerShare.add( graceReward.mul(ACC_GRACE_PRECISION) / lpSupply ); } pending = int256( user.amount.mul(accGracePerShare) / ACC_GRACE_PRECISION ) .sub(user.rewardDebt) .toUInt256(); } /// @notice Update reward variables for all pools with non-zero allocPoint. /// Be careful of gas spending! function massUpdatePoolsNonZero() public { uint256 len = poolLength(); for (uint256 i = 0; i < len; ++i) { if (poolInfo[i].allocPoint > 0) updatePool(i); } } /// @notice Update reward variables for all pools. Be careful of gas spending! /// @param pids Pool IDs of all to be updated. Make sure to update all active pools. function massUpdatePools(uint256[] memory pids) public { uint256 len = pids.length; for (uint256 i = 0; i < len; ++i) { updatePool(pids[i]); } } /// @notice Update reward variables for all pools and set the expire time for skipping `massUpdatePoolsNonZero()`. /// Be careful of gas spending! Can only be called by the owner. /// DO NOT use this function until `massUpdatePoolsNonZero()` reverts because of out of gas. /// If that is the case, try to update all pools first and then call onlyOwner function to set a correct state. /// @param pids Pool IDs of all to be updated. Make sure to update all active pools. function massUpdatePoolsAndSet(uint256[] calldata pids) external onlyOwner { massUpdatePools(pids); // Leave an hour for owner to be able to skip `massUpdatePoolsNonZero()` _skipOwnerMassUpdateUntil = block.timestamp.add(3600); } /// @notice Update reward variables of the given pool. /// @param pid The index of the pool. See `poolInfo`. /// @return pool Returns the pool that was updated. function updatePool(uint256 pid) public returns (PoolInfo memory pool) { pool = poolInfo[pid]; if (block.timestamp > pool.lastRewardTime) { ////////////////////////// New // uint256 lpSupply = lpToken[pid].balanceOf(address(this)); // Need to get the lpSupply from fountain IFountain fountain = IFountain(archangel.getFountain(address(lpToken[pid]))); (, uint256 lpSupply) = fountain.angelInfo(address(this)); uint256 _lastTimeRewardApplicable = lastTimeRewardApplicable(); // Only accumulate reward before end time if ( lpSupply > 0 && pool.allocPoint > 0 && _lastTimeRewardApplicable > pool.lastRewardTime ) { uint256 time = _lastTimeRewardApplicable.sub(pool.lastRewardTime); uint256 graceReward = time.mul(gracePerSecond).mul(pool.allocPoint) / totalAllocPoint; pool.accGracePerShare = pool.accGracePerShare.add( (graceReward.mul(ACC_GRACE_PRECISION) / lpSupply).to128() ); } pool.lastRewardTime = block.timestamp.to64(); poolInfo[pid] = pool; emit LogUpdatePool( pid, pool.lastRewardTime, lpSupply, pool.accGracePerShare ); } } /// @notice Deposit LP tokens to MCV2 for GRACE allocation. /// @param pid The index of the pool. See `poolInfo`. /// @param amount LP token amount to deposit. /// @param to The receiver of `amount` deposit benefit. function deposit( uint256 pid, uint256 amount, address to ) external onlyFountain(pid) { PoolInfo memory pool = updatePool(pid); UserInfo storage user = userInfo[pid][to]; // Effects user.amount = user.amount.add(amount); user.rewardDebt = user.rewardDebt.add( int256(amount.mul(pool.accGracePerShare) / ACC_GRACE_PRECISION) ); // Interactions IRewarder _rewarder = rewarder[pid]; if (address(_rewarder) != address(0)) { _rewarder.onGraceReward(pid, to, to, 0, user.amount); } ////////////////////////// New // Handle in fountain // lpToken[pid].safeTransferFrom(msg.sender, address(this), amount); // emit Deposit(msg.sender, pid, amount, to); emit Deposit(to, pid, amount, to); } /// @notice Withdraw LP tokens from MCV2. /// @param pid The index of the pool. See `poolInfo`. /// @param amount LP token amount to withdraw. /// @param to Receiver of the LP tokens. function withdraw( uint256 pid, uint256 amount, address to ) external onlyFountain(pid) { PoolInfo memory pool = updatePool(pid); ////////////////////////// New // Delegate by fountain // UserInfo storage user = userInfo[pid][msg.sender]; UserInfo storage user = userInfo[pid][to]; // Effects user.rewardDebt = user.rewardDebt.sub( int256(amount.mul(pool.accGracePerShare) / ACC_GRACE_PRECISION) ); user.amount = user.amount.sub(amount); // Interactions IRewarder _rewarder = rewarder[pid]; if (address(_rewarder) != address(0)) { ////////////////////////// New // Delegate by fountain // _rewarder.onGraceReward(pid, msg.sender, to, 0, user.amount); _rewarder.onGraceReward(pid, to, to, 0, user.amount); } ////////////////////////// New // Handle in fountain // lpToken[pid].safeTransfer(to, amount); // emit Withdraw(msg.sender, pid, amount, to); emit Withdraw(to, pid, amount, to); } /// @notice Harvest proceeds for transaction sender to `to`. /// @param pid The index of the pool. See `poolInfo`. /// @param to Receiver of GRACE rewards. function harvest( uint256 pid, address from, address to ) external onlyFountain(pid) { PoolInfo memory pool = updatePool(pid); ////////////////////////// New // Delegate by fountain // UserInfo storage user = userInfo[pid][msg.sender]; UserInfo storage user = userInfo[pid][from]; int256 accumulatedGrace = int256( user.amount.mul(pool.accGracePerShare) / ACC_GRACE_PRECISION ); uint256 _pendingGrace = accumulatedGrace.sub(user.rewardDebt).toUInt256(); // Effects user.rewardDebt = accumulatedGrace; // Interactions if (_pendingGrace != 0) { GRACE.safeTransfer(to, _pendingGrace); } IRewarder _rewarder = rewarder[pid]; if (address(_rewarder) != address(0)) { _rewarder.onGraceReward( pid, ////////////////////////// New // Delegate by fountain // msg.sender, from, to, _pendingGrace, user.amount ); } ////////////////////////// New // emit Harvest(msg.sender, pid, _pendingGrace); emit Harvest(from, pid, _pendingGrace); } /// @notice Withdraw without caring about rewards. EMERGENCY ONLY. /// @param pid The index of the pool. See `poolInfo`. /// @param to Receiver of the LP tokens. function emergencyWithdraw(uint256 pid, address to) external onlyFountain(pid) { ////////////////////////// New // Delegate by fountain // UserInfo storage user = userInfo[pid][msg.sender]; UserInfo storage user = userInfo[pid][to]; uint256 amount = user.amount; user.amount = 0; user.rewardDebt = 0; IRewarder _rewarder = rewarder[pid]; if (address(_rewarder) != address(0)) { ////////////////////////// New // Delegate by fountain // _rewarder.onGraceReward(pid, msg.sender, to, 0, 0); // Execution of emergencyWithdraw should never fail. Considering // the possibility of failure caused by rewarder execution, use // try/catch on rewarder execution with limited gas try _rewarder.onGraceReward{gas: 1000000}(pid, to, to, 0, 0) {} catch { emit RewarderExecFail(address(_rewarder), pid, to); } } // Note: transfer can fail or succeed if `amount` is zero. ////////////////////////// New // Handle in fountain // lpToken[pid].safeTransfer(to, amount); // emit EmergencyWithdraw(msg.sender, pid, amount, to); emit EmergencyWithdraw(to, pid, amount, to); } /// @notice Fetch the token from angel. Can only be called by owner. /// @param token The token address. /// @param amount The amount of token to be rescued. Replace by current balance if uint256(-1). /// @param to The receiver. /// @return The transferred amount. function rescueERC20( IERC20 token, uint256 amount, address to ) external onlyOwner returns (uint256) { if (amount == type(uint256).max) { amount = token.balanceOf(address(this)); } token.safeTransfer(to, amount); return amount; } } // File: contracts/Angel.sol pragma solidity 0.6.12; /// @title Manage the rewards and configuration. contract Angel is AngelBase, ERC20FlashLoan { modifier onlyArchangel() { _requireMsg( msg.sender == address(archangel), "general", "not from archangel" ); _; } constructor(IERC20 token, uint256 flashLoanFee) public AngelBase(token) ERC20FlashLoan(token, flashLoanFee) {} /// @notice Set the fee rate for flash loan. can only be set by Archangel. /// @param fee The fee rate. function setFlashLoanFee(uint256 fee) public override onlyArchangel { super.setFlashLoanFee(fee); } /// @notice Set the fee collector. Fee are transferred to Archangel after /// flash loan execution. function flashLoanFeeCollector() public view override returns (address) { return address(archangel); } } // File: contracts/AngelFactory.sol pragma solidity 0.6.12; /// @title The factory of angel. contract AngelFactory is ErrorMsg { using BoringERC20 for IERC20; using BoringMath for uint256; IArchangel public immutable archangel; mapping(Angel => IERC20) private _rewards; event Created(address to); constructor() public { archangel = IArchangel(msg.sender); } // Getters /// @notice Check if angel is valid. /// @param angel The angel to be verified. /// @return Is valid or not. function isValid(Angel angel) external view returns (bool) { return (address(_rewards[angel]) != address(0)); } /// @notice Get the reward token of angel. /// @param angel The angel address. /// @return The reward token address. function rewardOf(Angel angel) external view returns (IERC20) { return _rewards[angel]; } /// @notice Create the angel of given token as reward. Multiple angels for /// the same token is possible. Notice that angel with tokens that has /// floating amount (including Inflationary/Deflationary tokens, Interest /// tokens, Rebase tokens), might leads to error according to the design /// policy of angel. function create(IERC20 reward) external returns (Angel) { _requireMsg( address(reward) != address(0), "create", "reward is zero address" ); Angel newAngel = new Angel(reward, archangel.defaultFlashLoanFee()); _rewards[newAngel] = reward; newAngel.transferOwnership(msg.sender, true, false); emit Created(address(newAngel)); return newAngel; } } // File: contracts/libraries/interfaces/IERC3156.sol pragma solidity 0.6.12; /** * @dev Interface of the ERC3156 FlashBorrower, as defined in * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. * * _Available since v4.1._ */ interface IERC3156FlashBorrower { /** * @dev Receive a flash loan. * @param initiator The initiator of the loan. * @param token The loan currency. * @param amount The amount of tokens lent. * @param fee The additional amount of tokens to repay. * @param data Arbitrary data structure, intended to contain user-defined parameters. * @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan" */ function onFlashLoan( address initiator, address token, uint256 amount, uint256 fee, bytes calldata data ) external returns (bytes32); } // File: contracts/interfaces/IArchangel.sol pragma solidity 0.6.12; interface IArchangel { // Getters function angelFactory() external view returns (address); function fountainFactory() external view returns (address); function defaultFlashLoanFee() external view returns (uint256); function getFountain(address token) external view returns (address); function rescueERC20(address token, address from) external returns (uint256); function setDefaultFlashLoanFee(uint256 fee) external; } // File: contracts/Archangel.sol pragma solidity 0.6.12; /// @title Staking system manager contract Archangel is Ownable, ErrorMsg { using SafeERC20 for IERC20; AngelFactory public immutable angelFactory; FountainFactory public immutable fountainFactory; uint256 public defaultFlashLoanFee; uint256 public constant FEE_BASE = 1e4; constructor(uint256 _defaultFlashLoanFee) public { defaultFlashLoanFee = _defaultFlashLoanFee; angelFactory = new AngelFactory(); fountainFactory = new FountainFactory(); } // Getters /// @notice Get the fountain for given token. /// @param token The token to be queried. /// @return Fountain address. function getFountain(IERC20 token) external view returns (Fountain) { return fountainFactory.fountainOf(token); } /// @notice Fetch the token from fountain or archangel itself. Can /// only be called from owner. /// @param token The token to be fetched. /// @param from The fountain to be fetched. /// @return The token amount being fetched. function rescueERC20(IERC20 token, Fountain from) external onlyOwner returns (uint256) { if (fountainFactory.isValid(from)) { return from.rescueERC20(token, _msgSender()); } else { uint256 amount = token.balanceOf(address(this)); token.safeTransfer(_msgSender(), amount); return amount; } } /// @notice Set the default fee rate for flash loan. The default fee /// rate will be applied when fountain or angel is being created. Can /// only be set by owner. function setDefaultFlashLoanFee(uint256 fee) external onlyOwner { _requireMsg( fee <= FEE_BASE, "setDefaultFlashLoanFee", "fee rate exceeded" ); defaultFlashLoanFee = fee; } /// @notice Set the flash loan fee rate of angel or fountain. Can only /// be set by owner. /// @param lender The address of angel of fountain. /// @param fee The fee rate to be applied. function setFlashLoanFee(address lender, uint256 fee) external onlyOwner { IFlashLender(lender).setFlashLoanFee(fee); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"flashLoanFee","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Harvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"gracePerSecond","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"LogGracePerSecondAndEndTime","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocPoint","type":"uint256"},{"indexed":true,"internalType":"contract IERC20","name":"lpToken","type":"address"},{"indexed":true,"internalType":"contract IRewarder","name":"rewarder","type":"address"}],"name":"LogPoolAddition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocPoint","type":"uint256"},{"indexed":true,"internalType":"contract IRewarder","name":"rewarder","type":"address"},{"indexed":false,"internalType":"bool","name":"overwrite","type":"bool"}],"name":"LogSetPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"lastRewardTime","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"lpSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accGracePerShare","type":"uint256"}],"name":"LogUpdatePool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"rewarder","type":"address"},{"indexed":false,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"}],"name":"RewarderExecFail","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"FEE_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BASE_OFFSET","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GRACE","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"allocPoint","type":"uint256"},{"internalType":"contract IERC20","name":"_lpToken","type":"address"},{"internalType":"contract IRewarder","name":"_rewarder","type":"address"}],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_endTime","type":"uint256"}],"name":"addGraceReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"archangel","outputs":[{"internalType":"contract IArchangel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"calls","type":"bytes[]"},{"internalType":"bool","name":"revertOnFail","type":"bool"}],"name":"batch","outputs":[{"internalType":"bool[]","name":"successes","type":"bool[]"},{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"claimOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract IAngelFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"flashFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC3156FlashBorrower","name":"receiver","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashLoan","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"flashLoanFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flashLoanFeeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gracePerSecond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastTimeRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lendingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"lpToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"pids","type":"uint256[]"}],"name":"massUpdatePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"pids","type":"uint256[]"}],"name":"massUpdatePoolsAndSet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"massUpdatePoolsNonZero","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"maxFlashLoan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"pendingGrace","outputs":[{"internalType":"uint256","name":"pending","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Permit","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permitToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolInfo","outputs":[{"internalType":"uint128","name":"accGracePerShare","type":"uint128"},{"internalType":"uint64","name":"lastRewardTime","type":"uint64"},{"internalType":"uint64","name":"allocPoint","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolLength","outputs":[{"internalType":"uint256","name":"pools","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"rescueERC20","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewarder","outputs":[{"internalType":"contract IRewarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"contract IRewarder","name":"_rewarder","type":"address"},{"internalType":"bool","name":"overwrite","type":"bool"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"setFlashLoanFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gracePerSecond","type":"uint256"},{"internalType":"uint256","name":"_endTime","type":"uint256"}],"name":"setGracePerSecond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalAllocPoint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"},{"internalType":"bool","name":"direct","type":"bool"},{"internalType":"bool","name":"renounce","type":"bool"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"}],"name":"updatePool","outputs":[{"components":[{"internalType":"uint128","name":"accGracePerShare","type":"uint128"},{"internalType":"uint64","name":"lastRewardTime","type":"uint64"},{"internalType":"uint64","name":"allocPoint","type":"uint64"}],"internalType":"struct AngelBase.PoolInfo","name":"pool","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"int256","name":"rewardDebt","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101006040523480156200001257600080fd5b50604051620043343803806200433483398101604081905262000035916200018c565b600080546001600160a01b0319163390811782556040518492849284929091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3606081811b6001600160601b031916608052339081901b60c05260408051632e9a9b6560e21b81529051829163ba6a6d94916004808301926020929190829003018186803b158015620000cc57600080fd5b505afa158015620000e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000107919062000166565b60601b6001600160601b03191660a0525050612710811115620001475760405162461bcd60e51b81526004016200013e90620001bc565b60405180910390fd5b60609190911b6001600160601b03191660e052600a5550620002009050565b60006020828403121562000178578081fd5b81516200018581620001e7565b9392505050565b600080604083850312156200019f578081fd5b8251620001ac81620001e7565b6020939093015192949293505050565b602080825260119082015270199959481c985d1948195e18d959591959607a1b604082015260600190565b6001600160a01b0381168114620001fd57600080fd5b50565b60805160601c60a05160601c60c05160601c60e05160601c614093620002a1600039806114b852806115c0528061168452806116d452806117ac528061180152806121bc52806126b05250806124f45250806107a15280610ae25280610def52806110e45280611a8b5280611e0752806123d052806124c3528061273e5280612765525080610d7f5280611b5d528061216352806129fd52506140936000f3fe6080604052600436106102465760003560e01c80637c516e9411610139578063ba6a6d94116100b6578063d9d98ce41161007a578063d9d98ce41461066e578063e30c39781461068e578063e5cd6a15146106a3578063e92d0d5d146106b8578063ecefc705146106d8578063edbc8302146106ed57610246565b8063ba6a6d94146105ee578063c346253d14610603578063c45a015514610623578063d2423b5114610638578063d977a1961461065957610246565b80638dbdbe6d116100fd5780638dbdbe6d1461054b57806390a999ee1461056b57806393f1a40b1461058b578063aaaca558146105b9578063ab7de098146105ce57610246565b80637c516e94146104c157806380faa57d146104e157806387a4459b146104f657806388bba42f146105165780638da5cb5b1461053657610246565b80634847cdc8116101c75780635cffe9de1161018b5780635cffe9de14610414578063613255ab146104415780636e19a5cf1461046157806377662ffc1461048157806378ed5d1f146104a157610246565b80634847cdc8146103885780634c7848ab1461039d5780634e71e0c8146103b257806351eb05a6146103c757806357a5b58c146103f457610246565b8063137d29d91161020e578063137d29d9146102ed5780631526fe271461030f57806317caf6f11461033e5780632f940c70146103535780633197cbb61461037357610246565b806305cf35e31461024b5780630664567b14610276578063078dfbe714610296578063081e3eda146102b85780630ad58d2f146102cd575b600080fd5b34801561025757600080fd5b5061026061070d565b60405161026d9190613ebc565b60405180910390f35b34801561028257600080fd5b506102606102913660046135b5565b610713565b3480156102a257600080fd5b506102b66102b13660046131f7565b6109e7565b005b3480156102c457600080fd5b50610260610ad6565b3480156102d957600080fd5b506102b66102e836600461365e565b610adc565b3480156102f957600080fd5b50610302610d7d565b60405161026d9190613769565b34801561031b57600080fd5b5061032f61032a36600461359d565b610da1565b60405161026d93929190613e92565b34801561034a57600080fd5b50610260610de3565b34801561035f57600080fd5b506102b661036e3660046135b5565b610de9565b34801561037f57600080fd5b50610260610f80565b34801561039457600080fd5b50610260610f86565b3480156103a957600080fd5b506102b6610f8c565b3480156103be57600080fd5b506102b6610feb565b3480156103d357600080fd5b506103e76103e236600461359d565b611078565b60405161026d9190613e59565b34801561040057600080fd5b506102b661040f3660046132f4565b6113ea565b34801561042057600080fd5b5061043461042f366004613479565b61141c565b60405161026d919061392b565b34801561044d57600080fd5b5061026061045c3660046131bf565b6117a8565b34801561046d57600080fd5b506102b661047c3660046132b5565b61188c565b34801561048d57600080fd5b5061026061049c366004613443565b611905565b3480156104ad57600080fd5b506103026104bc36600461359d565b6119d7565b3480156104cd57600080fd5b506102b66104dc3660046133bc565b6119fe565b3480156104ed57600080fd5b50610260611a72565b34801561050257600080fd5b506102b66105113660046135e4565b611a85565b34801561052257600080fd5b506102b661053136600461368b565b611c65565b34801561054257600080fd5b50610302611df2565b34801561055757600080fd5b506102b661056636600461365e565b611e01565b34801561057757600080fd5b506102b661058636600461361a565b611f9c565b34801561059757600080fd5b506105ab6105a63660046135b5565b612196565b60405161026d929190613f04565b3480156105c557600080fd5b506103026121ba565b3480156105da57600080fd5b506102b66105e93660046135e4565b6121de565b3480156105fa57600080fd5b506103026124c1565b34801561060f57600080fd5b5061030261061e36600461359d565b6124e5565b34801561062f57600080fd5b506103026124f2565b61064b61064636600461326c565b612516565b60405161026d929190613891565b34801561066557600080fd5b506102606126a6565b34801561067a57600080fd5b50610260610689366004613241565b6126ac565b34801561069a57600080fd5b5061030261272d565b3480156106af57600080fd5b5061030261273c565b3480156106c457600080fd5b506102b66106d336600461359d565b612760565b3480156106e457600080fd5b506102606127f4565b3480156106f957600080fd5b506102b661070836600461361a565b6127fa565b60075481565b600061071d613157565b6002848154811061072a57fe5b600091825260208083206040805160608101825291909301546001600160801b0380821683526001600160401b03600160801b8304811684860152600160c01b90920490911682850152888552600583528385206001600160a01b03808a16875293529284208151600380549397509195941693927f00000000000000000000000000000000000000000000000000000000000000001691632118ab3091908a9081106107d357fe5b6000918252602090912001546040516001600160e01b031960e084901b168152610809916001600160a01b031690600401613769565b60206040518083038186803b15801561082157600080fd5b505afa158015610835573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085991906131db565b90506000816001600160a01b031663a2e655b3306040518263ffffffff1660e01b81526004016108899190613769565b604080518083038186803b1580156108a057600080fd5b505afa1580156108b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d8919061363b565b91505060006108e5611a72565b905081158015906109035750600086604001516001600160401b0316115b801561091b575085602001516001600160401b031681115b156109a757600061094287602001516001600160401b031683612a2f90919063ffffffff16565b9050600060065461097589604001516001600160401b031661096f60075486612a5290919063ffffffff16565b90612a52565b8161097c57fe5b0490506109a2846109928364e8d4a51000612a52565b8161099957fe5b88919004612a89565b955050505b600185015485546109da916109d59164e8d4a51000906109c79089612a52565b816109ce57fe5b0490612aac565b612af2565b9998505050505050505050565b6000546001600160a01b03163314610a1a5760405162461bcd60e51b8152600401610a1190613bfa565b60405180910390fd5b8115610ab5576001600160a01b038316151580610a345750805b610a505760405162461bcd60e51b8152600401610a1190613a7a565b600080546040516001600160a01b03808716939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0385166001600160a01b031991821617909155600180549091169055610ad1565b600180546001600160a01b0319166001600160a01b0385161790555b505050565b60025490565b82610c117f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632118ab3060038481548110610b1c57fe5b6000918252602090912001546040516001600160e01b031960e084901b168152610b52916001600160a01b031690600401613769565b60206040518083038186803b158015610b6a57600080fd5b505afa158015610b7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba291906131db565b6001600160a01b0316336001600160a01b0316146040518060400160405280600781526020016611d95b995c985b60ca1b8152506040518060400160405280601e81526020017f6e6f742063616c6c656420627920636f727265637420666f756e7461696e0000815250612b18565b610c19613157565b610c2285611078565b60008681526005602090815260408083206001600160a01b03881684529091529020815191925090610c7d9064e8d4a5100090610c699088906001600160801b0316612a52565b81610c7057fe5b6001840154919004612aac565b60018201558054610c8e9086612a2f565b8155600480546000919088908110610ca257fe5b6000918252602090912001546001600160a01b031690508015610d2857815460405163521c20cd60e11b81526001600160a01b0383169163a438419a91610cf5918b918a91829160009190600401613ec5565b600060405180830381600087803b158015610d0f57600080fd5b505af1158015610d23573d6000803e3d6000fd5b505050505b846001600160a01b031687866001600160a01b03167f8166bf25f8a2b7ed3c85049207da4358d16edbed977d23fa2ee6f0dde3ec213289604051610d6c9190613ebc565b60405180910390a450505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60028181548110610dae57fe5b6000918252602090912001546001600160801b03811691506001600160401b03600160801b8204811691600160c01b90041683565b60065481565b81610e297f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632118ab3060038481548110610b1c57fe5b60008381526005602090815260408083206001600160a01b03861684529091528120805482825560018201839055600480549293919287908110610e6957fe5b6000918252602090912001546001600160a01b031690508015610f2c5760405163521c20cd60e11b81526001600160a01b0382169063a438419a90620f424090610ec0908a908a9081906000908190600401613ec5565b600060405180830381600088803b158015610eda57600080fd5b5087f193505050508015610eec575060015b610f2c577f2a9d486215ebc1121559bcb611baa52d007f33dc3e739e718274daba711328e3818787604051610f239392919061386e565b60405180910390a15b846001600160a01b031686866001600160a01b03167f2cac5e20e1541d836381527a43f651851e302817b71dc8e810284e69210c1c6b85604051610f709190613ebc565b60405180910390a4505050505050565b60085481565b600a5481565b6000610f96610ad6565b905060005b81811015610fe757600060028281548110610fb257fe5b600091825260209091200154600160c01b90046001600160401b03161115610fdf57610fdd81611078565b505b600101610f9b565b5050565b6001546001600160a01b03163381146110165760405162461bcd60e51b8152600401610a1190613c91565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b611080613157565b6002828154811061108d57fe5b60009182526020918290206040805160608101825292909101546001600160801b03811683526001600160401b03600160801b82048116948401859052600160c01b909104169082015291504211156113e55760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632118ab306003858154811061111e57fe5b6000918252602090912001546040516001600160e01b031960e084901b168152611154916001600160a01b031690600401613769565b60206040518083038186803b15801561116c57600080fd5b505afa158015611180573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a491906131db565b90506000816001600160a01b031663a2e655b3306040518263ffffffff1660e01b81526004016111d49190613769565b604080518083038186803b1580156111eb57600080fd5b505afa1580156111ff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611223919061363b565b9150506000611230611a72565b905060008211801561124f5750600084604001516001600160401b0316115b8015611267575083602001516001600160401b031681115b1561130757600061128e85602001516001600160401b031683612a2f90919063ffffffff16565b905060006006546112bb87604001516001600160401b031661096f60075486612a5290919063ffffffff16565b816112c257fe5b0490506112f96112e8856112db8464e8d4a51000612a52565b816112e257fe5b04612b27565b87516001600160801b031690612b50565b6001600160801b0316865250505b61131042612b7f565b6001600160401b03166020850152600280548591908790811061132f57fe5b6000918252602091829020835191018054848401516040958601516001600160801b03199092166001600160801b039094169390931767ffffffffffffffff60801b1916600160801b6001600160401b0394851602176001600160c01b0316600160c01b93909116929092029190911790558501518551915187927f0fc9545022a542541ad085d091fb09a2ab36fee366a4576ab63714ea907ad353926113d99290918791613f12565b60405180910390a25050505b919050565b805160005b81811015610ad15761141383828151811061140657fe5b6020026020010151611078565b506001016113ef565b600080856001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161144b9190613769565b60206040518083038186803b15801561146357600080fd5b505afa158015611477573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149b91906133a4565b905060006114a987876126ac565b90506114df6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168988612ba8565b6040516323e30c8b60e01b81527f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9906001600160a01b038a16906323e30c8b906115379033908c908c9088908d908d9060040161377d565b602060405180830381600087803b15801561155157600080fd5b505af1158015611565573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158991906133a4565b146115a65760405162461bcd60e51b8152600401610a119061399d565b604051636eb1769f60e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063dd62ed3e906115f7908c9030906004016137d6565b60206040518083038186803b15801561160f57600080fd5b505afa158015611623573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061164791906133a4565b905060006116558884612bfe565b9050808210156116775760405162461bcd60e51b8152600401610a1190613c2f565b6116ac6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168b3084612c23565b60006116b661273c565b90506001600160a01b038116156116fb576116fb6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168286612ba8565b6040516370a0823160e01b815285906001600160a01b038c16906370a0823190611729903090600401613769565b60206040518083038186803b15801561174157600080fd5b505afa158015611755573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177991906133a4565b10156117975760405162461bcd60e51b8152600401610a1190613cfd565b5060019a9950505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146117ea576000611886565b6040516370a0823160e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190611836903090600401613769565b60206040518083038186803b15801561184e57600080fd5b505afa158015611862573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188691906133a4565b92915050565b6000546001600160a01b031633146118b65760405162461bcd60e51b8152600401610a1190613bfa565b6118f28282808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506113ea92505050565b6118fe42610e10612a89565b6009555050565b600080546001600160a01b031633146119305760405162461bcd60e51b8152600401610a1190613bfa565b6000198314156119b9576040516370a0823160e01b81526001600160a01b038516906370a0823190611966903090600401613769565b60206040518083038186803b15801561197e57600080fd5b505afa158015611992573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119b691906133a4565b92505b6119cd6001600160a01b0385168385612c4a565b50815b9392505050565b600381815481106119e457fe5b6000918252602090912001546001600160a01b0316905081565b60405163d505accf60e01b81526001600160a01b0389169063d505accf90611a36908a908a908a908a908a908a908a90600401613814565b600060405180830381600087803b158015611a5057600080fd5b505af1158015611a64573d6000803e3d6000fd5b505050505050505050505050565b6000611a8042600854612d38565b905090565b82611ac57f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632118ab3060038481548110610b1c57fe5b611acd613157565b611ad685611078565b60008681526005602090815260408083206001600160a01b0389168452909152812082518154939450909264e8d4a5100091611b1b91906001600160801b0316612a52565b81611b2257fe5b0490506000611b416109d5846001015484612aac90919063ffffffff16565b6001840183905590508015611b8457611b846001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168783612c4a565b600060048981548110611b9357fe5b6000918252602090912001546001600160a01b031690508015611c1857835460405163521c20cd60e11b81526001600160a01b0383169163a438419a91611be5918d918d918d91899190600401613ec5565b600060405180830381600087803b158015611bff57600080fd5b505af1158015611c13573d6000803e3d6000fd5b505050505b88886001600160a01b03167f71bab65ced2e5750775a0613be067df48ef06cf92a496ebf7663ae066092495484604051611c529190613ebc565b60405180910390a3505050505050505050565b6000546001600160a01b03163314611c8f5760405162461bcd60e51b8152600401610a1190613bfa565b600954421115611ca157611ca1610f8c565b611caa84611078565b50611cea83611ce460028781548110611cbf57fe5b60009182526020909120015460065490600160c01b90046001600160401b0316612a2f565b90612a89565b600655611cf683612b7f565b60028581548110611d0357fe5b9060005260206000200160000160186101000a8154816001600160401b0302191690836001600160401b031602179055508015611d77578160048581548110611d4857fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b80611da35760048481548110611d8957fe5b6000918252602090912001546001600160a01b0316611da5565b815b6001600160a01b0316847f95895a6ab1df54420d241b55243258a33e61b2194db66c1179ec521aae8e18658584604051611de0929190613ef4565b60405180910390a35050426009555050565b6000546001600160a01b031681565b82611e417f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632118ab3060038481548110610b1c57fe5b611e49613157565b611e5285611078565b60008681526005602090815260408083206001600160a01b03881684529091529020805491925090611e849086612a89565b81558151611ebb9064e8d4a5100090611ea79088906001600160801b0316612a52565b81611eae57fe5b6001840154919004612d4e565b8160010181905550600060048781548110611ed257fe5b6000918252602090912001546001600160a01b031690508015611f5857815460405163521c20cd60e11b81526001600160a01b0383169163a438419a91611f25918b918a91829160009190600401613ec5565b600060405180830381600087803b158015611f3f57600080fd5b505af1158015611f53573d6000803e3d6000fd5b505050505b846001600160a01b031687866001600160a01b03167f02d7e648dd130fc184d383e55bb126ac4c9c60e8f94bf05acdf557ba2d540b4789604051610d6c9190613ebc565b6000546001600160a01b03163314611fc65760405162461bcd60e51b8152600401610a1190613bfa565b600954421115611fd857611fd8610f8c565b6120306001600160801b038016831115604051806040016040528060118152602001701cd95d11dc9858d954195c94d958dbdb99607a1b81525060405180606001604052806024815260200161401560249139612b18565b61209b428211604051806040016040528060118152602001701cd95d11dc9858d954195c94d958dbdb99607a1b8152506040518060400160405280602081526020017f656e642074696d652073686f756c6420626520696e2074686520667574757265815250612b18565b60006120a78242612a2f565b905060006120b58483612a52565b9050600060085442106120c957508061210c565b6008546000906120d99042612a2f565b905060006120f260075483612a5290919063ffffffff16565b905080841115612109576121068482612a2f565b92505b50505b600785905560088490556040517fc9cd3a88c1375a3ef18d5f395f9ab5c9f317945ab2ffc76b5153bbc72ecaf8cb906121489087908790613f04565b60405180910390a1801561218b5761218b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333084612d94565b505042600955505050565b60056020908152600092835260408084209091529082529020805460019091015482565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b031633146122085760405162461bcd60e51b8152600401610a1190613bfa565b60095442111561221a5761221a610f8c565b60035460065461222a9085612a89565b6006556003805460018181019092557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0180546001600160a01b038087166001600160a01b03199283161790925560048054938401815560009081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b9093018054928616929091169190911790556040805160608101909152908152600290602081016122d742612b7f565b6001600160401b031681526020016122ee87612b7f565b6001600160401b0390811690915282546001810184556000938452602093849020835191018054948401516040948501518416600160c01b026001600160c01b0391909416600160801b0267ffffffffffffffff60801b196001600160801b039094166001600160801b03199097169690961792909216949094171617909155516001600160a01b03808416919085169083907f81ee0f8c5c46e2cb41984886f77a84181724abb86c32a5f6de539b07509d45e5906123ae908990613ebc565b60405180910390a46040516302118ab360e41b81526000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632118ab3090612405908790600401613769565b60206040518083038186803b15801561241d57600080fd5b505afa158015612431573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061245591906131db565b604051632b1e004b60e21b81529091506001600160a01b0382169063ac78012c90612484908590600401613ebc565b600060405180830381600087803b15801561249e57600080fd5b505af11580156124b2573d6000803e3d6000fd5b50504260095550505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600481815481106119e457fe5b7f000000000000000000000000000000000000000000000000000000000000000081565b606080836001600160401b038111801561252f57600080fd5b50604051908082528060200260200182016040528015612559578160200160208202803683370190505b509150836001600160401b038111801561257257600080fd5b506040519080825280602002602001820160405280156125a657816020015b60608152602001906001900390816125915790505b50905060005b8481101561269d5760006060308888858181106125c557fe5b90506020028101906125d79190613f3c565b6040516125e5929190613700565b600060405180830381855af49150503d8060008114612620576040519150601f19603f3d011682016040523d82523d6000602084013e612625565b606091505b50915091508180612634575085155b61263d82612e85565b9061265b5760405162461bcd60e51b8152600401610a119190613936565b508185848151811061266957fe5b6020026020010190151590811515815250508084848151811061268857fe5b602090810291909101015250506001016125ac565b50935093915050565b61138881565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316146126ff5760405162461bcd60e51b8152600401610a1190613b26565b6119d061271061272760028204612721600a5487612ee590919063ffffffff16565b90612bfe565b90612f1f565b6001546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000090565b6127e87f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316336001600160a01b0316146040518060400160405280600781526020016619d95b995c985b60ca1b815250604051806040016040528060128152602001711b9bdd08199c9bdb48185c98da185b99d95b60721b815250612b18565b6127f181612f51565b50565b61271081565b6000546001600160a01b031633146128245760405162461bcd60e51b8152600401610a1190613bfa565b60095442111561283657612836610f8c565b612882600083116040518060400160405280600e81526020016d18591911dc9858d954995dd85c9960921b81525060405180606001604052806025815260200161403960259139612b18565b6128ea4282116040518060400160405280600e81526020016d18591911dc9858d954995dd85c9960921b8152506040518060400160405280602081526020017f656e642074696d652073686f756c6420626520696e2074686520667574757265815250612b18565b60006128f68242612a2f565b9050600060085442106129145781848161290c57fe5b049050612957565b6008546000906129249042612a2f565b9050600061293d60075483612a5290919063ffffffff16565b90508361294a8288612a89565b8161295157fe5b04925050505b6129ac6001600160801b0380168211156040518060400160405280600e81526020016d18591911dc9858d954995dd85c9960921b81525060405180606001604052806024815260200161401560249139612b18565b600781905560088390556040517fc9cd3a88c1375a3ef18d5f395f9ab5c9f317945ab2ffc76b5153bbc72ecaf8cb906129e89083908690613f04565b60405180910390a1612a256001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333087612d94565b5050426009555050565b808203828111156118865760405162461bcd60e51b8152600401610a1190613949565b6000811580612a6d57505080820282828281612a6a57fe5b04145b6118865760405162461bcd60e51b8152600401610a1190613e22565b818101818110156118865760405162461bcd60e51b8152600401610a1190613b82565b6000818303818312801590612ac15750838113155b80612ad65750600083128015612ad657508381135b6119d05760405162461bcd60e51b8152600401610a1190613d5f565b600080821215612b145760405162461bcd60e51b8152600401610a1190613978565b5090565b82610ad157610ad18282612f78565b60006001600160801b03821115612b145760405162461bcd60e51b8152600401610a1190613b4b565b8181016001600160801b0380831690821610156118865760405162461bcd60e51b8152600401610a1190613b82565b60006001600160401b03821115612b145760405162461bcd60e51b8152600401610a1190613cc6565b610ad18363a9059cbb60e01b8484604051602401612bc7929190613855565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612fb1565b6000828201838110156119d05760405162461bcd60e51b8152600401610a1190613a02565b612c44846323b872dd60e01b858585604051602401612bc7939291906137f0565b50505050565b60006060846001600160a01b031663a9059cbb8585604051602401612c70929190613855565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051612ca99190613710565b6000604051808303816000865af19150503d8060008114612ce6576040519150601f19603f3d011682016040523d82523d6000602084013e612ceb565b606091505b5091509150818015612d15575080511580612d15575080806020019051810190612d159190613388565b612d315760405162461bcd60e51b8152600401610a11906139cb565b5050505050565b6000818310612d4757816119d0565b5090919050565b6000828201818312801590612d635750838112155b80612d785750600083128015612d7857508381125b6119d05760405162461bcd60e51b8152600401610a1190613a39565b60006060856001600160a01b03166323b872dd868686604051602401612dbc939291906137f0565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051612df59190613710565b6000604051808303816000865af19150503d8060008114612e32576040519150601f19603f3d011682016040523d82523d6000602084013e612e37565b606091505b5091509150818015612e61575080511580612e61575080806020019051810190612e619190613388565b612e7d5760405162461bcd60e51b8152600401610a1190613da3565b505050505050565b6060604482511015612ecb575060408051808201909152601d81527f5472616e73616374696f6e2072657665727465642073696c656e746c7900000060208201526113e5565b600482019150818060200190518101906118869190613512565b600082612ef457506000611886565b82820282848281612f0157fe5b04146119d05760405162461bcd60e51b8152600401610a1190613bb9565b6000808211612f405760405162461bcd60e51b8152600401610a1190613aef565b818381612f4957fe5b049392505050565b612710811115612f735760405162461bcd60e51b8152600401610a1190613c66565b600a55565b8181604051602001612f8b92919061372c565b60408051601f198184030181529082905262461bcd60e51b8252610a1191600401613936565b6060613006826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166130409092919063ffffffff16565b805190915015610ad157808060200190518101906130249190613388565b610ad15760405162461bcd60e51b8152600401610a1190613dd8565b606061304f8484600085613057565b949350505050565b6060824710156130795760405162461bcd60e51b8152600401610a1190613aa9565b61308285613118565b61309e5760405162461bcd60e51b8152600401610a1190613d28565b60006060866001600160a01b031685876040516130bb9190613710565b60006040518083038185875af1925050503d80600081146130f8576040519150601f19603f3d011682016040523d82523d6000602084013e6130fd565b606091505b509150915061310d82828661311e565b979650505050505050565b3b151590565b6060831561312d5750816119d0565b82511561313d5782518084602001fd5b8160405162461bcd60e51b8152600401610a119190613936565b604080516060810182526000808252602082018190529181019190915290565b60008083601f840112613188578182fd5b5081356001600160401b0381111561319e578182fd5b60208301915083602080830285010111156131b857600080fd5b9250929050565b6000602082840312156131d0578081fd5b81356119d081613ff1565b6000602082840312156131ec578081fd5b81516119d081613ff1565b60008060006060848603121561320b578182fd5b833561321681613ff1565b9250602084013561322681614006565b9150604084013561323681614006565b809150509250925092565b60008060408385031215613253578182fd5b823561325e81613ff1565b946020939093013593505050565b600080600060408486031215613280578283fd5b83356001600160401b03811115613295578384fd5b6132a186828701613177565b909450925050602084013561323681614006565b600080602083850312156132c7578182fd5b82356001600160401b038111156132dc578283fd5b6132e885828601613177565b90969095509350505050565b60006020808385031215613306578182fd5b82356001600160401b0381111561331b578283fd5b8301601f8101851361332b578283fd5b803561333e61333982613fa6565b613f80565b818152838101908385018584028501860189101561335a578687fd5b8694505b8385101561337c57803583526001949094019391850191850161335e565b50979650505050505050565b600060208284031215613399578081fd5b81516119d081614006565b6000602082840312156133b5578081fd5b5051919050565b600080600080600080600080610100898b0312156133d8578586fd5b88356133e381613ff1565b975060208901356133f381613ff1565b9650604089013561340381613ff1565b9550606089013594506080890135935060a089013560ff81168114613426578384fd5b979a969950949793969295929450505060c08201359160e0013590565b600080600060608486031215613457578081fd5b833561346281613ff1565b925060208401359150604084013561323681613ff1565b600080600080600060808688031215613490578283fd5b853561349b81613ff1565b945060208601356134ab81613ff1565b93506040860135925060608601356001600160401b03808211156134cd578283fd5b818801915088601f8301126134e0578283fd5b8135818111156134ee578384fd5b8960208285010111156134ff578384fd5b9699959850939650602001949392505050565b600060208284031215613523578081fd5b81516001600160401b0380821115613539578283fd5b818401915084601f83011261354c578283fd5b81518181111561355a578384fd5b61356d601f8201601f1916602001613f80565b9150808252856020828501011115613583578384fd5b613594816020840160208601613fc5565b50949350505050565b6000602082840312156135ae578081fd5b5035919050565b600080604083850312156135c7578182fd5b8235915060208301356135d981613ff1565b809150509250929050565b6000806000606084860312156135f8578081fd5b83359250602084013561360a81613ff1565b9150604084013561323681613ff1565b6000806040838503121561362c578182fd5b50508035926020909101359150565b6000806040838503121561364d578182fd5b505080516020909101519092909150565b600080600060608486031215613672578081fd5b8335925060208401359150604084013561323681613ff1565b600080600080608085870312156136a0578182fd5b843593506020850135925060408501356136b981613ff1565b915060608501356136c981614006565b939692955090935050565b600081518084526136ec816020860160208601613fc5565b601f01601f19169290920160200192915050565b6000828483379101908152919050565b60008251613722818460208701613fc5565b9190910192915050565b6000835161373e818460208801613fc5565b6101d160f51b908301908152835161375d816002840160208801613fc5565b01600201949350505050565b6001600160a01b0391909116815260200190565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c084013781830160c090810191909152601f909201601f1916010195945050505050565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b604080825283519082018190526000906020906060840190828701845b828110156138cc5781511515845292840192908401906001016138ae565b505050838103828501528085516138e38184613ebc565b91508192508381028201848801865b8381101561391c57858303855261390a8383516136d4565b948701949250908601906001016138f2565b50909998505050505050505050565b901515815260200190565b6000602082526119d060208301846136d4565b602080825260159082015274426f72696e674d6174683a20556e646572666c6f7760581b604082015260600190565b6020808252600b908201526a0496e7465676572203c20360ac1b604082015260600190565b602080825260149082015273696e76616c69642072657475726e2076616c756560601b604082015260600190565b6020808252601c908201527f426f72696e6745524332303a205472616e73666572206661696c656400000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526021908201527f5369676e6564536166654d6174683a206164646974696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252601590820152744f776e61626c653a207a65726f206164647265737360581b604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b6020808252600b908201526a3bb937b733903a37b5b2b760a91b604082015260600190565b6020808252601c908201527f426f72696e674d6174683a2075696e74313238204f766572666c6f7700000000604082015260600190565b60208082526018908201527f426f72696e674d6174683a20416464204f766572666c6f770000000000000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601f908201527f616c6c6f77616e636520646f6573206e6f7420616c6c6f7720726566756e6400604082015260600190565b602080825260119082015270199959481c985d1948195e18d959591959607a1b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c657220213d2070656e64696e67206f776e6572604082015260600190565b6020808252601b908201527f426f72696e674d6174683a2075696e743634204f766572666c6f770000000000604082015260600190565b60208082526011908201527018985b185b98d948191958dc99585cd959607a1b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b60208082526024908201527f5369676e6564536166654d6174683a207375627472616374696f6e206f766572604082015263666c6f7760e01b606082015260800190565b6020808252818101527f426f72696e6745524332303a205472616e7366657246726f6d206661696c6564604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526018908201527f426f72696e674d6174683a204d756c204f766572666c6f770000000000000000604082015260600190565b81516001600160801b031681526020808301516001600160401b0390811691830191909152604092830151169181019190915260600190565b6001600160801b039390931683526001600160401b03918216602084015216604082015260600190565b90815260200190565b9485526001600160a01b0393841660208601529190921660408401526060830191909152608082015260a00190565b9182521515602082015260400190565b918252602082015260400190565b6001600160401b0393909316835260208301919091526001600160801b0316604082015260600190565b6000808335601e19843603018112613f52578283fd5b8301803591506001600160401b03821115613f6b578283fd5b6020019150368190038213156131b857600080fd5b6040518181016001600160401b0381118282101715613f9e57600080fd5b604052919050565b60006001600160401b03821115613fbb578081fd5b5060209081020190565b60005b83811015613fe0578181015183820152602001613fc8565b83811115612c445750506000910152565b6001600160a01b03811681146127f157600080fd5b80151581146127f157600080fdfe6e657720677261636520706572207365636f6e6420657863656564732075696e74313238677261636520616d6f756e742073686f756c642062652067726561746572207468616e2030a2646970667358221220b858822616d66b761153f19064c8efe7f6a943c1eb332414fe76cb7151fad82564736f6c634300060c00330000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12700000000000000000000000000000000000000000000000000000000000000009
Deployed Bytecode
0x6080604052600436106102465760003560e01c80637c516e9411610139578063ba6a6d94116100b6578063d9d98ce41161007a578063d9d98ce41461066e578063e30c39781461068e578063e5cd6a15146106a3578063e92d0d5d146106b8578063ecefc705146106d8578063edbc8302146106ed57610246565b8063ba6a6d94146105ee578063c346253d14610603578063c45a015514610623578063d2423b5114610638578063d977a1961461065957610246565b80638dbdbe6d116100fd5780638dbdbe6d1461054b57806390a999ee1461056b57806393f1a40b1461058b578063aaaca558146105b9578063ab7de098146105ce57610246565b80637c516e94146104c157806380faa57d146104e157806387a4459b146104f657806388bba42f146105165780638da5cb5b1461053657610246565b80634847cdc8116101c75780635cffe9de1161018b5780635cffe9de14610414578063613255ab146104415780636e19a5cf1461046157806377662ffc1461048157806378ed5d1f146104a157610246565b80634847cdc8146103885780634c7848ab1461039d5780634e71e0c8146103b257806351eb05a6146103c757806357a5b58c146103f457610246565b8063137d29d91161020e578063137d29d9146102ed5780631526fe271461030f57806317caf6f11461033e5780632f940c70146103535780633197cbb61461037357610246565b806305cf35e31461024b5780630664567b14610276578063078dfbe714610296578063081e3eda146102b85780630ad58d2f146102cd575b600080fd5b34801561025757600080fd5b5061026061070d565b60405161026d9190613ebc565b60405180910390f35b34801561028257600080fd5b506102606102913660046135b5565b610713565b3480156102a257600080fd5b506102b66102b13660046131f7565b6109e7565b005b3480156102c457600080fd5b50610260610ad6565b3480156102d957600080fd5b506102b66102e836600461365e565b610adc565b3480156102f957600080fd5b50610302610d7d565b60405161026d9190613769565b34801561031b57600080fd5b5061032f61032a36600461359d565b610da1565b60405161026d93929190613e92565b34801561034a57600080fd5b50610260610de3565b34801561035f57600080fd5b506102b661036e3660046135b5565b610de9565b34801561037f57600080fd5b50610260610f80565b34801561039457600080fd5b50610260610f86565b3480156103a957600080fd5b506102b6610f8c565b3480156103be57600080fd5b506102b6610feb565b3480156103d357600080fd5b506103e76103e236600461359d565b611078565b60405161026d9190613e59565b34801561040057600080fd5b506102b661040f3660046132f4565b6113ea565b34801561042057600080fd5b5061043461042f366004613479565b61141c565b60405161026d919061392b565b34801561044d57600080fd5b5061026061045c3660046131bf565b6117a8565b34801561046d57600080fd5b506102b661047c3660046132b5565b61188c565b34801561048d57600080fd5b5061026061049c366004613443565b611905565b3480156104ad57600080fd5b506103026104bc36600461359d565b6119d7565b3480156104cd57600080fd5b506102b66104dc3660046133bc565b6119fe565b3480156104ed57600080fd5b50610260611a72565b34801561050257600080fd5b506102b66105113660046135e4565b611a85565b34801561052257600080fd5b506102b661053136600461368b565b611c65565b34801561054257600080fd5b50610302611df2565b34801561055757600080fd5b506102b661056636600461365e565b611e01565b34801561057757600080fd5b506102b661058636600461361a565b611f9c565b34801561059757600080fd5b506105ab6105a63660046135b5565b612196565b60405161026d929190613f04565b3480156105c557600080fd5b506103026121ba565b3480156105da57600080fd5b506102b66105e93660046135e4565b6121de565b3480156105fa57600080fd5b506103026124c1565b34801561060f57600080fd5b5061030261061e36600461359d565b6124e5565b34801561062f57600080fd5b506103026124f2565b61064b61064636600461326c565b612516565b60405161026d929190613891565b34801561066557600080fd5b506102606126a6565b34801561067a57600080fd5b50610260610689366004613241565b6126ac565b34801561069a57600080fd5b5061030261272d565b3480156106af57600080fd5b5061030261273c565b3480156106c457600080fd5b506102b66106d336600461359d565b612760565b3480156106e457600080fd5b506102606127f4565b3480156106f957600080fd5b506102b661070836600461361a565b6127fa565b60075481565b600061071d613157565b6002848154811061072a57fe5b600091825260208083206040805160608101825291909301546001600160801b0380821683526001600160401b03600160801b8304811684860152600160c01b90920490911682850152888552600583528385206001600160a01b03808a16875293529284208151600380549397509195941693927f000000000000000000000000f40388b593efb236d1ab314a6aa969f9487890d81691632118ab3091908a9081106107d357fe5b6000918252602090912001546040516001600160e01b031960e084901b168152610809916001600160a01b031690600401613769565b60206040518083038186803b15801561082157600080fd5b505afa158015610835573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085991906131db565b90506000816001600160a01b031663a2e655b3306040518263ffffffff1660e01b81526004016108899190613769565b604080518083038186803b1580156108a057600080fd5b505afa1580156108b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d8919061363b565b91505060006108e5611a72565b905081158015906109035750600086604001516001600160401b0316115b801561091b575085602001516001600160401b031681115b156109a757600061094287602001516001600160401b031683612a2f90919063ffffffff16565b9050600060065461097589604001516001600160401b031661096f60075486612a5290919063ffffffff16565b90612a52565b8161097c57fe5b0490506109a2846109928364e8d4a51000612a52565b8161099957fe5b88919004612a89565b955050505b600185015485546109da916109d59164e8d4a51000906109c79089612a52565b816109ce57fe5b0490612aac565b612af2565b9998505050505050505050565b6000546001600160a01b03163314610a1a5760405162461bcd60e51b8152600401610a1190613bfa565b60405180910390fd5b8115610ab5576001600160a01b038316151580610a345750805b610a505760405162461bcd60e51b8152600401610a1190613a7a565b600080546040516001600160a01b03808716939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0385166001600160a01b031991821617909155600180549091169055610ad1565b600180546001600160a01b0319166001600160a01b0385161790555b505050565b60025490565b82610c117f000000000000000000000000f40388b593efb236d1ab314a6aa969f9487890d86001600160a01b0316632118ab3060038481548110610b1c57fe5b6000918252602090912001546040516001600160e01b031960e084901b168152610b52916001600160a01b031690600401613769565b60206040518083038186803b158015610b6a57600080fd5b505afa158015610b7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba291906131db565b6001600160a01b0316336001600160a01b0316146040518060400160405280600781526020016611d95b995c985b60ca1b8152506040518060400160405280601e81526020017f6e6f742063616c6c656420627920636f727265637420666f756e7461696e0000815250612b18565b610c19613157565b610c2285611078565b60008681526005602090815260408083206001600160a01b03881684529091529020815191925090610c7d9064e8d4a5100090610c699088906001600160801b0316612a52565b81610c7057fe5b6001840154919004612aac565b60018201558054610c8e9086612a2f565b8155600480546000919088908110610ca257fe5b6000918252602090912001546001600160a01b031690508015610d2857815460405163521c20cd60e11b81526001600160a01b0383169163a438419a91610cf5918b918a91829160009190600401613ec5565b600060405180830381600087803b158015610d0f57600080fd5b505af1158015610d23573d6000803e3d6000fd5b505050505b846001600160a01b031687866001600160a01b03167f8166bf25f8a2b7ed3c85049207da4358d16edbed977d23fa2ee6f0dde3ec213289604051610d6c9190613ebc565b60405180910390a450505050505050565b7f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf127081565b60028181548110610dae57fe5b6000918252602090912001546001600160801b03811691506001600160401b03600160801b8204811691600160c01b90041683565b60065481565b81610e297f000000000000000000000000f40388b593efb236d1ab314a6aa969f9487890d86001600160a01b0316632118ab3060038481548110610b1c57fe5b60008381526005602090815260408083206001600160a01b03861684529091528120805482825560018201839055600480549293919287908110610e6957fe5b6000918252602090912001546001600160a01b031690508015610f2c5760405163521c20cd60e11b81526001600160a01b0382169063a438419a90620f424090610ec0908a908a9081906000908190600401613ec5565b600060405180830381600088803b158015610eda57600080fd5b5087f193505050508015610eec575060015b610f2c577f2a9d486215ebc1121559bcb611baa52d007f33dc3e739e718274daba711328e3818787604051610f239392919061386e565b60405180910390a15b846001600160a01b031686866001600160a01b03167f2cac5e20e1541d836381527a43f651851e302817b71dc8e810284e69210c1c6b85604051610f709190613ebc565b60405180910390a4505050505050565b60085481565b600a5481565b6000610f96610ad6565b905060005b81811015610fe757600060028281548110610fb257fe5b600091825260209091200154600160c01b90046001600160401b03161115610fdf57610fdd81611078565b505b600101610f9b565b5050565b6001546001600160a01b03163381146110165760405162461bcd60e51b8152600401610a1190613c91565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b611080613157565b6002828154811061108d57fe5b60009182526020918290206040805160608101825292909101546001600160801b03811683526001600160401b03600160801b82048116948401859052600160c01b909104169082015291504211156113e55760007f000000000000000000000000f40388b593efb236d1ab314a6aa969f9487890d86001600160a01b0316632118ab306003858154811061111e57fe5b6000918252602090912001546040516001600160e01b031960e084901b168152611154916001600160a01b031690600401613769565b60206040518083038186803b15801561116c57600080fd5b505afa158015611180573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a491906131db565b90506000816001600160a01b031663a2e655b3306040518263ffffffff1660e01b81526004016111d49190613769565b604080518083038186803b1580156111eb57600080fd5b505afa1580156111ff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611223919061363b565b9150506000611230611a72565b905060008211801561124f5750600084604001516001600160401b0316115b8015611267575083602001516001600160401b031681115b1561130757600061128e85602001516001600160401b031683612a2f90919063ffffffff16565b905060006006546112bb87604001516001600160401b031661096f60075486612a5290919063ffffffff16565b816112c257fe5b0490506112f96112e8856112db8464e8d4a51000612a52565b816112e257fe5b04612b27565b87516001600160801b031690612b50565b6001600160801b0316865250505b61131042612b7f565b6001600160401b03166020850152600280548591908790811061132f57fe5b6000918252602091829020835191018054848401516040958601516001600160801b03199092166001600160801b039094169390931767ffffffffffffffff60801b1916600160801b6001600160401b0394851602176001600160c01b0316600160c01b93909116929092029190911790558501518551915187927f0fc9545022a542541ad085d091fb09a2ab36fee366a4576ab63714ea907ad353926113d99290918791613f12565b60405180910390a25050505b919050565b805160005b81811015610ad15761141383828151811061140657fe5b6020026020010151611078565b506001016113ef565b600080856001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161144b9190613769565b60206040518083038186803b15801561146357600080fd5b505afa158015611477573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149b91906133a4565b905060006114a987876126ac565b90506114df6001600160a01b037f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf1270168988612ba8565b6040516323e30c8b60e01b81527f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9906001600160a01b038a16906323e30c8b906115379033908c908c9088908d908d9060040161377d565b602060405180830381600087803b15801561155157600080fd5b505af1158015611565573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158991906133a4565b146115a65760405162461bcd60e51b8152600401610a119061399d565b604051636eb1769f60e11b81526000906001600160a01b037f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf1270169063dd62ed3e906115f7908c9030906004016137d6565b60206040518083038186803b15801561160f57600080fd5b505afa158015611623573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061164791906133a4565b905060006116558884612bfe565b9050808210156116775760405162461bcd60e51b8152600401610a1190613c2f565b6116ac6001600160a01b037f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf1270168b3084612c23565b60006116b661273c565b90506001600160a01b038116156116fb576116fb6001600160a01b037f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf1270168286612ba8565b6040516370a0823160e01b815285906001600160a01b038c16906370a0823190611729903090600401613769565b60206040518083038186803b15801561174157600080fd5b505afa158015611755573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177991906133a4565b10156117975760405162461bcd60e51b8152600401610a1190613cfd565b5060019a9950505050505050505050565b60007f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b0316826001600160a01b0316146117ea576000611886565b6040516370a0823160e01b81526001600160a01b037f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf127016906370a0823190611836903090600401613769565b60206040518083038186803b15801561184e57600080fd5b505afa158015611862573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188691906133a4565b92915050565b6000546001600160a01b031633146118b65760405162461bcd60e51b8152600401610a1190613bfa565b6118f28282808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506113ea92505050565b6118fe42610e10612a89565b6009555050565b600080546001600160a01b031633146119305760405162461bcd60e51b8152600401610a1190613bfa565b6000198314156119b9576040516370a0823160e01b81526001600160a01b038516906370a0823190611966903090600401613769565b60206040518083038186803b15801561197e57600080fd5b505afa158015611992573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119b691906133a4565b92505b6119cd6001600160a01b0385168385612c4a565b50815b9392505050565b600381815481106119e457fe5b6000918252602090912001546001600160a01b0316905081565b60405163d505accf60e01b81526001600160a01b0389169063d505accf90611a36908a908a908a908a908a908a908a90600401613814565b600060405180830381600087803b158015611a5057600080fd5b505af1158015611a64573d6000803e3d6000fd5b505050505050505050505050565b6000611a8042600854612d38565b905090565b82611ac57f000000000000000000000000f40388b593efb236d1ab314a6aa969f9487890d86001600160a01b0316632118ab3060038481548110610b1c57fe5b611acd613157565b611ad685611078565b60008681526005602090815260408083206001600160a01b0389168452909152812082518154939450909264e8d4a5100091611b1b91906001600160801b0316612a52565b81611b2257fe5b0490506000611b416109d5846001015484612aac90919063ffffffff16565b6001840183905590508015611b8457611b846001600160a01b037f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf1270168783612c4a565b600060048981548110611b9357fe5b6000918252602090912001546001600160a01b031690508015611c1857835460405163521c20cd60e11b81526001600160a01b0383169163a438419a91611be5918d918d918d91899190600401613ec5565b600060405180830381600087803b158015611bff57600080fd5b505af1158015611c13573d6000803e3d6000fd5b505050505b88886001600160a01b03167f71bab65ced2e5750775a0613be067df48ef06cf92a496ebf7663ae066092495484604051611c529190613ebc565b60405180910390a3505050505050505050565b6000546001600160a01b03163314611c8f5760405162461bcd60e51b8152600401610a1190613bfa565b600954421115611ca157611ca1610f8c565b611caa84611078565b50611cea83611ce460028781548110611cbf57fe5b60009182526020909120015460065490600160c01b90046001600160401b0316612a2f565b90612a89565b600655611cf683612b7f565b60028581548110611d0357fe5b9060005260206000200160000160186101000a8154816001600160401b0302191690836001600160401b031602179055508015611d77578160048581548110611d4857fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b80611da35760048481548110611d8957fe5b6000918252602090912001546001600160a01b0316611da5565b815b6001600160a01b0316847f95895a6ab1df54420d241b55243258a33e61b2194db66c1179ec521aae8e18658584604051611de0929190613ef4565b60405180910390a35050426009555050565b6000546001600160a01b031681565b82611e417f000000000000000000000000f40388b593efb236d1ab314a6aa969f9487890d86001600160a01b0316632118ab3060038481548110610b1c57fe5b611e49613157565b611e5285611078565b60008681526005602090815260408083206001600160a01b03881684529091529020805491925090611e849086612a89565b81558151611ebb9064e8d4a5100090611ea79088906001600160801b0316612a52565b81611eae57fe5b6001840154919004612d4e565b8160010181905550600060048781548110611ed257fe5b6000918252602090912001546001600160a01b031690508015611f5857815460405163521c20cd60e11b81526001600160a01b0383169163a438419a91611f25918b918a91829160009190600401613ec5565b600060405180830381600087803b158015611f3f57600080fd5b505af1158015611f53573d6000803e3d6000fd5b505050505b846001600160a01b031687866001600160a01b03167f02d7e648dd130fc184d383e55bb126ac4c9c60e8f94bf05acdf557ba2d540b4789604051610d6c9190613ebc565b6000546001600160a01b03163314611fc65760405162461bcd60e51b8152600401610a1190613bfa565b600954421115611fd857611fd8610f8c565b6120306001600160801b038016831115604051806040016040528060118152602001701cd95d11dc9858d954195c94d958dbdb99607a1b81525060405180606001604052806024815260200161401560249139612b18565b61209b428211604051806040016040528060118152602001701cd95d11dc9858d954195c94d958dbdb99607a1b8152506040518060400160405280602081526020017f656e642074696d652073686f756c6420626520696e2074686520667574757265815250612b18565b60006120a78242612a2f565b905060006120b58483612a52565b9050600060085442106120c957508061210c565b6008546000906120d99042612a2f565b905060006120f260075483612a5290919063ffffffff16565b905080841115612109576121068482612a2f565b92505b50505b600785905560088490556040517fc9cd3a88c1375a3ef18d5f395f9ab5c9f317945ab2ffc76b5153bbc72ecaf8cb906121489087908790613f04565b60405180910390a1801561218b5761218b6001600160a01b037f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf127016333084612d94565b505042600955505050565b60056020908152600092835260408084209091529082529020805460019091015482565b7f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf127081565b6000546001600160a01b031633146122085760405162461bcd60e51b8152600401610a1190613bfa565b60095442111561221a5761221a610f8c565b60035460065461222a9085612a89565b6006556003805460018181019092557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0180546001600160a01b038087166001600160a01b03199283161790925560048054938401815560009081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b9093018054928616929091169190911790556040805160608101909152908152600290602081016122d742612b7f565b6001600160401b031681526020016122ee87612b7f565b6001600160401b0390811690915282546001810184556000938452602093849020835191018054948401516040948501518416600160c01b026001600160c01b0391909416600160801b0267ffffffffffffffff60801b196001600160801b039094166001600160801b03199097169690961792909216949094171617909155516001600160a01b03808416919085169083907f81ee0f8c5c46e2cb41984886f77a84181724abb86c32a5f6de539b07509d45e5906123ae908990613ebc565b60405180910390a46040516302118ab360e41b81526000906001600160a01b037f000000000000000000000000f40388b593efb236d1ab314a6aa969f9487890d81690632118ab3090612405908790600401613769565b60206040518083038186803b15801561241d57600080fd5b505afa158015612431573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061245591906131db565b604051632b1e004b60e21b81529091506001600160a01b0382169063ac78012c90612484908590600401613ebc565b600060405180830381600087803b15801561249e57600080fd5b505af11580156124b2573d6000803e3d6000fd5b50504260095550505050505050565b7f000000000000000000000000f40388b593efb236d1ab314a6aa969f9487890d881565b600481815481106119e457fe5b7f00000000000000000000000066ab9f76e7822b7160e22f8b02dbd2d757fabf3281565b606080836001600160401b038111801561252f57600080fd5b50604051908082528060200260200182016040528015612559578160200160208202803683370190505b509150836001600160401b038111801561257257600080fd5b506040519080825280602002602001820160405280156125a657816020015b60608152602001906001900390816125915790505b50905060005b8481101561269d5760006060308888858181106125c557fe5b90506020028101906125d79190613f3c565b6040516125e5929190613700565b600060405180830381855af49150503d8060008114612620576040519150601f19603f3d011682016040523d82523d6000602084013e612625565b606091505b50915091508180612634575085155b61263d82612e85565b9061265b5760405162461bcd60e51b8152600401610a119190613936565b508185848151811061266957fe5b6020026020010190151590811515815250508084848151811061268857fe5b602090810291909101015250506001016125ac565b50935093915050565b61138881565b60007f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b0316836001600160a01b0316146126ff5760405162461bcd60e51b8152600401610a1190613b26565b6119d061271061272760028204612721600a5487612ee590919063ffffffff16565b90612bfe565b90612f1f565b6001546001600160a01b031681565b7f000000000000000000000000f40388b593efb236d1ab314a6aa969f9487890d890565b6127e87f000000000000000000000000f40388b593efb236d1ab314a6aa969f9487890d86001600160a01b0316336001600160a01b0316146040518060400160405280600781526020016619d95b995c985b60ca1b815250604051806040016040528060128152602001711b9bdd08199c9bdb48185c98da185b99d95b60721b815250612b18565b6127f181612f51565b50565b61271081565b6000546001600160a01b031633146128245760405162461bcd60e51b8152600401610a1190613bfa565b60095442111561283657612836610f8c565b612882600083116040518060400160405280600e81526020016d18591911dc9858d954995dd85c9960921b81525060405180606001604052806025815260200161403960259139612b18565b6128ea4282116040518060400160405280600e81526020016d18591911dc9858d954995dd85c9960921b8152506040518060400160405280602081526020017f656e642074696d652073686f756c6420626520696e2074686520667574757265815250612b18565b60006128f68242612a2f565b9050600060085442106129145781848161290c57fe5b049050612957565b6008546000906129249042612a2f565b9050600061293d60075483612a5290919063ffffffff16565b90508361294a8288612a89565b8161295157fe5b04925050505b6129ac6001600160801b0380168211156040518060400160405280600e81526020016d18591911dc9858d954995dd85c9960921b81525060405180606001604052806024815260200161401560249139612b18565b600781905560088390556040517fc9cd3a88c1375a3ef18d5f395f9ab5c9f317945ab2ffc76b5153bbc72ecaf8cb906129e89083908690613f04565b60405180910390a1612a256001600160a01b037f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf127016333087612d94565b5050426009555050565b808203828111156118865760405162461bcd60e51b8152600401610a1190613949565b6000811580612a6d57505080820282828281612a6a57fe5b04145b6118865760405162461bcd60e51b8152600401610a1190613e22565b818101818110156118865760405162461bcd60e51b8152600401610a1190613b82565b6000818303818312801590612ac15750838113155b80612ad65750600083128015612ad657508381135b6119d05760405162461bcd60e51b8152600401610a1190613d5f565b600080821215612b145760405162461bcd60e51b8152600401610a1190613978565b5090565b82610ad157610ad18282612f78565b60006001600160801b03821115612b145760405162461bcd60e51b8152600401610a1190613b4b565b8181016001600160801b0380831690821610156118865760405162461bcd60e51b8152600401610a1190613b82565b60006001600160401b03821115612b145760405162461bcd60e51b8152600401610a1190613cc6565b610ad18363a9059cbb60e01b8484604051602401612bc7929190613855565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612fb1565b6000828201838110156119d05760405162461bcd60e51b8152600401610a1190613a02565b612c44846323b872dd60e01b858585604051602401612bc7939291906137f0565b50505050565b60006060846001600160a01b031663a9059cbb8585604051602401612c70929190613855565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051612ca99190613710565b6000604051808303816000865af19150503d8060008114612ce6576040519150601f19603f3d011682016040523d82523d6000602084013e612ceb565b606091505b5091509150818015612d15575080511580612d15575080806020019051810190612d159190613388565b612d315760405162461bcd60e51b8152600401610a11906139cb565b5050505050565b6000818310612d4757816119d0565b5090919050565b6000828201818312801590612d635750838112155b80612d785750600083128015612d7857508381125b6119d05760405162461bcd60e51b8152600401610a1190613a39565b60006060856001600160a01b03166323b872dd868686604051602401612dbc939291906137f0565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051612df59190613710565b6000604051808303816000865af19150503d8060008114612e32576040519150601f19603f3d011682016040523d82523d6000602084013e612e37565b606091505b5091509150818015612e61575080511580612e61575080806020019051810190612e619190613388565b612e7d5760405162461bcd60e51b8152600401610a1190613da3565b505050505050565b6060604482511015612ecb575060408051808201909152601d81527f5472616e73616374696f6e2072657665727465642073696c656e746c7900000060208201526113e5565b600482019150818060200190518101906118869190613512565b600082612ef457506000611886565b82820282848281612f0157fe5b04146119d05760405162461bcd60e51b8152600401610a1190613bb9565b6000808211612f405760405162461bcd60e51b8152600401610a1190613aef565b818381612f4957fe5b049392505050565b612710811115612f735760405162461bcd60e51b8152600401610a1190613c66565b600a55565b8181604051602001612f8b92919061372c565b60408051601f198184030181529082905262461bcd60e51b8252610a1191600401613936565b6060613006826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166130409092919063ffffffff16565b805190915015610ad157808060200190518101906130249190613388565b610ad15760405162461bcd60e51b8152600401610a1190613dd8565b606061304f8484600085613057565b949350505050565b6060824710156130795760405162461bcd60e51b8152600401610a1190613aa9565b61308285613118565b61309e5760405162461bcd60e51b8152600401610a1190613d28565b60006060866001600160a01b031685876040516130bb9190613710565b60006040518083038185875af1925050503d80600081146130f8576040519150601f19603f3d011682016040523d82523d6000602084013e6130fd565b606091505b509150915061310d82828661311e565b979650505050505050565b3b151590565b6060831561312d5750816119d0565b82511561313d5782518084602001fd5b8160405162461bcd60e51b8152600401610a119190613936565b604080516060810182526000808252602082018190529181019190915290565b60008083601f840112613188578182fd5b5081356001600160401b0381111561319e578182fd5b60208301915083602080830285010111156131b857600080fd5b9250929050565b6000602082840312156131d0578081fd5b81356119d081613ff1565b6000602082840312156131ec578081fd5b81516119d081613ff1565b60008060006060848603121561320b578182fd5b833561321681613ff1565b9250602084013561322681614006565b9150604084013561323681614006565b809150509250925092565b60008060408385031215613253578182fd5b823561325e81613ff1565b946020939093013593505050565b600080600060408486031215613280578283fd5b83356001600160401b03811115613295578384fd5b6132a186828701613177565b909450925050602084013561323681614006565b600080602083850312156132c7578182fd5b82356001600160401b038111156132dc578283fd5b6132e885828601613177565b90969095509350505050565b60006020808385031215613306578182fd5b82356001600160401b0381111561331b578283fd5b8301601f8101851361332b578283fd5b803561333e61333982613fa6565b613f80565b818152838101908385018584028501860189101561335a578687fd5b8694505b8385101561337c57803583526001949094019391850191850161335e565b50979650505050505050565b600060208284031215613399578081fd5b81516119d081614006565b6000602082840312156133b5578081fd5b5051919050565b600080600080600080600080610100898b0312156133d8578586fd5b88356133e381613ff1565b975060208901356133f381613ff1565b9650604089013561340381613ff1565b9550606089013594506080890135935060a089013560ff81168114613426578384fd5b979a969950949793969295929450505060c08201359160e0013590565b600080600060608486031215613457578081fd5b833561346281613ff1565b925060208401359150604084013561323681613ff1565b600080600080600060808688031215613490578283fd5b853561349b81613ff1565b945060208601356134ab81613ff1565b93506040860135925060608601356001600160401b03808211156134cd578283fd5b818801915088601f8301126134e0578283fd5b8135818111156134ee578384fd5b8960208285010111156134ff578384fd5b9699959850939650602001949392505050565b600060208284031215613523578081fd5b81516001600160401b0380821115613539578283fd5b818401915084601f83011261354c578283fd5b81518181111561355a578384fd5b61356d601f8201601f1916602001613f80565b9150808252856020828501011115613583578384fd5b613594816020840160208601613fc5565b50949350505050565b6000602082840312156135ae578081fd5b5035919050565b600080604083850312156135c7578182fd5b8235915060208301356135d981613ff1565b809150509250929050565b6000806000606084860312156135f8578081fd5b83359250602084013561360a81613ff1565b9150604084013561323681613ff1565b6000806040838503121561362c578182fd5b50508035926020909101359150565b6000806040838503121561364d578182fd5b505080516020909101519092909150565b600080600060608486031215613672578081fd5b8335925060208401359150604084013561323681613ff1565b600080600080608085870312156136a0578182fd5b843593506020850135925060408501356136b981613ff1565b915060608501356136c981614006565b939692955090935050565b600081518084526136ec816020860160208601613fc5565b601f01601f19169290920160200192915050565b6000828483379101908152919050565b60008251613722818460208701613fc5565b9190910192915050565b6000835161373e818460208801613fc5565b6101d160f51b908301908152835161375d816002840160208801613fc5565b01600201949350505050565b6001600160a01b0391909116815260200190565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c084013781830160c090810191909152601f909201601f1916010195945050505050565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b604080825283519082018190526000906020906060840190828701845b828110156138cc5781511515845292840192908401906001016138ae565b505050838103828501528085516138e38184613ebc565b91508192508381028201848801865b8381101561391c57858303855261390a8383516136d4565b948701949250908601906001016138f2565b50909998505050505050505050565b901515815260200190565b6000602082526119d060208301846136d4565b602080825260159082015274426f72696e674d6174683a20556e646572666c6f7760581b604082015260600190565b6020808252600b908201526a0496e7465676572203c20360ac1b604082015260600190565b602080825260149082015273696e76616c69642072657475726e2076616c756560601b604082015260600190565b6020808252601c908201527f426f72696e6745524332303a205472616e73666572206661696c656400000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526021908201527f5369676e6564536166654d6174683a206164646974696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252601590820152744f776e61626c653a207a65726f206164647265737360581b604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b6020808252600b908201526a3bb937b733903a37b5b2b760a91b604082015260600190565b6020808252601c908201527f426f72696e674d6174683a2075696e74313238204f766572666c6f7700000000604082015260600190565b60208082526018908201527f426f72696e674d6174683a20416464204f766572666c6f770000000000000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601f908201527f616c6c6f77616e636520646f6573206e6f7420616c6c6f7720726566756e6400604082015260600190565b602080825260119082015270199959481c985d1948195e18d959591959607a1b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c657220213d2070656e64696e67206f776e6572604082015260600190565b6020808252601b908201527f426f72696e674d6174683a2075696e743634204f766572666c6f770000000000604082015260600190565b60208082526011908201527018985b185b98d948191958dc99585cd959607a1b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b60208082526024908201527f5369676e6564536166654d6174683a207375627472616374696f6e206f766572604082015263666c6f7760e01b606082015260800190565b6020808252818101527f426f72696e6745524332303a205472616e7366657246726f6d206661696c6564604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526018908201527f426f72696e674d6174683a204d756c204f766572666c6f770000000000000000604082015260600190565b81516001600160801b031681526020808301516001600160401b0390811691830191909152604092830151169181019190915260600190565b6001600160801b039390931683526001600160401b03918216602084015216604082015260600190565b90815260200190565b9485526001600160a01b0393841660208601529190921660408401526060830191909152608082015260a00190565b9182521515602082015260400190565b918252602082015260400190565b6001600160401b0393909316835260208301919091526001600160801b0316604082015260600190565b6000808335601e19843603018112613f52578283fd5b8301803591506001600160401b03821115613f6b578283fd5b6020019150368190038213156131b857600080fd5b6040518181016001600160401b0381118282101715613f9e57600080fd5b604052919050565b60006001600160401b03821115613fbb578081fd5b5060209081020190565b60005b83811015613fe0578181015183820152602001613fc8565b83811115612c445750506000910152565b6001600160a01b03811681146127f157600080fd5b80151581146127f157600080fdfe6e657720677261636520706572207365636f6e6420657863656564732075696e74313238677261636520616d6f756e742073686f756c642062652067726561746572207468616e2030a2646970667358221220b858822616d66b761153f19064c8efe7f6a943c1eb332414fe76cb7151fad82564736f6c634300060c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12700000000000000000000000000000000000000000000000000000000000000009
-----Decoded View---------------
Arg [0] : token (address): 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270
Arg [1] : flashLoanFee (uint256): 9
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf1270
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000009
Deployed Bytecode Sourcemap
130850:857:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;112263:29;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;119957:1363;;;;;;;;;;-1:-1:-1;119957:1363:0;;;;;:::i;:::-;;:::i;107543:472::-;;;;;;;;;;-1:-1:-1;107543:472:0;;;;;:::i;:::-;;:::i;:::-;;114464:100;;;;;;;;;;;;;:::i;125848:1158::-;;;;;;;;;;-1:-1:-1;125848:1158:0;;;;;:::i;:::-;;:::i;111593:29::-;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;111778:26::-;;;;;;;;;;-1:-1:-1;111778:26:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;:::i;112224:30::-;;;;;;;;;;;;;:::i;128732:1380::-;;;;;;;;;;-1:-1:-1;128732:1380:0;;;;;:::i;:::-;;:::i;112484:22::-;;;;;;;;;;;;;:::i;85470:27::-;;;;;;;;;;;;;:::i;121446:202::-;;;;;;;;;;;;;:::i;108064:348::-;;;;;;;;;;;;;:::i;122967:1538::-;;;;;;;;;;-1:-1:-1;122967:1538:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;121830:189::-;;;;;;;;;;-1:-1:-1;121830:189:0;;;;;:::i;:::-;;:::i;87269:1304::-;;;;;;;;;;-1:-1:-1;87269:1304:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;86070:266::-;;;;;;;;;;-1:-1:-1;86070:266:0;;;;;:::i;:::-;;:::i;122522:261::-;;;;;;;;;;-1:-1:-1;122522:261:0;;;;;:::i;:::-;;:::i;130410:318::-;;;;;;;;;;-1:-1:-1;130410:318:0;;;;;:::i;:::-;;:::i;111872:23::-;;;;;;;;;;-1:-1:-1;111872:23:0;;;;;:::i;:::-;;:::i;91122:331::-;;;;;;;;;;-1:-1:-1;91122:331:0;;;;;:::i;:::-;;:::i;114572:126::-;;;;;;;;;;;;;:::i;127185:1362::-;;;;;;;;;;-1:-1:-1;127185:1362:0;;;;;:::i;:::-;;:::i;116244:608::-;;;;;;;;;;-1:-1:-1;116244:608:0;;;;;:::i;:::-;;:::i;107119:20::-;;;;;;;;;;;;;:::i;124749:887::-;;;;;;;;;;-1:-1:-1;124749:887:0;;;;;:::i;:::-;;:::i;118545:1184::-;;;;;;;;;;-1:-1:-1;118545:1184:0;;;;;:::i;:::-;;:::i;112059:64::-;;;;;;;;;;-1:-1:-1;112059:64:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;85427:36::-;;;;;;;;;;;;;:::i;115037:813::-;;;;;;;;;;-1:-1:-1;115037:813:0;;;;;:::i;:::-;;:::i;112395:37::-;;;;;;;;;;;;;:::i;111965:27::-;;;;;;;;;;-1:-1:-1;111965:27:0;;;;;:::i;:::-;;:::i;112439:38::-;;;;;;;;;;;;;:::i;90171:604::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;85549:54::-;;;;;;;;;;;;;:::i;86604:325::-;;;;;;;;;;-1:-1:-1;86604:325:0;;;;;:::i;:::-;;:::i;107166:27::-;;;;;;;;;;;;;:::i;131588:116::-;;;;;;;;;;;;;:::i;131357:113::-;;;;;;;;;;-1:-1:-1;131357:113:0;;;;;:::i;:::-;;:::i;85504:38::-;;;;;;;;;;;;;:::i;117131:1230::-;;;;;;;;;;-1:-1:-1;117131:1230:0;;;;;:::i;:::-;;:::i;112263:29::-;;;;:::o;119957:1363::-;120058:15;120091:20;;:::i;:::-;120114:8;120123:4;120114:14;;;;;;;;;;;;;;;;120091:37;;;;;;;;120114:14;;;;120091:37;-1:-1:-1;;;;;120091:37:0;;;;;-1:-1:-1;;;;;;;;120091:37:0;;;;;;;;-1:-1:-1;;;120091:37:0;;;;;;;;;;120163:14;;;:8;:14;;;;;-1:-1:-1;;;;;120163:21:0;;;;;;;;;;120222;;120490:7;:13;;120091:37;;-1:-1:-1;120163:21:0;;120195:48;;;120114:14;;120460:9;:21;;;;120490:7;120163:14;;120490:13;;;;;;;;;;;;;;;;120460:45;;-1:-1:-1;;;;;;;120460:45:0;;;;;;;;-1:-1:-1;;;;;120490:13:0;;120460:45;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;120540:33;;-1:-1:-1;;;120540:33:0;;120416:90;;-1:-1:-1;120520:16:0;;-1:-1:-1;;;;;120540:18:0;;;-1:-1:-1;;120540:33:0;;120567:4;;120540:33;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;120517:56;;;120584:33;120620:26;:24;:26::i;:::-;120584:62;-1:-1:-1;120675:13:0;;;;;:49;;-1:-1:-1;120705:15:0;;;;-1:-1:-1;;;;;120705:19:0;;;120675:49;:113;;;;-1:-1:-1;120769:19:0;;;;-1:-1:-1;;;;;120741:47:0;;;120675:113;120657:487;;;120860:19;;;;120815:12;;120830:50;;:25;;-1:-1:-1;;;;;120830:50:0;:29;:50::i;:::-;120982:15;;120963;;;;120943:14;;120815:65;;-1:-1:-1;120895:19:0;;120934:45;;-1:-1:-1;;;;;120934:45:0;;:24;;120815:65;;120934:8;:24::i;:::-;:28;;:45::i;:::-;:63;;;;;;;-1:-1:-1;121031:101:0;121109:8;121070:36;120934:63;112346:4;121070:15;:36::i;:::-;:47;;;;;121031:16;;121070:47;;121031:20;:101::i;:::-;121012:120;;120657:487;;;121270:15;;;;121185:11;;121164:148;;:122;;112346:4;;121185:33;;121201:16;121185:15;:33::i;:::-;:55;;;;;;;121164:105;:122::i;:::-;:146;:148::i;:::-;121154:158;119957:1363;-1:-1:-1;;;;;;;;;119957:1363:0:o;107543:472::-;108515:5;;-1:-1:-1;;;;;108515:5:0;108501:10;:19;108493:64;;;;-1:-1:-1;;;108493:64:0;;;;;;;:::i;:::-;;;;;;;;;107648:6:::1;107644:364;;;-1:-1:-1::0;;;;;107702:22:0;::::1;::::0;::::1;::::0;:34:::1;;;107728:8;107702:34;107694:68;;;::::0;-1:-1:-1;;;107694:68:0;;::::1;::::0;::::1;;;:::i;:::-;107829:5;::::0;;107808:37:::1;::::0;-1:-1:-1;;;;;107808:37:0;;::::1;::::0;107829:5;::::1;::::0;107808:37:::1;::::0;::::1;107860:5;:16:::0;;-1:-1:-1;;;;;107860:16:0;::::1;-1:-1:-1::0;;;;;;107860:16:0;;::::1;;::::0;;;-1:-1:-1;107891:25:0;;;;::::1;::::0;;107644:364:::1;;;107973:12;:23:::0;;-1:-1:-1;;;;;;107973:23:0::1;-1:-1:-1::0;;;;;107973:23:0;::::1;;::::0;;107644:364:::1;107543:472:::0;;;:::o;114464:100::-;114541:8;:15;;114464:100::o;125848:1158::-;125963:3;113754:166;113794:9;-1:-1:-1;;;;;113794:21:0;;113824:7;113832:3;113824:12;;;;;;;;;;;;;;;;;;113794:44;;-1:-1:-1;;;;;;;113794:44:0;;;;;;;;-1:-1:-1;;;;;113824:12:0;;113794:44;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;113754:166;;;;;;;;;;;-1:-1:-1;;;113754:166:0;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;113780:58:0;;;;:10;:58;;113754:166;:11;:166::i;:::-;125979:20:::1;;:::i;:::-;126002:15;126013:3;126002:10;:15::i;:::-;126164:21;126188:13:::0;;;:8:::1;:13;::::0;;;;;;;-1:-1:-1;;;;;126188:17:0;::::1;::::0;;;;;;;126308:21;;;;-1:-1:-1;126188:17:0;126256:108:::1;::::0;112346:4:::1;::::0;126297:33:::1;::::0;:6;;-1:-1:-1;;;;;126297:33:0::1;:10;:33::i;:::-;:55;;;;;126256:15;::::0;::::1;::::0;;126297:55;::::1;126256:19;:108::i;:::-;126238:15;::::0;::::1;:126:::0;126389:11;;:23:::1;::::0;126405:6;126389:15:::1;:23::i;:::-;126375:37:::0;;126472:8:::1;:13:::0;;126375:11:::1;::::0;126472:8;126481:3;;126472:13;::::1;;;;;;::::0;;;::::1;::::0;;;::::1;::::0;-1:-1:-1;;;;;126472:13:0::1;::::0;-1:-1:-1;126500:32:0;;126496:276:::1;;126748:11:::0;;126708:52:::1;::::0;-1:-1:-1;;;126708:52:0;;-1:-1:-1;;;;;126708:23:0;::::1;::::0;::::1;::::0;:52:::1;::::0;126732:3;;126737:2;;;;126745:1:::1;::::0;126748:11;126708:52:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;126496:276;126969:29;::::0;-1:-1:-1;;;;;126969:29:0;::::1;::::0;126982:3;;126969:29;;::::1;::::0;::::1;::::0;126987:6;;126969:29:::1;:::i;:::-;;;;;;;;113931:1;;;125848:1158:::0;;;;:::o;111593:29::-;;;:::o;111778:26::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;111778:26:0;;;-1:-1:-1;;;;;;;;;111778:26:0;;;;;-1:-1:-1;;;111778:26:0;;;;:::o;112224:30::-;;;;:::o;128732:1380::-;128824:3;113754:166;113794:9;-1:-1:-1;;;;;113794:21:0;;113824:7;113832:3;113824:12;;;;;;;113754:166;128981:21:::1;129005:13:::0;;;:8:::1;:13;::::0;;;;;;;-1:-1:-1;;;;;129005:17:0;::::1;::::0;;;;;;;129050:11;;129072:15;;;-1:-1:-1;129098:15:0;::::1;:19:::0;;;129152:8:::1;:13:::0;;129005:17;;129050:11;;129005:13;;129152;::::1;;;;;;::::0;;;::::1;::::0;;;::::1;::::0;-1:-1:-1;;;;;129152:13:0::1;::::0;-1:-1:-1;129180:32:0;;129176:618:::1;;129619:56;::::0;-1:-1:-1;;;129619:56:0;;-1:-1:-1;;;;;129619:23:0;::::1;::::0;::::1;::::0;129648:7:::1;::::0;129619:56:::1;::::0;129657:3;;129662:2;;;;129670:1:::1;::::0;;;129619:56:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;129598:185;;129722:45;129747:9;129759:3;129764:2;129722:45;;;;;;;;:::i;:::-;;;;;;;;129598:185;130066:38;::::0;-1:-1:-1;;;;;130066:38:0;::::1;::::0;130088:3;;130066:38;;::::1;::::0;::::1;::::0;130093:6;;130066:38:::1;:::i;:::-;;;;;;;;113931:1;;;128732:1380:::0;;;:::o;112484:22::-;;;;:::o;85470:27::-;;;;:::o;121446:202::-;121498:11;121512:12;:10;:12::i;:::-;121498:26;;121540:9;121535:106;121559:3;121555:1;:7;121535:106;;;121613:1;121588:8;121597:1;121588:11;;;;;;;;;;;;;;;;;:22;-1:-1:-1;;;121588:22:0;;-1:-1:-1;;;;;121588:22:0;:26;121584:45;;;121616:13;121627:1;121616:10;:13::i;:::-;;121584:45;121564:3;;121535:106;;;;121446:202;:::o;108064:348::-;108132:12;;-1:-1:-1;;;;;108132:12:0;108192:10;:27;;108184:72;;;;-1:-1:-1;;;108184:72:0;;;;;;;:::i;:::-;108315:5;;;108294:42;;-1:-1:-1;;;;;108294:42:0;;;;108315:5;;;108294:42;;;108347:5;:21;;-1:-1:-1;;;;;108347:21:0;;;;-1:-1:-1;;;;;;108347:21:0;;;;;;-1:-1:-1;108379:25:0;;;;;;;108064:348::o;122967:1538::-;123016:20;;:::i;:::-;123056:8;123065:3;123056:13;;;;;;;;;;;;;;;;;123049:20;;;;;;;;123056:13;;;;123049:20;-1:-1:-1;;;;;123049:20:0;;;;-1:-1:-1;;;;;;;;123049:20:0;;;;;;;;;;-1:-1:-1;;;123049:20:0;;;;;;;;;-1:-1:-1;123084:15:0;:37;123080:1418;;;123311:18;123359:9;-1:-1:-1;;;;;123359:21:0;;123389:7;123397:3;123389:12;;;;;;;;;;;;;;;;;;123359:44;;-1:-1:-1;;;;;;;123359:44:0;;;;;;;;-1:-1:-1;;;;;123389:12:0;;123359:44;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;123442:33;;-1:-1:-1;;;123442:33:0;;123311:93;;-1:-1:-1;123422:16:0;;-1:-1:-1;;;;;123442:18:0;;;-1:-1:-1;;123442:33:0;;123469:4;;123442:33;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;123419:56;;;123490:33;123526:26;:24;:26::i;:::-;123490:62;;123655:1;123644:8;:12;:52;;;;-1:-1:-1;123677:15:0;;;;-1:-1:-1;;;;;123677:19:0;;;123644:52;:120;;;;-1:-1:-1;123745:19:0;;;;-1:-1:-1;;;;;123717:47:0;;;123644:120;123622:596;;;123865:19;;;;123799:12;;123835:50;;:25;;-1:-1:-1;;;;;123835:50:0;:29;:50::i;:::-;124020:15;;123976;;;;123956:14;;123799:86;;-1:-1:-1;123904:19:0;;123947:45;;-1:-1:-1;;;;;123947:45:0;;:24;;123799:86;;123947:8;:24::i;:45::-;:88;;;;;;;-1:-1:-1;124078:124:0;124126:57;124166:8;124127:36;123947:88;112346:4;124127:15;:36::i;:::-;:47;;;;;;124126:55;:57::i;:::-;124078:21;;-1:-1:-1;;;;;124078:25:0;;;:124::i;:::-;-1:-1:-1;;;;;124054:148:0;;;-1:-1:-1;;123622:596:0;124254:22;:15;:20;:22::i;:::-;-1:-1:-1;;;;;124232:44:0;:19;;;:44;124291:8;:13;;124232:19;;124291:8;124300:3;;124291:13;;;;;;;;;;;;;;;:20;;:13;;:20;;;;;;;;;;;-1:-1:-1;;;;;;124291:20:0;;;-1:-1:-1;;;;;124291:20:0;;;;;;;-1:-1:-1;;;;124291:20:0;-1:-1:-1;;;;;;;;124291:20:0;;;;;-1:-1:-1;;;;;124291:20:0;-1:-1:-1;;;124291:20:0;;;;;;;;;;;;;;124385:19;;;124450:21;;124331:155;;124363:3;;124331:155;;;;124385:19;;124423:8;;124331:155;:::i;:::-;;;;;;;;123080:1418;;;;122967:1538;;;:::o;121830:189::-;121910:11;;121896;121932:80;121956:3;121952:1;:7;121932:80;;;121981:19;121992:4;121997:1;121992:7;;;;;;;;;;;;;;121981:10;:19::i;:::-;-1:-1:-1;121961:3:0;;121932:80;;87269:1304;87477:38;;-1:-1:-1;;;87477:38:0;;87442:4;;;;-1:-1:-1;;;;;87477:23:0;;;-1:-1:-1;;87477:38:0;;87509:4;;87477:38;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;87459:56;;87526:11;87540:23;87549:5;87556:6;87540:8;:23::i;:::-;87526:37;-1:-1:-1;87609:52:0;-1:-1:-1;;;;;87609:12:0;:25;87643:8;87654:6;87609:25;:52::i;:::-;87694:58;;-1:-1:-1;;;87694:58:0;;85660:45;;-1:-1:-1;;;;;87694:20:0;;;-1:-1:-1;;87694:58:0;;87715:10;;87727:5;;87734:6;;87742:3;;87747:4;;;;87694:58;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:92;87672:162;;;;-1:-1:-1;;;87672:162:0;;;;;;;:::i;:::-;87885:56;;-1:-1:-1;;;87885:56:0;;87845:24;;-1:-1:-1;;;;;87885:12:0;:22;;;;:56;;87916:8;;87935:4;;87885:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;87845:96;-1:-1:-1;87952:17:0;87972:15;:6;87983:3;87972:10;:15::i;:::-;87952:35;;88040:9;88020:16;:29;;87998:110;;;;-1:-1:-1;;;87998:110:0;;;;;;;:::i;:::-;88155:124;-1:-1:-1;;;;;88155:12:0;:29;88207:8;88239:4;88259:9;88155:29;:124::i;:::-;88290:17;88310:23;:21;:23::i;:::-;88290:43;-1:-1:-1;;;;;;88348:23:0;;;88344:70;;88373:41;-1:-1:-1;;;;;88373:12:0;:25;88399:9;88410:3;88373:25;:41::i;:::-;88447:38;;-1:-1:-1;;;88447:38:0;;88489:7;;-1:-1:-1;;;;;88447:23:0;;;-1:-1:-1;;88447:38:0;;88479:4;;88447:38;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:49;;88425:116;;;;-1:-1:-1;;;88425:116:0;;;;;;;:::i;:::-;-1:-1:-1;88561:4:0;;87269:1304;-1:-1:-1;;;;;;;;;;87269:1304:0:o;86070:266::-;86175:7;86237:12;-1:-1:-1;;;;;86220:30:0;;;;;;;:108;;86327:1;86220:108;;;86270:37;;-1:-1:-1;;;86270:37:0;;-1:-1:-1;;;;;86270:12:0;:22;;-1:-1:-1;;86270:37:0;;86301:4;;86270:37;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;86200:128;86070:266;-1:-1:-1;;86070:266:0:o;122522:261::-;108515:5;;-1:-1:-1;;;;;108515:5:0;108501:10;:19;108493:64;;;;-1:-1:-1;;;108493:64:0;;;;;;;:::i;:::-;122608:21:::1;122624:4;;122608:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;122608:15:0::1;::::0;-1:-1:-1;;;122608:21:0:i:1;:::-;122750:25;:15;122770:4;122750:19;:25::i;:::-;122722;:53:::0;-1:-1:-1;;122522:261:0:o;130410:318::-;130535:7;108515:5;;-1:-1:-1;;;;;108515:5:0;108501:10;:19;108493:64;;;;-1:-1:-1;;;108493:64:0;;;;;;;:::i;:::-;-1:-1:-1;;130559:27:0;::::1;130555:99;;;130612:30;::::0;-1:-1:-1;;;130612:30:0;;-1:-1:-1;;;;;130612:15:0;::::1;::::0;-1:-1:-1;;130612:30:0::1;::::0;130636:4:::1;::::0;130612:30:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;130603:39;;130555:99;130664:30;-1:-1:-1::0;;;;;130664:18:0;::::1;130683:2:::0;130687:6;130664:18:::1;:30::i;:::-;-1:-1:-1::0;130714:6:0;108568:1:::1;130410:318:::0;;;;;:::o;111872:23::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;111872:23:0;;-1:-1:-1;111872:23:0;:::o;91122:331::-;91396:49;;-1:-1:-1;;;91396:49:0;;-1:-1:-1;;;;;91396:12:0;;;-1:-1:-1;;91396:49:0;;91409:4;;91415:2;;91419:6;;91427:8;;91437:1;;91440;;91443;;91396:49;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91122:331;;;;;;;;:::o;114572:126::-;114629:7;114656:34;114665:15;114682:7;;114656:8;:34::i;:::-;114649:41;;114572:126;:::o;127185:1362::-;127297:3;113754:166;113794:9;-1:-1:-1;;;;;113794:21:0;;113824:7;113832:3;113824:12;;;;;;;113754:166;127313:20:::1;;:::i;:::-;127336:15;127347:3;127336:10;:15::i;:::-;127498:21;127522:13:::0;;;:8:::1;:13;::::0;;;;;;;-1:-1:-1;;;;;127522:19:0;::::1;::::0;;;;;;;127632:21;;127616:11;;127632:21;;-1:-1:-1;127522:19:0;;112346:4:::1;::::0;127616:38:::1;::::0;:11;-1:-1:-1;;;;;127616:38:0::1;:15;:38::i;:::-;:60;;;;;;127552:139;;127702:21;127739:49;:37;127760:4;:15;;;127739:16;:20;;:37;;;;:::i;:49::-;127821:15;::::0;::::1;:34:::0;;;127702:86;-1:-1:-1;127897:18:0;;127893:88:::1;;127932:37;-1:-1:-1::0;;;;;127932:5:0::1;:18;127951:2:::0;127955:13;127932:18:::1;:37::i;:::-;127993:19;128015:8;128024:3;128015:13;;;;;;;;;::::0;;;::::1;::::0;;;::::1;::::0;-1:-1:-1;;;;;128015:13:0::1;::::0;-1:-1:-1;128043:32:0;;128039:352:::1;;128353:11:::0;;128092:287:::1;::::0;-1:-1:-1;;;128092:287:0;;-1:-1:-1;;;;;128092:23:0;::::1;::::0;::::1;::::0;:287:::1;::::0;128134:3;;128277:4;;128300:2;;128321:13;;128353:11;128092:287:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;128039:352;128506:33;::::0;128520:3;;-1:-1:-1;;;;;128506:33:0;::::1;::::0;::::1;::::0;::::1;::::0;128525:13;;128506:33:::1;:::i;:::-;;;;;;;;113931:1;;;;;127185:1362:::0;;;;:::o;116244:608::-;108515:5;;-1:-1:-1;;;;;108515:5:0;108501:10;:19;108493:64;;;;-1:-1:-1;;;108493:64:0;;;;;;;:::i;:::-;114008:25:::1;;113990:15;:43;113986:86;;;114048:24;:22;:24::i;:::-;116418:16:::2;116429:4;116418:10;:16::i;:::-;;116463:87;116528:11;116463:46;116483:8;116492:4;116483:14;;;;;;;;;::::0;;;::::2;::::0;;;::::2;:25:::0;116463:15:::2;::::0;;-1:-1:-1;;;116483:25:0;::::2;-1:-1:-1::0;;;;;116483:25:0::2;116463:19;:46::i;:::-;:50:::0;::::2;:87::i;:::-;116445:15;:105:::0;116589:18:::2;:11:::0;:16:::2;:18::i;:::-;116561:8;116570:4;116561:14;;;;;;;;;::::0;;;::::2;::::0;;;::::2;:46:::0;;-1:-1:-1;;;;;116561:46:0;;;::::2;-1:-1:-1::0;;;116561:46:0::2;-1:-1:-1::0;;;;;116561:46:0;;::::2;::::0;;;::::2;::::0;;116618:68;::::2;;;116665:9;116648:8;116657:4;116648:14;;;;;;;;;::::0;;;::::2;::::0;;;::::2;:26:::0;;-1:-1:-1;;;;;;116648:26:0::2;-1:-1:-1::0;;;;;116648:26:0;;;::::2;::::0;;;::::2;::::0;;116618:68:::2;116771:9;:38;;116795:8;116804:4;116795:14;;;;;;;;;::::0;;;::::2;::::0;;;::::2;::::0;-1:-1:-1;;;;;116795:14:0::2;116771:38;;;116783:9;116771:38;-1:-1:-1::0;;;;;116701:143:0::2;116726:4;116701:143;116745:11;116824:9;116701:143;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1::0;;114123:15:0::1;114095:25;:43:::0;-1:-1:-1;;116244:608:0:o;107119:20::-;;;-1:-1:-1;;;;;107119:20:0;;:::o;124749:887::-;124863:3;113754:166;113794:9;-1:-1:-1;;;;;113794:21:0;;113824:7;113832:3;113824:12;;;;;;;113754:166;124879:20:::1;;:::i;:::-;124902:15;124913:3;124902:10;:15::i;:::-;124928:21;124952:13:::0;;;:8:::1;:13;::::0;;;;;;;-1:-1:-1;;;;;124952:17:0;::::1;::::0;;;;;;;125016:11;;124879:38;;-1:-1:-1;124952:17:0;125016:23:::1;::::0;125032:6;125016:15:::1;:23::i;:::-;125002:37:::0;;125120:21;;125068:108:::1;::::0;112346:4:::1;::::0;125109:33:::1;::::0;:6;;-1:-1:-1;;;;;125109:33:0::1;:10;:33::i;:::-;:55;;;;;125068:15;::::0;::::1;::::0;;125109:55;::::1;125068:19;:108::i;:::-;125050:4;:15;;:126;;;;125214:19;125236:8;125245:3;125236:13;;;;;;;;;::::0;;;::::1;::::0;;;::::1;::::0;-1:-1:-1;;;;;125236:13:0::1;::::0;-1:-1:-1;125264:32:0;;125260:117:::1;;125353:11:::0;;125313:52:::1;::::0;-1:-1:-1;;;125313:52:0;;-1:-1:-1;;;;;125313:23:0;::::1;::::0;::::1;::::0;:52:::1;::::0;125337:3;;125342:2;;;;125350:1:::1;::::0;125353:11;125313:52:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;125260:117;125600:28;::::0;-1:-1:-1;;;;;125600:28:0;::::1;::::0;125612:3;;125600:28;;::::1;::::0;::::1;::::0;125617:6;;125600:28:::1;:::i;118545:1184::-:0;108515:5;;-1:-1:-1;;;;;108515:5:0;108501:10;:19;108493:64;;;;-1:-1:-1;;;108493:64:0;;;;;;;:::i;:::-;114008:25:::1;;113990:15;:43;113986:86;;;114048:24;:22;:24::i;:::-;118693:160:::2;-1:-1:-1::0;;;;;118719:36:0;::::2;:15;:36;;118693:160;;;;;;;;;;;;;-1:-1:-1::0;;;118693:160:0::2;;::::0;::::2;;;;;;;;;;;;;;;;;:11;:160::i;:::-;118864:146;118901:15;118890:8;:26;118864:146;;;;;;;;;;;;;-1:-1:-1::0;;;118864:146:0::2;;::::0;::::2;;;;;;;;;;;;;;;;::::0;:11:::2;:146::i;:::-;119023:16;119042:29;:8:::0;119055:15:::2;119042:12;:29::i;:::-;119023:48:::0;-1:-1:-1;119082:20:0::2;119105:29;:15:::0;119023:48;119105:19:::2;:29::i;:::-;119082:52;;119145:16;119195:7;;119176:15;:26;119172:307;;-1:-1:-1::0;119230:12:0;119172:307:::2;;;119295:7;::::0;119275:17:::2;::::0;119295:28:::2;::::0;119307:15:::2;119295:11;:28::i;:::-;119275:48;;119338:16;119357:29;119371:14;;119357:9;:13;;:29;;;;:::i;:::-;119338:48;;119420:8;119405:12;:23;119401:66;;;119441:26;:12:::0;119458:8;119441:16:::2;:26::i;:::-;119430:37;;119401:66;119172:307;;;119489:14;:32:::0;;;119532:7:::2;:18:::0;;;119566:52:::2;::::0;::::2;::::0;::::2;::::0;119506:15;;119542:8;;119566:52:::2;:::i;:::-;;;;;;;;119635:12:::0;;119631:90:::2;;119662:59;-1:-1:-1::0;;;;;119662:5:0::2;:22;119685:10;119705:4;119712:8:::0;119662:22:::2;:59::i;:::-;-1:-1:-1::0;;114123:15:0::1;114095:25;:43:::0;-1:-1:-1;;;118545:1184:0:o;112059:64::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;85427:36::-;;;:::o;115037:813::-;108515:5;;-1:-1:-1;;;;;108515:5:0;108501:10;:19;108493:64;;;;-1:-1:-1;;;108493:64:0;;;;;;;:::i;:::-;114008:25:::1;;113990:15;:43;113986:86;;;114048:24;:22;:24::i;:::-;115202:7:::2;:14:::0;115247:15:::2;::::0;:31:::2;::::0;115267:10;115247:19:::2;:31::i;:::-;115229:15;:49:::0;115289:7:::2;:22:::0;;::::2;::::0;;::::2;::::0;;;;::::2;::::0;;-1:-1:-1;;;;;115289:22:0;;::::2;-1:-1:-1::0;;;;;;115289:22:0;;::::2;;::::0;;;115322:8:::2;:24:::0;;;;::::2;::::0;;-1:-1:-1;115322:24:0;;;;;;::::2;::::0;;;;::::2;::::0;;;::::2;::::0;;;::::2;::::0;;115387:168:::2;::::0;;::::2;::::0;::::2;::::0;;;;;;115359:8:::2;::::0;115289:22:::2;115387:168:::0;::::2;115479:22;:15;:20;:22::i;:::-;-1:-1:-1::0;;;;;115387:168:0::2;::::0;;::::2;;115427:17;:10:::0;:15:::2;:17::i;:::-;-1:-1:-1::0;;;;;115387:168:0;;::::2;::::0;;;115359:207;;-1:-1:-1;115359:207:0;::::2;::::0;;-1:-1:-1;115359:207:0;;;::::2;::::0;;;;;;;::::2;::::0;;;;::::2;::::0;-1:-1:-1;115359:207:0;;::::2;::::0;;::::2;-1:-1:-1::0;;;115359:207:0::2;-1:-1:-1::0;;;;;115359:207:0;;;::::2;-1:-1:-1::0;;;115359:207:0::2;-1:-1:-1::0;;;;;;;;;115359:207:0;;::::2;-1:-1:-1::0;;;;;;115359:207:0;;::::2;::::0;;;::::2;::::0;;;::::2;::::0;;;::::2;;;::::0;;;115582:53;-1:-1:-1;;;;;115582:53:0;;::::2;::::0;;;::::2;::::0;115598:3;;115582:53:::2;::::0;::::2;::::0;115603:10;;115582:53:::2;:::i;:::-;;;;;;;;115767:40;::::0;-1:-1:-1;;;115767:40:0;;115723:18:::2;::::0;-1:-1:-1;;;;;115767:9:0::2;:21;::::0;::::2;::::0;:40:::2;::::0;115797:8;;115767:40:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;115819:23;::::0;-1:-1:-1;;;115819:23:0;;115723:85;;-1:-1:-1;;;;;;115819:18:0;::::2;::::0;::::2;::::0;:23:::2;::::0;115838:3;;115819:23:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;-1:-1:-1::0;;114123:15:0::1;114095:25;:43:::0;-1:-1:-1;;;;;;;115037:813:0:o;112395:37::-;;;:::o;111965:27::-;;;;;;;;;;112439:38;;;:::o;90171:604::-;90282:23;;90395:5;-1:-1:-1;;;;;90384:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;90384:24:0;-1:-1:-1;90372:36:0;-1:-1:-1;90441:5:0;-1:-1:-1;;;;;90429:25:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;90419:35;;90470:9;90465:303;90485:16;;;90465:303;;;90524:12;90538:19;90586:4;90605:5;;90611:1;90605:8;;;;;;;;;;;;;;;;;;:::i;:::-;90578:36;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;90523:91;;;;90637:7;:24;;;;90649:12;90648:13;90637:24;90663:21;90677:6;90663:13;:21::i;:::-;90629:56;;;;;-1:-1:-1;;;90629:56:0;;;;;;;;:::i;:::-;;90715:7;90700:9;90710:1;90700:12;;;;;;;;;;;;;:22;;;;;;;;;;;90750:6;90737:7;90745:1;90737:10;;;;;;;;;;;;;;;;;:19;-1:-1:-1;;90503:3:0;;90465:303;;;;90171:604;;;;;;:::o;85549:54::-;85591:12;85549:54;:::o;86604:325::-;86719:7;86769:12;-1:-1:-1;;;;;86752:30:0;;;;;;;86744:54;;;;-1:-1:-1;;;86744:54:0;;;;;;;:::i;:::-;86860:61;85539:3;86861:45;85602:1;85539:3;85591:12;86861:24;86872:12;;86861:6;:10;;:24;;;;:::i;:::-;:28;;:45::i;:::-;86860:51;;:61::i;107166:27::-;;;-1:-1:-1;;;;;107166:27:0;;:::o;131588:116::-;131686:9;131588:116;:::o;131357:113::-;130937:128;;;;;;;;;;;-1:-1:-1;;;130937:128:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;130937:128:0;;;;;;130985:9;-1:-1:-1;;;;;130963:32:0;:10;:32;;130937:128;:11;:128::i;:::-;131436:26:::1;131458:3;131436:21;:26::i;:::-;131357:113:::0;:::o;85504:38::-;85539:3;85504:38;:::o;117131:1230::-;108515:5;;-1:-1:-1;;;;;108515:5:0;108501:10;:19;108493:64;;;;-1:-1:-1;;;108493:64:0;;;;;;;:::i;:::-;114008:25:::1;;113990:15;:43;113986:86;;;114048:24;:22;:24::i;:::-;117268:133:::2;117304:1;117294:7;:11;117268:133;;;;;;;;;;;;;-1:-1:-1::0;;;117268:133:0::2;;::::0;::::2;;;;;;;;;;;;;;;;;:11;:133::i;:::-;117412:143;117449:15;117438:8;:26;117412:143;;;;;;;;;;;;;-1:-1:-1::0;;;117412:143:0::2;;::::0;::::2;;;;;;;;;;;;;;;;::::0;:11:::2;:143::i;:::-;117568:16;117587:29;:8:::0;117600:15:::2;117587:12;:29::i;:::-;117568:48;;117627:25;117686:7;;117667:15;:26;117663:308;;117740:8;117730:7;:18;;;;;;117710:38;;117663:308;;;117801:7;::::0;117781:17:::2;::::0;117801:28:::2;::::0;117813:15:::2;117801:11;:28::i;:::-;117781:48;;117844:16;117863:29;117877:14;;117863:9;:13;;:29;;;;:::i;:::-;117844:48:::0;-1:-1:-1;117951:8:0;117927:21:::2;117844:48:::0;117940:7;117927:12:::2;:21::i;:::-;:32;;;;;;117907:52;;117663:308;;;117981:159;-1:-1:-1::0;;;;;118007:38:0;::::2;:17;:38;;117981:159;;;;;;;;;;;;;-1:-1:-1::0;;;117981:159:0::2;;::::0;::::2;;;;;;;;;;;;;;;;;:11;:159::i;:::-;118151:14;:34:::0;;;118196:7:::2;:18:::0;;;118230:52:::2;::::0;::::2;::::0;::::2;::::0;118168:17;;118206:8;;118230:52:::2;:::i;:::-;;;;;;;;118295:58;-1:-1:-1::0;;;;;118295:5:0::2;:22;118318:10;118338:4;118345:7:::0;118295:22:::2;:58::i;:::-;-1:-1:-1::0;;114123:15:0::1;114095:25;:43:::0;-1:-1:-1;;117131:1230:0:o;91841:122::-;91924:5;;;91919:16;;;;91911:50;;;;-1:-1:-1;;;91911:50:0;;;;;;;:::i;91969:137::-;92027:9;92047:6;;;:28;;-1:-1:-1;;92062:5:0;;;92074:1;92069;92062:5;92069:1;92057:13;;;;;:18;92047:28;92039:65;;;;-1:-1:-1;;;92039:65:0;;;;;;;:::i;91710:125::-;91793:5;;;91788:16;;;;91780:53;;;;-1:-1:-1;;;91780:53:0;;;;;;;:::i;105585:255::-;105641:6;105671:5;;;105710:6;;;;;;:16;;;105725:1;105720;:6;;105710:16;105709:38;;;;105736:1;105732;:5;:14;;;;;105745:1;105741;:5;105732:14;105687:124;;;;-1:-1:-1;;;105687:124:0;;;;;;;:::i;106592:138::-;106644:7;106677:1;106672;:6;;106664:30;;;;-1:-1:-1;;;106664:30:0;;;;;;;:::i;:::-;-1:-1:-1;106720:1:0;106592:138::o;57565:202::-;57716:9;57711:48;;57727:32;57738:12;57752:6;57727:10;:32::i;92112:161::-;92161:9;-1:-1:-1;;;;;92191:16:0;;;92183:57;;;;-1:-1:-1;;;92183:57:0;;;;;;;:::i;92633:125::-;92716:5;;;-1:-1:-1;;;;;92711:16:0;;;;;;;;92703:53;;;;-1:-1:-1;;;92703:53:0;;;;;;;:::i;92279:156::-;92327:8;-1:-1:-1;;;;;92356:15:0;;;92348:55;;;;-1:-1:-1;;;92348:55:0;;;;;;;:::i;20114:177::-;20197:86;20217:5;20247:23;;;20272:2;20276:5;20224:58;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;20224:58:0;;;;;;;;;;;;;;-1:-1:-1;;;;;20224:58:0;-1:-1:-1;;;;;;20224:58:0;;;;;;;;;;;20197:19;:86::i;11970:179::-;12028:7;12060:5;;;12084:6;;;;12076:46;;;;-1:-1:-1;;;12076:46:0;;;;;;;:::i;20299:205::-;20400:96;20420:5;20450:27;;;20479:4;20485:2;20489:5;20427:68;;;;;;;;;;:::i;20400:96::-;20299:205;;;;:::o;109575:388::-;109694:12;109708:17;109750:5;-1:-1:-1;;;;;109742:19:0;109785:10;109797:2;109801:6;109762:46;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;109762:46:0;;;;;;;;;;;;;;-1:-1:-1;;;;;109762:46:0;-1:-1:-1;109762:46:0;;;;;;;;;;;109742:67;;;;109762:46;109742:67;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;109693:116;;;;109842:7;:57;;;;-1:-1:-1;109854:11:0;;:16;;:44;;;109885:4;109874:24;;;;;;;;;;;;:::i;:::-;109820:135;;;;-1:-1:-1;;;109820:135:0;;;;;;;:::i;:::-;109575:388;;;;;:::o;93891:106::-;93949:7;93980:1;93976;:5;:13;;93988:1;93976:13;;;-1:-1:-1;93984:1:0;;93891:106;-1:-1:-1;93891:106:0:o;106085:252::-;106141:6;106171:5;;;106210:6;;;;;;:16;;;106225:1;106220;:6;;106210:16;106209:38;;;;106236:1;106232;:5;:14;;;;;106245:1;106241;:5;106232:14;106187:121;;;;-1:-1:-1;;;106187:121:0;;;;;;;:::i;109971:457::-;110117:12;110131:17;110173:5;-1:-1:-1;;;;;110165:19:0;110226:10;110238:4;110244:2;110248:6;110203:52;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;110203:52:0;;;;;;;;;;;;;;-1:-1:-1;;;;;110203:52:0;-1:-1:-1;110203:52:0;;;;;;;;;;;110165:105;;;;110203:52;110165:105;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;110116:154;;;;110303:7;:57;;;;-1:-1:-1;110315:11:0;;:16;;:44;;;110346:4;110335:24;;;;;;;;;;;;:::i;:::-;110281:139;;;;-1:-1:-1;;;110281:139:0;;;;;;;:::i;:::-;109971:457;;;;;;:::o;89191:528::-;89290:13;89458:2;89437:11;:18;:23;89433:67;;;-1:-1:-1;89462:38:0;;;;;;;;;;;;;;;;;;;89433:67;89604:4;89591:11;89587:22;89572:37;;89648:11;89637:33;;;;;;;;;;;;:::i;12849:220::-;12907:7;12931:6;12927:20;;-1:-1:-1;12946:1:0;12939:8;;12927:20;12970:5;;;12974:1;12970;:5;:1;12994:5;;;;;:10;12986:56;;;;-1:-1:-1;;;12986:56:0;;;;;;;:::i;13547:153::-;13605:7;13637:1;13633;:5;13625:44;;;;-1:-1:-1;;;13625:44:0;;;;;;;:::i;:::-;13691:1;13687;:5;;;;;;;13547:153;-1:-1:-1;;;13547:153:0:o;88770:155::-;85539:3;88851;:15;;88843:45;;;;-1:-1:-1;;;88843:45:0;;;;;;;:::i;:::-;88899:12;:18;88770:155::o;57944:186::-;58093:12;58113:6;58076:44;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;58076:44:0;;;;;;;;;;-1:-1:-1;;;58062:60:0;;;;;;;:::i;22419:761::-;22869:69;;;;;;;;;;;;;;;;;;22843:23;;22869:69;;-1:-1:-1;;;;;22869:27:0;;;22897:4;;22869:27;:69::i;:::-;22953:17;;22843:95;;-1:-1:-1;22953:21:0;22949:224;;23095:10;23084:30;;;;;;;;;;;;:::i;:::-;23076:85;;;;-1:-1:-1;;;23076:85:0;;;;;;;:::i;4832:195::-;4935:12;4967:52;4989:6;4997:4;5003:1;5006:12;4967:21;:52::i;:::-;4960:59;4832:195;-1:-1:-1;;;;4832:195:0:o;5884:530::-;6011:12;6069:5;6044:21;:30;;6036:81;;;;-1:-1:-1;;;6036:81:0;;;;;;;:::i;:::-;6136:18;6147:6;6136:10;:18::i;:::-;6128:60;;;;-1:-1:-1;;;6128:60:0;;;;;;;:::i;:::-;6262:12;6276:23;6303:6;-1:-1:-1;;;;;6303:11:0;6323:5;6331:4;6303:33;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6261:75;;;;6354:52;6372:7;6381:10;6393:12;6354:17;:52::i;:::-;6347:59;5884:530;-1:-1:-1;;;;;;;5884:530:0:o;1914:422::-;2281:20;2320:8;;;1914:422::o;8424:742::-;8539:12;8568:7;8564:595;;;-1:-1:-1;8599:10:0;8592:17;;8564:595;8713:17;;:21;8709:439;;8976:10;8970:17;9037:15;9024:10;9020:2;9016:19;9009:44;8924:148;9112:20;;-1:-1:-1;;;9112:20:0;;;;9119:12;;9112:20;;;:::i;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;299:363::-;;;440:3;433:4;425:6;421:17;417:27;407:2;;-1:-1;;448:12;407:2;-1:-1;478:20;;-1:-1;;;;;507:30;;504:2;;;-1:-1;;540:12;504:2;584:4;576:6;572:17;560:29;;635:3;584:4;;619:6;615:17;576:6;601:32;;598:41;595:2;;;652:1;;642:12;595:2;400:262;;;;;:::o;4261:241::-;;4365:2;4353:9;4344:7;4340:23;4336:32;4333:2;;;-1:-1;;4371:12;4333:2;85:6;72:20;97:33;124:5;97:33;:::i;4509:263::-;;4624:2;4612:9;4603:7;4599:23;4595:32;4592:2;;;-1:-1;;4630:12;4592:2;226:6;220:13;238:33;265:5;238:33;:::i;4779:479::-;;;;4911:2;4899:9;4890:7;4886:23;4882:32;4879:2;;;-1:-1;;4917:12;4879:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;4969:63;-1:-1;5069:2;5105:22;;1845:20;1870:30;1845:20;1870:30;:::i;:::-;5077:60;-1:-1;5174:2;5210:22;;1845:20;1870:30;1845:20;1870:30;:::i;:::-;5182:60;;;;4873:385;;;;;:::o;5265:366::-;;;5386:2;5374:9;5365:7;5361:23;5357:32;5354:2;;;-1:-1;;5392:12;5354:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;5444:63;5544:2;5583:22;;;;3917:20;;-1:-1;;;5348:283::o;5638:538::-;;;;5802:2;5790:9;5781:7;5777:23;5773:32;5770:2;;;-1:-1;;5808:12;5770:2;5853:31;;-1:-1;;;;;5893:30;;5890:2;;;-1:-1;;5926:12;5890:2;5964:91;6047:7;6038:6;6027:9;6023:22;5964:91;:::i;:::-;5946:109;;-1:-1;5946:109;-1:-1;;6092:2;6128:22;;1845:20;1870:30;1845:20;1870:30;:::i;6183:397::-;;;6322:2;6310:9;6301:7;6297:23;6293:32;6290:2;;;-1:-1;;6328:12;6290:2;6373:31;;-1:-1;;;;;6413:30;;6410:2;;;-1:-1;;6446:12;6410:2;6484:80;6556:7;6547:6;6536:9;6532:22;6484:80;:::i;:::-;6466:98;;;;-1:-1;6284:296;-1:-1;;;;6284:296::o;6587:377::-;;6716:2;;6704:9;6695:7;6691:23;6687:32;6684:2;;;-1:-1;;6722:12;6684:2;6767:31;;-1:-1;;;;;6807:30;;6804:2;;;-1:-1;;6840:12;6804:2;6916:22;;1176:4;1164:17;;1160:27;-1:-1;1150:2;;-1:-1;;1191:12;1150:2;1238:6;1225:20;1260:80;1275:64;1332:6;1275:64;:::i;:::-;1260:80;:::i;:::-;1368:21;;;1425:14;;;;1400:17;;;1514;;;1505:27;;;;1502:36;-1:-1;1499:2;;;-1:-1;;1541:12;1499:2;-1:-1;1567:10;;1561:206;1586:6;1583:1;1580:13;1561:206;;;3917:20;;1654:50;;1608:1;1601:9;;;;;1718:14;;;;1746;;1561:206;;;-1:-1;6860:88;6678:286;-1:-1;;;;;;;6678:286::o;6971:257::-;;7083:2;7071:9;7062:7;7058:23;7054:32;7051:2;;;-1:-1;;7089:12;7051:2;1993:6;1987:13;2005:30;2029:5;2005:30;:::i;7235:263::-;;7350:2;7338:9;7329:7;7325:23;7321:32;7318:2;;;-1:-1;;7356:12;7318:2;-1:-1;2262:13;;7312:186;-1:-1;7312:186::o;7505:1159::-;;;;;;;;;7747:3;7735:9;7726:7;7722:23;7718:33;7715:2;;;-1:-1;;7754:12;7715:2;2784:6;2771:20;2796:54;2844:5;2796:54;:::i;:::-;7806:84;-1:-1;7927:2;7966:22;;72:20;97:33;72:20;97:33;:::i;:::-;7935:63;-1:-1;8035:2;8074:22;;72:20;97:33;72:20;97:33;:::i;:::-;8043:63;-1:-1;8143:2;8182:22;;3917:20;;-1:-1;8251:3;8291:22;;3917:20;;-1:-1;8360:3;8398:22;;4193:20;56796:4;56785:16;;60366:33;;60356:2;;-1:-1;;60403:12;60356:2;7709:955;;;;-1:-1;7709:955;;;;;;8369:61;;-1:-1;;;8467:3;8507:22;;2114:20;;8576:3;8616:22;2114:20;;7709:955::o;8671:519::-;;;;8823:2;8811:9;8802:7;8798:23;8794:32;8791:2;;;-1:-1;;8829:12;8791:2;2956:6;2943:20;2968:47;3009:5;2968:47;:::i;:::-;8881:77;-1:-1;8995:2;9034:22;;3917:20;;-1:-1;9103:2;9142:22;;72:20;97:33;72:20;97:33;:::i;9197:801::-;;;;;;9401:3;9389:9;9380:7;9376:23;9372:33;9369:2;;;-1:-1;;9408:12;9369:2;3137:6;3124:20;3149:63;3206:5;3149:63;:::i;:::-;9460:93;-1:-1;9590:2;9629:22;;72:20;97:33;72:20;97:33;:::i;:::-;9598:63;-1:-1;9698:2;9737:22;;3917:20;;-1:-1;9834:2;9819:18;;9806:32;-1:-1;;;;;9847:30;;;9844:2;;;-1:-1;;9880:12;9844:2;9965:6;9954:9;9950:22;;;2453:3;2446:4;2438:6;2434:17;2430:27;2420:2;;-1:-1;;2461:12;2420:2;2504:6;2491:20;9858:18;2523:6;2520:30;2517:2;;;-1:-1;;2553:12;2517:2;2648:3;9590:2;2628:17;2589:6;2614:32;;2611:41;2608:2;;;-1:-1;;2655:12;2608:2;9363:635;;;;-1:-1;9363:635;;-1:-1;9590:2;2585:17;;9900:82;9363:635;-1:-1;;;9363:635::o;10005:362::-;;10130:2;10118:9;10109:7;10105:23;10101:32;10098:2;;;-1:-1;;10136:12;10098:2;10181:24;;-1:-1;;;;;10214:30;;;10211:2;;;-1:-1;;10247:12;10211:2;10334:6;10323:9;10319:22;;;3511:3;3504:4;3496:6;3492:17;3488:27;3478:2;;-1:-1;;3519:12;3478:2;3559:6;3553:13;10225:18;52980:6;52977:30;52974:2;;;-1:-1;;53010:12;52974:2;3581:65;-1:-1;53064:17;;-1:-1;;53060:33;10130:2;53141:15;3581:65;:::i;:::-;3572:74;;3666:6;3659:5;3652:21;3770:3;10130:2;3761:6;3694;3752:16;;3749:25;3746:2;;;-1:-1;;3777:12;3746:2;3797:39;3829:6;10130:2;3728:5;3724:16;10130:2;3694:6;3690:17;3797:39;:::i;:::-;-1:-1;10267:84;10092:275;-1:-1;;;;10092:275::o;10374:241::-;;10478:2;10466:9;10457:7;10453:23;10449:32;10446:2;;;-1:-1;;10484:12;10446:2;-1:-1;3917:20;;10440:175;-1:-1;10440:175::o;10892:366::-;;;11013:2;11001:9;10992:7;10988:23;10984:32;10981:2;;;-1:-1;;11019:12;10981:2;3930:6;3917:20;11071:63;;11171:2;11214:9;11210:22;72:20;97:33;124:5;97:33;:::i;:::-;11179:63;;;;10975:283;;;;;:::o;11265:491::-;;;;11403:2;11391:9;11382:7;11378:23;11374:32;11371:2;;;-1:-1;;11409:12;11371:2;3930:6;3917:20;11461:63;;11561:2;11604:9;11600:22;72:20;97:33;124:5;97:33;:::i;:::-;11569:63;-1:-1;11669:2;11708:22;;72:20;97:33;72:20;97:33;:::i;12325:366::-;;;12446:2;12434:9;12425:7;12421:23;12417:32;12414:2;;;-1:-1;;12452:12;12414:2;-1:-1;;3917:20;;;12604:2;12643:22;;;3917:20;;-1:-1;12408:283::o;12698:399::-;;;12830:2;12818:9;12809:7;12805:23;12801:32;12798:2;;;-1:-1;;12836:12;12798:2;-1:-1;;4065:13;;12999:2;13049:22;;;4065:13;;;;;-1:-1;12792:305::o;13104:491::-;;;;13242:2;13230:9;13221:7;13217:23;13213:32;13210:2;;;-1:-1;;13248:12;13210:2;3930:6;3917:20;13300:63;;13400:2;13443:9;13439:22;3917:20;13408:63;;13508:2;13551:9;13547:22;72:20;97:33;124:5;97:33;:::i;13602:647::-;;;;;13772:3;13760:9;13751:7;13747:23;13743:33;13740:2;;;-1:-1;;13779:12;13740:2;3930:6;3917:20;13831:63;;13931:2;13974:9;13970:22;3917:20;13939:63;;14039:2;14100:9;14096:22;3309:20;3334:51;3379:5;3334:51;:::i;:::-;14047:81;-1:-1;14165:2;14201:22;;1845:20;1870:30;1845:20;1870:30;:::i;:::-;13734:515;;;;-1:-1;13734:515;;-1:-1;;13734:515::o;17548:323::-;;17680:5;53595:12;54410:6;54405:3;54398:19;17763:52;17808:6;54447:4;54442:3;54438:14;54447:4;17789:5;17785:16;17763:52;:::i;:::-;53083:9;59120:14;-1:-1;;59116:28;17827:39;;;;54447:4;17827:39;;17628:243;-1:-1;;17628:243::o;30037:291::-;;58703:6;58698:3;58693;58680:30;58741:16;;58734:27;;;58741:16;30181:147;-1:-1;30181:147::o;30335:271::-;;18038:5;53595:12;18149:52;18194:6;18189:3;18182:4;18175:5;18171:16;18149:52;:::i;:::-;18213:16;;;;;30469:137;-1:-1;;30469:137::o;30613:703::-;;18038:5;53595:12;18149:52;18194:6;18189:3;18182:4;18175:5;18171:16;18149:52;:::i;:::-;-1:-1;;;18213:16;;;28090:25;;;53595:12;;18149:52;53595:12;28075:1;28134:11;;18182:4;18171:16;;18149:52;:::i;:::-;18213:16;28075:1;18213:16;;30898:418;-1:-1;;;;30898:418::o;31323:222::-;-1:-1;;;;;56477:54;;;;14844:37;;31450:2;31435:18;;31421:124::o;31552:788::-;-1:-1;;;;;56477:54;;;14703:58;;56477:54;;32000:2;31985:18;;14844:37;32083:2;32068:18;;16830:37;;;32166:2;32151:18;;16830:37;;;-1:-1;32203:3;32188:19;;32181:49;;;31812:19;;54398;;;-1:-1;54398:19;58698:3;54438:14;;;58680:30;58741:16;;;54438:14;58741:16;;;58734:27;;;;53083:9;59120:14;;;-1:-1;;59116:28;17154:39;;;31798:542;-1:-1;;;;;31798:542::o;32347:333::-;-1:-1;;;;;56477:54;;;14844:37;;56477:54;;32666:2;32651:18;;14844:37;32502:2;32487:18;;32473:207::o;32687:444::-;-1:-1;;;;;56477:54;;;14844:37;;56477:54;;;;33034:2;33019:18;;14844:37;33117:2;33102:18;;16830:37;;;;32870:2;32855:18;;32841:290::o;33138:884::-;-1:-1;;;;;56477:54;;;14844:37;;56477:54;;;;33594:2;33579:18;;14844:37;33677:2;33662:18;;16830:37;;;;33760:2;33745:18;;16830:37;;;;56796:4;56785:16;33839:3;33824:19;;29990:35;-1:-1;33908:19;;16830:37;34007:3;33992:19;;16830:37;;;;33429:3;33414:19;;33400:622::o;34029:333::-;-1:-1;;;;;56477:54;;;;14844:37;;34348:2;34333:18;;16830:37;34184:2;34169:18;;34155:207::o;34369:444::-;-1:-1;;;;;56477:54;;;14844:37;;34716:2;34701:18;;16830:37;;;;56477:54;;;34799:2;34784:18;;14844:37;34552:2;34537:18;;34523:290::o;34820:653::-;35087:2;35101:47;;;53595:12;;35072:18;;;54398:19;;;34820:653;;54447:4;;54438:14;;;;53285;;;34820:653;15311:251;15336:6;15333:1;15330:13;15311:251;;;15397:13;;55637;55630:21;16602:34;;14398:14;;;;54132;;;;15358:1;15351:9;15311:251;;;15315:14;;;35312:9;35306:4;35302:20;54447:4;35286:9;35282:18;35275:48;35337:126;15839:5;53595:12;15858:95;15946:6;15941:3;15858:95;:::i;:::-;15851:102;;;;;54447:4;16010:6;16006:17;16001:3;15997:27;54447:4;16104:5;53285:14;-1:-1;16143:357;16168:6;16165:1;16162:13;16143:357;;;16230:9;16224:4;16220:20;16215:3;16208:33;14546:64;14606:3;16275:6;16269:13;14546:64;:::i;:::-;16479:14;;;;16289:90;-1:-1;54132:14;;;;15358:1;16183:9;16143:357;;;-1:-1;35329:134;;35058:415;-1:-1;;;;;;;;;35058:415::o;35480:210::-;55637:13;;55630:21;16602:34;;35601:2;35586:18;;35572:118::o;36759:310::-;;36906:2;36927:17;36920:47;36981:78;36906:2;36895:9;36891:18;37045:6;36981:78;:::i;37076:416::-;37276:2;37290:47;;;20131:2;37261:18;;;54398:19;-1:-1;;;54438:14;;;20147:44;20210:12;;;37247:245::o;37499:416::-;37699:2;37713:47;;;20461:2;37684:18;;;54398:19;-1:-1;;;54438:14;;;20477:34;20530:12;;;37670:245::o;37922:416::-;38122:2;38136:47;;;20781:2;38107:18;;;54398:19;-1:-1;;;54438:14;;;20797:43;-1:-1;20859:12;;38093:245::o;38345:416::-;38545:2;38559:47;;;21110:2;38530:18;;;54398:19;21146:30;54438:14;;;21126:51;21196:12;;;38516:245::o;38768:416::-;38968:2;38982:47;;;21447:2;38953:18;;;54398:19;21483:29;54438:14;;;21463:50;21532:12;;;38939:245::o;39191:416::-;39391:2;39405:47;;;21783:2;39376:18;;;54398:19;21819:34;54438:14;;;21799:55;-1:-1;;;21874:12;;;21867:25;21911:12;;;39362:245::o;39614:416::-;39814:2;39828:47;;;22162:2;39799:18;;;54398:19;-1:-1;;;54438:14;;;22178:44;22241:12;;;39785:245::o;40037:416::-;40237:2;40251:47;;;22492:2;40222:18;;;54398:19;22528:34;54438:14;;;22508:55;-1:-1;;;22583:12;;;22576:30;22625:12;;;40208:245::o;40460:416::-;40660:2;40674:47;;;22876:2;40645:18;;;54398:19;22912:28;54438:14;;;22892:49;22960:12;;;40631:245::o;40883:416::-;41083:2;41097:47;;;23211:2;41068:18;;;54398:19;-1:-1;;;54438:14;;;23227:34;23280:12;;;41054:245::o;41306:416::-;41506:2;41520:47;;;23531:2;41491:18;;;54398:19;23567:30;54438:14;;;23547:51;23617:12;;;41477:245::o;41729:416::-;41929:2;41943:47;;;23868:2;41914:18;;;54398:19;23904:26;54438:14;;;23884:47;23950:12;;;41900:245::o;42152:416::-;42352:2;42366:47;;;24201:2;42337:18;;;54398:19;24237:34;54438:14;;;24217:55;-1:-1;;;24292:12;;;24285:25;24329:12;;;42323:245::o;42575:416::-;42775:2;42789:47;;;42760:18;;;54398:19;24616:34;54438:14;;;24596:55;24670:12;;;42746:245::o;42998:416::-;43198:2;43212:47;;;24921:2;43183:18;;;54398:19;24957:33;54438:14;;;24937:54;25010:12;;;43169:245::o;43421:416::-;43621:2;43635:47;;;25261:2;43606:18;;;54398:19;-1:-1;;;54438:14;;;25277:40;25336:12;;;43592:245::o;43844:416::-;44044:2;44058:47;;;44029:18;;;54398:19;25623:34;54438:14;;;25603:55;25677:12;;;44015:245::o;44267:416::-;44467:2;44481:47;;;25928:2;44452:18;;;54398:19;25964:29;54438:14;;;25944:50;26013:12;;;44438:245::o;44690:416::-;44890:2;44904:47;;;26264:2;44875:18;;;54398:19;-1:-1;;;54438:14;;;26280:40;26339:12;;;44861:245::o;45113:416::-;45313:2;45327:47;;;26590:2;45298:18;;;54398:19;26626:31;54438:14;;;26606:52;26677:12;;;45284:245::o;45536:416::-;45736:2;45750:47;;;26928:2;45721:18;;;54398:19;26964:34;54438:14;;;26944:55;-1:-1;;;27019:12;;;27012:28;27059:12;;;45707:245::o;45959:416::-;46159:2;46173:47;;;46144:18;;;54398:19;27346:34;54438:14;;;27326:55;27400:12;;;46130:245::o;46382:416::-;46582:2;46596:47;;;27651:2;46567:18;;;54398:19;27687:34;54438:14;;;27667:55;-1:-1;;;27742:12;;;27735:34;27788:12;;;46553:245::o;46805:416::-;47005:2;47019:47;;;28384:2;46990:18;;;54398:19;28420:26;54438:14;;;28400:47;28466:12;;;46976:245::o;47228:326::-;28776:23;;-1:-1;;;;;56357:46;29277:37;;28957:4;28946:16;;;28940:23;-1:-1;;;;;56683:30;;;29015:14;;;29758:36;;;;-1:-1;29104:16;;;29098:23;56683:30;29173:14;;;29758:36;;;;47407:2;47392:18;;47378:176::o;47561:436::-;-1:-1;;;;;56357:46;;;;29277:37;;-1:-1;;;;;56683:30;;;47902:2;47887:18;;29758:36;56683:30;-1:-1;47968:18;;29758:36;47740:2;47725:18;;47711:286::o;48004:222::-;16830:37;;;48131:2;48116:18;;48102:124::o;48233:700::-;16830:37;;;-1:-1;;;;;56477:54;;;48653:2;48638:18;;14844:37;56477:54;;;;48736:2;48721:18;;14844:37;48827:2;48812:18;;19115:58;;;;48918:3;48903:19;;19115:58;-1:-1;48473:19;;48459:474::o;50306:321::-;16830:37;;;55637:13;55630:21;50613:2;50598:18;;16602:34;50455:2;50440:18;;50426:201::o;50634:329::-;16830:37;;;50949:2;50934:18;;16830:37;50787:2;50772:18;;50758:205::o;51310:440::-;-1:-1;;;;;56683:30;;;;29758:36;;51653:2;51638:18;;16830:37;;;;-1:-1;;;;;56357:46;-1:-1;51721:18;;29517:50;51491:2;51476:18;;51462:288::o;51757:506::-;;;51892:11;51879:25;51943:48;;51967:8;51951:14;51947:29;51943:48;51923:18;51919:73;51909:2;;-1:-1;;51996:12;51909:2;52023:33;;52077:18;;;-1:-1;;;;;;52104:30;;52101:2;;;-1:-1;;52137:12;52101:2;51982:4;52165:13;;-1:-1;51951:14;52197:38;;;52187:49;;52184:2;;;52249:1;;52239:12;52270:256;52332:2;52326:9;52358:17;;;-1:-1;;;;;52418:34;;52454:22;;;52415:62;52412:2;;;52490:1;;52480:12;52412:2;52332;52499:22;52310:216;;-1:-1;52310:216::o;52533:304::-;;-1:-1;;;;;52681:30;;52678:2;;;-1:-1;;52714:12;52678:2;-1:-1;52759:4;52747:17;;;52812:15;;52615:222::o;58776:268::-;58841:1;58848:101;58862:6;58859:1;58856:13;58848:101;;;58929:11;;;58923:18;58910:11;;;58903:39;58884:2;58877:10;58848:101;;;58964:6;58961:1;58958:13;58955:2;;;-1:-1;;58841:1;59011:16;;59004:27;58825:219::o;59157:117::-;-1:-1;;;;;56477:54;;59216:35;;59206:2;;59265:1;;59255:12;59281:111;59362:5;55637:13;55630:21;59340:5;59337:32;59327:2;;59383:1;;59373:12
Swarm Source
ipfs://b858822616d66b761153f19064c8efe7f6a943c1eb332414fe76cb7151fad825
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.