Source Code
Overview
MON Balance
MON Value
$0.00Latest 14 from a total of 14 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Set Vault Implem... | 48640226 | 10 days ago | IN | 0 MON | 0.00555929 | ||||
| Deploy | 38300323 | 58 days ago | IN | 0 MON | 0.61202269 | ||||
| Submit Spec | 38300221 | 58 days ago | IN | 0 MON | 0.13744405 | ||||
| Submit Spec | 38146037 | 59 days ago | IN | 0 MON | 0.14143456 | ||||
| Deploy | 32439119 | 85 days ago | IN | 0 MON | 0.25253406 | ||||
| Submit Spec | 32438969 | 85 days ago | IN | 0 MON | 3.0385 | ||||
| Deploy | 32438190 | 85 days ago | IN | 0 MON | 1.5 | ||||
| Deploy | 32435852 | 85 days ago | IN | 0 MON | 0.35 | ||||
| Deploy | 32434910 | 85 days ago | IN | 0 MON | 0.468 | ||||
| Deploy | 32433754 | 85 days ago | IN | 0 MON | 0.1545 | ||||
| Submit Spec | 32433226 | 85 days ago | IN | 0 MON | 0.04205144 | ||||
| Set Vault Implem... | 32431154 | 85 days ago | IN | 0 MON | 0.00276168 | ||||
| Set Token Implem... | 32429599 | 85 days ago | IN | 0 MON | 0.00276163 | ||||
| Set Endpoint | 32428298 | 85 days ago | IN | 0 MON | 0.00365763 |
Latest 25 internal transactions (View All)
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
MasterDeployer
Compiler Version
v0.8.24+commit.e11b9ed9
Contract Source Code (Solidity)
/**
*Submitted for verification at monadscan.com on 2025-11-24
*/
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0 ^0.8.1 ^0.8.19 ^0.8.2 ^0.8.20 ^0.8.3;
// lib/open-zeppelin/utils/Address.sol
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
/**
* @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
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 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://consensys.net/diligence/blog/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 functionCallWithValue(target, data, 0, "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");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or 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 {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// 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
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
// src/core/BaseReentrancy.sol
abstract contract BaseReentrancy {
// ----------------------------------------------------------------------------------------------------
// Constants
// ----------------------------------------------------------------------------------------------------
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
// ----------------------------------------------------------------------------------------------------
// Errors
// ----------------------------------------------------------------------------------------------------
error ReentrantCall();
// ----------------------------------------------------------------------------------------------------
// Storage layout
// ----------------------------------------------------------------------------------------------------
uint256 private _status;
// ----------------------------------------------------------------------------------------------------
// Modifiers
// ----------------------------------------------------------------------------------------------------
/**
* @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 making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == _ENTERED) {
revert ReentrantCall();
}
// 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;
}
}
// lib/open-zeppelin/utils/Context.sol
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
// src/core/interfaces/IAggregatorV3Interface.sol
interface IAggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(
uint80 _roundId
) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}
// lib/open-zeppelin/proxy/beacon/IBeacon.sol
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}
// src/core/interfaces/IConfigurableMintableToken.sol
interface IConfigurableMintableToken {
function configure(address[] calldata newMinters, address[] calldata newBurners) external;
}
// lib/open-zeppelin/token/ERC20/IERC20.sol
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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);
/**
* @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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool);
}
// src/core/interfaces/IEnableOnlyAssetsWhitelist.sol
interface IEnableOnlyAssetsWhitelist {
error ZeroAddressError();
error WhitelistLimitReached();
error InvalidOraclePrice();
error InvalidAddress();
error ReferenceAssetNotPermitted();
error InvalidDecimalPlaces();
error AssetAlreadyEnabled();
error StalePrice();
error RoundNotComplete();
error InvalidTimePeriod();
error InvalidOracleTimestamp();
struct OracleInfo {
address oracleAddress;
address tokenAddress;
uint8 oracleDecimals;
uint8 tokenDecimals;
}
function enableAsset(
address depositableAssetAddr,
address oracleAddr,
uint256 newOracleDuration
) external;
function getWhitelistedAssets() external view returns (address[] memory);
function isWhitelisted(address addr) external view returns (bool);
function getOracleAddress(address assetAddr) external view returns (address);
function fromInputAssetToReferenceAsset(address assetAddr, uint256 amount) external view returns (uint256);
function getTotalAssetsValuation(uint256 externalAssets) external view returns (uint256);
function convertToShares(
address lpTokenAddress,
address assetInAddr,
address vaultAddr,
uint256 assetInAmount,
uint256 externalAssets
) external view returns (uint256 shares, uint256 amountInReferenceTokens);
function REFERENCE_ASSET() external view returns (address);
function REFERENCE_ASSET_DECIMALS() external view returns (uint8);
}
// src/core/interfaces/IFeeCollectorsAware.sol
interface IFeeCollectorsAware {
struct CollectorDefinition {
address collectorAddress;
uint256 percentage;
}
function updateFeeCollectors(CollectorDefinition[] calldata collectors) external;
function updatePerformanceFeeCollectors(CollectorDefinition[] calldata collectors) external;
}
// src/core/interfaces/IOperableResource.sol
interface IOperableResource {
function owner() external view returns (address);
function operatorAddress() external view returns (address);
}
// src/core/interfaces/IOwnable.sol
interface IOwnable {
function transferOwnership(address newOwnerAddr) external;
function owner() external view returns (address);
}
// src/core/interfaces/IResourceBasedTimelockedCall.sol
interface IResourceBasedTimelockedCall {
error Unauthorized();
error HashRequired();
error HashAlreadyEnqueued();
error HashNotEnqueued();
error TimelockInPlace();
error InvalidTimelockDuration();
error InvalidResourceAddress();
struct TimelockedCallInfo {
uint256 targetEpoch; // The unix epoch at which the hash can be consumed
address createdBy; // The address of the scheduler
}
/// @notice Triggers when a hash is scheduled for further execution
event HashScheduled(bytes32 h, address postedBy);
/// @notice Triggers when a hash is consumed by the address specified.
event HashConsumed(bytes32 h, address consumerAddress);
/// @notice Triggers when a hash is cancelled.
event HashCancelled(bytes32 h, address consumerAddress);
function schedule(bytes32 h) external;
function cancel(bytes32 h) external;
function consume(bytes32 h) external;
function hashExists(bytes32 h) external view returns (bool);
function getInfo(bytes32 h) external view returns (TimelockedCallInfo memory);
}
// src/core/interfaces/ISendersWhitelist.sol
interface ISendersWhitelist {
function enableSender(address addr) external;
function disableSender(address addr) external;
function isWhitelisted(address addr) external view returns (bool);
}
// src/tokenized-vaults/ITokenizedVault.sol
interface ITokenizedVault {
error HighWatermarkViolation();
error HighWatermarkDurationError();
error TokenDecimalsMismatch();
error InvalidLagDuration();
struct ConfigInfo {
uint256 maxDepositAmount;
uint256 maxWithdrawalAmount;
uint256 instantRedemptionFee;
uint256 lagDuration;
uint256 withdrawalFee;
uint256 watermarkTimeWindow;
uint256 maxChangePercent;
uint256 managementFeePercent;
uint256 performanceFeeRate;
address sendersWhitelistAddress;
address operatorAddress;
address scheduledCallerAddress;
address lpTokenAddress;
address referenceAsset;
address futureOwnerAddress;
address assetsWhitelistAddress;
}
/// @notice Triggers when the resource is configured.
event ContractConfigured();
/// @notice Triggers during an emergency withdrawal.
event OnEmergencyWithdraw(address receiverAddr);
function configure(ConfigInfo calldata newConfig) external;
function asset() external view returns (address);
}
// lib/open-zeppelin/utils/math/MathUpgradeable.sol
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library MathUpgradeable {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
// src/core/OwnableGuarded.sol
abstract contract OwnableGuarded {
// ----------------------------------------------------------------------------------------------------
// Constants
// ----------------------------------------------------------------------------------------------------
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
// ----------------------------------------------------------------------------------------------------
// Errors
// ----------------------------------------------------------------------------------------------------
error OwnerOnly();
error OwnerAddressRequired();
error ReentrancyGuardReentrantCall();
// ----------------------------------------------------------------------------------------------------
// Storage layout
// ----------------------------------------------------------------------------------------------------
uint256 private _status;
address internal _owner;
// ----------------------------------------------------------------------------------------------------
// Events
// ----------------------------------------------------------------------------------------------------
/**
* @notice Triggers when contract ownership changes.
* @param previousOwner The previous owner of the contract.
* @param newOwner The new owner of the contract.
*/
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
// ----------------------------------------------------------------------------------------------------
// Modifiers
// ----------------------------------------------------------------------------------------------------
/**
* @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 making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// 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;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
if (msg.sender != _owner) revert OwnerOnly();
_;
}
// ----------------------------------------------------------------------------------------------------
// Functions
// ----------------------------------------------------------------------------------------------------
/**
* @notice Transfers ownership of the contract to the account specified.
* @param newOwner The address of the new owner.
*/
function transferOwnership(address newOwner) external virtual nonReentrant onlyOwner {
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
if (newOwner == address(0)) revert OwnerAddressRequired();
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @notice Gets the owner of the contract.
* @return address The address who owns the contract.
*/
function owner() external view virtual returns (address) {
return _owner;
}
}
// lib/open-zeppelin/proxy/Proxy.sol
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive() external payable virtual {
_fallback();
}
/**
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
* call, or as part of the Solidity `fallback` or `receive` functions.
*
* If overridden should call `super._beforeFallback()`.
*/
function _beforeFallback() internal virtual {}
}
// lib/open-zeppelin/utils/StorageSlot.sol
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}
// lib/open-zeppelin/interfaces/draft-IERC1822.sol
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}
// lib/open-zeppelin/token/ERC20/extensions/IERC20Metadata.sol
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
// src/core/Ownable2StepsGuarded.sol
abstract contract Ownable2StepsGuarded is OwnableGuarded {
error InvalidAddress();
error Unauthorized();
/// @dev The address of the pending owner, if any.
address internal _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @notice Starts the ownership transfer of this contract to the address specified.
* @dev The ownership transfer is time-locked. Calling this function cancels any previous scheduled requests.
* @param newOwner The address of the new owner.
*/
function transferOwnership(address newOwner) public virtual override nonReentrant onlyOwner {
_proposeOwnershipTransfer(newOwner);
}
/**
* @notice Accepts the ownership transfer initiated by the current owner of this contract.
*/
function acceptOwnership() public virtual nonReentrant {
if (_pendingOwner != msg.sender) revert Unauthorized();
_transferOwnership(msg.sender);
}
function _proposeOwnershipTransfer(address newOwner) internal {
if ((newOwner == address(0)) || (newOwner == address(this))) revert InvalidAddress();
_pendingOwner = newOwner;
emit OwnershipTransferStarted(_owner, newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @notice Gets the address of the pending owner, if any.
* @return Returns the address of the pending owner. Returns the zero address if there is no pending owner at all.
*/
function pendingOwner() external view returns (address) {
return _pendingOwner;
}
}
// src/core/SendersWhitelist.sol
/**
* @title This contract manages a whitelist of message senders.
*/
contract SendersWhitelist is ISendersWhitelist, OwnableGuarded {
error AlreadyApproved();
mapping (address => bool) internal _addresses;
constructor(address ownerAddr) {
_owner = ownerAddr;
}
/**
* @notice Enables the address specified.
* @param addr The address to enable.
*/
function enableSender(address addr) external override onlyOwner {
if (_addresses[addr]) revert AlreadyApproved();
_addresses[addr] = true;
}
/**
* @notice Disables the address specified.
* @param addr The address to disable.
*/
function disableSender(address addr) external override onlyOwner {
_addresses[addr] = false;
}
/**
* @notice Indicates if the address specified is whitelisted.
* @param addr The address to evaluate.
* @return bool Returns true if the address is whitelisted.
*/
function isWhitelisted(address addr) external view override returns (bool) {
return _addresses[addr];
}
}
// lib/open-zeppelin/token/ERC20/ERC20.sol
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* 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}.
*
* 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 default value returned by this function, unless
* it's 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:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, 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}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, 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}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, 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) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, 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) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* 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:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, 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;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_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;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_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 Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - 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 {}
}
// src/core/ResourceBasedTimelockedCall.sol
/**
* @title Allows a resource to schedule and consume time-locked hashes.
*/
contract ResourceBasedTimelockedCall is IResourceBasedTimelockedCall, BaseReentrancy {
/// @dev A reasonable time-window for manipulating the block timestamp as a miner.
uint256 constant internal _TIMESTAMP_MANIPULATION_WINDOW = 5 minutes;
/// @notice The address of the operable smart contract.
IOperableResource public immutable RESOURCE;
/// @notice The time-lock duration of the consumer.
uint256 public immutable TIMELOCK_DURATION;
/// @notice The time-lock info of a given hash.
mapping (bytes32 => TimelockedCallInfo) public queue;
/// @dev Throws if the sender is not the expected resource address.
modifier onlyResource() {
if (msg.sender != address(RESOURCE)) revert Unauthorized();
_;
}
constructor(
address newResource,
uint256 newTimeLockDuration
) {
if (newTimeLockDuration < _TIMESTAMP_MANIPULATION_WINDOW) revert InvalidTimelockDuration();
RESOURCE = IOperableResource(newResource);
TIMELOCK_DURATION = newTimeLockDuration;
}
/**
* @notice Schedules a hash for further execution.
* @dev Throws if the sender is not the expected resource, nor the owner/operator of such resource.
* @param h Specifies the hash to schedule.
*/
function schedule(bytes32 h) external override nonReentrant {
if (h == bytes32(0)) revert HashRequired();
if (queue[h].createdBy != address(0)) revert HashAlreadyEnqueued();
queue[h] = TimelockedCallInfo({
createdBy: msg.sender,
targetEpoch: block.timestamp + TIMELOCK_DURATION
});
emit HashScheduled(h, msg.sender);
// Validate the message sender
_enforceValidSender();
}
/**
* @notice Cancels an existing hash.
* @param h Specifies the hash to cancel.
*/
function cancel(bytes32 h) external nonReentrant {
if (queue[h].createdBy == address(0)) revert HashNotEnqueued();
delete queue[h];
emit HashCancelled(h, msg.sender);
// Validate the message sender
_enforceValidSender();
}
/**
* @notice Consumes the hash specified.
* @dev Throws if the sender is not the expected resource.
* @param h Specifies the hash to consume.
*/
function consume(bytes32 h) external override nonReentrant onlyResource {
if (queue[h].targetEpoch < 1) revert HashNotEnqueued();
if (block.timestamp < queue[h].targetEpoch) revert TimelockInPlace();
delete queue[h];
emit HashConsumed(h, msg.sender);
}
/**
* @notice Indicates if the hash specified was enqueued.
* @param h Specifies the hash to evaluate.
* @return bool Returns true if the hash specified was enqueued.
*/
function hashExists(bytes32 h) external override view returns (bool) {
return queue[h].targetEpoch > 0;
}
/**
* @notice Gets the details of the hash specified.
* @param h Specifies the hash to evaluate.
* @return TimelockedCallInfo Returns a struct containing the details.
*/
function getInfo(bytes32 h) external override view returns (TimelockedCallInfo memory) {
return queue[h];
}
/// @dev Throws if the sender is not the expected resource, nor the owner/operator of such resource.
function _enforceValidSender() private view {
address theOwner = RESOURCE.owner();
address theOperator = RESOURCE.operatorAddress();
if (
(msg.sender != address(RESOURCE)) &&
(msg.sender != theOwner) &&
(msg.sender != theOperator)
) revert Unauthorized();
}
}
// lib/open-zeppelin/proxy/ERC1967/ERC1967Upgrade.sol
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*/
abstract contract ERC1967Upgrade {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Emitted when the beacon is upgraded.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}
// lib/open-zeppelin/proxy/ERC1967/ERC1967Proxy.sol
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)
/**
* @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
* implementation address that can be changed. This address is stored in storage in the location specified by
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
* implementation behind the proxy.
*/
contract ERC1967Proxy is Proxy, ERC1967Upgrade {
/**
* @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
*
* If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
* function call, and allows initializing the storage of the proxy like a Solidity constructor.
*/
constructor(address _logic, bytes memory _data) payable {
_upgradeToAndCall(_logic, _data, false);
}
/**
* @dev Returns the current implementation address.
*/
function _implementation() internal view virtual override returns (address impl) {
return ERC1967Upgrade._getImplementation();
}
}
// lib/open-zeppelin/proxy/transparent/TransparentUpgradeableProxy.sol
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/transparent/TransparentUpgradeableProxy.sol)
/**
* @dev This contract implements a proxy that is upgradeable by an admin.
*
* To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
* clashing], which can potentially be used in an attack, this contract uses the
* https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
* things that go hand in hand:
*
* 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
* that call matches one of the admin functions exposed by the proxy itself.
* 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
* implementation. If the admin tries to call a function on the implementation it will fail with an error that says
* "admin cannot fallback to proxy target".
*
* These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
* the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
* to sudden errors when trying to call a function from the proxy implementation.
*
* Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
* you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
*/
contract TransparentUpgradeableProxy is ERC1967Proxy {
/**
* @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
* optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
*/
constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
_changeAdmin(admin_);
}
/**
* @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
*/
modifier ifAdmin() {
if (msg.sender == _getAdmin()) {
_;
} else {
_fallback();
}
}
/**
* @dev Returns the current admin.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function admin() external payable ifAdmin returns (address admin_) {
_requireZeroValue();
admin_ = _getAdmin();
}
/**
* @dev Returns the current implementation.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
*/
function implementation() external payable ifAdmin returns (address implementation_) {
_requireZeroValue();
implementation_ = _implementation();
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
*/
function changeAdmin(address newAdmin) external payable virtual ifAdmin {
_requireZeroValue();
_changeAdmin(newAdmin);
}
/**
* @dev Upgrade the implementation of the proxy.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
*/
function upgradeTo(address newImplementation) external payable ifAdmin {
_requireZeroValue();
_upgradeToAndCall(newImplementation, bytes(""), false);
}
/**
* @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
* by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
* proxied contract.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
*/
function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
_upgradeToAndCall(newImplementation, data, true);
}
/**
* @dev Returns the current admin.
*/
function _admin() internal view virtual returns (address) {
return _getAdmin();
}
/**
* @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
*/
function _beforeFallback() internal virtual override {
require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
super._beforeFallback();
}
/**
* @dev To keep this contract fully transparent, all `ifAdmin` functions must be payable. This helper is here to
* emulate some proxy functions being non-payable while still allowing value to pass through.
*/
function _requireZeroValue() private {
require(msg.value == 0);
}
}
// src/core/EnableOnlyAssetsWhitelist.sol
/**
* @title Assets whitelist.
* @dev Assets cannot be disabled once they're enabled. There is one whitelist per Reference Asset.
*/
contract EnableOnlyAssetsWhitelist is IEnableOnlyAssetsWhitelist, OwnableGuarded {
using MathUpgradeable for uint256;
// --------------------------------------------------------------------------
// Storage layout
// --------------------------------------------------------------------------
/// @dev The list of whitelisted assets
address[] internal _whitelistedAssets;
/// @notice The address of the reference asset
address public immutable override REFERENCE_ASSET;
/// @notice The decimal places of the reference asset
uint8 public immutable override REFERENCE_ASSET_DECIMALS;
/// @dev Tracks the oracle assigned to a synthetic pair (input asset => OracleInfo)
mapping (address => OracleInfo) internal _oracleOfInputAsset;
/// @notice The difference between the current timestamp and the quote from the external oracle, expressed in seconds.
mapping (address => uint256) public maxOracleUpdatesDuration;
// --------------------------------------------------------------------------
// Constructor
// --------------------------------------------------------------------------
constructor(address ownerAddr, address referenceAssetAddr) {
if (ownerAddr == address(0)) revert OwnerAddressRequired();
if (referenceAssetAddr == address(0)) revert InvalidAddress();
_owner = ownerAddr;
REFERENCE_ASSET = referenceAssetAddr;
REFERENCE_ASSET_DECIMALS = ERC20(referenceAssetAddr).decimals();
}
// --------------------------------------------------------------------------
// Functions
// --------------------------------------------------------------------------
/**
* @notice Enables the asset specified.
* @dev Enabling an asset requires assigning an oracle to the synthetic pair.
* @param assetAddr The address of the asset to enable.
* @param oracleAddr The oracle assigned to the asset specified.
* @param newOracleDuration The lag accepted on the oracle of this asset
*/
function enableAsset(
address assetAddr,
address oracleAddr,
uint256 newOracleDuration
) external override nonReentrant onlyOwner {
if ((oracleAddr == address(0)) || (assetAddr == address(0))) revert ZeroAddressError();
if (_whitelistedAssets.length > 30) revert WhitelistLimitReached();
if (assetAddr == REFERENCE_ASSET) revert ReferenceAssetNotPermitted();
// Make sure the asset is not duplicated
if (_oracleOfInputAsset[assetAddr].tokenAddress != address(0)) revert AssetAlreadyEnabled();
_whitelistedAssets.push(assetAddr);
uint8 tokenDecimals = ERC20(assetAddr).decimals();
// Make sure the token has 6 decimal positions at least
if (tokenDecimals < 6) revert InvalidDecimalPlaces();
uint8 oracleDecimals = IAggregatorV3Interface(oracleAddr).decimals();
_oracleOfInputAsset[assetAddr] = OracleInfo({
oracleAddress: oracleAddr,
tokenAddress: assetAddr,
oracleDecimals: oracleDecimals,
tokenDecimals: tokenDecimals
});
maxOracleUpdatesDuration[assetAddr] = newOracleDuration;
}
/**
* @notice Updates the maximum lag of oracles.
* @param newMaxOracleUpdatesDuration The lag we are willing to accept.
* @param assetAddr The asset address
*/
function updateOracleLagDuration(uint256 newMaxOracleUpdatesDuration, address assetAddr) external nonReentrant onlyOwner {
maxOracleUpdatesDuration[assetAddr] = newMaxOracleUpdatesDuration;
}
/**
* @notice Shares conversion function.
* @param lpTokenAddress The address of the LP token.
* @param assetInAddr The address of the deposit token.
* @param vaultAddr The address of the vault.
* @param assetInAmount The deposit amount.
* @param externalAssets The external assets reported by the vault.
* @return shares The number of shares
* @return amountInReferenceTokens The amount expressed in reference tokens
*/
function convertToShares(
address lpTokenAddress,
address assetInAddr,
address vaultAddr,
uint256 assetInAmount,
uint256 externalAssets
) external view override returns (
uint256 shares,
uint256 amountInReferenceTokens
) {
if (assetInAmount < 1) return (0, 0);
uint256 tSupply = IERC20(lpTokenAddress).totalSupply();
amountInReferenceTokens = (assetInAddr == REFERENCE_ASSET) ? assetInAmount : _fromInputAssetToReferenceAsset(assetInAddr, assetInAmount);
uint256 totalAssetsInReferenceTokens = _getTotalAssetsValuation(vaultAddr, externalAssets);
shares = (tSupply < 1) ? amountInReferenceTokens : amountInReferenceTokens.mulDiv(tSupply, totalAssetsInReferenceTokens, MathUpgradeable.Rounding.Down);
}
/**
* @notice Gets the oracle assigned to the asset specified.
* @return address Returns the address of the oracle.
*/
function getOracleAddress(address assetAddr) external view override returns (address) {
return _oracleOfInputAsset[assetAddr].oracleAddress;
}
/**
* @notice Indicates if a given asset is whitelisted.
* @return bool Returns true if the asset is whitelisted.
*/
function isWhitelisted(address assetAddr) external view override returns (bool) {
return _oracleOfInputAsset[assetAddr].oracleAddress != address(0);
}
/**
* @notice Gets the list of whitelisted assets.
* @return address[] Returns an array of asset addresses.
*/
function getWhitelistedAssets() external view override returns (address[] memory) {
return _whitelistedAssets;
}
/**
* @notice Converts the input amount into the respective amount of reference tokens.
* @param assetAddr The asset address.
* @param amount The asset amount.
*/
function fromInputAssetToReferenceAsset(
address assetAddr,
uint256 amount
) external view override returns (uint256) {
return _fromInputAssetToReferenceAsset(assetAddr, amount);
}
/**
* @notice Gets the valuation (total assets) of the sender specified. The sender is a vault.
* @param externalAssets The external assets reported by the vault.
* @return uint256 The total valuation of the vault.
*/
function getTotalAssetsValuation(uint256 externalAssets) external view override returns (uint256) {
return _getTotalAssetsValuation(msg.sender, externalAssets);
}
function _convertToAssets(
address vaultAddr,
address lpTokenAddress,
uint256 externalAssets,
uint256 shares,
MathUpgradeable.Rounding rounding
) internal view returns (uint256) {
uint256 tSupply = IERC20(lpTokenAddress).totalSupply();
return (tSupply < 1) ? shares : shares.mulDiv(_getTotalAssetsValuation(vaultAddr, externalAssets), tSupply, rounding);
}
/// @dev Calculates the valuation of the vault specified. The result is expressed in reference tokens.
function _getTotalAssetsValuation(
address vaultAddr,
uint256 externalAssets
) internal view returns (uint256) {
address assetAddr;
uint256 assetBalance;
uint256 balanceInReferenceTokens;
uint256 t = _whitelistedAssets.length;
uint256 acum = externalAssets + IERC20(REFERENCE_ASSET).balanceOf(vaultAddr);
for (uint256 i; i < t; i++) {
assetAddr = _whitelistedAssets[i];
assetBalance = IERC20(assetAddr).balanceOf(vaultAddr);
if (assetBalance > 0) {
balanceInReferenceTokens = _fromInputAssetToReferenceAsset(assetAddr, assetBalance);
acum += balanceInReferenceTokens;
}
}
// External assets + multi assets liquidity + liquidity of the reference token
return acum;
}
/// @dev Converts the input amount into the respective amount of reference tokens
function _fromInputAssetToReferenceAsset(
address assetAddr,
uint256 amount
) internal view returns (uint256) {
address oracleAddr = _oracleOfInputAsset[assetAddr].oracleAddress;
uint8 tokenDecimals = _oracleOfInputAsset[assetAddr].tokenDecimals;
uint8 oracleDecimals = _oracleOfInputAsset[assetAddr].oracleDecimals;
// Query the external Oracle
(
uint80 quoteRoundId,
int256 quoteAnswer,
,
uint256 quoteTimestamp,
uint80 quoteAnsweredInRound
) = IAggregatorV3Interface(oracleAddr).latestRoundData();
// Validate the Oracle's response
if (quoteAnswer < 1) revert InvalidOraclePrice();
if (quoteAnsweredInRound < quoteRoundId) revert StalePrice();
if (quoteTimestamp < 1) revert RoundNotComplete();
if (quoteTimestamp > block.timestamp) revert InvalidOracleTimestamp(); // Cannot trust in the external contract/oracle, thus the check.
if (block.timestamp - quoteTimestamp > maxOracleUpdatesDuration[assetAddr]) revert InvalidTimePeriod();
// Distance between the decimals of the oracle and the decimals of the token
uint256 d1 = (oracleDecimals > tokenDecimals) ? 10 ** (oracleDecimals - tokenDecimals) : 1;
uint256 d2 = (REFERENCE_ASSET_DECIMALS > oracleDecimals) ? 10 ** (REFERENCE_ASSET_DECIMALS - oracleDecimals) : 1;
uint256 amountInNormalized = amount * d1;
// Distance between the maximum scale and the scale provided by the oracle
uint256 d3 = 10 ** (18 - oracleDecimals);
uint256 ratio = (10 ** oracleDecimals) * d3 / uint256(quoteAnswer); // Scaled to d2
uint256 result = ratio * amountInNormalized * d2 / d3;
if (tokenDecimals == REFERENCE_ASSET_DECIMALS) {
if (REFERENCE_ASSET_DECIMALS == 6) {
result /= d1;
}
else if (REFERENCE_ASSET_DECIMALS > 17) {
ratio = uint256(quoteAnswer);
result = ratio * amountInNormalized * d2 / d3 / 1e18;
}
}
if (REFERENCE_ASSET_DECIMALS == 6) {
if (tokenDecimals == 18) result /= 1e7;
else if (tokenDecimals == 8) result /= 1e2;
}
return result;
}
}
// src/core/ProxyAdminOwnable2Steps.sol
contract ProxyAdminOwnable2Steps is Ownable2StepsGuarded {
error FunctionNotAvailable();
constructor() {
_owner = msg.sender;
}
/**
* @dev Returns the current implementation of `proxy`.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function getProxyImplementation(TransparentUpgradeableProxy proxy) public view returns (address) {
// We need to manually run the static call since the getter cannot be flagged as view
// bytes4(keccak256("implementation()")) == 0x5c60da1b
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
if (!success) revert FunctionNotAvailable();
return abi.decode(returndata, (address));
}
/**
* @dev Returns the current admin of `proxy`.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function getProxyAdmin(TransparentUpgradeableProxy proxy) public view returns (address) {
// We need to manually run the static call since the getter cannot be flagged as view
// bytes4(keccak256("admin()")) == 0xf851a440
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
if (!success) revert FunctionNotAvailable();
return abi.decode(returndata, (address));
}
/**
* @dev Changes the admin of `proxy` to `newAdmin`.
*
* Requirements:
*
* - This contract must be the current admin of `proxy`.
*/
function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) external nonReentrant onlyOwner {
proxy.changeAdmin(newAdmin);
}
/**
* @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function upgrade(TransparentUpgradeableProxy proxy, address implementation) external nonReentrant onlyOwner {
proxy.upgradeTo(implementation);
}
/**
* @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
* {TransparentUpgradeableProxy-upgradeToAndCall}.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function upgradeAndCall(
TransparentUpgradeableProxy proxy,
address implementation,
bytes memory data
) external payable nonReentrant onlyOwner {
proxy.upgradeToAndCall{value: msg.value}(implementation, data);
}
}
// src/tokenized-vaults/MasterDeployer.sol
contract MasterDeployer is Ownable2StepsGuarded {
error LayerZeroEndpointNotAvailable();
error LayerZeroEndpointAlreadySet();
error InvalidErc20();
error ZeroAddressError();
error DeployerNotWhitelisted();
error DeployerAlreadyWhitelisted();
error TokenImplementationNotSet();
error VaultImplementationNotSet();
error AddressAlreadyTaken();
error InvalidTokenDecimals();
error ProxyAdminDeploymentFailed();
error ProxyDeploymentFailed();
error DeploymentAlreadyExecuted();
error DeploymentSpecRequired();
bytes32 constant private _VAULT_PROXYADMIN_PREFIX = bytes32("VaultProxyAdmin.");
bytes32 constant private _VAULT_PROXY_PREFIX = bytes32("VaultProxy.");
bytes32 constant private _TOKEN_PROXYADMIN_PREFIX = bytes32("TokenProxyAdmin.");
bytes32 constant private _TOKEN_PROXY_PREFIX = bytes32("TokenProxy.");
bytes32 constant private _PLATFORM_VENDOR_PREFIX = bytes32("Upshift.");
struct Spec {
address referenceAsset;
bool kycRequired;
uint8 lpTokenDecimals;
string lpTokenSymbol;
string lpTokenName;
string orgName;
string entropyA;
string entropyB;
string entropyC;
string entropyD;
address tokenProxyOwner;
address tokenProxyAdminOwner;
address vaultProxyOwner;
address vaultProxyAdminOwner;
address operatorAddress;
IFeeCollectorsAware.CollectorDefinition[] feeCollectors;
IFeeCollectorsAware.CollectorDefinition[] performanceFeeCollectors;
uint256 maxDepositAmount;
uint256 maxWithdrawalAmount;
uint256 instantRedemptionFee;
uint256 lagDuration;
uint256 withdrawalFee;
uint256 watermarkTimeWindow;
uint256 maxChangePercent;
uint256 managementFeePercent;
uint256 performanceFeeRate;
}
struct DeploymentRequest {
bytes32 adminSaltVault;
bytes32 proxySaltVault;
bytes32 adminSaltToken;
bytes32 proxySaltToken;
uint256 totalFeeCollectors;
uint256 totalPerformanceFeeCollectors;
uint256 maxDepositAmount;
uint256 maxWithdrawalAmount;
uint256 instantRedemptionFee;
uint256 lagDuration;
uint256 withdrawalFee;
uint256 watermarkTimeWindow;
uint256 maxChangePercent;
uint256 managementFeePercent;
uint256 performanceFeeRate;
bytes tokenInitData;
bytes vaultInitData;
address tokenProxyOwner;
address tokenProxyAdminOwner;
address vaultProxyOwner;
address vaultProxyAdminOwner;
address operatorAddress;
address vaultReferenceAsset;
bool kycRequired;
}
struct DeploymentRecord {
address tokenProxy;
address tokenProxyAdmin;
address tokenImplAddress;
address vaultProxy;
address vaultProxyAdmin;
address vaultImplAddress;
address assetsWhitelistAddress;
address sendersWhitelistAddress;
address scheduledCallerAddress;
}
uint256 private _nextId;
address public lzEndpointAddress;
address public tokenImplementationAddress;
address public vaultImplementationAddress;
mapping (address => bool) public whitelistedDeployers;
mapping (uint256 => DeploymentRecord) public deploymentRecords;
mapping (uint256 => DeploymentRequest) private _deploymentRequests;
mapping (uint256 => mapping(uint256 => address)) private _feeCollectorAddresses;
mapping (uint256 => mapping(uint256 => uint256)) private _feeCollectorPercent;
mapping (uint256 => mapping(uint256 => address)) private _performanceFeeCollectorAddresses;
mapping (uint256 => mapping(uint256 => uint256)) private _performanceFeeCollectorPercent;
event DeploymentRequestAccepted(uint256 deploymentId);
event DeploymentCompleted(uint256 deploymentId);
event LpTokenDeployed(address proxyAddr, address proxyAdminAddr, address implAddr);
event VaultDeployed(address proxyAddr, address proxyAdminAddr, address implAddr);
constructor(address ownerAddr) {
if (ownerAddr == address(0)) revert ZeroAddressError();
_owner = ownerAddr;
whitelistedDeployers[ownerAddr] = true;
}
modifier onlyDeployer() {
if (!whitelistedDeployers[msg.sender]) revert DeployerNotWhitelisted();
_;
}
/**
* @notice Grants permissions to the deployer address specified.
* @param addr The address of the deployer.
*/
function grantDeployer(address addr) external nonReentrant onlyOwner {
if (addr == address(0)) revert ZeroAddressError();
if (whitelistedDeployers[addr]) revert DeployerAlreadyWhitelisted();
whitelistedDeployers[addr] = true;
}
/**
* @notice Revokes permissions from the deployer address specified.
* @param addr The address of the deployer.
*/
function revokeDeployer(address addr) external nonReentrant onlyOwner {
if (!whitelistedDeployers[addr]) revert DeployerNotWhitelisted();
whitelistedDeployers[addr] = false;
}
/**
* @notice Sets the address of the token implementation.
* @param addr The new address.
*/
function setTokenImplementation(address addr) external nonReentrant onlyOwner {
if (addr == address(0)) revert ZeroAddressError();
tokenImplementationAddress = addr;
}
/**
* @notice Sets the address of the vault implementation.
* @param addr The new address.
*/
function setVaultImplementation(address addr) external nonReentrant onlyOwner {
if (addr == address(0)) revert ZeroAddressError();
vaultImplementationAddress = addr;
}
/**
* @notice Sets the LayerZero endpoint for the current chain. The endpoint cannot be updated once it is defined.
* @param lzEndpointAddr The address of the LayerZero endpoint for the current chain.
*/
function setEndpoint(address lzEndpointAddr) external nonReentrant onlyOwner {
if (lzEndpointAddr == address(0)) revert ZeroAddressError();
if (lzEndpointAddress != address(0)) revert LayerZeroEndpointAlreadySet();
lzEndpointAddress = lzEndpointAddr;
}
/**
* @notice Requests the execution of a brand new deployment.
* @dev Throws if the sender is not a whitelisted deployer.
* @param spec The deployment specification.
* @return uint256 Returns the ID of the newly created deployment request.
*/
function submitSpec(Spec calldata spec) external nonReentrant onlyDeployer returns (uint256) {
// Make sure the LayerZero endpoint was defined for the current chain
if (lzEndpointAddress == address(0)) revert LayerZeroEndpointNotAvailable();
// Make sure the implementations are available
if (tokenImplementationAddress == address(0)) revert TokenImplementationNotSet();
if (vaultImplementationAddress == address(0)) revert VaultImplementationNotSet();
// Check the decimals of the LP token
if ((spec.lpTokenDecimals < 6) || (spec.lpTokenDecimals > 18)) revert InvalidTokenDecimals();
// Compute the deployment hashes.
// The hashes below represent the salt(s) to be used when deploying the transparent proxies of the Vault and LP token.
(
bytes32 tokenProxyHash,
bytes32 tokenProxyAdminHash,
bytes32 vaultProxyHash,
bytes32 vaultProxyAdminHash
) = _buildHashes(spec);
// Acquire a new deployment ID
uint256 deploymentId = ++_nextId;
// Save the deployment request, for the sake of transparency.
_deploymentRequests[deploymentId] = DeploymentRequest({
adminSaltVault: vaultProxyAdminHash,
proxySaltVault: vaultProxyHash,
adminSaltToken: tokenProxyAdminHash,
proxySaltToken: tokenProxyHash,
tokenInitData: abi.encodeWithSignature("initialize(address,uint8,string,string)", address(this), spec.lpTokenDecimals, spec.lpTokenSymbol, spec.lpTokenName),
vaultInitData: abi.encodeWithSignature("initialize(address)", address(this)),
tokenProxyOwner: spec.tokenProxyOwner,
tokenProxyAdminOwner: spec.tokenProxyAdminOwner,
vaultProxyOwner: spec.vaultProxyOwner,
vaultProxyAdminOwner: spec.vaultProxyAdminOwner,
totalFeeCollectors: spec.feeCollectors.length,
totalPerformanceFeeCollectors: spec.performanceFeeCollectors.length,
vaultReferenceAsset: spec.referenceAsset,
kycRequired: spec.kycRequired,
operatorAddress: spec.operatorAddress,
maxDepositAmount: spec.maxDepositAmount,
maxWithdrawalAmount: spec.maxWithdrawalAmount,
instantRedemptionFee: spec.instantRedemptionFee,
lagDuration: spec.lagDuration,
withdrawalFee: spec.withdrawalFee,
watermarkTimeWindow: spec.watermarkTimeWindow,
maxChangePercent: spec.maxChangePercent,
managementFeePercent: spec.managementFeePercent,
performanceFeeRate: spec.performanceFeeRate
});
// Transform the fee collectors, due to the technical constraints of the EVM
_transformCollectors(deploymentId, spec);
// Log the respective event
emit DeploymentRequestAccepted(deploymentId);
// Revert if the reference asset is not compliant with the ERC20 standard
if (IERC20Metadata(spec.referenceAsset).decimals() < 6) revert InvalidErc20();
return deploymentId;
}
/**
* @notice Deploys a fresh ecosystem based on the request specified.
* @param deploymentId The ID of the deployment request.
*/
function deploy(uint256 deploymentId) external nonReentrant onlyDeployer {
// Cannot deploy without an existing Spec
if (_deploymentRequests[deploymentId].vaultProxyOwner == address(0)) revert DeploymentSpecRequired();
// Cannot re-deploy the same ID
if (deploymentRecords[deploymentId].vaultProxy != address(0)) revert DeploymentAlreadyExecuted();
// Deploy the LP token
(address tokenAdminContractAddr, address tokenProxyContractAddr) = _deployToken(deploymentId);
// Deploy the vault
(address vaultAdminContractAddr, address vaultProxyContractAddr) = _deployVault(deploymentId);
// Deploy a new instance of the resource-based time-locked calls contract.
address vaultScheduledCallerAddr = address(new ResourceBasedTimelockedCall(vaultProxyContractAddr, 24 hours));
// Deploy a new instance of the contract responsible for managing whitelisted tokens
address assetsWhitelistAddr = address(new EnableOnlyAssetsWhitelist(address(this), _deploymentRequests[deploymentId].vaultReferenceAsset));
// Deploy KYC, if needed
address sendersWhitelistAddr;
if (_deploymentRequests[deploymentId].kycRequired) {
sendersWhitelistAddr = address(new SendersWhitelist(_deploymentRequests[deploymentId].vaultProxyOwner));
}
// Track the newly created contract addresses
deploymentRecords[deploymentId] = DeploymentRecord({
tokenProxy: tokenProxyContractAddr,
tokenProxyAdmin: tokenAdminContractAddr,
tokenImplAddress: tokenImplementationAddress,
vaultProxy: vaultProxyContractAddr,
vaultProxyAdmin: vaultAdminContractAddr,
vaultImplAddress: vaultImplementationAddress,
assetsWhitelistAddress: assetsWhitelistAddr,
sendersWhitelistAddress: sendersWhitelistAddr,
scheduledCallerAddress: vaultScheduledCallerAddr
});
// Configure the LP token. The vault is the only actor authorized to mint and burn LP tokens.
address[] memory newMinters = new address[](1);
address[] memory newBurners = new address[](1);
newMinters[0] = vaultProxyContractAddr;
newBurners[0] = vaultProxyContractAddr;
IConfigurableMintableToken(tokenProxyContractAddr).configure(newMinters, newBurners);
// Configure the vault
ITokenizedVault.ConfigInfo memory vaultConfig = ITokenizedVault.ConfigInfo({
maxDepositAmount: _deploymentRequests[deploymentId].maxDepositAmount,
maxWithdrawalAmount: _deploymentRequests[deploymentId].maxWithdrawalAmount,
instantRedemptionFee: _deploymentRequests[deploymentId].instantRedemptionFee,
lagDuration: _deploymentRequests[deploymentId].lagDuration,
withdrawalFee: _deploymentRequests[deploymentId].withdrawalFee,
watermarkTimeWindow: _deploymentRequests[deploymentId].watermarkTimeWindow,
maxChangePercent: _deploymentRequests[deploymentId].maxChangePercent,
managementFeePercent: _deploymentRequests[deploymentId].managementFeePercent,
performanceFeeRate: _deploymentRequests[deploymentId].performanceFeeRate,
operatorAddress: _deploymentRequests[deploymentId].operatorAddress,
referenceAsset: _deploymentRequests[deploymentId].vaultReferenceAsset,
futureOwnerAddress: _deploymentRequests[deploymentId].vaultProxyOwner,
lpTokenAddress: tokenProxyContractAddr,
assetsWhitelistAddress: assetsWhitelistAddr,
sendersWhitelistAddress: sendersWhitelistAddr,
scheduledCallerAddress: vaultScheduledCallerAddr
});
ITokenizedVault(vaultProxyContractAddr).configure(vaultConfig);
_setFeeCollectors(deploymentId, vaultProxyContractAddr);
_setPerformanceFeeCollectors(deploymentId, vaultProxyContractAddr);
// Run the respective ownership transfers
IOwnable(tokenProxyContractAddr).transferOwnership(_deploymentRequests[deploymentId].tokenProxyOwner); // LP Token
IOwnable(vaultProxyContractAddr).transferOwnership(_deploymentRequests[deploymentId].vaultProxyOwner); // Vault
IOwnable(assetsWhitelistAddr).transferOwnership(_deploymentRequests[deploymentId].vaultProxyOwner); // Assets whitelist
emit DeploymentCompleted(deploymentId);
}
function _transformCollectors(uint256 deploymentId, Spec calldata spec) private {
// Transform the fee collectors, due to the technical constraints of the EVM
for (uint256 i; i < spec.feeCollectors.length; i++) {
_feeCollectorAddresses[deploymentId][i] = spec.feeCollectors[i].collectorAddress;
_feeCollectorPercent[deploymentId][i] = spec.feeCollectors[i].percentage;
}
for (uint256 i; i < spec.performanceFeeCollectors.length; i++) {
_performanceFeeCollectorAddresses[deploymentId][i] = spec.performanceFeeCollectors[i].collectorAddress;
_performanceFeeCollectorPercent[deploymentId][i] = spec.performanceFeeCollectors[i].percentage;
}
}
/// @dev Deploys the LP token
function _deployToken(uint256 deploymentId) private returns (
address tokenAdminContractAddr,
address tokenProxyContractAddr
) {
// Deploy a fresh LP token
(tokenAdminContractAddr, tokenProxyContractAddr) = _deployTransparentProxy(
_deploymentRequests[deploymentId].adminSaltToken,
_deploymentRequests[deploymentId].proxySaltToken,
tokenImplementationAddress,
_deploymentRequests[deploymentId].tokenProxyAdminOwner,
_deploymentRequests[deploymentId].tokenInitData
);
emit LpTokenDeployed(tokenProxyContractAddr, tokenAdminContractAddr, tokenImplementationAddress);
}
/// @dev Deploys the Vault
function _deployVault(uint256 deploymentId) private returns (
address vaultAdminContractAddr,
address vaultProxyContractAddr
) {
// Deploy a fresh Vault
(vaultAdminContractAddr, vaultProxyContractAddr) = _deployTransparentProxy(
_deploymentRequests[deploymentId].adminSaltVault,
_deploymentRequests[deploymentId].proxySaltVault,
vaultImplementationAddress,
_deploymentRequests[deploymentId].vaultProxyAdminOwner,
_deploymentRequests[deploymentId].vaultInitData
);
emit VaultDeployed(vaultProxyContractAddr, vaultAdminContractAddr, vaultImplementationAddress);
}
function _setPerformanceFeeCollectors(uint256 deploymentId, address vaultAddr) private {
uint256 t = _deploymentRequests[deploymentId].totalPerformanceFeeCollectors;
IFeeCollectorsAware.CollectorDefinition[] memory collectors = new IFeeCollectorsAware.CollectorDefinition[](t);
for (uint256 i; i < t; i++) {
collectors[i] = IFeeCollectorsAware.CollectorDefinition({
collectorAddress: _performanceFeeCollectorAddresses[deploymentId][i],
percentage: _performanceFeeCollectorPercent[deploymentId][i]
});
}
IFeeCollectorsAware(vaultAddr).updatePerformanceFeeCollectors(collectors);
}
function _setFeeCollectors(uint256 deploymentId, address vaultAddr) private {
uint256 t = _deploymentRequests[deploymentId].totalFeeCollectors;
IFeeCollectorsAware.CollectorDefinition[] memory collectors = new IFeeCollectorsAware.CollectorDefinition[](t);
for (uint256 i; i < t; i++) {
collectors[i] = IFeeCollectorsAware.CollectorDefinition({
collectorAddress: _feeCollectorAddresses[deploymentId][i],
percentage: _feeCollectorPercent[deploymentId][i]
});
}
IFeeCollectorsAware(vaultAddr).updateFeeCollectors(collectors);
}
function _deployTransparentProxy (
bytes32 adminSalt,
bytes32 proxySalt,
address implementationAddr,
address proxyOwnerAddr,
bytes memory initData
) private returns (address, address) {
// Get the predictable address of both the proxy and the proxy admin
(address adminContractAddr, address proxyContractAddr) = _getDeploymentAddress(adminSalt, proxySalt, implementationAddr, initData);
// Make sure the contract addresses above were not taken
if ((adminContractAddr.code.length > 0) || (proxyContractAddr.code.length > 0)) revert AddressAlreadyTaken();
// Deploy the proxy admin
ProxyAdminOwnable2Steps adminInstance = (new ProxyAdminOwnable2Steps){salt: adminSalt}();
if (address(adminInstance) != adminContractAddr) revert ProxyAdminDeploymentFailed();
// Deploy the transparent proxy
TransparentUpgradeableProxy proxy = (new TransparentUpgradeableProxy){salt: proxySalt}(implementationAddr, address(adminInstance), initData);
if (address(proxy) != proxyContractAddr) revert ProxyDeploymentFailed();
// Transfer ownership of the Proxy Admin
adminInstance.transferOwnership(proxyOwnerAddr);
return (adminContractAddr, proxyContractAddr);
}
/**
* @notice Calculates the deployment address of the proxy specified.
* @param adminSalt The salt of the Proxy Admin
* @param proxySalt The salt of the Transparent Proxy
* @param implementationAddr The implementation address
* @param initData The initialization data
* @return adminContractAddr The address of the proxy admin
* @return proxyContractAddr The address of the transparent proxy
*/
function _getDeploymentAddress (
bytes32 adminSalt,
bytes32 proxySalt,
address implementationAddr,
bytes memory initData
) internal view returns (
address adminContractAddr,
address proxyContractAddr
) {
adminContractAddr = address(uint160(uint256(
keccak256(abi.encodePacked(bytes1(0xff), address(this), adminSalt, keccak256(type(ProxyAdminOwnable2Steps).creationCode)))
)));
proxyContractAddr = address(uint160(uint256(
keccak256(abi.encodePacked(bytes1(0xff), address(this), proxySalt, keccak256(
abi.encodePacked(type(TransparentUpgradeableProxy).creationCode, abi.encode(implementationAddr, adminContractAddr, initData))
)))
)));
}
/**
* @notice Builds the entropy of a given spec.
* @param spec The deployment spec.
* @return tokenProxyHash The hash of the Transparent Proxy of the LP token.
* @return tokenProxyAdminHash The hash of the ProxyAdmin of the LP token.
* @return vaultProxyHash The hash of the Transparent Proxy of the Vault.
* @return vaultProxyAdminHash The hash of the ProxyAdmin of the Vault.
*/
function _buildHashes(Spec calldata spec) private pure returns (
bytes32 tokenProxyHash,
bytes32 tokenProxyAdminHash,
bytes32 vaultProxyHash,
bytes32 vaultProxyAdminHash
) {
// Build the hash of the keywords
bytes32 keywordsHash = _efficientHash(
_efficientHash(bytes32(bytes(spec.entropyA)), bytes32(bytes(spec.entropyB))),
_efficientHash(bytes32(bytes(spec.entropyC)), bytes32(bytes(spec.entropyD)))
);
// Build the hash of the very basic ERC20
bytes32 tokenHash = _efficientHash(
_efficientHash(bytes32(bytes(spec.lpTokenSymbol)), bytes32(bytes(spec.lpTokenName))),
bytes32(uint256(spec.lpTokenDecimals))
);
// Build the hash for a given vendor, token and organization
bytes32 commonHash = _efficientHash(
_efficientHash(_PLATFORM_VENDOR_PREFIX, bytes32(bytes(spec.orgName))),
_efficientHash(tokenHash, keywordsHash)
);
// Build the hash of the token's Proxy
tokenProxyHash = _efficientHash(_TOKEN_PROXY_PREFIX, commonHash);
// Build the hash of the token's ProxyAdmin
tokenProxyAdminHash = _efficientHash(_TOKEN_PROXYADMIN_PREFIX, tokenProxyHash);
// Build the hash of the vault's Proxy
vaultProxyHash = _efficientHash(_VAULT_PROXY_PREFIX, tokenProxyHash);
// Build the hash of the vault's ProxyAdmin
vaultProxyAdminHash = _efficientHash(_VAULT_PROXYADMIN_PREFIX, vaultProxyHash);
}
/// @dev Computes a hash through the most efficient manner.
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"ownerAddr","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressAlreadyTaken","type":"error"},{"inputs":[],"name":"DeployerAlreadyWhitelisted","type":"error"},{"inputs":[],"name":"DeployerNotWhitelisted","type":"error"},{"inputs":[],"name":"DeploymentAlreadyExecuted","type":"error"},{"inputs":[],"name":"DeploymentSpecRequired","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidErc20","type":"error"},{"inputs":[],"name":"InvalidTokenDecimals","type":"error"},{"inputs":[],"name":"LayerZeroEndpointAlreadySet","type":"error"},{"inputs":[],"name":"LayerZeroEndpointNotAvailable","type":"error"},{"inputs":[],"name":"OwnerAddressRequired","type":"error"},{"inputs":[],"name":"OwnerOnly","type":"error"},{"inputs":[],"name":"ProxyAdminDeploymentFailed","type":"error"},{"inputs":[],"name":"ProxyDeploymentFailed","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"TokenImplementationNotSet","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"VaultImplementationNotSet","type":"error"},{"inputs":[],"name":"ZeroAddressError","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"deploymentId","type":"uint256"}],"name":"DeploymentCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"deploymentId","type":"uint256"}],"name":"DeploymentRequestAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"proxyAddr","type":"address"},{"indexed":false,"internalType":"address","name":"proxyAdminAddr","type":"address"},{"indexed":false,"internalType":"address","name":"implAddr","type":"address"}],"name":"LpTokenDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","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":"proxyAddr","type":"address"},{"indexed":false,"internalType":"address","name":"proxyAdminAddr","type":"address"},{"indexed":false,"internalType":"address","name":"implAddr","type":"address"}],"name":"VaultDeployed","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"deploymentId","type":"uint256"}],"name":"deploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"deploymentRecords","outputs":[{"internalType":"address","name":"tokenProxy","type":"address"},{"internalType":"address","name":"tokenProxyAdmin","type":"address"},{"internalType":"address","name":"tokenImplAddress","type":"address"},{"internalType":"address","name":"vaultProxy","type":"address"},{"internalType":"address","name":"vaultProxyAdmin","type":"address"},{"internalType":"address","name":"vaultImplAddress","type":"address"},{"internalType":"address","name":"assetsWhitelistAddress","type":"address"},{"internalType":"address","name":"sendersWhitelistAddress","type":"address"},{"internalType":"address","name":"scheduledCallerAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"grantDeployer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lzEndpointAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"revokeDeployer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lzEndpointAddr","type":"address"}],"name":"setEndpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setTokenImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setVaultImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"referenceAsset","type":"address"},{"internalType":"bool","name":"kycRequired","type":"bool"},{"internalType":"uint8","name":"lpTokenDecimals","type":"uint8"},{"internalType":"string","name":"lpTokenSymbol","type":"string"},{"internalType":"string","name":"lpTokenName","type":"string"},{"internalType":"string","name":"orgName","type":"string"},{"internalType":"string","name":"entropyA","type":"string"},{"internalType":"string","name":"entropyB","type":"string"},{"internalType":"string","name":"entropyC","type":"string"},{"internalType":"string","name":"entropyD","type":"string"},{"internalType":"address","name":"tokenProxyOwner","type":"address"},{"internalType":"address","name":"tokenProxyAdminOwner","type":"address"},{"internalType":"address","name":"vaultProxyOwner","type":"address"},{"internalType":"address","name":"vaultProxyAdminOwner","type":"address"},{"internalType":"address","name":"operatorAddress","type":"address"},{"components":[{"internalType":"address","name":"collectorAddress","type":"address"},{"internalType":"uint256","name":"percentage","type":"uint256"}],"internalType":"struct IFeeCollectorsAware.CollectorDefinition[]","name":"feeCollectors","type":"tuple[]"},{"components":[{"internalType":"address","name":"collectorAddress","type":"address"},{"internalType":"uint256","name":"percentage","type":"uint256"}],"internalType":"struct IFeeCollectorsAware.CollectorDefinition[]","name":"performanceFeeCollectors","type":"tuple[]"},{"internalType":"uint256","name":"maxDepositAmount","type":"uint256"},{"internalType":"uint256","name":"maxWithdrawalAmount","type":"uint256"},{"internalType":"uint256","name":"instantRedemptionFee","type":"uint256"},{"internalType":"uint256","name":"lagDuration","type":"uint256"},{"internalType":"uint256","name":"withdrawalFee","type":"uint256"},{"internalType":"uint256","name":"watermarkTimeWindow","type":"uint256"},{"internalType":"uint256","name":"maxChangePercent","type":"uint256"},{"internalType":"uint256","name":"managementFeePercent","type":"uint256"},{"internalType":"uint256","name":"performanceFeeRate","type":"uint256"}],"internalType":"struct MasterDeployer.Spec","name":"spec","type":"tuple"}],"name":"submitSpec","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenImplementationAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultImplementationAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelistedDeployers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801562000010575f80fd5b50604051620060c7380380620060c7833981016040819052620000339162000099565b6001600160a01b0381166200005b57604051633efa09af60e01b815260040160405180910390fd5b600180546001600160a01b039092166001600160a01b0319909216821781555f91825260076020526040909120805460ff19169091179055620000c8565b5f60208284031215620000aa575f80fd5b81516001600160a01b0381168114620000c1575f80fd5b9392505050565b615ff180620000d65f395ff3fe608060405234801562000010575f80fd5b506004361062000110575f3560e01c80638b1d7b27116200009f578063d83722f0116200006b578063d83722f01462000315578063dbbb4155146200032c578063e30c39781462000343578063f2fde38b1462000355575f80fd5b80638b1d7b2714620002065780638da5cb5b146200021a578063a4e6a7b4146200022c578063a5e3875114620002fe575f80fd5b8063730791f811620000df578063730791f8146200019b5780637680711114620001d157806379ba509714620001e557806388282e2a14620001ef575f80fd5b80631f338cbf14620001145780632e4934dd14620001455780632fa435f3146200015e57806353e78b6b1462000184575b5f80fd5b60055462000128906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6200015c620001563660046200231b565b6200036c565b005b620001756200016f3660046200234a565b6200041c565b6040519081526020016200013c565b6200015c620001953660046200231b565b62000a36565b620001c0620001ac3660046200231b565b60076020525f908152604090205460ff1681565b60405190151581526020016200013c565b60045462000128906001600160a01b031681565b6200015c62000ad7565b6200015c620002003660046200231b565b62000b3a565b60065462000128906001600160a01b031681565b6001546001600160a01b031662000128565b620002a36200023d36600462002385565b600860208190525f91825260409091208054600182015460028301546003840154600485015460058601546006870154600788015497909801546001600160a01b0396871698958716979487169693841695928416949184169392831692918216911689565b604080516001600160a01b039a8b168152988a1660208a01529689169688019690965293871660608701529186166080860152851660a0850152841660c0840152831660e0830152909116610100820152610120016200013c565b6200015c6200030f36600462002385565b62000bdb565b6200015c620003263660046200231b565b6200153d565b6200015c6200033d3660046200231b565b6200161a565b6002546001600160a01b031662000128565b6200015c620003663660046200231b565b620016e6565b60025f54036200038f57604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b03163314620003bf57604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b0381165f9081526007602052604090205460ff16620003f8576040516305dab3df60e21b815260040160405180910390fd5b6001600160a01b03165f908152600760205260408120805460ff1916905560019055565b5f60025f54036200044057604051633ee5aeb560e01b815260040160405180910390fd5b60025f9081553381526007602052604090205460ff1662000474576040516305dab3df60e21b815260040160405180910390fd5b6004546001600160a01b03166200049e576040516311f68ef960e21b815260040160405180910390fd5b6005546001600160a01b0316620004c85760405163daa2f31f60e01b815260040160405180910390fd5b6006546001600160a01b0316620004f257604051632a38eca960e01b815260040160405180910390fd5b6006620005066060840160408501620023ac565b60ff1610806200052a57506012620005256060840160408501620023ac565b60ff16115b15620005495760405163686d360760e01b815260040160405180910390fd5b5f805f8062000558866200174b565b93509350935093505f60035f81546200057190620023ca565b919050819055905060405180610300016040528083815260200184815260200185815260200186815260200188806101e00190620005b09190620023ef565b825250602001620005c66102008a018a620023ef565b905081526020018861022001358152602001886102400135815260200188610260013581526020018861028001358152602001886102a001358152602001886102c001358152602001886102e0013581526020018861030001358152602001886103200135815260200130896040016020810190620006469190620023ac565b6200065560608c018c6200243f565b6200066460808e018e6200243f565b6040516024016200067b96959493929190620024ad565b60408051601f19818403018152918152602080830180516001600160e01b03166285fc1360e71b1790529183525130602482015291019060440160408051601f19818403018152919052602080820180516001600160e01b031663189acdbd60e31b17905290825201620006f86101608a016101408b016200231b565b6001600160a01b031681526020016200071a6101808a016101608b016200231b565b6001600160a01b031681526020016200073c6101a08a016101808b016200231b565b6001600160a01b031681526020016200075e6101c08a016101a08b016200231b565b6001600160a01b03168152602001620007806101e08a016101c08b016200231b565b6001600160a01b031681526020908101906200079f908a018a6200231b565b6001600160a01b03168152602001886020016020810190620007c29190620024fe565b151590525f8281526009602081815260409283902084518155908401516001820155918301516002830155606083015160038301556080830151600483015560a0830151600583015560c0830151600683015560e08301516007830155610100830151600883015561012083015190820155610140820151600a820155610160820151600b820155610180820151600c8201556101a0820151600d8201556101c0820151600e8201556101e0820151600f820190620008829082620025bc565b5061020082015160108201906200089a9082620025bc565b506102208201516011820180546001600160a01b03199081166001600160a01b03938416179091556102408401516012840180548316918416919091179055610260840151601384018054831691841691909117905561028084015160148401805483169184169190911790556102a08401516015840180549092169083161790556102c0830151601690920180546102e090940151929091166001600160a81b031990931692909217600160a01b911515919091021790556200095f8188620018ff565b6040518181527fc847abf55529a155d6d2f882c916fba247bea5ebd30a638bd2cd5699b5c177d99060200160405180910390a16006620009a360208901896200231b565b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620009df573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000a05919062002689565b60ff16101562000a285760405163668dd6cd60e11b815260040160405180910390fd5b60015f559695505050505050565b60025f540362000a5957604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b0316331462000a8957604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b03811662000ab157604051633efa09af60e01b815260040160405180910390fd5b600680546001600160a01b0319166001600160a01b039290921691909117905560015f55565b60025f540362000afa57604051633ee5aeb560e01b815260040160405180910390fd5b60025f819055546001600160a01b0316331462000b29576040516282b42960e81b815260040160405180910390fd5b62000b343362001ac5565b60015f55565b60025f540362000b5d57604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b0316331462000b8d57604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b03811662000bb557604051633efa09af60e01b815260040160405180910390fd5b600580546001600160a01b0319166001600160a01b039290921691909117905560015f55565b60025f540362000bfe57604051633ee5aeb560e01b815260040160405180910390fd5b60025f9081553381526007602052604090205460ff1662000c32576040516305dab3df60e21b815260040160405180910390fd5b5f818152600960205260409020601301546001600160a01b031662000c6a576040516310708d7360e01b815260040160405180910390fd5b5f818152600860205260409020600301546001600160a01b03161562000ca357604051633fd1a6b560e01b815260040160405180910390fd5b5f8062000cb08362001ae3565b915091505f8062000cc18562001c0f565b915091505f816201518060405162000cd990620022d5565b6001600160a01b0390921682526020820152604001604051809103905ff08015801562000d08573d5f803e3d5ffd5b505f87815260096020526040808220601601549051929350909130916001600160a01b03169062000d3990620022e3565b6001600160a01b03928316815291166020820152604001604051809103905ff08015801562000d6a573d5f803e3d5ffd5b505f8881526009602052604081206016015491925090600160a01b900460ff161562000dea575f88815260096020526040908190206013015490516001600160a01b039091169062000dbc90620022f1565b6001600160a01b039091168152602001604051809103905ff08015801562000de6573d5f803e3d5ffd5b5090505b604051806101200160405280876001600160a01b03168152602001886001600160a01b0316815260200160055f9054906101000a90046001600160a01b03166001600160a01b03168152602001856001600160a01b03168152602001866001600160a01b0316815260200160065f9054906101000a90046001600160a01b03166001600160a01b03168152602001836001600160a01b03168152602001826001600160a01b03168152602001846001600160a01b031681525060085f8a81526020019081526020015f205f820151815f015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506020820151816001015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506040820151816002015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506060820151816003015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506080820151816004015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a0820151816005015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c0820151816006015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060e0820151816007015f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550610100820151816008015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055509050505f600167ffffffffffffffff8111156200106057620010606200251f565b6040519080825280602002602001820160405280156200108a578160200160208202803683370190505b506040805160018082528183019092529192505f91906020808301908036833701905050905085825f81518110620010c657620010c6620026a7565b60200260200101906001600160a01b031690816001600160a01b03168152505085815f81518110620010fc57620010fc620026a7565b6001600160a01b0392831660209182029290920101526040516311ffb1d360e11b8152908916906323ff63a6906200113b908590859060040162002700565b5f604051808303815f87803b15801562001153575f80fd5b505af115801562001166573d5f803e3d5ffd5b505050505f60405180610200016040528060095f8e81526020019081526020015f2060060154815260200160095f8e81526020019081526020015f2060070154815260200160095f8e81526020019081526020015f2060080154815260200160095f8e81526020019081526020015f2060090154815260200160095f8e81526020019081526020015f20600a0154815260200160095f8e81526020019081526020015f20600b0154815260200160095f8e81526020019081526020015f20600c0154815260200160095f8e81526020019081526020015f20600d0154815260200160095f8e81526020019081526020015f20600e01548152602001856001600160a01b0316815260200160095f8e81526020019081526020015f206015015f9054906101000a90046001600160a01b03166001600160a01b03168152602001876001600160a01b031681526020018a6001600160a01b0316815260200160095f8e81526020019081526020015f206016015f9054906101000a90046001600160a01b03166001600160a01b0316815260200160095f8e81526020019081526020015f206013015f9054906101000a90046001600160a01b03166001600160a01b03168152602001866001600160a01b03168152509050866001600160a01b031663cb3dc357826040518263ffffffff1660e01b81526004016200136a919062002731565b5f604051808303815f87803b15801562001382575f80fd5b505af115801562001395573d5f803e3d5ffd5b50505050620013a58b8862001ca8565b620013b18b8862001dfe565b5f8b8152600960205260409081902060110154905163f2fde38b60e01b81526001600160a01b039182166004820152908a169063f2fde38b906024015f604051808303815f87803b15801562001405575f80fd5b505af115801562001418573d5f803e3d5ffd5b5050505f8c8152600960205260409081902060130154905163f2fde38b60e01b81526001600160a01b039182166004820152908916915063f2fde38b906024015f604051808303815f87803b15801562001470575f80fd5b505af115801562001483573d5f803e3d5ffd5b5050505f8c8152600960205260409081902060130154905163f2fde38b60e01b81526001600160a01b039182166004820152908716915063f2fde38b906024015f604051808303815f87803b158015620014db575f80fd5b505af1158015620014ee573d5f803e3d5ffd5b505050507f714892568bf1dfd927822710be2b993ecc9f4dae5f0c6bf9b119711a12d5fb158b6040516200152491815260200190565b60405180910390a1505060015f55505050505050505050565b60025f54036200156057604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146200159057604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b038116620015b857604051633efa09af60e01b815260040160405180910390fd5b6001600160a01b0381165f9081526007602052604090205460ff1615620015f2576040516379fd1e0560e11b815260040160405180910390fd5b6001600160a01b03165f908152600760205260408120805460ff191660019081179091559055565b60025f54036200163d57604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146200166d57604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b0381166200169557604051633efa09af60e01b815260040160405180910390fd5b6004546001600160a01b031615620016c0576040516373aa896760e01b815260040160405180910390fd5b600480546001600160a01b0319166001600160a01b039290921691909117905560015f55565b60025f54036200170957604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146200173957604051630b2db9b760e31b815260040160405180910390fd5b620017448162001f1f565b5060015f55565b5f80808080620017c96200179a6200176760c08901896200243f565b62001772916200280d565b6200178160e08a018a6200243f565b6200178c916200280d565b5f9182526020526040902090565b6200178c620017ae6101008a018a6200243f565b620017b9916200280d565b620017816101208b018b6200243f565b90505f62001820620017fd620017e360608a018a6200243f565b620017ee916200280d565b6200178160808b018b6200243f565b6200180f60608a0160408b01620023ac565b60ff165f9182526020526040902090565b90505f6200185962001846672ab839b434b33a1760c11b6200178160a08c018c6200243f565b5f8481526020869052604090206200178c565b90506200187d6a2a37b5b2b7283937bc3c9760a91b825f9182526020526040902090565b9650620018a66f2a37b5b2b7283937bc3ca0b236b4b71760811b885f9182526020526040902090565b9550620018ca6a2b30bab63a283937bc3c9760a91b885f9182526020526040902090565b9450620018f36f2b30bab63a283937bc3ca0b236b4b71760811b865f9182526020526040902090565b93505050509193509193565b5f5b620019116101e0830183620023ef565b9050811015620019df576200192b6101e0830183620023ef565b828181106200193e576200193e620026a7565b6200195692602060409092020190810191506200231b565b5f848152600a60209081526040808320858452909152902080546001600160a01b0319166001600160a01b03929092169190911790556200199c6101e0830183620023ef565b82818110620019af57620019af620026a7565b5f868152600b60209081526040808320878452825291829020919092029390930101359091555060010162001901565b505f5b620019f2610200830183620023ef565b905081101562001ac05762001a0c610200830183620023ef565b8281811062001a1f5762001a1f620026a7565b62001a3792602060409092020190810191506200231b565b5f848152600c60209081526040808320858452909152902080546001600160a01b0319166001600160a01b039290921691909117905562001a7d610200830183620023ef565b8281811062001a905762001a90620026a7565b5f868152600d602090815260408083208784528252918290209190920293909301013590915550600101620019e2565b505050565b600280546001600160a01b031916905562001ae08162001fae565b50565b5f818152600960205260408120600281015460038201546005546012840154600f9094018054869562001bb49594936001600160a01b039081169391169162001b2c9062002533565b80601f016020809104026020016040519081016040528092919081815260200182805462001b5a9062002533565b801562001ba95780601f1062001b7f5761010080835404028352916020019162001ba9565b820191905f5260205f20905b81548152906001019060200180831162001b8b57829003601f168201915b505050505062002027565b600554604080516001600160a01b03808516825280861660208301529092169082015291935091507fa8bb59c0ffcc9833d1ff47a631a1bcbc76b2da935566a08f663e6c8ad1b5ba84906060015b60405180910390a1915091565b5f81815260096020526040812080546001820154600654601484015460109094018054869562001c559594936001600160a01b039081169391169162001b2c9062002533565b600654604080516001600160a01b03808516825280861660208301529092169082015291935091507f26ad9f07a47e389150a15677a365d64f42af0000b792c182ada6a3b5ab193a0b9060600162001c02565b5f82815260096020526040812060040154908167ffffffffffffffff81111562001cd65762001cd66200251f565b60405190808252806020026020018201604052801562001d1c57816020015b604080518082019091525f808252602082015281526020019060019003908162001cf55790505b5090505f5b8281101562001d9a576040805180820182525f878152600a60209081528382208583528152838220546001600160a01b03168352888252600b815283822085835281529290205491810191909152825183908390811062001d865762001d86620026a7565b602090810291909101015260010162001d21565b506040516314a28d1160e11b81526001600160a01b038416906329451a229062001dc99084906004016200282c565b5f604051808303815f87803b15801562001de1575f80fd5b505af115801562001df4573d5f803e3d5ffd5b5050505050505050565b5f82815260096020526040812060050154908167ffffffffffffffff81111562001e2c5762001e2c6200251f565b60405190808252806020026020018201604052801562001e7257816020015b604080518082019091525f808252602082015281526020019060019003908162001e4b5790505b5090505f5b8281101562001ef0576040805180820182525f878152600c60209081528382208583528152838220546001600160a01b03168352888252600d815283822085835281529290205491810191909152825183908390811062001edc5762001edc620026a7565b602090810291909101015260010162001e77565b50604051631bca511360e01b81526001600160a01b03841690631bca51139062001dc99084906004016200282c565b6001600160a01b038116158062001f3e57506001600160a01b03811630145b1562001f5d5760405163e6c4247b60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b03838116918217909255600154604051919216907f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700905f90a350565b6001600160a01b03811662001fd65760405163156fee5160e31b815260040160405180910390fd5b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f805f806200203989898988620021c0565b915091505f826001600160a01b03163b11806200205f57505f816001600160a01b03163b115b156200207e57604051631f99271960e11b815260040160405180910390fd5b5f896040516200208e90620022ff565b8190604051809103905ff5905080158015620020ac573d5f803e3d5ffd5b509050826001600160a01b0316816001600160a01b031614620020e257604051633e89a13360e01b815260040160405180910390fd5b5f89898389604051620020f5906200230d565b6200210393929190620028a9565b8190604051809103905ff590508015801562002121573d5f803e3d5ffd5b509050826001600160a01b0316816001600160a01b0316146200215757604051631b0a7c4160e31b815260040160405180910390fd5b60405163f2fde38b60e01b81526001600160a01b03898116600483015283169063f2fde38b906024015f604051808303815f87803b15801562002198575f80fd5b505af1158015620021ab573d5f803e3d5ffd5b50959d949c50939a5050505050505050505050565b5f8060ff60f81b308760405180602001620021db90620022ff565b6020820181038252601f19601f82011660405250805190602001206040516020016200220b9493929190620028f7565b604051602081830303815290604052805190602001205f1c915060ff60f81b3086604051806020016200223e906200230d565b601f1982820381018352601f9091011660408190526200226790899088908a90602001620028a9565b60408051601f198184030181529082905262002287929160200162002930565b60405160208183030381529060405280519060200120604051602001620022b29493929190620028f7565b604051602081830303815290604052805190602001205f1c905094509492505050565b610851806200296383390190565b61149c80620031b483390190565b61038a806200465083390190565b61085a80620049da83390190565b610d88806200523483390190565b5f602082840312156200232c575f80fd5b81356001600160a01b038116811462002343575f80fd5b9392505050565b5f602082840312156200235b575f80fd5b813567ffffffffffffffff81111562002372575f80fd5b8201610340818503121562002343575f80fd5b5f6020828403121562002396575f80fd5b5035919050565b60ff8116811462001ae0575f80fd5b5f60208284031215620023bd575f80fd5b813562002343816200239d565b5f60018201620023e857634e487b7160e01b5f52601160045260245ffd5b5060010190565b5f808335601e1984360301811262002405575f80fd5b83018035915067ffffffffffffffff82111562002420575f80fd5b6020019150600681901b360382131562002438575f80fd5b9250929050565b5f808335601e1984360301811262002455575f80fd5b83018035915067ffffffffffffffff82111562002470575f80fd5b60200191503681900382131562002438575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b038716815260ff861660208201526080604082018190525f90620024dc908301868862002485565b8281036060840152620024f181858762002485565b9998505050505050505050565b5f602082840312156200250f575f80fd5b8135801515811462002343575f80fd5b634e487b7160e01b5f52604160045260245ffd5b600181811c908216806200254857607f821691505b6020821081036200256757634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111562001ac057805f5260205f20601f840160051c81016020851015620025945750805b601f840160051c820191505b81811015620025b5575f8155600101620025a0565b5050505050565b815167ffffffffffffffff811115620025d957620025d96200251f565b620025f181620025ea845462002533565b846200256d565b602080601f83116001811462002627575f84156200260f5750858301515b5f19600386901b1c1916600185901b17855562002681565b5f85815260208120601f198616915b82811015620026575788860151825594840194600190910190840162002636565b50858210156200267557878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b5f602082840312156200269a575f80fd5b815162002343816200239d565b634e487b7160e01b5f52603260045260245ffd5b5f815180845260208085019450602084015f5b83811015620026f55781516001600160a01b031687529582019590820190600101620026ce565b509495945050505050565b604081525f620027146040830185620026bb565b8281036020840152620027288185620026bb565b95945050505050565b5f61020082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151620027ab828501826001600160a01b03169052565b5050610140838101516001600160a01b039081169184019190915261016080850151821690840152610180808501518216908401526101a0808501518216908401526101c0808501518216908401526101e09384015116929091019190915290565b8035602083101562002826575f19602084900360031b1b165b92915050565b602080825282518282018190525f919060409081850190868401855b828110156200287857815180516001600160a01b0316855286015186850152928401929085019060010162002848565b5091979650505050505050565b5f5b83811015620028a157818101518382015260200162002887565b50505f910152565b5f60018060a01b038086168352808516602084015250606060408301528251806060840152620028e181608085016020870162002885565b601f01601f191691909101608001949350505050565b6001600160f81b031994909416845260609290921b6bffffffffffffffffffffffff191660018401526015830152603582015260550190565b5f83516200294381846020880162002885565b8351908301906200295981836020880162002885565b0194935050505056fe60c060405234801561000f575f80fd5b5060405161085138038061085183398101604081905261002e91610067565b61012c8110156100515760405163dd09ae8560e01b815260040160405180910390fd5b6001600160a01b0390911660805260a05261009e565b5f8060408385031215610078575f80fd5b82516001600160a01b038116811461008e575f80fd5b6020939093015192949293505050565b60805160a0516107716100e05f395f818160d201526102bb01525f8181608e0152818161039c01528181610557015281816105da015261066501526107715ff3fe608060405234801561000f575f80fd5b5060043610610085575f3560e01c80637c10dea6116100585780637c10dea61461018e578063af6f8c1b146101da578063b535b5c3146101ed578063c4d252f51461021e575f80fd5b80632b3ed84e146100895780634623c81e146100cd578063548eac04146101025780637a02dc0614610117575b5f80fd5b6100b07f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6100f47f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016100c4565b6101156101103660046106d2565b610231565b005b61016a6101253660046106d2565b604080518082019091525f8082526020820152505f90815260016020818152604092839020835180850190945280548452909101546001600160a01b03169082015290565b60408051825181526020928301516001600160a01b031692810192909252016100c4565b6101bd61019c3660046106d2565b600160208190525f918252604090912080549101546001600160a01b031682565b604080519283526001600160a01b039091166020830152016100c4565b6101156101e83660046106d2565b61036b565b61020e6101fb3660046106d2565b5f90815260016020526040902054151590565b60405190151581526020016100c4565b61011561022c3660046106d2565b61049b565b60025f5403610253576040516306fda65d60e31b815260040160405180910390fd5b60025f55806102755760405163e0f8778160e01b815260040160405180910390fd5b5f81815260016020819052604090912001546001600160a01b0316156102ae57604051632da5055760e21b815260040160405180910390fd5b60405180604001604052807f0000000000000000000000000000000000000000000000000000000000000000426102e591906106e9565b81523360209182018190525f84815260018084526040918290208551815594840151940180546001600160a01b0319166001600160a01b03909516949094179093558251848152918201527f6ef595d41bb19bf4009067ebfca1e965c782641ffd735166641d1832d9955ca591015b60405180910390a1610364610554565b5060015f55565b60025f540361038d576040516306fda65d60e31b815260040160405180910390fd5b60025f55336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103d9576040516282b42960e81b815260040160405180910390fd5b5f81815260016020819052604090912054101561040957604051637d9b58e760e11b815260040160405180910390fd5b5f81815260016020526040902054421015610437576040516331524f6360e21b815260040160405180910390fd5b5f8181526001602081815260408084209384559290910180546001600160a01b0319169055815183815233918101919091527fc0c97b5bfc2b0d319a6dadd3efddd19273d76957d4cf2c1f72697f8b589dea05910160405180910390a15060015f55565b60025f54036104bd576040516306fda65d60e31b815260040160405180910390fd5b60025f90815581815260016020819052604090912001546001600160a01b03166104fa57604051637d9b58e760e11b815260040160405180910390fd5b5f8181526001602081815260408084209384559290910180546001600160a01b0319169055815183815233918101919091527f37a82c88859b7ebdc11c1ada9b2f845df41bcf0b0f60931aad69c56bf38440149101610354565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105b1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105d5919061070e565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663127effb26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610634573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610658919061070e565b9050336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480159061069c5750336001600160a01b03831614155b80156106b15750336001600160a01b03821614155b156106ce576040516282b42960e81b815260040160405180910390fd5b5050565b5f602082840312156106e2575f80fd5b5035919050565b8082018082111561070857634e487b7160e01b5f52601160045260245ffd5b92915050565b5f6020828403121561071e575f80fd5b81516001600160a01b0381168114610734575f80fd5b939250505056fea264697066735822122082406706a29eebee4051b97dfa4927d596b49e6ce9dd7a3826c285f790a59d4364736f6c6343000818003360c060405234801562000010575f80fd5b506040516200149c3803806200149c833981016040819052620000339162000135565b6001600160a01b0382166200005b5760405163156fee5160e31b815260040160405180910390fd5b6001600160a01b038116620000835760405163e6c4247b60e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0384811691909117909155811660808190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015620000e4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200010a91906200016b565b60ff1660a05250620001949050565b80516001600160a01b038116811462000130575f80fd5b919050565b5f806040838503121562000147575f80fd5b620001528362000119565b9150620001626020840162000119565b90509250929050565b5f602082840312156200017c575f80fd5b815160ff811681146200018d575f80fd5b9392505050565b60805160a0516112a8620001f45f395f818160d4015281816109b4015281816109e801528181610a8801528181610ab501528181610af30152610b5601525f818161025b0152818161037b015281816105310152610bf701526112a85ff3fe608060405234801561000f575f80fd5b50600436106100cb575f3560e01c80638da5cb5b11610088578063c8d2df5611610063578063c8d2df5614610230578063d861811514610243578063ded4a6fe14610256578063f2fde38b1461027d575f80fd5b80638da5cb5b146101f7578063a22484d914610208578063ad0780211461021d575f80fd5b8063304cef9d146100cf5780633af32abf1461010d57806348ad6f5c1461014a578063544821731461015f57806356f1b546146101a2578063803bc5e2146101ca575b5f80fd5b6100f67f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020015b60405180910390f35b61013a61011b366004610ecb565b6001600160a01b039081165f9081526003602052604090205416151590565b6040519015158152602001610104565b61015d610158366004610ee4565b610290565b005b61018a61016d366004610ecb565b6001600160a01b039081165f908152600360205260409020541690565b6040516001600160a01b039091168152602001610104565b6101b56101b0366004610f0e565b610301565b60408051928352602083019190915201610104565b6101e96101d8366004610ecb565b60046020525f908152604090205481565b604051908152602001610104565b6001546001600160a01b031661018a565b6102106103fc565b6040516101049190610f5f565b6101e961022b366004610fab565b61045c565b6101e961023e366004610fc2565b61046d565b61015d610251366004610fea565b61047f565b61018a7f000000000000000000000000000000000000000000000000000000000000000081565b61015d61028b366004610ecb565b610797565b60025f54036102b257604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146102e157604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b03165f9081526004602052604081209190915560019055565b5f80600184101561031657505f9050806103f2565b5f876001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610353573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103779190611023565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b0316146103c1576103bc87866107f8565b6103c3565b845b91505f6103d08786610bca565b9050600182106103eb576103e68383835f610d35565b6103ed565b825b935050505b9550959350505050565b6060600280548060200260200160405190810160405280929190818152602001828054801561045257602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610434575b5050505050905090565b5f6104673383610bca565b92915050565b5f61047883836107f8565b9392505050565b60025f54036104a157604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146104d057604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b03821615806104ed57506001600160a01b038316155b1561050b57604051633efa09af60e01b815260040160405180910390fd5b600254601e101561052f5760405163be8f94e960e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031603610581576040516319fc848960e21b815260040160405180910390fd5b6001600160a01b038381165f9081526003602052604090206001015416156105bc57604051635405c10760e11b815260040160405180910390fd5b600280546001810182555f9182527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0180546001600160a01b0319166001600160a01b0386169081179091556040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015610641573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610665919061103a565b905060068160ff16101561068c57604051630da74dab60e01b815260040160405180910390fd5b5f836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106c9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106ed919061103a565b604080516080810182526001600160a01b039687168152968616602080890182815260ff9485168a850190815296851660608b019081525f938452600383528484209a518b54908b166001600160a01b0319909116178b55905160019a8b018054985192518716600160a81b0260ff60a81b1993909716600160a01b026001600160a81b031990991691909a16179690961795909516929092179095556004909252509182205555565b60025f54036107b957604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146107e857604051630b2db9b760e31b815260040160405180910390fd5b6107f181610d90565b5060015f55565b6001600160a01b038083165f9081526003602052604080822080546001909101548251633fabe5a360e21b815292519394919091169260ff600160a81b8304811693600160a01b90930416918591829182918291889163feaf968c9160048082019260a0929091908290030181865afa158015610877573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061089b9190611073565b94509450509350935060018312156108c55760405162fc7cad60e51b815260040160405180910390fd5b8369ffffffffffffffffffff168169ffffffffffffffffffff1610156108fe57604051630cd5fa0760e11b815260040160405180910390fd5b600182101561091f5760405162ace4c560e51b815260040160405180910390fd5b42821115610940576040516352c4db3960e11b815260040160405180910390fd5b6001600160a01b038a165f9081526004602052604090205461096283426110d3565b1115610981576040516329fc802760e11b815260040160405180910390fd5b5f8660ff168660ff16116109965760016109ab565b6109a087876110e6565b6109ab90600a6111df565b90505f8660ff167f000000000000000000000000000000000000000000000000000000000000000060ff16116109e2576001610a17565b610a0c877f00000000000000000000000000000000000000000000000000000000000000006110e6565b610a1790600a6111df565b90505f610a24838d6111ed565b90505f610a328960126110e6565b610a3d90600a6111df565b90505f8782610a4d8c600a6111df565b610a5791906111ed565b610a619190611218565b90505f8285610a7086856111ed565b610a7a91906111ed565b610a849190611218565b90507f000000000000000000000000000000000000000000000000000000000000000060ff168c60ff1603610b54577f000000000000000000000000000000000000000000000000000000000000000060ff16600603610aef57610ae88682611218565b9050610b54565b60117f000000000000000000000000000000000000000000000000000000000000000060ff161115610b5457889150670de0b6b3a76400008386610b3387866111ed565b610b3d91906111ed565b610b479190611218565b610b519190611218565b90505b7f000000000000000000000000000000000000000000000000000000000000000060ff16600603610bb7578b60ff16601203610b9e57610b976298968082611218565b9050610bb7565b8b60ff16600803610bb757610bb4606482611218565b90505b9f9e505050505050505050505050505050565b6002546040516370a0823160e01b81526001600160a01b0384811660048301525f928392839283929183917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610c3c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c609190611023565b610c6a9088611237565b90505f5b82811015610d295760028181548110610c8957610c8961124a565b5f918252602090912001546040516370a0823160e01b81526001600160a01b038b81166004830152909116965086906370a0823190602401602060405180830381865afa158015610cdc573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d009190611023565b94508415610d2157610d1286866107f8565b9350610d1e8483611237565b91505b600101610c6e565b50979650505050505050565b5f80610d42868686610e08565b90506001836002811115610d5857610d5861125e565b148015610d7457505f8480610d6f57610d6f611204565b868809115b15610d8757610d84600182611237565b90505b95945050505050565b6001600160a01b038116610db75760405163156fee5160e31b815260040160405180910390fd5b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f80805f19858709858702925082811083820303915050805f03610e3f57838281610e3557610e35611204565b0492505050610478565b808411610e4a575f80fd5b5f84868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203025f889003889004909101858311909403939093029303949094049190911702949350505050565b80356001600160a01b0381168114610ec6575f80fd5b919050565b5f60208284031215610edb575f80fd5b61047882610eb0565b5f8060408385031215610ef5575f80fd5b82359150610f0560208401610eb0565b90509250929050565b5f805f805f60a08688031215610f22575f80fd5b610f2b86610eb0565b9450610f3960208701610eb0565b9350610f4760408701610eb0565b94979396509394606081013594506080013592915050565b602080825282518282018190525f9190848201906040850190845b81811015610f9f5783516001600160a01b031683529284019291840191600101610f7a565b50909695505050505050565b5f60208284031215610fbb575f80fd5b5035919050565b5f8060408385031215610fd3575f80fd5b610fdc83610eb0565b946020939093013593505050565b5f805f60608486031215610ffc575f80fd5b61100584610eb0565b925061101360208501610eb0565b9150604084013590509250925092565b5f60208284031215611033575f80fd5b5051919050565b5f6020828403121561104a575f80fd5b815160ff81168114610478575f80fd5b805169ffffffffffffffffffff81168114610ec6575f80fd5b5f805f805f60a08688031215611087575f80fd5b6110908661105a565b94506020860151935060408601519250606086015191506110b36080870161105a565b90509295509295909350565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610467576104676110bf565b60ff8281168282160390811115610467576104676110bf565b600181815b8085111561113957815f190482111561111f5761111f6110bf565b8085161561112c57918102915b93841c9390800290611104565b509250929050565b5f8261114f57506001610467565b8161115b57505f610467565b8160018114611171576002811461117b57611197565b6001915050610467565b60ff84111561118c5761118c6110bf565b50506001821b610467565b5060208310610133831016604e8410600b84101617156111ba575081810a610467565b6111c483836110ff565b805f19048211156111d7576111d76110bf565b029392505050565b5f61047860ff841683611141565b8082028115828204841417610467576104676110bf565b634e487b7160e01b5f52601260045260245ffd5b5f8261123257634e487b7160e01b5f52601260045260245ffd5b500490565b80820180821115610467576104676110bf565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52602160045260245ffdfea26469706673582212201d12ab731a2b5553cbf1c71b1477503e9c5fddd55972d8232d310eb3be4d5ae364736f6c63430008180033608060405234801561000f575f80fd5b5060405161038a38038061038a83398101604081905261002e91610053565b600180546001600160a01b0319166001600160a01b0392909216919091179055610080565b5f60208284031215610063575f80fd5b81516001600160a01b0381168114610079575f80fd5b9392505050565b6102fd8061008d5f395ff3fe608060405234801561000f575f80fd5b5060043610610055575f3560e01c80633af32abf146100595780633ca40a24146100995780638da5cb5b146100ae5780639d74164f146100c9578063f2fde38b146100dc575b5f80fd5b61008461006736600461029a565b6001600160a01b03165f9081526002602052604090205460ff1690565b60405190151581526020015b60405180910390f35b6100ac6100a736600461029a565b6100ef565b005b6001546040516001600160a01b039091168152602001610090565b6100ac6100d736600461029a565b61013a565b6100ac6100ea36600461029a565b6101c1565b6001546001600160a01b0316331461011a57604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b03165f908152600260205260409020805460ff19169055565b6001546001600160a01b0316331461016557604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b0381165f9081526002602052604090205460ff161561019e5760405163080fc0bd60e11b815260040160405180910390fd5b6001600160a01b03165f908152600260205260409020805460ff19166001179055565b60025f54036101e357604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b0316331461021257604051630b2db9b760e31b815260040160405180910390fd5b61021b81610222565b5060015f55565b6001600160a01b0381166102495760405163156fee5160e31b815260040160405180910390fd5b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f602082840312156102aa575f80fd5b81356001600160a01b03811681146102c0575f80fd5b939250505056fea26469706673582212202747930dd2f2cb02d243987196f2f0e030ca62e9bc02aba887b50e19dc5500d564736f6c63430008180033608060405234801561000f575f80fd5b50600180546001600160a01b0319163317905561082b8061002f5f395ff3fe608060405260043610610084575f3560e01c80639623609d116100575780639623609d1461011557806399a88ec414610128578063e30c397814610147578063f2fde38b14610164578063f3b7dead14610183575f80fd5b8063204e1c7a1461008857806379ba5097146100c35780637eff275e146100d95780638da5cb5b146100f8575b5f80fd5b348015610093575f80fd5b506100a76100a2366004610642565b6101a2565b6040516001600160a01b03909116815260200160405180910390f35b3480156100ce575f80fd5b506100d7610242565b005b3480156100e4575f80fd5b506100d76100f3366004610664565b6102a1565b348015610103575f80fd5b506001546001600160a01b03166100a7565b6100d76101233660046106af565b610351565b348015610133575f80fd5b506100d7610142366004610664565b610409565b348015610152575f80fd5b506002546001600160a01b03166100a7565b34801561016f575f80fd5b506100d761017e366004610642565b610488565b34801561018e575f80fd5b506100a761019d366004610642565b6104e9565b5f805f836001600160a01b03166040516101c690635c60da1b60e01b815260040190565b5f60405180830381855afa9150503d805f81146101fe576040519150601f19603f3d011682016040523d82523d5f602084013e610203565b606091505b509150915081610226576040516385be45b560e01b815260040160405180910390fd5b8080602001905181019061023a919061077e565b949350505050565b60025f540361026457604051633ee5aeb560e01b815260040160405180910390fd5b60025f819055546001600160a01b03163314610292576040516282b42960e81b815260040160405180910390fd5b61029b3361050d565b60015f55565b60025f54036102c357604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146102f257604051630b2db9b760e31b815260040160405180910390fd5b6040516308f2839760e41b81526001600160a01b038281166004830152831690638f283970906024015b5f604051808303815f87803b158015610333575f80fd5b505af1158015610345573d5f803e3d5ffd5b505060015f5550505050565b60025f540361037357604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146103a257604051630b2db9b760e31b815260040160405180910390fd5b60405163278f794360e11b81526001600160a01b03841690634f1ef2869034906103d29086908690600401610799565b5f604051808303818588803b1580156103e9575f80fd5b505af11580156103fb573d5f803e3d5ffd5b505060015f55505050505050565b60025f540361042b57604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b0316331461045a57604051630b2db9b760e31b815260040160405180910390fd5b604051631b2ce7f360e11b81526001600160a01b038281166004830152831690633659cfe69060240161031c565b60025f54036104aa57604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146104d957604051630b2db9b760e31b815260040160405180910390fd5b6104e281610529565b5060015f55565b5f805f836001600160a01b03166040516101c6906303e1469160e61b815260040190565b600280546001600160a01b0319169055610526816105b6565b50565b6001600160a01b038116158061054757506001600160a01b03811630145b156105655760405163e6c4247b60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b03838116918217909255600154604051919216907f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700905f90a350565b6001600160a01b0381166105dd5760405163156fee5160e31b815260040160405180910390fd5b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b0381168114610526575f80fd5b5f60208284031215610652575f80fd5b813561065d8161062e565b9392505050565b5f8060408385031215610675575f80fd5b82356106808161062e565b915060208301356106908161062e565b809150509250929050565b634e487b7160e01b5f52604160045260245ffd5b5f805f606084860312156106c1575f80fd5b83356106cc8161062e565b925060208401356106dc8161062e565b9150604084013567ffffffffffffffff808211156106f8575f80fd5b818601915086601f83011261070b575f80fd5b81358181111561071d5761071d61069b565b604051601f8201601f19908116603f011681019083821181831017156107455761074561069b565b8160405282815289602084870101111561075d575f80fd5b826020860160208301375f6020848301015280955050505050509250925092565b5f6020828403121561078e575f80fd5b815161065d8161062e565b60018060a01b03831681525f60206040602084015283518060408501525f5b818110156107d4578581018301518582016060015282016107b8565b505f606082860101526060601f19601f83011685010192505050939250505056fea264697066735822122066cfa399ff14a6fa5676bf6889fb6e3b33c287da27c77fba72388f5f5b0ffa8f64736f6c63430008180033608060405260405162000d8838038062000d88833981016040819052620000269162000415565b82816200003582825f6200004c565b50620000439050826200007d565b50505062000540565b6200005783620000ee565b5f82511180620000645750805b1562000078576200007683836200012f565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f620000be5f8051602062000d41833981519152546001600160a01b031690565b604080516001600160a01b03928316815291841660208301520160405180910390a1620000eb816200015e565b50565b620000f981620001fb565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b606062000157838360405180606001604052806027815260200162000d616027913962000292565b9392505050565b6001600160a01b038116620001c95760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b805f8051602062000d418339815191525b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b6200026a5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401620001c0565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc620001da565b60605f80856001600160a01b031685604051620002b09190620004ef565b5f60405180830381855af49150503d805f8114620002ea576040519150601f19603f3d011682016040523d82523d5f602084013e620002ef565b606091505b50909250905062000303868383876200030d565b9695505050505050565b60608315620003805782515f0362000378576001600160a01b0385163b620003785760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620001c0565b50816200038c565b6200038c838362000394565b949350505050565b815115620003a55781518083602001fd5b8060405162461bcd60e51b8152600401620001c091906200050c565b80516001600160a01b0381168114620003d8575f80fd5b919050565b634e487b7160e01b5f52604160045260245ffd5b5f5b838110156200040d578181015183820152602001620003f3565b50505f910152565b5f805f6060848603121562000428575f80fd5b6200043384620003c1565b92506200044360208501620003c1565b60408501519092506001600160401b038082111562000460575f80fd5b818601915086601f83011262000474575f80fd5b815181811115620004895762000489620003dd565b604051601f8201601f19908116603f01168101908382118183101715620004b457620004b4620003dd565b81604052828152896020848701011115620004cd575f80fd5b620004e0836020830160208801620003f1565b80955050505050509250925092565b5f825162000502818460208701620003f1565b9190910192915050565b602081525f82518060208401526200052c816040850160208701620003f1565b601f01601f19169190910160400192915050565b6107f3806200054e5f395ff3fe60806040526004361061004d575f3560e01c80633659cfe6146100645780634f1ef286146100775780635c60da1b1461008a5780638f283970146100ae578063f851a440146100c15761005c565b3661005c5761005a6100c9565b005b61005a6100c9565b61005a610072366004610692565b6100e3565b61005a6100853660046106ab565b610126565b61009261018c565b6040516001600160a01b03909116815260200160405180910390f35b61005a6100bc366004610692565b6101c4565b6100926101ec565b6100d1610214565b6100e16100dc6102a9565b6102b2565b565b6100eb6102d0565b6001600160a01b0316330361011e57610102610302565b61011b8160405180602001604052805f8152505f61030c565b50565b61011b6100c9565b61012e6102d0565b6001600160a01b031633036101845761017f8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506001925061030c915050565b505050565b61017f6100c9565b5f6101956102d0565b6001600160a01b031633036101b9576101ac610302565b6101b46102a9565b905090565b6101c16100c9565b90565b6101cc6102d0565b6001600160a01b0316330361011e576101e3610302565b61011b81610336565b5f6101f56102d0565b6001600160a01b031633036101b95761020c610302565b6101b46102d0565b61021c6102d0565b6001600160a01b031633036100e15760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b5f6101b461038a565b365f80375f80365f845af43d5f803e8080156102cc573d5ff35b3d5ffd5b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b34156100e1575f80fd5b610315836103b1565b5f825111806103215750805b1561017f5761033083836103f0565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f61035f6102d0565b604080516001600160a01b03928316815291841660208301520160405180910390a161011b8161041c565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6102f3565b6103ba816104c5565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b6060610415838360405180606001604052806027815260200161079760279139610559565b9392505050565b6001600160a01b0381166104815760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102a0565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b6105325760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102a0565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104a4565b60605f80856001600160a01b0316856040516105759190610749565b5f60405180830381855af49150503d805f81146105ad576040519150601f19603f3d011682016040523d82523d5f602084013e6105b2565b606091505b50915091506105c3868383876105cd565b9695505050505050565b6060831561063b5782515f03610634576001600160a01b0385163b6106345760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102a0565b5081610645565b610645838361064d565b949350505050565b81511561065d5781518083602001fd5b8060405162461bcd60e51b81526004016102a09190610764565b80356001600160a01b038116811461068d575f80fd5b919050565b5f602082840312156106a2575f80fd5b61041582610677565b5f805f604084860312156106bd575f80fd5b6106c684610677565b9250602084013567ffffffffffffffff808211156106e2575f80fd5b818601915086601f8301126106f5575f80fd5b813581811115610703575f80fd5b876020828501011115610714575f80fd5b6020830194508093505050509250925092565b5f5b83811015610741578181015183820152602001610729565b50505f910152565b5f825161075a818460208701610727565b9190910192915050565b602081525f8251806020840152610782816040850160208701610727565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212200574afa0af7d8edebf3ec31d8bf7147040f26698a800538942decacb0b574c7a64736f6c63430008180033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122014ba4a2fae7d0111bac55f469a6089f1db93f2f00a8b5010ff0260101e66edb764736f6c63430008180033000000000000000000000000c573100a879f480c9ae5290f865a1e354f4ba67f
Deployed Bytecode
0x608060405234801562000010575f80fd5b506004361062000110575f3560e01c80638b1d7b27116200009f578063d83722f0116200006b578063d83722f01462000315578063dbbb4155146200032c578063e30c39781462000343578063f2fde38b1462000355575f80fd5b80638b1d7b2714620002065780638da5cb5b146200021a578063a4e6a7b4146200022c578063a5e3875114620002fe575f80fd5b8063730791f811620000df578063730791f8146200019b5780637680711114620001d157806379ba509714620001e557806388282e2a14620001ef575f80fd5b80631f338cbf14620001145780632e4934dd14620001455780632fa435f3146200015e57806353e78b6b1462000184575b5f80fd5b60055462000128906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6200015c620001563660046200231b565b6200036c565b005b620001756200016f3660046200234a565b6200041c565b6040519081526020016200013c565b6200015c620001953660046200231b565b62000a36565b620001c0620001ac3660046200231b565b60076020525f908152604090205460ff1681565b60405190151581526020016200013c565b60045462000128906001600160a01b031681565b6200015c62000ad7565b6200015c620002003660046200231b565b62000b3a565b60065462000128906001600160a01b031681565b6001546001600160a01b031662000128565b620002a36200023d36600462002385565b600860208190525f91825260409091208054600182015460028301546003840154600485015460058601546006870154600788015497909801546001600160a01b0396871698958716979487169693841695928416949184169392831692918216911689565b604080516001600160a01b039a8b168152988a1660208a01529689169688019690965293871660608701529186166080860152851660a0850152841660c0840152831660e0830152909116610100820152610120016200013c565b6200015c6200030f36600462002385565b62000bdb565b6200015c620003263660046200231b565b6200153d565b6200015c6200033d3660046200231b565b6200161a565b6002546001600160a01b031662000128565b6200015c620003663660046200231b565b620016e6565b60025f54036200038f57604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b03163314620003bf57604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b0381165f9081526007602052604090205460ff16620003f8576040516305dab3df60e21b815260040160405180910390fd5b6001600160a01b03165f908152600760205260408120805460ff1916905560019055565b5f60025f54036200044057604051633ee5aeb560e01b815260040160405180910390fd5b60025f9081553381526007602052604090205460ff1662000474576040516305dab3df60e21b815260040160405180910390fd5b6004546001600160a01b03166200049e576040516311f68ef960e21b815260040160405180910390fd5b6005546001600160a01b0316620004c85760405163daa2f31f60e01b815260040160405180910390fd5b6006546001600160a01b0316620004f257604051632a38eca960e01b815260040160405180910390fd5b6006620005066060840160408501620023ac565b60ff1610806200052a57506012620005256060840160408501620023ac565b60ff16115b15620005495760405163686d360760e01b815260040160405180910390fd5b5f805f8062000558866200174b565b93509350935093505f60035f81546200057190620023ca565b919050819055905060405180610300016040528083815260200184815260200185815260200186815260200188806101e00190620005b09190620023ef565b825250602001620005c66102008a018a620023ef565b905081526020018861022001358152602001886102400135815260200188610260013581526020018861028001358152602001886102a001358152602001886102c001358152602001886102e0013581526020018861030001358152602001886103200135815260200130896040016020810190620006469190620023ac565b6200065560608c018c6200243f565b6200066460808e018e6200243f565b6040516024016200067b96959493929190620024ad565b60408051601f19818403018152918152602080830180516001600160e01b03166285fc1360e71b1790529183525130602482015291019060440160408051601f19818403018152919052602080820180516001600160e01b031663189acdbd60e31b17905290825201620006f86101608a016101408b016200231b565b6001600160a01b031681526020016200071a6101808a016101608b016200231b565b6001600160a01b031681526020016200073c6101a08a016101808b016200231b565b6001600160a01b031681526020016200075e6101c08a016101a08b016200231b565b6001600160a01b03168152602001620007806101e08a016101c08b016200231b565b6001600160a01b031681526020908101906200079f908a018a6200231b565b6001600160a01b03168152602001886020016020810190620007c29190620024fe565b151590525f8281526009602081815260409283902084518155908401516001820155918301516002830155606083015160038301556080830151600483015560a0830151600583015560c0830151600683015560e08301516007830155610100830151600883015561012083015190820155610140820151600a820155610160820151600b820155610180820151600c8201556101a0820151600d8201556101c0820151600e8201556101e0820151600f820190620008829082620025bc565b5061020082015160108201906200089a9082620025bc565b506102208201516011820180546001600160a01b03199081166001600160a01b03938416179091556102408401516012840180548316918416919091179055610260840151601384018054831691841691909117905561028084015160148401805483169184169190911790556102a08401516015840180549092169083161790556102c0830151601690920180546102e090940151929091166001600160a81b031990931692909217600160a01b911515919091021790556200095f8188620018ff565b6040518181527fc847abf55529a155d6d2f882c916fba247bea5ebd30a638bd2cd5699b5c177d99060200160405180910390a16006620009a360208901896200231b565b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620009df573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000a05919062002689565b60ff16101562000a285760405163668dd6cd60e11b815260040160405180910390fd5b60015f559695505050505050565b60025f540362000a5957604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b0316331462000a8957604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b03811662000ab157604051633efa09af60e01b815260040160405180910390fd5b600680546001600160a01b0319166001600160a01b039290921691909117905560015f55565b60025f540362000afa57604051633ee5aeb560e01b815260040160405180910390fd5b60025f819055546001600160a01b0316331462000b29576040516282b42960e81b815260040160405180910390fd5b62000b343362001ac5565b60015f55565b60025f540362000b5d57604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b0316331462000b8d57604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b03811662000bb557604051633efa09af60e01b815260040160405180910390fd5b600580546001600160a01b0319166001600160a01b039290921691909117905560015f55565b60025f540362000bfe57604051633ee5aeb560e01b815260040160405180910390fd5b60025f9081553381526007602052604090205460ff1662000c32576040516305dab3df60e21b815260040160405180910390fd5b5f818152600960205260409020601301546001600160a01b031662000c6a576040516310708d7360e01b815260040160405180910390fd5b5f818152600860205260409020600301546001600160a01b03161562000ca357604051633fd1a6b560e01b815260040160405180910390fd5b5f8062000cb08362001ae3565b915091505f8062000cc18562001c0f565b915091505f816201518060405162000cd990620022d5565b6001600160a01b0390921682526020820152604001604051809103905ff08015801562000d08573d5f803e3d5ffd5b505f87815260096020526040808220601601549051929350909130916001600160a01b03169062000d3990620022e3565b6001600160a01b03928316815291166020820152604001604051809103905ff08015801562000d6a573d5f803e3d5ffd5b505f8881526009602052604081206016015491925090600160a01b900460ff161562000dea575f88815260096020526040908190206013015490516001600160a01b039091169062000dbc90620022f1565b6001600160a01b039091168152602001604051809103905ff08015801562000de6573d5f803e3d5ffd5b5090505b604051806101200160405280876001600160a01b03168152602001886001600160a01b0316815260200160055f9054906101000a90046001600160a01b03166001600160a01b03168152602001856001600160a01b03168152602001866001600160a01b0316815260200160065f9054906101000a90046001600160a01b03166001600160a01b03168152602001836001600160a01b03168152602001826001600160a01b03168152602001846001600160a01b031681525060085f8a81526020019081526020015f205f820151815f015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506020820151816001015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506040820151816002015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506060820151816003015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506080820151816004015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a0820151816005015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c0820151816006015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060e0820151816007015f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550610100820151816008015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055509050505f600167ffffffffffffffff8111156200106057620010606200251f565b6040519080825280602002602001820160405280156200108a578160200160208202803683370190505b506040805160018082528183019092529192505f91906020808301908036833701905050905085825f81518110620010c657620010c6620026a7565b60200260200101906001600160a01b031690816001600160a01b03168152505085815f81518110620010fc57620010fc620026a7565b6001600160a01b0392831660209182029290920101526040516311ffb1d360e11b8152908916906323ff63a6906200113b908590859060040162002700565b5f604051808303815f87803b15801562001153575f80fd5b505af115801562001166573d5f803e3d5ffd5b505050505f60405180610200016040528060095f8e81526020019081526020015f2060060154815260200160095f8e81526020019081526020015f2060070154815260200160095f8e81526020019081526020015f2060080154815260200160095f8e81526020019081526020015f2060090154815260200160095f8e81526020019081526020015f20600a0154815260200160095f8e81526020019081526020015f20600b0154815260200160095f8e81526020019081526020015f20600c0154815260200160095f8e81526020019081526020015f20600d0154815260200160095f8e81526020019081526020015f20600e01548152602001856001600160a01b0316815260200160095f8e81526020019081526020015f206015015f9054906101000a90046001600160a01b03166001600160a01b03168152602001876001600160a01b031681526020018a6001600160a01b0316815260200160095f8e81526020019081526020015f206016015f9054906101000a90046001600160a01b03166001600160a01b0316815260200160095f8e81526020019081526020015f206013015f9054906101000a90046001600160a01b03166001600160a01b03168152602001866001600160a01b03168152509050866001600160a01b031663cb3dc357826040518263ffffffff1660e01b81526004016200136a919062002731565b5f604051808303815f87803b15801562001382575f80fd5b505af115801562001395573d5f803e3d5ffd5b50505050620013a58b8862001ca8565b620013b18b8862001dfe565b5f8b8152600960205260409081902060110154905163f2fde38b60e01b81526001600160a01b039182166004820152908a169063f2fde38b906024015f604051808303815f87803b15801562001405575f80fd5b505af115801562001418573d5f803e3d5ffd5b5050505f8c8152600960205260409081902060130154905163f2fde38b60e01b81526001600160a01b039182166004820152908916915063f2fde38b906024015f604051808303815f87803b15801562001470575f80fd5b505af115801562001483573d5f803e3d5ffd5b5050505f8c8152600960205260409081902060130154905163f2fde38b60e01b81526001600160a01b039182166004820152908716915063f2fde38b906024015f604051808303815f87803b158015620014db575f80fd5b505af1158015620014ee573d5f803e3d5ffd5b505050507f714892568bf1dfd927822710be2b993ecc9f4dae5f0c6bf9b119711a12d5fb158b6040516200152491815260200190565b60405180910390a1505060015f55505050505050505050565b60025f54036200156057604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146200159057604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b038116620015b857604051633efa09af60e01b815260040160405180910390fd5b6001600160a01b0381165f9081526007602052604090205460ff1615620015f2576040516379fd1e0560e11b815260040160405180910390fd5b6001600160a01b03165f908152600760205260408120805460ff191660019081179091559055565b60025f54036200163d57604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146200166d57604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b0381166200169557604051633efa09af60e01b815260040160405180910390fd5b6004546001600160a01b031615620016c0576040516373aa896760e01b815260040160405180910390fd5b600480546001600160a01b0319166001600160a01b039290921691909117905560015f55565b60025f54036200170957604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146200173957604051630b2db9b760e31b815260040160405180910390fd5b620017448162001f1f565b5060015f55565b5f80808080620017c96200179a6200176760c08901896200243f565b62001772916200280d565b6200178160e08a018a6200243f565b6200178c916200280d565b5f9182526020526040902090565b6200178c620017ae6101008a018a6200243f565b620017b9916200280d565b620017816101208b018b6200243f565b90505f62001820620017fd620017e360608a018a6200243f565b620017ee916200280d565b6200178160808b018b6200243f565b6200180f60608a0160408b01620023ac565b60ff165f9182526020526040902090565b90505f6200185962001846672ab839b434b33a1760c11b6200178160a08c018c6200243f565b5f8481526020869052604090206200178c565b90506200187d6a2a37b5b2b7283937bc3c9760a91b825f9182526020526040902090565b9650620018a66f2a37b5b2b7283937bc3ca0b236b4b71760811b885f9182526020526040902090565b9550620018ca6a2b30bab63a283937bc3c9760a91b885f9182526020526040902090565b9450620018f36f2b30bab63a283937bc3ca0b236b4b71760811b865f9182526020526040902090565b93505050509193509193565b5f5b620019116101e0830183620023ef565b9050811015620019df576200192b6101e0830183620023ef565b828181106200193e576200193e620026a7565b6200195692602060409092020190810191506200231b565b5f848152600a60209081526040808320858452909152902080546001600160a01b0319166001600160a01b03929092169190911790556200199c6101e0830183620023ef565b82818110620019af57620019af620026a7565b5f868152600b60209081526040808320878452825291829020919092029390930101359091555060010162001901565b505f5b620019f2610200830183620023ef565b905081101562001ac05762001a0c610200830183620023ef565b8281811062001a1f5762001a1f620026a7565b62001a3792602060409092020190810191506200231b565b5f848152600c60209081526040808320858452909152902080546001600160a01b0319166001600160a01b039290921691909117905562001a7d610200830183620023ef565b8281811062001a905762001a90620026a7565b5f868152600d602090815260408083208784528252918290209190920293909301013590915550600101620019e2565b505050565b600280546001600160a01b031916905562001ae08162001fae565b50565b5f818152600960205260408120600281015460038201546005546012840154600f9094018054869562001bb49594936001600160a01b039081169391169162001b2c9062002533565b80601f016020809104026020016040519081016040528092919081815260200182805462001b5a9062002533565b801562001ba95780601f1062001b7f5761010080835404028352916020019162001ba9565b820191905f5260205f20905b81548152906001019060200180831162001b8b57829003601f168201915b505050505062002027565b600554604080516001600160a01b03808516825280861660208301529092169082015291935091507fa8bb59c0ffcc9833d1ff47a631a1bcbc76b2da935566a08f663e6c8ad1b5ba84906060015b60405180910390a1915091565b5f81815260096020526040812080546001820154600654601484015460109094018054869562001c559594936001600160a01b039081169391169162001b2c9062002533565b600654604080516001600160a01b03808516825280861660208301529092169082015291935091507f26ad9f07a47e389150a15677a365d64f42af0000b792c182ada6a3b5ab193a0b9060600162001c02565b5f82815260096020526040812060040154908167ffffffffffffffff81111562001cd65762001cd66200251f565b60405190808252806020026020018201604052801562001d1c57816020015b604080518082019091525f808252602082015281526020019060019003908162001cf55790505b5090505f5b8281101562001d9a576040805180820182525f878152600a60209081528382208583528152838220546001600160a01b03168352888252600b815283822085835281529290205491810191909152825183908390811062001d865762001d86620026a7565b602090810291909101015260010162001d21565b506040516314a28d1160e11b81526001600160a01b038416906329451a229062001dc99084906004016200282c565b5f604051808303815f87803b15801562001de1575f80fd5b505af115801562001df4573d5f803e3d5ffd5b5050505050505050565b5f82815260096020526040812060050154908167ffffffffffffffff81111562001e2c5762001e2c6200251f565b60405190808252806020026020018201604052801562001e7257816020015b604080518082019091525f808252602082015281526020019060019003908162001e4b5790505b5090505f5b8281101562001ef0576040805180820182525f878152600c60209081528382208583528152838220546001600160a01b03168352888252600d815283822085835281529290205491810191909152825183908390811062001edc5762001edc620026a7565b602090810291909101015260010162001e77565b50604051631bca511360e01b81526001600160a01b03841690631bca51139062001dc99084906004016200282c565b6001600160a01b038116158062001f3e57506001600160a01b03811630145b1562001f5d5760405163e6c4247b60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b03838116918217909255600154604051919216907f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700905f90a350565b6001600160a01b03811662001fd65760405163156fee5160e31b815260040160405180910390fd5b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f805f806200203989898988620021c0565b915091505f826001600160a01b03163b11806200205f57505f816001600160a01b03163b115b156200207e57604051631f99271960e11b815260040160405180910390fd5b5f896040516200208e90620022ff565b8190604051809103905ff5905080158015620020ac573d5f803e3d5ffd5b509050826001600160a01b0316816001600160a01b031614620020e257604051633e89a13360e01b815260040160405180910390fd5b5f89898389604051620020f5906200230d565b6200210393929190620028a9565b8190604051809103905ff590508015801562002121573d5f803e3d5ffd5b509050826001600160a01b0316816001600160a01b0316146200215757604051631b0a7c4160e31b815260040160405180910390fd5b60405163f2fde38b60e01b81526001600160a01b03898116600483015283169063f2fde38b906024015f604051808303815f87803b15801562002198575f80fd5b505af1158015620021ab573d5f803e3d5ffd5b50959d949c50939a5050505050505050505050565b5f8060ff60f81b308760405180602001620021db90620022ff565b6020820181038252601f19601f82011660405250805190602001206040516020016200220b9493929190620028f7565b604051602081830303815290604052805190602001205f1c915060ff60f81b3086604051806020016200223e906200230d565b601f1982820381018352601f9091011660408190526200226790899088908a90602001620028a9565b60408051601f198184030181529082905262002287929160200162002930565b60405160208183030381529060405280519060200120604051602001620022b29493929190620028f7565b604051602081830303815290604052805190602001205f1c905094509492505050565b610851806200296383390190565b61149c80620031b483390190565b61038a806200465083390190565b61085a80620049da83390190565b610d88806200523483390190565b5f602082840312156200232c575f80fd5b81356001600160a01b038116811462002343575f80fd5b9392505050565b5f602082840312156200235b575f80fd5b813567ffffffffffffffff81111562002372575f80fd5b8201610340818503121562002343575f80fd5b5f6020828403121562002396575f80fd5b5035919050565b60ff8116811462001ae0575f80fd5b5f60208284031215620023bd575f80fd5b813562002343816200239d565b5f60018201620023e857634e487b7160e01b5f52601160045260245ffd5b5060010190565b5f808335601e1984360301811262002405575f80fd5b83018035915067ffffffffffffffff82111562002420575f80fd5b6020019150600681901b360382131562002438575f80fd5b9250929050565b5f808335601e1984360301811262002455575f80fd5b83018035915067ffffffffffffffff82111562002470575f80fd5b60200191503681900382131562002438575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b038716815260ff861660208201526080604082018190525f90620024dc908301868862002485565b8281036060840152620024f181858762002485565b9998505050505050505050565b5f602082840312156200250f575f80fd5b8135801515811462002343575f80fd5b634e487b7160e01b5f52604160045260245ffd5b600181811c908216806200254857607f821691505b6020821081036200256757634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111562001ac057805f5260205f20601f840160051c81016020851015620025945750805b601f840160051c820191505b81811015620025b5575f8155600101620025a0565b5050505050565b815167ffffffffffffffff811115620025d957620025d96200251f565b620025f181620025ea845462002533565b846200256d565b602080601f83116001811462002627575f84156200260f5750858301515b5f19600386901b1c1916600185901b17855562002681565b5f85815260208120601f198616915b82811015620026575788860151825594840194600190910190840162002636565b50858210156200267557878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b5f602082840312156200269a575f80fd5b815162002343816200239d565b634e487b7160e01b5f52603260045260245ffd5b5f815180845260208085019450602084015f5b83811015620026f55781516001600160a01b031687529582019590820190600101620026ce565b509495945050505050565b604081525f620027146040830185620026bb565b8281036020840152620027288185620026bb565b95945050505050565b5f61020082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151620027ab828501826001600160a01b03169052565b5050610140838101516001600160a01b039081169184019190915261016080850151821690840152610180808501518216908401526101a0808501518216908401526101c0808501518216908401526101e09384015116929091019190915290565b8035602083101562002826575f19602084900360031b1b165b92915050565b602080825282518282018190525f919060409081850190868401855b828110156200287857815180516001600160a01b0316855286015186850152928401929085019060010162002848565b5091979650505050505050565b5f5b83811015620028a157818101518382015260200162002887565b50505f910152565b5f60018060a01b038086168352808516602084015250606060408301528251806060840152620028e181608085016020870162002885565b601f01601f191691909101608001949350505050565b6001600160f81b031994909416845260609290921b6bffffffffffffffffffffffff191660018401526015830152603582015260550190565b5f83516200294381846020880162002885565b8351908301906200295981836020880162002885565b0194935050505056fe60c060405234801561000f575f80fd5b5060405161085138038061085183398101604081905261002e91610067565b61012c8110156100515760405163dd09ae8560e01b815260040160405180910390fd5b6001600160a01b0390911660805260a05261009e565b5f8060408385031215610078575f80fd5b82516001600160a01b038116811461008e575f80fd5b6020939093015192949293505050565b60805160a0516107716100e05f395f818160d201526102bb01525f8181608e0152818161039c01528181610557015281816105da015261066501526107715ff3fe608060405234801561000f575f80fd5b5060043610610085575f3560e01c80637c10dea6116100585780637c10dea61461018e578063af6f8c1b146101da578063b535b5c3146101ed578063c4d252f51461021e575f80fd5b80632b3ed84e146100895780634623c81e146100cd578063548eac04146101025780637a02dc0614610117575b5f80fd5b6100b07f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6100f47f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016100c4565b6101156101103660046106d2565b610231565b005b61016a6101253660046106d2565b604080518082019091525f8082526020820152505f90815260016020818152604092839020835180850190945280548452909101546001600160a01b03169082015290565b60408051825181526020928301516001600160a01b031692810192909252016100c4565b6101bd61019c3660046106d2565b600160208190525f918252604090912080549101546001600160a01b031682565b604080519283526001600160a01b039091166020830152016100c4565b6101156101e83660046106d2565b61036b565b61020e6101fb3660046106d2565b5f90815260016020526040902054151590565b60405190151581526020016100c4565b61011561022c3660046106d2565b61049b565b60025f5403610253576040516306fda65d60e31b815260040160405180910390fd5b60025f55806102755760405163e0f8778160e01b815260040160405180910390fd5b5f81815260016020819052604090912001546001600160a01b0316156102ae57604051632da5055760e21b815260040160405180910390fd5b60405180604001604052807f0000000000000000000000000000000000000000000000000000000000000000426102e591906106e9565b81523360209182018190525f84815260018084526040918290208551815594840151940180546001600160a01b0319166001600160a01b03909516949094179093558251848152918201527f6ef595d41bb19bf4009067ebfca1e965c782641ffd735166641d1832d9955ca591015b60405180910390a1610364610554565b5060015f55565b60025f540361038d576040516306fda65d60e31b815260040160405180910390fd5b60025f55336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103d9576040516282b42960e81b815260040160405180910390fd5b5f81815260016020819052604090912054101561040957604051637d9b58e760e11b815260040160405180910390fd5b5f81815260016020526040902054421015610437576040516331524f6360e21b815260040160405180910390fd5b5f8181526001602081815260408084209384559290910180546001600160a01b0319169055815183815233918101919091527fc0c97b5bfc2b0d319a6dadd3efddd19273d76957d4cf2c1f72697f8b589dea05910160405180910390a15060015f55565b60025f54036104bd576040516306fda65d60e31b815260040160405180910390fd5b60025f90815581815260016020819052604090912001546001600160a01b03166104fa57604051637d9b58e760e11b815260040160405180910390fd5b5f8181526001602081815260408084209384559290910180546001600160a01b0319169055815183815233918101919091527f37a82c88859b7ebdc11c1ada9b2f845df41bcf0b0f60931aad69c56bf38440149101610354565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105b1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105d5919061070e565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663127effb26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610634573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610658919061070e565b9050336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480159061069c5750336001600160a01b03831614155b80156106b15750336001600160a01b03821614155b156106ce576040516282b42960e81b815260040160405180910390fd5b5050565b5f602082840312156106e2575f80fd5b5035919050565b8082018082111561070857634e487b7160e01b5f52601160045260245ffd5b92915050565b5f6020828403121561071e575f80fd5b81516001600160a01b0381168114610734575f80fd5b939250505056fea264697066735822122082406706a29eebee4051b97dfa4927d596b49e6ce9dd7a3826c285f790a59d4364736f6c6343000818003360c060405234801562000010575f80fd5b506040516200149c3803806200149c833981016040819052620000339162000135565b6001600160a01b0382166200005b5760405163156fee5160e31b815260040160405180910390fd5b6001600160a01b038116620000835760405163e6c4247b60e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0384811691909117909155811660808190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015620000e4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200010a91906200016b565b60ff1660a05250620001949050565b80516001600160a01b038116811462000130575f80fd5b919050565b5f806040838503121562000147575f80fd5b620001528362000119565b9150620001626020840162000119565b90509250929050565b5f602082840312156200017c575f80fd5b815160ff811681146200018d575f80fd5b9392505050565b60805160a0516112a8620001f45f395f818160d4015281816109b4015281816109e801528181610a8801528181610ab501528181610af30152610b5601525f818161025b0152818161037b015281816105310152610bf701526112a85ff3fe608060405234801561000f575f80fd5b50600436106100cb575f3560e01c80638da5cb5b11610088578063c8d2df5611610063578063c8d2df5614610230578063d861811514610243578063ded4a6fe14610256578063f2fde38b1461027d575f80fd5b80638da5cb5b146101f7578063a22484d914610208578063ad0780211461021d575f80fd5b8063304cef9d146100cf5780633af32abf1461010d57806348ad6f5c1461014a578063544821731461015f57806356f1b546146101a2578063803bc5e2146101ca575b5f80fd5b6100f67f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020015b60405180910390f35b61013a61011b366004610ecb565b6001600160a01b039081165f9081526003602052604090205416151590565b6040519015158152602001610104565b61015d610158366004610ee4565b610290565b005b61018a61016d366004610ecb565b6001600160a01b039081165f908152600360205260409020541690565b6040516001600160a01b039091168152602001610104565b6101b56101b0366004610f0e565b610301565b60408051928352602083019190915201610104565b6101e96101d8366004610ecb565b60046020525f908152604090205481565b604051908152602001610104565b6001546001600160a01b031661018a565b6102106103fc565b6040516101049190610f5f565b6101e961022b366004610fab565b61045c565b6101e961023e366004610fc2565b61046d565b61015d610251366004610fea565b61047f565b61018a7f000000000000000000000000000000000000000000000000000000000000000081565b61015d61028b366004610ecb565b610797565b60025f54036102b257604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146102e157604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b03165f9081526004602052604081209190915560019055565b5f80600184101561031657505f9050806103f2565b5f876001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610353573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103779190611023565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b0316146103c1576103bc87866107f8565b6103c3565b845b91505f6103d08786610bca565b9050600182106103eb576103e68383835f610d35565b6103ed565b825b935050505b9550959350505050565b6060600280548060200260200160405190810160405280929190818152602001828054801561045257602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610434575b5050505050905090565b5f6104673383610bca565b92915050565b5f61047883836107f8565b9392505050565b60025f54036104a157604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146104d057604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b03821615806104ed57506001600160a01b038316155b1561050b57604051633efa09af60e01b815260040160405180910390fd5b600254601e101561052f5760405163be8f94e960e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031603610581576040516319fc848960e21b815260040160405180910390fd5b6001600160a01b038381165f9081526003602052604090206001015416156105bc57604051635405c10760e11b815260040160405180910390fd5b600280546001810182555f9182527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0180546001600160a01b0319166001600160a01b0386169081179091556040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015610641573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610665919061103a565b905060068160ff16101561068c57604051630da74dab60e01b815260040160405180910390fd5b5f836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106c9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106ed919061103a565b604080516080810182526001600160a01b039687168152968616602080890182815260ff9485168a850190815296851660608b019081525f938452600383528484209a518b54908b166001600160a01b0319909116178b55905160019a8b018054985192518716600160a81b0260ff60a81b1993909716600160a01b026001600160a81b031990991691909a16179690961795909516929092179095556004909252509182205555565b60025f54036107b957604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146107e857604051630b2db9b760e31b815260040160405180910390fd5b6107f181610d90565b5060015f55565b6001600160a01b038083165f9081526003602052604080822080546001909101548251633fabe5a360e21b815292519394919091169260ff600160a81b8304811693600160a01b90930416918591829182918291889163feaf968c9160048082019260a0929091908290030181865afa158015610877573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061089b9190611073565b94509450509350935060018312156108c55760405162fc7cad60e51b815260040160405180910390fd5b8369ffffffffffffffffffff168169ffffffffffffffffffff1610156108fe57604051630cd5fa0760e11b815260040160405180910390fd5b600182101561091f5760405162ace4c560e51b815260040160405180910390fd5b42821115610940576040516352c4db3960e11b815260040160405180910390fd5b6001600160a01b038a165f9081526004602052604090205461096283426110d3565b1115610981576040516329fc802760e11b815260040160405180910390fd5b5f8660ff168660ff16116109965760016109ab565b6109a087876110e6565b6109ab90600a6111df565b90505f8660ff167f000000000000000000000000000000000000000000000000000000000000000060ff16116109e2576001610a17565b610a0c877f00000000000000000000000000000000000000000000000000000000000000006110e6565b610a1790600a6111df565b90505f610a24838d6111ed565b90505f610a328960126110e6565b610a3d90600a6111df565b90505f8782610a4d8c600a6111df565b610a5791906111ed565b610a619190611218565b90505f8285610a7086856111ed565b610a7a91906111ed565b610a849190611218565b90507f000000000000000000000000000000000000000000000000000000000000000060ff168c60ff1603610b54577f000000000000000000000000000000000000000000000000000000000000000060ff16600603610aef57610ae88682611218565b9050610b54565b60117f000000000000000000000000000000000000000000000000000000000000000060ff161115610b5457889150670de0b6b3a76400008386610b3387866111ed565b610b3d91906111ed565b610b479190611218565b610b519190611218565b90505b7f000000000000000000000000000000000000000000000000000000000000000060ff16600603610bb7578b60ff16601203610b9e57610b976298968082611218565b9050610bb7565b8b60ff16600803610bb757610bb4606482611218565b90505b9f9e505050505050505050505050505050565b6002546040516370a0823160e01b81526001600160a01b0384811660048301525f928392839283929183917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610c3c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c609190611023565b610c6a9088611237565b90505f5b82811015610d295760028181548110610c8957610c8961124a565b5f918252602090912001546040516370a0823160e01b81526001600160a01b038b81166004830152909116965086906370a0823190602401602060405180830381865afa158015610cdc573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d009190611023565b94508415610d2157610d1286866107f8565b9350610d1e8483611237565b91505b600101610c6e565b50979650505050505050565b5f80610d42868686610e08565b90506001836002811115610d5857610d5861125e565b148015610d7457505f8480610d6f57610d6f611204565b868809115b15610d8757610d84600182611237565b90505b95945050505050565b6001600160a01b038116610db75760405163156fee5160e31b815260040160405180910390fd5b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f80805f19858709858702925082811083820303915050805f03610e3f57838281610e3557610e35611204565b0492505050610478565b808411610e4a575f80fd5b5f84868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203025f889003889004909101858311909403939093029303949094049190911702949350505050565b80356001600160a01b0381168114610ec6575f80fd5b919050565b5f60208284031215610edb575f80fd5b61047882610eb0565b5f8060408385031215610ef5575f80fd5b82359150610f0560208401610eb0565b90509250929050565b5f805f805f60a08688031215610f22575f80fd5b610f2b86610eb0565b9450610f3960208701610eb0565b9350610f4760408701610eb0565b94979396509394606081013594506080013592915050565b602080825282518282018190525f9190848201906040850190845b81811015610f9f5783516001600160a01b031683529284019291840191600101610f7a565b50909695505050505050565b5f60208284031215610fbb575f80fd5b5035919050565b5f8060408385031215610fd3575f80fd5b610fdc83610eb0565b946020939093013593505050565b5f805f60608486031215610ffc575f80fd5b61100584610eb0565b925061101360208501610eb0565b9150604084013590509250925092565b5f60208284031215611033575f80fd5b5051919050565b5f6020828403121561104a575f80fd5b815160ff81168114610478575f80fd5b805169ffffffffffffffffffff81168114610ec6575f80fd5b5f805f805f60a08688031215611087575f80fd5b6110908661105a565b94506020860151935060408601519250606086015191506110b36080870161105a565b90509295509295909350565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610467576104676110bf565b60ff8281168282160390811115610467576104676110bf565b600181815b8085111561113957815f190482111561111f5761111f6110bf565b8085161561112c57918102915b93841c9390800290611104565b509250929050565b5f8261114f57506001610467565b8161115b57505f610467565b8160018114611171576002811461117b57611197565b6001915050610467565b60ff84111561118c5761118c6110bf565b50506001821b610467565b5060208310610133831016604e8410600b84101617156111ba575081810a610467565b6111c483836110ff565b805f19048211156111d7576111d76110bf565b029392505050565b5f61047860ff841683611141565b8082028115828204841417610467576104676110bf565b634e487b7160e01b5f52601260045260245ffd5b5f8261123257634e487b7160e01b5f52601260045260245ffd5b500490565b80820180821115610467576104676110bf565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52602160045260245ffdfea26469706673582212201d12ab731a2b5553cbf1c71b1477503e9c5fddd55972d8232d310eb3be4d5ae364736f6c63430008180033608060405234801561000f575f80fd5b5060405161038a38038061038a83398101604081905261002e91610053565b600180546001600160a01b0319166001600160a01b0392909216919091179055610080565b5f60208284031215610063575f80fd5b81516001600160a01b0381168114610079575f80fd5b9392505050565b6102fd8061008d5f395ff3fe608060405234801561000f575f80fd5b5060043610610055575f3560e01c80633af32abf146100595780633ca40a24146100995780638da5cb5b146100ae5780639d74164f146100c9578063f2fde38b146100dc575b5f80fd5b61008461006736600461029a565b6001600160a01b03165f9081526002602052604090205460ff1690565b60405190151581526020015b60405180910390f35b6100ac6100a736600461029a565b6100ef565b005b6001546040516001600160a01b039091168152602001610090565b6100ac6100d736600461029a565b61013a565b6100ac6100ea36600461029a565b6101c1565b6001546001600160a01b0316331461011a57604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b03165f908152600260205260409020805460ff19169055565b6001546001600160a01b0316331461016557604051630b2db9b760e31b815260040160405180910390fd5b6001600160a01b0381165f9081526002602052604090205460ff161561019e5760405163080fc0bd60e11b815260040160405180910390fd5b6001600160a01b03165f908152600260205260409020805460ff19166001179055565b60025f54036101e357604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b0316331461021257604051630b2db9b760e31b815260040160405180910390fd5b61021b81610222565b5060015f55565b6001600160a01b0381166102495760405163156fee5160e31b815260040160405180910390fd5b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f602082840312156102aa575f80fd5b81356001600160a01b03811681146102c0575f80fd5b939250505056fea26469706673582212202747930dd2f2cb02d243987196f2f0e030ca62e9bc02aba887b50e19dc5500d564736f6c63430008180033608060405234801561000f575f80fd5b50600180546001600160a01b0319163317905561082b8061002f5f395ff3fe608060405260043610610084575f3560e01c80639623609d116100575780639623609d1461011557806399a88ec414610128578063e30c397814610147578063f2fde38b14610164578063f3b7dead14610183575f80fd5b8063204e1c7a1461008857806379ba5097146100c35780637eff275e146100d95780638da5cb5b146100f8575b5f80fd5b348015610093575f80fd5b506100a76100a2366004610642565b6101a2565b6040516001600160a01b03909116815260200160405180910390f35b3480156100ce575f80fd5b506100d7610242565b005b3480156100e4575f80fd5b506100d76100f3366004610664565b6102a1565b348015610103575f80fd5b506001546001600160a01b03166100a7565b6100d76101233660046106af565b610351565b348015610133575f80fd5b506100d7610142366004610664565b610409565b348015610152575f80fd5b506002546001600160a01b03166100a7565b34801561016f575f80fd5b506100d761017e366004610642565b610488565b34801561018e575f80fd5b506100a761019d366004610642565b6104e9565b5f805f836001600160a01b03166040516101c690635c60da1b60e01b815260040190565b5f60405180830381855afa9150503d805f81146101fe576040519150601f19603f3d011682016040523d82523d5f602084013e610203565b606091505b509150915081610226576040516385be45b560e01b815260040160405180910390fd5b8080602001905181019061023a919061077e565b949350505050565b60025f540361026457604051633ee5aeb560e01b815260040160405180910390fd5b60025f819055546001600160a01b03163314610292576040516282b42960e81b815260040160405180910390fd5b61029b3361050d565b60015f55565b60025f54036102c357604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146102f257604051630b2db9b760e31b815260040160405180910390fd5b6040516308f2839760e41b81526001600160a01b038281166004830152831690638f283970906024015b5f604051808303815f87803b158015610333575f80fd5b505af1158015610345573d5f803e3d5ffd5b505060015f5550505050565b60025f540361037357604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146103a257604051630b2db9b760e31b815260040160405180910390fd5b60405163278f794360e11b81526001600160a01b03841690634f1ef2869034906103d29086908690600401610799565b5f604051808303818588803b1580156103e9575f80fd5b505af11580156103fb573d5f803e3d5ffd5b505060015f55505050505050565b60025f540361042b57604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b0316331461045a57604051630b2db9b760e31b815260040160405180910390fd5b604051631b2ce7f360e11b81526001600160a01b038281166004830152831690633659cfe69060240161031c565b60025f54036104aa57604051633ee5aeb560e01b815260040160405180910390fd5b60025f556001546001600160a01b031633146104d957604051630b2db9b760e31b815260040160405180910390fd5b6104e281610529565b5060015f55565b5f805f836001600160a01b03166040516101c6906303e1469160e61b815260040190565b600280546001600160a01b0319169055610526816105b6565b50565b6001600160a01b038116158061054757506001600160a01b03811630145b156105655760405163e6c4247b60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b03838116918217909255600154604051919216907f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700905f90a350565b6001600160a01b0381166105dd5760405163156fee5160e31b815260040160405180910390fd5b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b0381168114610526575f80fd5b5f60208284031215610652575f80fd5b813561065d8161062e565b9392505050565b5f8060408385031215610675575f80fd5b82356106808161062e565b915060208301356106908161062e565b809150509250929050565b634e487b7160e01b5f52604160045260245ffd5b5f805f606084860312156106c1575f80fd5b83356106cc8161062e565b925060208401356106dc8161062e565b9150604084013567ffffffffffffffff808211156106f8575f80fd5b818601915086601f83011261070b575f80fd5b81358181111561071d5761071d61069b565b604051601f8201601f19908116603f011681019083821181831017156107455761074561069b565b8160405282815289602084870101111561075d575f80fd5b826020860160208301375f6020848301015280955050505050509250925092565b5f6020828403121561078e575f80fd5b815161065d8161062e565b60018060a01b03831681525f60206040602084015283518060408501525f5b818110156107d4578581018301518582016060015282016107b8565b505f606082860101526060601f19601f83011685010192505050939250505056fea264697066735822122066cfa399ff14a6fa5676bf6889fb6e3b33c287da27c77fba72388f5f5b0ffa8f64736f6c63430008180033608060405260405162000d8838038062000d88833981016040819052620000269162000415565b82816200003582825f6200004c565b50620000439050826200007d565b50505062000540565b6200005783620000ee565b5f82511180620000645750805b1562000078576200007683836200012f565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f620000be5f8051602062000d41833981519152546001600160a01b031690565b604080516001600160a01b03928316815291841660208301520160405180910390a1620000eb816200015e565b50565b620000f981620001fb565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b606062000157838360405180606001604052806027815260200162000d616027913962000292565b9392505050565b6001600160a01b038116620001c95760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b805f8051602062000d418339815191525b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b6200026a5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401620001c0565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc620001da565b60605f80856001600160a01b031685604051620002b09190620004ef565b5f60405180830381855af49150503d805f8114620002ea576040519150601f19603f3d011682016040523d82523d5f602084013e620002ef565b606091505b50909250905062000303868383876200030d565b9695505050505050565b60608315620003805782515f0362000378576001600160a01b0385163b620003785760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620001c0565b50816200038c565b6200038c838362000394565b949350505050565b815115620003a55781518083602001fd5b8060405162461bcd60e51b8152600401620001c091906200050c565b80516001600160a01b0381168114620003d8575f80fd5b919050565b634e487b7160e01b5f52604160045260245ffd5b5f5b838110156200040d578181015183820152602001620003f3565b50505f910152565b5f805f6060848603121562000428575f80fd5b6200043384620003c1565b92506200044360208501620003c1565b60408501519092506001600160401b038082111562000460575f80fd5b818601915086601f83011262000474575f80fd5b815181811115620004895762000489620003dd565b604051601f8201601f19908116603f01168101908382118183101715620004b457620004b4620003dd565b81604052828152896020848701011115620004cd575f80fd5b620004e0836020830160208801620003f1565b80955050505050509250925092565b5f825162000502818460208701620003f1565b9190910192915050565b602081525f82518060208401526200052c816040850160208701620003f1565b601f01601f19169190910160400192915050565b6107f3806200054e5f395ff3fe60806040526004361061004d575f3560e01c80633659cfe6146100645780634f1ef286146100775780635c60da1b1461008a5780638f283970146100ae578063f851a440146100c15761005c565b3661005c5761005a6100c9565b005b61005a6100c9565b61005a610072366004610692565b6100e3565b61005a6100853660046106ab565b610126565b61009261018c565b6040516001600160a01b03909116815260200160405180910390f35b61005a6100bc366004610692565b6101c4565b6100926101ec565b6100d1610214565b6100e16100dc6102a9565b6102b2565b565b6100eb6102d0565b6001600160a01b0316330361011e57610102610302565b61011b8160405180602001604052805f8152505f61030c565b50565b61011b6100c9565b61012e6102d0565b6001600160a01b031633036101845761017f8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506001925061030c915050565b505050565b61017f6100c9565b5f6101956102d0565b6001600160a01b031633036101b9576101ac610302565b6101b46102a9565b905090565b6101c16100c9565b90565b6101cc6102d0565b6001600160a01b0316330361011e576101e3610302565b61011b81610336565b5f6101f56102d0565b6001600160a01b031633036101b95761020c610302565b6101b46102d0565b61021c6102d0565b6001600160a01b031633036100e15760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b5f6101b461038a565b365f80375f80365f845af43d5f803e8080156102cc573d5ff35b3d5ffd5b5f7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b34156100e1575f80fd5b610315836103b1565b5f825111806103215750805b1561017f5761033083836103f0565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f61035f6102d0565b604080516001600160a01b03928316815291841660208301520160405180910390a161011b8161041c565b5f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6102f3565b6103ba816104c5565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b6060610415838360405180606001604052806027815260200161079760279139610559565b9392505050565b6001600160a01b0381166104815760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102a0565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b6105325760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102a0565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104a4565b60605f80856001600160a01b0316856040516105759190610749565b5f60405180830381855af49150503d805f81146105ad576040519150601f19603f3d011682016040523d82523d5f602084013e6105b2565b606091505b50915091506105c3868383876105cd565b9695505050505050565b6060831561063b5782515f03610634576001600160a01b0385163b6106345760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102a0565b5081610645565b610645838361064d565b949350505050565b81511561065d5781518083602001fd5b8060405162461bcd60e51b81526004016102a09190610764565b80356001600160a01b038116811461068d575f80fd5b919050565b5f602082840312156106a2575f80fd5b61041582610677565b5f805f604084860312156106bd575f80fd5b6106c684610677565b9250602084013567ffffffffffffffff808211156106e2575f80fd5b818601915086601f8301126106f5575f80fd5b813581811115610703575f80fd5b876020828501011115610714575f80fd5b6020830194508093505050509250925092565b5f5b83811015610741578181015183820152602001610729565b50505f910152565b5f825161075a818460208701610727565b9190910192915050565b602081525f8251806020840152610782816040850160208701610727565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212200574afa0af7d8edebf3ec31d8bf7147040f26698a800538942decacb0b574c7a64736f6c63430008180033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122014ba4a2fae7d0111bac55f469a6089f1db93f2f00a8b5010ff0260101e66edb764736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c573100a879f480c9ae5290f865a1e354f4ba67f
-----Decoded View---------------
Arg [0] : ownerAddr (address): 0xc573100a879f480c9AE5290f865a1e354F4BA67F
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000c573100a879f480c9ae5290f865a1e354f4ba67f
Deployed Bytecode Sourcemap
96075:23258:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;99347:41;;;;;-1:-1:-1;;;;;99347:41:0;;;;;;-1:-1:-1;;;;;287:32:1;;;269:51;;257:2;242:18;99347:41:0;;;;;;;;101174:198;;;;;;:::i;:::-;;:::i;:::-;;102808:3180;;;;;;:::i;:::-;;:::i;:::-;;;1157:25:1;;;1145:2;1130:18;102808:3180:0;1011:177:1;101812:190:0;;;;;;:::i;:::-;;:::i;99445:53::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;1358:14:1;;1351:22;1333:41;;1321:2;1306:18;99445:53:0;1193:187:1;99308:32:0;;;;;-1:-1:-1;;;;;99308:32:0;;;49919:169;;;:::i;101497:190::-;;;;;;:::i;:::-;;:::i;99395:41::-;;;;;-1:-1:-1;;;;;99395:41:0;;;39792:89;39867:6;;-1:-1:-1;;;;;39867:6:0;39792:89;;99505:62;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;99505:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1997:15:1;;;1979:34;;2049:15;;;2044:2;2029:18;;2022:43;2101:15;;;2081:18;;;2074:43;;;;2153:15;;;2148:2;2133:18;;2126:43;2206:15;;;2200:3;2185:19;;2178:44;2259:15;;1959:3;2238:19;;2231:44;2312:15;;2306:3;2291:19;;2284:44;2365:15;;2359:3;2344:19;;2337:44;2418:15;;;2412:3;2397:19;;2390:44;1928:3;1913:19;99505:62:0;1570:870:1;106151:4508:0;;;;;;:::i;:::-;;:::i;100767:259::-;;;;;;:::i;:::-;;:::i;102237:284::-;;;;;;:::i;:::-;;:::i;50911:95::-;50985:13;;-1:-1:-1;;;;;50985:13:0;50911:95;;49651:146;;;;;;:::i;:::-;;:::i;101174:198::-;36420:1;38319:7;;:18;38315:88;;38361:30;;-1:-1:-1;;;38361:30:0;;;;;;;;;;;38315:88;36420:1;38480:7;:17;38818:6:::1;::::0;-1:-1:-1;;;;;38818:6:0::1;38804:10;:20;38800:44;;38833:11;;-1:-1:-1::0;;;38833:11:0::1;;;;;;;;;;;38800:44;-1:-1:-1::0;;;;;101260:26:0;::::2;;::::0;;;:20:::2;:26;::::0;;;;;::::2;;101255:64;;101295:24;;-1:-1:-1::0;;;101295:24:0::2;;;;;;;;;;;101255:64;-1:-1:-1::0;;;;;101330:26:0::2;101359:5;101330:26:::0;;;:20:::2;:26;::::0;;;;:34;;-1:-1:-1;;101330:34:0::2;::::0;;;38646:21;;101174:198::o;102808:3180::-;102892:7;36420:1;38319:7;;:18;38315:88;;38361:30;;-1:-1:-1;;;38361:30:0;;;;;;;;;;;38315:88;36420:1;38480:7;:17;;;100558:10:::1;100537:32:::0;;:20:::1;:32;::::0;;;;;::::1;;100532:70;;100578:24;;-1:-1:-1::0;;;100578:24:0::1;;;;;;;;;;;100532:70;102995:17:::2;::::0;-1:-1:-1;;;;;102995:17:0::2;102991:75;;103035:31;;-1:-1:-1::0;;;103035:31:0::2;;;;;;;;;;;102991:75;103139:26;::::0;-1:-1:-1;;;;;103139:26:0::2;103135:80;;103188:27;;-1:-1:-1::0;;;103188:27:0::2;;;;;;;;;;;103135:80;103230:26;::::0;-1:-1:-1;;;;;103230:26:0::2;103226:80;;103279:27;;-1:-1:-1::0;;;103279:27:0::2;;;;;;;;;;;103226:80;103394:1;103371:20;::::0;;;::::2;::::0;::::2;;:::i;:::-;:24;;;103370:57;;;-1:-1:-1::0;103424:2:0::2;103401:20;::::0;;;::::2;::::0;::::2;;:::i;:::-;:25;;;103370:57;103366:92;;;103436:22;;-1:-1:-1::0;;;103436:22:0::2;;;;;;;;;;;103366:92;103657:22;103694:27:::0;103736:22:::2;103773:27:::0;103814:18:::2;103827:4;103814:12;:18::i;:::-;103642:190;;;;;;;;103885:20;103910:7;;103908:9;;;;;:::i;:::-;;;;;;;103885:32;;104037:1505;;;;;;;;104086:19;104037:1505;;;;104136:14;104037:1505;;;;104181:19;104037:1505;;;;104231:14;104037:1505;;;;104770:4;:18;;;;;;;;:::i;:::-;104037:1505:::0;;-1:-1:-1;104037:1505:0::2;;104841:29;;::::0;::::2;:4:::0;:29:::2;:::i;:::-;:36;;104037:1505;;;;105061:4;:21;;;104037:1505;;;;105118:4;:24;;;104037:1505;;;;105179:4;:25;;;104037:1505;;;;105232:4;:16;;;104037:1505;;;;105278:4;:18;;;104037:1505;;;;105332:4;:24;;;104037:1505;;;;105389:4;:21;;;104037:1505;;;;105447:4;:25;;;104037:1505;;;;105507:4;:23;;;104037:1505;;;;104350:4;104357;:20;;;;;;;;;;:::i;:::-;104379:18;;::::0;::::2;:4:::0;:18:::2;:::i;:::-;104399:16;;::::0;::::2;:4:::0;:16:::2;:::i;:::-;104275:141;;;;;;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;104275:141:0;;::::2;::::0;;;;;;::::2;::::0;;::::2;::::0;;-1:-1:-1;;;;;104275:141:0::2;-1:-1:-1::0;;;104275:141:0::2;::::0;;104037:1505;;;104446:61;104501:4:::2;104446:61;::::0;::::2;269:51:1::0;104037:1505:0;::::2;::::0;242:18:1;;104446:61:0::2;::::0;;-1:-1:-1;;104446:61:0;;::::2;::::0;;;;;;::::2;::::0;;::::2;::::0;;-1:-1:-1;;;;;104446:61:0::2;-1:-1:-1::0;;;104446:61:0::2;::::0;;104037:1505;;;::::2;104539:20;::::0;;;::::2;::::0;::::2;;:::i;:::-;-1:-1:-1::0;;;;;104037:1505:0::2;::::0;;::::2;;104596:25;::::0;;;::::2;::::0;::::2;;:::i;:::-;-1:-1:-1::0;;;;;104037:1505:0::2;::::0;;::::2;;104653:20;::::0;;;::::2;::::0;::::2;;:::i;:::-;-1:-1:-1::0;;;;;104037:1505:0::2;::::0;;::::2;;104710:25;::::0;;;::::2;::::0;::::2;;:::i;:::-;-1:-1:-1::0;;;;;104037:1505:0::2;::::0;;::::2;;105008:20;::::0;;;::::2;::::0;::::2;;:::i;:::-;-1:-1:-1::0;;;;;104037:1505:0::2;::::0;;::::2;::::0;;::::2;::::0;104913:19:::2;::::0;;::::2;:4:::0;:19:::2;:::i;:::-;-1:-1:-1::0;;;;;104037:1505:0::2;;;;;104960:4;:16;;;;;;;;;;:::i;:::-;104037:1505;;::::0;;104001:33:::2;::::0;;;:19:::2;:33;::::0;;;;;;;;:1541;;;;;;::::2;::::0;::::2;::::0;::::2;::::0;;;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;;;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;;::::2;:::i;:::-;-1:-1:-1::0;104001:1541:0::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;;::::2;:::i;:::-;-1:-1:-1::0;104001:1541:0::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;;-1:-1:-1;;;;;;104001:1541:0;;::::2;-1:-1:-1::0;;;;;104001:1541:0;;::::2;;::::0;;;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;;;::::2;::::0;;::::2;::::0;;;::::2;::::0;;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;;;::::2;::::0;;::::2;::::0;;;::::2;::::0;;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;;;::::2;::::0;;::::2;::::0;;;::::2;::::0;;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;;;;::::2;::::0;;::::2;;::::0;;::::2;::::0;::::2;::::0;::::2;::::0;;::::2;::::0;;::::2;::::0;;::::2;::::0;;;;::::2;-1:-1:-1::0;;;;;;104001:1541:0;;;;;;;-1:-1:-1;;;104001:1541:0;::::2;;::::0;;;::::2;;::::0;;105641:40:::2;105662:12:::0;105676:4;105641:20:::2;:40::i;:::-;105736:39;::::0;1157:25:1;;;105736:39:0::2;::::0;1145:2:1;1130:18;105736:39:0::2;;;;;;;105924:1;105890:19;;::::0;::::2;:4:::0;:19:::2;:::i;:::-;-1:-1:-1::0;;;;;105875:44:0::2;;:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:50;;;105871:77;;;105934:14;;-1:-1:-1::0;;;105934:14:0::2;;;;;;;;;;;105871:77;36377:1:::0;38646:7;:21;105968:12;102808:3180;-1:-1:-1;;;;;;102808:3180:0:o;101812:190::-;36420:1;38319:7;;:18;38315:88;;38361:30;;-1:-1:-1;;;38361:30:0;;;;;;;;;;;38315:88;36420:1;38480:7;:17;38818:6:::1;::::0;-1:-1:-1;;;;;38818:6:0::1;38804:10;:20;38800:44;;38833:11;;-1:-1:-1::0;;;38833:11:0::1;;;;;;;;;;;38800:44;-1:-1:-1::0;;;;;101905:18:0;::::2;101901:49;;101932:18;;-1:-1:-1::0;;;101932:18:0::2;;;;;;;;;;;101901:49;101961:26;:33:::0;;-1:-1:-1;;;;;;101961:33:0::2;-1:-1:-1::0;;;;;101961:33:0;;;::::2;::::0;;;::::2;::::0;;-1:-1:-1;;38646:21:0;101812:190::o;49919:169::-;36420:1;38319:7;;:18;38315:88;;38361:30;;-1:-1:-1;;;38361:30:0;;;;;;;;;;;38315:88;36420:1;38480:7;:17;;;49989:13;-1:-1:-1;;;;;49989:13:0::1;50006:10;49989:27;49985:54;;50025:14;;-1:-1:-1::0;;;50025:14:0::1;;;;;;;;;;;49985:54;50050:30;50069:10;50050:18;:30::i;:::-;36377:1:::0;38646:7;:21;49919:169::o;101497:190::-;36420:1;38319:7;;:18;38315:88;;38361:30;;-1:-1:-1;;;38361:30:0;;;;;;;;;;;38315:88;36420:1;38480:7;:17;38818:6:::1;::::0;-1:-1:-1;;;;;38818:6:0::1;38804:10;:20;38800:44;;38833:11;;-1:-1:-1::0;;;38833:11:0::1;;;;;;;;;;;38800:44;-1:-1:-1::0;;;;;101590:18:0;::::2;101586:49;;101617:18;;-1:-1:-1::0;;;101617:18:0::2;;;;;;;;;;;101586:49;101646:26;:33:::0;;-1:-1:-1;;;;;;101646:33:0::2;-1:-1:-1::0;;;;;101646:33:0;;;::::2;::::0;;;::::2;::::0;;-1:-1:-1;;38646:21:0;101497:190::o;106151:4508::-;36420:1;38319:7;;:18;38315:88;;38361:30;;-1:-1:-1;;;38361:30:0;;;;;;;;;;;38315:88;36420:1;38480:7;:17;;;100558:10:::1;100537:32:::0;;:20:::1;:32;::::0;;;;;::::1;;100532:70;;100578:24;;-1:-1:-1::0;;;100578:24:0::1;;;;;;;;;;;100532:70;106351:1:::2;106290:33:::0;;;:19:::2;:33;::::0;;;;:49:::2;;::::0;-1:-1:-1;;;;;106290:49:0::2;106286:100;;106362:24;;-1:-1:-1::0;;;106362:24:0::2;;;;;;;;;;;106286:100;106498:1;106444:31:::0;;;:17:::2;:31;::::0;;;;:42:::2;;::::0;-1:-1:-1;;;;;106444:42:0::2;:56:::0;106440:96:::2;;106509:27;;-1:-1:-1::0;;;106509:27:0::2;;;;;;;;;;;106440:96;106582:30;106614::::0;106648:26:::2;106661:12;106648;:26::i;:::-;106581:93;;;;106717:30;106749::::0;106783:26:::2;106796:12;106783;:26::i;:::-;106716:93;;;;106906:32;106981:22;107005:8;106949:65;;;;;:::i;:::-;-1:-1:-1::0;;;;;8470:32:1;;;8452:51;;8534:2;8519:18;;8512:34;8440:2;8425:18;106949:65:0::2;;;;;;;;;;;;;;;;::::0;::::2;;;;;-1:-1:-1::0;107122:27:0::2;107205:33:::0;;;:19:::2;:33;::::0;;;;;:53:::2;;::::0;107160:99;;106906:109;;-1:-1:-1;107122:27:0;;107198:4:::2;::::0;-1:-1:-1;;;;;107205:53:0::2;::::0;107160:99:::2;::::0;::::2;:::i;:::-;-1:-1:-1::0;;;;;8787:15:1;;;8769:34;;8839:15;;8834:2;8819:18;;8812:43;8719:2;8704:18;107160:99:0::2;;;;;;;;;;;;;;;;::::0;::::2;;;;;-1:-1:-1::0;107307:28:0::2;107350:33:::0;;;:19:::2;:33;::::0;;;;:45:::2;;::::0;107122:138;;-1:-1:-1;107307:28:0;-1:-1:-1;;;107350:45:0;::::2;;;107346:181;;;107464:33;::::0;;;:19:::2;:33;::::0;;;;;;:49:::2;;::::0;107443:71;;-1:-1:-1;;;;;107464:49:0;;::::2;::::0;107443:71:::2;::::0;::::2;:::i;:::-;-1:-1:-1::0;;;;;287:32:1;;;269:51;;257:2;242:18;107443:71:0::2;;;;;;;;;;;;;;;;::::0;::::2;;;;;;107412:103;;107346:181;107628:534;;;;;;;;107672:22;-1:-1:-1::0;;;;;107628:534:0::2;;;;;107726:22;-1:-1:-1::0;;;;;107628:534:0::2;;;;;107781:26;;;;;;;;;-1:-1:-1::0;;;;;107781:26:0::2;-1:-1:-1::0;;;;;107628:534:0::2;;;;;107834:22;-1:-1:-1::0;;;;;107628:534:0::2;;;;;107888:22;-1:-1:-1::0;;;;;107628:534:0::2;;;;;107943:26;;;;;;;;;-1:-1:-1::0;;;;;107943:26:0::2;-1:-1:-1::0;;;;;107628:534:0::2;;;;;108008:19;-1:-1:-1::0;;;;;107628:534:0::2;;;;;108067:20;-1:-1:-1::0;;;;;107628:534:0::2;;;;;108126:24;-1:-1:-1::0;;;;;107628:534:0::2;;;::::0;107594:17:::2;:31;107612:12;107594:31;;;;;;;;;;;:568;;;;;;;;;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;-1:-1:-1::0;;;;;107594:568:0::2;;;;;;;;;108278:27;108322:1;108308:16;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;108308:16:0::2;-1:-1:-1::0;108365:16:0::2;::::0;;108379:1:::2;108365:16:::0;;;;;::::2;::::0;;;108278:46;;-1:-1:-1;108335:27:0::2;::::0;108365:16;::::2;::::0;;::::2;::::0;;::::2;::::0;::::2;;::::0;-1:-1:-1;108365:16:0::2;108335:46;;108408:22;108392:10;108403:1;108392:13;;;;;;;;:::i;:::-;;;;;;:38;-1:-1:-1::0;;;;;108392:38:0::2;;;-1:-1:-1::0;;;;;108392:38:0::2;;;::::0;::::2;108457:22;108441:10;108452:1;108441:13;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;108441:38:0;;::::2;:13;::::0;;::::2;::::0;;;;;:38;108490:84:::2;::::0;-1:-1:-1;;;108490:84:0;;:60;;::::2;::::0;::::2;::::0;:84:::2;::::0;108551:10;;108563;;108490:84:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;108619:45;108667:1285;;;;;;;;108727:19;:33;108747:12;108727:33;;;;;;;;;;;:50;;;108667:1285;;;;108813:19;:33;108833:12;108813:33;;;;;;;;;;;:53;;;108667:1285;;;;108903:19;:33;108923:12;108903:33;;;;;;;;;;;:54;;;108667:1285;;;;108985:19;:33;109005:12;108985:33;;;;;;;;;;;:45;;;108667:1285;;;;109060:19;:33;109080:12;109060:33;;;;;;;;;;;:47;;;108667:1285;;;;109143:19;:33;109163:12;109143:33;;;;;;;;;;;:53;;;108667:1285;;;;109229:19;:33;109249:12;109229:33;;;;;;;;;;;:50;;;108667:1285;;;;109316:19;:33;109336:12;109316:33;;;;;;;;;;;:54;;;108667:1285;;;;109405:19;:33;109425:12;109405:33;;;;;;;;;;;:52;;;108667:1285;;;;109857:20;-1:-1:-1::0;;;;;108667:1285:0::2;;;;;109489:19;:33;109509:12;109489:33;;;;;;;;;;;:49;;;;;;;;;;-1:-1:-1::0;;;;;109489:49:0::2;-1:-1:-1::0;;;;;108667:1285:0::2;;;;;109916:24;-1:-1:-1::0;;;;;108667:1285:0::2;;;;;109737:22;-1:-1:-1::0;;;;;108667:1285:0::2;;;;;109569:19;:33;109589:12;109569:33;;;;;;;;;;;:53;;;;;;;;;;-1:-1:-1::0;;;;;109569:53:0::2;-1:-1:-1::0;;;;;108667:1285:0::2;;;;;109657:19;:33;109677:12;109657:33;;;;;;;;;;;:49;;;;;;;;;;-1:-1:-1::0;;;;;109657:49:0::2;-1:-1:-1::0;;;;;108667:1285:0::2;;;;;109798:19;-1:-1:-1::0;;;;;108667:1285:0::2;;;::::0;108619:1333:::2;;109981:22;-1:-1:-1::0;;;;;109965:49:0::2;;110015:11;109965:62;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;110038:55;110056:12;110070:22;110038:17;:55::i;:::-;110104:66;110133:12;110147:22;110104:28;:66::i;:::-;110285:33;::::0;;;:19:::2;:33;::::0;;;;;;:49:::2;;::::0;110234:101;;-1:-1:-1;;;110234:101:0;;-1:-1:-1;;;;;110285:49:0;;::::2;110234:101;::::0;::::2;269:51:1::0;110234:50:0;;::::2;::::0;::::2;::::0;242:18:1;;110234:101:0::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;-1:-1:-1::0;;;110409:33:0::2;::::0;;;:19:::2;:33;::::0;;;;;;:49:::2;;::::0;110358:101;;-1:-1:-1;;;110358:101:0;;-1:-1:-1;;;;;110409:49:0;;::::2;110358:101;::::0;::::2;269:51:1::0;110358:50:0;;::::2;::::0;-1:-1:-1;110358:50:0::2;::::0;242:18:1;;110358:101:0::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;-1:-1:-1::0;;;110527:33:0::2;::::0;;;:19:::2;:33;::::0;;;;;;:49:::2;;::::0;110479:98;;-1:-1:-1;;;110479:98:0;;-1:-1:-1;;;;;110527:49:0;;::::2;110479:98;::::0;::::2;269:51:1::0;110479:47:0;;::::2;::::0;-1:-1:-1;110479:47:0::2;::::0;242:18:1;;110479:98:0::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;110618:33;110638:12;110618:33;;;;1157:25:1::0;;1145:2;1130:18;;1011:177;110618:33:0::2;;;;;;;;-1:-1:-1::0;;36377:1:0;38646:7;:21;-1:-1:-1;;;;;;;;;106151:4508:0:o;100767:259::-;36420:1;38319:7;;:18;38315:88;;38361:30;;-1:-1:-1;;;38361:30:0;;;;;;;;;;;38315:88;36420:1;38480:7;:17;38818:6:::1;::::0;-1:-1:-1;;;;;38818:6:0::1;38804:10;:20;38800:44;;38833:11;;-1:-1:-1::0;;;38833:11:0::1;;;;;;;;;;;38800:44;-1:-1:-1::0;;;;;100851:18:0;::::2;100847:49;;100878:18;;-1:-1:-1::0;;;100878:18:0::2;;;;;;;;;;;100847:49;-1:-1:-1::0;;;;;100911:26:0;::::2;;::::0;;;:20:::2;:26;::::0;;;;;::::2;;100907:67;;;100946:28;;-1:-1:-1::0;;;100946:28:0::2;;;;;;;;;;;100907:67;-1:-1:-1::0;;;;;100985:26:0::2;;::::0;;;:20:::2;:26;::::0;;;;:33;;-1:-1:-1;;100985:33:0::2;101014:4;100985:33:::0;;::::2;::::0;;;38646:21;;100767:259::o;102237:284::-;36420:1;38319:7;;:18;38315:88;;38361:30;;-1:-1:-1;;;38361:30:0;;;;;;;;;;;38315:88;36420:1;38480:7;:17;38818:6:::1;::::0;-1:-1:-1;;;;;38818:6:0::1;38804:10;:20;38800:44;;38833:11;;-1:-1:-1::0;;;38833:11:0::1;;;;;;;;;;;38800:44;-1:-1:-1::0;;;;;102329:28:0;::::2;102325:59;;102366:18;;-1:-1:-1::0;;;102366:18:0::2;;;;;;;;;;;102325:59;102399:17;::::0;-1:-1:-1;;;;;102399:17:0::2;:31:::0;102395:73:::2;;102439:29;;-1:-1:-1::0;;;102439:29:0::2;;;;;;;;;;;102395:73;102479:17;:34:::0;;-1:-1:-1;;;;;;102479:34:0::2;-1:-1:-1::0;;;;;102479:34:0;;;::::2;::::0;;;::::2;::::0;;-1:-1:-1;;38646:21:0;102237:284::o;49651:146::-;36420:1;38319:7;;:18;38315:88;;38361:30;;-1:-1:-1;;;38361:30:0;;;;;;;;;;;38315:88;36420:1;38480:7;:17;38818:6:::1;::::0;-1:-1:-1;;;;;38818:6:0::1;38804:10;:20;38800:44;;38833:11;;-1:-1:-1::0;;;38833:11:0::1;;;;;;;;;;;38800:44;49754:35:::2;49780:8;49754:25;:35::i;:::-;-1:-1:-1::0;36377:1:0;38646:7;:21;49651:146::o;117407:1578::-;117481:22;;;;;117697:208;117726:76;117755:13;;;;:4;:13;:::i;:::-;117741:29;;;:::i;:::-;117786:13;;;;:4;:13;:::i;:::-;117772:29;;;:::i;:::-;119130:13;119224:15;;;119260:4;119253:15;119307:4;119291:21;;;119062:268;117726:76;117818;117847:13;;;;:4;:13;:::i;:::-;117833:29;;;:::i;:::-;117878:13;;;;:4;:13;:::i;117697:208::-;117674:231;-1:-1:-1;117969:17:0;117989:178;118018:84;118047:18;;;;:4;:18;:::i;:::-;118033:34;;;:::i;:::-;118083:16;;;;:4;:16;:::i;118018:84::-;118134:20;;;;;;;;:::i;:::-;118126:29;;119130:13;119224:15;;;119260:4;119253:15;119307:4;119291:21;;;119062:268;117989:178;117969:198;-1:-1:-1;118250:18:0;118271:164;118300:69;-1:-1:-1;;;118354:12:0;;;;:4;:12;:::i;118300:69::-;119130:13;119224:15;;;119260:4;119253:15;;;119307:4;119291:21;;118385:39;119062:268;118271:164;118250:185;;118513:47;-1:-1:-1;;;118549:10:0;119130:13;119224:15;;;119260:4;119253:15;119307:4;119291:21;;;119062:268;118513:47;118496:64;;118648:56;-1:-1:-1;;;118689:14:0;119130:13;119224:15;;;119260:4;119253:15;119307:4;119291:21;;;119062:268;118648:56;118626:78;;118782:51;-1:-1:-1;;;118818:14:0;119130:13;119224:15;;;119260:4;119253:15;119307:4;119291:21;;;119062:268;118782:51;118765:68;;118921:56;-1:-1:-1;;;118962:14:0;119130:13;119224:15;;;119260:4;119253:15;119307:4;119291:21;;;119062:268;118921:56;118899:78;;117620:1365;;;117407:1578;;;;;:::o;110667:743::-;110849:9;110844:246;110864:18;;;;:4;:18;:::i;:::-;:25;;110860:1;:29;110844:246;;;110953:18;;;;:4;:18;:::i;:::-;110972:1;110953:21;;;;;;;:::i;:::-;:38;;;:21;;;;;:38;;;;-1:-1:-1;110953:38:0;:::i;:::-;110911:36;;;;:22;:36;;;;;;;;:39;;;;;;;;:80;;-1:-1:-1;;;;;;110911:80:0;-1:-1:-1;;;;;110911:80:0;;;;;;;;;;111046:18;;;;;;:::i;:::-;111065:1;111046:21;;;;;;;:::i;:::-;111006:34;;;;:20;111046:32;111006:34;;;111046:21;111006:34;;;:37;;;;;;;;;111046:21;;;;;;;;:32;;111006:72;;;-1:-1:-1;110891:3:0;;110844:246;;;;111107:9;111102:301;111122:29;;;;:4;:29;:::i;:::-;:36;;111118:1;:40;111102:301;;;111233:29;;;;:4;:29;:::i;:::-;111263:1;111233:32;;;;;;;:::i;:::-;:49;;;:32;;;;;:49;;;;-1:-1:-1;111233:49:0;:::i;:::-;111180:47;;;;:33;:47;;;;;;;;:50;;;;;;;;:102;;-1:-1:-1;;;;;;111180:102:0;-1:-1:-1;;;;;111180:102:0;;;;;;;;;;111348:29;;;;;;:::i;:::-;111378:1;111348:32;;;;;;;:::i;:::-;111297:45;;;;:31;111348:43;111297:45;;;111348:32;111297:45;;;:48;;;;;;;;;111348:32;;;;;;;;:43;;111297:94;;;-1:-1:-1;111160:3:0;;111102:301;;;;110667:743;;:::o;50546:156::-;50636:13;50629:20;;-1:-1:-1;;;;;;50629:20:0;;;50660:34;50685:8;50660:24;:34::i;:::-;50546:156;:::o;111453:701::-;111524:30;111740:33;;;:19;:33;;;;;:48;;;;111804;;;;111868:26;;111909:54;;;;111979:47;;;;111702:335;;111524:30;;111702:335;;111740:48;111804;-1:-1:-1;;;;;111868:26:0;;;;111909:54;;;111702:335;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:23;:335::i;:::-;112119:26;;112055:91;;;-1:-1:-1;;;;;12208:15:1;;;12190:34;;12260:15;;;12255:2;12240:18;;12233:43;112119:26:0;;;12292:18:1;;;12285:43;111651:386:0;;-1:-1:-1;111651:386:0;-1:-1:-1;112055:91:0;;12140:2:1;12125:18;112055:91:0;;;;;;;;111453:701;;;:::o;112194:696::-;112265:30;112478:33;;;:19;:33;;;;;:48;;112542;;;;112606:26;;112647:54;;;;112717:47;;;;112440:335;;112265:30;;112440:335;;112478:48;112542;-1:-1:-1;;;;;112606:26:0;;;;112647:54;;;112440:335;;;:::i;:::-;112855:26;;112793:89;;;-1:-1:-1;;;;;12208:15:1;;;12190:34;;12260:15;;;12255:2;12240:18;;12233:43;112855:26:0;;;12292:18:1;;;12285:43;112389:386:0;;-1:-1:-1;112389:386:0;-1:-1:-1;112793:89:0;;12140:2:1;12125:18;112793:89:0;11950:384:1;113608:647:0;113695:9;113708:33;;;:19;:33;;;;;:52;;;;;113841:48;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;113841:48:0;;;;;;;;;;;;;;;;113779:110;;113907:9;113902:271;113922:1;113918;:5;113902:271;;;113961:200;;;;;;;;-1:-1:-1;114038:36:0;;;:22;:36;;;;;;;:39;;;;;;;;;-1:-1:-1;;;;;114038:39:0;113961:200;;114108:34;;;:20;:34;;;;;:37;;;;;;;;;113961:200;;;;;;;113945:13;;:10;;114075:1;;113945:13;;;;;;:::i;:::-;;;;;;;;;;:216;113925:3;;113902:271;;;-1:-1:-1;114185:62:0;;-1:-1:-1;;;114185:62:0;;-1:-1:-1;;;;;114185:50:0;;;;;:62;;114236:10;;114185:62;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;113684:571;;113608:647;;:::o;112898:702::-;112996:9;113009:33;;;:19;:33;;;;;:63;;;;;113153:48;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;113153:48:0;;;;;;;;;;;;;;;;113091:110;;113219:9;113214:293;113234:1;113230;:5;113214:293;;;113273:222;;;;;;;;-1:-1:-1;113350:47:0;;;:33;:47;;;;;;;:50;;;;;;;;;-1:-1:-1;;;;;113350:50:0;113273:222;;113431:45;;;:31;:45;;;;;:48;;;;;;;;;113273:222;;;;;;;113257:13;;:10;;113398:1;;113257:13;;;;;;:::i;:::-;;;;;;;;;;:238;113237:3;;113214:293;;;-1:-1:-1;113519:73:0;;-1:-1:-1;;;113519:73:0;;-1:-1:-1;;;;;113519:61:0;;;;;:73;;113581:10;;113519:73;;;:::i;50096:260::-;-1:-1:-1;;;;;50174:22:0;;;;50173:55;;-1:-1:-1;;;;;;50202:25:0;;50222:4;50202:25;50173:55;50169:84;;;50237:16;;-1:-1:-1;;;50237:16:0;;;;;;;;;;;50169:84;50266:13;:24;;-1:-1:-1;;;;;;50266:24:0;-1:-1:-1;;;;;50266:24:0;;;;;;;;;-1:-1:-1;50331:6:0;50306:42;;50266:24;;50331:6;;50306:42;;-1:-1:-1;;50306:42:0;50096:260;:::o;39398:261::-;-1:-1:-1;;;;;39476:22:0;;39472:57;;39507:22;;-1:-1:-1;;;39507:22:0;;;;;;;;;;;39472:57;39561:6;;;-1:-1:-1;;;;;39578:17:0;;;-1:-1:-1;;;;;;39578:17:0;;;;;;;39611:40;;39561:6;;;39578:17;39561:6;;39611:40;;39542:16;;39611:40;39461:198;39398:261;:::o;114263:1327::-;114483:7;114492;114591:25;114618;114647:73;114669:9;114680;114691:18;114711:8;114647:21;:73::i;:::-;114590:130;;;;114836:1;114804:17;-1:-1:-1;;;;;114804:29:0;;:33;114803:74;;;;114875:1;114843:17;-1:-1:-1;;;;;114843:29:0;;:33;114803:74;114799:108;;;114886:21;;-1:-1:-1;;;114886:21:0;;;;;;;;;;;114799:108;114955:37;115031:9;114995:48;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;114955:88;;115084:17;-1:-1:-1;;;;;115058:43:0;115066:13;-1:-1:-1;;;;;115058:43:0;;115054:84;;115110:28;;-1:-1:-1;;;115110:28:0;;;;;;;;;;;115054:84;115192:33;115268:9;115279:18;115307:13;115323:8;115228:104;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;115192:140;;115365:17;-1:-1:-1;;;;;115347:35:0;115355:5;-1:-1:-1;;;;;115347:35:0;;115343:71;;115391:23;;-1:-1:-1;;;115391:23:0;;;;;;;;;;;115343:71;115477:47;;-1:-1:-1;;;115477:47:0;;-1:-1:-1;;;;;287:32:1;;;115477:47:0;;;269:51:1;115477:31:0;;;;;242:18:1;;115477:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;115545:17:0;;115564;;-1:-1:-1;114263:1327:0;;-1:-1:-1;;;;;;;;;;;114263:1327:0:o;116047:923::-;116247:25;116284;116440:4;116433:12;;116455:4;116462:9;116483:42;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;116473:53;;;;;;116416:111;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;116406:122;;;;;;116364:195;;116328:233;;116686:4;116679:12;;116701:4;116708:9;116784:46;;;;;;;;:::i;:::-;-1:-1:-1;;116784:46:0;;;;;;;;;;;;;;;;116832:59;;116843:18;;116863:17;;116882:8;;116784:46;116832:59;;:::i;:::-;;;;-1:-1:-1;;116832:59:0;;;;;;;;;;116767:125;;;116832:59;116767:125;;:::i;:::-;;;;;;;;;;;;;116719:208;;;;;;116662:266;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;116652:277;;;;;;116610:350;;116574:388;;116047:923;;;;;;;:::o;-1:-1:-1:-;;;;;;;;:::o;:::-;;;;;;;;:::o;:::-;;;;;;;;:::o;:::-;;;;;;;;:::o;:::-;;;;;;;;:::o;331:286:1:-;390:6;443:2;431:9;422:7;418:23;414:32;411:52;;;459:1;456;449:12;411:52;485:23;;-1:-1:-1;;;;;537:31:1;;527:42;;517:70;;583:1;580;573:12;517:70;606:5;331:286;-1:-1:-1;;;331:286:1:o;622:384::-;705:6;758:2;746:9;737:7;733:23;729:32;726:52;;;774:1;771;764:12;726:52;814:9;801:23;847:18;839:6;836:30;833:50;;;879:1;876;869:12;833:50;902:22;;958:3;940:16;;;936:26;933:46;;;975:1;972;965:12;1385:180;1444:6;1497:2;1485:9;1476:7;1472:23;1468:32;1465:52;;;1513:1;1510;1503:12;1465:52;-1:-1:-1;1536:23:1;;1385:180;-1:-1:-1;1385:180:1:o;2445:114::-;2529:4;2522:5;2518:16;2511:5;2508:27;2498:55;;2549:1;2546;2539:12;2564:243;2621:6;2674:2;2662:9;2653:7;2649:23;2645:32;2642:52;;;2690:1;2687;2680:12;2642:52;2729:9;2716:23;2748:29;2771:5;2748:29;:::i;2812:232::-;2851:3;2872:17;;;2869:140;;2931:10;2926:3;2922:20;2919:1;2912:31;2966:4;2963:1;2956:15;2994:4;2991:1;2984:15;2869:140;-1:-1:-1;3036:1:1;3025:13;;2812:232::o;3049:583::-;3180:4;3186:6;3246:11;3233:25;3340:2;3336:7;3325:8;3309:14;3305:29;3301:43;3281:18;3277:68;3267:96;;3359:1;3356;3349:12;3267:96;3386:33;;3438:20;;;-1:-1:-1;3481:18:1;3470:30;;3467:50;;;3513:1;3510;3503:12;3467:50;3546:4;3534:17;;-1:-1:-1;3597:1:1;3593:14;;;3577;3573:35;3563:46;;3560:66;;;3622:1;3619;3612:12;3560:66;3049:583;;;;;:::o;3637:522::-;3715:4;3721:6;3781:11;3768:25;3875:2;3871:7;3860:8;3844:14;3840:29;3836:43;3816:18;3812:68;3802:96;;3894:1;3891;3884:12;3802:96;3921:33;;3973:20;;;-1:-1:-1;4016:18:1;4005:30;;4002:50;;;4048:1;4045;4038:12;4002:50;4081:4;4069:17;;-1:-1:-1;4112:14:1;4108:27;;;4098:38;;4095:58;;;4149:1;4146;4139:12;4164:267;4253:6;4248:3;4241:19;4305:6;4298:5;4291:4;4286:3;4282:14;4269:43;-1:-1:-1;4357:1:1;4332:16;;;4350:4;4328:27;;;4321:38;;;;4413:2;4392:15;;;-1:-1:-1;;4388:29:1;4379:39;;;4375:50;;4164:267::o;4436:614::-;-1:-1:-1;;;;;4705:32:1;;4687:51;;4786:4;4774:17;;4769:2;4754:18;;4747:45;4828:3;4823:2;4808:18;;4801:31;;;-1:-1:-1;;4855:63:1;;4898:19;;4890:6;4882;4855:63;:::i;:::-;4966:9;4958:6;4954:22;4949:2;4938:9;4934:18;4927:50;4994;5037:6;5029;5021;4994:50;:::i;:::-;4986:58;4436:614;-1:-1:-1;;;;;;;;;4436:614:1:o;5055:273::-;5111:6;5164:2;5152:9;5143:7;5139:23;5135:32;5132:52;;;5180:1;5177;5170:12;5132:52;5219:9;5206:23;5272:5;5265:13;5258:21;5251:5;5248:32;5238:60;;5294:1;5291;5284:12;5333:127;5394:10;5389:3;5385:20;5382:1;5375:31;5425:4;5422:1;5415:15;5449:4;5446:1;5439:15;5465:380;5544:1;5540:12;;;;5587;;;5608:61;;5662:4;5654:6;5650:17;5640:27;;5608:61;5715:2;5707:6;5704:14;5684:18;5681:38;5678:161;;5761:10;5756:3;5752:20;5749:1;5742:31;5796:4;5793:1;5786:15;5824:4;5821:1;5814:15;5678:161;;5465:380;;;:::o;5975:517::-;6076:2;6071:3;6068:11;6065:421;;;6112:5;6109:1;6102:16;6156:4;6153:1;6143:18;6226:2;6214:10;6210:19;6207:1;6203:27;6197:4;6193:38;6262:4;6250:10;6247:20;6244:47;;;-1:-1:-1;6285:4:1;6244:47;6340:2;6335:3;6331:12;6328:1;6324:20;6318:4;6314:31;6304:41;;6395:81;6413:2;6406:5;6403:13;6395:81;;;6472:1;6458:16;;6439:1;6428:13;6395:81;;;6399:3;;5975:517;;;:::o;6668:1341::-;6792:3;6786:10;6819:18;6811:6;6808:30;6805:56;;;6841:18;;:::i;:::-;6870:96;6959:6;6919:38;6951:4;6945:11;6919:38;:::i;:::-;6913:4;6870:96;:::i;:::-;7021:4;;7078:2;7067:14;;7095:1;7090:662;;;;7796:1;7813:6;7810:89;;;-1:-1:-1;7865:19:1;;;7859:26;7810:89;-1:-1:-1;;6625:1:1;6621:11;;;6617:24;6613:29;6603:40;6649:1;6645:11;;;6600:57;7912:81;;7060:943;;7090:662;5922:1;5915:14;;;5959:4;5946:18;;-1:-1:-1;;7126:20:1;;;7243:236;7257:7;7254:1;7251:14;7243:236;;;7346:19;;;7340:26;7325:42;;7438:27;;;;7406:1;7394:14;;;;7273:19;;7243:236;;;7247:3;7507:6;7498:7;7495:19;7492:201;;;7568:19;;;7562:26;-1:-1:-1;;7651:1:1;7647:14;;;7663:3;7643:24;7639:37;7635:42;7620:58;7605:74;;7492:201;;;7739:1;7730:6;7727:1;7723:14;7719:22;7713:4;7706:36;7060:943;;;;;6668:1341;;:::o;8014:247::-;8082:6;8135:2;8123:9;8114:7;8110:23;8106:32;8103:52;;;8151:1;8148;8141:12;8103:52;8183:9;8177:16;8202:29;8225:5;8202:29;:::i;8866:127::-;8927:10;8922:3;8918:20;8915:1;8908:31;8958:4;8955:1;8948:15;8982:4;8979:1;8972:15;8998:465;9051:3;9089:5;9083:12;9116:6;9111:3;9104:19;9142:4;9171;9166:3;9162:14;9155:21;;9210:4;9203:5;9199:16;9233:1;9243:195;9257:6;9254:1;9251:13;9243:195;;;9322:13;;-1:-1:-1;;;;;9318:39:1;9306:52;;9378:12;;;;9413:15;;;;9354:1;9272:9;9243:195;;;-1:-1:-1;9454:3:1;;8998:465;-1:-1:-1;;;;;8998:465:1:o;9468:::-;9725:2;9714:9;9707:21;9688:4;9751:56;9803:2;9792:9;9788:18;9780:6;9751:56;:::i;:::-;9855:9;9847:6;9843:22;9838:2;9827:9;9823:18;9816:50;9883:44;9920:6;9912;9883:44;:::i;:::-;9875:52;9468:465;-1:-1:-1;;;;;9468:465:1:o;9938:1747::-;10084:4;10126:3;10115:9;10111:19;10103:27;;10163:6;10157:13;10146:9;10139:32;10227:4;10219:6;10215:17;10209:24;10202:4;10191:9;10187:20;10180:54;10290:4;10282:6;10278:17;10272:24;10265:4;10254:9;10250:20;10243:54;10353:4;10345:6;10341:17;10335:24;10328:4;10317:9;10313:20;10306:54;10416:4;10408:6;10404:17;10398:24;10391:4;10380:9;10376:20;10369:54;10479:4;10471:6;10467:17;10461:24;10454:4;10443:9;10439:20;10432:54;10542:4;10534:6;10530:17;10524:24;10517:4;10506:9;10502:20;10495:54;10605:4;10597:6;10593:17;10587:24;10580:4;10569:9;10565:20;10558:54;10631:6;10691:2;10683:6;10679:15;10673:22;10668:2;10657:9;10653:18;10646:50;;10715:6;10768:2;10760:6;10756:15;10750:22;10781:52;10829:2;10818:9;10814:18;10800:12;-1:-1:-1;;;;;80:31:1;68:44;;14:104;10781:52;-1:-1:-1;;10852:6:1;10895:15;;;10889:22;-1:-1:-1;;;;;80:31:1;;;10955:18;;;68:44;;;;10993:6;11036:15;;;11030:22;80:31;;11096:18;;;68:44;11134:6;11177:15;;;11171:22;80:31;;11237:18;;;68:44;11275:6;11318:15;;;11312:22;80:31;;11378:18;;;68:44;11416:6;11459:15;;;11453:22;80:31;;11519:18;;;68:44;11557:6;11600:15;;;11594:22;80:31;11660:18;;;;68:44;;;;9938:1747;:::o;11690:255::-;11810:19;;11849:2;11841:11;;11838:101;;;-1:-1:-1;;11910:2:1;11906:12;;;11903:1;11899:20;11895:33;11884:45;11838:101;11690:255;;;;:::o;12339:836::-;12582:2;12634:21;;;12704:13;;12607:18;;;12726:22;;;12553:4;;12582:2;12767;;12785:18;;;;12826:15;;;12553:4;12869:280;12883:6;12880:1;12877:13;12869:280;;;12942:13;;12984:9;;-1:-1:-1;;;;;12980:35:1;12968:48;;13056:11;;13050:18;13036:12;;;13029:40;13089:12;;;;13124:15;;;;13012:1;12898:9;12869:280;;;-1:-1:-1;13166:3:1;;12339:836;-1:-1:-1;;;;;;;12339:836:1:o;13180:250::-;13265:1;13275:113;13289:6;13286:1;13283:13;13275:113;;;13365:11;;;13359:18;13346:11;;;13339:39;13311:2;13304:10;13275:113;;;-1:-1:-1;;13422:1:1;13404:16;;13397:27;13180:250::o;13435:594::-;13601:4;13647:1;13643;13638:3;13634:11;13630:19;13688:2;13680:6;13676:15;13665:9;13658:34;13740:2;13732:6;13728:15;13723:2;13712:9;13708:18;13701:43;;13780:2;13775;13764:9;13760:18;13753:30;13812:6;13806:13;13855:6;13850:2;13839:9;13835:18;13828:34;13871:80;13944:6;13938:3;13927:9;13923:19;13918:2;13910:6;13906:15;13871:80;:::i;:::-;14012:2;13991:15;-1:-1:-1;;13987:29:1;13972:45;;;;14019:3;13968:55;;13435:594;-1:-1:-1;;;;13435:594:1:o;14034:441::-;-1:-1:-1;;;;;;14257:26:1;;;;14245:39;;14321:2;14317:15;;;;-1:-1:-1;;14313:53:1;14309:1;14300:11;;14293:74;14392:2;14383:12;;14376:28;14429:2;14420:12;;14413:28;14466:2;14457:12;;14034:441::o;14480:492::-;14655:3;14693:6;14687:13;14709:66;14768:6;14763:3;14756:4;14748:6;14744:17;14709:66;:::i;:::-;14838:13;;14797:16;;;;14860:70;14838:13;14797:16;14907:4;14895:17;;14860:70;:::i;:::-;14946:20;;14480:492;-1:-1:-1;;;;14480:492:1:o
Swarm Source
ipfs://14ba4a2fae7d0111bac55f469a6089f1db93f2f00a8b5010ff0260101e66edb7
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in MON
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.