Source Code
Latest 25 from a total of 18,869 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Swap And Deposit | 12344115 | 429 days ago | IN | 0.0002 ETH | 0.00006802 | ||||
| Swap In Same Cha... | 12339039 | 429 days ago | IN | 0 ETH | 0.00009219 | ||||
| Swap And Deposit | 12323519 | 429 days ago | IN | 0 ETH | 0.00017975 | ||||
| Swap In Same Cha... | 12322765 | 429 days ago | IN | 0 ETH | 0.0002723 | ||||
| Swap And Deposit | 12319006 | 429 days ago | IN | 0.011 ETH | 0.00024019 | ||||
| Swap In Same Cha... | 12314125 | 429 days ago | IN | 0.00057063 ETH | 0.00055904 | ||||
| Swap And Deposit | 12311697 | 429 days ago | IN | 0.00061802 ETH | 0.00001685 | ||||
| Swap And Deposit | 12311381 | 429 days ago | IN | 0.00070568 ETH | 0.0000187 | ||||
| Swap And Deposit | 12310703 | 429 days ago | IN | 0.028 ETH | 0.00021222 | ||||
| Swap In Same Cha... | 12309332 | 430 days ago | IN | 0.00110442 ETH | 0.00008177 | ||||
| Swap In Same Cha... | 12308356 | 430 days ago | IN | 0.00123246 ETH | 0.00002764 | ||||
| Swap In Same Cha... | 12301757 | 430 days ago | IN | 0.00322 ETH | 0.00003862 | ||||
| Swap In Same Cha... | 12301271 | 430 days ago | IN | 0.00102815 ETH | 0.0000615 | ||||
| Swap And Deposit | 12299916 | 430 days ago | IN | 0.15 ETH | 0.00002588 | ||||
| Swap In Same Cha... | 12298331 | 430 days ago | IN | 0 ETH | 0.00002704 | ||||
| Swap In Same Cha... | 12289385 | 430 days ago | IN | 0 ETH | 0.00002068 | ||||
| Swap In Same Cha... | 12287047 | 430 days ago | IN | 0.00215705 ETH | 0.00001956 | ||||
| Swap In Same Cha... | 12286112 | 430 days ago | IN | 0 ETH | 0.00004656 | ||||
| Swap In Same Cha... | 12278491 | 430 days ago | IN | 0.00237943 ETH | 0.00024998 | ||||
| Swap In Same Cha... | 12277616 | 430 days ago | IN | 0.0006713 ETH | 0.00014217 | ||||
| Swap In Same Cha... | 12276006 | 430 days ago | IN | 0 ETH | 0.00029268 | ||||
| Swap In Same Cha... | 12273574 | 430 days ago | IN | 0 ETH | 0.00022595 | ||||
| Swap In Same Cha... | 12273552 | 430 days ago | IN | 0.0005218 ETH | 0.00040387 | ||||
| Swap In Same Cha... | 12267635 | 430 days ago | IN | 0 ETH | 0.0000967 | ||||
| Swap And Deposit | 12265683 | 431 days ago | IN | 0 ETH | 0.00020012 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 12344115 | 429 days ago | 0 ETH | ||||
| 12344115 | 429 days ago | 0 ETH | ||||
| 12344115 | 429 days ago | 0 ETH | ||||
| 12344115 | 429 days ago | 0 ETH | ||||
| 12344115 | 429 days ago | 0 ETH | ||||
| 12344115 | 429 days ago | 0 ETH | ||||
| 12344115 | 429 days ago | 0 ETH | ||||
| 12344115 | 429 days ago | 0 ETH | ||||
| 12344115 | 429 days ago | 0 ETH | ||||
| 12344115 | 429 days ago | 0.0002 ETH | ||||
| 12341785 | 429 days ago | 0 ETH | ||||
| 12341785 | 429 days ago | 0 ETH | ||||
| 12341785 | 429 days ago | 0 ETH | ||||
| 12341785 | 429 days ago | 0 ETH | ||||
| 12341785 | 429 days ago | 0 ETH | ||||
| 12341785 | 429 days ago | 0 ETH | ||||
| 12341785 | 429 days ago | 0 ETH | ||||
| 12341785 | 429 days ago | 0 ETH | ||||
| 12341785 | 429 days ago | 0 ETH | ||||
| 12341785 | 429 days ago | 0.0049975 ETH | ||||
| 12341785 | 429 days ago | 0 ETH | ||||
| 12341785 | 429 days ago | 0.0049975 ETH | ||||
| 12339039 | 429 days ago | 0.00094703 ETH | ||||
| 12339039 | 429 days ago | 0.00094703 ETH | ||||
| 12339039 | 429 days ago | 0 ETH |
Cross-Chain Transactions
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:
DexSpan
Compiler Version
v0.8.20+commit.a1b79de6
Contract Source Code (Solidity)
/**
*Submitted for verification at lineascan.build/ on 2024-03-18
*/
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
// OpenZeppelin Contracts (last updated v4.9.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);
}
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
// OpenZeppelin Contracts (last updated v4.9.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.8.0/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);
}
}
}
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @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);
}
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
// OpenZeppelin Contracts (last updated v4.9.4) (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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
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) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 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 256, 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);
}
}
}
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
// OpenZeppelin Contracts (last updated v4.9.5) (utils/Multicall.sol)
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* Consider any assumption about calldata validation performed by the sender may be violated if it's not especially
* careful about sending transactions invoking {multicall}. For example, a relay address that filters function
* selectors won't filter calls nested within a {multicall} operation.
*
* NOTE: Since 5.0.1 and 4.9.4, this contract identifies non-canonical contexts (i.e. `msg.sender` is not {_msgSender}).
* If a non-canonical context is identified, the following self `delegatecall` appends the last bytes of `msg.data`
* to the subcall. This makes it safe to use with {ERC2771Context}. Contexts that don't affect the resolution of
* {_msgSender} are not propagated to subcalls.
*
* _Available since v4.1._
*/
abstract contract Multicall is Context {
/**
* @dev Receives and executes a batch of function calls on this contract.
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
bytes memory context = msg.sender == _msgSender()
? new bytes(0)
: msg.data[msg.data.length - _contextSuffixLength():];
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = Address.functionDelegateCall(address(this), bytes.concat(data[i], context));
}
return results;
}
}
interface IUniswapExchange {
function getEthToTokenInputPrice(
uint256 ethSold
) external view returns (uint256 tokensBought);
function getTokenToEthInputPrice(
uint256 tokensSold
) external view returns (uint256 ethBought);
function ethToTokenSwapInput(
uint256 minTokens,
uint256 deadline
) external payable returns (uint256 tokensBought);
function tokenToEthSwapInput(
uint256 tokensSold,
uint256 minEth,
uint256 deadline
) external returns (uint256 ethBought);
function tokenToTokenSwapInput(
uint256 tokensSold,
uint256 minTokensBought,
uint256 minEthBought,
uint256 deadline,
address tokenAddr
) external returns (uint256 tokensBought);
}
interface IUniswapFactory {
function getExchange(
IERC20Upgradeable token
) external view returns (IUniswapExchange exchange);
}
// OpenZeppelin Contracts (last updated v4.9.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) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 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 256, 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);
}
}
}
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
library SafeMathUpgradeable {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20PermitUpgradeable {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @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.8.0/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);
}
}
}
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20Upgradeable {
using AddressUpgradeable for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20PermitUpgradeable token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));
}
}
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
function safeApprove(address token, address to, uint256 value) internal {
// bytes4(keccak256(bytes('approve(address,uint256)')));
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0x095ea7b3, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper::safeApprove: approve failed"
);
}
function safeTransfer(address token, address to, uint256 value) internal {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0xa9059cbb, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper::safeTransfer: transfer failed"
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0x23b872dd, from, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper::transferFrom: transferFrom failed"
);
}
}
library UniversalERC20 {
using SafeMathUpgradeable for uint256;
using SafeERC20Upgradeable for IERC20Upgradeable;
IERC20Upgradeable private constant ZERO_ADDRESS =
IERC20Upgradeable(0x0000000000000000000000000000000000000000);
IERC20Upgradeable private constant ETH_ADDRESS =
IERC20Upgradeable(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
function universalTransfer(
IERC20Upgradeable token,
address to,
uint256 amount
) internal returns (bool) {
if (amount == 0) {
return true;
}
if (isETH(token)) {
(bool success, ) = payable(address(uint160(to))).call{
value: amount
}("");
assert(success == true);
} else {
TransferHelper.safeTransfer(address(token), to, amount);
return true;
}
}
function universalTransferFrom(
IERC20Upgradeable token,
address from,
address to,
uint256 amount
) internal {
if (amount == 0) {
return;
}
if (isETH(token)) {
require(
from == msg.sender && msg.value >= amount,
"Wrong usage of ETH.universalTransferFrom()"
);
if (to != address(this)) {
(bool success, ) = payable(address(uint160(to))).call{
value: amount
}("");
assert(success == true);
}
if (msg.value > amount) {
(bool success, ) = payable(msg.sender).call{
value: msg.value.sub(amount)
}("");
assert(success == true);
}
} else {
TransferHelper.safeTransferFrom(address(token), from, to, amount);
}
}
function universalTransferFromSenderToThis(
IERC20Upgradeable token,
uint256 amount
) internal {
if (amount == 0) {
return;
}
if (isETH(token)) {
if (msg.value > amount) {
// Return remainder if exist
(bool success, ) = payable(msg.sender).call{
value: msg.value.sub(amount)
}("");
assert(success == true);
}
} else {
TransferHelper.safeTransferFrom(
address(token),
msg.sender,
address(this),
amount
);
}
}
function universalApprove(
IERC20Upgradeable token,
address to,
uint256 amount
) internal {
if (!isETH(token)) {
// if (amount == 0) {
// TransferHelper.safeApprove(address(token), to, 0);
// return;
// }
// uint256 allowance = token.allowance(address(this), to);
// if (allowance < amount) {
// if (allowance > 0) {
// TransferHelper.safeApprove(address(token), to, 0);
// }
// TransferHelper.safeApprove(address(token), to, amount);
// }
TransferHelper.safeApprove(address(token), to, 0);
TransferHelper.safeApprove(address(token), to, amount);
}
}
function universalBalanceOf(
IERC20Upgradeable token,
address who
) internal view returns (uint256) {
if (isETH(token)) {
return who.balance;
} else {
return token.balanceOf(who);
}
}
function isETH(IERC20Upgradeable token) internal pure returns (bool) {
return (address(token) == address(ZERO_ADDRESS) ||
address(token) == address(ETH_ADDRESS));
}
function eq(
IERC20Upgradeable a,
IERC20Upgradeable b
) internal pure returns (bool) {
return a == b || (isETH(a) && isETH(b));
}
}
interface IUniswapV2Exchange {
function getReserves()
external
view
returns (
uint112 _reserve0,
uint112 _reserve1,
uint32 _blockTimestampLast
);
function swap(
uint256 amount0Out,
uint256 amount1Out,
address to,
bytes calldata data
) external;
function skim(address to) external;
function sync() external;
}
library UniswapV2ExchangeLib {
using MathUpgradeable for uint256;
using SafeMathUpgradeable for uint256;
using UniversalERC20 for IERC20Upgradeable;
function getReturn(
IUniswapV2Exchange exchange,
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint256 amountIn
) internal view returns (uint256 result, bool needSync, bool needSkim) {
uint256 reserveIn = fromToken.universalBalanceOf(address(exchange));
uint256 reserveOut = destToken.universalBalanceOf(address(exchange));
(uint112 reserve0, uint112 reserve1, ) = exchange.getReserves();
if (fromToken > destToken) {
(reserve0, reserve1) = (reserve1, reserve0);
}
needSync = (reserveIn < reserve0 || reserveOut < reserve1);
needSkim = !needSync && (reserveIn > reserve0 || reserveOut > reserve1);
uint256 amountInWithFee = amountIn.mul(997);
uint256 numerator = amountInWithFee.mul(
MathUpgradeable.min(reserveOut, reserve1)
);
uint256 denominator = MathUpgradeable
.min(reserveIn, reserve0)
.mul(1000)
.add(amountInWithFee);
result = (denominator == 0) ? 0 : numerator.div(denominator);
}
}
interface IUniswapV2Factory {
function getPair(
IERC20Upgradeable tokenA,
IERC20Upgradeable tokenB
) external view returns (IUniswapV2Exchange pair);
}
interface IHandlerReserve {
function _lpToContract(address token) external returns (address);
function _contractToLP(address token) external returns (address);
}
interface IEthHandler {
function withdraw(address WETH, uint256) external;
}
contract DexSpanFlags {
// flags = FLAG_DISABLE_UNISWAP + FLAG_DISABLE_BANCOR + ...
uint256 internal constant FLAG_DISABLE_UNISWAP = 0x400;
uint256 internal constant FLAG_DISABLE_SPLIT_RECALCULATION = 0x800000000000;
uint256 internal constant FLAG_DISABLE_ALL_SPLIT_SOURCES = 0x20000000;
uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ALL = 0x400;
uint256 internal constant FLAG_DISABLE_EMPTY = 0x100000000000;
uint256 internal constant FLAG_DISABLE_DFYN = 0x800;
uint256 internal constant FLAG_DISABLE_PANCAKESWAP = 0x80;
uint256 internal constant FLAG_DISABLE_QUICKSWAP = 0x40000000000;
uint256 internal constant FLAG_DISABLE_SUSHISWAP = 0x1000000;
uint256 internal constant FLAG_DISABLE_ONEINCH = 0x100000;
}
abstract contract IDexSpan is DexSpanFlags {
function getExpectedReturn(
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint256 amount,
uint256 parts,
uint256 flags // See constants in IOneSplit.sol
)
public
view
virtual
returns (uint256 returnAmount, uint256[] memory distribution);
function getExpectedReturnWithGasMulti(
IERC20Upgradeable[] memory tokens,
uint256 amount,
uint256[] memory parts,
uint256[] memory flags,
uint256[] memory destTokenEthPriceTimesGasPrices
)
public
view
virtual
returns (
uint256[] memory returnAmounts,
uint256 estimateGasAmount,
uint256[] memory distribution
);
function getExpectedReturnWithGas(
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint256 amount,
uint256 parts,
uint256 flags, // See constants in IOneSplit.sol
uint256 destTokenEthPriceTimesGasPrice
)
public
view
virtual
returns (
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
);
function setHandlerAddress(
address _handlerAddress
) external virtual returns (bool);
function setReserveAddress(
address _reserveAddress
) external virtual returns (bool);
function setBridgeAddress(
address _bridgeAddress
) external virtual returns (bool);
function withdraw(
address tokenAddress,
address recipient,
uint256 amount
) public payable virtual returns (bool);
function swap(
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint256 amount,
uint256 minReturn,
uint256 flags,
bytes memory dataTx,
bool isWrapper
) public payable virtual returns (uint256 returnAmount);
function swapWithRecipient(
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint256 amount,
uint256 minReturn,
uint256 flags,
bytes memory dataTx,
bool isWrapper,
address recipient
) public payable virtual returns (uint256 returnAmount);
function swapMulti(
IERC20Upgradeable[] memory tokens,
uint256 amount,
uint256 minReturn,
uint256[] memory flags,
bytes[] memory dataTx,
bool isWrapper
) public payable virtual returns (uint256 returnAmount);
function swapMultiWithRecipient(
IERC20Upgradeable[] memory tokens,
uint256 amount,
uint256 minReturn,
uint256[] memory flags,
bytes[] memory dataTx,
bool isWrapper,
address recipient
) public payable virtual returns (uint256 returnAmount);
function getExpectedReturnETH(
IERC20Upgradeable srcStablefromtoken,
uint256 srcStableFromTokenAmount,
uint256 parts,
uint256 flags
) public view virtual returns (uint256 returnAmount);
}
abstract contract IWETH is IERC20Upgradeable {
function deposit() external payable virtual;
function withdraw(uint256 amount) external virtual;
}
// import "./libraries/Multicall.sol";
interface IAugustusSwapper {
function getTokenTransferProxy() external view returns (address);
}
/// @title Interface for handler contracts that support deposits and deposit executions.
/// @author Router Protocol.
interface IAssetForwarder {
event FundsDeposited(
uint256 partnerId,
uint256 amount,
bytes32 destChainIdBytes,
uint256 destAmount,
uint256 depositId,
address srcToken,
address depositor,
bytes recipient,
bytes destToken
);
event iUSDCDeposited(
uint256 partnerId,
uint256 amount,
bytes32 destChainIdBytes,
uint256 usdcNonce,
address srcToken,
bytes32 recipient,
address depositor
);
event FundsDepositedWithMessage(
uint256 partnerId,
uint256 amount,
bytes32 destChainIdBytes,
uint256 destAmount,
uint256 depositId,
address srcToken,
bytes recipient,
address depositor,
bytes destToken,
bytes message
);
event FundsPaid(bytes32 messageHash, address forwarder, uint256 nonce);
event DepositInfoUpdate(
address srcToken,
uint256 feeAmount,
uint256 depositId,
uint256 eventNonce,
bool initiatewithdrawal,
address depositor
);
event FundsPaidWithMessage(
bytes32 messageHash,
address forwarder,
uint256 nonce,
bool execFlag,
bytes execData
);
struct DestDetails {
uint32 domainId;
uint256 fee;
bool isSet;
}
struct RelayData {
uint256 amount;
bytes32 srcChainId;
uint256 depositId;
address destToken;
address recipient;
}
struct RelayDataMessage {
uint256 amount;
bytes32 srcChainId;
uint256 depositId;
address destToken;
address recipient;
bytes message;
}
struct DepositData {
uint256 partnerId;
uint256 amount;
uint256 destAmount;
address srcToken;
address refundRecipient;
bytes32 destChainIdBytes;
}
function iDepositUSDC(
uint256 partnerId,
bytes32 destChainIdBytes,
bytes32 recipient,
uint256 amount
) external payable;
function iDeposit(
DepositData memory depositData,
bytes memory destToken,
bytes memory recipient
) external payable;
function iDepositInfoUpdate(
address srcToken,
uint256 feeAmount,
uint256 depositId,
bool initiatewithdrawal
) external payable;
function iDepositMessage(
DepositData memory depositData,
bytes memory destToken,
bytes memory recipient,
bytes memory message
) external payable;
function iRelay(RelayData memory relayData) external payable;
function iRelayMessage(RelayDataMessage memory relayData) external payable;
}
/// @title Handles ERC20 deposits and deposit executions.
/// @author Router Protocol.
/// @notice This contract is intended to be used with the Bridge contract.
interface IMessageHandler {
function handleMessage(
address tokenSent,
uint256 amount,
bytes memory message
) external;
}
abstract contract IDexSpanView is DexSpanFlags {
function getExpectedReturn(
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint256 amount,
uint256 parts,
uint256 flags
)
public
view
virtual
returns (uint256 returnAmount, uint256[] memory distribution);
function getExpectedReturnWithGas(
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
virtual
returns (
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
);
}
library DisableFlags {
function check(uint256 flags, uint256 flag) internal pure returns (bool) {
return (flags & flag) != 0;
}
}
contract DexSpanRoot {
using SafeMath for uint256;
using DisableFlags for uint256;
using UniversalERC20 for IERC20Upgradeable;
using UniversalERC20 for IWETH;
using UniswapV2ExchangeLib for IUniswapV2Exchange;
uint256 internal constant DEXES_COUNT = 4;
uint256 internal constant DEXES_COUNT_UPDATED = 1;
IERC20Upgradeable internal ZERO_ADDRESS;
int256 internal constant VERY_NEGATIVE_VALUE = -1e72;
IWETH public wnativeAddress;
IERC20Upgradeable public nativeAddress;
function _findBestDistribution(
uint256 s, // parts
int256[][] memory amounts // exchangesReturns
)
internal
pure
returns (int256 returnAmount, uint256[] memory distribution)
{
uint256 n = amounts.length;
int256[][] memory answer = new int256[][](n); // int[n][s+1]
uint256[][] memory parent = new uint256[][](n); // int[n][s+1]
for (uint256 i; i < n; i++) {
answer[i] = new int256[](s + 1);
parent[i] = new uint256[](s + 1);
}
for (uint256 j; j <= s; j++) {
answer[0][j] = amounts[0][j];
for (uint256 i = 1; i < n; i++) {
answer[i][j] = -1e72;
}
parent[0][j] = 0;
}
for (uint256 i = 1; i < n; i++) {
for (uint256 j; j <= s; j++) {
answer[i][j] = answer[i - 1][j];
parent[i][j] = j;
for (uint256 k = 1; k <= j; k++) {
if (answer[i - 1][j - k] + amounts[i][k] > answer[i][j]) {
answer[i][j] = answer[i - 1][j - k] + amounts[i][k];
parent[i][j] = j - k;
}
}
}
}
distribution = new uint256[](DEXES_COUNT_UPDATED);
uint256 partsLeft = s;
for (uint256 curExchange = n - 1; partsLeft > 0; curExchange--) {
distribution[curExchange] =
partsLeft -
parent[curExchange][partsLeft];
partsLeft = parent[curExchange][partsLeft];
}
returnAmount = (answer[n - 1][s] == VERY_NEGATIVE_VALUE)
? int256(0)
: answer[n - 1][s];
}
}
contract DexSpan is DexSpanFlags, DexSpanRoot, AccessControl, Multicall {
using UniversalERC20 for IERC20Upgradeable;
using SafeMath for uint256;
using DisableFlags for uint256;
using UniswapV2ExchangeLib for IUniswapV2Exchange;
IAssetForwarder public assetForwarder;
address public assetBridge;
address public univ2SkimAddress;
address public newOwner;
// IWETH public wnativeAddress;
mapping(uint256 => address) public flagToAddress;
event Swap(
string indexed funcName,
IERC20Upgradeable[] tokenPath,
uint256 amount,
address indexed sender,
address indexed receiver,
uint256 finalAmt,
uint256[] flags,
uint256 widgetID
);
event SwapWithRecipient(
string indexed funcName,
IERC20Upgradeable[] tokenPath,
uint256 amount,
address indexed sender,
address indexed receiver,
uint256 finalAmt,
uint256[] flags,
uint256 widgetID
);
event SwapOnSameChain(
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint amount,
bytes _data,
uint256 flags
);
event SetAssetForwarder(address assetForwarder, address admin);
event SetAssetBridge(address assetBridge, address admin);
event SetFlagToFactory(uint flag, address factoryAddress);
event SetFactorySetter(address factorySetter);
event SetWNativeAddresses(address wrappedNative);
event TransferOwnership(address newOwner);
event ClaimOwnership(address newOwner);
error InavlidPool();
error InavlidCaller();
error ZeroAddress();
error ZeroFlag();
error InvalidCaller();
error RestrictNativeToken();
error WrongTokenSent();
error WrongDataLength();
error AmountTooLow();
error ExcecutionFailed();
error AlreadyFactorySetter();
struct DexesArgs {
IERC20Upgradeable factoryAddress;
uint256 _exchangeCode;
}
struct SwapParams {
IERC20Upgradeable[] tokens;
uint256 amount;
uint256 minReturn;
uint256[] flags;
bytes[] dataTx;
bool isWrapper;
address recipient;
bytes destToken;
}
bytes32 public constant FACTORY_SETTER_ROLE =
keccak256("FACTORY_SETTER_ROLE");
bytes4 internal constant SWAP_MULTI_WITH_RECEPIENT_SELECTOR = 0xe738aa8d;
receive() external payable {}
constructor(
address _assetForwarderAddress,
address _native,
address _wrappedNative,
address _univ2SkimAddress
) {
if (_assetForwarderAddress == address(0)) revert ZeroAddress();
if (_native == address(0)) revert ZeroAddress();
if (_wrappedNative == address(0)) revert ZeroAddress();
if (_univ2SkimAddress == address(0)) revert ZeroAddress();
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
assetForwarder = IAssetForwarder(_assetForwarderAddress);
nativeAddress = IERC20Upgradeable(_native);
wnativeAddress = IWETH(_wrappedNative);
univ2SkimAddress = _univ2SkimAddress;
}
function transferOwnership(
address _newOwner
) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (_newOwner == address(0)) revert ZeroAddress();
newOwner = _newOwner;
emit TransferOwnership(_newOwner);
}
function claimOwnership() external {
if (newOwner != msg.sender) {
revert InavlidCaller();
}
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
emit ClaimOwnership(msg.sender);
}
function setAssetForwarder(
address _forwarder
) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (_forwarder == address(0)) revert ZeroAddress();
assetForwarder = IAssetForwarder(_forwarder);
emit SetAssetForwarder(_forwarder, msg.sender);
}
function setAssetBridge(
address _assetBridge
) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (_assetBridge == address(0)) revert ZeroAddress();
assetBridge = _assetBridge;
emit SetAssetBridge(_assetBridge, msg.sender);
}
function setFlagToFactoryAddress(
uint256 _flagCode,
address _factoryAddress
) external onlyRole(FACTORY_SETTER_ROLE) {
if (_flagCode == 0) revert ZeroFlag();
if (_factoryAddress == address(0)) revert ZeroAddress();
flagToAddress[_flagCode] = address(_factoryAddress);
emit SetFlagToFactory(_flagCode, _factoryAddress);
}
function setFactorySetter(
address _factorySetter
) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (_factorySetter == address(0)) revert ZeroAddress();
if (hasRole(FACTORY_SETTER_ROLE, _factorySetter))
revert AlreadyFactorySetter();
_setupRole(FACTORY_SETTER_ROLE, _factorySetter);
emit SetFactorySetter(_factorySetter);
}
function setWNativeAddresses(
address _native,
address _wrappedNative
) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (_native == address(0)) revert ZeroAddress();
if (_wrappedNative == address(0)) revert ZeroAddress();
nativeAddress = IERC20Upgradeable(_native);
wnativeAddress = IWETH(_wrappedNative);
emit SetWNativeAddresses(_wrappedNative);
}
function handleMessage(
address _tokenSent,
uint256 _amount,
bytes memory message
) external {
if (
msg.sender != address(assetForwarder) &&
msg.sender != address(assetBridge)
) revert InvalidCaller();
messageHandler(_tokenSent, _amount, message);
}
function swapInSameChain(
IERC20Upgradeable[] memory tokens,
uint256 amount,
uint256 minReturn,
uint256[] memory flags,
bytes[] memory dataTx,
bool isWrapper,
address recipient,
uint256 widgetID
) public payable returns (uint256 returnAmount) {
returnAmount = swapMultiWithRecipient(
tokens,
amount,
minReturn,
flags,
dataTx,
isWrapper,
recipient
);
emit Swap(
"swapInSameChain",
tokens,
amount,
msg.sender,
recipient,
returnAmount,
flags,
widgetID
);
}
function swapMultiWithRecipient(
IERC20Upgradeable[] memory tokens,
uint256 amount,
uint256 minReturn,
uint256[] memory flags,
bytes[] memory dataTx,
bool isWrapper,
address recipient
) public payable returns (uint256 returnAmount) {
returnAmount = _swapMultiInternal(
tokens,
amount,
minReturn,
flags,
dataTx,
isWrapper,
recipient
);
emit SwapWithRecipient(
"swapMultiWithRecipient",
tokens,
amount,
msg.sender,
recipient,
returnAmount,
flags,
0
);
}
function swapAndDeposit(
uint256 partnerId,
bytes32 destChainIdBytes,
bytes calldata recipient,
uint8 depositType,
uint256 feeAmount,
bytes memory message,
SwapParams memory swapData,
address refundRecipient
) public payable {
_swapMultiInternal(
swapData.tokens,
swapData.amount,
swapData.minReturn,
swapData.flags,
swapData.dataTx,
swapData.isWrapper,
address(this)
);
IERC20Upgradeable reserveToken = swapData.tokens[
swapData.tokens.length - 1
];
// swapAndDeposit
if (depositType == 0) {
uint256 amount = reserveToken.universalBalanceOf(address(this));
reserveToken.universalApprove(address(assetForwarder), amount);
assetForwarder.iDeposit{value: reserveToken.isETH() ? amount : 0}(
IAssetForwarder.DepositData(
partnerId,
amount,
amount - feeAmount,
address(reserveToken),
refundRecipient,
destChainIdBytes
),
swapData.destToken,
recipient
);
return;
}
// swapAndDepositWithMessage
if (depositType == 1) {
uint256 amount = reserveToken.universalBalanceOf(address(this));
reserveToken.universalApprove(
address(assetForwarder),
swapData.minReturn
);
assetForwarder.iDepositMessage{
value: reserveToken.isETH() ? amount : 0
}(
IAssetForwarder.DepositData(
partnerId,
swapData.minReturn,
swapData.minReturn - feeAmount,
address(reserveToken),
refundRecipient,
destChainIdBytes
),
swapData.destToken,
recipient,
message
);
if (amount > swapData.minReturn) {
reserveToken.universalTransfer(
refundRecipient,
amount - swapData.minReturn
);
}
return;
}
// swapAndDepositUSDC : Circle Flow
if (depositType == 2) {
//NOTE: here reserveToken should be usdc
uint256 amount = reserveToken.universalBalanceOf(address(this));
reserveToken.universalApprove(address(assetForwarder), amount);
// any extra fee will be left over here
assetForwarder.iDepositUSDC{value: msg.value}(
partnerId,
destChainIdBytes,
bytes32(recipient),
amount
);
return;
}
}
function messageHandler(
address _tokenSent,
uint256 _amount,
bytes memory message
) internal {
(
IERC20Upgradeable[] memory tokens,
uint256 minReturn,
bytes[] memory dataTx,
uint256[] memory flags,
address recipient,
bool isInstruction,
bytes memory instruction
) = abi.decode(
message,
(
IERC20Upgradeable[],
uint256,
bytes[],
uint256[],
address,
bool,
bytes
)
);
if (_tokenSent != address(tokens[0])) revert WrongTokenSent();
bytes memory execData;
bool execFlag;
(execFlag, execData) = address(this).call(
abi.encodeWithSelector(
SWAP_MULTI_WITH_RECEPIENT_SELECTOR,
tokens,
_amount,
minReturn,
flags,
dataTx,
true,
recipient
)
);
if (!execFlag) {
tokens[0].universalTransfer(recipient, _amount);
}
if (isInstruction) {
uint256 finalAmount = execFlag
? uint256(bytes32(execData))
: _amount;
address finalToken = execFlag
? address(tokens[tokens.length - 1])
: _tokenSent;
(execFlag, execData) = recipient.call(
abi.encodeWithSelector(
IMessageHandler.handleMessage.selector,
finalToken,
finalAmount,
instruction
)
);
}
}
function _swapMultiInternal(
IERC20Upgradeable[] memory tokens,
uint256 amount,
uint256 minReturn,
uint256[] memory flags,
bytes[] memory dataTx,
bool isWrapper,
address recipient
) internal returns (uint256 returnAmount) {
if (recipient == address(0)) revert ZeroAddress();
if (tokens.length - 1 != flags.length) {
revert WrongDataLength();
}
if (!isWrapper) {
if (!tokens[0].isETH() && msg.value != 0) {
revert RestrictNativeToken();
}
tokens[0].universalTransferFrom(msg.sender, address(this), amount);
}
returnAmount = tokens[0].universalBalanceOf(address(this));
IERC20Upgradeable destinationToken = tokens[tokens.length - 1];
for (uint256 i = 1; i < tokens.length; i++) {
if (tokens[i - 1] == tokens[i]) {
continue;
}
returnAmount = _swapFloor(
tokens[i - 1],
tokens[i],
returnAmount,
0,
flags[i - 1],
dataTx[i - 1]
);
}
if (destinationToken.isETH()) {
returnAmount = wnativeAddress.balanceOf(address(this));
wnativeAddress.withdraw(returnAmount);
}
if (recipient != address(this)) {
uint256 userBalanceOld = destinationToken.universalBalanceOf(
recipient
);
destinationToken.universalTransfer(recipient, returnAmount);
uint256 userBalanceNew = destinationToken.universalBalanceOf(
recipient
);
uint receivedTokens = userBalanceNew - userBalanceOld;
if (receivedTokens <= minReturn) {
revert AmountTooLow();
}
returnAmount = receivedTokens;
}
}
function _swapFloor(
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint256 amount,
uint256 minReturn,
uint256 flags,
bytes memory _data
) internal returns (uint returnAmount) {
returnAmount = _swap(
fromToken,
destToken,
amount,
minReturn,
flags,
_data
);
}
function _swap(
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint256 amount,
uint256 minReturn,
uint256 flags,
bytes memory _data
) internal returns (uint256 returnAmount) {
if (fromToken == destToken) {
return amount;
}
function(
IERC20Upgradeable,
IERC20Upgradeable,
uint256,
bytes memory,
uint256
) reserve = _getReserveExchange(flags);
uint256 remainingAmount = fromToken.universalBalanceOf(address(this));
reserve(fromToken, destToken, remainingAmount, _data, flags);
returnAmount = destToken.universalBalanceOf(address(this));
}
function _getReserveExchange(
uint256 flag
)
internal
pure
returns (
function(
IERC20Upgradeable,
IERC20Upgradeable,
uint256,
bytes memory,
uint256
)
)
{
if (flag < 0x03E9 && flag >= 0x0001) {
// 1 - 1000
return _swapOnUniswapV2;
} else if (flag == 0x07D2) {
return _swapOnParaswap; // 2002
} else if (flag == 0x03EA) {
return _swapOnOneInch; // 1002
} else if (flag == 0x0FA2) {
return _swapOnOpenocean; // 4002
} else if (flag == 0x0BBA) {
return _swapOnUniswapV3; // 3002
}
revert("RA: Exchange not found");
}
function _swapOnUniswapV2(
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint256 amount,
bytes memory _data,
uint256 flags
) internal {
_swapOnExchangeInternal(fromToken, destToken, amount, flags);
}
function _swapOnUniswapV3(
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint256 amount,
bytes memory _data,
uint256 flagCode
) internal {
if (_data.length < 0) {
revert WrongDataLength();
}
address uniswapv3router = flagToAddress[flagCode];
if (uniswapv3router == address(0)) {
revert ZeroAddress();
}
if (fromToken.isETH()) {
wnativeAddress.deposit{value: amount}();
}
IERC20Upgradeable fromTokenReal = fromToken.isETH()
? wnativeAddress
: fromToken;
fromTokenReal.universalApprove(address(uniswapv3router), amount);
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = address(uniswapv3router).call(_data);
if (!success) revert ExcecutionFailed();
}
function _swapOnOpenocean(
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint256 amount,
bytes memory _data,
uint256 flagCode
) internal {
if (_data.length < 0) {
revert WrongDataLength();
}
address openoceanSwap = flagToAddress[flagCode];
if (openoceanSwap == address(0)) {
revert ZeroAddress();
}
if (fromToken.isETH()) {
wnativeAddress.deposit{value: amount}();
}
IERC20Upgradeable fromTokenReal = fromToken.isETH()
? wnativeAddress
: fromToken;
fromTokenReal.universalApprove(address(openoceanSwap), amount);
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = address(openoceanSwap).call(_data);
if (!success) {
revert ExcecutionFailed();
}
}
function _swapOnOneInch(
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint256 amount,
bytes memory _data,
uint256 flagCode
) internal {
if (_data.length < 0) {
revert WrongDataLength();
}
address oneInchSwap = flagToAddress[flagCode];
if (oneInchSwap == address(0)) {
revert ZeroAddress();
}
if (fromToken.isETH()) {
wnativeAddress.deposit{value: amount}();
}
IERC20Upgradeable fromTokenReal = fromToken.isETH()
? wnativeAddress
: fromToken;
fromTokenReal.universalApprove(address(oneInchSwap), amount);
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = address(oneInchSwap).call(_data);
if (!success) {
revert ExcecutionFailed();
}
}
function _swapOnParaswap(
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint256 amount,
bytes memory _data,
uint256 flagCode
) internal {
if (_data.length < 0) {
revert WrongDataLength();
}
address paraswap = flagToAddress[flagCode];
if (paraswap == address(0)) {
revert ZeroAddress();
}
if (fromToken.isETH()) {
wnativeAddress.deposit{value: amount}();
}
IERC20Upgradeable fromTokenReal = fromToken.isETH()
? wnativeAddress
: fromToken;
fromTokenReal.universalApprove(
IAugustusSwapper(paraswap).getTokenTransferProxy(),
amount
);
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = address(paraswap).call(_data);
if (!success) {
revert ExcecutionFailed();
}
}
function _swapOnExchangeInternal(
IERC20Upgradeable fromToken,
IERC20Upgradeable destToken,
uint256 amount,
uint256 flagCode
) internal returns (uint256 returnAmount) {
if (fromToken.isETH()) {
wnativeAddress.deposit{value: amount}();
}
address dexAddress = flagToAddress[flagCode];
require(dexAddress != address(0), "RA: Exchange not found");
IUniswapV2Factory factory = IUniswapV2Factory(address(dexAddress));
IERC20Upgradeable fromTokenReal = fromToken.isETH()
? wnativeAddress
: fromToken;
IERC20Upgradeable toTokenReal = destToken.isETH()
? wnativeAddress
: destToken;
if (fromTokenReal == toTokenReal) {
return amount;
}
IUniswapV2Exchange pool = factory.getPair(fromTokenReal, toTokenReal);
if (address(pool) == address(0)) revert InavlidPool();
bool needSync;
bool needSkim;
(returnAmount, needSync, needSkim) = pool.getReturn(
fromTokenReal,
toTokenReal,
amount
);
if (needSync) {
pool.sync();
} else if (needSkim) {
pool.skim(univ2SkimAddress);
}
fromTokenReal.universalTransfer(address(pool), amount);
if (
uint256(uint160(address(fromTokenReal))) <
uint256(uint160(address(toTokenReal)))
) {
pool.swap(0, returnAmount, address(this), "");
} else {
pool.swap(returnAmount, 0, address(this), "");
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_assetForwarderAddress","type":"address"},{"internalType":"address","name":"_native","type":"address"},{"internalType":"address","name":"_wrappedNative","type":"address"},{"internalType":"address","name":"_univ2SkimAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyFactorySetter","type":"error"},{"inputs":[],"name":"AmountTooLow","type":"error"},{"inputs":[],"name":"ExcecutionFailed","type":"error"},{"inputs":[],"name":"InavlidCaller","type":"error"},{"inputs":[],"name":"InavlidPool","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"RestrictNativeToken","type":"error"},{"inputs":[],"name":"WrongDataLength","type":"error"},{"inputs":[],"name":"WrongTokenSent","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroFlag","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"ClaimOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"assetBridge","type":"address"},{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"SetAssetBridge","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"assetForwarder","type":"address"},{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"SetAssetForwarder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"factorySetter","type":"address"}],"name":"SetFactorySetter","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"flag","type":"uint256"},{"indexed":false,"internalType":"address","name":"factoryAddress","type":"address"}],"name":"SetFlagToFactory","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"wrappedNative","type":"address"}],"name":"SetWNativeAddresses","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"funcName","type":"string"},{"indexed":false,"internalType":"contract IERC20Upgradeable[]","name":"tokenPath","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"finalAmt","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"flags","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"widgetID","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20Upgradeable","name":"fromToken","type":"address"},{"indexed":false,"internalType":"contract IERC20Upgradeable","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"_data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"flags","type":"uint256"}],"name":"SwapOnSameChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"funcName","type":"string"},{"indexed":false,"internalType":"contract IERC20Upgradeable[]","name":"tokenPath","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"finalAmt","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"flags","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"widgetID","type":"uint256"}],"name":"SwapWithRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"TransferOwnership","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FACTORY_SETTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetBridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetForwarder","outputs":[{"internalType":"contract IAssetForwarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"flagToAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenSent","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"handleMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nativeAddress","outputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_assetBridge","type":"address"}],"name":"setAssetBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_forwarder","type":"address"}],"name":"setAssetForwarder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_factorySetter","type":"address"}],"name":"setFactorySetter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_flagCode","type":"uint256"},{"internalType":"address","name":"_factoryAddress","type":"address"}],"name":"setFlagToFactoryAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_native","type":"address"},{"internalType":"address","name":"_wrappedNative","type":"address"}],"name":"setWNativeAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"partnerId","type":"uint256"},{"internalType":"bytes32","name":"destChainIdBytes","type":"bytes32"},{"internalType":"bytes","name":"recipient","type":"bytes"},{"internalType":"uint8","name":"depositType","type":"uint8"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes","name":"message","type":"bytes"},{"components":[{"internalType":"contract IERC20Upgradeable[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"uint256[]","name":"flags","type":"uint256[]"},{"internalType":"bytes[]","name":"dataTx","type":"bytes[]"},{"internalType":"bool","name":"isWrapper","type":"bool"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"destToken","type":"bytes"}],"internalType":"struct DexSpan.SwapParams","name":"swapData","type":"tuple"},{"internalType":"address","name":"refundRecipient","type":"address"}],"name":"swapAndDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20Upgradeable[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"uint256[]","name":"flags","type":"uint256[]"},{"internalType":"bytes[]","name":"dataTx","type":"bytes[]"},{"internalType":"bool","name":"isWrapper","type":"bool"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"widgetID","type":"uint256"}],"name":"swapInSameChain","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20Upgradeable[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"uint256[]","name":"flags","type":"uint256[]"},{"internalType":"bytes[]","name":"dataTx","type":"bytes[]"},{"internalType":"bool","name":"isWrapper","type":"bool"},{"internalType":"address","name":"recipient","type":"address"}],"name":"swapMultiWithRecipient","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"univ2SkimAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wnativeAddress","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040523480156200001157600080fd5b5060405162004fd238038062004fd2833981016040819052620000349162000206565b6001600160a01b0384166200005c5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038316620000845760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038216620000ac5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038116620000d45760405163d92e233d60e01b815260040160405180910390fd5b620000e160003362000135565b600480546001600160a01b039586166001600160a01b031991821617909155600280549486169482169490941790935560018054928516928416929092179091556006805491909316911617905562000263565b62000141828262000145565b5050565b60008281526003602090815260408083206001600160a01b038516845290915290205460ff16620001415760008281526003602090815260408083206001600160a01b03851684529091529020805460ff19166001179055620001a53390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b80516001600160a01b03811681146200020157600080fd5b919050565b600080600080608085870312156200021d57600080fd5b6200022885620001e9565b93506200023860208601620001e9565b92506200024860408601620001e9565b91506200025860608601620001e9565b905092959194509250565b614d5f80620002736000396000f3fe6080604052600436106101b05760003560e01c806391d14854116100ec578063d00a2d5f1161008a578063da6689f011610064578063da6689f01461057e578063e2a4ac2d1461059e578063e738aa8d146105cb578063f2fde38b146105de57600080fd5b8063d00a2d5f14610511578063d4ee1d9014610531578063d547741f1461055e57600080fd5b8063a2625efc116100c6578063a2625efc14610454578063ac9650d814610481578063adb88982146104ae578063c75a57e4146104ce57600080fd5b806391d14854146103cc5780639e99ec391461041f578063a217fddf1461043f57600080fd5b8063248a9ca3116101595780632f2ff15d116101335780632f2ff15d1461034a57806336568abe1461036a5780634e71e0c81461038a5780637fe689171461039f57600080fd5b8063248a9ca31461029b578063285f94a0146102cb5780632e4763371461031d57600080fd5b8063169651601161018a578063169651601461024857806318137a4114610268578063183d9c951461028857600080fd5b806301ffc9a7146101bc57806306135b7c146101f1578063086efdc41461020657600080fd5b366101b757005b600080fd5b3480156101c857600080fd5b506101dc6101d7366004613a65565b6105fe565b60405190151581526020015b60405180910390f35b6102046101ff366004613eee565b610697565b005b34801561021257600080fd5b5061023a7fafffb39e42e2a1496bc4305c8783f904fa76641e3895205b6002a03336ee097581565b6040519081526020016101e8565b34801561025457600080fd5b50610204610263366004613fbd565b610ac3565b34801561027457600080fd5b50610204610283366004613fed565b610c01565b61023a61029636600461400a565b610cd9565b3480156102a757600080fd5b5061023a6102b63660046140d1565b60009081526003602052604090206001015490565b3480156102d757600080fd5b506005546102f89073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101e8565b34801561032957600080fd5b506002546102f89073ffffffffffffffffffffffffffffffffffffffff1681565b34801561035657600080fd5b50610204610365366004613fbd565b610d83565b34801561037657600080fd5b50610204610385366004613fbd565b610dad565b34801561039657600080fd5b50610204610e65565b3480156103ab57600080fd5b506004546102f89073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103d857600080fd5b506101dc6103e7366004613fbd565b600091825260036020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b34801561042b57600080fd5b5061020461043a366004613fed565b610ef6565b34801561044b57600080fd5b5061023a600081565b34801561046057600080fd5b506006546102f89073ffffffffffffffffffffffffffffffffffffffff1681565b34801561048d57600080fd5b506104a161049c3660046140ea565b610fc6565b6040516101e89190614222565b3480156104ba57600080fd5b506102046104c9366004613fed565b6110b9565b3480156104da57600080fd5b506102f86104e93660046140d1565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561051d57600080fd5b5061020461052c366004614235565b611200565b34801561053d57600080fd5b506007546102f89073ffffffffffffffffffffffffffffffffffffffff1681565b34801561056a57600080fd5b50610204610579366004613fbd565b611282565b34801561058a57600080fd5b5061020461059936600461428e565b6112a7565b3480156105aa57600080fd5b506001546102f89073ffffffffffffffffffffffffffffffffffffffff1681565b61023a6105d93660046142bc565b6113cf565b3480156105ea57600080fd5b506102046105f9366004613fed565b611479565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061069157507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6106be826000015183602001518460400151856060015186608001518760a0015130611544565b5081518051600091906106d3906001906143ae565b815181106106e3576106e36143c1565b602002602001015190508560ff1660000361084157600061071a73ffffffffffffffffffffffffffffffffffffffff831630611a5a565b6004549091506107449073ffffffffffffffffffffffffffffffffffffffff848116911683611b1f565b60045473ffffffffffffffffffffffffffffffffffffffff9081169063f452ed4d90610771908516611b43565b61077c57600061077e565b825b6040518060c001604052808f81526020018581526020018a866107a191906143ae565b81526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018e8152508760e001518d8d6040518663ffffffff1660e01b81526004016108089493929190614439565b6000604051808303818588803b15801561082157600080fd5b505af1158015610835573d6000803e3d6000fd5b50505050505050610ab8565b8560ff166001036109e457600061086e73ffffffffffffffffffffffffffffffffffffffff831630611a5a565b600454604086015191925061089d9173ffffffffffffffffffffffffffffffffffffffff858116921690611b1f565b60045473ffffffffffffffffffffffffffffffffffffffff90811690630421caf0906108ca908516611b43565b6108d55760006108d7565b825b6040518060c001604052808f8152602001886040015181526020018a896040015161090291906143ae565b81526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018e8152508760e001518d8d8b6040518763ffffffff1660e01b815260040161096b9594939291906144c0565b6000604051808303818588803b15801561098457600080fd5b505af1158015610998573d6000803e3d6000fd5b505050505083604001518111156109dd576109db838560400151836109bd91906143ae565b73ffffffffffffffffffffffffffffffffffffffff85169190611b96565b505b5050610ab8565b8560ff16600203610ab6576000610a1173ffffffffffffffffffffffffffffffffffffffff831630611a5a565b600454909150610a3b9073ffffffffffffffffffffffffffffffffffffffff848116911683611b1f565b60045473ffffffffffffffffffffffffffffffffffffffff16633e28c7d2348d8d610a668d8f614568565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815260048101939093526024830191909152604482015260648101859052608401610808565b505b505050505050505050565b7fafffb39e42e2a1496bc4305c8783f904fa76641e3895205b6002a03336ee0975610aed81611c48565b82600003610b27576040517f196de28b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216610b74576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526008602090815260409182902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86169081179091558251868152918201527f11f5b5361c420666dc3452b8107601e1702f94b951f15bd93c26262c8147874e91015b60405180910390a1505050565b6000610c0c81611c48565b73ffffffffffffffffffffffffffffffffffffffff8216610c59576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155604080519182523360208301527f61b6fe2922f0180b98d305419bf3dcf432f5d8df894388c61c1f599c2194ec1d91015b60405180910390a15050565b6000610cea898989898989896113cf565b6040517f73776170496e53616d65436861696e0000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8416903390600f0160405180910390207fe3716b48e7d01d727d68472c873c69c2c4407365e4f68b2b6c8dd4569cd16dc78c8c868c89604051610d6f959493929190614625565b60405180910390a498975050505050505050565b600082815260036020526040902060010154610d9e81611c48565b610da88383611c55565b505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610e57576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b610e618282611d49565b5050565b60075473ffffffffffffffffffffffffffffffffffffffff163314610eb6576040517f821de23100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ec1600033611e04565b6040513381527f85a8c8100c1d48466310240af79644f50cdae7d09cb4820d60dfc5b2462f0fd09060200160405180910390a1565b6000610f0181611c48565b73ffffffffffffffffffffffffffffffffffffffff8216610f4e576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155604080519182523360208301527f45085069ced50a4d2e82656a82ba8f5a1a28694489d8ea262252e40899a930a29101610ccd565b6040805160008152602081019091526060908267ffffffffffffffff811115610ff157610ff1613b06565b60405190808252806020026020018201604052801561102457816020015b606081526020019060019003908161100f5790505b50915060005b838110156110b15761108130868684818110611048576110486143c1565b905060200281019061105a9190614669565b8560405160200161106d939291906146ce565b604051602081830303815290604052611e0e565b838281518110611093576110936143c1565b602002602001018190525080806110a9906146f5565b91505061102a565b505092915050565b60006110c481611c48565b73ffffffffffffffffffffffffffffffffffffffff8216611111576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081527f3ab9add546f7e3b43565da9bc7e65e47b969d3856bb01a7dcac7bc8ff5080cbd602052604090205460ff1615611190576040517fe4e970d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111ba7fafffb39e42e2a1496bc4305c8783f904fa76641e3895205b6002a03336ee097583611e04565b60405173ffffffffffffffffffffffffffffffffffffffff831681527fd2b69bde5a989d23ef605a0dd4e0edf7662105058ab69f2559e482857b599ed890602001610ccd565b60045473ffffffffffffffffffffffffffffffffffffffff163314801590611240575060055473ffffffffffffffffffffffffffffffffffffffff163314155b15611277576040517f48f5c3ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610da8838383611e33565b60008281526003602052604090206001015461129d81611c48565b610da88383611d49565b60006112b281611c48565b73ffffffffffffffffffffffffffffffffffffffff83166112ff576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821661134c576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff8581167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316179092556001805492851692909116821790556040519081527fcc4166d40cf68104cdf710f65ce022efd296742868a22b42e4695f89b886363690602001610bf4565b60006113e088888888888888611544565b6040517f737761704d756c746957697468526563697069656e7400000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff831690339060160160405180910390207fc40fae9d5f584875c393ac222c6f88b6c9dced1e9cc6251483648ac2e902c8b08b8b868b6000604051611466959493929190614625565b60405180910390a4979650505050505050565b600061148481611c48565b73ffffffffffffffffffffffffffffffffffffffff82166114d1576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527fcfaaa26691e16e66e73290fc725eee1a6b4e0e693a1640484937aac25ffb55a490602001610ccd565b600073ffffffffffffffffffffffffffffffffffffffff8216611593576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8451600189516115a391906143ae565b146115da576040517fcc513c7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826116a257611618886000815181106115f5576115f56143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16611b43565b15801561162457503415155b1561165b576040517f694b150300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116a23330898b600081518110611674576116746143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff166121a6909392919063ffffffff16565b6116e530896000815181106116b9576116b96143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16611a5a90919063ffffffff16565b905060008860018a516116f891906143ae565b81518110611708576117086143c1565b602002602001015190506000600190505b895181101561183e57898181518110611734576117346143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168a60018361176091906143ae565b81518110611770576117706143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16031561182c576118298a6117a36001846143ae565b815181106117b3576117b36143c1565b60200260200101518b83815181106117cd576117cd6143c1565b60200260200101518560008b6001876117e691906143ae565b815181106117f6576117f66143c1565b60200260200101518b60018861180c91906143ae565b8151811061181c5761181c6143c1565b6020026020010151612386565b92505b80611836816146f5565b915050611719565b5061185e8173ffffffffffffffffffffffffffffffffffffffff16611b43565b1561197b576001546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa1580156118d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f5919061472d565b6001546040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905291935073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561196257600080fd5b505af1158015611976573d6000803e3d6000fd5b505050505b73ffffffffffffffffffffffffffffffffffffffff83163014611a4e5760006119ba73ffffffffffffffffffffffffffffffffffffffff831685611a5a565b90506119dd73ffffffffffffffffffffffffffffffffffffffff83168585611b96565b506000611a0073ffffffffffffffffffffffffffffffffffffffff841686611a5a565b90506000611a0e83836143ae565b9050898111611a49576040517f1fbaba3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b935050505b50979650505050505050565b6000611a6583611b43565b15611a88575073ffffffffffffffffffffffffffffffffffffffff811631610691565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301528416906370a0823190602401602060405180830381865afa158015611af4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b18919061472d565b9050610691565b611b2883611b43565b610da857611b38838360006123a1565b610da88383836123a1565b600073ffffffffffffffffffffffffffffffffffffffff82161580610691575073ffffffffffffffffffffffffffffffffffffffff821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b600081600003611ba857506001611c41565b611bb184611b43565b15611c325760008373ffffffffffffffffffffffffffffffffffffffff168360405160006040518083038185875af1925050503d8060008114611c10576040519150601f19603f3d011682016040523d82523d6000602084013e611c15565b606091505b5090915050600181151514611c2c57611c2c614746565b50611c41565b611c3d848484612537565b5060015b9392505050565b611c5281336126c6565b50565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610e6157600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611ceb3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610e6157600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b610e618282611c55565b6060611c418383604051806060016040528060278152602001614d0360279139612780565b600080600080600080600087806020019051810190611e52919061490f565b965096509650965096509650965086600081518110611e7357611e736143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff1614611edf576040517f198b098900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606060003073ffffffffffffffffffffffffffffffffffffffff1663e738aa8d60e01b8a8d8b8a8c60018c604051602401611f2097969594939291906149e7565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611fa99190614a5e565b6000604051808303816000865af19150503d8060008114611fe6576040519150601f19603f3d011682016040523d82523d6000602084013e611feb565b606091505b50925090508061203c5761203a858c8b60008151811061200d5761200d6143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16611b969092919063ffffffff16565b505b83156121985760008161204f578b612058565b61205883614a7a565b9050600082612067578d61208f565b8a60018c5161207691906143ae565b81518110612086576120866143c1565b60200260200101515b90508673ffffffffffffffffffffffffffffffffffffffff1663d00a2d5f60e01b8284886040516024016120c593929190614abf565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161214e9190614a5e565b6000604051808303816000865af19150503d806000811461218b576040519150601f19603f3d011682016040523d82523d6000602084013e612190565b606091505b509450925050505b505050505050505050505050565b8015612380576121b584611b43565b156123745773ffffffffffffffffffffffffffffffffffffffff8316331480156121df5750803410155b61226b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f57726f6e67207573616765206f66204554482e756e6976657273616c5472616e60448201527f7366657246726f6d2829000000000000000000000000000000000000000000006064820152608401610e4e565b73ffffffffffffffffffffffffffffffffffffffff821630146123005760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146122e2576040519150601f19603f3d011682016040523d82523d6000602084013e6122e7565b606091505b50909150506001811515146122fe576122fe614746565b505b8034111561236f576000336123153484612805565b604051600081818185875af1925050503d8060008114612351576040519150601f19603f3d011682016040523d82523d6000602084013e612356565b606091505b509091505060018115151461236d5761236d614746565b505b612380565b61238084848484612811565b50505050565b60006123968787878787876129b0565b979650505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905291516000928392908716916124389190614a5e565b6000604051808303816000865af19150503d8060008114612475576040519150601f19603f3d011682016040523d82523d6000602084013e61247a565b606091505b50915091508180156124a45750805115806124a45750808060200190518101906124a49190614afd565b612530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f5472616e7366657248656c7065723a3a73616665417070726f76653a2061707060448201527f726f7665206661696c65640000000000000000000000000000000000000000006064820152608401610e4e565b5050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905291516000928392908716916125ce9190614a5e565b6000604051808303816000865af19150503d806000811461260b576040519150601f19603f3d011682016040523d82523d6000602084013e612610565b606091505b509150915081801561263a57508051158061263a57508080602001905181019061263a9190614afd565b612530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f5472616e7366657248656c7065723a3a736166655472616e736665723a20747260448201527f616e73666572206661696c6564000000000000000000000000000000000000006064820152608401610e4e565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610e615761270681612a5c565b612711836020612a7b565b604051602001612722929190614b1a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a0000000000000000000000000000000000000000000000000000000008252610e4e91600401614b9b565b60606000808573ffffffffffffffffffffffffffffffffffffffff16856040516127aa9190614a5e565b600060405180830381855af49150503d80600081146127e5576040519150601f19603f3d011682016040523d82523d6000602084013e6127ea565b606091505b50915091506127fb86838387612cbe565b9695505050505050565b6000611c4182846143ae565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905291516000928392908816916128b09190614a5e565b6000604051808303816000865af19150503d80600081146128ed576040519150601f19603f3d011682016040523d82523d6000602084013e6128f2565b606091505b509150915081801561291c57508051158061291c57508080602001905181019061291c9190614afd565b6129a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f5472616e7366657248656c7065723a3a7472616e7366657246726f6d3a20747260448201527f616e7366657246726f6d206661696c65640000000000000000000000000000006064820152608401610e4e565b505050505050565b60008573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff16036129ec5750836127fb565b613a5b6129f884612d66565b90506000612a1c73ffffffffffffffffffffffffffffffffffffffff8a1630611a5a565b9050612a2f89898387898763ffffffff16565b612a4f73ffffffffffffffffffffffffffffffffffffffff891630611a5a565b9998505050505050505050565b606061069173ffffffffffffffffffffffffffffffffffffffff831660145b60606000612a8a836002614bae565b612a95906002614bc5565b67ffffffffffffffff811115612aad57612aad613b06565b6040519080825280601f01601f191660200182016040528015612ad7576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612b0e57612b0e6143c1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612b7157612b716143c1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000612bad846002614bae565b612bb8906001614bc5565b90505b6001811115612c55577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110612bf957612bf96143c1565b1a60f81b828281518110612c0f57612c0f6143c1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93612c4e81614bd8565b9050612bbb565b508315611c41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610e4e565b60608315612d54578251600003612d4d5773ffffffffffffffffffffffffffffffffffffffff85163b612d4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610e4e565b5081612d5e565b612d5e8383612e33565b949350505050565b613a5b6103e982108015612d7b575060018210155b15612d895750612e77919050565b816107d203612d9b5750612e83919050565b816103ea03612dad575061310c919050565b81610fa203612dbf575061310c919050565b81610bba03612dd1575061310c919050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52413a2045786368616e6765206e6f7420666f756e64000000000000000000006044820152606401610e4e565b815115612e435781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e4e9190614b9b565b6129a885858584613278565b60008181526008602052604090205473ffffffffffffffffffffffffffffffffffffffff1680612edf576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612efe8673ffffffffffffffffffffffffffffffffffffffff16611b43565b15612f8757600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f6d57600080fd5b505af1158015612f81573d6000803e3d6000fd5b50505050505b6000612fa88773ffffffffffffffffffffffffffffffffffffffff16611b43565b612fb25786612fcc565b60015473ffffffffffffffffffffffffffffffffffffffff165b905061305e8273ffffffffffffffffffffffffffffffffffffffff1663d2c4b5986040518163ffffffff1660e01b8152600401602060405180830381865afa15801561301c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130409190614c0d565b73ffffffffffffffffffffffffffffffffffffffff83169087611b1f565b60008273ffffffffffffffffffffffffffffffffffffffff16856040516130859190614a5e565b6000604051808303816000865af19150503d80600081146130c2576040519150601f19603f3d011682016040523d82523d6000602084013e6130c7565b606091505b5050905080613102576040517f5987947500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050505050565b60008181526008602052604090205473ffffffffffffffffffffffffffffffffffffffff1680613168576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6131878673ffffffffffffffffffffffffffffffffffffffff16611b43565b1561321057600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b1580156131f657600080fd5b505af115801561320a573d6000803e3d6000fd5b50505050505b60006132318773ffffffffffffffffffffffffffffffffffffffff16611b43565b61323b5786613255565b60015473ffffffffffffffffffffffffffffffffffffffff165b905061305e73ffffffffffffffffffffffffffffffffffffffff82168387611b1f565b60006132998573ffffffffffffffffffffffffffffffffffffffff16611b43565b1561332257600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b15801561330857600080fd5b505af115801561331c573d6000803e3d6000fd5b50505050505b60008281526008602052604090205473ffffffffffffffffffffffffffffffffffffffff16806133ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52413a2045786368616e6765206e6f7420666f756e64000000000000000000006044820152606401610e4e565b8060006133d073ffffffffffffffffffffffffffffffffffffffff8916611b43565b6133da57876133f4565b60015473ffffffffffffffffffffffffffffffffffffffff165b905060006134178873ffffffffffffffffffffffffffffffffffffffff16611b43565b613421578761343b565b60015473ffffffffffffffffffffffffffffffffffffffff165b90508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361347c5786945050505050612d5e565b6040517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff838116600483015282811660248301526000919085169063e6a4390590604401602060405180830381865afa1580156134f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135189190614c0d565b905073ffffffffffffffffffffffffffffffffffffffff8116613567576040517f1fcdbb0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008061358c73ffffffffffffffffffffffffffffffffffffffff841686868d61382b565b9199509250905081156135fe578273ffffffffffffffffffffffffffffffffffffffff1663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156135e157600080fd5b505af11580156135f5573d6000803e3d6000fd5b5050505061368a565b801561368a576006546040517fbc25cf7700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201529084169063bc25cf7790602401600060405180830381600087803b15801561367157600080fd5b505af1158015613685573d6000803e3d6000fd5b505050505b6136ab73ffffffffffffffffffffffffffffffffffffffff8616848c611b96565b508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161015613780576040517f022c0d9f000000000000000000000000000000000000000000000000000000008152600060048201819052602482018a905230604483015260806064830152608482015273ffffffffffffffffffffffffffffffffffffffff84169063022c0d9f9060a401600060405180830381600087803b15801561376357600080fd5b505af1158015613777573d6000803e3d6000fd5b5050505061381c565b6040517f022c0d9f0000000000000000000000000000000000000000000000000000000081526004810189905260006024820181905230604483015260806064830152608482015273ffffffffffffffffffffffffffffffffffffffff84169063022c0d9f9060a401600060405180830381600087803b15801561380357600080fd5b505af1158015613817573d6000803e3d6000fd5b505050505b50505050505050949350505050565b600080808061385073ffffffffffffffffffffffffffffffffffffffff881689611a5a565b9050600061387473ffffffffffffffffffffffffffffffffffffffff88168a611a5a565b90506000808a73ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156138c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138e89190614c48565b50915091508873ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff16111561392357905b816dffffffffffffffffffffffffffff168410806139505750806dffffffffffffffffffffffffffff1683105b9550851580156139885750816dffffffffffffffffffffffffffff168411806139885750806dffffffffffffffffffffffffffff1683115b94506000613998896103e5613a21565b905060006139c06139b986856dffffffffffffffffffffffffffff16613a2d565b8390613a21565b905060006139f4836139ee6103e86139e88b8a6dffffffffffffffffffffffffffff16613a2d565b90613a21565b90613a43565b90508015613a0b57613a068282613a4f565b613a0e565b60005b9950505050505050509450945094915050565b6000611c418284614bae565b6000818310613a3c5781611c41565b5090919050565b6000611c418284614bc5565b6000611c418284614c98565b613a63614cd3565b565b600060208284031215613a7757600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611c4157600080fd5b60008083601f840112613ab957600080fd5b50813567ffffffffffffffff811115613ad157600080fd5b602083019150836020828501011115613ae957600080fd5b9250929050565b803560ff81168114613b0157600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715613b5957613b59613b06565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ba657613ba6613b06565b604052919050565b600067ffffffffffffffff821115613bc857613bc8613b06565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613c0557600080fd5b8135613c18613c1382613bae565b613b5f565b818152846020838601011115613c2d57600080fd5b816020850160208301376000918101602001919091529392505050565b600067ffffffffffffffff821115613c6457613c64613b06565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff81168114611c5257600080fd5b600082601f830112613ca157600080fd5b81356020613cb1613c1383613c4a565b82815260059290921b84018101918181019086841115613cd057600080fd5b8286015b84811015613cf4578035613ce781613c6e565b8352918301918301613cd4565b509695505050505050565b600082601f830112613d1057600080fd5b81356020613d20613c1383613c4a565b82815260059290921b84018101918181019086841115613d3f57600080fd5b8286015b84811015613cf45780358352918301918301613d43565b600082601f830112613d6b57600080fd5b81356020613d7b613c1383613c4a565b82815260059290921b84018101918181019086841115613d9a57600080fd5b8286015b84811015613cf457803567ffffffffffffffff811115613dbe5760008081fd5b613dcc8986838b0101613bf4565b845250918301918301613d9e565b8015158114611c5257600080fd5b8035613b0181613dda565b8035613b0181613c6e565b60006101008284031215613e1157600080fd5b613e19613b35565b9050813567ffffffffffffffff80821115613e3357600080fd5b613e3f85838601613c90565b835260208401356020840152604084013560408401526060840135915080821115613e6957600080fd5b613e7585838601613cff565b60608401526080840135915080821115613e8e57600080fd5b613e9a85838601613d5a565b6080840152613eab60a08501613de8565b60a0840152613ebc60c08501613df3565b60c084015260e0840135915080821115613ed557600080fd5b50613ee284828501613bf4565b60e08301525092915050565b60008060008060008060008060006101008a8c031215613f0d57600080fd5b8935985060208a0135975060408a013567ffffffffffffffff80821115613f3357600080fd5b613f3f8d838e01613aa7565b9099509750879150613f5360608d01613af0565b965060808c0135955060a08c0135915080821115613f7057600080fd5b613f7c8d838e01613bf4565b945060c08c0135915080821115613f9257600080fd5b50613f9f8c828d01613dfe565b925050613fae60e08b01613df3565b90509295985092959850929598565b60008060408385031215613fd057600080fd5b823591506020830135613fe281613c6e565b809150509250929050565b600060208284031215613fff57600080fd5b8135611c4181613c6e565b600080600080600080600080610100898b03121561402757600080fd5b883567ffffffffffffffff8082111561403f57600080fd5b61404b8c838d01613c90565b995060208b0135985060408b0135975060608b013591508082111561406f57600080fd5b61407b8c838d01613cff565b965060808b013591508082111561409157600080fd5b5061409e8b828c01613d5a565b9450506140ad60a08a01613de8565b92506140bb60c08a01613df3565b915060e089013590509295985092959890939650565b6000602082840312156140e357600080fd5b5035919050565b600080602083850312156140fd57600080fd5b823567ffffffffffffffff8082111561411557600080fd5b818501915085601f83011261412957600080fd5b81358181111561413857600080fd5b8660208260051b850101111561414d57600080fd5b60209290920196919550909350505050565b60005b8381101561417a578181015183820152602001614162565b50506000910152565b6000815180845261419b81602086016020860161415f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015614215578284038952614203848351614183565b988501989350908401906001016141eb565b5091979650505050505050565b602081526000611c4160208301846141cd565b60008060006060848603121561424a57600080fd5b833561425581613c6e565b925060208401359150604084013567ffffffffffffffff81111561427857600080fd5b61428486828701613bf4565b9150509250925092565b600080604083850312156142a157600080fd5b82356142ac81613c6e565b91506020830135613fe281613c6e565b600080600080600080600060e0888a0312156142d757600080fd5b873567ffffffffffffffff808211156142ef57600080fd5b6142fb8b838c01613c90565b985060208a0135975060408a0135965060608a013591508082111561431f57600080fd5b61432b8b838c01613cff565b955060808a013591508082111561434157600080fd5b5061434e8a828b01613d5a565b93505060a088013561435f81613dda565b915060c088013561436f81613c6e565b8091505092959891949750929550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156106915761069161437f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60006101006144998388805182526020810151602083015260408101516040830152606081015173ffffffffffffffffffffffffffffffffffffffff8082166060850152806080840151166080850152505060a081015160a08301525050565b8060c08401526144ab81840187614183565b905082810360e08401526123968185876143f0565b60006101206145208389805182526020810151602083015260408101516040830152606081015173ffffffffffffffffffffffffffffffffffffffff8082166060850152806080840151166080850152505060a081015160a08301525050565b8060c084015261453281840188614183565b905082810360e08401526145478186886143f0565b905082810361010084015261455c8185614183565b98975050505050505050565b80356020831015610691577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b600081518084526020808501945080840160005b838110156145ea57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145b8565b509495945050505050565b600081518084526020808501945080840160005b838110156145ea57815187529582019590820190600101614609565b60a08152600061463860a08301886145a4565b866020840152856040840152828103606084015261465681866145f5565b9150508260808301529695505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261469e57600080fd5b83018035915067ffffffffffffffff8211156146b957600080fd5b602001915036819003821315613ae957600080fd5b8284823760008382016000815283516146eb81836020880161415f565b0195945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036147265761472661437f565b5060010190565b60006020828403121561473f57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b600082601f83011261478657600080fd5b81516020614796613c1383613c4a565b82815260059290921b840181019181810190868411156147b557600080fd5b8286015b84811015613cf45780516147cc81613c6e565b83529183019183016147b9565b600082601f8301126147ea57600080fd5b81516147f8613c1382613bae565b81815284602083860101111561480d57600080fd5b612d5e82602083016020870161415f565b600082601f83011261482f57600080fd5b8151602061483f613c1383613c4a565b82815260059290921b8401810191818101908684111561485e57600080fd5b8286015b84811015613cf457805167ffffffffffffffff8111156148825760008081fd5b6148908986838b01016147d9565b845250918301918301614862565b600082601f8301126148af57600080fd5b815160206148bf613c1383613c4a565b82815260059290921b840181019181810190868411156148de57600080fd5b8286015b84811015613cf457805183529183019183016148e2565b8051613b0181613c6e565b8051613b0181613dda565b600080600080600080600060e0888a03121561492a57600080fd5b875167ffffffffffffffff8082111561494257600080fd5b61494e8b838c01614775565b985060208a0151975060408a015191508082111561496b57600080fd5b6149778b838c0161481e565b965060608a015191508082111561498d57600080fd5b6149998b838c0161489e565b95506149a760808b016148f9565b94506149b560a08b01614904565b935060c08a01519150808211156149cb57600080fd5b506149d88a828b016147d9565b91505092959891949750929550565b60e0815260006149fa60e083018a6145a4565b8860208401528760408401528281036060840152614a1881886145f5565b90508281036080840152614a2c81876141cd565b94151560a0840152505073ffffffffffffffffffffffffffffffffffffffff9190911660c09091015295945050505050565b60008251614a7081846020870161415f565b9190910192915050565b80516020808301519190811015614ab9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000614af46060830184614183565b95945050505050565b600060208284031215614b0f57600080fd5b8151611c4181613dda565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351614b5281601785016020880161415f565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351614b8f81602884016020880161415f565b01602801949350505050565b602081526000611c416020830184614183565b80820281158282048414176106915761069161437f565b808201808211156106915761069161437f565b600081614be757614be761437f565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b600060208284031215614c1f57600080fd5b8151611c4181613c6e565b80516dffffffffffffffffffffffffffff81168114613b0157600080fd5b600080600060608486031215614c5d57600080fd5b614c6684614c2a565b9250614c7460208501614c2a565b9150604084015163ffffffff81168114614c8d57600080fd5b809150509250925092565b600082614cce577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052605160045260246000fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220f233254f60810fffa4df2aa6c8f504943466fc2c52e7fbcec0dda0e42998d42064736f6c634300081400330000000000000000000000008c4acd74ff4385f3b7911432fa6787aa14406f8b000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000e5d7c2a44ffddf6b295a15c148167daaaf5cf34f000000000000000000000000b1b64005b11350a94c4d069eff4215592d98f2e2
Deployed Bytecode
0x6080604052600436106101b05760003560e01c806391d14854116100ec578063d00a2d5f1161008a578063da6689f011610064578063da6689f01461057e578063e2a4ac2d1461059e578063e738aa8d146105cb578063f2fde38b146105de57600080fd5b8063d00a2d5f14610511578063d4ee1d9014610531578063d547741f1461055e57600080fd5b8063a2625efc116100c6578063a2625efc14610454578063ac9650d814610481578063adb88982146104ae578063c75a57e4146104ce57600080fd5b806391d14854146103cc5780639e99ec391461041f578063a217fddf1461043f57600080fd5b8063248a9ca3116101595780632f2ff15d116101335780632f2ff15d1461034a57806336568abe1461036a5780634e71e0c81461038a5780637fe689171461039f57600080fd5b8063248a9ca31461029b578063285f94a0146102cb5780632e4763371461031d57600080fd5b8063169651601161018a578063169651601461024857806318137a4114610268578063183d9c951461028857600080fd5b806301ffc9a7146101bc57806306135b7c146101f1578063086efdc41461020657600080fd5b366101b757005b600080fd5b3480156101c857600080fd5b506101dc6101d7366004613a65565b6105fe565b60405190151581526020015b60405180910390f35b6102046101ff366004613eee565b610697565b005b34801561021257600080fd5b5061023a7fafffb39e42e2a1496bc4305c8783f904fa76641e3895205b6002a03336ee097581565b6040519081526020016101e8565b34801561025457600080fd5b50610204610263366004613fbd565b610ac3565b34801561027457600080fd5b50610204610283366004613fed565b610c01565b61023a61029636600461400a565b610cd9565b3480156102a757600080fd5b5061023a6102b63660046140d1565b60009081526003602052604090206001015490565b3480156102d757600080fd5b506005546102f89073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101e8565b34801561032957600080fd5b506002546102f89073ffffffffffffffffffffffffffffffffffffffff1681565b34801561035657600080fd5b50610204610365366004613fbd565b610d83565b34801561037657600080fd5b50610204610385366004613fbd565b610dad565b34801561039657600080fd5b50610204610e65565b3480156103ab57600080fd5b506004546102f89073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103d857600080fd5b506101dc6103e7366004613fbd565b600091825260036020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b34801561042b57600080fd5b5061020461043a366004613fed565b610ef6565b34801561044b57600080fd5b5061023a600081565b34801561046057600080fd5b506006546102f89073ffffffffffffffffffffffffffffffffffffffff1681565b34801561048d57600080fd5b506104a161049c3660046140ea565b610fc6565b6040516101e89190614222565b3480156104ba57600080fd5b506102046104c9366004613fed565b6110b9565b3480156104da57600080fd5b506102f86104e93660046140d1565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561051d57600080fd5b5061020461052c366004614235565b611200565b34801561053d57600080fd5b506007546102f89073ffffffffffffffffffffffffffffffffffffffff1681565b34801561056a57600080fd5b50610204610579366004613fbd565b611282565b34801561058a57600080fd5b5061020461059936600461428e565b6112a7565b3480156105aa57600080fd5b506001546102f89073ffffffffffffffffffffffffffffffffffffffff1681565b61023a6105d93660046142bc565b6113cf565b3480156105ea57600080fd5b506102046105f9366004613fed565b611479565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061069157507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6106be826000015183602001518460400151856060015186608001518760a0015130611544565b5081518051600091906106d3906001906143ae565b815181106106e3576106e36143c1565b602002602001015190508560ff1660000361084157600061071a73ffffffffffffffffffffffffffffffffffffffff831630611a5a565b6004549091506107449073ffffffffffffffffffffffffffffffffffffffff848116911683611b1f565b60045473ffffffffffffffffffffffffffffffffffffffff9081169063f452ed4d90610771908516611b43565b61077c57600061077e565b825b6040518060c001604052808f81526020018581526020018a866107a191906143ae565b81526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018e8152508760e001518d8d6040518663ffffffff1660e01b81526004016108089493929190614439565b6000604051808303818588803b15801561082157600080fd5b505af1158015610835573d6000803e3d6000fd5b50505050505050610ab8565b8560ff166001036109e457600061086e73ffffffffffffffffffffffffffffffffffffffff831630611a5a565b600454604086015191925061089d9173ffffffffffffffffffffffffffffffffffffffff858116921690611b1f565b60045473ffffffffffffffffffffffffffffffffffffffff90811690630421caf0906108ca908516611b43565b6108d55760006108d7565b825b6040518060c001604052808f8152602001886040015181526020018a896040015161090291906143ae565b81526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018e8152508760e001518d8d8b6040518763ffffffff1660e01b815260040161096b9594939291906144c0565b6000604051808303818588803b15801561098457600080fd5b505af1158015610998573d6000803e3d6000fd5b505050505083604001518111156109dd576109db838560400151836109bd91906143ae565b73ffffffffffffffffffffffffffffffffffffffff85169190611b96565b505b5050610ab8565b8560ff16600203610ab6576000610a1173ffffffffffffffffffffffffffffffffffffffff831630611a5a565b600454909150610a3b9073ffffffffffffffffffffffffffffffffffffffff848116911683611b1f565b60045473ffffffffffffffffffffffffffffffffffffffff16633e28c7d2348d8d610a668d8f614568565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815260048101939093526024830191909152604482015260648101859052608401610808565b505b505050505050505050565b7fafffb39e42e2a1496bc4305c8783f904fa76641e3895205b6002a03336ee0975610aed81611c48565b82600003610b27576040517f196de28b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216610b74576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526008602090815260409182902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86169081179091558251868152918201527f11f5b5361c420666dc3452b8107601e1702f94b951f15bd93c26262c8147874e91015b60405180910390a1505050565b6000610c0c81611c48565b73ffffffffffffffffffffffffffffffffffffffff8216610c59576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155604080519182523360208301527f61b6fe2922f0180b98d305419bf3dcf432f5d8df894388c61c1f599c2194ec1d91015b60405180910390a15050565b6000610cea898989898989896113cf565b6040517f73776170496e53616d65436861696e0000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8416903390600f0160405180910390207fe3716b48e7d01d727d68472c873c69c2c4407365e4f68b2b6c8dd4569cd16dc78c8c868c89604051610d6f959493929190614625565b60405180910390a498975050505050505050565b600082815260036020526040902060010154610d9e81611c48565b610da88383611c55565b505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610e57576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b610e618282611d49565b5050565b60075473ffffffffffffffffffffffffffffffffffffffff163314610eb6576040517f821de23100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ec1600033611e04565b6040513381527f85a8c8100c1d48466310240af79644f50cdae7d09cb4820d60dfc5b2462f0fd09060200160405180910390a1565b6000610f0181611c48565b73ffffffffffffffffffffffffffffffffffffffff8216610f4e576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155604080519182523360208301527f45085069ced50a4d2e82656a82ba8f5a1a28694489d8ea262252e40899a930a29101610ccd565b6040805160008152602081019091526060908267ffffffffffffffff811115610ff157610ff1613b06565b60405190808252806020026020018201604052801561102457816020015b606081526020019060019003908161100f5790505b50915060005b838110156110b15761108130868684818110611048576110486143c1565b905060200281019061105a9190614669565b8560405160200161106d939291906146ce565b604051602081830303815290604052611e0e565b838281518110611093576110936143c1565b602002602001018190525080806110a9906146f5565b91505061102a565b505092915050565b60006110c481611c48565b73ffffffffffffffffffffffffffffffffffffffff8216611111576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081527f3ab9add546f7e3b43565da9bc7e65e47b969d3856bb01a7dcac7bc8ff5080cbd602052604090205460ff1615611190576040517fe4e970d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111ba7fafffb39e42e2a1496bc4305c8783f904fa76641e3895205b6002a03336ee097583611e04565b60405173ffffffffffffffffffffffffffffffffffffffff831681527fd2b69bde5a989d23ef605a0dd4e0edf7662105058ab69f2559e482857b599ed890602001610ccd565b60045473ffffffffffffffffffffffffffffffffffffffff163314801590611240575060055473ffffffffffffffffffffffffffffffffffffffff163314155b15611277576040517f48f5c3ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610da8838383611e33565b60008281526003602052604090206001015461129d81611c48565b610da88383611d49565b60006112b281611c48565b73ffffffffffffffffffffffffffffffffffffffff83166112ff576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821661134c576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff8581167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316179092556001805492851692909116821790556040519081527fcc4166d40cf68104cdf710f65ce022efd296742868a22b42e4695f89b886363690602001610bf4565b60006113e088888888888888611544565b6040517f737761704d756c746957697468526563697069656e7400000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff831690339060160160405180910390207fc40fae9d5f584875c393ac222c6f88b6c9dced1e9cc6251483648ac2e902c8b08b8b868b6000604051611466959493929190614625565b60405180910390a4979650505050505050565b600061148481611c48565b73ffffffffffffffffffffffffffffffffffffffff82166114d1576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527fcfaaa26691e16e66e73290fc725eee1a6b4e0e693a1640484937aac25ffb55a490602001610ccd565b600073ffffffffffffffffffffffffffffffffffffffff8216611593576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8451600189516115a391906143ae565b146115da576040517fcc513c7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826116a257611618886000815181106115f5576115f56143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16611b43565b15801561162457503415155b1561165b576040517f694b150300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116a23330898b600081518110611674576116746143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff166121a6909392919063ffffffff16565b6116e530896000815181106116b9576116b96143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16611a5a90919063ffffffff16565b905060008860018a516116f891906143ae565b81518110611708576117086143c1565b602002602001015190506000600190505b895181101561183e57898181518110611734576117346143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168a60018361176091906143ae565b81518110611770576117706143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16031561182c576118298a6117a36001846143ae565b815181106117b3576117b36143c1565b60200260200101518b83815181106117cd576117cd6143c1565b60200260200101518560008b6001876117e691906143ae565b815181106117f6576117f66143c1565b60200260200101518b60018861180c91906143ae565b8151811061181c5761181c6143c1565b6020026020010151612386565b92505b80611836816146f5565b915050611719565b5061185e8173ffffffffffffffffffffffffffffffffffffffff16611b43565b1561197b576001546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa1580156118d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f5919061472d565b6001546040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905291935073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561196257600080fd5b505af1158015611976573d6000803e3d6000fd5b505050505b73ffffffffffffffffffffffffffffffffffffffff83163014611a4e5760006119ba73ffffffffffffffffffffffffffffffffffffffff831685611a5a565b90506119dd73ffffffffffffffffffffffffffffffffffffffff83168585611b96565b506000611a0073ffffffffffffffffffffffffffffffffffffffff841686611a5a565b90506000611a0e83836143ae565b9050898111611a49576040517f1fbaba3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b935050505b50979650505050505050565b6000611a6583611b43565b15611a88575073ffffffffffffffffffffffffffffffffffffffff811631610691565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301528416906370a0823190602401602060405180830381865afa158015611af4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b18919061472d565b9050610691565b611b2883611b43565b610da857611b38838360006123a1565b610da88383836123a1565b600073ffffffffffffffffffffffffffffffffffffffff82161580610691575073ffffffffffffffffffffffffffffffffffffffff821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b600081600003611ba857506001611c41565b611bb184611b43565b15611c325760008373ffffffffffffffffffffffffffffffffffffffff168360405160006040518083038185875af1925050503d8060008114611c10576040519150601f19603f3d011682016040523d82523d6000602084013e611c15565b606091505b5090915050600181151514611c2c57611c2c614746565b50611c41565b611c3d848484612537565b5060015b9392505050565b611c5281336126c6565b50565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610e6157600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611ceb3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610e6157600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b610e618282611c55565b6060611c418383604051806060016040528060278152602001614d0360279139612780565b600080600080600080600087806020019051810190611e52919061490f565b965096509650965096509650965086600081518110611e7357611e736143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff1614611edf576040517f198b098900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606060003073ffffffffffffffffffffffffffffffffffffffff1663e738aa8d60e01b8a8d8b8a8c60018c604051602401611f2097969594939291906149e7565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611fa99190614a5e565b6000604051808303816000865af19150503d8060008114611fe6576040519150601f19603f3d011682016040523d82523d6000602084013e611feb565b606091505b50925090508061203c5761203a858c8b60008151811061200d5761200d6143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16611b969092919063ffffffff16565b505b83156121985760008161204f578b612058565b61205883614a7a565b9050600082612067578d61208f565b8a60018c5161207691906143ae565b81518110612086576120866143c1565b60200260200101515b90508673ffffffffffffffffffffffffffffffffffffffff1663d00a2d5f60e01b8284886040516024016120c593929190614abf565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161214e9190614a5e565b6000604051808303816000865af19150503d806000811461218b576040519150601f19603f3d011682016040523d82523d6000602084013e612190565b606091505b509450925050505b505050505050505050505050565b8015612380576121b584611b43565b156123745773ffffffffffffffffffffffffffffffffffffffff8316331480156121df5750803410155b61226b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f57726f6e67207573616765206f66204554482e756e6976657273616c5472616e60448201527f7366657246726f6d2829000000000000000000000000000000000000000000006064820152608401610e4e565b73ffffffffffffffffffffffffffffffffffffffff821630146123005760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146122e2576040519150601f19603f3d011682016040523d82523d6000602084013e6122e7565b606091505b50909150506001811515146122fe576122fe614746565b505b8034111561236f576000336123153484612805565b604051600081818185875af1925050503d8060008114612351576040519150601f19603f3d011682016040523d82523d6000602084013e612356565b606091505b509091505060018115151461236d5761236d614746565b505b612380565b61238084848484612811565b50505050565b60006123968787878787876129b0565b979650505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905291516000928392908716916124389190614a5e565b6000604051808303816000865af19150503d8060008114612475576040519150601f19603f3d011682016040523d82523d6000602084013e61247a565b606091505b50915091508180156124a45750805115806124a45750808060200190518101906124a49190614afd565b612530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f5472616e7366657248656c7065723a3a73616665417070726f76653a2061707060448201527f726f7665206661696c65640000000000000000000000000000000000000000006064820152608401610e4e565b5050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905291516000928392908716916125ce9190614a5e565b6000604051808303816000865af19150503d806000811461260b576040519150601f19603f3d011682016040523d82523d6000602084013e612610565b606091505b509150915081801561263a57508051158061263a57508080602001905181019061263a9190614afd565b612530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f5472616e7366657248656c7065723a3a736166655472616e736665723a20747260448201527f616e73666572206661696c6564000000000000000000000000000000000000006064820152608401610e4e565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610e615761270681612a5c565b612711836020612a7b565b604051602001612722929190614b1a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a0000000000000000000000000000000000000000000000000000000008252610e4e91600401614b9b565b60606000808573ffffffffffffffffffffffffffffffffffffffff16856040516127aa9190614a5e565b600060405180830381855af49150503d80600081146127e5576040519150601f19603f3d011682016040523d82523d6000602084013e6127ea565b606091505b50915091506127fb86838387612cbe565b9695505050505050565b6000611c4182846143ae565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905291516000928392908816916128b09190614a5e565b6000604051808303816000865af19150503d80600081146128ed576040519150601f19603f3d011682016040523d82523d6000602084013e6128f2565b606091505b509150915081801561291c57508051158061291c57508080602001905181019061291c9190614afd565b6129a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f5472616e7366657248656c7065723a3a7472616e7366657246726f6d3a20747260448201527f616e7366657246726f6d206661696c65640000000000000000000000000000006064820152608401610e4e565b505050505050565b60008573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff16036129ec5750836127fb565b613a5b6129f884612d66565b90506000612a1c73ffffffffffffffffffffffffffffffffffffffff8a1630611a5a565b9050612a2f89898387898763ffffffff16565b612a4f73ffffffffffffffffffffffffffffffffffffffff891630611a5a565b9998505050505050505050565b606061069173ffffffffffffffffffffffffffffffffffffffff831660145b60606000612a8a836002614bae565b612a95906002614bc5565b67ffffffffffffffff811115612aad57612aad613b06565b6040519080825280601f01601f191660200182016040528015612ad7576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612b0e57612b0e6143c1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612b7157612b716143c1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000612bad846002614bae565b612bb8906001614bc5565b90505b6001811115612c55577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110612bf957612bf96143c1565b1a60f81b828281518110612c0f57612c0f6143c1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93612c4e81614bd8565b9050612bbb565b508315611c41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610e4e565b60608315612d54578251600003612d4d5773ffffffffffffffffffffffffffffffffffffffff85163b612d4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610e4e565b5081612d5e565b612d5e8383612e33565b949350505050565b613a5b6103e982108015612d7b575060018210155b15612d895750612e77919050565b816107d203612d9b5750612e83919050565b816103ea03612dad575061310c919050565b81610fa203612dbf575061310c919050565b81610bba03612dd1575061310c919050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52413a2045786368616e6765206e6f7420666f756e64000000000000000000006044820152606401610e4e565b815115612e435781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e4e9190614b9b565b6129a885858584613278565b60008181526008602052604090205473ffffffffffffffffffffffffffffffffffffffff1680612edf576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612efe8673ffffffffffffffffffffffffffffffffffffffff16611b43565b15612f8757600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f6d57600080fd5b505af1158015612f81573d6000803e3d6000fd5b50505050505b6000612fa88773ffffffffffffffffffffffffffffffffffffffff16611b43565b612fb25786612fcc565b60015473ffffffffffffffffffffffffffffffffffffffff165b905061305e8273ffffffffffffffffffffffffffffffffffffffff1663d2c4b5986040518163ffffffff1660e01b8152600401602060405180830381865afa15801561301c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130409190614c0d565b73ffffffffffffffffffffffffffffffffffffffff83169087611b1f565b60008273ffffffffffffffffffffffffffffffffffffffff16856040516130859190614a5e565b6000604051808303816000865af19150503d80600081146130c2576040519150601f19603f3d011682016040523d82523d6000602084013e6130c7565b606091505b5050905080613102576040517f5987947500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050505050565b60008181526008602052604090205473ffffffffffffffffffffffffffffffffffffffff1680613168576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6131878673ffffffffffffffffffffffffffffffffffffffff16611b43565b1561321057600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b1580156131f657600080fd5b505af115801561320a573d6000803e3d6000fd5b50505050505b60006132318773ffffffffffffffffffffffffffffffffffffffff16611b43565b61323b5786613255565b60015473ffffffffffffffffffffffffffffffffffffffff165b905061305e73ffffffffffffffffffffffffffffffffffffffff82168387611b1f565b60006132998573ffffffffffffffffffffffffffffffffffffffff16611b43565b1561332257600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b15801561330857600080fd5b505af115801561331c573d6000803e3d6000fd5b50505050505b60008281526008602052604090205473ffffffffffffffffffffffffffffffffffffffff16806133ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52413a2045786368616e6765206e6f7420666f756e64000000000000000000006044820152606401610e4e565b8060006133d073ffffffffffffffffffffffffffffffffffffffff8916611b43565b6133da57876133f4565b60015473ffffffffffffffffffffffffffffffffffffffff165b905060006134178873ffffffffffffffffffffffffffffffffffffffff16611b43565b613421578761343b565b60015473ffffffffffffffffffffffffffffffffffffffff165b90508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361347c5786945050505050612d5e565b6040517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff838116600483015282811660248301526000919085169063e6a4390590604401602060405180830381865afa1580156134f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135189190614c0d565b905073ffffffffffffffffffffffffffffffffffffffff8116613567576040517f1fcdbb0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008061358c73ffffffffffffffffffffffffffffffffffffffff841686868d61382b565b9199509250905081156135fe578273ffffffffffffffffffffffffffffffffffffffff1663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156135e157600080fd5b505af11580156135f5573d6000803e3d6000fd5b5050505061368a565b801561368a576006546040517fbc25cf7700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201529084169063bc25cf7790602401600060405180830381600087803b15801561367157600080fd5b505af1158015613685573d6000803e3d6000fd5b505050505b6136ab73ffffffffffffffffffffffffffffffffffffffff8616848c611b96565b508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161015613780576040517f022c0d9f000000000000000000000000000000000000000000000000000000008152600060048201819052602482018a905230604483015260806064830152608482015273ffffffffffffffffffffffffffffffffffffffff84169063022c0d9f9060a401600060405180830381600087803b15801561376357600080fd5b505af1158015613777573d6000803e3d6000fd5b5050505061381c565b6040517f022c0d9f0000000000000000000000000000000000000000000000000000000081526004810189905260006024820181905230604483015260806064830152608482015273ffffffffffffffffffffffffffffffffffffffff84169063022c0d9f9060a401600060405180830381600087803b15801561380357600080fd5b505af1158015613817573d6000803e3d6000fd5b505050505b50505050505050949350505050565b600080808061385073ffffffffffffffffffffffffffffffffffffffff881689611a5a565b9050600061387473ffffffffffffffffffffffffffffffffffffffff88168a611a5a565b90506000808a73ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156138c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138e89190614c48565b50915091508873ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff16111561392357905b816dffffffffffffffffffffffffffff168410806139505750806dffffffffffffffffffffffffffff1683105b9550851580156139885750816dffffffffffffffffffffffffffff168411806139885750806dffffffffffffffffffffffffffff1683115b94506000613998896103e5613a21565b905060006139c06139b986856dffffffffffffffffffffffffffff16613a2d565b8390613a21565b905060006139f4836139ee6103e86139e88b8a6dffffffffffffffffffffffffffff16613a2d565b90613a21565b90613a43565b90508015613a0b57613a068282613a4f565b613a0e565b60005b9950505050505050509450945094915050565b6000611c418284614bae565b6000818310613a3c5781611c41565b5090919050565b6000611c418284614bc5565b6000611c418284614c98565b613a63614cd3565b565b600060208284031215613a7757600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611c4157600080fd5b60008083601f840112613ab957600080fd5b50813567ffffffffffffffff811115613ad157600080fd5b602083019150836020828501011115613ae957600080fd5b9250929050565b803560ff81168114613b0157600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715613b5957613b59613b06565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ba657613ba6613b06565b604052919050565b600067ffffffffffffffff821115613bc857613bc8613b06565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613c0557600080fd5b8135613c18613c1382613bae565b613b5f565b818152846020838601011115613c2d57600080fd5b816020850160208301376000918101602001919091529392505050565b600067ffffffffffffffff821115613c6457613c64613b06565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff81168114611c5257600080fd5b600082601f830112613ca157600080fd5b81356020613cb1613c1383613c4a565b82815260059290921b84018101918181019086841115613cd057600080fd5b8286015b84811015613cf4578035613ce781613c6e565b8352918301918301613cd4565b509695505050505050565b600082601f830112613d1057600080fd5b81356020613d20613c1383613c4a565b82815260059290921b84018101918181019086841115613d3f57600080fd5b8286015b84811015613cf45780358352918301918301613d43565b600082601f830112613d6b57600080fd5b81356020613d7b613c1383613c4a565b82815260059290921b84018101918181019086841115613d9a57600080fd5b8286015b84811015613cf457803567ffffffffffffffff811115613dbe5760008081fd5b613dcc8986838b0101613bf4565b845250918301918301613d9e565b8015158114611c5257600080fd5b8035613b0181613dda565b8035613b0181613c6e565b60006101008284031215613e1157600080fd5b613e19613b35565b9050813567ffffffffffffffff80821115613e3357600080fd5b613e3f85838601613c90565b835260208401356020840152604084013560408401526060840135915080821115613e6957600080fd5b613e7585838601613cff565b60608401526080840135915080821115613e8e57600080fd5b613e9a85838601613d5a565b6080840152613eab60a08501613de8565b60a0840152613ebc60c08501613df3565b60c084015260e0840135915080821115613ed557600080fd5b50613ee284828501613bf4565b60e08301525092915050565b60008060008060008060008060006101008a8c031215613f0d57600080fd5b8935985060208a0135975060408a013567ffffffffffffffff80821115613f3357600080fd5b613f3f8d838e01613aa7565b9099509750879150613f5360608d01613af0565b965060808c0135955060a08c0135915080821115613f7057600080fd5b613f7c8d838e01613bf4565b945060c08c0135915080821115613f9257600080fd5b50613f9f8c828d01613dfe565b925050613fae60e08b01613df3565b90509295985092959850929598565b60008060408385031215613fd057600080fd5b823591506020830135613fe281613c6e565b809150509250929050565b600060208284031215613fff57600080fd5b8135611c4181613c6e565b600080600080600080600080610100898b03121561402757600080fd5b883567ffffffffffffffff8082111561403f57600080fd5b61404b8c838d01613c90565b995060208b0135985060408b0135975060608b013591508082111561406f57600080fd5b61407b8c838d01613cff565b965060808b013591508082111561409157600080fd5b5061409e8b828c01613d5a565b9450506140ad60a08a01613de8565b92506140bb60c08a01613df3565b915060e089013590509295985092959890939650565b6000602082840312156140e357600080fd5b5035919050565b600080602083850312156140fd57600080fd5b823567ffffffffffffffff8082111561411557600080fd5b818501915085601f83011261412957600080fd5b81358181111561413857600080fd5b8660208260051b850101111561414d57600080fd5b60209290920196919550909350505050565b60005b8381101561417a578181015183820152602001614162565b50506000910152565b6000815180845261419b81602086016020860161415f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015614215578284038952614203848351614183565b988501989350908401906001016141eb565b5091979650505050505050565b602081526000611c4160208301846141cd565b60008060006060848603121561424a57600080fd5b833561425581613c6e565b925060208401359150604084013567ffffffffffffffff81111561427857600080fd5b61428486828701613bf4565b9150509250925092565b600080604083850312156142a157600080fd5b82356142ac81613c6e565b91506020830135613fe281613c6e565b600080600080600080600060e0888a0312156142d757600080fd5b873567ffffffffffffffff808211156142ef57600080fd5b6142fb8b838c01613c90565b985060208a0135975060408a0135965060608a013591508082111561431f57600080fd5b61432b8b838c01613cff565b955060808a013591508082111561434157600080fd5b5061434e8a828b01613d5a565b93505060a088013561435f81613dda565b915060c088013561436f81613c6e565b8091505092959891949750929550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156106915761069161437f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60006101006144998388805182526020810151602083015260408101516040830152606081015173ffffffffffffffffffffffffffffffffffffffff8082166060850152806080840151166080850152505060a081015160a08301525050565b8060c08401526144ab81840187614183565b905082810360e08401526123968185876143f0565b60006101206145208389805182526020810151602083015260408101516040830152606081015173ffffffffffffffffffffffffffffffffffffffff8082166060850152806080840151166080850152505060a081015160a08301525050565b8060c084015261453281840188614183565b905082810360e08401526145478186886143f0565b905082810361010084015261455c8185614183565b98975050505050505050565b80356020831015610691577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b600081518084526020808501945080840160005b838110156145ea57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145b8565b509495945050505050565b600081518084526020808501945080840160005b838110156145ea57815187529582019590820190600101614609565b60a08152600061463860a08301886145a4565b866020840152856040840152828103606084015261465681866145f5565b9150508260808301529695505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261469e57600080fd5b83018035915067ffffffffffffffff8211156146b957600080fd5b602001915036819003821315613ae957600080fd5b8284823760008382016000815283516146eb81836020880161415f565b0195945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036147265761472661437f565b5060010190565b60006020828403121561473f57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b600082601f83011261478657600080fd5b81516020614796613c1383613c4a565b82815260059290921b840181019181810190868411156147b557600080fd5b8286015b84811015613cf45780516147cc81613c6e565b83529183019183016147b9565b600082601f8301126147ea57600080fd5b81516147f8613c1382613bae565b81815284602083860101111561480d57600080fd5b612d5e82602083016020870161415f565b600082601f83011261482f57600080fd5b8151602061483f613c1383613c4a565b82815260059290921b8401810191818101908684111561485e57600080fd5b8286015b84811015613cf457805167ffffffffffffffff8111156148825760008081fd5b6148908986838b01016147d9565b845250918301918301614862565b600082601f8301126148af57600080fd5b815160206148bf613c1383613c4a565b82815260059290921b840181019181810190868411156148de57600080fd5b8286015b84811015613cf457805183529183019183016148e2565b8051613b0181613c6e565b8051613b0181613dda565b600080600080600080600060e0888a03121561492a57600080fd5b875167ffffffffffffffff8082111561494257600080fd5b61494e8b838c01614775565b985060208a0151975060408a015191508082111561496b57600080fd5b6149778b838c0161481e565b965060608a015191508082111561498d57600080fd5b6149998b838c0161489e565b95506149a760808b016148f9565b94506149b560a08b01614904565b935060c08a01519150808211156149cb57600080fd5b506149d88a828b016147d9565b91505092959891949750929550565b60e0815260006149fa60e083018a6145a4565b8860208401528760408401528281036060840152614a1881886145f5565b90508281036080840152614a2c81876141cd565b94151560a0840152505073ffffffffffffffffffffffffffffffffffffffff9190911660c09091015295945050505050565b60008251614a7081846020870161415f565b9190910192915050565b80516020808301519190811015614ab9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000614af46060830184614183565b95945050505050565b600060208284031215614b0f57600080fd5b8151611c4181613dda565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351614b5281601785016020880161415f565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351614b8f81602884016020880161415f565b01602801949350505050565b602081526000611c416020830184614183565b80820281158282048414176106915761069161437f565b808201808211156106915761069161437f565b600081614be757614be761437f565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b600060208284031215614c1f57600080fd5b8151611c4181613c6e565b80516dffffffffffffffffffffffffffff81168114613b0157600080fd5b600080600060608486031215614c5d57600080fd5b614c6684614c2a565b9250614c7460208501614c2a565b9150604084015163ffffffff81168114614c8d57600080fd5b809150509250925092565b600082614cce577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052605160045260246000fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220f233254f60810fffa4df2aa6c8f504943466fc2c52e7fbcec0dda0e42998d42064736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000008c4acd74ff4385f3b7911432fa6787aa14406f8b000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000e5d7c2a44ffddf6b295a15c148167daaaf5cf34f000000000000000000000000b1b64005b11350a94c4d069eff4215592d98f2e2
-----Decoded View---------------
Arg [0] : _assetForwarderAddress (address): 0x8C4aCd74Ff4385f3B7911432FA6787Aa14406f8B
Arg [1] : _native (address): 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
Arg [2] : _wrappedNative (address): 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f
Arg [3] : _univ2SkimAddress (address): 0xB1b64005B11350a94c4D069eff4215592d98F2E2
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000008c4acd74ff4385f3b7911432fa6787aa14406f8b
Arg [1] : 000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
Arg [2] : 000000000000000000000000e5d7c2a44ffddf6b295a15c148167daaaf5cf34f
Arg [3] : 000000000000000000000000b1b64005b11350a94c4d069eff4215592d98f2e2
Deployed Bytecode Sourcemap
128064:22026:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60639:204;;;;;;;;;;-1:-1:-1;60639:204:0;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;60639:204:0;;;;;;;;135430:3022;;;;;;:::i;:::-;;:::i;:::-;;130372:87;;;;;;;;;;;;130427:32;130372:87;;;;;8367:25:1;;;8355:2;8340:18;130372:87:0;8221:177:1;132334:385:0;;;;;;;;;;-1:-1:-1;132334:385:0;;;;;:::i;:::-;;:::i;131772:282::-;;;;;;;;;;-1:-1:-1;131772:282:0;;;;;:::i;:::-;;:::i;133893:766::-;;;;;;:::i;:::-;;:::i;62462:131::-;;;;;;;;;;-1:-1:-1;62462:131:0;;;;;:::i;:::-;62536:7;62563:12;;;:6;:12;;;;;:22;;;;62462:131;128362:26;;;;;;;;;;-1:-1:-1;128362:26:0;;;;;;;;;;;10785:42:1;10773:55;;;10755:74;;10743:2;10728:18;128362:26:0;10609:226:1;126233:38:0;;;;;;;;;;-1:-1:-1;126233:38:0;;;;;;;;62903:147;;;;;;;;;;-1:-1:-1;62903:147:0;;;;;:::i;:::-;;:::i;64047:218::-;;;;;;;;;;-1:-1:-1;64047:218:0;;;;;:::i;:::-;;:::i;131539:225::-;;;;;;;;;;;;;:::i;128318:37::-;;;;;;;;;;-1:-1:-1;128318:37:0;;;;;;;;60935:147;;;;;;;;;;-1:-1:-1;60935:147:0;;;;;:::i;:::-;61021:4;61045:12;;;:6;:12;;;;;;;;:29;;;;;;;;;;;;;;;;60935:147;132062:264;;;;;;;;;;-1:-1:-1;132062:264:0;;;;;:::i;:::-;;:::i;60040:49::-;;;;;;;;;;-1:-1:-1;60040:49:0;60085:4;60040:49;;128395:31;;;;;;;;;;-1:-1:-1;128395:31:0;;;;;;;;67430:494;;;;;;;;;;-1:-1:-1;67430:494:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;132727:386::-;;;;;;;;;;-1:-1:-1;132727:386:0;;;;;:::i;:::-;;:::i;128504:48::-;;;;;;;;;;-1:-1:-1;128504:48:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;133546:339;;;;;;;;;;-1:-1:-1;133546:339:0;;;;;:::i;:::-;;:::i;128433:23::-;;;;;;;;;;-1:-1:-1;128433:23:0;;;;;;;;63343:149;;;;;;;;;;-1:-1:-1;63343:149:0;;;;;:::i;:::-;;:::i;133121:417::-;;;;;;;;;;-1:-1:-1;133121:417:0;;;;;:::i;:::-;;:::i;126199:27::-;;;;;;;;;;-1:-1:-1;126199:27:0;;;;;;;;134667:755;;;;;;:::i;:::-;;:::i;131288:243::-;;;;;;;;;;-1:-1:-1;131288:243:0;;;;;:::i;:::-;;:::i;60639:204::-;60724:4;60748:47;;;60763:32;60748:47;;:87;;-1:-1:-1;58071:25:0;58056:40;;;;60799:36;60741:94;60639:204;-1:-1:-1;;60639:204:0:o;135430:3022::-;135743:242;135776:8;:15;;;135806:8;:15;;;135836:8;:18;;;135869:8;:14;;;135898:8;:15;;;135928:8;:18;;;135969:4;135743:18;:242::i;:::-;-1:-1:-1;136029:15:0;;136059:22;;135996:30;;136029:15;136059:26;;136084:1;;136059:26;:::i;:::-;136029:67;;;;;;;;:::i;:::-;;;;;;;135996:100;;136140:11;:16;;136155:1;136140:16;136136:658;;136173:14;136190:46;:31;;;136230:4;136190:31;:46::i;:::-;136289:14;;136173:63;;-1:-1:-1;136251:62:0;;136289:14;136251:29;;;;136289:14;136173:63;136251:29;:62::i;:::-;136328:14;;;;;;;:23;;136359:20;;:18;;;:20::i;:::-;:33;;136391:1;136359:33;;;136382:6;136359:33;136412:269;;;;;;;;136462:9;136412:269;;;;136494:6;136412:269;;;;136532:9;136523:6;:18;;;;:::i;:::-;136412:269;;;;136572:12;136412:269;;;;;;136608:15;136412:269;;;;;;136646:16;136412:269;;;136700:8;:18;;;136737:9;;136328:433;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;136776:7;;;;136136:658;136848:11;:16;;136863:1;136848:16;136844:1027;;136881:14;136898:46;:31;;;136938:4;136898:31;:46::i;:::-;137015:14;;137049:18;;;;136881:63;;-1:-1:-1;136959:123:0;;137015:14;136959:29;;;;137015:14;;136959:29;:123::i;:::-;137097:14;;;;;;;:30;;137153:20;;:18;;;:20::i;:::-;:33;;137185:1;137153:33;;;137176:6;137153:33;137220:293;;;;;;;;137270:9;137220:293;;;;137302:8;:18;;;137220:293;;;;137364:9;137343:8;:18;;;:30;;;;:::i;:::-;137220:293;;;;137404:12;137220:293;;;;;;137440:15;137220:293;;;;;;137478:16;137220:293;;;137532:8;:18;;;137569:9;;137597:7;137097:522;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;137647:8;:18;;;137638:6;:27;137634:205;;;137686:137;137739:15;137786:8;:18;;;137777:6;:27;;;;:::i;:::-;137686:30;;;;:137;:30;:137::i;:::-;;137634:205;137853:7;;;;136844:1027;137932:11;:16;;137947:1;137932:16;137928:517;;138019:14;138036:46;:31;;;138076:4;138036:31;:46::i;:::-;138135:14;;138019:63;;-1:-1:-1;138097:62:0;;138135:14;138097:29;;;;138135:14;138019:63;138097:29;:62::i;:::-;138227:14;;;;:27;138262:9;138291;138319:16;138354:18;138362:9;;138354:18;:::i;:::-;138227:185;;;;;;;;;;;;;19751:25:1;;;;19792:18;;;19785:34;;;;19835:18;;;19828:34;19878:18;;;19871:34;;;19723:19;;138227:185:0;19520:391:1;137928:517:0;135732:2720;135430:3022;;;;;;;;;;:::o;132334:385::-;130427:32;60531:16;60542:4;60531:10;:16::i;:::-;132490:9:::1;132503:1;132490:14:::0;132486:37:::1;;132513:10;;;;;;;;;;;;;;132486:37;132538:29;::::0;::::1;132534:55;;132576:13;;;;;;;;;;;;;;132534:55;132600:24;::::0;;;:13:::1;:24;::::0;;;;;;;;:51;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;132667:44;;20090:25:1;;;20131:18;;;20124:83;132667:44:0::1;::::0;20063:18:1;132667:44:0::1;;;;;;;;132334:385:::0;;;:::o;131772:282::-;60085:4;60531:16;60085:4;60531:10;:16::i;:::-;131888:24:::1;::::0;::::1;131884:50;;131921:13;;;;;;;;;;;;;;131884:50;131945:14;:44:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;132005:41:::1;::::0;;20453:34:1;;;132035:10:0::1;20518:2:1::0;20503:18;;20496:43;132005:41:0::1;::::0;20365:18:1;132005:41:0::1;;;;;;;;131772:282:::0;;:::o;133893:766::-;134191:20;134239:188;134276:6;134297;134318:9;134342:5;134362:6;134383:9;134407;134239:22;:188::i;:::-;134443:208;;20764:17:1;20752:30;;134224:203:0;;-1:-1:-1;134443:208:0;;;;134536:10;;20807:2:1;20798:12;134443:208:0;;;;;;;;134494:6;134515;134585:12;134612:5;134632:8;134443:208;;;;;;;;;;:::i;:::-;;;;;;;;133893:766;;;;;;;;;;:::o;62903:147::-;62536:7;62563:12;;;:6;:12;;;;;:22;;;60531:16;60542:4;60531:10;:16::i;:::-;63017:25:::1;63028:4;63034:7;63017:10;:25::i;:::-;62903:147:::0;;;:::o;64047:218::-;64143:23;;;33497:10;64143:23;64135:83;;;;;;;22702:2:1;64135:83:0;;;22684:21:1;22741:2;22721:18;;;22714:30;22780:34;22760:18;;;22753:62;22851:17;22831:18;;;22824:45;22886:19;;64135:83:0;;;;;;;;;64231:26;64243:4;64249:7;64231:11;:26::i;:::-;64047:218;;:::o;131539:225::-;131589:8;;:22;:8;131601:10;131589:22;131585:77;;131635:15;;;;;;;;;;;;;;131585:77;131672:42;60085:4;131703:10;131672;:42::i;:::-;131730:26;;131745:10;10755:74:1;;131730:26:0;;10743:2:1;10728:18;131730:26:0;;;;;;;131539:225::o;132062:264::-;60085:4;60531:16;60085:4;60531:10;:16::i;:::-;132177:26:::1;::::0;::::1;132173:52;;132212:13;;;;;;;;;;;;;;132173:52;132236:11;:26:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;132278:40:::1;::::0;;20453:34:1;;;132307:10:0::1;20518:2:1::0;20503:18;;20496:43;132278:40:0::1;::::0;20365:18:1;132278:40:0::1;20218:327:1::0;67430:494:0;67598:12;;;67533:20;67598:12;;;;;;;;67498:22;;67712:4;67700:24;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;67690:34;;67740:9;67735:157;67755:15;;;67735:157;;;67805:75;67842:4;67862;;67867:1;67862:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;67871;67849:30;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;67805:28;:75::i;:::-;67792:7;67800:1;67792:10;;;;;;;;:::i;:::-;;;;;;:88;;;;67772:3;;;;;:::i;:::-;;;;67735:157;;;;67902:14;67430:494;;;;:::o;132727:386::-;60085:4;60531:16;60085:4;60531:10;:16::i;:::-;132846:28:::1;::::0;::::1;132842:54;;132883:13;;;;;;;;;;;;;;132842:54;61045:29:::0;;;61021:4;61045:29;;;:12;;:29;:12;:29;;;;;132907:92:::1;;;132977:22;;;;;;;;;;;;;;132907:92;133010:47;130427:32;133042:14;133010:10;:47::i;:::-;133073:32;::::0;10785:42:1;10773:55;;10755:74;;133073:32:0::1;::::0;10743:2:1;10728:18;133073:32:0::1;10609:226:1::0;133546:339:0;133722:14;;;;133700:10;:37;;;;:88;;-1:-1:-1;133776:11:0;;;;133754:10;:34;;133700:88;133682:140;;;133807:15;;;;;;;;;;;;;;133682:140;133833:44;133848:10;133860:7;133869;133833:14;:44::i;63343:149::-;62536:7;62563:12;;;:6;:12;;;;;:22;;;60531:16;60542:4;60531:10;:16::i;:::-;63458:26:::1;63470:4;63476:7;63458:11;:26::i;133121:417::-:0;60085:4;60531:16;60085:4;60531:10;:16::i;:::-;133269:21:::1;::::0;::::1;133265:47;;133299:13;;;;;;;;;;;;;;133265:47;133327:28;::::0;::::1;133323:54;;133364:13;;;;;;;;;;;;;;133323:54;133388:13;:42:::0;;::::1;::::0;;::::1;::::0;;;::::1;;::::0;;;-1:-1:-1;133441:38:0;;;;::::1;::::0;;;::::1;::::0;::::1;::::0;;133495:35:::1;::::0;10755:74:1;;;133495:35:0::1;::::0;10743:2:1;10728:18;133495:35:0::1;10609:226:1::0;134667:755:0;134945:20;134993:184;135026:6;135047;135068:9;135092:5;135112:6;135133:9;135157;134993:18;:184::i;:::-;135193:221;;24696:24:1;24684:37;;134978:199:0;;-1:-1:-1;135193:221:0;;;;135306:10;;24746:2:1;24737:12;135193:221:0;;;;;;;;135264:6;135285;135355:12;135382:5;135402:1;135193:221;;;;;;;;;;:::i;:::-;;;;;;;;134667:755;;;;;;;;;:::o;131288:243::-;60085:4;60531:16;60085:4;60531:10;:16::i;:::-;131403:23:::1;::::0;::::1;131399:49;;131435:13;;;;;;;;;;;;;;131399:49;131459:8;:20:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;131495:28:::1;::::0;10755:74:1;;;131495:28:0::1;::::0;10743:2:1;10728:18;131495:28:0::1;10609:226:1::0;140346:1980:0;140614:20;140651:23;;;140647:49;;140683:13;;;;;;;;;;;;;;140647:49;140732:5;:12;140727:1;140711:6;:13;:17;;;;:::i;:::-;:33;140707:90;;140768:17;;;;;;;;;;;;;;140707:90;140812:9;140807:228;;140843:17;:6;140850:1;140843:9;;;;;;;;:::i;:::-;;;;;;;:15;;;:17::i;:::-;140842:18;:36;;;;-1:-1:-1;140864:9:0;:14;;140842:36;140838:105;;;140906:21;;;;;;;;;;;;;;140838:105;140957:66;140989:10;141009:4;141016:6;140957;140964:1;140957:9;;;;;;;;:::i;:::-;;;;;;;:31;;;;:66;;;;;;:::i;:::-;141060:43;141097:4;141060:6;141067:1;141060:9;;;;;;;;:::i;:::-;;;;;;;:28;;;;:43;;;;:::i;:::-;141045:58;;141114:34;141151:6;141174:1;141158:6;:13;:17;;;;:::i;:::-;141151:25;;;;;;;;:::i;:::-;;;;;;;141114:62;;141192:9;141204:1;141192:13;;141187:374;141211:6;:13;141207:1;:17;141187:374;;;141267:6;141274:1;141267:9;;;;;;;;:::i;:::-;;;;;;;141250:26;;:6;141261:1;141257;:5;;;;:::i;:::-;141250:13;;;;;;;;:::i;:::-;;;;;;;:26;;;141246:75;141297:8;141246:75;141350:199;141379:6;141386:5;141390:1;141386;:5;:::i;:::-;141379:13;;;;;;;;:::i;:::-;;;;;;;141411:6;141418:1;141411:9;;;;;;;;:::i;:::-;;;;;;;141439:12;141470:1;141490:5;141500:1;141496;:5;;;;:::i;:::-;141490:12;;;;;;;;:::i;:::-;;;;;;;141521:6;141532:1;141528;:5;;;;:::i;:::-;141521:13;;;;;;;;:::i;:::-;;;;;;;141350:10;:199::i;:::-;141335:214;;141187:374;141226:3;;;;:::i;:::-;;;;141187:374;;;;141577:24;:16;:22;;;:24::i;:::-;141573:163;;;141633:14;;:39;;;;;141666:4;141633:39;;;10755:74:1;141633:14:0;;;;;:24;;10728:18:1;;141633:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;141687:14;;:37;;;;;;;;8367:25:1;;;141618:54:0;;-1:-1:-1;141687:14:0;;;:23;;8340:18:1;;141687:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;141573:163;141752:26;;;141773:4;141752:26;141748:571;;141795:22;141820:78;:35;;;141874:9;141820:35;:78::i;:::-;141795:103;-1:-1:-1;141913:59:0;:34;;;141948:9;141959:12;141913:34;:59::i;:::-;-1:-1:-1;141987:22:0;142012:78;:35;;;142066:9;142012:35;:78::i;:::-;141987:103;-1:-1:-1;142107:19:0;142129:31;142146:14;141987:103;142129:31;:::i;:::-;142107:53;;142197:9;142179:14;:27;142175:89;;142234:14;;;;;;;;;;;;;;142175:89;142293:14;-1:-1:-1;;;141748:571:0;140636:1690;140346:1980;;;;;;;;;:::o;114277:264::-;114391:7;114415:12;114421:5;114415;:12::i;:::-;114411:123;;;-1:-1:-1;114451:11:0;;;;114444:18;;114411:123;114502:20;;;;;:15;10773:55:1;;;114502:20:0;;;10755:74:1;114502:15:0;;;;;10728:18:1;;114502:20:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;114495:27;;;;113465:804;113603:12;113609:5;113603;:12::i;:::-;113598:664;;114132:49;114167:5;114175:2;114179:1;114132:26;:49::i;:::-;114196:54;114231:5;114239:2;114243:6;114196:26;:54::i;114549:191::-;114612:4;114637:39;;;;;:94;;-1:-1:-1;114693:38:0;;;111183:42;114693:38;114629:103;114549:191;-1:-1:-1;;114549:191:0:o;111235:524::-;111367:4;111388:6;111398:1;111388:11;111384:55;;-1:-1:-1;111423:4:0;111416:11;;111384:55;111455:12;111461:5;111455;:12::i;:::-;111451:301;;;111485:12;111527:2;111503:34;;111563:6;111503:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;111484:104:0;;-1:-1:-1;;111621:4:0;111610:15;;;;111603:23;;;;:::i;:::-;111469:169;111451:301;;;111659:55;111695:5;111703:2;111707:6;111659:27;:55::i;:::-;-1:-1:-1;111736:4:0;111451:301;111235:524;;;;;:::o;61386:105::-;61453:30;61464:4;33497:10;61453;:30::i;:::-;61386:105;:::o;65644:238::-;61021:4;61045:12;;;:6;:12;;;;;;;;:29;;;;;;;;;;;;;65723:152;;65767:12;;;;:6;:12;;;;;;;;:29;;;;;;;;;;:36;;;;65799:4;65767:36;;;65850:12;33497:10;;33417:98;65850:12;65823:40;;65841:7;65823:40;;65835:4;65823:40;;;;;;;;;;65644:238;;:::o;66062:239::-;61021:4;61045:12;;;:6;:12;;;;;;;;:29;;;;;;;;;;;;;66142:152;;;66217:5;66185:12;;;:6;:12;;;;;;;;:29;;;;;;;;;;;:37;;;;;;66242:40;33497:10;;66185:12;;66242:40;;66217:5;66242:40;66062:239;;:::o;64972:112::-;65051:25;65062:4;65068:7;65051:10;:25::i;20370:200::-;20453:12;20485:77;20506:6;20514:4;20485:77;;;;;;;;;;;;;;;;;:20;:77::i;138460:1878::-;138612:33;138660:17;138692:21;138728:22;138765:17;138797:18;138830:24;138897:7;138868:308;;;;;;;;;;;;:::i;:::-;138597:579;;;;;;;;;;;;;;139213:6;139220:1;139213:9;;;;;;;;:::i;:::-;;;;;;;139191:32;;:10;:32;;;139187:61;;139232:16;;;;;;;;;;;;;;139187:61;139259:21;139291:13;139346:4;139338:18;;130528:10;139412:34;;139465:6;139490:7;139516:9;139544:5;139568:6;139593:4;139616:9;139371:269;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;139338:313;;;;139371:269;139338:313;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;139315:336:0;-1:-1:-1;139315:336:0;-1:-1:-1;139315:336:0;139664:89;;139694:47;139722:9;139733:7;139694:6;139701:1;139694:9;;;;;;;;:::i;:::-;;;;;;;:27;;;;:47;;;;;:::i;:::-;;139664:89;139769:13;139765:566;;;139799:19;139821:8;:81;;139895:7;139821:81;;;139857:17;139865:8;139857:17;:::i;:::-;139799:103;;139917:18;139938:8;:92;;140020:10;139938:92;;;139974:6;139997:1;139981:6;:13;:17;;;;:::i;:::-;139974:25;;;;;;;;:::i;:::-;;;;;;;139938:92;139917:113;;140068:9;:14;;140146:38;;;140207:10;140240:11;140274;140101:203;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;140068:251;;;;140101:203;140068:251;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;140045:274:0;-1:-1:-1;140045:274:0;-1:-1:-1;;;139765:566:0;138586:1752;;;;;;;;;138460:1878;;;:::o;111767:978::-;111928:50;;111960:7;111928:50;111994:12;112000:5;111994;:12::i;:::-;111990:748;;;112049:18;;;112057:10;112049:18;:41;;;;;112084:6;112071:9;:19;;112049:41;112023:145;;;;;;;32937:2:1;112023:145:0;;;32919:21:1;32976:2;32956:18;;;32949:30;33015:34;32995:18;;;32988:62;33086:12;33066:18;;;33059:40;33116:19;;112023:145:0;32735:406:1;112023:145:0;112187:19;;;112201:4;112187:19;112183:214;;112228:12;112270:2;112246:34;;112310:6;112246:93;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;112227:112:0;;-1:-1:-1;;112376:4:0;112365:15;;;;112358:23;;;;:::i;:::-;112208:189;112183:214;112427:6;112415:9;:18;112411:218;;;112455:12;112481:10;112527:21;:9;112541:6;112527:13;:21::i;:::-;112473:98;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;112454:117:0;;-1:-1:-1;;112608:4:0;112597:15;;;;112590:23;;;;:::i;:::-;112435:194;112411:218;111990:748;;;112661:65;112701:5;112709:4;112715:2;112719:6;112661:31;:65::i;:::-;111767:978;;;;:::o;142334:429::-;142561:17;142606:149;142626:9;142650;142674:6;142695:9;142719:5;142739;142606;:149::i;:::-;142591:164;142334:429;-1:-1:-1;;;;;;;142334:429:0:o;109430:435::-;109640:45;;;109615:10;33338:55:1;;;109640:45:0;;;33320:74:1;33410:18;;;;33403:34;;;109640:45:0;;;;;;;;;;33293:18:1;;;;109640:45:0;;;;;;;;;;;;;109615:81;;-1:-1:-1;;;;109615:10:0;;;;:81;;109640:45;109615:81;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;109579:117;;;;109729:7;:57;;;;-1:-1:-1;109741:11:0;;:16;;:44;;;109772:4;109761:24;;;;;;;;;;;;:::i;:::-;109707:150;;;;;;;33900:2:1;109707:150:0;;;33882:21:1;33939:2;33919:18;;;33912:30;33978:34;33958:18;;;33951:62;34049:13;34029:18;;;34022:41;34080:19;;109707:150:0;33698:407:1;109707:150:0;109502:363;;109430:435;;;:::o;109873:439::-;110085:45;;;110060:10;33338:55:1;;;110085:45:0;;;33320:74:1;33410:18;;;;33403:34;;;110085:45:0;;;;;;;;;;33293:18:1;;;;110085:45:0;;;;;;;;;;;;;110060:81;;-1:-1:-1;;;;110060:10:0;;;;:81;;110085:45;110060:81;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;110024:117;;;;110174:7;:57;;;;-1:-1:-1;110186:11:0;;:16;;:44;;;110217:4;110206:24;;;;;;;;;;;;:::i;:::-;110152:152;;;;;;;34312:2:1;110152:152:0;;;34294:21:1;34351:2;34331:18;;;34324:30;34390:34;34370:18;;;34363:62;34461:15;34441:18;;;34434:43;34494:19;;110152:152:0;34110:409:1;61781:492:0;61021:4;61045:12;;;:6;:12;;;;;;;;:29;;;;;;;;;;;;;61865:401;;62058:28;62078:7;62058:19;:28::i;:::-;62159:38;62187:4;62194:2;62159:19;:38::i;:::-;61963:257;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;61909:345;;;;;;;;:::i;20764:332::-;20909:12;20935;20949:23;20976:6;:19;;20996:4;20976:25;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20934:67;;;;21019:69;21046:6;21054:7;21063:10;21075:12;21019:26;:69::i;:::-;21012:76;20764:332;-1:-1:-1;;;;;;20764:332:0:o;85154:98::-;85212:7;85239:5;85243:1;85239;:5;:::i;110320:522::-;110605:51;;;110580:10;35846:15:1;;;110605:51:0;;;35828:34:1;35898:15;;;35878:18;;;35871:43;35930:18;;;;35923:34;;;110605:51:0;;;;;;;;;;35740:18:1;;;;110605:51:0;;;;;;;;;;;;;110580:87;;-1:-1:-1;;;;110580:10:0;;;;:87;;110605:51;110580:87;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;110544:123;;;;110700:7;:57;;;;-1:-1:-1;110712:11:0;;:16;;:44;;;110743:4;110732:24;;;;;;;;;;;;:::i;:::-;110678:156;;;;;;;36170:2:1;110678:156:0;;;36152:21:1;36209:2;36189:18;;;36182:30;36248:34;36228:18;;;36221:62;36319:19;36299:18;;;36292:47;36356:19;;110678:156:0;35968:413:1;110678:156:0;110454:388;;110320:522;;;;:::o;142771:754::-;142993:20;143043:9;143030:22;;:9;:22;;;143026:68;;-1:-1:-1;143076:6:0;143069:13;;143026:68;143104:162;143269:26;143289:5;143269:19;:26::i;:::-;143104:191;-1:-1:-1;143308:23:0;143334:43;:28;;;143371:4;143334:28;:43::i;:::-;143308:69;;143388:60;143396:9;143407;143418:15;143435:5;143442;143388:7;:60;;:::i;:::-;143474:43;:28;;;143511:4;143474:28;:43::i;:::-;143459:58;142771:754;-1:-1:-1;;;;;;;;;142771:754:0:o;55974:151::-;56032:13;56065:52;56077:22;;;53849:2;55370:447;55445:13;55471:19;55503:10;55507:6;55503:1;:10;:::i;:::-;:14;;55516:1;55503:14;:::i;:::-;55493:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;55493:25:0;;55471:47;;55529:15;:6;55536:1;55529:9;;;;;;;;:::i;:::-;;;;:15;;;;;;;;;;;55555;:6;55562:1;55555:9;;;;;;;;:::i;:::-;;;;:15;;;;;;;;;;-1:-1:-1;55586:9:0;55598:10;55602:6;55598:1;:10;:::i;:::-;:14;;55611:1;55598:14;:::i;:::-;55586:26;;55581:131;55618:1;55614;:5;55581:131;;;55653:8;55662:5;55670:3;55662:11;55653:21;;;;;;;:::i;:::-;;;;55641:6;55648:1;55641:9;;;;;;;;:::i;:::-;;;;:33;;;;;;;;;;-1:-1:-1;55699:1:0;55689:11;;;;;55621:3;;;:::i;:::-;;;55581:131;;;-1:-1:-1;55730:10:0;;55722:55;;;;;;;37092:2:1;55722:55:0;;;37074:21:1;;;37111:18;;;37104:30;37170:34;37150:18;;;37143:62;37222:18;;55722:55:0;36890:356:1;21392:644:0;21577:12;21606:7;21602:427;;;21634:10;:17;21655:1;21634:22;21630:290;;15273:19;;;;21844:60;;;;;;;37453:2:1;21844:60:0;;;37435:21:1;37492:2;37472:18;;;37465:30;37531:31;37511:18;;;37504:59;37580:18;;21844:60:0;37251:353:1;21844:60:0;-1:-1:-1;21941:10:0;21934:17;;21602:427;21984:33;21992:10;22004:12;21984:7;:33::i;:::-;21392:644;;;;;;:::o;143533:824::-;143656:189;143873:6;143866:4;:13;:31;;;;;143891:6;143883:4;:14;;143866:31;143862:445;;;-1:-1:-1;143946:16:0;;143533:824;-1:-1:-1;143533:824:0:o;143862:445::-;143984:4;143992:6;143984:14;143980:327;;-1:-1:-1;144022:15:0;;143533:824;-1:-1:-1;143533:824:0:o;143980:327::-;144067:4;144075:6;144067:14;144063:244;;-1:-1:-1;144105:14:0;;143533:824;-1:-1:-1;143533:824:0:o;144063:244::-;144149:4;144157:6;144149:14;144145:162;;-1:-1:-1;144187:16:0;;143533:824;-1:-1:-1;143533:824:0:o;144145:162::-;144233:4;144241:6;144233:14;144229:78;;-1:-1:-1;144271:16:0;;143533:824;-1:-1:-1;143533:824:0:o;144229:78::-;144317:32;;;;;37811:2:1;144317:32:0;;;37793:21:1;37850:2;37830:18;;;37823:30;37889:24;37869:18;;;37862:52;37931:18;;144317:32:0;37609:346:1;22578:552:0;22739:17;;:21;22735:388;;22971:10;22965:17;23028:15;23015:10;23011:2;23007:19;23000:44;22735:388;23098:12;23091:20;;;;;;;;;;;:::i;144365:275::-;144572:60;144596:9;144607;144618:6;144626:5;144572:23;:60::i;147433:980::-;147725:16;147744:23;;;:13;:23;;;;;;;;;147778:75;;147828:13;;;;;;;;;;;;;;147778:75;147869:17;:9;:15;;;:17::i;:::-;147865:89;;;147903:14;;;;;;;;;;;:22;;;147933:6;147903:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;147865:89;147964:31;147998:17;:9;:15;;;:17::i;:::-;:72;;148061:9;147998:72;;;148031:14;;;;147998:72;147964:106;;148083:127;148145:8;148128:48;;;:50;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;148083:30;;;;148193:6;148083:30;:127::i;:::-;148282:12;148308:8;148300:22;;148323:5;148300:29;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;148281:48;;;148345:7;148340:66;;148376:18;;;;;;;;;;;;;;148340:66;147631:782;;;147433:980;;;;;:::o;146506:919::-;146797:19;146819:23;;;:13;:23;;;;;;;;;146853:78;;146906:13;;;;;;;;;;;;;;146853:78;146947:17;:9;:15;;;:17::i;:::-;146943:89;;;146981:14;;;;;;;;;;;:22;;;147011:6;146981:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;146943:89;147042:31;147076:17;:9;:15;;;:17::i;:::-;:72;;147139:9;147076:72;;;147109:14;;;;147076:72;147042:106;-1:-1:-1;147159:60:0;:30;;;147198:11;147212:6;147159:30;:60::i;148421:1666::-;148607:20;148644:17;:9;:15;;;:17::i;:::-;148640:89;;;148678:14;;;;;;;;;;;:22;;;148708:6;148678:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;148640:89;148741:18;148762:23;;;:13;:23;;;;;;;;;148796:59;;;;;;;37811:2:1;148796:59:0;;;37793:21:1;37850:2;37830:18;;;37823:30;37889:24;37869:18;;;37862:52;37931:18;;148796:59:0;37609:346:1;148796:59:0;148920:10;148866:25;148979:17;:15;;;;:17::i;:::-;:72;;149042:9;148979:72;;;149012:14;;;;148979:72;148945:106;;149062:29;149094:17;:9;:15;;;:17::i;:::-;:72;;149157:9;149094:72;;;149127:14;;;;149094:72;149062:104;;149200:11;149183:28;;:13;:28;;;149179:74;;149235:6;149228:13;;;;;;;;149179:74;149289:43;;;;;:15;20471::1;;;149289:43:0;;;20453:34:1;20523:15;;;20503:18;;;20496:43;149263:23:0;;149289:15;;;;;;20365:18:1;;149289:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;149263:69;-1:-1:-1;149347:27:0;;;149343:53;;149383:13;;;;;;;;;;;;;;149343:53;149407:13;;149492:100;:14;;;149521:13;149549:11;149575:6;149492:14;:100::i;:::-;149455:137;;-1:-1:-1;149455:137:0;-1:-1:-1;149455:137:0;-1:-1:-1;149603:126:0;;;;149632:4;:9;;;:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;149603:126;;;149665:8;149661:68;;;149700:16;;149690:27;;;;;:9;149700:16;;;149690:27;;;10755:74:1;149690:9:0;;;;;;10728:18:1;;149690:27:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;149661:68;149741:54;:31;;;149781:4;149788:6;149741:31;:54::i;:::-;;149904:11;149880:38;;149848:13;149824:40;;:94;149806:274;;;149945:45;;;;;149955:1;149945:45;;;39196:25:1;;;39237:18;;;39230:34;;;149980:4:0;39280:18:1;;;39273:83;39392:3;39372:18;;;39365:31;39412:19;;;39405:30;149945:9:0;;;;;;39452:19:1;;149945:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;149806:274;;;150023:45;;;;;;;;39196:25:1;;;150047:1:0;39237:18:1;;;39230:34;;;150058:4:0;39280:18:1;;;39273:83;39392:3;39372:18;;;39365:31;39412:19;;;39405:30;150023:9:0;;;;;;39452:19:1;;150023:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;149806:274;148629:1458;;;;;;;148421:1666;;;;;;:::o;115547:1123::-;115737:14;;;;115814:47;:28;;;115851:8;115814:28;:47::i;:::-;115794:67;-1:-1:-1;115872:18:0;115893:47;:28;;;115930:8;115893:28;:47::i;:::-;115872:68;;115952:16;115970;115992:8;:20;;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;115951:63;;;;;116041:9;116029:21;;:9;:21;;;116025:97;;;116091:8;116025:97;116156:8;116144:20;;:9;:20;:45;;;;116181:8;116168:21;;:10;:21;116144:45;116132:58;;116213:8;116212:9;:60;;;;;116238:8;116226:20;;:9;:20;:45;;;;116263:8;116250:21;;:10;:21;116226:45;116201:71;-1:-1:-1;116285:23:0;116311:17;:8;116324:3;116311:12;:17::i;:::-;116285:43;;116339:17;116359:86;116393:41;116413:10;116425:8;116393:41;;:19;:41::i;:::-;116359:15;;:19;:86::i;:::-;116339:106;;116456:19;116478:113;116575:15;116478:78;116551:4;116478:54;116512:9;116523:8;116478:54;;:33;:54::i;:::-;:72;;:78::i;:::-;:96;;:113::i;:::-;116456:135;-1:-1:-1;116612:16:0;;116611:51;;116636:26;:9;116650:11;116636:13;:26::i;:::-;116611:51;;;116632:1;116611:51;116602:60;;115783:887;;;;;;;115547:1123;;;;;;;;:::o;85511:98::-;85569:7;85596:5;85600:1;85596;:5;:::i;69462:106::-;69520:7;69551:1;69547;:5;:13;;69559:1;69547:13;;;-1:-1:-1;69555:1:0;;69462:106;-1:-1:-1;69462:106:0:o;84773:98::-;84831:7;84858:5;84862:1;84858;:5;:::i;85910:98::-;85968:7;85995:5;85999:1;85995;:5;:::i;-1:-1:-1:-;;;:::i;:::-;:::o;14:332:1:-;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;543:347;594:8;604:6;658:3;651:4;643:6;639:17;635:27;625:55;;676:1;673;666:12;625:55;-1:-1:-1;699:20:1;;742:18;731:30;;728:50;;;774:1;771;764:12;728:50;811:4;803:6;799:17;787:29;;863:3;856:4;847:6;839;835:19;831:30;828:39;825:59;;;880:1;877;870:12;825:59;543:347;;;;;:::o;895:156::-;961:20;;1021:4;1010:16;;1000:27;;990:55;;1041:1;1038;1031:12;990:55;895:156;;;:::o;1056:184::-;1108:77;1105:1;1098:88;1205:4;1202:1;1195:15;1229:4;1226:1;1219:15;1245:255;1317:2;1311:9;1359:6;1347:19;;1396:18;1381:34;;1417:22;;;1378:62;1375:88;;;1443:18;;:::i;:::-;1479:2;1472:22;1245:255;:::o;1505:334::-;1576:2;1570:9;1632:2;1622:13;;1637:66;1618:86;1606:99;;1735:18;1720:34;;1756:22;;;1717:62;1714:88;;;1782:18;;:::i;:::-;1818:2;1811:22;1505:334;;-1:-1:-1;1505:334:1:o;1844:245::-;1892:4;1925:18;1917:6;1914:30;1911:56;;;1947:18;;:::i;:::-;-1:-1:-1;2004:2:1;1992:15;2009:66;1988:88;2078:4;1984:99;;1844:245::o;2094:462::-;2136:5;2189:3;2182:4;2174:6;2170:17;2166:27;2156:55;;2207:1;2204;2197:12;2156:55;2243:6;2230:20;2274:48;2290:31;2318:2;2290:31;:::i;:::-;2274:48;:::i;:::-;2347:2;2338:7;2331:19;2393:3;2386:4;2381:2;2373:6;2369:15;2365:26;2362:35;2359:55;;;2410:1;2407;2400:12;2359:55;2475:2;2468:4;2460:6;2456:17;2449:4;2440:7;2436:18;2423:55;2523:1;2498:16;;;2516:4;2494:27;2487:38;;;;2502:7;2094:462;-1:-1:-1;;;2094:462:1:o;2561:202::-;2640:4;2673:18;2665:6;2662:30;2659:56;;;2695:18;;:::i;:::-;-1:-1:-1;2740:1:1;2736:14;2752:4;2732:25;;2561:202::o;2768:173::-;2873:42;2866:5;2862:54;2855:5;2852:65;2842:93;;2931:1;2928;2921:12;2946:794;3019:5;3072:3;3065:4;3057:6;3053:17;3049:27;3039:55;;3090:1;3087;3080:12;3039:55;3126:6;3113:20;3152:4;3176:79;3192:62;3251:2;3192:62;:::i;3176:79::-;3289:15;;;3375:1;3371:10;;;;3359:23;;3355:32;;;3320:12;;;;3399:15;;;3396:35;;;3427:1;3424;3417:12;3396:35;3463:2;3455:6;3451:15;3475:236;3491:6;3486:3;3483:15;3475:236;;;3571:3;3558:17;3588:50;3632:5;3588:50;:::i;:::-;3651:18;;3689:12;;;;3508;;3475:236;;;-1:-1:-1;3729:5:1;2946:794;-1:-1:-1;;;;;;2946:794:1:o;3745:681::-;3799:5;3852:3;3845:4;3837:6;3833:17;3829:27;3819:55;;3870:1;3867;3860:12;3819:55;3906:6;3893:20;3932:4;3956:79;3972:62;4031:2;3972:62;:::i;3956:79::-;4069:15;;;4155:1;4151:10;;;;4139:23;;4135:32;;;4100:12;;;;4179:15;;;4176:35;;;4207:1;4204;4197:12;4176:35;4243:2;4235:6;4231:15;4255:142;4271:6;4266:3;4263:15;4255:142;;;4337:17;;4325:30;;4375:12;;;;4288;;4255:142;;4431:905;4483:5;4536:3;4529:4;4521:6;4517:17;4513:27;4503:55;;4554:1;4551;4544:12;4503:55;4590:6;4577:20;4616:4;4640:79;4656:62;4715:2;4656:62;:::i;4640:79::-;4753:15;;;4839:1;4835:10;;;;4823:23;;4819:32;;;4784:12;;;;4863:15;;;4860:35;;;4891:1;4888;4881:12;4860:35;4927:2;4919:6;4915:15;4939:368;4955:6;4950:3;4947:15;4939:368;;;5041:3;5028:17;5077:18;5064:11;5061:35;5058:125;;;5137:1;5166:2;5162;5155:14;5058:125;5208:56;5260:3;5255:2;5241:11;5233:6;5229:24;5225:33;5208:56;:::i;:::-;5196:69;;-1:-1:-1;5285:12:1;;;;4972;;4939:368;;5341:118;5427:5;5420:13;5413:21;5406:5;5403:32;5393:60;;5449:1;5446;5439:12;5464:128;5529:20;;5558:28;5529:20;5558:28;:::i;5597:153::-;5665:20;;5694:50;5665:20;5694:50;:::i;5755:1246::-;5812:5;5860:6;5848:9;5843:3;5839:19;5835:32;5832:52;;;5880:1;5877;5870:12;5832:52;5902:22;;:::i;:::-;5893:31;;5960:9;5947:23;5989:18;6030:2;6022:6;6019:14;6016:34;;;6046:1;6043;6036:12;6016:34;6073:76;6145:3;6136:6;6125:9;6121:22;6073:76;:::i;:::-;6066:5;6059:91;6210:2;6199:9;6195:18;6182:32;6177:2;6170:5;6166:14;6159:56;6275:2;6264:9;6260:18;6247:32;6242:2;6235:5;6231:14;6224:56;6333:2;6322:9;6318:18;6305:32;6289:48;;6362:2;6352:8;6349:16;6346:36;;;6378:1;6375;6368:12;6346:36;6414:59;6469:3;6458:8;6447:9;6443:24;6414:59;:::i;:::-;6409:2;6402:5;6398:14;6391:83;6527:3;6516:9;6512:19;6499:33;6483:49;;6557:2;6547:8;6544:16;6541:36;;;6573:1;6570;6563:12;6541:36;6610:57;6663:3;6652:8;6641:9;6637:24;6610:57;:::i;:::-;6604:3;6597:5;6593:15;6586:82;6701:36;6732:3;6721:9;6717:19;6701:36;:::i;:::-;6695:3;6688:5;6684:15;6677:61;6771:39;6805:3;6794:9;6790:19;6771:39;:::i;:::-;6765:3;6758:5;6754:15;6747:64;6864:3;6853:9;6849:19;6836:33;6820:49;;6894:2;6884:8;6881:16;6878:36;;;6910:1;6907;6900:12;6878:36;;6947:47;6990:3;6979:8;6968:9;6964:24;6947:47;:::i;:::-;6941:3;6934:5;6930:15;6923:72;;5755:1246;;;;:::o;7006:1210::-;7174:6;7182;7190;7198;7206;7214;7222;7230;7238;7291:3;7279:9;7270:7;7266:23;7262:33;7259:53;;;7308:1;7305;7298:12;7259:53;7344:9;7331:23;7321:33;;7401:2;7390:9;7386:18;7373:32;7363:42;;7456:2;7445:9;7441:18;7428:32;7479:18;7520:2;7512:6;7509:14;7506:34;;;7536:1;7533;7526:12;7506:34;7575:58;7625:7;7616:6;7605:9;7601:22;7575:58;:::i;:::-;7652:8;;-1:-1:-1;7549:84:1;-1:-1:-1;7549:84:1;;-1:-1:-1;7706:36:1;7738:2;7723:18;;7706:36;:::i;:::-;7696:46;;7789:3;7778:9;7774:19;7761:33;7751:43;;7847:3;7836:9;7832:19;7819:33;7803:49;;7877:2;7867:8;7864:16;7861:36;;;7893:1;7890;7883:12;7861:36;7916:51;7959:7;7948:8;7937:9;7933:24;7916:51;:::i;:::-;7906:61;;8020:3;8009:9;8005:19;7992:33;7976:49;;8050:2;8040:8;8037:16;8034:36;;;8066:1;8063;8056:12;8034:36;;8089:63;8144:7;8133:8;8122:9;8118:24;8089:63;:::i;:::-;8079:73;;;8171:39;8205:3;8194:9;8190:19;8171:39;:::i;:::-;8161:49;;7006:1210;;;;;;;;;;;:::o;8403:334::-;8471:6;8479;8532:2;8520:9;8511:7;8507:23;8503:32;8500:52;;;8548:1;8545;8538:12;8500:52;8584:9;8571:23;8561:33;;8644:2;8633:9;8629:18;8616:32;8657:50;8701:5;8657:50;:::i;:::-;8726:5;8716:15;;;8403:334;;;;;:::o;8742:266::-;8801:6;8854:2;8842:9;8833:7;8829:23;8825:32;8822:52;;;8870:1;8867;8860:12;8822:52;8909:9;8896:23;8928:50;8972:5;8928:50;:::i;9013:1224::-;9242:6;9250;9258;9266;9274;9282;9290;9298;9351:3;9339:9;9330:7;9326:23;9322:33;9319:53;;;9368:1;9365;9358:12;9319:53;9408:9;9395:23;9437:18;9478:2;9470:6;9467:14;9464:34;;;9494:1;9491;9484:12;9464:34;9517:80;9589:7;9580:6;9569:9;9565:22;9517:80;:::i;:::-;9507:90;;9644:2;9633:9;9629:18;9616:32;9606:42;;9695:2;9684:9;9680:18;9667:32;9657:42;;9752:2;9741:9;9737:18;9724:32;9708:48;;9781:2;9771:8;9768:16;9765:36;;;9797:1;9794;9787:12;9765:36;9820:63;9875:7;9864:8;9853:9;9849:24;9820:63;:::i;:::-;9810:73;;9936:3;9925:9;9921:19;9908:33;9892:49;;9966:2;9956:8;9953:16;9950:36;;;9982:1;9979;9972:12;9950:36;;10005:61;10058:7;10047:8;10036:9;10032:24;10005:61;:::i;:::-;9995:71;;;10085:36;10116:3;10105:9;10101:19;10085:36;:::i;:::-;10075:46;;10140:39;10174:3;10163:9;10159:19;10140:39;:::i;:::-;10130:49;;10226:3;10215:9;10211:19;10198:33;10188:43;;9013:1224;;;;;;;;;;;:::o;10424:180::-;10483:6;10536:2;10524:9;10515:7;10511:23;10507:32;10504:52;;;10552:1;10549;10542:12;10504:52;-1:-1:-1;10575:23:1;;10424:180;-1:-1:-1;10424:180:1:o;11691:626::-;11788:6;11796;11849:2;11837:9;11828:7;11824:23;11820:32;11817:52;;;11865:1;11862;11855:12;11817:52;11905:9;11892:23;11934:18;11975:2;11967:6;11964:14;11961:34;;;11991:1;11988;11981:12;11961:34;12029:6;12018:9;12014:22;12004:32;;12074:7;12067:4;12063:2;12059:13;12055:27;12045:55;;12096:1;12093;12086:12;12045:55;12136:2;12123:16;12162:2;12154:6;12151:14;12148:34;;;12178:1;12175;12168:12;12148:34;12231:7;12226:2;12216:6;12213:1;12209:14;12205:2;12201:23;12197:32;12194:45;12191:65;;;12252:1;12249;12242:12;12191:65;12283:2;12275:11;;;;;12305:6;;-1:-1:-1;11691:626:1;;-1:-1:-1;;;;11691:626:1:o;12322:250::-;12407:1;12417:113;12431:6;12428:1;12425:13;12417:113;;;12507:11;;;12501:18;12488:11;;;12481:39;12453:2;12446:10;12417:113;;;-1:-1:-1;;12564:1:1;12546:16;;12539:27;12322:250::o;12577:329::-;12618:3;12656:5;12650:12;12683:6;12678:3;12671:19;12699:76;12768:6;12761:4;12756:3;12752:14;12745:4;12738:5;12734:16;12699:76;:::i;:::-;12820:2;12808:15;12825:66;12804:88;12795:98;;;;12895:4;12791:109;;12577:329;-1:-1:-1;;12577:329:1:o;12911:614::-;12962:3;13000:5;12994:12;13027:6;13022:3;13015:19;13053:4;13094:2;13089:3;13085:12;13119:11;13146;13139:18;;13196:6;13193:1;13189:14;13182:5;13178:26;13166:38;;13238:2;13231:5;13227:14;13259:1;13269:230;13283:6;13280:1;13277:13;13269:230;;;13354:5;13348:4;13344:16;13339:3;13332:29;13382:37;13414:4;13405:6;13399:13;13382:37;:::i;:::-;13477:12;;;;13374:45;-1:-1:-1;13442:15:1;;;;13305:1;13298:9;13269:230;;;-1:-1:-1;13515:4:1;;12911:614;-1:-1:-1;;;;;;;12911:614:1:o;13530:277::-;13727:2;13716:9;13709:21;13690:4;13747:54;13797:2;13786:9;13782:18;13774:6;13747:54;:::i;13997:542::-;14083:6;14091;14099;14152:2;14140:9;14131:7;14127:23;14123:32;14120:52;;;14168:1;14165;14158:12;14120:52;14207:9;14194:23;14226:50;14270:5;14226:50;:::i;:::-;14295:5;-1:-1:-1;14347:2:1;14332:18;;14319:32;;-1:-1:-1;14402:2:1;14387:18;;14374:32;14429:18;14418:30;;14415:50;;;14461:1;14458;14451:12;14415:50;14484:49;14525:7;14516:6;14505:9;14501:22;14484:49;:::i;:::-;14474:59;;;13997:542;;;;;:::o;14544:426::-;14612:6;14620;14673:2;14661:9;14652:7;14648:23;14644:32;14641:52;;;14689:1;14686;14679:12;14641:52;14728:9;14715:23;14747:50;14791:5;14747:50;:::i;:::-;14816:5;-1:-1:-1;14873:2:1;14858:18;;14845:32;14886:52;14845:32;14886:52;:::i;15220:1302::-;15440:6;15448;15456;15464;15472;15480;15488;15541:3;15529:9;15520:7;15516:23;15512:33;15509:53;;;15558:1;15555;15548:12;15509:53;15598:9;15585:23;15627:18;15668:2;15660:6;15657:14;15654:34;;;15684:1;15681;15674:12;15654:34;15707:80;15779:7;15770:6;15759:9;15755:22;15707:80;:::i;:::-;15697:90;;15834:2;15823:9;15819:18;15806:32;15796:42;;15885:2;15874:9;15870:18;15857:32;15847:42;;15942:2;15931:9;15927:18;15914:32;15898:48;;15971:2;15961:8;15958:16;15955:36;;;15987:1;15984;15977:12;15955:36;16010:63;16065:7;16054:8;16043:9;16039:24;16010:63;:::i;:::-;16000:73;;16126:3;16115:9;16111:19;16098:33;16082:49;;16156:2;16146:8;16143:16;16140:36;;;16172:1;16169;16162:12;16140:36;;16195:61;16248:7;16237:8;16226:9;16222:24;16195:61;:::i;:::-;16185:71;;;16306:3;16295:9;16291:19;16278:33;16320:28;16342:5;16320:28;:::i;:::-;16367:5;-1:-1:-1;16424:3:1;16409:19;;16396:33;16438:52;16396:33;16438:52;:::i;:::-;16509:7;16499:17;;;15220:1302;;;;;;;;;;:::o;16527:184::-;16579:77;16576:1;16569:88;16676:4;16673:1;16666:15;16700:4;16697:1;16690:15;16716:128;16783:9;;;16804:11;;;16801:37;;;16818:18;;:::i;16849:184::-;16901:77;16898:1;16891:88;16998:4;16995:1;16988:15;17022:4;17019:1;17012:15;17539:325;17627:6;17622:3;17615:19;17679:6;17672:5;17665:4;17660:3;17656:14;17643:43;;17731:1;17724:4;17715:6;17710:3;17706:16;17702:27;17695:38;17597:3;17853:4;17783:66;17778:2;17770:6;17766:15;17762:88;17757:3;17753:98;17749:109;17742:116;;17539:325;;;;:::o;17869:580::-;18121:4;18150:3;18162:48;18200:9;18192:6;17121:5;17115:12;17110:3;17103:25;17177:4;17170:5;17166:16;17160:23;17153:4;17148:3;17144:14;17137:47;17233:4;17226:5;17222:16;17216:23;17209:4;17204:3;17200:14;17193:47;17286:4;17279:5;17275:16;17269:23;17311:42;17403:2;17389:12;17385:21;17378:4;17373:3;17369:14;17362:45;17468:2;17460:4;17453:5;17449:16;17443:23;17439:32;17432:4;17427:3;17423:14;17416:56;;;17521:4;17514:5;17510:16;17504:23;17497:4;17492:3;17488:14;17481:47;17038:496;;;18162:48;18247:2;18241:3;18230:9;18226:19;18219:31;18273:44;18313:2;18302:9;18298:18;18290:6;18273:44;:::i;:::-;18259:58;;18366:9;18358:6;18354:22;18348:3;18337:9;18333:19;18326:51;18394:49;18436:6;18428;18420;18394:49;:::i;18454:741::-;18752:4;18781:3;18793:48;18831:9;18823:6;17121:5;17115:12;17110:3;17103:25;17177:4;17170:5;17166:16;17160:23;17153:4;17148:3;17144:14;17137:47;17233:4;17226:5;17222:16;17216:23;17209:4;17204:3;17200:14;17193:47;17286:4;17279:5;17275:16;17269:23;17311:42;17403:2;17389:12;17385:21;17378:4;17373:3;17369:14;17362:45;17468:2;17460:4;17453:5;17449:16;17443:23;17439:32;17432:4;17427:3;17423:14;17416:56;;;17521:4;17514:5;17510:16;17504:23;17497:4;17492:3;17488:14;17481:47;17038:496;;;18793:48;18878:2;18872:3;18861:9;18857:19;18850:31;18904:44;18944:2;18933:9;18929:18;18921:6;18904:44;:::i;:::-;18890:58;;18997:9;18989:6;18985:22;18979:3;18968:9;18964:19;18957:51;19031:49;19073:6;19065;19057;19031:49;:::i;:::-;19017:63;;19129:9;19121:6;19117:22;19111:3;19100:9;19096:19;19089:51;19157:32;19182:6;19174;19157:32;:::i;:::-;19149:40;18454:741;-1:-1:-1;;;;;;;;18454:741:1:o;19200:315::-;19320:19;;19359:2;19351:11;;19348:161;;;19431:66;19420:2;19416:12;;;19413:1;19409:20;19405:93;19394:105;19200:315;;;;:::o;20821:503::-;20893:3;20931:5;20925:12;20958:6;20953:3;20946:19;20984:4;21013:2;21008:3;21004:12;20997:19;;21050:2;21043:5;21039:14;21071:1;21081:218;21095:6;21092:1;21089:13;21081:218;;;21160:13;;21175:42;21156:62;21144:75;;21239:12;;;;21274:15;;;;21117:1;21110:9;21081:218;;;-1:-1:-1;21315:3:1;;20821:503;-1:-1:-1;;;;;20821:503:1:o;21329:435::-;21382:3;21420:5;21414:12;21447:6;21442:3;21435:19;21473:4;21502:2;21497:3;21493:12;21486:19;;21539:2;21532:5;21528:14;21560:1;21570:169;21584:6;21581:1;21578:13;21570:169;;;21645:13;;21633:26;;21679:12;;;;21714:15;;;;21606:1;21599:9;21570:169;;21769:726;22136:3;22125:9;22118:22;22099:4;22163:76;22234:3;22223:9;22219:19;22211:6;22163:76;:::i;:::-;22275:6;22270:2;22259:9;22255:18;22248:34;22318:6;22313:2;22302:9;22298:18;22291:34;22373:9;22365:6;22361:22;22356:2;22345:9;22341:18;22334:50;22401:44;22438:6;22430;22401:44;:::i;:::-;22393:52;;;22482:6;22476:3;22465:9;22461:19;22454:35;21769:726;;;;;;;;:::o;23252:580::-;23329:4;23335:6;23395:11;23382:25;23485:66;23474:8;23458:14;23454:29;23450:102;23430:18;23426:127;23416:155;;23567:1;23564;23557:12;23416:155;23594:33;;23646:20;;;-1:-1:-1;23689:18:1;23678:30;;23675:50;;;23721:1;23718;23711:12;23675:50;23754:4;23742:17;;-1:-1:-1;23785:14:1;23781:27;;;23771:38;;23768:58;;;23822:1;23819;23812:12;23837:440;24066:6;24058;24053:3;24040:33;24022:3;24101:6;24096:3;24092:16;24128:1;24124:2;24117:13;24159:6;24153:13;24175:65;24233:6;24229:2;24222:4;24214:6;24210:17;24175:65;:::i;:::-;24256:15;;23837:440;-1:-1:-1;;;;;23837:440:1:o;24282:195::-;24321:3;24352:66;24345:5;24342:77;24339:103;;24422:18;;:::i;:::-;-1:-1:-1;24469:1:1;24458:13;;24282:195::o;25499:184::-;25569:6;25622:2;25610:9;25601:7;25597:23;25593:32;25590:52;;;25638:1;25635;25628:12;25590:52;-1:-1:-1;25661:16:1;;25499:184;-1:-1:-1;25499:184:1:o;25898:::-;25950:77;25947:1;25940:88;26047:4;26044:1;26037:15;26071:4;26068:1;26061:15;26087:791;26171:5;26224:3;26217:4;26209:6;26205:17;26201:27;26191:55;;26242:1;26239;26232:12;26191:55;26271:6;26265:13;26297:4;26321:79;26337:62;26396:2;26337:62;:::i;26321:79::-;26434:15;;;26520:1;26516:10;;;;26504:23;;26500:32;;;26465:12;;;;26544:15;;;26541:35;;;26572:1;26569;26562:12;26541:35;26608:2;26600:6;26596:15;26620:229;26636:6;26631:3;26628:15;26620:229;;;26709:3;26703:10;26726:50;26770:5;26726:50;:::i;:::-;26789:18;;26827:12;;;;26653;;26620:229;;26883:441;26936:5;26989:3;26982:4;26974:6;26970:17;26966:27;26956:55;;27007:1;27004;26997:12;26956:55;27036:6;27030:13;27067:48;27083:31;27111:2;27083:31;:::i;27067:48::-;27140:2;27131:7;27124:19;27186:3;27179:4;27174:2;27166:6;27162:15;27158:26;27155:35;27152:55;;;27203:1;27200;27193:12;27152:55;27216:77;27290:2;27283:4;27274:7;27270:18;27263:4;27255:6;27251:17;27216:77;:::i;27329:913::-;27392:5;27445:3;27438:4;27430:6;27426:17;27422:27;27412:55;;27463:1;27460;27453:12;27412:55;27492:6;27486:13;27518:4;27542:79;27558:62;27617:2;27558:62;:::i;27542:79::-;27655:15;;;27741:1;27737:10;;;;27725:23;;27721:32;;;27686:12;;;;27765:15;;;27762:35;;;27793:1;27790;27783:12;27762:35;27829:2;27821:6;27817:15;27841:372;27857:6;27852:3;27849:15;27841:372;;;27936:3;27930:10;27972:18;27959:11;27956:35;27953:125;;;28032:1;28061:2;28057;28050:14;27953:125;28103:67;28166:3;28161:2;28147:11;28139:6;28135:24;28131:33;28103:67;:::i;:::-;28091:80;;-1:-1:-1;28191:12:1;;;;27874;;27841:372;;28247:678;28312:5;28365:3;28358:4;28350:6;28346:17;28342:27;28332:55;;28383:1;28380;28373:12;28332:55;28412:6;28406:13;28438:4;28462:79;28478:62;28537:2;28478:62;:::i;28462:79::-;28575:15;;;28661:1;28657:10;;;;28645:23;;28641:32;;;28606:12;;;;28685:15;;;28682:35;;;28713:1;28710;28703:12;28682:35;28749:2;28741:6;28737:15;28761:135;28777:6;28772:3;28769:15;28761:135;;;28843:10;;28831:23;;28874:12;;;;28794;;28761:135;;28930:165;29017:13;;29039:50;29017:13;29039:50;:::i;29100:132::-;29176:13;;29198:28;29176:13;29198:28;:::i;29237:1343::-;29485:6;29493;29501;29509;29517;29525;29533;29586:3;29574:9;29565:7;29561:23;29557:33;29554:53;;;29603:1;29600;29593:12;29554:53;29636:9;29630:16;29665:18;29706:2;29698:6;29695:14;29692:34;;;29722:1;29719;29712:12;29692:34;29745:91;29828:7;29819:6;29808:9;29804:22;29745:91;:::i;:::-;29735:101;;29876:2;29865:9;29861:18;29855:25;29845:35;;29926:2;29915:9;29911:18;29905:25;29889:41;;29955:2;29945:8;29942:16;29939:36;;;29971:1;29968;29961:12;29939:36;29994:72;30058:7;30047:8;30036:9;30032:24;29994:72;:::i;:::-;29984:82;;30112:2;30101:9;30097:18;30091:25;30075:41;;30141:2;30131:8;30128:16;30125:36;;;30157:1;30154;30147:12;30125:36;30180:74;30246:7;30235:8;30224:9;30220:24;30180:74;:::i;:::-;30170:84;;30273:58;30326:3;30315:9;30311:19;30273:58;:::i;:::-;30263:68;;30350:47;30392:3;30381:9;30377:19;30350:47;:::i;:::-;30340:57;;30443:3;30432:9;30428:19;30422:26;30406:42;;30473:2;30463:8;30460:16;30457:36;;;30489:1;30486;30479:12;30457:36;;30512:62;30566:7;30555:8;30544:9;30540:24;30512:62;:::i;:::-;30502:72;;;29237:1343;;;;;;;;;;:::o;30585:1078::-;31070:3;31059:9;31052:22;31033:4;31097:76;31168:3;31157:9;31153:19;31145:6;31097:76;:::i;:::-;31209:6;31204:2;31193:9;31189:18;31182:34;31252:6;31247:2;31236:9;31232:18;31225:34;31307:9;31299:6;31295:22;31290:2;31279:9;31275:18;31268:50;31341:44;31378:6;31370;31341:44;:::i;:::-;31327:58;;31434:9;31426:6;31422:22;31416:3;31405:9;31401:19;31394:51;31462:42;31497:6;31489;31462:42;:::i;:::-;31548:14;;31541:22;31535:3;31520:19;;31513:51;-1:-1:-1;;31613:42:1;31601:55;;;;31595:3;31580:19;;;31573:84;31454:50;30585:1078;-1:-1:-1;;;;;30585:1078:1:o;31668:287::-;31797:3;31835:6;31829:13;31851:66;31910:6;31905:3;31898:4;31890:6;31886:17;31851:66;:::i;:::-;31933:16;;;;;31668:287;-1:-1:-1;;31668:287:1:o;31960:357::-;32078:12;;32125:4;32114:16;;;32108:23;;32078:12;32143:16;;32140:171;;;32233:66;32223:6;32217:4;32213:17;32210:1;32206:25;32202:98;32195:5;32191:110;32182:119;;32140:171;;31960:357;;;:::o;32322:408::-;32537:42;32529:6;32525:55;32514:9;32507:74;32617:6;32612:2;32601:9;32597:18;32590:34;32660:2;32655;32644:9;32640:18;32633:30;32488:4;32680:44;32720:2;32709:9;32705:18;32697:6;32680:44;:::i;:::-;32672:52;32322:408;-1:-1:-1;;;;;32322:408:1:o;33448:245::-;33515:6;33568:2;33556:9;33547:7;33543:23;33539:32;33536:52;;;33584:1;33581;33574:12;33536:52;33616:9;33610:16;33635:28;33657:5;33635:28;:::i;34524:812::-;34935:25;34930:3;34923:38;34905:3;34990:6;34984:13;35006:75;35074:6;35069:2;35064:3;35060:12;35053:4;35045:6;35041:17;35006:75;:::i;:::-;35145:19;35140:2;35100:16;;;35132:11;;;35125:40;35190:13;;35212:76;35190:13;35274:2;35266:11;;35259:4;35247:17;;35212:76;:::i;:::-;35308:17;35327:2;35304:26;;34524:812;-1:-1:-1;;;;34524:812:1:o;35341:219::-;35490:2;35479:9;35472:21;35453:4;35510:44;35550:2;35539:9;35535:18;35527:6;35510:44;:::i;36386:168::-;36459:9;;;36490;;36507:15;;;36501:22;;36487:37;36477:71;;36528:18;;:::i;36559:125::-;36624:9;;;36645:10;;;36642:36;;;36658:18;;:::i;36689:196::-;36728:3;36756:5;36746:39;;36765:18;;:::i;:::-;-1:-1:-1;36812:66:1;36801:78;;36689:196::o;37960:270::-;38030:6;38083:2;38071:9;38062:7;38058:23;38054:32;38051:52;;;38099:1;38096;38089:12;38051:52;38131:9;38125:16;38150:50;38194:5;38150:50;:::i;40043:188::-;40122:13;;40175:30;40164:42;;40154:53;;40144:81;;40221:1;40218;40211:12;40236:450;40323:6;40331;40339;40392:2;40380:9;40371:7;40367:23;40363:32;40360:52;;;40408:1;40405;40398:12;40360:52;40431:40;40461:9;40431:40;:::i;:::-;40421:50;;40490:49;40535:2;40524:9;40520:18;40490:49;:::i;:::-;40480:59;;40582:2;40571:9;40567:18;40561:25;40626:10;40619:5;40615:22;40608:5;40605:33;40595:61;;40652:1;40649;40642:12;40595:61;40675:5;40665:15;;;40236:450;;;;;:::o;40691:274::-;40731:1;40757;40747:189;;40792:77;40789:1;40782:88;40893:4;40890:1;40883:15;40921:4;40918:1;40911:15;40747:189;-1:-1:-1;40950:9:1;;40691:274::o;40970:184::-;41022:77;41019:1;41012:88;41119:4;41116:1;41109:15;41143:4;41140:1;41133:15
Swarm Source
ipfs://f233254f60810fffa4df2aa6c8f504943466fc2c52e7fbcec0dda0e42998d420
Loading...
Loading
Loading...
Loading
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.