Contract
0x23a479a83e4fac12c2096ab1d79ea7a788f4489e
1
Contract Overview
My Name Tag:
Not Available, login to update
[ Download CSV Export ]
Latest 1 internal transaction
Parent Txn Hash | Block | From | To | Value | |||
---|---|---|---|---|---|---|---|
0x5e6e00ea35a872496e6402452b04dd33d90b88d0c84aaf6b1d7789faefc3e7d2 | 712538 | 709 days 2 hrs ago | 0x23a479a83e4fac12c2096ab1d79ea7a788f4489e | Contract Creation | 0 MOVR |
[ Download CSV Export ]
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
StableSwap
Compiler Version
v0.8.4+commit.c7e474f2
Contract Source Code (Solidity)
/** *Submitted for verification at moonriver.moonscan.io on 2021-11-01 */ // File @openzeppelin/contracts/security/[email protected] // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; abstract contract ReentrancyGuard { uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _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 @openzeppelin/contracts/proxy/utils/[email protected] pragma solidity ^0.8.0; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } } // File @openzeppelin/contracts/token/ERC20/[email protected] pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File @openzeppelin/contracts/utils/[email protected] pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // File @openzeppelin/contracts/token/ERC20/utils/Sa[email protected] pragma solidity ^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 Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } // File @openzeppelin/contracts/utils/[email protected] pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } } // File @openzeppelin/contracts/access/[email protected] pragma solidity ^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() { _setOwner(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _setOwner(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _setOwner(newOwner); } function _setOwner(address newOwner) private { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } } // File @openzeppelin/contracts/security/[email protected] pragma solidity ^0.8.0; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } } // File contracts/stableswap/OwnerPausable.sol pragma solidity 0.8.4; abstract contract OwnerPausable is Ownable, Pausable { function pause() external onlyOwner { _pause(); } function unpause() external onlyOwner { _unpause(); } } // File @openzeppelin/contracts/token/ERC20/extensions/[email protected] pragma solidity ^0.8.0; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); } // File @openzeppelin/contracts/token/ERC20/[email protected] pragma solidity ^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 Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); uint256 currentAllowance = _allowances[sender][_msgSender()]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); unchecked { _approve(sender, _msgSender(), currentAllowance - amount); } return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { uint256 currentAllowance = _allowances[_msgSender()][spender]; require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(_msgSender(), spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `sender` to `recipient`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); uint256 senderBalance = _balances[sender]; require(senderBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[sender] = senderBalance - amount; } _balances[recipient] += amount; emit Transfer(sender, recipient, amount); _afterTokenTransfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; } _totalSupply -= amount; emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} } // File @openzeppelin/contracts/token/ERC20/extensions/[email protected] pragma solidity ^0.8.0; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20Burnable is Context, ERC20 { /** * @dev Destroys `amount` tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); } /** * @dev Destroys `amount` tokens from `account`, deducting from the caller's * allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `amount`. */ function burnFrom(address account, uint256 amount) public virtual { uint256 currentAllowance = allowance(account, _msgSender()); require(currentAllowance >= amount, "ERC20: burn amount exceeds allowance"); unchecked { _approve(account, _msgSender(), currentAllowance - amount); } _burn(account, amount); } } // File contracts/interfaces/IStableSwap.sol pragma solidity 0.8.4; interface IStableSwap { /// EVENTS event AddLiquidity( address indexed provider, uint256[] tokenAmounts, uint256[] fees, uint256 invariant, uint256 tokenSupply ); event TokenExchange( address indexed buyer, uint256 soldId, uint256 tokensSold, uint256 boughtId, uint256 tokensBought ); event RemoveLiquidity(address indexed provider, uint256[] tokenAmounts, uint256[] fees, uint256 tokenSupply); event RemoveLiquidityOne(address indexed provider, uint256 tokenIndex, uint256 tokenAmount, uint256 coinAmount); event RemoveLiquidityImbalance( address indexed provider, uint256[] tokenAmounts, uint256[] fees, uint256 invariant, uint256 tokenSupply ); event RampA(uint256 oldA, uint256 newA, uint256 initialTime, uint256 futureTime); event StopRampA(uint256 A, uint256 timestamp); event NewFee(uint256 fee, uint256 adminFee); event CollectProtocolFee(address token, uint256 amount); event FeeControllerChanged(address newController); event FeeDistributorChanged(address newController); // pool data view functions function getLpToken() external view returns (IERC20 lpToken); function getA() external view returns (uint256); function getAPrecise() external view returns (uint256); function getToken(uint8 index) external view returns (IERC20); function getTokens() external view returns (IERC20[] memory); function getTokenIndex(address tokenAddress) external view returns (uint8); function getTokenBalance(uint8 index) external view returns (uint256); function getTokenBalances() external view returns (uint256[] memory); function getNumberOfTokens() external view returns (uint256); function getVirtualPrice() external view returns (uint256); function calculateTokenAmount(uint256[] calldata amounts, bool deposit) external view returns (uint256); function calculateSwap( uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx ) external view returns (uint256); function calculateRemoveLiquidity(uint256 amount) external view returns (uint256[] memory); function calculateRemoveLiquidityOneToken(uint256 tokenAmount, uint8 tokenIndex) external view returns (uint256 availableTokenAmount); function getAdminBalances() external view returns (uint256[] memory adminBalances); function getAdminBalance(uint8 index) external view returns (uint256); // state modifying functions function swap( uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx, uint256 minDy, uint256 deadline ) external returns (uint256); function addLiquidity( uint256[] calldata amounts, uint256 minToMint, uint256 deadline ) external returns (uint256); function removeLiquidity( uint256 amount, uint256[] calldata minAmounts, uint256 deadline ) external returns (uint256[] memory); function removeLiquidityOneToken( uint256 tokenAmount, uint8 tokenIndex, uint256 minAmount, uint256 deadline ) external returns (uint256); function removeLiquidityImbalance( uint256[] calldata amounts, uint256 maxBurnAmount, uint256 deadline ) external returns (uint256); function withdrawAdminFee() external; } // File contracts/stableswap/LPToken.sol pragma solidity ^0.8.4; contract LPToken is Ownable, ERC20Burnable { IStableSwap public swap; constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) { swap = IStableSwap(msg.sender); } function mint(address _to, uint256 _amount) external onlyOwner { require(_amount > 0, "zeroMintAmount"); _mint(_to, _amount); } } // File contracts/stableswap/StableSwapStorage.sol pragma solidity 0.8.4; /** * StableSwap main algorithm */ library StableSwapStorage { using SafeERC20 for IERC20; event AddLiquidity( address indexed provider, uint256[] token_amounts, uint256[] fees, uint256 invariant, uint256 token_supply ); event TokenExchange( address indexed buyer, uint256 sold_id, uint256 tokens_sold, uint256 bought_id, uint256 tokens_bought ); event RemoveLiquidity(address indexed provider, uint256[] token_amounts, uint256[] fees, uint256 token_supply); event RemoveLiquidityOne(address indexed provider, uint256 index, uint256 token_amount, uint256 coin_amount); event RemoveLiquidityImbalance( address indexed provider, uint256[] token_amounts, uint256[] fees, uint256 invariant, uint256 token_supply ); uint256 public constant FEE_DENOMINATOR = 1e10; // uint256 public constant PRECISION = 1e18; /// @dev protect from division loss when run approximation loop. We cannot divide at the end because of overflow, /// so we add some (small) PRECISION when divide in each iteration uint256 public constant A_PRECISION = 100; /// @dev max iteration of converge calccuate uint256 internal constant MAX_ITERATION = 256; uint256 public constant POOL_TOKEN_COMMON_DECIMALS = 18; struct SwapStorage { IERC20[] pooledTokens; LPToken lpToken; /// @dev token i multiplier to reach POOL_TOKEN_COMMON_DECIMALS uint256[] tokenMultipliers; /// @dev effective balance which might different from token balance of the contract 'cause it hold admin fee as well uint256[] balances; /// @dev swap fee ratio. Charge on any action which move balance state far from the ideal state uint256 fee; /// @dev admin fee in ratio of swap fee. uint256 adminFee; /// @dev observation of A, multiplied with A_PRECISION uint256 initialA; uint256 futureA; uint256 initialATime; uint256 futureATime; } /** * @notice Deposit coins into the pool * @param amounts List of amounts of coins to deposit * @param minMintAmount Minimum amount of LP tokens to mint from the deposit * @return mintAmount Amount of LP tokens received by depositing */ function addLiquidity( SwapStorage storage self, uint256[] memory amounts, uint256 minMintAmount ) external returns (uint256 mintAmount) { uint256 nCoins = self.pooledTokens.length; require(amounts.length == nCoins, "invalidAmountsLength"); uint256[] memory fees = new uint256[](nCoins); uint256 _fee = _feePerToken(self); uint256 tokenSupply = self.lpToken.totalSupply(); uint256 amp = _getAPrecise(self); uint256 D0 = 0; if (tokenSupply > 0) { D0 = _getD(_xp(self.balances, self.tokenMultipliers), amp); } uint256[] memory newBalances = self.balances; for (uint256 i = 0; i < nCoins; i++) { if (tokenSupply == 0) { require(amounts[i] > 0, "initialDepositRequireAllTokens"); } // get real transfer in amount newBalances[i] += _doTransferIn(self.pooledTokens[i], amounts[i]); } uint256 D1 = _getD(_xp(newBalances, self.tokenMultipliers), amp); assert(D1 > D0); // double check if (tokenSupply == 0) { self.balances = newBalances; mintAmount = D1; } else { uint256 diff = 0; for (uint256 i = 0; i < nCoins; i++) { diff = _distance((D1 * self.balances[i]) / D0, newBalances[i]); fees[i] = (_fee * diff) / FEE_DENOMINATOR; self.balances[i] = newBalances[i] - ((fees[i] * self.adminFee) / FEE_DENOMINATOR); newBalances[i] -= fees[i]; } D1 = _getD(_xp(newBalances, self.tokenMultipliers), amp); mintAmount = (tokenSupply * (D1 - D0)) / D0; } require(mintAmount >= minMintAmount, "> slippage"); self.lpToken.mint(msg.sender, mintAmount); emit AddLiquidity(msg.sender, amounts, fees, D1, mintAmount); } function swap( SwapStorage storage self, uint256 i, uint256 j, uint256 inAmount, uint256 minOutAmount ) external returns (uint256) { IERC20 inCoin = self.pooledTokens[i]; uint256[] memory normalizedBalances = _xp(self); inAmount = _doTransferIn(inCoin, inAmount); uint256 x = normalizedBalances[i] + (inAmount * self.tokenMultipliers[i]); uint256 y = _getY(self, i, j, x, normalizedBalances); uint256 dy = normalizedBalances[j] - y - 1; // iliminate rouding errors uint256 dy_fee = (dy * self.fee) / FEE_DENOMINATOR; dy = (dy - dy_fee) / self.tokenMultipliers[j]; // denormalize require(dy >= minOutAmount, "> slippage"); uint256 _adminFee = (dy_fee * self.adminFee) / FEE_DENOMINATOR / self.tokenMultipliers[j]; // update balances self.balances[i] += inAmount; self.balances[j] -= dy + _adminFee; self.pooledTokens[j].safeTransfer(msg.sender, dy); emit TokenExchange(msg.sender, i, inAmount, j, dy); return dy; } function removeLiquidity( SwapStorage storage self, uint256 lpAmount, uint256[] memory minAmounts ) external returns (uint256[] memory amounts) { uint256 totalSupply = self.lpToken.totalSupply(); require(lpAmount <= totalSupply); uint256 nCoins = self.pooledTokens.length; uint256[] memory fees = new uint256[](nCoins); amounts = _calculateRemoveLiquidity(self, lpAmount); for (uint256 i = 0; i < amounts.length; i++) { require(amounts[i] >= minAmounts[i], "> slippage"); self.balances[i] = self.balances[i] - amounts[i]; self.pooledTokens[i].safeTransfer(msg.sender, amounts[i]); } self.lpToken.burnFrom(msg.sender, lpAmount); emit RemoveLiquidity(msg.sender, amounts, fees, totalSupply - lpAmount); } function removeLiquidityOneToken( SwapStorage storage self, uint256 lpAmount, uint256 index, uint256 minAmount ) external returns (uint256) { uint256 totalSupply = self.lpToken.totalSupply(); require(totalSupply > 0, "totalSupply = 0"); uint256 numTokens = self.pooledTokens.length; require(lpAmount <= self.lpToken.balanceOf(msg.sender), "> balance"); require(lpAmount <= totalSupply, "> totalSupply"); require(index < numTokens, "tokenNotFound"); uint256 dyFee; uint256 dy; (dy, dyFee) = _calculateRemoveLiquidityOneToken(self, lpAmount, index); require(dy >= minAmount, "> slippage"); self.balances[index] -= (dy + (dyFee * self.adminFee) / FEE_DENOMINATOR); self.lpToken.burnFrom(msg.sender, lpAmount); self.pooledTokens[index].safeTransfer(msg.sender, dy); emit RemoveLiquidityOne(msg.sender, index, lpAmount, dy); return dy; } function removeLiquidityImbalance( SwapStorage storage self, uint256[] memory amounts, uint256 maxBurnAmount ) external returns (uint256 burnAmount) { uint256 nCoins = self.pooledTokens.length; require(amounts.length == nCoins, "invalidAmountsLength"); uint256 totalSupply = self.lpToken.totalSupply(); require(totalSupply != 0, "totalSupply = 0"); uint256 _fee = _feePerToken(self); uint256 amp = _getAPrecise(self); uint256[] memory newBalances = self.balances; uint256 D0 = _getD(_xp(self), amp); for (uint256 i = 0; i < nCoins; i++) { newBalances[i] -= amounts[i]; } uint256 D1 = _getD(_xp(newBalances, self.tokenMultipliers), amp); uint256[] memory fees = new uint256[](nCoins); for (uint256 i = 0; i < nCoins; i++) { uint256 idealBalance = (D1 * self.balances[i]) / D0; uint256 diff = _distance(newBalances[i], idealBalance); fees[i] = (_fee * diff) / FEE_DENOMINATOR; self.balances[i] = newBalances[i] - ((fees[i] * self.adminFee) / FEE_DENOMINATOR); newBalances[i] -= fees[i]; } // recalculate invariant with fee charged balances D1 = _getD(_xp(newBalances, self.tokenMultipliers), amp); burnAmount = ((D0 - D1) * totalSupply) / D0; assert(burnAmount > 0); require(burnAmount <= maxBurnAmount, "> slippage"); self.lpToken.burnFrom(msg.sender, burnAmount); for (uint256 i = 0; i < nCoins; i++) { if (amounts[i] != 0) { self.pooledTokens[i].safeTransfer(msg.sender, amounts[i]); } } emit RemoveLiquidityImbalance(msg.sender, amounts, fees, D1, totalSupply - burnAmount); } /// VIEW FUNCTIONS function getAPrecise(SwapStorage storage self) external view returns (uint256) { return _getAPrecise(self); } /** * Returns portfolio virtual price (for calculating profit) * scaled up by 1e18 */ function getVirtualPrice(SwapStorage storage self) external view returns (uint256) { uint256 D = _getD(_xp(self), _getAPrecise(self)); uint256 tokenSupply = self.lpToken.totalSupply(); return (D * 10**POOL_TOKEN_COMMON_DECIMALS) / tokenSupply; } function getAdminBalance(SwapStorage storage self, uint256 index) external view returns (uint256) { require(index < self.pooledTokens.length, "indexOutOfRange"); return self.pooledTokens[index].balanceOf(address(this)) - (self.balances[index]); } /** * Estimate amount of LP token minted or burned at deposit or withdrawal * without taking fees into account */ function calculateTokenAmount( SwapStorage storage self, uint256[] memory amounts, bool deposit ) external view returns (uint256) { uint256 nCoins = self.pooledTokens.length; require(amounts.length == nCoins, "invalidAmountsLength"); uint256 amp = _getAPrecise(self); uint256 D0 = _getD(_xp(self), amp); uint256[] memory newBalances = self.balances; for (uint256 i = 0; i < nCoins; i++) { if (deposit) { newBalances[i] += amounts[i]; } else { newBalances[i] -= amounts[i]; } } uint256 D1 = _getD(_xp(newBalances, self.tokenMultipliers), amp); uint256 totalSupply = self.lpToken.totalSupply(); if (totalSupply == 0) { return D1; // first depositor take it all } uint256 diff = deposit ? D1 - D0 : D0 - D1; return (diff * self.lpToken.totalSupply()) / D0; } function getA(SwapStorage storage self) external view returns (uint256) { return _getAPrecise(self) / A_PRECISION; } function calculateSwap( SwapStorage storage self, uint256 inIndex, uint256 outIndex, uint256 inAmount ) external view returns (uint256) { uint256[] memory normalizedBalances = _xp(self); uint256 newInBalance = normalizedBalances[inIndex] + (inAmount * self.tokenMultipliers[inIndex]); uint256 outBalance = _getY(self, inIndex, outIndex, newInBalance, normalizedBalances); uint256 outAmount = (normalizedBalances[outIndex] - outBalance - 1) / self.tokenMultipliers[outIndex]; uint256 _fee = (self.fee * outAmount) / FEE_DENOMINATOR; return outAmount - _fee; } function calculateRemoveLiquidity(SwapStorage storage self, uint256 amount) external view returns (uint256[] memory) { return _calculateRemoveLiquidity(self, amount); } function calculateRemoveLiquidityOneToken( SwapStorage storage self, uint256 lpAmount, uint256 tokenIndex ) external view returns (uint256 amount) { (amount, ) = _calculateRemoveLiquidityOneToken(self, lpAmount, tokenIndex); } /// INTERNAL FUNCTIONS /** * Ramping A up or down, return A with precision of A_PRECISION */ function _getAPrecise(SwapStorage storage self) internal view returns (uint256) { if (block.timestamp >= self.futureATime) { return self.futureA; } if (self.futureA > self.initialA) { return self.initialA + ((self.futureA - self.initialA) * (block.timestamp - self.initialATime)) / (self.futureATime - self.initialATime); } return self.initialA - ((self.initialA - self.futureA) * (block.timestamp - self.initialATime)) / (self.futureATime - self.initialATime); } /** * normalized balances of each tokens. */ function _xp(uint256[] memory balances, uint256[] memory rates) internal pure returns (uint256[] memory) { for (uint256 i = 0; i < balances.length; i++) { rates[i] = (rates[i] * balances[i]); } return rates; } function _xp(SwapStorage storage self) internal view returns (uint256[] memory) { return _xp(self.balances, self.tokenMultipliers); } /** * Calculate D for *NORMALIZED* balances of each tokens * @param xp normalized balances of token */ function _getD(uint256[] memory xp, uint256 amp) internal pure returns (uint256) { uint256 nCoins = xp.length; uint256 sum = _sumOf(xp); if (sum == 0) { return 0; } uint256 Dprev = 0; uint256 D = sum; uint256 Ann = amp * nCoins; for (uint256 i = 0; i < MAX_ITERATION; i++) { uint256 D_P = D; for (uint256 j = 0; j < xp.length; j++) { D_P = (D_P * D) / (xp[j] * nCoins); } Dprev = D; D = (((Ann * sum) / A_PRECISION + D_P * nCoins) * D) / (((Ann - A_PRECISION) * D) / A_PRECISION + (nCoins + 1) * D_P); if (_distance(D, Dprev) <= 1) { return D; } } // Convergence should occur in 4 loops or less. If this is reached, there may be something wrong // with the pool. If this were to occur repeatedly, LPs should withdraw via `removeLiquidity()` // function which does not rely on D. revert("invariantCalculationFailed"); } /** * calculate new balance of when swap * Done by solving quadratic equation iteratively. * x_1**2 + x_1 * (sum' - (A*n**n - 1) * D / (A * n**n)) = D ** (n + 1) / (n ** (2 * n) * prod' * A) * x_1**2 + b*x_1 = c * x_1 = (x_1**2 + c) / (2*x_1 + b) * @param inIndex index of token to swap in * @param outIndex index of token to swap out * @param inBalance new balance (normalized) of input token if the swap success * @return NORMALIZED balance of output token if the swap success */ function _getY( SwapStorage storage self, uint256 inIndex, uint256 outIndex, uint256 inBalance, uint256[] memory normalizedBalances ) internal view returns (uint256) { require(inIndex != outIndex, "sameToken"); uint256 nCoins = self.pooledTokens.length; require(inIndex < nCoins && outIndex < nCoins, "indexOutOfRange"); uint256 amp = _getAPrecise(self); uint256 Ann = amp * nCoins; uint256 D = _getD(normalizedBalances, amp); uint256 sum = 0; // sum of new balances except output token uint256 c = D; for (uint256 i = 0; i < nCoins; i++) { if (i == outIndex) { continue; } uint256 x = i == inIndex ? inBalance : normalizedBalances[i]; sum += x; c = (c * D) / (x * nCoins); } c = (c * D * A_PRECISION) / (Ann * nCoins); uint256 b = sum + (D * A_PRECISION) / Ann; uint256 lastY = 0; uint256 y = D; for (uint256 index = 0; index < MAX_ITERATION; index++) { lastY = y; y = (y * y + c) / (2 * y + b - D); if (_distance(lastY, y) <= 1) { return y; } } revert("yCalculationFailed"); } function _calculateRemoveLiquidity(SwapStorage storage self, uint256 amount) internal view returns (uint256[] memory) { uint256 totalSupply = self.lpToken.totalSupply(); require(amount <= totalSupply, "Cannot exceed total supply"); uint256[] memory amounts = new uint256[](self.pooledTokens.length); for (uint256 i = 0; i < self.pooledTokens.length; i++) { amounts[i] = (self.balances[i] * (amount)) / (totalSupply); } return amounts; } function _calculateRemoveLiquidityOneToken( SwapStorage storage self, uint256 tokenAmount, uint256 index ) internal view returns (uint256 dy, uint256 fee) { require(index < self.pooledTokens.length, "indexOutOfRange"); uint256 amp = _getAPrecise(self); uint256[] memory xp = _xp(self); uint256 D0 = _getD(xp, amp); uint256 D1 = D0 - (tokenAmount * D0) / self.lpToken.totalSupply(); uint256 newY = _getYD(self, amp, index, xp, D1); uint256[] memory reducedXP = xp; uint256 _fee = _feePerToken(self); for (uint256 i = 0; i < self.pooledTokens.length; i++) { uint256 expectedDx = 0; if (i == index) { expectedDx = (xp[i] * D1) / D0 - newY; } else { expectedDx = xp[i] - (xp[i] * D1) / D0; } reducedXP[i] -= (_fee * expectedDx) / FEE_DENOMINATOR; } dy = reducedXP[index] - _getYD(self, amp, index, reducedXP, D1); dy = (dy - 1) / self.tokenMultipliers[index]; fee = ((xp[index] - newY) / self.tokenMultipliers[index]) - dy; } function _feePerToken(SwapStorage storage self) internal view returns (uint256) { uint256 nCoins = self.pooledTokens.length; return (self.fee * nCoins) / (4 * (nCoins - 1)); } function _getYD( SwapStorage storage self, uint256 A, uint256 index, uint256[] memory xp, uint256 D ) internal view returns (uint256) { uint256 nCoins = self.pooledTokens.length; assert(index < nCoins); uint256 Ann = A * nCoins; uint256 c = D; uint256 s = 0; uint256 _x = 0; uint256 yPrev = 0; for (uint256 i = 0; i < nCoins; i++) { if (i == index) { continue; } _x = xp[i]; s += _x; c = (c * D) / (_x * nCoins); } c = (c * D * A_PRECISION) / (Ann * nCoins); uint256 b = s + (D * A_PRECISION) / Ann; uint256 y = D; for (uint256 i = 0; i < MAX_ITERATION; i++) { yPrev = y; y = (y * y + c) / (2 * y + b - D); if (_distance(yPrev, y) <= 1) { return y; } } revert("invariantCalculationFailed"); } function _doTransferIn(IERC20 token, uint256 amount) internal returns (uint256) { uint256 priorBalance = token.balanceOf(address(this)); token.safeTransferFrom(msg.sender, address(this), amount); return token.balanceOf(address(this)) - priorBalance; } function _sumOf(uint256[] memory x) internal pure returns (uint256 sum) { sum = 0; for (uint256 i = 0; i < x.length; i++) { sum += x[i]; } } function _distance(uint256 x, uint256 y) internal pure returns (uint256) { return x > y ? x - y : y - x; } } // File contracts/stableswap/StableSwap.sol pragma solidity 0.8.4; contract StableSwap is OwnerPausable, ReentrancyGuard, Initializable, IStableSwap { using StableSwapStorage for StableSwapStorage.SwapStorage; using SafeERC20 for IERC20; /// constants uint256 public constant MIN_RAMP_TIME = 1 days; uint256 public constant MAX_A = 1e6; // max_a with precision uint256 public constant MAX_A_CHANGE = 10; uint256 public constant MAX_ADMIN_FEE = 1e10; // 100% uint256 public constant MAX_SWAP_FEE = 1e8; // 1% /// STATE VARS StableSwapStorage.SwapStorage public swapStorage; address public feeDistributor; address public feeController; mapping(address => uint8) public tokenIndexes; modifier deadlineCheck(uint256 _deadline) { require(block.timestamp <= _deadline, "timeout"); _; } modifier onlyFeeControllerOrOwner() { require(msg.sender == feeController || msg.sender == owner(), "!feeControllerOrOwner"); _; } function initialize( address[] memory _coins, uint8[] memory _decimals, string memory lpTokenName, string memory lpTokenSymbol, uint256 _A, uint256 _fee, uint256 _adminFee, address _feeDistributor ) external onlyOwner initializer { require(_coins.length == _decimals.length, "coinsLength != decimalsLength"); require(_feeDistributor != address(0), "feeDistributor = empty"); uint256 numberOfCoins = _coins.length; uint256[] memory rates = new uint256[](numberOfCoins); IERC20[] memory coins = new IERC20[](numberOfCoins); for (uint256 i = 0; i < numberOfCoins; i++) { require(_coins[i] != address(0), "invalidTokenAddress"); require(_decimals[i] <= StableSwapStorage.POOL_TOKEN_COMMON_DECIMALS, "invalidDecimals"); rates[i] = 10**(StableSwapStorage.POOL_TOKEN_COMMON_DECIMALS - _decimals[i]); coins[i] = IERC20(_coins[i]); tokenIndexes[address(coins[i])] = uint8(i); } require(_A < MAX_A, "> maxA"); require(_fee <= MAX_SWAP_FEE, "> maxSwapFee"); require(_adminFee <= MAX_ADMIN_FEE, "> maxAdminFee"); swapStorage.lpToken = new LPToken(lpTokenName, lpTokenSymbol); swapStorage.balances = new uint256[](numberOfCoins); swapStorage.tokenMultipliers = rates; swapStorage.pooledTokens = coins; swapStorage.initialA = _A * StableSwapStorage.A_PRECISION; swapStorage.futureA = _A * StableSwapStorage.A_PRECISION; swapStorage.fee = _fee; swapStorage.adminFee = _adminFee; feeDistributor = _feeDistributor; } /// PUBLIC FUNCTIONS function addLiquidity( uint256[] memory amounts, uint256 minMintAmount, uint256 deadline ) external override whenNotPaused nonReentrant deadlineCheck(deadline) returns (uint256) { return swapStorage.addLiquidity(amounts, minMintAmount); } function swap( uint8 fromIndex, uint8 toIndex, uint256 inAmount, uint256 minOutAmount, uint256 deadline ) external override whenNotPaused nonReentrant deadlineCheck(deadline) returns (uint256) { return swapStorage.swap(fromIndex, toIndex, inAmount, minOutAmount); } function removeLiquidity( uint256 lpAmount, uint256[] memory minAmounts, uint256 deadline ) external override nonReentrant deadlineCheck(deadline) returns (uint256[] memory) { return swapStorage.removeLiquidity(lpAmount, minAmounts); } function removeLiquidityOneToken( uint256 lpAmount, uint8 index, uint256 minAmount, uint256 deadline ) external override nonReentrant whenNotPaused deadlineCheck(deadline) returns (uint256) { return swapStorage.removeLiquidityOneToken(lpAmount, index, minAmount); } function removeLiquidityImbalance( uint256[] memory amounts, uint256 maxBurnAmount, uint256 deadline ) external override nonReentrant whenNotPaused deadlineCheck(deadline) returns (uint256) { return swapStorage.removeLiquidityImbalance(amounts, maxBurnAmount); } /// VIEW FUNCTIONS function getVirtualPrice() external view override returns (uint256) { return swapStorage.getVirtualPrice(); } function getA() external view override returns (uint256) { return swapStorage.getA(); } function getAPrecise() external view override returns (uint256) { return swapStorage.getAPrecise(); } function getTokens() external view override returns (IERC20[] memory) { return swapStorage.pooledTokens; } function getToken(uint8 index) external view override returns (IERC20) { return swapStorage.pooledTokens[index]; } function getLpToken() external view override returns (IERC20) { return swapStorage.lpToken; } function getTokenIndex(address token) external view override returns (uint8 index) { index = tokenIndexes[token]; require(address(swapStorage.pooledTokens[index]) == token, "tokenNotFound"); } function getTokenPrecisionMultipliers() external view returns (uint256[] memory) { return swapStorage.tokenMultipliers; } function getTokenBalances() external view override returns (uint256[] memory) { return swapStorage.balances; } function getTokenBalance(uint8 index) external view override returns (uint256) { return swapStorage.balances[index]; } function getNumberOfTokens() external view override returns (uint256) { return swapStorage.pooledTokens.length; } function getAdminBalances() external view override returns (uint256[] memory adminBalances) { uint256 length = swapStorage.pooledTokens.length; adminBalances = new uint256[](length); for (uint256 i = 0; i < length; i++) { adminBalances[i] = swapStorage.getAdminBalance(i); } } function getAdminBalance(uint8 index) external view override returns (uint256) { return swapStorage.getAdminBalance((index)); } function calculateTokenAmount(uint256[] calldata amounts, bool deposit) external view override returns (uint256) { return swapStorage.calculateTokenAmount(amounts, deposit); } function calculateSwap( uint8 inIndex, uint8 outIndex, uint256 inAmount ) external view override returns (uint256) { return swapStorage.calculateSwap(inIndex, outIndex, inAmount); } function calculateRemoveLiquidity(uint256 amount) external view override returns (uint256[] memory) { return swapStorage.calculateRemoveLiquidity(amount); } function calculateRemoveLiquidityOneToken(uint256 amount, uint8 index) external view override returns (uint256) { return swapStorage.calculateRemoveLiquidityOneToken(amount, index); } /// RESTRICTED FUNCTION /** * @notice Sets the admin fee * @dev adminFee cannot be higher than 100% of the swap fee * swap fee cannot be higher than 1% of each swap * @param newSwapFee new swap fee to be applied on future transactions * @param newAdminFee new admin fee to be applied on future transactions */ function setFee(uint256 newSwapFee, uint256 newAdminFee) external onlyOwner { require(newSwapFee <= MAX_SWAP_FEE, "> maxSwapFee"); require(newAdminFee <= MAX_ADMIN_FEE, "> maxAdminFee"); swapStorage.adminFee = newAdminFee; swapStorage.fee = newSwapFee; emit NewFee(newSwapFee, newAdminFee); } /** * @notice Start ramping up or down A parameter towards given futureA_ and futureTime_ * Checks if the change is too rapid, and commits the new A value only when it falls under * the limit range. * @param futureA the new A to ramp towards * @param futureATime timestamp when the new A should be reached */ function rampA(uint256 futureA, uint256 futureATime) external onlyOwner { require(block.timestamp >= swapStorage.initialATime + (1 days), "< rampDelay"); // please wait 1 days before start a new ramping require(futureATime >= block.timestamp + (MIN_RAMP_TIME), "< minRampTime"); require(0 < futureA && futureA < MAX_A, "outOfRange"); uint256 initialAPrecise = swapStorage.getAPrecise(); uint256 futureAPrecise = futureA * StableSwapStorage.A_PRECISION; if (futureAPrecise < initialAPrecise) { require(futureAPrecise * (MAX_A_CHANGE) >= initialAPrecise, "> maxChange"); } else { require(futureAPrecise <= initialAPrecise * (MAX_A_CHANGE), "> maxChange"); } swapStorage.initialA = initialAPrecise; swapStorage.futureA = futureAPrecise; swapStorage.initialATime = block.timestamp; swapStorage.futureATime = futureATime; emit RampA(initialAPrecise, futureAPrecise, block.timestamp, futureATime); } function stopRampA() external onlyOwner { require(swapStorage.futureATime > block.timestamp, "alreadyStopped"); uint256 currentA = swapStorage.getAPrecise(); swapStorage.initialA = currentA; swapStorage.futureA = currentA; swapStorage.initialATime = block.timestamp; swapStorage.futureATime = block.timestamp; emit StopRampA(currentA, block.timestamp); } function setFeeController(address _feeController) external onlyOwner { require(_feeController != address(0), "zeroAddress"); feeController = _feeController; emit FeeControllerChanged(_feeController); } function setFeeDistributor(address _feeDistributor) external onlyOwner { require(_feeDistributor != address(0), "zeroAddress"); feeDistributor = _feeDistributor; emit FeeDistributorChanged(_feeDistributor); } function withdrawAdminFee() external override onlyFeeControllerOrOwner { for (uint256 i = 0; i < swapStorage.pooledTokens.length; i++) { IERC20 token = swapStorage.pooledTokens[i]; uint256 balance = token.balanceOf(address(this)) - (swapStorage.balances[i]); if (balance != 0) { token.safeTransfer(feeDistributor, balance); emit CollectProtocolFee(address(token), balance); } } } }
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"fees","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"invariant","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenSupply","type":"uint256"}],"name":"AddLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CollectProtocolFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newController","type":"address"}],"name":"FeeControllerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newController","type":"address"}],"name":"FeeDistributorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"adminFee","type":"uint256"}],"name":"NewFee","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":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"initialTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"futureTime","type":"uint256"}],"name":"RampA","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"fees","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"tokenSupply","type":"uint256"}],"name":"RemoveLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"fees","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"invariant","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenSupply","type":"uint256"}],"name":"RemoveLiquidityImbalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"coinAmount","type":"uint256"}],"name":"RemoveLiquidityOne","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"A","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"StopRampA","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"soldId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensSold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"boughtId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensBought","type":"uint256"}],"name":"TokenExchange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"MAX_A","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ADMIN_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_A_CHANGE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SWAP_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_RAMP_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"minMintAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"calculateRemoveLiquidity","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"index","type":"uint8"}],"name":"calculateRemoveLiquidityOneToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"inIndex","type":"uint8"},{"internalType":"uint8","name":"outIndex","type":"uint8"},{"internalType":"uint256","name":"inAmount","type":"uint256"}],"name":"calculateSwap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bool","name":"deposit","type":"bool"}],"name":"calculateTokenAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeDistributor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAPrecise","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"getAdminBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAdminBalances","outputs":[{"internalType":"uint256[]","name":"adminBalances","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLpToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumberOfTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"getToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"getTokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokenBalances","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTokenIndex","outputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokenPrecisionMultipliers","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokens","outputs":[{"internalType":"contract IERC20[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVirtualPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_coins","type":"address[]"},{"internalType":"uint8[]","name":"_decimals","type":"uint8[]"},{"internalType":"string","name":"lpTokenName","type":"string"},{"internalType":"string","name":"lpTokenSymbol","type":"string"},{"internalType":"uint256","name":"_A","type":"uint256"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_adminFee","type":"uint256"},{"internalType":"address","name":"_feeDistributor","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"futureA","type":"uint256"},{"internalType":"uint256","name":"futureATime","type":"uint256"}],"name":"rampA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"lpAmount","type":"uint256"},{"internalType":"uint256[]","name":"minAmounts","type":"uint256[]"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"maxBurnAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityImbalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"lpAmount","type":"uint256"},{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint256","name":"minAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityOneToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newSwapFee","type":"uint256"},{"internalType":"uint256","name":"newAdminFee","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeController","type":"address"}],"name":"setFeeController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeDistributor","type":"address"}],"name":"setFeeDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopRampA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"fromIndex","type":"uint8"},{"internalType":"uint8","name":"toIndex","type":"uint8"},{"internalType":"uint256","name":"inAmount","type":"uint256"},{"internalType":"uint256","name":"minOutAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapStorage","outputs":[{"internalType":"contract LPToken","name":"lpToken","type":"address"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"adminFee","type":"uint256"},{"internalType":"uint256","name":"initialA","type":"uint256"},{"internalType":"uint256","name":"futureA","type":"uint256"},{"internalType":"uint256","name":"initialATime","type":"uint256"},{"internalType":"uint256","name":"futureATime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenIndexes","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawAdminFee","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5061001a33610030565b6000805460ff60a01b1916905560018055610080565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61448b80620000906000396000f3fe60806040523480156200001157600080fd5b5060043610620002a95760003560e01c806384cdd9bc116200016d578063c4db7fa011620000d3578063e6ab28061162000092578063e6ab28061462000612578063efeecb511462000629578063f2fad2b61462000632578063f2fde38b1462000649578063f3de03621462000660578063fe49abe3146200066d57600080fd5b8063c4db7fa014620005d3578063ccfc2e8d14620005dd578063d41f656814620005f4578063d46300fd14620005fe578063e25aa5fa146200060857600080fd5b8063a1dc9031116200012c578063a1dc9031146200056d578063a95b089f1462000577578063aa6ca808146200058e578063ab3d854414620005a7578063ab5ac06114620005b3578063b28cb6dc14620005bc57600080fd5b806384cdd9bc14620004ff5780638554a7d414620005165780638da5cb5b146200052d57806391695586146200053f57806391ceb3eb146200055657600080fd5b80634d49e87d116200021357806366c0bd2411620001d257806366c0bd2414620004975780636999b37714620004ae578063715018a614620004c25780638214f5a414620004cc57806382b8660014620004de5780638456cb5914620004f557600080fd5b80634d49e87d14620003c857806352f7c98814620003df578063593d132c14620003f65780635c975abb146200040d5780635fd65f0f146200042b57600080fd5b806331cd52b0116200026c57806331cd52b01462000355578063342a87a1146200036c5780633969841514620003835780633e3a1560146200038e5780633ed4c67814620003a55780633f4ba83a14620003be57600080fd5b806304bc3b1c14620002ae57806306e9481c14620002eb5780630ba8195914620003055780630d43e8ad146200030f57806318f52ce2146200033c575b600080fd5b620002d4620002bf3660046200299c565b600f6020526000908152604090205460ff1681565b60405160ff90911681526020015b60405180910390f35b620002f66201518081565b604051908152602001620002e2565b620002f662000677565b600d5462000323906001600160a01b031681565b6040516001600160a01b039091168152602001620002e2565b6200034662000707565b604051620002e2919062002ec7565b620003466200036636600462002c63565b62000842565b620002f66200037d36600462002cd7565b6200093f565b620002f6620f424081565b620002f66200039f36600462002d05565b620009e2565b620003bc620003b63660046200299c565b62000b0c565b005b620003bc62000bd4565b620002f6620003d936600462002bc2565b62000c0d565b620003bc620003f036600462002cb5565b62000d1c565b620003bc6200040736600462002cb5565b62000e1c565b600054600160a01b900460ff166040519015158152602001620002e2565b600454600754600854600954600a54600b54600c5462000457966001600160a01b031695949392919087565b604080516001600160a01b0390981688526020880196909652948601939093526060850191909152608084015260a083015260c082015260e001620002e2565b620002d4620004a83660046200299c565b620010de565b600e5462000323906001600160a01b031681565b620003bc6200117a565b6004546001600160a01b031662000323565b62000323620004ef36600462002d42565b620011b3565b620003bc620011f8565b620002f66200051036600462002bc2565b6200122f565b620002f66200052736600462002d42565b620012eb565b6000546001600160a01b031662000323565b620002f66200055036600462002d9f565b6200137e565b620002f66200056736600462002d42565b620014b0565b62000346620014eb565b620002f66200058836600462002d5f565b62001547565b62000598620015f4565b604051620002e2919062002e78565b620002f66305f5e10081565b620002f6600a81565b620003bc620005cd366004620029b9565b6200165a565b620003bc62001cf7565b620003bc620005ee3660046200299c565b62001e42565b6200034662001f04565b620002f662001f5f565b620002f662001f9b565b620002f66200062336600462002a9e565b62001fd7565b600354620002f6565b620003466200064336600462002c31565b6200201a565b620003bc6200065a3660046200299c565b620020af565b620002f66402540be40081565b620003bc62002151565b604051637461cf1b60e01b815260036004820152600090733bccb81261aba479c1ecab28aa92a248ae2e130e90637461cf1b906024015b60206040518083038186803b158015620006c757600080fd5b505af4158015620006dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000702919062002c4a565b905090565b6003546060908067ffffffffffffffff8111156200073557634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156200075f578160200160208202803683370190505b50915060005b818110156200083d57604051630a1368cd60e01b81526003600482015260248101829052733bccb81261aba479c1ecab28aa92a248ae2e130e90630a1368cd9060440160206040518083038186803b158015620007c157600080fd5b505af4158015620007d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007fc919062002c4a565b8382815181106200081d57634e487b7160e01b600052603260045260246000fd5b60209081029190910101528062000834816200327f565b91505062000765565b505090565b606060026001541415620008735760405162461bcd60e51b81526004016200086a9062002fc8565b60405180910390fd5b600260015581428110156200089c5760405162461bcd60e51b81526004016200086a9062002fa7565b60405163d0b1a00560e01b8152733bccb81261aba479c1ecab28aa92a248ae2e130e9063d0b1a00590620008da906003908990899060040162003074565b60006040518083038186803b158015620008f357600080fd5b505af415801562000908573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262000932919081019062002b26565b6001805595945050505050565b6040516309bba52360e31b8152600360048201526024810183905260ff82166044820152600090733bccb81261aba479c1ecab28aa92a248ae2e130e90634ddd29189060640160206040518083038186803b1580156200099e57600080fd5b505af4158015620009b3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620009d9919062002c4a565b90505b92915050565b60006002600154141562000a0a5760405162461bcd60e51b81526004016200086a9062002fc8565b6002600155600054600160a01b900460ff161562000a3c5760405162461bcd60e51b81526004016200086a9062002f48565b818042111562000a605760405162461bcd60e51b81526004016200086a9062002fa7565b6040516346732ec760e11b8152600360048201526024810187905260ff8616604482015260648101859052733bccb81261aba479c1ecab28aa92a248ae2e130e90638ce65d8e9060840160206040518083038186803b15801562000ac357600080fd5b505af415801562000ad8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000afe919062002c4a565b600180559695505050505050565b6000546001600160a01b0316331462000b395760405162461bcd60e51b81526004016200086a9062002f72565b6001600160a01b03811662000b7f5760405162461bcd60e51b815260206004820152600b60248201526a7a65726f4164647265737360a81b60448201526064016200086a565b600e80546001600160a01b0319166001600160a01b0383169081179091556040519081527f4c3f3b9852ccceadd50f16518f348e2624c8f0240acdd5bc81911c0fba83ec67906020015b60405180910390a150565b6000546001600160a01b0316331462000c015760405162461bcd60e51b81526004016200086a9062002f72565b62000c0b6200233f565b565b60008054600160a01b900460ff161562000c3b5760405162461bcd60e51b81526004016200086a9062002f48565b6002600154141562000c615760405162461bcd60e51b81526004016200086a9062002fc8565b6002600155814281101562000c8a5760405162461bcd60e51b81526004016200086a9062002fa7565b604051637217bafd60e11b8152733bccb81261aba479c1ecab28aa92a248ae2e130e9063e42f75fa9062000cc8906003908990899060040162003049565b60206040518083038186803b15801562000ce157600080fd5b505af415801562000cf6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000932919062002c4a565b6000546001600160a01b0316331462000d495760405162461bcd60e51b81526004016200086a9062002f72565b6305f5e10082111562000d8e5760405162461bcd60e51b815260206004820152600c60248201526b3e206d61785377617046656560a01b60448201526064016200086a565b6402540be40081111562000dd55760405162461bcd60e51b815260206004820152600d60248201526c3e206d617841646d696e46656560981b60448201526064016200086a565b6008819055600782905560408051838152602081018390527fbe12859b636aed607d5230b2cc2711f68d70e51060e6cca1f575ef5d2fcc95d1910160405180910390a15050565b6000546001600160a01b0316331462000e495760405162461bcd60e51b81526004016200086a9062002f72565b600b5462000e5b9062015180620030f0565b42101562000e9a5760405162461bcd60e51b815260206004820152600b60248201526a3c2072616d7044656c617960a81b60448201526064016200086a565b62000ea96201518042620030f0565b81101562000eea5760405162461bcd60e51b815260206004820152600d60248201526c3c206d696e52616d7054696d6560981b60448201526064016200086a565b81600010801562000efd5750620f424082105b62000f385760405162461bcd60e51b815260206004820152600a6024820152696f75744f6652616e676560b01b60448201526064016200086a565b604051637461cf1b60e01b815260036004820152600090733bccb81261aba479c1ecab28aa92a248ae2e130e90637461cf1b9060240160206040518083038186803b15801562000f8757600080fd5b505af415801562000f9c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000fc2919062002c4a565b9050600062000fd360648562003210565b90508181101562001030578162000fec600a8362003210565b10156200102a5760405162461bcd60e51b815260206004820152600b60248201526a3e206d61784368616e676560a81b60448201526064016200086a565b6200107c565b6200103d600a8362003210565b8111156200107c5760405162461bcd60e51b815260206004820152600b60248201526a3e206d61784368616e676560a81b60448201526064016200086a565b6009829055600a81905542600b819055600c84905560408051848152602081018490528082019290925260608201859052517fa2b71ec6df949300b59aab36b55e189697b750119dd349fcfa8c0f779e83c2549181900360800190a150505050565b6001600160a01b0381166000818152600f60205260409020546003805460ff9092169291839081106200112157634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031614620011755760405162461bcd60e51b815260206004820152600d60248201526c1d1bdad95b939bdd119bdd5b99609a1b60448201526064016200086a565b919050565b6000546001600160a01b03163314620011a75760405162461bcd60e51b81526004016200086a9062002f72565b62000c0b6000620023de565b600060036000018260ff1681548110620011dd57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031692915050565b6000546001600160a01b03163314620012255760405162461bcd60e51b81526004016200086a9062002f72565b62000c0b6200242e565b600060026001541415620012575760405162461bcd60e51b81526004016200086a9062002fc8565b6002600155600054600160a01b900460ff1615620012895760405162461bcd60e51b81526004016200086a9062002f48565b8180421115620012ad5760405162461bcd60e51b81526004016200086a9062002fa7565b60405163576b973560e01b8152733bccb81261aba479c1ecab28aa92a248ae2e130e9063576b97359062000cc8906003908990899060040162003049565b604051630a1368cd60e01b81526003600482015260ff82166024820152600090733bccb81261aba479c1ecab28aa92a248ae2e130e90630a1368cd9060440160206040518083038186803b1580156200134357600080fd5b505af415801562001358573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620009dc919062002c4a565b60008054600160a01b900460ff1615620013ac5760405162461bcd60e51b81526004016200086a9062002f48565b60026001541415620013d25760405162461bcd60e51b81526004016200086a9062002fc8565b60026001558142811015620013fb5760405162461bcd60e51b81526004016200086a9062002fa7565b604051633a8d10bd60e01b81526003600482015260ff8089166024830152871660448201526064810186905260848101859052733bccb81261aba479c1ecab28aa92a248ae2e130e90633a8d10bd9060a40160206040518083038186803b1580156200146657600080fd5b505af41580156200147b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620014a1919062002c4a565b60018055979650505050505050565b6000600380018260ff1681548110620014d957634e487b7160e01b600052603260045260246000fd5b90600052602060002001549050919050565b6060600380018054806020026020016040519081016040528092919081815260200182805480156200153d57602002820191906000526020600020905b81548152602001906001019080831162001528575b5050505050905090565b6040516376311d0f60e11b81526003600482015260ff80851660248301528316604482015260648101829052600090733bccb81261aba479c1ecab28aa92a248ae2e130e9063ec623a1e906084015b60206040518083038186803b158015620015af57600080fd5b505af4158015620015c4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620015ea919062002c4a565b90505b9392505050565b606060036000018054806020026020016040519081016040528092919081815260200182805480156200153d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162001632575050505050905090565b6000546001600160a01b03163314620016875760405162461bcd60e51b81526004016200086a9062002f72565b600254610100900460ff1680620016a1575060025460ff16155b620017065760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016200086a565b600254610100900460ff1615801562001729576002805461ffff19166101011790555b87518951146200177c5760405162461bcd60e51b815260206004820152601d60248201527f636f696e734c656e67746820213d20646563696d616c734c656e67746800000060448201526064016200086a565b6001600160a01b038216620017cd5760405162461bcd60e51b81526020600482015260166024820152756665654469737472696275746f72203d20656d70747960501b60448201526064016200086a565b885160008167ffffffffffffffff811115620017f957634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801562001823578160200160208202803683370190505b50905060008267ffffffffffffffff8111156200185057634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156200187a578160200160208202803683370190505b50905060005b8381101562001ad65760006001600160a01b03168d8281518110620018b557634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031614156200190c5760405162461bcd60e51b8152602060048201526013602482015272696e76616c6964546f6b656e4164647265737360681b60448201526064016200086a565b60128c82815181106200192f57634e487b7160e01b600052603260045260246000fd5b602002602001015160ff1611156200197c5760405162461bcd60e51b815260206004820152600f60248201526e696e76616c6964446563696d616c7360881b60448201526064016200086a565b8b81815181106200199d57634e487b7160e01b600052603260045260246000fd5b602002602001015160ff166012620019b6919062003232565b620019c390600a62003154565b838281518110620019e457634e487b7160e01b600052603260045260246000fd5b6020026020010181815250508c818151811062001a1157634e487b7160e01b600052603260045260246000fd5b602002602001015182828151811062001a3a57634e487b7160e01b600052603260045260246000fd5b60200260200101906001600160a01b031690816001600160a01b03168152505080600f600084848151811062001a8057634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908360ff160217905550808062001acd906200327f565b91505062001880565b50620f4240881062001b145760405162461bcd60e51b81526020600482015260066024820152653e206d61784160d01b60448201526064016200086a565b6305f5e10087111562001b595760405162461bcd60e51b815260206004820152600c60248201526b3e206d61785377617046656560a01b60448201526064016200086a565b6402540be40086111562001ba05760405162461bcd60e51b815260206004820152600d60248201526c3e206d617841646d696e46656560981b60448201526064016200086a565b898960405162001bb090620026e2565b62001bbd92919062002f16565b604051809103906000f08015801562001bda573d6000803e3d6000fd5b50600480546001600160a01b0319166001600160a01b03929092169190911790558267ffffffffffffffff81111562001c2357634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801562001c4d578160200160208202803683370190505b50805162001c6491600691602090910190620026f0565b50815162001c7a906005906020850190620026f0565b50805162001c9090600390602084019062002740565b5062001c9e60648962003210565b60095562001cae60648962003210565b600a5550505060078490556008839055600d80546001600160a01b0319166001600160a01b038416179055801562001cec576002805461ff00191690555b505050505050505050565b6000546001600160a01b0316331462001d245760405162461bcd60e51b81526004016200086a9062002f72565b600c54421062001d685760405162461bcd60e51b815260206004820152600e60248201526d185b1c9958591e54dd1bdc1c195960921b60448201526064016200086a565b604051637461cf1b60e01b815260036004820152600090733bccb81261aba479c1ecab28aa92a248ae2e130e90637461cf1b9060240160206040518083038186803b15801562001db757600080fd5b505af415801562001dcc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001df2919062002c4a565b6009819055600a81905542600b819055600c8190556040519192507f46e22fb3709ad289f62ce63d469248536dbc78d82b84a3d7e74ad606dc2019389162000bc991848252602082015260400190565b6000546001600160a01b0316331462001e6f5760405162461bcd60e51b81526004016200086a9062002f72565b6001600160a01b03811662001eb55760405162461bcd60e51b815260206004820152600b60248201526a7a65726f4164647265737360a81b60448201526064016200086a565b600d80546001600160a01b0319166001600160a01b0383169081179091556040519081527fae5a12c29e496b092467a620746b9eaf4e0e231a631a4370c233b1fac38e8e269060200162000bc9565b606060036002018054806020026020016040519081016040528092919081815260200182805480156200153d576020028201919060005260206000209081548152602001906001019080831162001528575050505050905090565b60405163172a21f960e31b815260036004820152600090733bccb81261aba479c1ecab28aa92a248ae2e130e9063b9510fc890602401620006ae565b604051631bd62df560e11b815260036004820152600090733bccb81261aba479c1ecab28aa92a248ae2e130e906337ac5bea90602401620006ae565b6040516345b69ab760e01b8152600090733bccb81261aba479c1ecab28aa92a248ae2e130e906345b69ab790620015969060039088908890889060040162002fff565b60405163f94eed8760e01b81526003600482015260248101829052606090733bccb81261aba479c1ecab28aa92a248ae2e130e9063f94eed879060440160006040518083038186803b1580156200207057600080fd5b505af415801562002085573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620009dc919081019062002b26565b6000546001600160a01b03163314620020dc5760405162461bcd60e51b81526004016200086a9062002f72565b6001600160a01b038116620021435760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016200086a565b6200214e81620023de565b50565b600e546001600160a01b03163314806200217557506000546001600160a01b031633145b620021bb5760405162461bcd60e51b815260206004820152601560248201527410b332b2a1b7b73a3937b63632b927b927bbb732b960591b60448201526064016200086a565b60005b6003548110156200214e57600060036000018281548110620021f057634e487b7160e01b600052603260045260246000fd5b6000918252602082200154600680546001600160a01b03909216935090849081106200222c57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546040516370a0823160e01b81523060048201526001600160a01b038416906370a082319060240160206040518083038186803b1580156200227857600080fd5b505afa1580156200228d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620022b3919062002c4a565b620022bf919062003232565b905080156200232757600d54620022e4906001600160a01b0384811691168362002497565b604080516001600160a01b0384168152602081018390527fee3859efa95e525bc2bcb149b51b60a8bb4e89c647392d9d4112e03c3e73bdd6910160405180910390a15b5050808062002336906200327f565b915050620021be565b600054600160a01b900460ff16620023915760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016200086a565b6000805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600054600160a01b900460ff16156200245b5760405162461bcd60e51b81526004016200086a9062002f48565b6000805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258620023c13390565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052620024eb908490620024f0565b505050565b600062002547826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316620025c99092919063ffffffff16565b805190915015620024eb578080602001905181019062002568919062002c12565b620024eb5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016200086a565b6060620015ea848460008585843b620026255760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016200086a565b600080866001600160a01b0316858760405162002643919062002e5a565b60006040518083038185875af1925050503d806000811462002682576040519150601f19603f3d011682016040523d82523d6000602084013e62002687565b606091505b509150915062002699828286620026a4565b979650505050505050565b60608315620026b5575081620015ed565b825115620026c65782518084602001fd5b8160405162461bcd60e51b81526004016200086a919062002f01565b61117d80620032d983390190565b8280548282559060005260206000209081019282156200272e579160200282015b828111156200272e57825182559160200191906001019062002711565b506200273c92915062002798565b5090565b8280548282559060005260206000209081019282156200272e579160200282015b828111156200272e57825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019062002761565b5b808211156200273c576000815560010162002799565b80356001600160a01b03811681146200117557600080fd5b600082601f830112620027d8578081fd5b81356020620027f1620027eb83620030c9565b62003095565b80838252828201915082860187848660051b890101111562002811578586fd5b855b858110156200283a576200282782620027af565b8452928401929084019060010162002813565b5090979650505050505050565b600082601f83011262002858578081fd5b813560206200286b620027eb83620030c9565b80838252828201915082860187848660051b89010111156200288b578586fd5b855b858110156200283a578135845292840192908401906001016200288d565b600082601f830112620028bc578081fd5b81356020620028cf620027eb83620030c9565b80838252828201915082860187848660051b8901011115620028ef578586fd5b855b858110156200283a5762002905826200298a565b84529284019290840190600101620028f1565b600082601f83011262002929578081fd5b813567ffffffffffffffff811115620029465762002946620032b3565b6200295b601f8201601f191660200162003095565b81815284602083860101111562002970578283fd5b816020850160208301379081016020019190915292915050565b803560ff811681146200117557600080fd5b600060208284031215620029ae578081fd5b620009d982620027af565b600080600080600080600080610100898b031215620029d6578384fd5b883567ffffffffffffffff80821115620029ee578586fd5b620029fc8c838d01620027c7565b995060208b013591508082111562002a12578586fd5b62002a208c838d01620028ab565b985060408b013591508082111562002a36578586fd5b62002a448c838d0162002918565b975060608b013591508082111562002a5a578586fd5b5062002a698b828c0162002918565b9550506080890135935060a0890135925060c0890135915062002a8f60e08a01620027af565b90509295985092959890939650565b60008060006040848603121562002ab3578283fd5b833567ffffffffffffffff8082111562002acb578485fd5b818601915086601f83011262002adf578485fd5b81358181111562002aee578586fd5b8760208260051b850101111562002b03578586fd5b6020928301955093505084013562002b1b81620032c9565b809150509250925092565b6000602080838503121562002b39578182fd5b825167ffffffffffffffff81111562002b50578283fd5b8301601f8101851362002b61578283fd5b805162002b72620027eb82620030c9565b80828252848201915084840188868560051b870101111562002b92578687fd5b8694505b8385101562002bb657805183526001949094019391850191850162002b96565b50979650505050505050565b60008060006060848603121562002bd7578283fd5b833567ffffffffffffffff81111562002bee578384fd5b62002bfc8682870162002847565b9660208601359650604090950135949350505050565b60006020828403121562002c24578081fd5b8151620015ed81620032c9565b60006020828403121562002c43578081fd5b5035919050565b60006020828403121562002c5c578081fd5b5051919050565b60008060006060848603121562002c78578081fd5b83359250602084013567ffffffffffffffff81111562002c96578182fd5b62002ca48682870162002847565b925050604084013590509250925092565b6000806040838503121562002cc8578182fd5b50508035926020909101359150565b6000806040838503121562002cea578182fd5b8235915062002cfc602084016200298a565b90509250929050565b6000806000806080858703121562002d1b578182fd5b8435935062002d2d602086016200298a565b93969395505050506040820135916060013590565b60006020828403121562002d54578081fd5b620009d9826200298a565b60008060006060848603121562002d74578081fd5b62002d7f846200298a565b925062002d8f602085016200298a565b9150604084013590509250925092565b600080600080600060a0868803121562002db7578283fd5b62002dc2866200298a565b945062002dd2602087016200298a565b94979496505050506040830135926060810135926080909101359150565b6000815180845260208085019450808401835b8381101562002e215781518752958201959082019060010162002e03565b509495945050505050565b6000815180845262002e468160208601602086016200324c565b601f01601f19169290920160200192915050565b6000825162002e6e8184602087016200324c565b9190910192915050565b6020808252825182820181905260009190848201906040850190845b8181101562002ebb5783516001600160a01b03168352928401929184019160010162002e94565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b8181101562002ebb5783518352928401929184019160010162002ee3565b602081526000620009d9602083018462002e2c565b60408152600062002f2b604083018562002e2c565b828103602084015262002f3f818562002e2c565b95945050505050565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252600790820152661d1a5b595bdd5d60ca1b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b848152606060208201819052810183905260006001600160fb1b0384111562003026578081fd5b8360051b8086608085013782016080019081529115156040909101529392505050565b83815260606020820152600062003064606083018562002df0565b9050826040830152949350505050565b83815282602082015260606040820152600062002f3f606083018462002df0565b604051601f8201601f1916810167ffffffffffffffff81118282101715620030c157620030c1620032b3565b604052919050565b600067ffffffffffffffff821115620030e657620030e6620032b3565b5060051b60200190565b600082198211156200310657620031066200329d565b500190565b600181815b808511156200314c5781600019048211156200313057620031306200329d565b808516156200313e57918102915b93841c939080029062003110565b509250929050565b6000620009d983836000826200316d57506001620009dc565b816200317c57506000620009dc565b8160018114620031955760028114620031a057620031c0565b6001915050620009dc565b60ff841115620031b457620031b46200329d565b50506001821b620009dc565b5060208310610133831016604e8410600b8410161715620031e5575081810a620009dc565b620031f183836200310b565b80600019048211156200320857620032086200329d565b029392505050565b60008160001904831182151516156200322d576200322d6200329d565b500290565b6000828210156200324757620032476200329d565b500390565b60005b83811015620032695781810151838201526020016200324f565b8381111562003279576000848401525b50505050565b60006000198214156200329657620032966200329d565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b80151581146200214e57600080fdfe60806040523480156200001157600080fd5b506040516200117d3803806200117d833981016040819052620000349162000233565b818162000041336200008a565b815162000056906004906020850190620000da565b5080516200006c906005906020840190620000da565b5050600680546001600160a01b0319163317905550620002ed915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b828054620000e8906200029a565b90600052602060002090601f0160209004810192826200010c576000855562000157565b82601f106200012757805160ff191683800117855562000157565b8280016001018555821562000157579182015b82811115620001575782518255916020019190600101906200013a565b506200016592915062000169565b5090565b5b808211156200016557600081556001016200016a565b600082601f83011262000191578081fd5b81516001600160401b0380821115620001ae57620001ae620002d7565b604051601f8301601f19908116603f01168101908282118183101715620001d957620001d9620002d7565b81604052838152602092508683858801011115620001f5578485fd5b8491505b83821015620002185785820183015181830184015290820190620001f9565b838211156200022957848385830101525b9695505050505050565b6000806040838503121562000246578182fd5b82516001600160401b03808211156200025d578384fd5b6200026b8683870162000180565b9350602085015191508082111562000281578283fd5b50620002908582860162000180565b9150509250929050565b600181811c90821680620002af57607f821691505b60208210811415620002d157634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b610e8080620002fd6000396000f3fe608060405234801561001057600080fd5b50600436106101165760003560e01c8063715018a6116100a257806395d89b411161007157806395d89b411461024b578063a457c2d714610253578063a9059cbb14610266578063dd62ed3e14610279578063f2fde38b146102b257600080fd5b8063715018a6146101f457806379cc6790146101fc5780638119c0651461020f5780638da5cb5b1461023a57600080fd5b8063313ce567116100e9578063313ce56714610181578063395093511461019057806340c10f19146101a357806342966c68146101b857806370a08231146101cb57600080fd5b806306fdde031461011b578063095ea7b31461013957806318160ddd1461015c57806323b872dd1461016e575b600080fd5b6101236102c5565b6040516101309190610d42565b60405180910390f35b61014c610147366004610d01565b610357565b6040519015158152602001610130565b6003545b604051908152602001610130565b61014c61017c366004610cc6565b61036d565b60405160128152602001610130565b61014c61019e366004610d01565b61041c565b6101b66101b1366004610d01565b610458565b005b6101b66101c6366004610d2a565b6104d1565b6101606101d9366004610c73565b6001600160a01b031660009081526001602052604090205490565b6101b66104de565b6101b661020a366004610d01565b610514565b600654610222906001600160a01b031681565b6040516001600160a01b039091168152602001610130565b6000546001600160a01b0316610222565b61012361059a565b61014c610261366004610d01565b6105a9565b61014c610274366004610d01565b610642565b610160610287366004610c94565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b6101b66102c0366004610c73565b61064f565b6060600480546102d490610df9565b80601f016020809104026020016040519081016040528092919081815260200182805461030090610df9565b801561034d5780601f106103225761010080835404028352916020019161034d565b820191906000526020600020905b81548152906001019060200180831161033057829003601f168201915b5050505050905090565b60006103643384846106e7565b50600192915050565b600061037a84848461080b565b6001600160a01b0384166000908152600260209081526040808320338452909152902054828110156104045760405162461bcd60e51b815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616044820152676c6c6f77616e636560c01b60648201526084015b60405180910390fd5b61041185338584036106e7565b506001949350505050565b3360008181526002602090815260408083206001600160a01b03871684529091528120549091610364918590610453908690610dca565b6106e7565b6000546001600160a01b031633146104825760405162461bcd60e51b81526004016103fb90610d95565b600081116104c35760405162461bcd60e51b815260206004820152600e60248201526d1e995c9bd35a5b9d105b5bdd5b9d60921b60448201526064016103fb565b6104cd82826109da565b5050565b6104db3382610ab9565b50565b6000546001600160a01b031633146105085760405162461bcd60e51b81526004016103fb90610d95565b6105126000610c07565b565b60006105208333610287565b90508181101561057e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a206275726e20616d6f756e74206578636565647320616c6c6f77604482015263616e636560e01b60648201526084016103fb565b61058b83338484036106e7565b6105958383610ab9565b505050565b6060600580546102d490610df9565b3360009081526002602090815260408083206001600160a01b03861684529091528120548281101561062b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016103fb565b61063833858584036106e7565b5060019392505050565b600061036433848461080b565b6000546001600160a01b031633146106795760405162461bcd60e51b81526004016103fb90610d95565b6001600160a01b0381166106de5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016103fb565b6104db81610c07565b6001600160a01b0383166107495760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016103fb565b6001600160a01b0382166107aa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016103fb565b6001600160a01b0383811660008181526002602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6001600160a01b03831661086f5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016103fb565b6001600160a01b0382166108d15760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016103fb565b6001600160a01b038316600090815260016020526040902054818110156109495760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016103fb565b6001600160a01b03808516600090815260016020526040808220858503905591851681529081208054849290610980908490610dca565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516109cc91815260200190565b60405180910390a350505050565b6001600160a01b038216610a305760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016103fb565b8060036000828254610a429190610dca565b90915550506001600160a01b03821660009081526001602052604081208054839290610a6f908490610dca565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b6001600160a01b038216610b195760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016103fb565b6001600160a01b03821660009081526001602052604090205481811015610b8d5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016103fb565b6001600160a01b0383166000908152600160205260408120838303905560038054849290610bbc908490610de2565b90915550506040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80356001600160a01b0381168114610c6e57600080fd5b919050565b600060208284031215610c84578081fd5b610c8d82610c57565b9392505050565b60008060408385031215610ca6578081fd5b610caf83610c57565b9150610cbd60208401610c57565b90509250929050565b600080600060608486031215610cda578081fd5b610ce384610c57565b9250610cf160208501610c57565b9150604084013590509250925092565b60008060408385031215610d13578182fd5b610d1c83610c57565b946020939093013593505050565b600060208284031215610d3b578081fd5b5035919050565b6000602080835283518082850152825b81811015610d6e57858101830151858201604001528201610d52565b81811115610d7f5783604083870101525b50601f01601f1916929092016040019392505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60008219821115610ddd57610ddd610e34565b500190565b600082821015610df457610df4610e34565b500390565b600181811c90821680610e0d57607f821691505b60208210811415610e2e57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220940a4f405437c05e8761ed20877c8d14cc4e8987da3ac7338569353e5a53e99f64736f6c63430008040033a2646970667358221220f1e0fdff8282f199e04c55c4ef68f3c457dbd5f44d255121bbc507bb09f15ef664736f6c63430008040033
Deployed ByteCode Sourcemap
62386:10669:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63022:45;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;28457:4:1;28445:17;;;28427:36;;28415:2;28400:18;63022:45:0;;;;;;;;62593:46;;62633:6;62593:46;;;;;23453:25:1;;;23441:2;23426:18;62593:46:0;23408:76:1;66949:115:0;;;:::i;62951:29::-;;;;;-1:-1:-1;;;;;62951:29:0;;;;;;-1:-1:-1;;;;;11043:32:1;;;11025:51;;11013:2;10998:18;62951:29:0;10980:102:1;68224:330:0;;;:::i;:::-;;;;;;;:::i;65750:281::-;;;;;;:::i;:::-;;:::i;69321:197::-;;;;;;:::i;:::-;;:::i;62646:35::-;;62678:3;62646:35;;66039:320;;;;;;:::i;:::-;;:::i;72075:233::-;;;;;;:::i;:::-;;:::i;:::-;;23475:67;;;:::i;65121:284::-;;;;;;:::i;:::-;;:::i;69884:342::-;;;;;;:::i;:::-;;:::i;70584:1049::-;;;;;;:::i;:::-;;:::i;22082:86::-;22129:4;22153:7;-1:-1:-1;;;22153:7:0;;;;22082:86;;12851:14:1;;12844:22;12826:41;;12814:2;12799:18;22082:86:0;12781:92:1;62896:48:0;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;62896:48:0;;;;;;;;;;;;;-1:-1:-1;;;;;13449:32:1;;;13431:51;;13513:2;13498:18;;13491:34;;;;13541:18;;;13534:34;;;;13599:2;13584:18;;13577:34;;;;13642:3;13627:19;;13620:35;13469:3;13671:19;;13664:35;13730:3;13715:19;;13708:35;13418:3;13403:19;62896:48:0;13385:364:1;67451:215:0;;;;;;:::i;:::-;;:::i;62987:28::-;;;;;-1:-1:-1;;;;;62987:28:0;;;20379:94;;;:::i;67336:107::-;67416:19;;-1:-1:-1;;;;;67416:19:0;67336:107;;67200:128;;;;;;:::i;:::-;;:::i;23404:63::-;;;:::i;66367:308::-;;;;;;:::i;:::-;;:::i;68562:141::-;;;;;;:::i;:::-;;:::i;19728:87::-;19774:7;19801:6;-1:-1:-1;;;;;19801:6:0;19728:87;;65413:329;;;;;;:::i;:::-;;:::i;67949:132::-;;;;;;:::i;:::-;;:::i;67817:124::-;;;:::i;68908:227::-;;;;;;:::i;:::-;;:::i;67072:120::-;;;:::i;:::-;;;;;;;:::i;62819:42::-;;62858:3;62819:42;;62712:41;;62751:2;62712:41;;63366:1721;;;;;;:::i;:::-;;:::i;71641:426::-;;;:::i;72316:240::-;;;;;;:::i;:::-;;:::i;67674:135::-;;;:::i;66840:101::-;;;:::i;66709:123::-;;;:::i;68711:189::-;;;;;;:::i;:::-;;:::i;68089:127::-;68177:11;:31;68089:127;;69143:170;;;;;;:::i;:::-;;:::i;20628:192::-;;;;;;:::i;:::-;;:::i;62760:44::-;;62800:4;62760:44;;72564:488;;;:::i;66949:115::-;67031:25;;-1:-1:-1;;;67031:25:0;;:11;:25;;;23453::1;67004:7:0;;67031:23;;;;23426:18:1;;67031:25:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;67024:32;;66949:115;:::o;68224:330::-;68344:11;:31;68284:30;;68344:31;68402:21;;;;;;-1:-1:-1;;;68402:21:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;68402:21:0;;68386:37;;68439:9;68434:113;68458:6;68454:1;:10;68434:113;;;68505:30;;-1:-1:-1;;;68505:30:0;;:11;:30;;;24839:25:1;24880:18;;;24873:34;;;68505:27:0;;;;24812:18:1;;68505:30:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;68486:13;68500:1;68486:16;;;;;;-1:-1:-1;;;68486:16:0;;;;;;;;;;;;;;;;;;:49;68466:3;;;;:::i;:::-;;;;68434:113;;;;68224:330;;:::o;65750:281::-;65938:16;256:1;852:7;;:19;;844:63;;;;-1:-1:-1;;;844:63:0;;;;;;;:::i;:::-;;;;;;;;;256:1;985:7;:18;65919:8;63137:15:::1;:28:::0;-1:-1:-1;63137:28:0::1;63129:48;;;;-1:-1:-1::0;;;63129:48:0::1;;;;;;;:::i;:::-;65974:49:::2;::::0;-1:-1:-1;;;65974:49:0;;:27:::2;::::0;::::2;::::0;:49:::2;::::0;:11:::2;::::0;66002:8;;66012:10;;65974:49:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;::::0;;::::2;-1:-1:-1::0;;65974:49:0::2;::::0;::::2;;::::0;::::2;::::0;;;::::2;::::0;::::2;:::i;:::-;212:1:::0;1164:22;;65967:56;65750:281;-1:-1:-1;;;;;65750:281:0:o;69321:197::-;69451:59;;-1:-1:-1;;;69451:59:0;;:11;:59;;;25602:25:1;25643:18;;;25636:34;;;25718:4;25706:17;;25686:18;;;25679:45;69424:7:0;;69451:44;;;;25575:18:1;;69451:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;69444:66;;69321:197;;;;;:::o;66039:320::-;66261:7;256:1;852:7;;:19;;844:63;;;;-1:-1:-1;;;844:63:0;;;;;;;:::i;:::-;256:1;985:7;:18;22129:4;22153:7;-1:-1:-1;;;22153:7:0;;;;22407:9:::1;22399:38;;;;-1:-1:-1::0;;;22399:38:0::1;;;;;;;:::i;:::-;66242:8:::2;63156:9;63137:15;:28;;63129:48;;;;-1:-1:-1::0;;;63129:48:0::2;;;;;;;:::i;:::-;66288:63:::3;::::0;-1:-1:-1;;;66288:63:0;;:11:::3;:63;::::0;::::3;26002:25:1::0;26043:18;;;26036:34;;;26118:4;26106:17;;26086:18;;;26079:45;26140:18;;;26133:34;;;66288:35:0::3;::::0;::::3;::::0;25974:19:1;;66288:63:0::3;;;;;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;212:1:::0;1164:22;;66281:70;66039:320;-1:-1:-1;;;;;;66039:320:0:o;72075:233::-;19774:7;19801:6;-1:-1:-1;;;;;19801:6:0;18596:10;19948:23;19940:68;;;;-1:-1:-1;;;19940:68:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;72163:28:0;::::1;72155:52;;;::::0;-1:-1:-1;;;72155:52:0;;18201:2:1;72155:52:0::1;::::0;::::1;18183:21:1::0;18240:2;18220:18;;;18213:30;-1:-1:-1;;;18259:18:1;;;18252:41;18310:18;;72155:52:0::1;18173:161:1::0;72155:52:0::1;72218:13;:30:::0;;-1:-1:-1;;;;;;72218:30:0::1;-1:-1:-1::0;;;;;72218:30:0;::::1;::::0;;::::1;::::0;;;72264:36:::1;::::0;11025:51:1;;;72264:36:0::1;::::0;11013:2:1;10998:18;72264:36:0::1;;;;;;;;72075:233:::0;:::o;23475:67::-;19774:7;19801:6;-1:-1:-1;;;;;19801:6:0;18596:10;19948:23;19940:68;;;;-1:-1:-1;;;19940:68:0;;;;;;;:::i;:::-;23524:10:::1;:8;:10::i;:::-;23475:67::o:0;65121:284::-;65322:7;22153;;-1:-1:-1;;;22153:7:0;;;;22407:9;22399:38;;;;-1:-1:-1;;;22399:38:0;;;;;;;:::i;:::-;256:1:::1;852:7;;:19;;844:63;;;;-1:-1:-1::0;;;844:63:0::1;;;;;;;:::i;:::-;256:1;985:7;:18:::0;65303:8;63137:15:::2;:28:::0;-1:-1:-1;63137:28:0::2;63129:48;;;;-1:-1:-1::0;;;63129:48:0::2;;;;;;;:::i;:::-;65349::::3;::::0;-1:-1:-1;;;65349:48:0;;:24:::3;::::0;::::3;::::0;:48:::3;::::0;:11:::3;::::0;65374:7;;65383:13;;65349:48:::3;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;69884:342::-:0;19774:7;19801:6;-1:-1:-1;;;;;19801:6:0;18596:10;19948:23;19940:68;;;;-1:-1:-1;;;19940:68:0;;;;;;;:::i;:::-;62858:3:::1;69979:10;:26;;69971:51;;;::::0;-1:-1:-1;;;69971:51:0;;16003:2:1;69971:51:0::1;::::0;::::1;15985:21:1::0;16042:2;16022:18;;;16015:30;-1:-1:-1;;;16061:18:1;;;16054:42;16113:18;;69971:51:0::1;15975:162:1::0;69971:51:0::1;62800:4;70041:11;:28;;70033:54;;;::::0;-1:-1:-1;;;70033:54:0;;17096:2:1;70033:54:0::1;::::0;::::1;17078:21:1::0;17135:2;17115:18;;;17108:30;-1:-1:-1;;;17154:18:1;;;17147:43;17207:18;;70033:54:0::1;17068:163:1::0;70033:54:0::1;70098:20:::0;:34;;;70143:15;:28;;;70187:31:::1;::::0;;24839:25:1;;;24895:2;24880:18;;24873:34;;;70187:31:0::1;::::0;24812:18:1;70187:31:0::1;;;;;;;69884:342:::0;;:::o;70584:1049::-;19774:7;19801:6;-1:-1:-1;;;;;19801:6:0;18596:10;19948:23;19940:68;;;;-1:-1:-1;;;19940:68:0;;;;;;;:::i;:::-;70694:24;;:35:::1;::::0;70722:6:::1;70694:35;:::i;:::-;70675:15;:54;;70667:78;;;::::0;-1:-1:-1;;;70667:78:0;;19937:2:1;70667:78:0::1;::::0;::::1;19919:21:1::0;19976:2;19956:18;;;19949:30;-1:-1:-1;;;19995:18:1;;;19988:41;20046:18;;70667:78:0::1;19909:161:1::0;70667:78:0::1;70828:33;62633:6;70828:15;:33;:::i;:::-;70813:11;:48;;70805:74;;;::::0;-1:-1:-1;;;70805:74:0;;18902:2:1;70805:74:0::1;::::0;::::1;18884:21:1::0;18941:2;18921:18;;;18914:30;-1:-1:-1;;;18960:18:1;;;18953:43;19013:18;;70805:74:0::1;18874:163:1::0;70805:74:0::1;70902:7;70898:1;:11;:30;;;;;62678:3;70913:7;:15;70898:30;70890:53;;;::::0;-1:-1:-1;;;70890:53:0;;22429:2:1;70890:53:0::1;::::0;::::1;22411:21:1::0;22468:2;22448:18;;;22441:30;-1:-1:-1;;;22487:18:1;;;22480:40;22537:18;;70890:53:0::1;22401:160:1::0;70890:53:0::1;70982:25;::::0;-1:-1:-1;;;70982:25:0;;:11:::1;:25;::::0;::::1;23453::1::0;70956:23:0::1;::::0;70982::::1;::::0;::::1;::::0;23426:18:1;;70982:25:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;70956:51:::0;-1:-1:-1;71018:22:0::1;71043:39;42958:3;71043:7:::0;:39:::1;:::i;:::-;71018:64;;71116:15;71099:14;:32;71095:246;;;71191:15:::0;71156:31:::1;62751:2;71156:14:::0;:31:::1;:::i;:::-;:50;;71148:74;;;::::0;-1:-1:-1;;;71148:74:0;;21754:2:1;71148:74:0::1;::::0;::::1;21736:21:1::0;21793:2;21773:18;;;21766:30;-1:-1:-1;;;21812:18:1;;;21805:41;21863:18;;71148:74:0::1;21726:161:1::0;71148:74:0::1;71095:246;;;71281:32;62751:2;71281:15:::0;:32:::1;:::i;:::-;71263:14;:50;;71255:74;;;::::0;-1:-1:-1;;;71255:74:0;;21754:2:1;71255:74:0::1;::::0;::::1;21736:21:1::0;21793:2;21773:18;;;21766:30;-1:-1:-1;;;21812:18:1;;;21805:41;21863:18;;71255:74:0::1;21726:161:1::0;71255:74:0::1;71353:20:::0;:38;;;71402:19;:36;;;71476:15:::1;71449:24:::0;:42;;;71502:23;:37;;;71557:68:::1;::::0;;28120:25:1;;;28176:2;28161:18;;28154:34;;;28204:18;;;28197:34;;;;28262:2;28247:18;;28240:34;;;71557:68:0;::::1;::::0;;;;28107:3:1;71557:68:0;;::::1;20019:1;;70584:1049:::0;;:::o;67451:215::-;-1:-1:-1;;;;;67553:19:0;;67521:11;67553:19;;;:12;:19;;;;;;67599:11;:31;;67553:19;;;;;;;;67599:31;;;;-1:-1:-1;;;67599:31:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;67599:31:0;67591:49;67583:75;;;;-1:-1:-1;;;67583:75:0;;19244:2:1;67583:75:0;;;19226:21:1;19283:2;19263:18;;;19256:30;-1:-1:-1;;;19302:18:1;;;19295:43;19355:18;;67583:75:0;19216:163:1;67583:75:0;67451:215;;;:::o;20379:94::-;19774:7;19801:6;-1:-1:-1;;;;;19801:6:0;18596:10;19948:23;19940:68;;;;-1:-1:-1;;;19940:68:0;;;;;;;:::i;:::-;20444:21:::1;20462:1;20444:9;:21::i;67200:128::-:0;67263:6;67289:11;:24;;67314:5;67289:31;;;;;;;;-1:-1:-1;;;67289:31:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;67289:31:0;;67200:128;-1:-1:-1;;67200:128:0:o;23404:63::-;19774:7;19801:6;-1:-1:-1;;;;;19801:6:0;18596:10;19948:23;19940:68;;;;-1:-1:-1;;;19940:68:0;;;;;;;:::i;:::-;23451:8:::1;:6;:8::i;66367:308::-:0;66580:7;256:1;852:7;;:19;;844:63;;;;-1:-1:-1;;;844:63:0;;;;;;;:::i;:::-;256:1;985:7;:18;22129:4;22153:7;-1:-1:-1;;;22153:7:0;;;;22407:9:::1;22399:38;;;;-1:-1:-1::0;;;22399:38:0::1;;;;;;;:::i;:::-;66561:8:::2;63156:9;63137:15;:28;;63129:48;;;;-1:-1:-1::0;;;63129:48:0::2;;;;;;;:::i;:::-;66607:60:::3;::::0;-1:-1:-1;;;66607:60:0;;:36:::3;::::0;::::3;::::0;:60:::3;::::0;:11:::3;::::0;66644:7;;66653:13;;66607:60:::3;;;:::i;68562:141::-:0;68659:36;;-1:-1:-1;;;68659:36:0;;:11;:36;;;26388:25:1;26461:4;26449:17;;26429:18;;;26422:45;68632:7:0;;68659:27;;;;26361:18:1;;68659:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;65413:329::-;65647:7;22153;;-1:-1:-1;;;22153:7:0;;;;22407:9;22399:38;;;;-1:-1:-1;;;22399:38:0;;;;;;;:::i;:::-;256:1:::1;852:7;;:19;;844:63;;;;-1:-1:-1::0;;;844:63:0::1;;;;;;;:::i;:::-;256:1;985:7;:18:::0;65628:8;63137:15:::2;:28:::0;-1:-1:-1;63137:28:0::2;63129:48;;;;-1:-1:-1::0;;;63129:48:0::2;;;;;;;:::i;:::-;65674:60:::3;::::0;-1:-1:-1;;;65674:60:0;;:11:::3;:60;::::0;::::3;27223:25:1::0;27296:4;27284:17;;;27264:18;;;27257:45;27338:17;;27318:18;;;27311:45;27372:18;;;27365:34;;;27415:19;;;27408:35;;;65674:16:0::3;::::0;::::3;::::0;27195:19:1;;65674:60:0::3;;;;;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;212:1:::1;1164:22:::0;;65667:67;65413:329;-1:-1:-1;;;;;;;65413:329:0:o;67949:132::-;68019:7;68046:11;:20;;68067:5;68046:27;;;;;;;;-1:-1:-1;;;68046:27:0;;;;;;;;;;;;;;;;;68039:34;;67949:132;;;:::o;67817:124::-;67877:16;67913:11;:20;;67906:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;67817:124;:::o;68908:227::-;69073:54;;-1:-1:-1;;;69073:54:0;;:11;:54;;;26743:25:1;26816:4;26804:17;;;26784:18;;;26777:45;26858:17;;26838:18;;;26831:45;26892:18;;;26885:34;;;69046:7:0;;69073:25;;;;26715:19:1;;69073:54:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;69066:61;;68908:227;;;;;;:::o;67072:120::-;67125:15;67160:11;:24;;67153:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;67153:31:0;;;;;;;;;;;;;;;;;;;;;;67072:120;:::o;63366:1721::-;19774:7;19801:6;-1:-1:-1;;;;;19801:6:0;18596:10;19948:23;19940:68;;;;-1:-1:-1;;;19940:68:0;;;;;;;:::i;:::-;2678:13:::1;::::0;::::1;::::0;::::1;;;::::0;:30:::1;;-1:-1:-1::0;2696:12:0::1;::::0;::::1;;2695:13;2678:30;2670:89;;;::::0;-1:-1:-1;;;2670:89:0;;17438:2:1;2670:89:0::1;::::0;::::1;17420:21:1::0;17477:2;17457:18;;;17450:30;17516:34;17496:18;;;17489:62;-1:-1:-1;;;17567:18:1;;;17560:44;17621:19;;2670:89:0::1;17410:236:1::0;2670:89:0::1;2795:13;::::0;::::1;::::0;::::1;;;2794:14;2819:101:::0;::::1;;;2854:13;:20:::0;;-1:-1:-1;;2889:19:0;;;;;2819:101:::1;63709:9:::2;:16;63692:6;:13;:33;63684:75;;;::::0;-1:-1:-1;;;63684:75:0;;20277:2:1;63684:75:0::2;::::0;::::2;20259:21:1::0;20316:2;20296:18;;;20289:30;20355:31;20335:18;;;20328:59;20404:18;;63684:75:0::2;20249:179:1::0;63684:75:0::2;-1:-1:-1::0;;;;;63778:29:0;::::2;63770:64;;;::::0;-1:-1:-1;;;63770:64:0;;19586:2:1;63770:64:0::2;::::0;::::2;19568:21:1::0;19625:2;19605:18;;;19598:30;-1:-1:-1;;;19644:18:1;;;19637:52;19706:18;;63770:64:0::2;19558:172:1::0;63770:64:0::2;63869:13:::0;;63845:21:::2;63869:13:::0;63918:28:::2;::::0;::::2;;;;-1:-1:-1::0;;;63918:28:0::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;63918:28:0::2;;63893:53;;63957:21;63994:13;63981:27;;;;;;-1:-1:-1::0;;;63981:27:0::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;63981:27:0::2;;63957:51;;64024:9;64019:420;64043:13;64039:1;:17;64019:420;;;64107:1;-1:-1:-1::0;;;;;64086:23:0::2;:6;64093:1;64086:9;;;;;;-1:-1:-1::0;;;64086:9:0::2;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;64086:23:0::2;;;64078:55;;;::::0;-1:-1:-1;;;64078:55:0;;17853:2:1;64078:55:0::2;::::0;::::2;17835:21:1::0;17892:2;17872:18;;;17865:30;-1:-1:-1;;;17911:18:1;;;17904:49;17970:18;;64078:55:0::2;17825:169:1::0;64078:55:0::2;43123:2;64156:9;64166:1;64156:12;;;;;;-1:-1:-1::0;;;64156:12:0::2;;;;;;;;;;;;;;;:60;;;;64148:88;;;::::0;-1:-1:-1;;;64148:88:0;;15659:2:1;64148:88:0::2;::::0;::::2;15641:21:1::0;15698:2;15678:18;;;15671:30;-1:-1:-1;;;15717:18:1;;;15710:45;15772:18;;64148:88:0::2;15631:165:1::0;64148:88:0::2;64314:9;64324:1;64314:12;;;;;;-1:-1:-1::0;;;64314:12:0::2;;;;;;;;;;;;;;;64267:59;;43123:2;64267:59;;;;:::i;:::-;64262:65;::::0;:2:::2;:65;:::i;:::-;64251:5;64257:1;64251:8;;;;;;-1:-1:-1::0;;;64251:8:0::2;;;;;;;;;;;;;;:76;;;::::0;::::2;64360:6;64367:1;64360:9;;;;;;-1:-1:-1::0;;;64360:9:0::2;;;;;;;;;;;;;;;64342:5;64348:1;64342:8;;;;;;-1:-1:-1::0;;;64342:8:0::2;;;;;;;;;;;;;;:28;-1:-1:-1::0;;;;;64342:28:0::2;;;-1:-1:-1::0;;;;;64342:28:0::2;;;::::0;::::2;64425:1;64385:12;:31;64406:5;64412:1;64406:8;;;;;;-1:-1:-1::0;;;64406:8:0::2;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;64385:31:0::2;-1:-1:-1::0;;;;;64385:31:0::2;;;;;;;;;;;;;:42;;;;;;;;;;;;;;;;;;64058:3;;;;;:::i;:::-;;;;64019:420;;;;62678:3;64459:2;:10;64451:29;;;::::0;-1:-1:-1;;;64451:29:0;;14918:2:1;64451:29:0::2;::::0;::::2;14900:21:1::0;14957:1;14937:18;;;14930:29;-1:-1:-1;;;14975:18:1;;;14968:36;15021:18;;64451:29:0::2;14890:155:1::0;64451:29:0::2;62858:3;64499:4;:20;;64491:45;;;::::0;-1:-1:-1;;;64491:45:0;;16003:2:1;64491:45:0::2;::::0;::::2;15985:21:1::0;16042:2;16022:18;;;16015:30;-1:-1:-1;;;16061:18:1;;;16054:42;16113:18;;64491:45:0::2;15975:162:1::0;64491:45:0::2;62800:4;64555:9;:26;;64547:52;;;::::0;-1:-1:-1;;;64547:52:0;;17096:2:1;64547:52:0::2;::::0;::::2;17078:21:1::0;17135:2;17115:18;;;17108:30;-1:-1:-1;;;17154:18:1;;;17147:43;17207:18;;64547:52:0::2;17068:163:1::0;64547:52:0::2;64646:11;64659:13;64634:39;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::2;;;;;-1:-1:-1::0;64612:19:0;:61;;-1:-1:-1;;;;;;64612:61:0::2;-1:-1:-1::0;;;;;64612:61:0;;;::::2;::::0;;;::::2;::::0;;64721:13;64707:28:::2;::::0;::::2;;;;-1:-1:-1::0;;;64707:28:0::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;64707:28:0::2;-1:-1:-1::0;64684:51:0;;::::2;::::0;:20;;:51:::2;::::0;;::::2;::::0;::::2;:::i;:::-;-1:-1:-1::0;64746:36:0;;::::2;::::0;:28;;:36:::2;::::0;::::2;::::0;::::2;:::i;:::-;-1:-1:-1::0;64793:32:0;;::::2;::::0;:11:::2;::::0;:32:::2;::::0;::::2;::::0;::::2;:::i;:::-;-1:-1:-1::0;64859:34:0::2;42958:3;64859:2:::0;:34:::2;:::i;:::-;64836:20:::0;:57;64926:34:::2;42958:3;64926:2:::0;:34:::2;:::i;:::-;64904:19:::0;:56;-1:-1:-1;;;64904:19:0::2;64971:22:::0;;;65004:20;:32;;;65047:14:::2;:32:::0;;-1:-1:-1;;;;;;65047:32:0::2;-1:-1:-1::0;;;;;65047:32:0;::::2;;::::0;;2946:68;::::1;;;2981:13;:21:::0;;-1:-1:-1;;2981:21:0::1;::::0;;2946:68:::1;20019:1;63366:1721:::0;;;;;;;;:::o;71641:426::-;19774:7;19801:6;-1:-1:-1;;;;;19801:6:0;18596:10;19948:23;19940:68;;;;-1:-1:-1;;;19940:68:0;;;;;;;:::i;:::-;71700:23;;71726:15:::1;-1:-1:-1::0;71692:68:0::1;;;::::0;-1:-1:-1;;;71692:68:0;;23128:2:1;71692:68:0::1;::::0;::::1;23110:21:1::0;23167:2;23147:18;;;23140:30;-1:-1:-1;;;23186:18:1;;;23179:44;23240:18;;71692:68:0::1;23100:164:1::0;71692:68:0::1;71790:25;::::0;-1:-1:-1;;;71790:25:0;;:11:::1;:25;::::0;::::1;23453::1::0;71771:16:0::1;::::0;71790:23:::1;::::0;::::1;::::0;23426:18:1;;71790:25:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;71828:20:::0;:31;;;71870:19;:30;;;71938:15:::1;71911:24:::0;:42;;;71964:23;:41;;;72023:36:::1;::::0;71771:44;;-1:-1:-1;72023:36:0::1;::::0;::::1;::::0;71771:44;24839:25:1;;24895:2;24880:18;;24873:34;24827:2;24812:18;;24794:119;72316:240:0;19774:7;19801:6;-1:-1:-1;;;;;19801:6:0;18596:10;19948:23;19940:68;;;;-1:-1:-1;;;19940:68:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;72406:29:0;::::1;72398:53;;;::::0;-1:-1:-1;;;72398:53:0;;18201:2:1;72398:53:0::1;::::0;::::1;18183:21:1::0;18240:2;18220:18;;;18213:30;-1:-1:-1;;;18259:18:1;;;18252:41;18310:18;;72398:53:0::1;18173:161:1::0;72398:53:0::1;72462:14;:32:::0;;-1:-1:-1;;;;;;72462:32:0::1;-1:-1:-1::0;;;;;72462:32:0;::::1;::::0;;::::1;::::0;;;72510:38:::1;::::0;11025:51:1;;;72510:38:0::1;::::0;11013:2:1;10998:18;72510:38:0::1;10980:102:1::0;67674:135:0;67737:16;67773:11;:28;;67766:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;67674:135;:::o;66840:101::-;66915:18;;-1:-1:-1;;;66915:18:0;;:11;:18;;;23453:25:1;66888:7:0;;66915:16;;;;23426:18:1;;66915::0;23408:76:1;66709:123:0;66795:29;;-1:-1:-1;;;66795:29:0;;:11;:29;;;23453:25:1;66768:7:0;;66795:27;;;;23426:18:1;;66795:29:0;23408:76:1;68711:189:0;68842:50;;-1:-1:-1;;;68842:50:0;;68815:7;;68842:32;;;;:50;;:11;;68875:7;;;;68884;;68842:50;;;:::i;69143:170::-;69261:44;;-1:-1:-1;;;69261:44:0;;:11;:44;;;24839:25:1;24880:18;;;24873:34;;;69225:16:0;;69261:36;;;;24812:18:1;;69261:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;69261:44:0;;;;;;;;;;;;:::i;20628:192::-;19774:7;19801:6;-1:-1:-1;;;;;19801:6:0;18596:10;19948:23;19940:68;;;;-1:-1:-1;;;19940:68:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;20717:22:0;::::1;20709:73;;;::::0;-1:-1:-1;;;20709:73:0;;15252:2:1;20709:73:0::1;::::0;::::1;15234:21:1::0;15291:2;15271:18;;;15264:30;15330:34;15310:18;;;15303:62;-1:-1:-1;;;15381:18:1;;;15374:36;15427:19;;20709:73:0::1;15224:228:1::0;20709:73:0::1;20793:19;20803:8;20793:9;:19::i;:::-;20628:192:::0;:::o;72564:488::-;63274:13;;-1:-1:-1;;;;;63274:13:0;63260:10;:27;;:52;;-1:-1:-1;19774:7:0;19801:6;-1:-1:-1;;;;;19801:6:0;63291:10;:21;63260:52;63252:86;;;;-1:-1:-1;;;63252:86:0;;20993:2:1;63252:86:0;;;20975:21:1;21032:2;21012:18;;;21005:30;-1:-1:-1;;;21051:18:1;;;21044:51;21112:18;;63252:86:0;20965:171:1;63252:86:0;72651:9:::1;72646:399;72670:11;:31:::0;72666:35;::::1;72646:399;;;72723:12;72738:11;:24;;72763:1;72738:27;;;;;;-1:-1:-1::0;;;72738:27:0::1;;;;;;;;;;::::0;;;::::1;::::0;;::::1;::::0;72832:20;:23;;-1:-1:-1;;;;;72738:27:0;;::::1;::::0;-1:-1:-1;72832:20:0;72853:1;;72832:23;::::1;;;-1:-1:-1::0;;;72832:23:0::1;;;;;;;;;;::::0;;;::::1;::::0;;;::::1;::::0;72798:30:::1;::::0;-1:-1:-1;;;72798:30:0;;72822:4:::1;72798:30;::::0;::::1;11025:51:1::0;-1:-1:-1;;;;;72798:15:0;::::1;::::0;::::1;::::0;10998:18:1;;72798:30:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:58;;;;:::i;:::-;72780:76:::0;-1:-1:-1;72875:12:0;;72871:163:::1;;72927:14;::::0;72908:43:::1;::::0;-1:-1:-1;;;;;72908:18:0;;::::1;::::0;72927:14:::1;72943:7:::0;72908:18:::1;:43::i;:::-;72975;::::0;;-1:-1:-1;;;;;11279:32:1;;11261:51;;11343:2;11328:18;;11321:34;;;72975:43:0::1;::::0;11234:18:1;72975:43:0::1;;;;;;;72871:163;72646:399;;72703:3;;;;;:::i;:::-;;;;72646:399;;23141:120:::0;22129:4;22153:7;-1:-1:-1;;;22153:7:0;;;;22677:41;;;;-1:-1:-1;;;22677:41:0;;14569:2:1;22677:41:0;;;14551:21:1;14608:2;14588:18;;;14581:30;-1:-1:-1;;;14627:18:1;;;14620:50;14687:18;;22677:41:0;14541:170:1;22677:41:0;23210:5:::1;23200:15:::0;;-1:-1:-1;;;;23200:15:0::1;::::0;;23231:22:::1;18596:10:::0;23240:12:::1;23231:22;::::0;-1:-1:-1;;;;;11043:32:1;;;11025:51;;11013:2;10998:18;23231:22:0::1;;;;;;;23141:120::o:0;20828:173::-;20884:16;20903:6;;-1:-1:-1;;;;;20920:17:0;;;-1:-1:-1;;;;;;20920:17:0;;;;;;20953:40;;20903:6;;;;;;;20953:40;;20884:16;20953:40;20828:173;;:::o;22882:118::-;22129:4;22153:7;-1:-1:-1;;;22153:7:0;;;;22407:9;22399:38;;;;-1:-1:-1;;;22399:38:0;;;;;;;:::i;:::-;22942:7:::1;:14:::0;;-1:-1:-1;;;;22942:14:0::1;-1:-1:-1::0;;;22942:14:0::1;::::0;;22972:20:::1;22979:12;18596:10:::0;;18516:98;14593:211;14737:58;;;-1:-1:-1;;;;;11279:32:1;;14737:58:0;;;11261:51:1;11328:18;;;;11321:34;;;14737:58:0;;;;;;;;;;11234:18:1;;;;14737:58:0;;;;;;;;-1:-1:-1;;;;;14737:58:0;-1:-1:-1;;;14737:58:0;;;14710:86;;14730:5;;14710:19;:86::i;:::-;14593:211;;;:::o;17166:716::-;17590:23;17616:69;17644:4;17616:69;;;;;;;;;;;;;;;;;17624:5;-1:-1:-1;;;;;17616:27:0;;;:69;;;;;:::i;:::-;17700:17;;17590:95;;-1:-1:-1;17700:21:0;17696:179;;17797:10;17786:30;;;;;;;;;;;;:::i;:::-;17778:85;;;;-1:-1:-1;;;17778:85:0;;21343:2:1;17778:85:0;;;21325:21:1;21382:2;21362:18;;;21355:30;21421:34;21401:18;;;21394:62;-1:-1:-1;;;21472:18:1;;;21465:40;21522:19;;17778:85:0;21315:232:1;9441:229:0;9578:12;9610:52;9632:6;9640:4;9646:1;9649:12;9578;6958:20;;10848:60;;;;-1:-1:-1;;;10848:60:0;;20635:2:1;10848:60:0;;;20617:21:1;20674:2;20654:18;;;20647:30;20713:31;20693:18;;;20686:59;20762:18;;10848:60:0;20607:179:1;10848:60:0;10922:12;10936:23;10963:6;-1:-1:-1;;;;;10963:11:0;10982:5;10989:4;10963:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10921:73;;;;11012:51;11029:7;11038:10;11050:12;11012:16;:51::i;:::-;11005:58;10561:510;-1:-1:-1;;;;;;;10561:510:0:o;13247:712::-;13397:12;13426:7;13422:530;;;-1:-1:-1;13457:10:0;13450:17;;13422:530;13571:17;;:21;13567:374;;13769:10;13763:17;13830:15;13817:10;13813:2;13809:19;13802:44;13717:148;13912:12;13905:20;;-1:-1:-1;;;13905:20:0;;;;;;;;:::i;-1:-1:-1:-;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14:173:1;82:20;;-1:-1:-1;;;;;131:31:1;;121:42;;111:2;;177:1;174;167:12;192:699;246:5;299:3;292:4;284:6;280:17;276:27;266:2;;321:5;314;307:20;266:2;361:6;348:20;387:4;411:60;427:43;467:2;427:43;:::i;:::-;411:60;:::i;:::-;493:3;517:2;512:3;505:15;545:2;540:3;536:12;529:19;;580:2;572:6;568:15;632:3;627:2;621;618:1;614:10;606:6;602:23;598:32;595:41;592:2;;;653:5;646;639:20;592:2;679:5;693:169;707:2;704:1;701:9;693:169;;;764:23;783:3;764:23;:::i;:::-;752:36;;808:12;;;;840;;;;725:1;718:9;693:169;;;-1:-1:-1;880:5:1;;256:635;-1:-1:-1;;;;;;;256:635:1:o;896:693::-;950:5;1003:3;996:4;988:6;984:17;980:27;970:2;;1025:5;1018;1011:20;970:2;1065:6;1052:20;1091:4;1115:60;1131:43;1171:2;1131:43;:::i;1115:60::-;1197:3;1221:2;1216:3;1209:15;1249:2;1244:3;1240:12;1233:19;;1284:2;1276:6;1272:15;1336:3;1331:2;1325;1322:1;1318:10;1310:6;1306:23;1302:32;1299:41;1296:2;;;1357:5;1350;1343:20;1296:2;1383:5;1397:163;1411:2;1408:1;1405:9;1397:163;;;1468:17;;1456:30;;1506:12;;;;1538;;;;1429:1;1422:9;1397:163;;1594:695;1646:5;1699:3;1692:4;1684:6;1680:17;1676:27;1666:2;;1721:5;1714;1707:20;1666:2;1761:6;1748:20;1787:4;1811:60;1827:43;1867:2;1827:43;:::i;1811:60::-;1893:3;1917:2;1912:3;1905:15;1945:2;1940:3;1936:12;1929:19;;1980:2;1972:6;1968:15;2032:3;2027:2;2021;2018:1;2014:10;2006:6;2002:23;1998:32;1995:41;1992:2;;;2053:5;2046;2039:20;1992:2;2079:5;2093:167;2107:2;2104:1;2101:9;2093:167;;;2164:21;2181:3;2164:21;:::i;:::-;2152:34;;2206:12;;;;2238;;;;2125:1;2118:9;2093:167;;2294:551;2337:5;2390:3;2383:4;2375:6;2371:17;2367:27;2357:2;;2412:5;2405;2398:20;2357:2;2452:6;2439:20;2478:18;2474:2;2471:26;2468:2;;;2500:18;;:::i;:::-;2544:55;2587:2;2568:13;;-1:-1:-1;;2564:27:1;2593:4;2560:38;2544:55;:::i;:::-;2624:2;2615:7;2608:19;2670:3;2663:4;2658:2;2650:6;2646:15;2642:26;2639:35;2636:2;;;2691:5;2684;2677:20;2636:2;2760;2753:4;2745:6;2741:17;2734:4;2725:7;2721:18;2708:55;2783:16;;;2801:4;2779:27;2772:42;;;;2787:7;2347:498;-1:-1:-1;;2347:498:1:o;2850:156::-;2916:20;;2976:4;2965:16;;2955:27;;2945:2;;2996:1;2993;2986:12;3011:196;3070:6;3123:2;3111:9;3102:7;3098:23;3094:32;3091:2;;;3144:6;3136;3129:22;3091:2;3172:29;3191:9;3172:29;:::i;3212:1324::-;3402:6;3410;3418;3426;3434;3442;3450;3458;3511:3;3499:9;3490:7;3486:23;3482:33;3479:2;;;3533:6;3525;3518:22;3479:2;3578:9;3565:23;3607:18;3648:2;3640:6;3637:14;3634:2;;;3669:6;3661;3654:22;3634:2;3697:61;3750:7;3741:6;3730:9;3726:22;3697:61;:::i;:::-;3687:71;;3811:2;3800:9;3796:18;3783:32;3767:48;;3840:2;3830:8;3827:16;3824:2;;;3861:6;3853;3846:22;3824:2;3889:61;3942:7;3931:8;3920:9;3916:24;3889:61;:::i;:::-;3879:71;;4003:2;3992:9;3988:18;3975:32;3959:48;;4032:2;4022:8;4019:16;4016:2;;;4053:6;4045;4038:22;4016:2;4081:52;4125:7;4114:8;4103:9;4099:24;4081:52;:::i;:::-;4071:62;;4186:2;4175:9;4171:18;4158:32;4142:48;;4215:2;4205:8;4202:16;4199:2;;;4236:6;4228;4221:22;4199:2;;4264:52;4308:7;4297:8;4286:9;4282:24;4264:52;:::i;:::-;4254:62;;;4363:3;4352:9;4348:19;4335:33;4325:43;;4415:3;4404:9;4400:19;4387:33;4377:43;;4467:3;4456:9;4452:19;4439:33;4429:43;;4491:39;4525:3;4514:9;4510:19;4491:39;:::i;:::-;4481:49;;3469:1067;;;;;;;;;;;:::o;4541:800::-;4633:6;4641;4649;4702:2;4690:9;4681:7;4677:23;4673:32;4670:2;;;4723:6;4715;4708:22;4670:2;4768:9;4755:23;4797:18;4838:2;4830:6;4827:14;4824:2;;;4859:6;4851;4844:22;4824:2;4902:6;4891:9;4887:22;4877:32;;4947:7;4940:4;4936:2;4932:13;4928:27;4918:2;;4974:6;4966;4959:22;4918:2;5019;5006:16;5045:2;5037:6;5034:14;5031:2;;;5066:6;5058;5051:22;5031:2;5126:7;5119:4;5109:6;5106:1;5102:14;5098:2;5094:23;5090:34;5087:47;5084:2;;;5152:6;5144;5137:22;5084:2;5188:4;5180:13;;;;-1:-1:-1;5212:6:1;-1:-1:-1;;5253:20:1;;5240:34;5283:28;5240:34;5283:28;:::i;:::-;5330:5;5320:15;;;4660:681;;;;;:::o;5346:937::-;5441:6;5472:2;5515;5503:9;5494:7;5490:23;5486:32;5483:2;;;5536:6;5528;5521:22;5483:2;5574:9;5568:16;5607:18;5599:6;5596:30;5593:2;;;5644:6;5636;5629:22;5593:2;5672:22;;5725:4;5717:13;;5713:27;-1:-1:-1;5703:2:1;;5759:6;5751;5744:22;5703:2;5793;5787:9;5816:60;5832:43;5872:2;5832:43;:::i;5816:60::-;5898:3;5922:2;5917:3;5910:15;5950:2;5945:3;5941:12;5934:19;;5981:2;5977;5973:11;6029:7;6024:2;6018;6015:1;6011:10;6007:2;6003:19;5999:28;5996:41;5993:2;;;6055:6;6047;6040:22;5993:2;6082:6;6073:15;;6097:156;6111:2;6108:1;6105:9;6097:156;;;6168:10;;6156:23;;6129:1;6122:9;;;;;6199:12;;;;6231;;6097:156;;;-1:-1:-1;6272:5:1;5452:831;-1:-1:-1;;;;;;;5452:831:1:o;6288:504::-;6390:6;6398;6406;6459:2;6447:9;6438:7;6434:23;6430:32;6427:2;;;6480:6;6472;6465:22;6427:2;6525:9;6512:23;6558:18;6550:6;6547:30;6544:2;;;6595:6;6587;6580:22;6544:2;6623:61;6676:7;6667:6;6656:9;6652:22;6623:61;:::i;:::-;6613:71;6731:2;6716:18;;6703:32;;-1:-1:-1;6782:2:1;6767:18;;;6754:32;;6417:375;-1:-1:-1;;;;6417:375:1:o;6797:255::-;6864:6;6917:2;6905:9;6896:7;6892:23;6888:32;6885:2;;;6938:6;6930;6923:22;6885:2;6975:9;6969:16;6994:28;7016:5;6994:28;:::i;7057:190::-;7116:6;7169:2;7157:9;7148:7;7144:23;7140:32;7137:2;;;7190:6;7182;7175:22;7137:2;-1:-1:-1;7218:23:1;;7127:120;-1:-1:-1;7127:120:1:o;7252:194::-;7322:6;7375:2;7363:9;7354:7;7350:23;7346:32;7343:2;;;7396:6;7388;7381:22;7343:2;-1:-1:-1;7424:16:1;;7333:113;-1:-1:-1;7333:113:1:o;7451:504::-;7553:6;7561;7569;7622:2;7610:9;7601:7;7597:23;7593:32;7590:2;;;7643:6;7635;7628:22;7590:2;7684:9;7671:23;7661:33;;7745:2;7734:9;7730:18;7717:32;7772:18;7764:6;7761:30;7758:2;;;7809:6;7801;7794:22;7758:2;7837:61;7890:7;7881:6;7870:9;7866:22;7837:61;:::i;:::-;7827:71;;;7945:2;7934:9;7930:18;7917:32;7907:42;;7580:375;;;;;:::o;7960:258::-;8028:6;8036;8089:2;8077:9;8068:7;8064:23;8060:32;8057:2;;;8110:6;8102;8095:22;8057:2;-1:-1:-1;;8138:23:1;;;8208:2;8193:18;;;8180:32;;-1:-1:-1;8047:171:1:o;8223:260::-;8289:6;8297;8350:2;8338:9;8329:7;8325:23;8321:32;8318:2;;;8371:6;8363;8356:22;8318:2;8412:9;8399:23;8389:33;;8441:36;8473:2;8462:9;8458:18;8441:36;:::i;:::-;8431:46;;8308:175;;;;;:::o;8488:397::-;8572:6;8580;8588;8596;8649:3;8637:9;8628:7;8624:23;8620:33;8617:2;;;8671:6;8663;8656:22;8617:2;8712:9;8699:23;8689:33;;8741:36;8773:2;8762:9;8758:18;8741:36;:::i;:::-;8607:278;;8731:46;;-1:-1:-1;;;;8824:2:1;8809:18;;8796:32;;8875:2;8860:18;8847:32;;8607:278::o;8890:192::-;8947:6;9000:2;8988:9;8979:7;8975:23;8971:32;8968:2;;;9021:6;9013;9006:22;8968:2;9049:27;9066:9;9049:27;:::i;9087:330::-;9160:6;9168;9176;9229:2;9217:9;9208:7;9204:23;9200:32;9197:2;;;9250:6;9242;9235:22;9197:2;9278:27;9295:9;9278:27;:::i;:::-;9268:37;;9324:36;9356:2;9345:9;9341:18;9324:36;:::i;:::-;9314:46;;9407:2;9396:9;9392:18;9379:32;9369:42;;9187:230;;;;;:::o;9422:468::-;9513:6;9521;9529;9537;9545;9598:3;9586:9;9577:7;9573:23;9569:33;9566:2;;;9620:6;9612;9605:22;9566:2;9648:27;9665:9;9648:27;:::i;:::-;9638:37;;9694:36;9726:2;9715:9;9711:18;9694:36;:::i;:::-;9556:334;;9684:46;;-1:-1:-1;;;;9777:2:1;9762:18;;9749:32;;9828:2;9813:18;;9800:32;;9879:3;9864:19;;;9851:33;;-1:-1:-1;9556:334:1:o;9895:437::-;9948:3;9986:5;9980:12;10013:6;10008:3;10001:19;10039:4;10068:2;10063:3;10059:12;10052:19;;10105:2;10098:5;10094:14;10126:3;10138:169;10152:6;10149:1;10146:13;10138:169;;;10213:13;;10201:26;;10247:12;;;;10282:15;;;;10174:1;10167:9;10138:169;;;-1:-1:-1;10323:3:1;;9956:376;-1:-1:-1;;;;;9956:376:1:o;10337:258::-;10379:3;10417:5;10411:12;10444:6;10439:3;10432:19;10460:63;10516:6;10509:4;10504:3;10500:14;10493:4;10486:5;10482:16;10460:63;:::i;:::-;10577:2;10556:15;-1:-1:-1;;10552:29:1;10543:39;;;;10584:4;10539:50;;10387:208;-1:-1:-1;;10387:208:1:o;10600:274::-;10729:3;10767:6;10761:13;10783:53;10829:6;10824:3;10817:4;10809:6;10805:17;10783:53;:::i;:::-;10852:16;;;;;10737:137;-1:-1:-1;;10737:137:1:o;11366:675::-;11551:2;11603:21;;;11673:13;;11576:18;;;11695:22;;;11522:4;;11551:2;11774:15;;;;11748:2;11733:18;;;11522:4;11820:195;11834:6;11831:1;11828:13;11820:195;;;11899:13;;-1:-1:-1;;;;;11895:39:1;11883:52;;11990:15;;;;11955:12;;;;11931:1;11849:9;11820:195;;;-1:-1:-1;12032:3:1;;11531:510;-1:-1:-1;;;;;;11531:510:1:o;12046:635::-;12217:2;12269:21;;;12339:13;;12242:18;;;12361:22;;;12188:4;;12217:2;12440:15;;;;12414:2;12399:18;;;12188:4;12486:169;12500:6;12497:1;12494:13;12486:169;;;12561:13;;12549:26;;12630:15;;;;12595:12;;;;12522:1;12515:9;12486:169;;13754:220;13903:2;13892:9;13885:21;13866:4;13923:45;13964:2;13953:9;13949:18;13941:6;13923:45;:::i;13979:383::-;14176:2;14165:9;14158:21;14139:4;14202:45;14243:2;14232:9;14228:18;14220:6;14202:45;:::i;:::-;14295:9;14287:6;14283:22;14278:2;14267:9;14263:18;14256:50;14323:33;14349:6;14341;14323:33;:::i;:::-;14315:41;14148:214;-1:-1:-1;;;;;14148:214:1:o;16549:340::-;16751:2;16733:21;;;16790:2;16770:18;;;16763:30;-1:-1:-1;;;16824:2:1;16809:18;;16802:46;16880:2;16865:18;;16723:166::o;18339:356::-;18541:2;18523:21;;;18560:18;;;18553:30;18619:34;18614:2;18599:18;;18592:62;18686:2;18671:18;;18513:182::o;21892:330::-;22094:2;22076:21;;;22133:1;22113:18;;;22106:29;-1:-1:-1;;;22166:2:1;22151:18;;22144:37;22213:2;22198:18;;22066:156::o;22566:355::-;22768:2;22750:21;;;22807:2;22787:18;;;22780:30;22846:33;22841:2;22826:18;;22819:61;22912:2;22897:18;;22740:181::o;23489:687::-;23748:25;;;23809:2;23804;23789:18;;23782:30;;;23828:18;;23821:34;;;-1:-1:-1;;;;;;23867:31:1;;23864:2;;;23914:4;23908;23901:18;23864:2;23951:6;23948:1;23944:14;24009:6;24001;23995:3;23984:9;23980:19;23967:49;24039:22;;24063:3;24035:32;24076:16;;;24154:14;;24147:22;24142:2;24127:18;;;24120:50;24035:32;23738:438;-1:-1:-1;;;23738:438:1:o;24181:441::-;24454:6;24443:9;24436:25;24497:2;24492;24481:9;24477:18;24470:30;24417:4;24517:56;24569:2;24558:9;24554:18;24546:6;24517:56;:::i;:::-;24509:64;;24609:6;24604:2;24593:9;24589:18;24582:34;24426:196;;;;;;:::o;24918:441::-;25191:6;25180:9;25173:25;25234:6;25229:2;25218:9;25214:18;25207:34;25277:2;25272;25261:9;25257:18;25250:30;25154:4;25297:56;25349:2;25338:9;25334:18;25326:6;25297:56;:::i;28474:275::-;28545:2;28539:9;28610:2;28591:13;;-1:-1:-1;;28587:27:1;28575:40;;28645:18;28630:34;;28666:22;;;28627:62;28624:2;;;28692:18;;:::i;:::-;28728:2;28721:22;28519:230;;-1:-1:-1;28519:230:1:o;28754:183::-;28814:4;28847:18;28839:6;28836:30;28833:2;;;28869:18;;:::i;:::-;-1:-1:-1;28914:1:1;28910:14;28926:4;28906:25;;28823:114::o;28942:128::-;28982:3;29013:1;29009:6;29006:1;29003:13;29000:2;;;29019:18;;:::i;:::-;-1:-1:-1;29055:9:1;;28990:80::o;29075:422::-;29164:1;29207:5;29164:1;29221:270;29242:7;29232:8;29229:21;29221:270;;;29301:4;29297:1;29293:6;29289:17;29283:4;29280:27;29277:2;;;29310:18;;:::i;:::-;29360:7;29350:8;29346:22;29343:2;;;29380:16;;;;29343:2;29459:22;;;;29419:15;;;;29221:270;;;29225:3;29139:358;;;;;:::o;29502:131::-;29562:5;29591:36;29618:8;29612:4;29687:5;29717:8;29707:2;;-1:-1:-1;29758:1:1;29772:5;;29707:2;29806:4;29796:2;;-1:-1:-1;29843:1:1;29857:5;;29796:2;29888:4;29906:1;29901:59;;;;29974:1;29969:130;;;;29881:218;;29901:59;29931:1;29922:10;;29945:5;;;29969:130;30006:3;29996:8;29993:17;29990:2;;;30013:18;;:::i;:::-;-1:-1:-1;;30069:1:1;30055:16;;30084:5;;29881:218;;30183:2;30173:8;30170:16;30164:3;30158:4;30155:13;30151:36;30145:2;30135:8;30132:16;30127:2;30121:4;30118:12;30114:35;30111:77;30108:2;;;-1:-1:-1;30220:19:1;;;30252:5;;30108:2;30299:34;30324:8;30318:4;30299:34;:::i;:::-;30369:6;30365:1;30361:6;30357:19;30348:7;30345:32;30342:2;;;30380:18;;:::i;:::-;30418:20;;29697:747;-1:-1:-1;;;29697:747:1:o;30449:168::-;30489:7;30555:1;30551;30547:6;30543:14;30540:1;30537:21;30532:1;30525:9;30518:17;30514:45;30511:2;;;30562:18;;:::i;:::-;-1:-1:-1;30602:9:1;;30501:116::o;30622:125::-;30662:4;30690:1;30687;30684:8;30681:2;;;30695:18;;:::i;:::-;-1:-1:-1;30732:9:1;;30671:76::o;30752:258::-;30824:1;30834:113;30848:6;30845:1;30842:13;30834:113;;;30924:11;;;30918:18;30905:11;;;30898:39;30870:2;30863:10;30834:113;;;30965:6;30962:1;30959:13;30956:2;;;31000:1;30991:6;30986:3;30982:16;30975:27;30956:2;;30805:205;;;:::o;31015:135::-;31054:3;-1:-1:-1;;31075:17:1;;31072:2;;;31095:18;;:::i;:::-;-1:-1:-1;31142:1:1;31131:13;;31062:88::o;31155:127::-;31216:10;31211:3;31207:20;31204:1;31197:31;31247:4;31244:1;31237:15;31271:4;31268:1;31261:15;31287:127;31348:10;31343:3;31339:20;31336:1;31329:31;31379:4;31376:1;31369:15;31403:4;31400:1;31393:15;31419:118;31505:5;31498:13;31491:21;31484:5;31481:32;31471:2;;31527:1;31524;31517:12
Swarm Source
ipfs://f1e0fdff8282f199e04c55c4ef68f3c457dbd5f44d255121bbc507bb09f15ef6
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.