Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 25 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Approve | 38990787 | 2 days ago | IN | 0 ETH | 0.00000022 | ||||
| Approve | 38631118 | 11 days ago | IN | 0 ETH | 0.00000006 | ||||
| Approve | 38508941 | 13 days ago | IN | 0 ETH | 0.00000004 | ||||
| Approve | 38501006 | 14 days ago | IN | 0 ETH | 0.00000005 | ||||
| Approve | 38468010 | 14 days ago | IN | 0 ETH | 0.0000006 | ||||
| Approve | 38327944 | 18 days ago | IN | 0 ETH | 0.00000076 | ||||
| Approve | 38299182 | 18 days ago | IN | 0 ETH | 0.00000012 | ||||
| Approve | 38262357 | 19 days ago | IN | 0 ETH | 0.0000003 | ||||
| Approve | 38156074 | 22 days ago | IN | 0 ETH | 0.00000029 | ||||
| Approve | 38153518 | 22 days ago | IN | 0 ETH | 0.0000007 | ||||
| Approve | 38050632 | 24 days ago | IN | 0 ETH | 0.00000051 | ||||
| Approve | 37691334 | 32 days ago | IN | 0 ETH | 0.00000193 | ||||
| Approve | 37674497 | 33 days ago | IN | 0 ETH | 0.00000067 | ||||
| Approve | 37572862 | 35 days ago | IN | 0 ETH | 0.00000034 | ||||
| Approve | 37481610 | 37 days ago | IN | 0 ETH | 0.0000005 | ||||
| Approve | 37389748 | 39 days ago | IN | 0 ETH | 0.00000094 | ||||
| Approve | 37317520 | 41 days ago | IN | 0 ETH | 0.00000083 | ||||
| Approve | 37282716 | 42 days ago | IN | 0 ETH | 0.00000042 | ||||
| Approve | 37033445 | 48 days ago | IN | 0 ETH | 0.00000005 | ||||
| Approve | 36880619 | 51 days ago | IN | 0 ETH | 0.00000034 | ||||
| Approve | 36857350 | 52 days ago | IN | 0 ETH | 0.00000087 | ||||
| Approve | 36571329 | 58 days ago | IN | 0 ETH | 0.00000033 | ||||
| Approve | 36478541 | 60 days ago | IN | 0 ETH | 0.00000044 | ||||
| Approve | 36459542 | 61 days ago | IN | 0 ETH | 0.00000012 | ||||
| Set Approval For... | 36450272 | 61 days ago | IN | 0 ETH | 0.00000042 |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Humain
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
No with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// humainlab.xyz
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {ERC404} from "../ERC404.sol";
import {ERC404UniswapV3Exempt} from "../extensions/ERC404UniswapV3Exempt.sol";
contract Humain is Ownable, ERC404, ERC404UniswapV3Exempt {
string public baseURI;
constructor(
string memory name_,
string memory symbol_,
string memory baseURI_,
uint8 decimals_,
uint256 maxTotalSupplyERC721_,
address initialOwner_,
address initialMintRecipient_,
address uniswapSwapRouter_,
address uniswapV3NonfungiblePositionManager_
)
ERC404(name_, symbol_, decimals_)
Ownable(initialOwner_)
ERC404UniswapV3Exempt(
uniswapSwapRouter_,
uniswapV3NonfungiblePositionManager_
)
{
baseURI = baseURI_;
// Do not mint the ERC721s to the initial owner, as it's a waste of gas.
_setERC721TransferExempt(initialMintRecipient_, true);
_mintERC20(initialMintRecipient_, maxTotalSupplyERC721_ * units);
}
function tokenURI(uint256 id_) public view override returns (string memory) {
return string.concat(baseURI, Strings.toString(id_));
}
function setBaseURI(string memory baseURI_) external onlyOwner {
baseURI = baseURI_;
}
function setERC721TransferExempt(
address account_,
bool value_
) external onlyOwner {
_setERC721TransferExempt(account_, value_);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @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.
*
* The initial owner is set to the address provided by the deployer. 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;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @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 {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @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 {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_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);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721Receiver.sol)
pragma solidity ^0.8.20;
import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC-721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC-721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* 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[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
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 success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * SafeCast.toUint(condition));
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(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 towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
Panic.panic(Panic.DIVISION_BY_ZERO);
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
}
}
/**
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
*
* 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²⁵⁶ and mod 2²⁵⁶ - 1, then use
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2²⁵⁶ + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
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²⁵⁶. Also prevents denominator == 0.
if (denominator <= prod1) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_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.
uint256 twos = denominator & (0 - denominator);
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²⁵⁶ / 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²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
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⁸
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
inverse *= 2 - denominator * inverse; // inverse mod 2³²
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
// 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²⁵⁶. Since the preconditions guarantee that the outcome is
// less than 2²⁵⁶, 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;
}
}
/**
* @dev 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) {
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
}
/**
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
*
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
*
* If the input value is not inversible, 0 is returned.
*
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
* inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
*/
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
unchecked {
if (n == 0) return 0;
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
// ax + ny = 1
// ax = 1 + (-y)n
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
// If the remainder is 0 the gcd is n right away.
uint256 remainder = a % n;
uint256 gcd = n;
// Therefore the initial coefficients are:
// ax + ny = gcd(a, n) = n
// 0a + 1n = n
int256 x = 0;
int256 y = 1;
while (remainder != 0) {
uint256 quotient = gcd / remainder;
(gcd, remainder) = (
// The old remainder is the next gcd to try.
remainder,
// Compute the next remainder.
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
// where gcd is at most n (capped to type(uint256).max)
gcd - remainder * quotient
);
(x, y) = (
// Increment the coefficient of a.
y,
// Decrement the coefficient of n.
// Can overflow, but the result is casted to uint256 so that the
// next value of y is "wrapped around" to a value between 0 and n - 1.
x - y * int256(quotient)
);
}
if (gcd != 1) return 0; // No inverse exists.
return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
}
}
/**
* @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
*
* From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
* prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
* `a**(p-2)` is the modular multiplicative inverse of a in Fp.
*
* NOTE: this function does NOT check that `p` is a prime greater than `2`.
*/
function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
unchecked {
return Math.modExp(a, p - 2, p);
}
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
*
* Requirements:
* - modulus can't be zero
* - underlying staticcall to precompile must succeed
*
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
* interpreted as 0.
*/
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
(bool success, uint256 result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
* It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
* to operate modulo 0 or if the underlying precompile reverted.
*
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
* of a revert, but the result may be incorrectly interpreted as 0.
*/
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
if (m == 0) return (false, 0);
assembly ("memory-safe") {
let ptr := mload(0x40)
// | Offset | Content | Content (Hex) |
// |-----------|------------|--------------------------------------------------------------------|
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
// | 0x80:0x9f | value of e | 0x<.............................................................e> |
// | 0xa0:0xbf | value of m | 0x<.............................................................m> |
mstore(ptr, 0x20)
mstore(add(ptr, 0x20), 0x20)
mstore(add(ptr, 0x40), 0x20)
mstore(add(ptr, 0x60), b)
mstore(add(ptr, 0x80), e)
mstore(add(ptr, 0xa0), m)
// Given the result < m, it's guaranteed to fit in 32 bytes,
// so we can use the memory scratch space located at offset 0.
success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
result := mload(0x00)
}
}
/**
* @dev Variant of {modExp} that supports inputs of arbitrary length.
*/
function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
(bool success, bytes memory result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Variant of {tryModExp} that supports inputs of arbitrary length.
*/
function tryModExp(
bytes memory b,
bytes memory e,
bytes memory m
) internal view returns (bool success, bytes memory result) {
if (_zeroBytes(m)) return (false, new bytes(0));
uint256 mLen = m.length;
// Encode call args in result and move the free memory pointer
result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
assembly ("memory-safe") {
let dataPtr := add(result, 0x20)
// Write result on top of args to avoid allocating extra memory.
success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
// Overwrite the length.
// result.length > returndatasize() is guaranteed because returndatasize() == m.length
mstore(result, mLen)
// Set the memory pointer after the returned data.
mstore(0x40, add(dataPtr, mLen))
}
}
/**
* @dev Returns whether the provided byte array is zero.
*/
function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
for (uint256 i = 0; i < byteArray.length; ++i) {
if (byteArray[i] != 0) {
return false;
}
}
return true;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* This method is based on Newton's method for computing square roots; the algorithm is restricted to only
* using integer operations.
*/
function sqrt(uint256 a) internal pure returns (uint256) {
unchecked {
// Take care of easy edge cases when a == 0 or a == 1
if (a <= 1) {
return a;
}
// In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
// sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
// the current value as `ε_n = | x_n - sqrt(a) |`.
//
// For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
// of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
// bigger than any uint256.
//
// By noticing that
// `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
// we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
// to the msb function.
uint256 aa = a;
uint256 xn = 1;
if (aa >= (1 << 128)) {
aa >>= 128;
xn <<= 64;
}
if (aa >= (1 << 64)) {
aa >>= 64;
xn <<= 32;
}
if (aa >= (1 << 32)) {
aa >>= 32;
xn <<= 16;
}
if (aa >= (1 << 16)) {
aa >>= 16;
xn <<= 8;
}
if (aa >= (1 << 8)) {
aa >>= 8;
xn <<= 4;
}
if (aa >= (1 << 4)) {
aa >>= 4;
xn <<= 2;
}
if (aa >= (1 << 2)) {
xn <<= 1;
}
// We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
//
// We can refine our estimation by noticing that the middle of that interval minimizes the error.
// If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
// This is going to be our x_0 (and ε_0)
xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
// From here, Newton's method give us:
// x_{n+1} = (x_n + a / x_n) / 2
//
// One should note that:
// x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
// = ((x_n² + a) / (2 * x_n))² - a
// = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
// = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
// = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
// = (x_n² - a)² / (2 * x_n)²
// = ((x_n² - a) / (2 * x_n))²
// ≥ 0
// Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
//
// This gives us the proof of quadratic convergence of the sequence:
// ε_{n+1} = | x_{n+1} - sqrt(a) |
// = | (x_n + a / x_n) / 2 - sqrt(a) |
// = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
// = | (x_n - sqrt(a))² / (2 * x_n) |
// = | ε_n² / (2 * x_n) |
// = ε_n² / | (2 * x_n) |
//
// For the first iteration, we have a special case where x_0 is known:
// ε_1 = ε_0² / | (2 * x_0) |
// ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
// ≤ 2**(2*e-4) / (3 * 2**(e-1))
// ≤ 2**(e-3) / 3
// ≤ 2**(e-3-log2(3))
// ≤ 2**(e-4.5)
//
// For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
// ε_{n+1} = ε_n² / | (2 * x_n) |
// ≤ (2**(e-k))² / (2 * 2**(e-1))
// ≤ 2**(2*e-2*k) / 2**e
// ≤ 2**(e-2*k)
xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above
xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5
xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9
xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18
xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36
xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72
// Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
// ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
// sqrt(a) or sqrt(a) + 1.
return xn - SafeCast.toUint(xn > a / xn);
}
}
/**
* @dev 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
uint256 exp;
unchecked {
exp = 128 * SafeCast.toUint(value > (1 << 128) - 1);
value >>= exp;
result += exp;
exp = 64 * SafeCast.toUint(value > (1 << 64) - 1);
value >>= exp;
result += exp;
exp = 32 * SafeCast.toUint(value > (1 << 32) - 1);
value >>= exp;
result += exp;
exp = 16 * SafeCast.toUint(value > (1 << 16) - 1);
value >>= exp;
result += exp;
exp = 8 * SafeCast.toUint(value > (1 << 8) - 1);
value >>= exp;
result += exp;
exp = 4 * SafeCast.toUint(value > (1 << 4) - 1);
value >>= exp;
result += exp;
exp = 2 * SafeCast.toUint(value > (1 << 2) - 1);
value >>= exp;
result += exp;
result += SafeCast.toUint(value > 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* 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;
uint256 isGt;
unchecked {
isGt = SafeCast.toUint(value > (1 << 128) - 1);
value >>= isGt * 128;
result += isGt * 16;
isGt = SafeCast.toUint(value > (1 << 64) - 1);
value >>= isGt * 64;
result += isGt * 8;
isGt = SafeCast.toUint(value > (1 << 32) - 1);
value >>= isGt * 32;
result += isGt * 4;
isGt = SafeCast.toUint(value > (1 << 16) - 1);
value >>= isGt * 16;
result += isGt * 2;
result += SafeCast.toUint(value > (1 << 8) - 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * int256(SafeCast.toUint(condition)));
}
}
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return ternary(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 {
// Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson.
// Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift,
// taking advantage of the most significant (or "sign" bit) in two's complement representation.
// This opcode adds new most significant bits set to the value of the previous most significant bit. As a result,
// the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative).
int256 mask = n >> 255;
// A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.
return uint256((n + mask) ^ mask);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)
pragma solidity ^0.8.20;
/**
* @dev Helper library for emitting standardized panic codes.
*
* ```solidity
* contract Example {
* using Panic for uint256;
*
* // Use any of the declared internal constants
* function foo() { Panic.GENERIC.panic(); }
*
* // Alternatively
* function foo() { Panic.panic(Panic.GENERIC); }
* }
* ```
*
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
*
* _Available since v5.1._
*/
// slither-disable-next-line unused-state
library Panic {
/// @dev generic / unspecified error
uint256 internal constant GENERIC = 0x00;
/// @dev used by the assert() builtin
uint256 internal constant ASSERT = 0x01;
/// @dev arithmetic underflow or overflow
uint256 internal constant UNDER_OVERFLOW = 0x11;
/// @dev division or modulo by zero
uint256 internal constant DIVISION_BY_ZERO = 0x12;
/// @dev enum conversion error
uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
/// @dev invalid encoding in storage
uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
/// @dev empty array pop
uint256 internal constant EMPTY_ARRAY_POP = 0x31;
/// @dev array out of bounds access
uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
/// @dev resource error (too large allocation or too large array)
uint256 internal constant RESOURCE_ERROR = 0x41;
/// @dev calling invalid internal function
uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
/// @dev Reverts with a panic code. Recommended to use with
/// the internal constants with predefined codes.
function panic(uint256 code) internal pure {
assembly ("memory-safe") {
mstore(0x00, 0x4e487b71)
mstore(0x20, code)
revert(0x1c, 0x24)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @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;
assembly ("memory-safe") {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
assembly ("memory-safe") {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(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) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
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 Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal
* representation, according to EIP-55.
*/
function toChecksumHexString(address addr) internal pure returns (string memory) {
bytes memory buffer = bytes(toHexString(addr));
// hash the hex part of buffer (skip length + 2 bytes, length 40)
uint256 hashValue;
assembly ("memory-safe") {
hashValue := shr(96, keccak256(add(buffer, 0x22), 40))
}
for (uint256 i = 41; i > 1; --i) {
// possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)
if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {
// case shift by xoring with 0x20
buffer[i] ^= 0x20;
}
hashValue >>= 4;
}
return string(buffer);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Immutable state
/// @notice Functions that return immutable state of the router
interface IPeripheryImmutableState {
/// @return Returns the address of the Uniswap V3 factory
function factory() external view returns (address);
/// @return Returns the address of WETH9
function WETH9() external view returns (address);
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IERC721Receiver} from "@openzeppelin/contracts/interfaces/IERC721Receiver.sol";
import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
import {IERC404} from "./interfaces/IERC404.sol";
import {DoubleEndedQueue} from "./lib/DoubleEndedQueue.sol";
import {ERC721Events} from "./lib/ERC721Events.sol";
import {ERC20Events} from "./lib/ERC20Events.sol";
abstract contract ERC404 is IERC404 {
using DoubleEndedQueue for DoubleEndedQueue.Uint256Deque;
/// @dev The queue of ERC-721 tokens stored in the contract.
DoubleEndedQueue.Uint256Deque private _storedERC721Ids;
/// @dev Token name
string public name;
/// @dev Token symbol
string public symbol;
/// @dev Decimals for ERC-20 representation
uint8 public immutable decimals;
/// @dev Units for ERC-20 representation
uint256 public immutable units;
/// @dev Total supply in ERC-20 representation
uint256 public totalSupply;
/// @dev Current mint counter which also represents the highest
/// minted id, monotonically increasing to ensure accurate ownership
uint256 public minted;
/// @dev Initial chain id for EIP-2612 support
uint256 internal immutable _INITIAL_CHAIN_ID;
/// @dev Initial domain separator for EIP-2612 support
bytes32 internal immutable _INITIAL_DOMAIN_SEPARATOR;
/// @dev Balance of user in ERC-20 representation
mapping(address => uint256) public balanceOf;
/// @dev Allowance of user in ERC-20 representation
mapping(address => mapping(address => uint256)) public allowance;
/// @dev Approval in ERC-721 representaion
mapping(uint256 => address) public getApproved;
/// @dev Approval for all in ERC-721 representation
mapping(address => mapping(address => bool)) public isApprovedForAll;
/// @dev Packed representation of ownerOf and owned indices
mapping(uint256 => uint256) internal _ownedData;
/// @dev Array of owned ids in ERC-721 representation
mapping(address => uint256[]) internal _owned;
/// @dev Addresses that are exempt from ERC-721 transfer, typically for gas savings (pairs, routers, etc)
mapping(address => bool) internal _erc721TransferExempt;
/// @dev EIP-2612 nonces
mapping(address => uint256) public nonces;
/// @dev Address bitmask for packed ownership data
uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
/// @dev Owned index bitmask for packed ownership data
uint256 private constant _BITMASK_OWNED_INDEX = ((1 << 96) - 1) << 160;
/// @dev Constant for token id encoding
uint256 public constant ID_ENCODING_PREFIX = 1 << 255;
constructor(string memory name_, string memory symbol_, uint8 decimals_) {
name = name_;
symbol = symbol_;
if (decimals_ < 18) {
revert DecimalsTooLow();
}
decimals = decimals_;
units = 10 ** decimals;
// EIP-2612 initialization
_INITIAL_CHAIN_ID = block.chainid;
_INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator();
}
/// @notice Function to find owner of a given ERC-721 token
function ownerOf(
uint256 id_
) public view virtual returns (address erc721Owner) {
erc721Owner = _getOwnerOf(id_);
if (!_isValidTokenId(id_)) {
revert InvalidTokenId();
}
if (erc721Owner == address(0)) {
revert NotFound();
}
}
function owned(
address owner_
) public view virtual returns (uint256[] memory) {
return _owned[owner_];
}
function erc721BalanceOf(
address owner_
) public view virtual returns (uint256) {
return _owned[owner_].length;
}
function erc20BalanceOf(
address owner_
) public view virtual returns (uint256) {
return balanceOf[owner_];
}
function erc20TotalSupply() public view virtual returns (uint256) {
return totalSupply;
}
function erc721TotalSupply() public view virtual returns (uint256) {
return minted;
}
function getERC721QueueLength() public view virtual returns (uint256) {
return _storedERC721Ids.length();
}
function getERC721TokensInQueue(
uint256 start_,
uint256 count_
) public view virtual returns (uint256[] memory) {
uint256[] memory tokensInQueue = new uint256[](count_);
for (uint256 i = start_; i < start_ + count_; ) {
tokensInQueue[i - start_] = _storedERC721Ids.at(i);
unchecked {
++i;
}
}
return tokensInQueue;
}
/// @notice tokenURI must be implemented by child contract
function tokenURI(uint256 id_) public view virtual returns (string memory);
/// @notice Function for token approvals
/// @dev This function assumes the operator is attempting to approve
/// an ERC-721 if valueOrId_ is a possibly valid ERC-721 token id.
/// Unlike setApprovalForAll, spender_ must be allowed to be 0x0 so
/// that approval can be revoked.
function approve(
address spender_,
uint256 valueOrId_
) public virtual returns (bool) {
if (_isValidTokenId(valueOrId_)) {
erc721Approve(spender_, valueOrId_);
} else {
return erc20Approve(spender_, valueOrId_);
}
return true;
}
function erc721Approve(address spender_, uint256 id_) public virtual {
// Intention is to approve as ERC-721 token (id).
address erc721Owner = _getOwnerOf(id_);
if (
msg.sender != erc721Owner && !isApprovedForAll[erc721Owner][msg.sender]
) {
revert Unauthorized();
}
getApproved[id_] = spender_;
emit ERC721Events.Approval(erc721Owner, spender_, id_);
}
/// @dev Providing type(uint256).max for approval value results in an
/// unlimited approval that is not deducted from on transfers.
function erc20Approve(
address spender_,
uint256 value_
) public virtual returns (bool) {
// Prevent granting 0x0 an ERC-20 allowance.
if (spender_ == address(0)) {
revert InvalidSpender();
}
allowance[msg.sender][spender_] = value_;
emit ERC20Events.Approval(msg.sender, spender_, value_);
return true;
}
/// @notice Function for ERC-721 approvals
function setApprovalForAll(address operator_, bool approved_) public virtual {
// Prevent approvals to 0x0.
if (operator_ == address(0)) {
revert InvalidOperator();
}
isApprovedForAll[msg.sender][operator_] = approved_;
emit ERC721Events.ApprovalForAll(msg.sender, operator_, approved_);
}
/// @notice Function for mixed transfers from an operator that may be different than 'from'.
/// @dev This function assumes the operator is attempting to transfer an ERC-721
/// if valueOrId is a possible valid token id.
function transferFrom(
address from_,
address to_,
uint256 valueOrId_
) public virtual returns (bool) {
if (_isValidTokenId(valueOrId_)) {
erc721TransferFrom(from_, to_, valueOrId_);
} else {
// Intention is to transfer as ERC-20 token (value).
return erc20TransferFrom(from_, to_, valueOrId_);
}
return true;
}
/// @notice Function for ERC-721 transfers from.
/// @dev This function is recommended for ERC721 transfers.
function erc721TransferFrom(
address from_,
address to_,
uint256 id_
) public virtual {
// Prevent minting tokens from 0x0.
if (from_ == address(0)) {
revert InvalidSender();
}
// Prevent burning tokens to 0x0.
if (to_ == address(0)) {
revert InvalidRecipient();
}
if (from_ != _getOwnerOf(id_)) {
revert Unauthorized();
}
// Check that the operator is either the sender or approved for the transfer.
if (
msg.sender != from_ &&
!isApprovedForAll[from_][msg.sender] &&
msg.sender != getApproved[id_]
) {
revert Unauthorized();
}
// We only need to check ERC-721 transfer exempt status for the recipient
// since the sender being ERC-721 transfer exempt means they have already
// had their ERC-721s stripped away during the rebalancing process.
if (erc721TransferExempt(to_)) {
revert RecipientIsERC721TransferExempt();
}
// Transfer 1 * units ERC-20 and 1 ERC-721 token.
// ERC-721 transfer exemptions handled above. Can't make it to this point if either is transfer exempt.
_transferERC20(from_, to_, units);
_transferERC721(from_, to_, id_);
}
/// @notice Function for ERC-20 transfers from.
/// @dev This function is recommended for ERC20 transfers
function erc20TransferFrom(
address from_,
address to_,
uint256 value_
) public virtual returns (bool) {
// Prevent minting tokens from 0x0.
if (from_ == address(0)) {
revert InvalidSender();
}
// Prevent burning tokens to 0x0.
if (to_ == address(0)) {
revert InvalidRecipient();
}
uint256 allowed = allowance[from_][msg.sender];
// Check that the operator has sufficient allowance.
if (allowed != type(uint256).max) {
allowance[from_][msg.sender] = allowed - value_;
}
// Transferring ERC-20s directly requires the _transferERC20WithERC721 function.
// Handles ERC-721 exemptions internally.
return _transferERC20WithERC721(from_, to_, value_);
}
/// @notice Function for ERC-20 transfers.
/// @dev This function assumes the operator is attempting to transfer as ERC-20
/// given this function is only supported on the ERC-20 interface.
/// Treats even large amounts that are valid ERC-721 ids as ERC-20s.
function transfer(address to_, uint256 value_) public virtual returns (bool) {
// Prevent burning tokens to 0x0.
if (to_ == address(0)) {
revert InvalidRecipient();
}
// Transferring ERC-20s directly requires the _transferERC20WithERC721 function.
// Handles ERC-721 exemptions internally.
return _transferERC20WithERC721(msg.sender, to_, value_);
}
/// @notice Function for ERC-721 transfers with contract support.
/// This function only supports moving valid ERC-721 ids, as it does not exist on the ERC-20
/// spec and will revert otherwise.
function safeTransferFrom(
address from_,
address to_,
uint256 id_
) public virtual {
safeTransferFrom(from_, to_, id_, "");
}
/// @notice Function for ERC-721 transfers with contract support and callback data.
/// This function only supports moving valid ERC-721 ids, as it does not exist on the
/// ERC-20 spec and will revert otherwise.
function safeTransferFrom(
address from_,
address to_,
uint256 id_,
bytes memory data_
) public virtual {
if (!_isValidTokenId(id_)) {
revert InvalidTokenId();
}
transferFrom(from_, to_, id_);
if (
to_.code.length != 0 &&
IERC721Receiver(to_).onERC721Received(msg.sender, from_, id_, data_) !=
IERC721Receiver.onERC721Received.selector
) {
revert UnsafeRecipient();
}
}
/// @notice Function for EIP-2612 permits (ERC-20 only).
/// @dev Providing type(uint256).max for permit value results in an
/// unlimited approval that is not deducted from on transfers.
function permit(
address owner_,
address spender_,
uint256 value_,
uint256 deadline_,
uint8 v_,
bytes32 r_,
bytes32 s_
) public virtual {
if (deadline_ < block.timestamp) {
revert PermitDeadlineExpired();
}
// permit cannot be used for ERC-721 token approvals, so ensure
// the value does not fall within the valid range of ERC-721 token ids.
if (_isValidTokenId(value_)) {
revert InvalidApproval();
}
if (spender_ == address(0)) {
revert InvalidSpender();
}
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner_,
spender_,
value_,
nonces[owner_]++,
deadline_
)
)
)
),
v_,
r_,
s_
);
if (recoveredAddress == address(0) || recoveredAddress != owner_) {
revert InvalidSigner();
}
allowance[recoveredAddress][spender_] = value_;
}
emit ERC20Events.Approval(owner_, spender_, value_);
}
/// @notice Returns domain initial domain separator, or recomputes if chain id is not equal to initial chain id
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return
block.chainid == _INITIAL_CHAIN_ID
? _INITIAL_DOMAIN_SEPARATOR
: _computeDomainSeparator();
}
function supportsInterface(
bytes4 interfaceId
) public view virtual returns (bool) {
return
interfaceId == type(IERC404).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
/// @notice Function for self-exemption
function setSelfERC721TransferExempt(bool state_) public virtual {
_setERC721TransferExempt(msg.sender, state_);
}
/// @notice Function to check if address is transfer exempt
function erc721TransferExempt(
address target_
) public view virtual returns (bool) {
return target_ == address(0) || _erc721TransferExempt[target_];
}
/// @notice For a token token id to be considered valid, it just needs
/// to fall within the range of possible token ids, it does not
/// necessarily have to be minted yet.
function _isValidTokenId(uint256 id_) internal pure returns (bool) {
return id_ > ID_ENCODING_PREFIX && id_ != type(uint256).max;
}
/// @notice Internal function to compute domain separator for EIP-2612 permits
function _computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/// @notice This is the lowest level ERC-20 transfer function, which
/// should be used for both normal ERC-20 transfers as well as minting.
/// Note that this function allows transfers to and from 0x0.
function _transferERC20(
address from_,
address to_,
uint256 value_
) internal virtual {
// Minting is a special case for which we should not check the balance of
// the sender, and we should increase the total supply.
if (from_ == address(0)) {
totalSupply += value_;
} else {
// Deduct value from sender's balance.
balanceOf[from_] -= value_;
}
// Update the recipient's balance.
// Can be unchecked because on mint, adding to totalSupply is checked, and on transfer balance deduction is checked.
unchecked {
balanceOf[to_] += value_;
}
emit ERC20Events.Transfer(from_, to_, value_);
}
/// @notice Consolidated record keeping function for transferring ERC-721s.
/// @dev Assign the token to the new owner, and remove from the old owner.
/// Note that this function allows transfers to and from 0x0.
/// Does not handle ERC-721 exemptions.
function _transferERC721(
address from_,
address to_,
uint256 id_
) internal virtual {
// If this is not a mint, handle record keeping for transfer from previous owner.
if (from_ != address(0)) {
// On transfer of an NFT, any previous approval is reset.
delete getApproved[id_];
uint256 updatedId = _owned[from_][_owned[from_].length - 1];
if (updatedId != id_) {
uint256 updatedIndex = _getOwnedIndex(id_);
// update _owned for sender
_owned[from_][updatedIndex] = updatedId;
// update index for the moved id
_setOwnedIndex(updatedId, updatedIndex);
}
// pop
_owned[from_].pop();
}
// Check if this is a burn.
if (to_ != address(0)) {
// If not a burn, update the owner of the token to the new owner.
// Update owner of the token to the new owner.
_setOwnerOf(id_, to_);
// Push token onto the new owner's stack.
_owned[to_].push(id_);
// Update index for new owner's stack.
_setOwnedIndex(id_, _owned[to_].length - 1);
} else {
// If this is a burn, reset the owner of the token to 0x0 by deleting the token from _ownedData.
delete _ownedData[id_];
}
emit ERC721Events.Transfer(from_, to_, id_);
}
/// @notice Internal function for ERC-20 transfers. Also handles any ERC-721 transfers that may be required.
// Handles ERC-721 exemptions.
function _transferERC20WithERC721(
address from_,
address to_,
uint256 value_
) internal virtual returns (bool) {
uint256 erc20BalanceOfSenderBefore = erc20BalanceOf(from_);
uint256 erc20BalanceOfReceiverBefore = erc20BalanceOf(to_);
_transferERC20(from_, to_, value_);
// Preload for gas savings on branches
bool isFromERC721TransferExempt = erc721TransferExempt(from_);
bool isToERC721TransferExempt = erc721TransferExempt(to_);
// Skip _withdrawAndStoreERC721 and/or _retrieveOrMintERC721 for ERC-721 transfer exempt addresses
// 1) to save gas
// 2) because ERC-721 transfer exempt addresses won't always have/need ERC-721s corresponding to their ERC20s.
if (isFromERC721TransferExempt && isToERC721TransferExempt) {
// Case 1) Both sender and recipient are ERC-721 transfer exempt. No ERC-721s need to be transferred.
// NOOP.
} else if (isFromERC721TransferExempt) {
// Case 2) The sender is ERC-721 transfer exempt, but the recipient is not. Contract should not attempt
// to transfer ERC-721s from the sender, but the recipient should receive ERC-721s
// from the bank/minted for any whole number increase in their balance.
// Only cares about whole number increments.
uint256 tokensToRetrieveOrMint = (balanceOf[to_] / units) -
(erc20BalanceOfReceiverBefore / units);
for (uint256 i = 0; i < tokensToRetrieveOrMint; ) {
_retrieveOrMintERC721(to_);
unchecked {
++i;
}
}
} else if (isToERC721TransferExempt) {
// Case 3) The sender is not ERC-721 transfer exempt, but the recipient is. Contract should attempt
// to withdraw and store ERC-721s from the sender, but the recipient should not
// receive ERC-721s from the bank/minted.
// Only cares about whole number increments.
uint256 tokensToWithdrawAndStore = (erc20BalanceOfSenderBefore / units) -
(balanceOf[from_] / units);
for (uint256 i = 0; i < tokensToWithdrawAndStore; ) {
_withdrawAndStoreERC721(from_);
unchecked {
++i;
}
}
} else {
// Case 4) Neither the sender nor the recipient are ERC-721 transfer exempt.
// Strategy:
// 1. First deal with the whole tokens. These are easy and will just be transferred.
// 2. Look at the fractional part of the value:
// a) If it causes the sender to lose a whole token that was represented by an NFT due to a
// fractional part being transferred, withdraw and store an additional NFT from the sender.
// b) If it causes the receiver to gain a whole new token that should be represented by an NFT
// due to receiving a fractional part that completes a whole token, retrieve or mint an NFT to the recevier.
// Whole tokens worth of ERC-20s get transferred as ERC-721s without any burning/minting.
uint256 nftsToTransfer = value_ / units;
for (uint256 i = 0; i < nftsToTransfer; ) {
// Pop from sender's ERC-721 stack and transfer them (LIFO)
uint256 indexOfLastToken = _owned[from_].length - 1;
uint256 tokenId = _owned[from_][indexOfLastToken];
_transferERC721(from_, to_, tokenId);
unchecked {
++i;
}
}
// If the transfer changes either the sender or the recipient's holdings from a fractional to a non-fractional
// amount (or vice versa), adjust ERC-721s.
// First check if the send causes the sender to lose a whole token that was represented by an ERC-721
// due to a fractional part being transferred.
//
// Process:
// Take the difference between the whole number of tokens before and after the transfer for the sender.
// If that difference is greater than the number of ERC-721s transferred (whole units), then there was
// an additional ERC-721 lost due to the fractional portion of the transfer.
// If this is a self-send and the before and after balances are equal (not always the case but often),
// then no ERC-721s will be lost here.
if (
erc20BalanceOfSenderBefore / units - erc20BalanceOf(from_) / units >
nftsToTransfer
) {
_withdrawAndStoreERC721(from_);
}
// Then, check if the transfer causes the receiver to gain a whole new token which requires gaining
// an additional ERC-721.
//
// Process:
// Take the difference between the whole number of tokens before and after the transfer for the recipient.
// If that difference is greater than the number of ERC-721s transferred (whole units), then there was
// an additional ERC-721 gained due to the fractional portion of the transfer.
// Again, for self-sends where the before and after balances are equal, no ERC-721s will be gained here.
if (
erc20BalanceOf(to_) / units - erc20BalanceOfReceiverBefore / units >
nftsToTransfer
) {
_retrieveOrMintERC721(to_);
}
}
return true;
}
/// @notice Internal function for ERC20 minting
/// @dev This function will allow minting of new ERC20s.
/// If mintCorrespondingERC721s_ is true, and the recipient is not ERC-721 exempt, it will
/// also mint the corresponding ERC721s.
/// Handles ERC-721 exemptions.
function _mintERC20(address to_, uint256 value_) internal virtual {
/// You cannot mint to the zero address (you can't mint and immediately burn in the same transfer).
if (to_ == address(0)) {
revert InvalidRecipient();
}
if (totalSupply + value_ > ID_ENCODING_PREFIX) {
revert MintLimitReached();
}
_transferERC20WithERC721(address(0), to_, value_);
}
/// @notice Internal function for ERC-721 minting and retrieval from the bank.
/// @dev This function will allow minting of new ERC-721s up to the total fractional supply. It will
/// first try to pull from the bank, and if the bank is empty, it will mint a new token.
/// Does not handle ERC-721 exemptions.
function _retrieveOrMintERC721(address to_) internal virtual {
if (to_ == address(0)) {
revert InvalidRecipient();
}
uint256 id;
if (!_storedERC721Ids.empty()) {
// If there are any tokens in the bank, use those first.
// Pop off the end of the queue (FIFO).
id = _storedERC721Ids.popBack();
} else {
// Otherwise, mint a new token, should not be able to go over the total fractional supply.
++minted;
// Reserve max uint256 for approvals
if (minted == type(uint256).max) {
revert MintLimitReached();
}
id = ID_ENCODING_PREFIX + minted;
}
address erc721Owner = _getOwnerOf(id);
// The token should not already belong to anyone besides 0x0 or this contract.
// If it does, something is wrong, as this should never happen.
if (erc721Owner != address(0)) {
revert AlreadyExists();
}
// Transfer the token to the recipient, either transferring from the contract's bank or minting.
// Does not handle ERC-721 exemptions.
_transferERC721(erc721Owner, to_, id);
}
/// @notice Internal function for ERC-721 deposits to bank (this contract).
/// @dev This function will allow depositing of ERC-721s to the bank, which can be retrieved by future minters.
// Does not handle ERC-721 exemptions.
function _withdrawAndStoreERC721(address from_) internal virtual {
if (from_ == address(0)) {
revert InvalidSender();
}
// Retrieve the latest token added to the owner's stack (LIFO).
uint256 id = _owned[from_][_owned[from_].length - 1];
// Transfer to 0x0.
// Does not handle ERC-721 exemptions.
_transferERC721(from_, address(0), id);
// Record the token in the contract's bank queue.
_storedERC721Ids.pushFront(id);
}
/// @notice Initialization function to set pairs / etc, saving gas by avoiding mint / burn on unnecessary targets
function _setERC721TransferExempt(
address target_,
bool state_
) internal virtual {
if (target_ == address(0)) {
revert InvalidExemption();
}
// Adjust the ERC721 balances of the target to respect exemption rules.
// Despite this logic, it is still recommended practice to exempt prior to the target
// having an active balance.
if (state_) {
_clearERC721Balance(target_);
} else {
_reinstateERC721Balance(target_);
}
_erc721TransferExempt[target_] = state_;
}
/// @notice Function to reinstate balance on exemption removal
function _reinstateERC721Balance(address target_) private {
uint256 expectedERC721Balance = erc20BalanceOf(target_) / units;
uint256 actualERC721Balance = erc721BalanceOf(target_);
for (uint256 i = 0; i < expectedERC721Balance - actualERC721Balance; ) {
// Transfer ERC721 balance in from pool
_retrieveOrMintERC721(target_);
unchecked {
++i;
}
}
}
/// @notice Function to clear balance on exemption inclusion
function _clearERC721Balance(address target_) private {
uint256 erc721Balance = erc721BalanceOf(target_);
for (uint256 i = 0; i < erc721Balance; ) {
// Transfer out ERC721 balance
_withdrawAndStoreERC721(target_);
unchecked {
++i;
}
}
}
function _getOwnerOf(
uint256 id_
) internal view virtual returns (address ownerOf_) {
uint256 data = _ownedData[id_];
assembly {
ownerOf_ := and(data, _BITMASK_ADDRESS)
}
}
function _setOwnerOf(uint256 id_, address owner_) internal virtual {
uint256 data = _ownedData[id_];
assembly {
data := add(
and(data, _BITMASK_OWNED_INDEX),
and(owner_, _BITMASK_ADDRESS)
)
}
_ownedData[id_] = data;
}
function _getOwnedIndex(
uint256 id_
) internal view virtual returns (uint256 ownedIndex_) {
uint256 data = _ownedData[id_];
assembly {
ownedIndex_ := shr(160, data)
}
}
function _setOwnedIndex(uint256 id_, uint256 index_) internal virtual {
uint256 data = _ownedData[id_];
if (index_ > _BITMASK_OWNED_INDEX >> 160) {
revert OwnedIndexOverflow();
}
assembly {
data := add(
and(data, _BITMASK_ADDRESS),
and(shl(160, index_), _BITMASK_OWNED_INDEX)
)
}
_ownedData[id_] = data;
}
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {ERC404} from "../ERC404.sol";
import {IPeripheryImmutableState} from "@uniswap/v3-periphery/contracts/interfaces/IPeripheryImmutableState.sol";
abstract contract ERC404UniswapV3Exempt is ERC404 {
error ERC404UniswapV3ExemptFactoryMismatch();
error ERC404UniswapV3ExemptWETH9Mismatch();
constructor(
address uniswapV3Router_,
address uniswapV3NonfungiblePositionManager_
) {
IPeripheryImmutableState uniswapV3Router = IPeripheryImmutableState(
uniswapV3Router_
);
// Set the Uniswap v3 swap router as exempt.
_setERC721TransferExempt(uniswapV3Router_, true);
IPeripheryImmutableState uniswapV3NonfungiblePositionManager = IPeripheryImmutableState(
uniswapV3NonfungiblePositionManager_
);
// Set the Uniswap v3 nonfungible position manager as exempt.
_setERC721TransferExempt(uniswapV3NonfungiblePositionManager_, true);
// Require the Uniswap v3 factory from the position manager and the swap router to be the same.
if (
uniswapV3Router.factory() != uniswapV3NonfungiblePositionManager.factory()
) {
revert ERC404UniswapV3ExemptFactoryMismatch();
}
// Require the Uniswap v3 WETH9 from the position manager and the swap router to be the same.
if (
uniswapV3Router.WETH9() != uniswapV3NonfungiblePositionManager.WETH9()
) {
revert ERC404UniswapV3ExemptWETH9Mismatch();
}
uint24[4] memory feeTiers = [
uint24(100),
uint24(500),
uint24(3_000),
uint24(10_000)
];
// Determine the Uniswap v3 pair address for this token.
for (uint256 i = 0; i < feeTiers.length; ) {
address uniswapV3Pair = _getUniswapV3Pair(
uniswapV3Router.factory(),
uniswapV3Router.WETH9(),
feeTiers[i]
);
// Set the Uniswap v3 pair as exempt.
_setERC721TransferExempt(uniswapV3Pair, true);
unchecked {
++i;
}
}
}
function _getUniswapV3Pair(
address uniswapV3Factory_,
address weth_,
uint24 fee_
) private view returns (address) {
address thisAddress = address(this);
(address token0, address token1) = thisAddress < weth_
? (thisAddress, weth_)
: (weth_, thisAddress);
return
address(
uint160(
uint256(
keccak256(
abi.encodePacked(
hex"ff",
uniswapV3Factory_,
keccak256(abi.encode(token0, token1, fee_)),
hex"e34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54"
)
)
)
)
);
}
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
interface IERC404 is IERC165 {
error NotFound();
error InvalidTokenId();
error AlreadyExists();
error InvalidRecipient();
error InvalidSender();
error InvalidSpender();
error InvalidOperator();
error UnsafeRecipient();
error RecipientIsERC721TransferExempt();
error Unauthorized();
error InsufficientAllowance();
error DecimalsTooLow();
error PermitDeadlineExpired();
error InvalidSigner();
error InvalidApproval();
error OwnedIndexOverflow();
error MintLimitReached();
error InvalidExemption();
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function erc20TotalSupply() external view returns (uint256);
function erc721TotalSupply() external view returns (uint256);
function balanceOf(address owner_) external view returns (uint256);
function erc721BalanceOf(address owner_) external view returns (uint256);
function erc20BalanceOf(address owner_) external view returns (uint256);
function erc721TransferExempt(address account_) external view returns (bool);
function isApprovedForAll(
address owner_,
address operator_
) external view returns (bool);
function allowance(
address owner_,
address spender_
) external view returns (uint256);
function owned(address owner_) external view returns (uint256[] memory);
function ownerOf(uint256 id_) external view returns (address erc721Owner);
function tokenURI(uint256 id_) external view returns (string memory);
function approve(
address spender_,
uint256 valueOrId_
) external returns (bool);
function erc20Approve(
address spender_,
uint256 value_
) external returns (bool);
function erc721Approve(address spender_, uint256 id_) external;
function setApprovalForAll(address operator_, bool approved_) external;
function transferFrom(
address from_,
address to_,
uint256 valueOrId_
) external returns (bool);
function erc20TransferFrom(
address from_,
address to_,
uint256 value_
) external returns (bool);
function erc721TransferFrom(address from_, address to_, uint256 id_) external;
function transfer(address to_, uint256 amount_) external returns (bool);
function getERC721QueueLength() external view returns (uint256);
function getERC721TokensInQueue(
uint256 start_,
uint256 count_
) external view returns (uint256[] memory);
function setSelfERC721TransferExempt(bool state_) external;
function safeTransferFrom(address from_, address to_, uint256 id_) external;
function safeTransferFrom(
address from_,
address to_,
uint256 id_,
bytes calldata data_
) external;
function DOMAIN_SEPARATOR() external view returns (bytes32);
function permit(
address owner_,
address spender_,
uint256 value_,
uint256 deadline_,
uint8 v_,
bytes32 r_,
bytes32 s_
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/DoubleEndedQueue.sol)
// Modified by Pandora Labs to support native uint256 operations
pragma solidity ^0.8.20;
/**
* @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of
* the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and
* FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that
* the existing queue contents are left in storage.
*
* The struct is called `Uint256Deque`. This data structure can only be used in storage, and not in memory.
*
* ```solidity
* DoubleEndedQueue.Uint256Deque queue;
* ```
*/
library DoubleEndedQueue {
/**
* @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty.
*/
error QueueEmpty();
/**
* @dev A push operation couldn't be completed due to the queue being full.
*/
error QueueFull();
/**
* @dev An operation (e.g. {at}) couldn't be completed due to an index being out of bounds.
*/
error QueueOutOfBounds();
/**
* @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access.
*
* Struct members have an underscore prefix indicating that they are "private" and should not be read or written to
* directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and
* lead to unexpected behavior.
*
* The first item is at data[begin] and the last item is at data[end - 1]. This range can wrap around.
*/
struct Uint256Deque {
uint128 _begin;
uint128 _end;
mapping(uint128 index => uint256) _data;
}
/**
* @dev Inserts an item at the end of the queue.
*
* Reverts with {QueueFull} if the queue is full.
*/
function pushBack(Uint256Deque storage deque, uint256 value) internal {
unchecked {
uint128 backIndex = deque._end;
if (backIndex + 1 == deque._begin) revert QueueFull();
deque._data[backIndex] = value;
deque._end = backIndex + 1;
}
}
/**
* @dev Removes the item at the end of the queue and returns it.
*
* Reverts with {QueueEmpty} if the queue is empty.
*/
function popBack(
Uint256Deque storage deque
) internal returns (uint256 value) {
unchecked {
uint128 backIndex = deque._end;
if (backIndex == deque._begin) revert QueueEmpty();
--backIndex;
value = deque._data[backIndex];
delete deque._data[backIndex];
deque._end = backIndex;
}
}
/**
* @dev Inserts an item at the beginning of the queue.
*
* Reverts with {QueueFull} if the queue is full.
*/
function pushFront(Uint256Deque storage deque, uint256 value) internal {
unchecked {
uint128 frontIndex = deque._begin - 1;
if (frontIndex == deque._end) revert QueueFull();
deque._data[frontIndex] = value;
deque._begin = frontIndex;
}
}
/**
* @dev Removes the item at the beginning of the queue and returns it.
*
* Reverts with `QueueEmpty` if the queue is empty.
*/
function popFront(
Uint256Deque storage deque
) internal returns (uint256 value) {
unchecked {
uint128 frontIndex = deque._begin;
if (frontIndex == deque._end) revert QueueEmpty();
value = deque._data[frontIndex];
delete deque._data[frontIndex];
deque._begin = frontIndex + 1;
}
}
/**
* @dev Returns the item at the beginning of the queue.
*
* Reverts with `QueueEmpty` if the queue is empty.
*/
function front(
Uint256Deque storage deque
) internal view returns (uint256 value) {
if (empty(deque)) revert QueueEmpty();
return deque._data[deque._begin];
}
/**
* @dev Returns the item at the end of the queue.
*
* Reverts with `QueueEmpty` if the queue is empty.
*/
function back(
Uint256Deque storage deque
) internal view returns (uint256 value) {
if (empty(deque)) revert QueueEmpty();
unchecked {
return deque._data[deque._end - 1];
}
}
/**
* @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at
* `length(deque) - 1`.
*
* Reverts with `QueueOutOfBounds` if the index is out of bounds.
*/
function at(
Uint256Deque storage deque,
uint256 index
) internal view returns (uint256 value) {
if (index >= length(deque)) revert QueueOutOfBounds();
// By construction, length is a uint128, so the check above ensures that index can be safely downcast to uint128
unchecked {
return deque._data[deque._begin + uint128(index)];
}
}
/**
* @dev Resets the queue back to being empty.
*
* NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses
* out on potential gas refunds.
*/
function clear(Uint256Deque storage deque) internal {
deque._begin = 0;
deque._end = 0;
}
/**
* @dev Returns the number of items in the queue.
*/
function length(Uint256Deque storage deque) internal view returns (uint256) {
unchecked {
return uint256(deque._end - deque._begin);
}
}
/**
* @dev Returns true if the queue is empty.
*/
function empty(Uint256Deque storage deque) internal view returns (bool) {
return deque._end == deque._begin;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
library ERC20Events {
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 amount);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
library ERC721Events {
event ApprovalForAll(
address indexed owner,
address indexed operator,
bool approved
);
event Approval(
address indexed owner,
address indexed spender,
uint256 indexed id
);
event Transfer(address indexed from, address indexed to, uint256 indexed id);
}{
"evmVersion": "paris",
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"string","name":"baseURI_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"},{"internalType":"uint256","name":"maxTotalSupplyERC721_","type":"uint256"},{"internalType":"address","name":"initialOwner_","type":"address"},{"internalType":"address","name":"initialMintRecipient_","type":"address"},{"internalType":"address","name":"uniswapSwapRouter_","type":"address"},{"internalType":"address","name":"uniswapV3NonfungiblePositionManager_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyExists","type":"error"},{"inputs":[],"name":"DecimalsTooLow","type":"error"},{"inputs":[],"name":"ERC404UniswapV3ExemptFactoryMismatch","type":"error"},{"inputs":[],"name":"ERC404UniswapV3ExemptWETH9Mismatch","type":"error"},{"inputs":[],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InvalidApproval","type":"error"},{"inputs":[],"name":"InvalidExemption","type":"error"},{"inputs":[],"name":"InvalidOperator","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidSpender","type":"error"},{"inputs":[],"name":"InvalidTokenId","type":"error"},{"inputs":[],"name":"MintLimitReached","type":"error"},{"inputs":[],"name":"NotFound","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"OwnedIndexOverflow","type":"error"},{"inputs":[],"name":"PermitDeadlineExpired","type":"error"},{"inputs":[],"name":"QueueEmpty","type":"error"},{"inputs":[],"name":"QueueFull","type":"error"},{"inputs":[],"name":"QueueOutOfBounds","type":"error"},{"inputs":[],"name":"RecipientIsERC721TransferExempt","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnsafeRecipient","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ID_ENCODING_PREFIX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"valueOrId_","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"erc20Approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"erc20BalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc20TotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"erc20TransferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"erc721Approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"erc721BalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc721TotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target_","type":"address"}],"name":"erc721TransferExempt","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"erc721TransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getERC721QueueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start_","type":"uint256"},{"internalType":"uint256","name":"count_","type":"uint256"}],"name":"getERC721TokensInQueue","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"owned","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"erc721Owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"uint8","name":"v_","type":"uint8"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator_","type":"address"},{"internalType":"bool","name":"approved_","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI_","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"},{"internalType":"bool","name":"value_","type":"bool"}],"name":"setERC721TransferExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state_","type":"bool"}],"name":"setSelfERC721TransferExempt","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":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"valueOrId_","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"units","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6101006040523480156200001257600080fd5b50604051620074c8380380620074c8833981810160405281019062000038919062001e95565b81818a8a8988600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620000b35760006040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401620000aa919062001fe2565b60405180910390fd5b620000c4816200061f60201b60201c565b508260039081620000d6919062002240565b508160049081620000e8919062002240565b5060128160ff16101562000128576040517f98790fd500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060ff1660808160ff1681525050608051600a620001479190620024aa565b60a081815250504660c0818152505062000166620006e360201b60201c565b60e081815250505050506000829050620001888360016200077360201b60201c565b6000829050620001a08360016200077360201b60201c565b8073ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002129190620024fb565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000274573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029a9190620024fb565b73ffffffffffffffffffffffffffffffffffffffff1614620002e8576040517f3338041700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16634aa4a4fc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000334573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035a9190620024fb565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16634aa4a4fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620003bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003e29190620024fb565b73ffffffffffffffffffffffffffffffffffffffff161462000430576040517f76a731bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518060800160405280606462ffffff1662ffffff1681526020016101f462ffffff1662ffffff168152602001610bb862ffffff1662ffffff16815260200161271062ffffff1662ffffff16815250905060005b6004811015620005c4576000620005a28573ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015620004e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005099190620024fb565b8673ffffffffffffffffffffffffffffffffffffffff16634aa4a4fc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000555573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200057b9190620024fb565b8585600481106200059157620005906200252d565b5b60200201516200086560201b60201c565b9050620005b78160016200077360201b60201c565b8160010191505062000487565b50505050505086600f9081620005db919062002240565b50620005ef8360016200077360201b60201c565b620006108360a051876200060491906200255c565b6200091760201b60201c565b50505050505050505062002a35565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600360405162000717919062002656565b60405180910390207fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc64630604051602001620007589594939291906200269b565b60405160208183030381529060405280519060200120905090565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603620007da576040517fa41e3d3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8015620007f857620007f28262000a0160201b60201c565b6200080a565b620008098262000a4460201b60201c565b5b80600d60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b6000803090506000808573ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1610620008aa578583620008ad565b82865b9150915086828287604051602001620008c99392919062002718565b60405160208183030381529060405280519060200120604051602001620008f292919062002875565b6040516020818303038152906040528051906020012060001c93505050509392505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036200097e576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f800000000000000000000000000000000000000000000000000000000000000081600554620009af9190620028bf565b1115620009e8576040517f303b682f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620009fc6000838362000ab960201b60201c565b505050565b600062000a148262000e3860201b60201c565b905060005b8181101562000a3f5762000a338362000e8460201b60201c565b80600101905062000a19565b505050565b600060a05162000a5a8362000fcc60201b60201c565b62000a66919062002929565b9050600062000a7b8362000e3860201b60201c565b905060005b818362000a8e919062002961565b81101562000ab35762000aa7846200101560201b60201c565b80600101905062000a80565b50505050565b60008062000acd8562000fcc60201b60201c565b9050600062000ae28562000fcc60201b60201c565b905062000af7868686620011ea60201b60201c565b600062000b0a876200135260201b60201c565b9050600062000b1f876200135260201b60201c565b905081801562000b2c5750805b62000e2957811562000bd857600060a0518462000b4a919062002929565b60a051600760008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205462000b99919062002929565b62000ba5919062002961565b905060005b8181101562000bd05762000bc4896200101560201b60201c565b80600101905062000baa565b505062000e28565b801562000c7f57600060a051600760008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205462000c30919062002929565b60a0518662000c40919062002929565b62000c4c919062002961565b905060005b8181101562000c775762000c6b8a62000e8460201b60201c565b80600101905062000c51565b505062000e27565b600060a0518762000c91919062002929565b905060005b8181101562000d785760006001600c60008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905062000cf2919062002961565b90506000600c60008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020828154811062000d4a5762000d496200252d565b5b9060005260206000200154905062000d6a8c8c83620013df60201b60201c565b826001019250505062000c96565b508060a05162000d8e8b62000fcc60201b60201c565b62000d9a919062002929565b60a0518762000daa919062002929565b62000db6919062002961565b111562000dcf5762000dce8962000e8460201b60201c565b5b8060a0518562000de0919062002929565b60a05162000df48b62000fcc60201b60201c565b62000e00919062002929565b62000e0c919062002961565b111562000e255762000e24886200101560201b60201c565b5b505b5b5b60019450505050509392505050565b6000600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050919050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160362000eeb576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001600c60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905062000f7d919062002961565b8154811062000f915762000f906200252d565b5b9060005260206000200154905062000fb282600083620013df60201b60201c565b62000fc88160016200178860201b90919060201c565b5050565b6000600760008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036200107c576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000620010906001620018ac60201b60201c565b620010af57620010a760016200191c60201b60201c565b905062001156565b600660008154620010c0906200299c565b919050819055507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6006540362001123576040517f303b682f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006547f8000000000000000000000000000000000000000000000000000000000000000620011539190620028bf565b90505b6000620011698262001a8160201b60201c565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614620011d2576040517f23369fa600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620011e5818484620013df60201b60201c565b505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160362001240578060056000828254620012339190620028bf565b9250508190555062001299565b80600760008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825462001291919062002961565b925050819055505b80600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051620013459190620029e9565b60405180910390a3505050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480620013d85750600d60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff165b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614620015fb576009600082815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000600c60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001600c60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050620014dc919062002961565b81548110620014f057620014ef6200252d565b5b9060005260206000200154905081811462001591576000620015188362001ab960201b60201c565b905081600c60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002082815481106200156f576200156e6200252d565b5b90600052602060002001819055506200158f828262001ade60201b60201c565b505b600c60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805480620015e357620015e262002a06565b5b60019003818190600052602060002001600090559055505b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614620017105762001642818362001bb260201b60201c565b600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190806001815401808255809150506001900390600052602060002001600090919091909150556200170a816001600c60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050620016fe919062002961565b62001ade60201b60201c565b62001728565b600b6000828152602001908152602001600020600090555b808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b600060018360000160009054906101000a90046fffffffffffffffffffffffffffffffff160390508260000160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff16036200182e576040517f8acb5f2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81836001016000836fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16815260200190815260200160002081905550808360000160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550505050565b60008160000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168260000160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16149050919050565b6000808260000160109054906101000a90046fffffffffffffffffffffffffffffffff1690508260000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff1603620019c0576040517f75e52f4f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600190039050826001016000826fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168152602001908152602001600020549150826001016000826fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16815260200190815260200160002060009055808360000160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555050919050565b600080600b600084815260200190815260200160002054905073ffffffffffffffffffffffffffffffffffffffff8116915050919050565b600080600b60008481526020019081526020016000205490508060a01c915050919050565b6000600b600084815260200190815260200160002054905060a07fffffffffffffffffffffffff0000000000000000000000000000000000000000901c82111562001b55576040517ffcb3438c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff00000000000000000000000000000000000000008260a01b1673ffffffffffffffffffffffffffffffffffffffff821601905080600b600085815260200190815260200160002081905550505050565b6000600b600084815260200190815260200160002054905073ffffffffffffffffffffffffffffffffffffffff82167fffffffffffffffffffffffff0000000000000000000000000000000000000000821601905080600b600085815260200190815260200160002081905550505050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b62001c8d8262001c42565b810181811067ffffffffffffffff8211171562001caf5762001cae62001c53565b5b80604052505050565b600062001cc462001c24565b905062001cd2828262001c82565b919050565b600067ffffffffffffffff82111562001cf55762001cf462001c53565b5b62001d008262001c42565b9050602081019050919050565b60005b8381101562001d2d57808201518184015260208101905062001d10565b60008484015250505050565b600062001d5062001d4a8462001cd7565b62001cb8565b90508281526020810184848401111562001d6f5762001d6e62001c3d565b5b62001d7c84828562001d0d565b509392505050565b600082601f83011262001d9c5762001d9b62001c38565b5b815162001dae84826020860162001d39565b91505092915050565b600060ff82169050919050565b62001dcf8162001db7565b811462001ddb57600080fd5b50565b60008151905062001def8162001dc4565b92915050565b6000819050919050565b62001e0a8162001df5565b811462001e1657600080fd5b50565b60008151905062001e2a8162001dff565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600062001e5d8262001e30565b9050919050565b62001e6f8162001e50565b811462001e7b57600080fd5b50565b60008151905062001e8f8162001e64565b92915050565b60008060008060008060008060006101208a8c03121562001ebb5762001eba62001c2e565b5b60008a015167ffffffffffffffff81111562001edc5762001edb62001c33565b5b62001eea8c828d0162001d84565b99505060208a015167ffffffffffffffff81111562001f0e5762001f0d62001c33565b5b62001f1c8c828d0162001d84565b98505060408a015167ffffffffffffffff81111562001f405762001f3f62001c33565b5b62001f4e8c828d0162001d84565b975050606062001f618c828d0162001dde565b965050608062001f748c828d0162001e19565b95505060a062001f878c828d0162001e7e565b94505060c062001f9a8c828d0162001e7e565b93505060e062001fad8c828d0162001e7e565b92505061010062001fc18c828d0162001e7e565b9150509295985092959850929598565b62001fdc8162001e50565b82525050565b600060208201905062001ff9600083018462001fd1565b92915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200205257607f821691505b6020821081036200206857620020676200200a565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620020d27fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262002093565b620020de868362002093565b95508019841693508086168417925050509392505050565b6000819050919050565b6000620021216200211b620021158462001df5565b620020f6565b62001df5565b9050919050565b6000819050919050565b6200213d8362002100565b620021556200214c8262002128565b848454620020a0565b825550505050565b600090565b6200216c6200215d565b6200217981848462002132565b505050565b5b81811015620021a1576200219560008262002162565b6001810190506200217f565b5050565b601f821115620021f057620021ba816200206e565b620021c58462002083565b81016020851015620021d5578190505b620021ed620021e48562002083565b8301826200217e565b50505b505050565b600082821c905092915050565b60006200221560001984600802620021f5565b1980831691505092915050565b600062002230838362002202565b9150826002028217905092915050565b6200224b8262001fff565b67ffffffffffffffff81111562002267576200226662001c53565b5b62002273825462002039565b62002280828285620021a5565b600060209050601f831160018114620022b85760008415620022a3578287015190505b620022af858262002222565b8655506200231f565b601f198416620022c8866200206e565b60005b82811015620022f257848901518255600182019150602085019450602081019050620022cb565b868310156200231257848901516200230e601f89168262002202565b8355505b6001600288020188555050505b505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008160011c9050919050565b6000808291508390505b6001851115620023b5578086048111156200238d576200238c62002327565b5b60018516156200239d5780820291505b8081029050620023ad8562002356565b94506200236d565b94509492505050565b600082620023d05760019050620024a3565b81620023e05760009050620024a3565b8160018114620023f9576002811462002404576200243a565b6001915050620024a3565b60ff84111562002419576200241862002327565b5b8360020a91508482111562002433576200243262002327565b5b50620024a3565b5060208310610133831016604e8410600b8410161715620024745782820a9050838111156200246e576200246d62002327565b5b620024a3565b62002483848484600162002363565b925090508184048111156200249d576200249c62002327565b5b81810290505b9392505050565b6000620024b78262001df5565b9150620024c48362001db7565b9250620024f37fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484620023be565b905092915050565b60006020828403121562002514576200251362001c2e565b5b6000620025248482850162001e7e565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000620025698262001df5565b9150620025768362001df5565b9250828202620025868162001df5565b91508282048414831517620025a0576200259f62002327565b5b5092915050565b600081905092915050565b60008190508160005260206000209050919050565b60008154620025d68162002039565b620025e28186620025a7565b9450600182166000811462002600576001811462002616576200264d565b60ff19831686528115158202860193506200264d565b6200262185620025b2565b60005b83811015620026455781548189015260018201915060208101905062002624565b838801955050505b50505092915050565b6000620026648284620025c7565b915081905092915050565b6000819050919050565b62002684816200266f565b82525050565b620026958162001df5565b82525050565b600060a082019050620026b2600083018862002679565b620026c1602083018762002679565b620026d0604083018662002679565b620026df60608301856200268a565b620026ee608083018462001fd1565b9695505050505050565b600062ffffff82169050919050565b6200271281620026f8565b82525050565b60006060820190506200272f600083018662001fd1565b6200273e602083018562001fd1565b6200274d604083018462002707565b949350505050565b600081905092915050565b7fff00000000000000000000000000000000000000000000000000000000000000600082015250565b60006200279860018362002755565b9150620027a58262002760565b600182019050919050565b60008160601b9050919050565b6000620027ca82620027b0565b9050919050565b6000620027de82620027bd565b9050919050565b620027fa620027f48262001e50565b620027d1565b82525050565b6000819050919050565b6200281f62002819826200266f565b62002800565b82525050565b7fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54600082015250565b60006200285d60208362002755565b91506200286a8262002825565b602082019050919050565b6000620028828262002789565b9150620028908285620027e5565b601482019150620028a282846200280a565b602082019150620028b3826200284e565b91508190509392505050565b6000620028cc8262001df5565b9150620028d98362001df5565b9250828201905080821115620028f457620028f362002327565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000620029368262001df5565b9150620029438362001df5565b925082620029565762002955620028fa565b5b828204905092915050565b60006200296e8262001df5565b91506200297b8362001df5565b925082820390508181111562002996576200299562002327565b5b92915050565b6000620029a98262001df5565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203620029de57620029dd62002327565b5b600182019050919050565b600060208201905062002a0060008301846200268a565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60805160a05160c05160e051614a0c62002abc6000396000610bbf01526000610b8b015260008181610ff901528181611d53015281816124ad015281816124d90152818161257e015281816125e9015281816126490152818161274f01528181612783015281816127ca015281816127f60152612edf01526000610b650152614a0c6000f3fe608060405234801561001057600080fd5b506004361061025e5760003560e01c806389fb4c6611610146578063c5ab3ba6116100c3578063dd62ed3e11610087578063dd62ed3e14610787578063dd637699146107b7578063dfabc033146107d3578063e985e9c5146107ef578063f2fde38b1461081f578063f780bc1a1461083b5761025e565b8063c5ab3ba6146106d1578063c6e672b9146106ef578063c87b56dd1461070b578063d505accf1461073b578063d96ca0b9146107575761025e565b8063a22cb4651161010a578063a22cb46514610609578063a9059cbb14610625578063b1ab931714610655578063b3f9ea3414610685578063b88d4fde146106b55761025e565b806389fb4c66146105755780638a696e50146105935780638da5cb5b146105af57806395d89b41146105cd578063976a8435146105eb5761025e565b80633644e515116101df5780636352211e116101a35780636352211e1461049f5780636c0360eb146104cf5780636e8f624b146104ed57806370a082311461050b578063715018a61461053b5780637ecebe00146105455761025e565b80633644e515146103fb57806342842e0e146104195780634d966072146104355780634f02c4201461046557806355f804b3146104835761025e565b806309674eb01161022657806309674eb01461034157806309f0ef651461035f57806318160ddd1461038f57806323b872dd146103ad578063313ce567146103dd5761025e565b806301ffc9a71461026357806302519da31461029357806306fdde03146102c3578063081812fc146102e1578063095ea7b314610311575b600080fd5b61027d60048036038101906102789190613854565b61086b565b60405161028a919061389c565b60405180910390f35b6102ad60048036038101906102a89190613915565b61093d565b6040516102ba919061395b565b60405180910390f35b6102cb610986565b6040516102d89190613a06565b60405180910390f35b6102fb60048036038101906102f69190613a54565b610a14565b6040516103089190613a90565b60405180910390f35b61032b60048036038101906103269190613aab565b610a47565b604051610338919061389c565b60405180910390f35b610349610a82565b604051610356919061395b565b60405180910390f35b61037960048036038101906103749190613915565b610a93565b604051610386919061389c565b60405180910390f35b610397610b1f565b6040516103a4919061395b565b60405180910390f35b6103c760048036038101906103c29190613aeb565b610b25565b6040516103d4919061389c565b60405180910390f35b6103e5610b63565b6040516103f29190613b5a565b60405180910390f35b610403610b87565b6040516104109190613b8e565b60405180910390f35b610433600480360381019061042e9190613aeb565b610be4565b005b61044f600480360381019061044a9190613aab565b610c04565b60405161045c919061389c565b60405180910390f35b61046d610d5b565b60405161047a919061395b565b60405180910390f35b61049d60048036038101906104989190613cde565b610d61565b005b6104b960048036038101906104b49190613a54565b610d7c565b6040516104c69190613a90565b60405180910390f35b6104d7610e33565b6040516104e49190613a06565b60405180910390f35b6104f5610ec1565b604051610502919061395b565b60405180910390f35b61052560048036038101906105209190613915565b610ee5565b604051610532919061395b565b60405180910390f35b610543610efd565b005b61055f600480360381019061055a9190613915565b610f11565b60405161056c919061395b565b60405180910390f35b61057d610f29565b60405161058a919061395b565b60405180910390f35b6105ad60048036038101906105a89190613d53565b610f33565b005b6105b7610f40565b6040516105c49190613a90565b60405180910390f35b6105d5610f69565b6040516105e29190613a06565b60405180910390f35b6105f3610ff7565b604051610600919061395b565b60405180910390f35b610623600480360381019061061e9190613d80565b61101b565b005b61063f600480360381019061063a9190613aab565b61117e565b60405161064c919061389c565b60405180910390f35b61066f600480360381019061066a9190613915565b6111f8565b60405161067c9190613e7e565b60405180910390f35b61069f600480360381019061069a9190613915565b61128f565b6040516106ac919061395b565b60405180910390f35b6106cf60048036038101906106ca9190613f41565b6112db565b005b6106d9611451565b6040516106e6919061395b565b60405180910390f35b61070960048036038101906107049190613d80565b61145b565b005b61072560048036038101906107209190613a54565b611471565b6040516107329190613a06565b60405180910390f35b6107556004803603810190610750919061401c565b6114a5565b005b610771600480360381019061076c9190613aeb565b611832565b60405161077e919061389c565b60405180910390f35b6107a1600480360381019061079c91906140be565b611a49565b6040516107ae919061395b565b60405180910390f35b6107d160048036038101906107cc9190613aeb565b611a6e565b005b6107ed60048036038101906107e89190613aab565b611d87565b005b610809600480360381019061080491906140be565b611f40565b604051610816919061389c565b60405180910390f35b61083960048036038101906108349190613915565b611f6f565b005b610855600480360381019061085091906140fe565b611ff5565b6040516108629190613e7e565b60405180910390f35b60007fcaf91ff5000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061093657507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b6000600760008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600380546109939061416d565b80601f01602080910402602001604051908101604052809291908181526020018280546109bf9061416d565b8015610a0c5780601f106109e157610100808354040283529160200191610a0c565b820191906000526020600020905b8154815290600101906020018083116109ef57829003601f168201915b505050505081565b60096020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000610a52826120b1565b15610a6657610a618383611d87565b610a77565b610a708383610c04565b9050610a7c565b600190505b92915050565b6000610a8e6001612109565b905090565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480610b185750600d60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff165b9050919050565b60055481565b6000610b30826120b1565b15610b4557610b40848484611a6e565b610b57565b610b50848484611832565b9050610b5c565b600190505b9392505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60007f00000000000000000000000000000000000000000000000000000000000000004614610bbd57610bb8612167565b610bdf565b7f00000000000000000000000000000000000000000000000000000000000000005b905090565b610bff838383604051806020016040528060008152506112db565b505050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610c6b576040517f5461585f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610d49919061395b565b60405180910390a36001905092915050565b60065481565b610d696121f3565b80600f9081610d78919061434a565b5050565b6000610d878261227a565b9050610d92826120b1565b610dc8576040517f3f6cc76800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610e2e576040517fc5723b5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b600f8054610e409061416d565b80601f0160208091040260200160405190810160405280929190818152602001828054610e6c9061416d565b8015610eb95780601f10610e8e57610100808354040283529160200191610eb9565b820191906000526020600020905b815481529060010190602001808311610e9c57829003601f168201915b505050505081565b7f800000000000000000000000000000000000000000000000000000000000000081565b60076020528060005260406000206000915090505481565b610f056121f3565b610f0f60006122b2565b565b600e6020528060005260406000206000915090505481565b6000600554905090565b610f3d3382612376565b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60048054610f769061416d565b80601f0160208091040260200160405190810160405280929190818152602001828054610fa29061416d565b8015610fef5780601f10610fc457610100808354040283529160200191610fef565b820191906000526020600020905b815481529060010190602001808311610fd257829003601f168201915b505050505081565b7f000000000000000000000000000000000000000000000000000000000000000081565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611081576040517fccea9e6f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600a60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051611172919061389c565b60405180910390a35050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036111e5576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111f0338484612455565b905092915050565b6060600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080548060200260200160405190810160405280929190818152602001828054801561128357602002820191906000526020600020905b81548152602001906001019080831161126f575b50505050509050919050565b6000600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050919050565b6112e4826120b1565b61131a576040517f3f6cc76800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611325848484610b25565b5060008373ffffffffffffffffffffffffffffffffffffffff163b14158015611414575063150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168373ffffffffffffffffffffffffffffffffffffffff1663150b7a02338786866040518563ffffffff1660e01b81526004016113af9493929190614471565b6020604051808303816000875af11580156113ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f291906144d2565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614155b1561144b576040517f3da6393100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b6000600654905090565b6114636121f3565b61146d8282612376565b5050565b6060600f61147e83612855565b60405160200161148f9291906145be565b6040516020818303038152906040529050919050565b428410156114df576040517f05787bdf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e8856120b1565b1561151f576040517f1f3e0de800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1603611585576040517f5461585f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006001611591610b87565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98a8a8a600e60008f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190600101919050558b604051602001611619969594939291906145e2565b604051602081830303815290604052805190602001206040516020016116409291906146b0565b604051602081830303815290604052805190602001208585856040516000815260200160405260405161167694939291906146e7565b6020604051602081039080840390855afa158015611698573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16148061170b57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b15611742576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85600860008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92587604051611821919061395b565b60405180910390a350505050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603611899576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036118ff576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600860008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611a345782816119b3919061475b565b600860008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b611a3f858585612455565b9150509392505050565b6008602052816000526040600020602052806000526040600020600091509150505481565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611ad4576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611b3a576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b438161227a565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614611ba7576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015611c6a5750600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b8015611cd557506009600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611d0c576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d1582610a93565b15611d4c576040517f5ce7539700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d7783837f0000000000000000000000000000000000000000000000000000000000000000612923565b611d82838383612a83565b505050565b6000611d928261227a565b90508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015611e575750600a60008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b15611e8e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826009600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b600a6020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b611f776121f3565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611fe95760006040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401611fe09190613a90565b60405180910390fd5b611ff2816122b2565b50565b606060008267ffffffffffffffff81111561201357612012613bb3565b5b6040519080825280602002602001820160405280156120415781602001602082028036833780820191505090505b50905060008490505b8385612056919061478f565b8110156120a657612071816001612dfb90919063ffffffff16565b82868361207e919061475b565b8151811061208f5761208e6147c3565b5b60200260200101818152505080600101905061204a565b508091505092915050565b60007f80000000000000000000000000000000000000000000000000000000000000008211801561210257507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214155b9050919050565b60008160000160009054906101000a90046fffffffffffffffffffffffffffffffff168260000160109054906101000a90046fffffffffffffffffffffffffffffffff16036fffffffffffffffffffffffffffffffff169050919050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60036040516121999190614895565b60405180910390207fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc646306040516020016121d89594939291906148ac565b60405160208183030381529060405280519060200120905090565b6121fb612ea2565b73ffffffffffffffffffffffffffffffffffffffff16612219610f40565b73ffffffffffffffffffffffffffffffffffffffff16146122785761223c612ea2565b6040517f118cdaa700000000000000000000000000000000000000000000000000000000815260040161226f9190613a90565b60405180910390fd5b565b600080600b600084815260200190815260200160002054905073ffffffffffffffffffffffffffffffffffffffff8116915050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036123dc576040517fa41e3d3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80156123f0576123eb82612eaa565b6123fa565b6123f982612edb565b5b80600d60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b6000806124618561093d565b9050600061246e8561093d565b905061247b868686612923565b600061248687610a93565b9050600061249387610a93565b905081801561249f5750805b6128465781156125745760007f0000000000000000000000000000000000000000000000000000000000000000846124d7919061492e565b7f0000000000000000000000000000000000000000000000000000000000000000600760008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612542919061492e565b61254c919061475b565b905060005b8181101561256d5761256289612f50565b806001019050612551565b5050612845565b80156126455760007f0000000000000000000000000000000000000000000000000000000000000000600760008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546125e7919061492e565b7f000000000000000000000000000000000000000000000000000000000000000086612613919061492e565b61261d919061475b565b905060005b8181101561263e576126338a6130fc565b806001019050612622565b5050612844565b60007f000000000000000000000000000000000000000000000000000000000000000087612673919061492e565b905060005b8181101561274b5760006001600c60008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506126d1919061475b565b90506000600c60008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208281548110612726576127256147c3565b5b9060005260206000200154905061273e8c8c83612a83565b8260010192505050612678565b50807f00000000000000000000000000000000000000000000000000000000000000006127778b61093d565b612781919061492e565b7f0000000000000000000000000000000000000000000000000000000000000000876127ad919061492e565b6127b7919061475b565b11156127c7576127c6896130fc565b5b807f0000000000000000000000000000000000000000000000000000000000000000856127f4919061492e565b7f000000000000000000000000000000000000000000000000000000000000000061281e8b61093d565b612828919061492e565b612832919061475b565b11156128425761284188612f50565b5b505b5b5b60019450505050509392505050565b60606000600161286484613234565b01905060008167ffffffffffffffff81111561288357612882613bb3565b5b6040519080825280601f01601f1916602001820160405280156128b55781602001600182028036833780820191505090505b509050600082602001820190505b600115612918578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a858161290c5761290b6148ff565b5b049450600085036128c3575b819350505050919050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612975578060056000828254612969919061478f565b925050819055506129cc565b80600760008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546129c4919061475b565b925050819055505b80600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051612a76919061395b565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614612c82576009600082815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000600c60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001600c60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050612b7d919061475b565b81548110612b8e57612b8d6147c3565b5b90600052602060002001549050818114612c1b576000612bad83613387565b905081600c60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208281548110612c0157612c006147c3565b5b9060005260206000200181905550612c1982826133ac565b505b600c60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805480612c6a57612c6961495f565b5b60019003818190600052602060002001600090559055505b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614612d8357612cc0818361347f565b600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819080600181540180825580915050600190039060005260206000200160009091909190915055612d7e816001600c60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050612d79919061475b565b6133ac565b612d9b565b600b6000828152602001908152602001600020600090555b808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b6000612e0683612109565b8210612e3e576040517f580821e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001016000838560000160009054906101000a90046fffffffffffffffffffffffffffffffff16016fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b6000612eb58261128f565b905060005b81811015612ed657612ecb836130fc565b806001019050612eba565b505050565b60007f0000000000000000000000000000000000000000000000000000000000000000612f078361093d565b612f11919061492e565b90506000612f1e8361128f565b905060005b8183612f2f919061475b565b811015612f4a57612f3f84612f50565b806001019050612f23565b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612fb6576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612fc260016134f1565b612fd757612fd06001613561565b9050613079565b600660008154612fe69061498e565b919050819055507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60065403613048576040517f303b682f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006547f8000000000000000000000000000000000000000000000000000000000000000613076919061478f565b90505b60006130848261227a565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146130ec576040517f23369fa600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6130f7818484612a83565b505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603613162576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001600c60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506131f2919061475b565b81548110613203576132026147c3565b5b9060005260206000200154905061321c82600083612a83565b6132308160016136c590919063ffffffff16565b5050565b600080600090507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310613292577a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008381613288576132876148ff565b5b0492506040810190505b6d04ee2d6d415b85acef810000000083106132cf576d04ee2d6d415b85acef810000000083816132c5576132c46148ff565b5b0492506020810190505b662386f26fc1000083106132fe57662386f26fc1000083816132f4576132f36148ff565b5b0492506010810190505b6305f5e1008310613327576305f5e100838161331d5761331c6148ff565b5b0492506008810190505b612710831061334c576127108381613342576133416148ff565b5b0492506004810190505b6064831061336f5760648381613365576133646148ff565b5b0492506002810190505b600a831061337e576001810190505b80915050919050565b600080600b60008481526020019081526020016000205490508060a01c915050919050565b6000600b600084815260200190815260200160002054905060a07fffffffffffffffffffffffff0000000000000000000000000000000000000000901c821115613422576040517ffcb3438c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff00000000000000000000000000000000000000008260a01b1673ffffffffffffffffffffffffffffffffffffffff821601905080600b600085815260200190815260200160002081905550505050565b6000600b600084815260200190815260200160002054905073ffffffffffffffffffffffffffffffffffffffff82167fffffffffffffffffffffffff0000000000000000000000000000000000000000821601905080600b600085815260200190815260200160002081905550505050565b60008160000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168260000160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16149050919050565b6000808260000160109054906101000a90046fffffffffffffffffffffffffffffffff1690508260000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff1603613604576040517f75e52f4f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600190039050826001016000826fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168152602001908152602001600020549150826001016000826fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16815260200190815260200160002060009055808360000160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555050919050565b600060018360000160009054906101000a90046fffffffffffffffffffffffffffffffff160390508260000160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff160361376a576040517f8acb5f2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81836001016000836fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16815260200190815260200160002081905550808360000160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550505050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613831816137fc565b811461383c57600080fd5b50565b60008135905061384e81613828565b92915050565b60006020828403121561386a576138696137f2565b5b60006138788482850161383f565b91505092915050565b60008115159050919050565b61389681613881565b82525050565b60006020820190506138b1600083018461388d565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006138e2826138b7565b9050919050565b6138f2816138d7565b81146138fd57600080fd5b50565b60008135905061390f816138e9565b92915050565b60006020828403121561392b5761392a6137f2565b5b600061393984828501613900565b91505092915050565b6000819050919050565b61395581613942565b82525050565b6000602082019050613970600083018461394c565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156139b0578082015181840152602081019050613995565b60008484015250505050565b6000601f19601f8301169050919050565b60006139d882613976565b6139e28185613981565b93506139f2818560208601613992565b6139fb816139bc565b840191505092915050565b60006020820190508181036000830152613a2081846139cd565b905092915050565b613a3181613942565b8114613a3c57600080fd5b50565b600081359050613a4e81613a28565b92915050565b600060208284031215613a6a57613a696137f2565b5b6000613a7884828501613a3f565b91505092915050565b613a8a816138d7565b82525050565b6000602082019050613aa56000830184613a81565b92915050565b60008060408385031215613ac257613ac16137f2565b5b6000613ad085828601613900565b9250506020613ae185828601613a3f565b9150509250929050565b600080600060608486031215613b0457613b036137f2565b5b6000613b1286828701613900565b9350506020613b2386828701613900565b9250506040613b3486828701613a3f565b9150509250925092565b600060ff82169050919050565b613b5481613b3e565b82525050565b6000602082019050613b6f6000830184613b4b565b92915050565b6000819050919050565b613b8881613b75565b82525050565b6000602082019050613ba36000830184613b7f565b92915050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613beb826139bc565b810181811067ffffffffffffffff82111715613c0a57613c09613bb3565b5b80604052505050565b6000613c1d6137e8565b9050613c298282613be2565b919050565b600067ffffffffffffffff821115613c4957613c48613bb3565b5b613c52826139bc565b9050602081019050919050565b82818337600083830152505050565b6000613c81613c7c84613c2e565b613c13565b905082815260208101848484011115613c9d57613c9c613bae565b5b613ca8848285613c5f565b509392505050565b600082601f830112613cc557613cc4613ba9565b5b8135613cd5848260208601613c6e565b91505092915050565b600060208284031215613cf457613cf36137f2565b5b600082013567ffffffffffffffff811115613d1257613d116137f7565b5b613d1e84828501613cb0565b91505092915050565b613d3081613881565b8114613d3b57600080fd5b50565b600081359050613d4d81613d27565b92915050565b600060208284031215613d6957613d686137f2565b5b6000613d7784828501613d3e565b91505092915050565b60008060408385031215613d9757613d966137f2565b5b6000613da585828601613900565b9250506020613db685828601613d3e565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b613df581613942565b82525050565b6000613e078383613dec565b60208301905092915050565b6000602082019050919050565b6000613e2b82613dc0565b613e358185613dcb565b9350613e4083613ddc565b8060005b83811015613e71578151613e588882613dfb565b9750613e6383613e13565b925050600181019050613e44565b5085935050505092915050565b60006020820190508181036000830152613e988184613e20565b905092915050565b600067ffffffffffffffff821115613ebb57613eba613bb3565b5b613ec4826139bc565b9050602081019050919050565b6000613ee4613edf84613ea0565b613c13565b905082815260208101848484011115613f0057613eff613bae565b5b613f0b848285613c5f565b509392505050565b600082601f830112613f2857613f27613ba9565b5b8135613f38848260208601613ed1565b91505092915050565b60008060008060808587031215613f5b57613f5a6137f2565b5b6000613f6987828801613900565b9450506020613f7a87828801613900565b9350506040613f8b87828801613a3f565b925050606085013567ffffffffffffffff811115613fac57613fab6137f7565b5b613fb887828801613f13565b91505092959194509250565b613fcd81613b3e565b8114613fd857600080fd5b50565b600081359050613fea81613fc4565b92915050565b613ff981613b75565b811461400457600080fd5b50565b60008135905061401681613ff0565b92915050565b600080600080600080600060e0888a03121561403b5761403a6137f2565b5b60006140498a828b01613900565b975050602061405a8a828b01613900565b965050604061406b8a828b01613a3f565b955050606061407c8a828b01613a3f565b945050608061408d8a828b01613fdb565b93505060a061409e8a828b01614007565b92505060c06140af8a828b01614007565b91505092959891949750929550565b600080604083850312156140d5576140d46137f2565b5b60006140e385828601613900565b92505060206140f485828601613900565b9150509250929050565b60008060408385031215614115576141146137f2565b5b600061412385828601613a3f565b925050602061413485828601613a3f565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061418557607f821691505b6020821081036141985761419761413e565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026142007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826141c3565b61420a86836141c3565b95508019841693508086168417925050509392505050565b6000819050919050565b600061424761424261423d84613942565b614222565b613942565b9050919050565b6000819050919050565b6142618361422c565b61427561426d8261424e565b8484546141d0565b825550505050565b600090565b61428a61427d565b614295818484614258565b505050565b5b818110156142b9576142ae600082614282565b60018101905061429b565b5050565b601f8211156142fe576142cf8161419e565b6142d8846141b3565b810160208510156142e7578190505b6142fb6142f3856141b3565b83018261429a565b50505b505050565b600082821c905092915050565b600061432160001984600802614303565b1980831691505092915050565b600061433a8383614310565b9150826002028217905092915050565b61435382613976565b67ffffffffffffffff81111561436c5761436b613bb3565b5b614376825461416d565b6143818282856142bd565b600060209050601f8311600181146143b457600084156143a2578287015190505b6143ac858261432e565b865550614414565b601f1984166143c28661419e565b60005b828110156143ea578489015182556001820191506020850194506020810190506143c5565b868310156144075784890151614403601f891682614310565b8355505b6001600288020188555050505b505050505050565b600081519050919050565b600082825260208201905092915050565b60006144438261441c565b61444d8185614427565b935061445d818560208601613992565b614466816139bc565b840191505092915050565b60006080820190506144866000830187613a81565b6144936020830186613a81565b6144a0604083018561394c565b81810360608301526144b28184614438565b905095945050505050565b6000815190506144cc81613828565b92915050565b6000602082840312156144e8576144e76137f2565b5b60006144f6848285016144bd565b91505092915050565b600081905092915050565b600081546145178161416d565b61452181866144ff565b9450600182166000811461453c576001811461455157614584565b60ff1983168652811515820286019350614584565b61455a8561419e565b60005b8381101561457c5781548189015260018201915060208101905061455d565b838801955050505b50505092915050565b600061459882613976565b6145a281856144ff565b93506145b2818560208601613992565b80840191505092915050565b60006145ca828561450a565b91506145d6828461458d565b91508190509392505050565b600060c0820190506145f76000830189613b7f565b6146046020830188613a81565b6146116040830187613a81565b61461e606083018661394c565b61462b608083018561394c565b61463860a083018461394c565b979650505050505050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b60006146796002836144ff565b915061468482614643565b600282019050919050565b6000819050919050565b6146aa6146a582613b75565b61468f565b82525050565b60006146bb8261466c565b91506146c78285614699565b6020820191506146d78284614699565b6020820191508190509392505050565b60006080820190506146fc6000830187613b7f565b6147096020830186613b4b565b6147166040830185613b7f565b6147236060830184613b7f565b95945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061476682613942565b915061477183613942565b92508282039050818111156147895761478861472c565b5b92915050565b600061479a82613942565b91506147a583613942565b92508282019050808211156147bd576147bc61472c565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081905092915050565b60008190508160005260206000209050919050565b6000815461481f8161416d565b61482981866147f2565b9450600182166000811461484457600181146148595761488c565b60ff198316865281151582028601935061488c565b614862856147fd565b60005b8381101561488457815481890152600182019150602081019050614865565b838801955050505b50505092915050565b60006148a18284614812565b915081905092915050565b600060a0820190506148c16000830188613b7f565b6148ce6020830187613b7f565b6148db6040830186613b7f565b6148e8606083018561394c565b6148f56080830184613a81565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061493982613942565b915061494483613942565b925082614954576149536148ff565b5b828204905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600061499982613942565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036149cb576149ca61472c565b5b60018201905091905056fea26469706673582212209f2164ae04d72272f645276af4e13afdf4b80d808b4fd322208eede85362d9f264736f6c634300081400330000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000002710000000000000000000000000bd0a65465d4bd0e9526683c0119c5daf325a58c7000000000000000000000000bd0a65465d4bd0e9526683c0119c5daf325a58c70000000000000000000000002626664c2603336e57b271c5c0b26f421741e48100000000000000000000000003a520b32c04bf3beef7beb72e919cf822ed34f1000000000000000000000000000000000000000000000000000000000000000648756d61696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000648554d41494e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043697066733a2f2f6261667962656961677a726c377472746f627a76786c7979357679776471627173733273686e706c6d77756d3461707371347a71336d76633679752f0000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061025e5760003560e01c806389fb4c6611610146578063c5ab3ba6116100c3578063dd62ed3e11610087578063dd62ed3e14610787578063dd637699146107b7578063dfabc033146107d3578063e985e9c5146107ef578063f2fde38b1461081f578063f780bc1a1461083b5761025e565b8063c5ab3ba6146106d1578063c6e672b9146106ef578063c87b56dd1461070b578063d505accf1461073b578063d96ca0b9146107575761025e565b8063a22cb4651161010a578063a22cb46514610609578063a9059cbb14610625578063b1ab931714610655578063b3f9ea3414610685578063b88d4fde146106b55761025e565b806389fb4c66146105755780638a696e50146105935780638da5cb5b146105af57806395d89b41146105cd578063976a8435146105eb5761025e565b80633644e515116101df5780636352211e116101a35780636352211e1461049f5780636c0360eb146104cf5780636e8f624b146104ed57806370a082311461050b578063715018a61461053b5780637ecebe00146105455761025e565b80633644e515146103fb57806342842e0e146104195780634d966072146104355780634f02c4201461046557806355f804b3146104835761025e565b806309674eb01161022657806309674eb01461034157806309f0ef651461035f57806318160ddd1461038f57806323b872dd146103ad578063313ce567146103dd5761025e565b806301ffc9a71461026357806302519da31461029357806306fdde03146102c3578063081812fc146102e1578063095ea7b314610311575b600080fd5b61027d60048036038101906102789190613854565b61086b565b60405161028a919061389c565b60405180910390f35b6102ad60048036038101906102a89190613915565b61093d565b6040516102ba919061395b565b60405180910390f35b6102cb610986565b6040516102d89190613a06565b60405180910390f35b6102fb60048036038101906102f69190613a54565b610a14565b6040516103089190613a90565b60405180910390f35b61032b60048036038101906103269190613aab565b610a47565b604051610338919061389c565b60405180910390f35b610349610a82565b604051610356919061395b565b60405180910390f35b61037960048036038101906103749190613915565b610a93565b604051610386919061389c565b60405180910390f35b610397610b1f565b6040516103a4919061395b565b60405180910390f35b6103c760048036038101906103c29190613aeb565b610b25565b6040516103d4919061389c565b60405180910390f35b6103e5610b63565b6040516103f29190613b5a565b60405180910390f35b610403610b87565b6040516104109190613b8e565b60405180910390f35b610433600480360381019061042e9190613aeb565b610be4565b005b61044f600480360381019061044a9190613aab565b610c04565b60405161045c919061389c565b60405180910390f35b61046d610d5b565b60405161047a919061395b565b60405180910390f35b61049d60048036038101906104989190613cde565b610d61565b005b6104b960048036038101906104b49190613a54565b610d7c565b6040516104c69190613a90565b60405180910390f35b6104d7610e33565b6040516104e49190613a06565b60405180910390f35b6104f5610ec1565b604051610502919061395b565b60405180910390f35b61052560048036038101906105209190613915565b610ee5565b604051610532919061395b565b60405180910390f35b610543610efd565b005b61055f600480360381019061055a9190613915565b610f11565b60405161056c919061395b565b60405180910390f35b61057d610f29565b60405161058a919061395b565b60405180910390f35b6105ad60048036038101906105a89190613d53565b610f33565b005b6105b7610f40565b6040516105c49190613a90565b60405180910390f35b6105d5610f69565b6040516105e29190613a06565b60405180910390f35b6105f3610ff7565b604051610600919061395b565b60405180910390f35b610623600480360381019061061e9190613d80565b61101b565b005b61063f600480360381019061063a9190613aab565b61117e565b60405161064c919061389c565b60405180910390f35b61066f600480360381019061066a9190613915565b6111f8565b60405161067c9190613e7e565b60405180910390f35b61069f600480360381019061069a9190613915565b61128f565b6040516106ac919061395b565b60405180910390f35b6106cf60048036038101906106ca9190613f41565b6112db565b005b6106d9611451565b6040516106e6919061395b565b60405180910390f35b61070960048036038101906107049190613d80565b61145b565b005b61072560048036038101906107209190613a54565b611471565b6040516107329190613a06565b60405180910390f35b6107556004803603810190610750919061401c565b6114a5565b005b610771600480360381019061076c9190613aeb565b611832565b60405161077e919061389c565b60405180910390f35b6107a1600480360381019061079c91906140be565b611a49565b6040516107ae919061395b565b60405180910390f35b6107d160048036038101906107cc9190613aeb565b611a6e565b005b6107ed60048036038101906107e89190613aab565b611d87565b005b610809600480360381019061080491906140be565b611f40565b604051610816919061389c565b60405180910390f35b61083960048036038101906108349190613915565b611f6f565b005b610855600480360381019061085091906140fe565b611ff5565b6040516108629190613e7e565b60405180910390f35b60007fcaf91ff5000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061093657507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b6000600760008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600380546109939061416d565b80601f01602080910402602001604051908101604052809291908181526020018280546109bf9061416d565b8015610a0c5780601f106109e157610100808354040283529160200191610a0c565b820191906000526020600020905b8154815290600101906020018083116109ef57829003601f168201915b505050505081565b60096020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000610a52826120b1565b15610a6657610a618383611d87565b610a77565b610a708383610c04565b9050610a7c565b600190505b92915050565b6000610a8e6001612109565b905090565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480610b185750600d60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff165b9050919050565b60055481565b6000610b30826120b1565b15610b4557610b40848484611a6e565b610b57565b610b50848484611832565b9050610b5c565b600190505b9392505050565b7f000000000000000000000000000000000000000000000000000000000000001281565b60007f00000000000000000000000000000000000000000000000000000000000021054614610bbd57610bb8612167565b610bdf565b7f9a52d8ff51ffea93afe30796cffec547f575211389ec0421b073c6bbc95c93c45b905090565b610bff838383604051806020016040528060008152506112db565b505050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610c6b576040517f5461585f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81600860003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610d49919061395b565b60405180910390a36001905092915050565b60065481565b610d696121f3565b80600f9081610d78919061434a565b5050565b6000610d878261227a565b9050610d92826120b1565b610dc8576040517f3f6cc76800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610e2e576040517fc5723b5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b600f8054610e409061416d565b80601f0160208091040260200160405190810160405280929190818152602001828054610e6c9061416d565b8015610eb95780601f10610e8e57610100808354040283529160200191610eb9565b820191906000526020600020905b815481529060010190602001808311610e9c57829003601f168201915b505050505081565b7f800000000000000000000000000000000000000000000000000000000000000081565b60076020528060005260406000206000915090505481565b610f056121f3565b610f0f60006122b2565b565b600e6020528060005260406000206000915090505481565b6000600554905090565b610f3d3382612376565b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60048054610f769061416d565b80601f0160208091040260200160405190810160405280929190818152602001828054610fa29061416d565b8015610fef5780601f10610fc457610100808354040283529160200191610fef565b820191906000526020600020905b815481529060010190602001808311610fd257829003601f168201915b505050505081565b7f0000000000000000000000000000000000000000000000000de0b6b3a764000081565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611081576040517fccea9e6f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600a60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051611172919061389c565b60405180910390a35050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036111e5576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111f0338484612455565b905092915050565b6060600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080548060200260200160405190810160405280929190818152602001828054801561128357602002820191906000526020600020905b81548152602001906001019080831161126f575b50505050509050919050565b6000600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050919050565b6112e4826120b1565b61131a576040517f3f6cc76800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611325848484610b25565b5060008373ffffffffffffffffffffffffffffffffffffffff163b14158015611414575063150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168373ffffffffffffffffffffffffffffffffffffffff1663150b7a02338786866040518563ffffffff1660e01b81526004016113af9493929190614471565b6020604051808303816000875af11580156113ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f291906144d2565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614155b1561144b576040517f3da6393100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b6000600654905090565b6114636121f3565b61146d8282612376565b5050565b6060600f61147e83612855565b60405160200161148f9291906145be565b6040516020818303038152906040529050919050565b428410156114df576040517f05787bdf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e8856120b1565b1561151f576040517f1f3e0de800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1603611585576040517f5461585f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006001611591610b87565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98a8a8a600e60008f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190600101919050558b604051602001611619969594939291906145e2565b604051602081830303815290604052805190602001206040516020016116409291906146b0565b604051602081830303815290604052805190602001208585856040516000815260200160405260405161167694939291906146e7565b6020604051602081039080840390855afa158015611698573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16148061170b57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b15611742576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85600860008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92587604051611821919061395b565b60405180910390a350505050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603611899576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036118ff576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600860008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611a345782816119b3919061475b565b600860008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b611a3f858585612455565b9150509392505050565b6008602052816000526040600020602052806000526040600020600091509150505481565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611ad4576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611b3a576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b438161227a565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614611ba7576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015611c6a5750600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b8015611cd557506009600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15611d0c576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d1582610a93565b15611d4c576040517f5ce7539700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611d7783837f0000000000000000000000000000000000000000000000000de0b6b3a7640000612923565b611d82838383612a83565b505050565b6000611d928261227a565b90508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015611e575750600a60008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b15611e8e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826009600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550818373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a4505050565b600a6020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b611f776121f3565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611fe95760006040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401611fe09190613a90565b60405180910390fd5b611ff2816122b2565b50565b606060008267ffffffffffffffff81111561201357612012613bb3565b5b6040519080825280602002602001820160405280156120415781602001602082028036833780820191505090505b50905060008490505b8385612056919061478f565b8110156120a657612071816001612dfb90919063ffffffff16565b82868361207e919061475b565b8151811061208f5761208e6147c3565b5b60200260200101818152505080600101905061204a565b508091505092915050565b60007f80000000000000000000000000000000000000000000000000000000000000008211801561210257507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214155b9050919050565b60008160000160009054906101000a90046fffffffffffffffffffffffffffffffff168260000160109054906101000a90046fffffffffffffffffffffffffffffffff16036fffffffffffffffffffffffffffffffff169050919050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60036040516121999190614895565b60405180910390207fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc646306040516020016121d89594939291906148ac565b60405160208183030381529060405280519060200120905090565b6121fb612ea2565b73ffffffffffffffffffffffffffffffffffffffff16612219610f40565b73ffffffffffffffffffffffffffffffffffffffff16146122785761223c612ea2565b6040517f118cdaa700000000000000000000000000000000000000000000000000000000815260040161226f9190613a90565b60405180910390fd5b565b600080600b600084815260200190815260200160002054905073ffffffffffffffffffffffffffffffffffffffff8116915050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036123dc576040517fa41e3d3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80156123f0576123eb82612eaa565b6123fa565b6123f982612edb565b5b80600d60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b6000806124618561093d565b9050600061246e8561093d565b905061247b868686612923565b600061248687610a93565b9050600061249387610a93565b905081801561249f5750805b6128465781156125745760007f0000000000000000000000000000000000000000000000000de0b6b3a7640000846124d7919061492e565b7f0000000000000000000000000000000000000000000000000de0b6b3a7640000600760008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054612542919061492e565b61254c919061475b565b905060005b8181101561256d5761256289612f50565b806001019050612551565b5050612845565b80156126455760007f0000000000000000000000000000000000000000000000000de0b6b3a7640000600760008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546125e7919061492e565b7f0000000000000000000000000000000000000000000000000de0b6b3a764000086612613919061492e565b61261d919061475b565b905060005b8181101561263e576126338a6130fc565b806001019050612622565b5050612844565b60007f0000000000000000000000000000000000000000000000000de0b6b3a764000087612673919061492e565b905060005b8181101561274b5760006001600c60008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506126d1919061475b565b90506000600c60008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208281548110612726576127256147c3565b5b9060005260206000200154905061273e8c8c83612a83565b8260010192505050612678565b50807f0000000000000000000000000000000000000000000000000de0b6b3a76400006127778b61093d565b612781919061492e565b7f0000000000000000000000000000000000000000000000000de0b6b3a7640000876127ad919061492e565b6127b7919061475b565b11156127c7576127c6896130fc565b5b807f0000000000000000000000000000000000000000000000000de0b6b3a7640000856127f4919061492e565b7f0000000000000000000000000000000000000000000000000de0b6b3a764000061281e8b61093d565b612828919061492e565b612832919061475b565b11156128425761284188612f50565b5b505b5b5b60019450505050509392505050565b60606000600161286484613234565b01905060008167ffffffffffffffff81111561288357612882613bb3565b5b6040519080825280601f01601f1916602001820160405280156128b55781602001600182028036833780820191505090505b509050600082602001820190505b600115612918578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a858161290c5761290b6148ff565b5b049450600085036128c3575b819350505050919050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612975578060056000828254612969919061478f565b925050819055506129cc565b80600760008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546129c4919061475b565b925050819055505b80600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051612a76919061395b565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614612c82576009600082815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000600c60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001600c60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050612b7d919061475b565b81548110612b8e57612b8d6147c3565b5b90600052602060002001549050818114612c1b576000612bad83613387565b905081600c60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208281548110612c0157612c006147c3565b5b9060005260206000200181905550612c1982826133ac565b505b600c60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805480612c6a57612c6961495f565b5b60019003818190600052602060002001600090559055505b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614612d8357612cc0818361347f565b600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819080600181540180825580915050600190039060005260206000200160009091909190915055612d7e816001600c60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050612d79919061475b565b6133ac565b612d9b565b600b6000828152602001908152602001600020600090555b808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b6000612e0683612109565b8210612e3e576040517f580821e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001016000838560000160009054906101000a90046fffffffffffffffffffffffffffffffff16016fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b6000612eb58261128f565b905060005b81811015612ed657612ecb836130fc565b806001019050612eba565b505050565b60007f0000000000000000000000000000000000000000000000000de0b6b3a7640000612f078361093d565b612f11919061492e565b90506000612f1e8361128f565b905060005b8183612f2f919061475b565b811015612f4a57612f3f84612f50565b806001019050612f23565b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612fb6576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612fc260016134f1565b612fd757612fd06001613561565b9050613079565b600660008154612fe69061498e565b919050819055507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60065403613048576040517f303b682f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006547f8000000000000000000000000000000000000000000000000000000000000000613076919061478f565b90505b60006130848261227a565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146130ec576040517f23369fa600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6130f7818484612a83565b505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603613162576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001600c60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490506131f2919061475b565b81548110613203576132026147c3565b5b9060005260206000200154905061321c82600083612a83565b6132308160016136c590919063ffffffff16565b5050565b600080600090507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310613292577a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008381613288576132876148ff565b5b0492506040810190505b6d04ee2d6d415b85acef810000000083106132cf576d04ee2d6d415b85acef810000000083816132c5576132c46148ff565b5b0492506020810190505b662386f26fc1000083106132fe57662386f26fc1000083816132f4576132f36148ff565b5b0492506010810190505b6305f5e1008310613327576305f5e100838161331d5761331c6148ff565b5b0492506008810190505b612710831061334c576127108381613342576133416148ff565b5b0492506004810190505b6064831061336f5760648381613365576133646148ff565b5b0492506002810190505b600a831061337e576001810190505b80915050919050565b600080600b60008481526020019081526020016000205490508060a01c915050919050565b6000600b600084815260200190815260200160002054905060a07fffffffffffffffffffffffff0000000000000000000000000000000000000000901c821115613422576040517ffcb3438c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffff00000000000000000000000000000000000000008260a01b1673ffffffffffffffffffffffffffffffffffffffff821601905080600b600085815260200190815260200160002081905550505050565b6000600b600084815260200190815260200160002054905073ffffffffffffffffffffffffffffffffffffffff82167fffffffffffffffffffffffff0000000000000000000000000000000000000000821601905080600b600085815260200190815260200160002081905550505050565b60008160000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168260000160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16149050919050565b6000808260000160109054906101000a90046fffffffffffffffffffffffffffffffff1690508260000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff1603613604576040517f75e52f4f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600190039050826001016000826fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168152602001908152602001600020549150826001016000826fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16815260200190815260200160002060009055808360000160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555050919050565b600060018360000160009054906101000a90046fffffffffffffffffffffffffffffffff160390508260000160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff160361376a576040517f8acb5f2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81836001016000836fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16815260200190815260200160002081905550808360000160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550505050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613831816137fc565b811461383c57600080fd5b50565b60008135905061384e81613828565b92915050565b60006020828403121561386a576138696137f2565b5b60006138788482850161383f565b91505092915050565b60008115159050919050565b61389681613881565b82525050565b60006020820190506138b1600083018461388d565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006138e2826138b7565b9050919050565b6138f2816138d7565b81146138fd57600080fd5b50565b60008135905061390f816138e9565b92915050565b60006020828403121561392b5761392a6137f2565b5b600061393984828501613900565b91505092915050565b6000819050919050565b61395581613942565b82525050565b6000602082019050613970600083018461394c565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156139b0578082015181840152602081019050613995565b60008484015250505050565b6000601f19601f8301169050919050565b60006139d882613976565b6139e28185613981565b93506139f2818560208601613992565b6139fb816139bc565b840191505092915050565b60006020820190508181036000830152613a2081846139cd565b905092915050565b613a3181613942565b8114613a3c57600080fd5b50565b600081359050613a4e81613a28565b92915050565b600060208284031215613a6a57613a696137f2565b5b6000613a7884828501613a3f565b91505092915050565b613a8a816138d7565b82525050565b6000602082019050613aa56000830184613a81565b92915050565b60008060408385031215613ac257613ac16137f2565b5b6000613ad085828601613900565b9250506020613ae185828601613a3f565b9150509250929050565b600080600060608486031215613b0457613b036137f2565b5b6000613b1286828701613900565b9350506020613b2386828701613900565b9250506040613b3486828701613a3f565b9150509250925092565b600060ff82169050919050565b613b5481613b3e565b82525050565b6000602082019050613b6f6000830184613b4b565b92915050565b6000819050919050565b613b8881613b75565b82525050565b6000602082019050613ba36000830184613b7f565b92915050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613beb826139bc565b810181811067ffffffffffffffff82111715613c0a57613c09613bb3565b5b80604052505050565b6000613c1d6137e8565b9050613c298282613be2565b919050565b600067ffffffffffffffff821115613c4957613c48613bb3565b5b613c52826139bc565b9050602081019050919050565b82818337600083830152505050565b6000613c81613c7c84613c2e565b613c13565b905082815260208101848484011115613c9d57613c9c613bae565b5b613ca8848285613c5f565b509392505050565b600082601f830112613cc557613cc4613ba9565b5b8135613cd5848260208601613c6e565b91505092915050565b600060208284031215613cf457613cf36137f2565b5b600082013567ffffffffffffffff811115613d1257613d116137f7565b5b613d1e84828501613cb0565b91505092915050565b613d3081613881565b8114613d3b57600080fd5b50565b600081359050613d4d81613d27565b92915050565b600060208284031215613d6957613d686137f2565b5b6000613d7784828501613d3e565b91505092915050565b60008060408385031215613d9757613d966137f2565b5b6000613da585828601613900565b9250506020613db685828601613d3e565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b613df581613942565b82525050565b6000613e078383613dec565b60208301905092915050565b6000602082019050919050565b6000613e2b82613dc0565b613e358185613dcb565b9350613e4083613ddc565b8060005b83811015613e71578151613e588882613dfb565b9750613e6383613e13565b925050600181019050613e44565b5085935050505092915050565b60006020820190508181036000830152613e988184613e20565b905092915050565b600067ffffffffffffffff821115613ebb57613eba613bb3565b5b613ec4826139bc565b9050602081019050919050565b6000613ee4613edf84613ea0565b613c13565b905082815260208101848484011115613f0057613eff613bae565b5b613f0b848285613c5f565b509392505050565b600082601f830112613f2857613f27613ba9565b5b8135613f38848260208601613ed1565b91505092915050565b60008060008060808587031215613f5b57613f5a6137f2565b5b6000613f6987828801613900565b9450506020613f7a87828801613900565b9350506040613f8b87828801613a3f565b925050606085013567ffffffffffffffff811115613fac57613fab6137f7565b5b613fb887828801613f13565b91505092959194509250565b613fcd81613b3e565b8114613fd857600080fd5b50565b600081359050613fea81613fc4565b92915050565b613ff981613b75565b811461400457600080fd5b50565b60008135905061401681613ff0565b92915050565b600080600080600080600060e0888a03121561403b5761403a6137f2565b5b60006140498a828b01613900565b975050602061405a8a828b01613900565b965050604061406b8a828b01613a3f565b955050606061407c8a828b01613a3f565b945050608061408d8a828b01613fdb565b93505060a061409e8a828b01614007565b92505060c06140af8a828b01614007565b91505092959891949750929550565b600080604083850312156140d5576140d46137f2565b5b60006140e385828601613900565b92505060206140f485828601613900565b9150509250929050565b60008060408385031215614115576141146137f2565b5b600061412385828601613a3f565b925050602061413485828601613a3f565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061418557607f821691505b6020821081036141985761419761413e565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026142007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826141c3565b61420a86836141c3565b95508019841693508086168417925050509392505050565b6000819050919050565b600061424761424261423d84613942565b614222565b613942565b9050919050565b6000819050919050565b6142618361422c565b61427561426d8261424e565b8484546141d0565b825550505050565b600090565b61428a61427d565b614295818484614258565b505050565b5b818110156142b9576142ae600082614282565b60018101905061429b565b5050565b601f8211156142fe576142cf8161419e565b6142d8846141b3565b810160208510156142e7578190505b6142fb6142f3856141b3565b83018261429a565b50505b505050565b600082821c905092915050565b600061432160001984600802614303565b1980831691505092915050565b600061433a8383614310565b9150826002028217905092915050565b61435382613976565b67ffffffffffffffff81111561436c5761436b613bb3565b5b614376825461416d565b6143818282856142bd565b600060209050601f8311600181146143b457600084156143a2578287015190505b6143ac858261432e565b865550614414565b601f1984166143c28661419e565b60005b828110156143ea578489015182556001820191506020850194506020810190506143c5565b868310156144075784890151614403601f891682614310565b8355505b6001600288020188555050505b505050505050565b600081519050919050565b600082825260208201905092915050565b60006144438261441c565b61444d8185614427565b935061445d818560208601613992565b614466816139bc565b840191505092915050565b60006080820190506144866000830187613a81565b6144936020830186613a81565b6144a0604083018561394c565b81810360608301526144b28184614438565b905095945050505050565b6000815190506144cc81613828565b92915050565b6000602082840312156144e8576144e76137f2565b5b60006144f6848285016144bd565b91505092915050565b600081905092915050565b600081546145178161416d565b61452181866144ff565b9450600182166000811461453c576001811461455157614584565b60ff1983168652811515820286019350614584565b61455a8561419e565b60005b8381101561457c5781548189015260018201915060208101905061455d565b838801955050505b50505092915050565b600061459882613976565b6145a281856144ff565b93506145b2818560208601613992565b80840191505092915050565b60006145ca828561450a565b91506145d6828461458d565b91508190509392505050565b600060c0820190506145f76000830189613b7f565b6146046020830188613a81565b6146116040830187613a81565b61461e606083018661394c565b61462b608083018561394c565b61463860a083018461394c565b979650505050505050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b60006146796002836144ff565b915061468482614643565b600282019050919050565b6000819050919050565b6146aa6146a582613b75565b61468f565b82525050565b60006146bb8261466c565b91506146c78285614699565b6020820191506146d78284614699565b6020820191508190509392505050565b60006080820190506146fc6000830187613b7f565b6147096020830186613b4b565b6147166040830185613b7f565b6147236060830184613b7f565b95945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061476682613942565b915061477183613942565b92508282039050818111156147895761478861472c565b5b92915050565b600061479a82613942565b91506147a583613942565b92508282019050808211156147bd576147bc61472c565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081905092915050565b60008190508160005260206000209050919050565b6000815461481f8161416d565b61482981866147f2565b9450600182166000811461484457600181146148595761488c565b60ff198316865281151582028601935061488c565b614862856147fd565b60005b8381101561488457815481890152600182019150602081019050614865565b838801955050505b50505092915050565b60006148a18284614812565b915081905092915050565b600060a0820190506148c16000830188613b7f565b6148ce6020830187613b7f565b6148db6040830186613b7f565b6148e8606083018561394c565b6148f56080830184613a81565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061493982613942565b915061494483613942565b925082614954576149536148ff565b5b828204905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600061499982613942565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036149cb576149ca61472c565b5b60018201905091905056fea26469706673582212209f2164ae04d72272f645276af4e13afdf4b80d808b4fd322208eede85362d9f264736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000002710000000000000000000000000bd0a65465d4bd0e9526683c0119c5daf325a58c7000000000000000000000000bd0a65465d4bd0e9526683c0119c5daf325a58c70000000000000000000000002626664c2603336e57b271c5c0b26f421741e48100000000000000000000000003a520b32c04bf3beef7beb72e919cf822ed34f1000000000000000000000000000000000000000000000000000000000000000648756d61696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000648554d41494e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043697066733a2f2f6261667962656961677a726c377472746f627a76786c7979357679776471627173733273686e706c6d77756d3461707371347a71336d76633679752f0000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : name_ (string): Humain
Arg [1] : symbol_ (string): HUMAIN
Arg [2] : baseURI_ (string): ipfs://bafybeiagzrl7trtobzvxlyy5vywdqbqss2shnplmwum4apsq4zq3mvc6yu/
Arg [3] : decimals_ (uint8): 18
Arg [4] : maxTotalSupplyERC721_ (uint256): 10000
Arg [5] : initialOwner_ (address): 0xBD0a65465d4bd0E9526683c0119C5Daf325a58c7
Arg [6] : initialMintRecipient_ (address): 0xBD0a65465d4bd0E9526683c0119C5Daf325a58c7
Arg [7] : uniswapSwapRouter_ (address): 0x2626664c2603336E57B271c5C0b26F421741e481
Arg [8] : uniswapV3NonfungiblePositionManager_ (address): 0x03a520b32C04BF3bEEf7BEb72E919cf822Ed34f1
-----Encoded View---------------
17 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [2] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [4] : 0000000000000000000000000000000000000000000000000000000000002710
Arg [5] : 000000000000000000000000bd0a65465d4bd0e9526683c0119c5daf325a58c7
Arg [6] : 000000000000000000000000bd0a65465d4bd0e9526683c0119c5daf325a58c7
Arg [7] : 0000000000000000000000002626664c2603336e57b271c5c0b26f421741e481
Arg [8] : 00000000000000000000000003a520b32c04bf3beef7beb72e919cf822ed34f1
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [10] : 48756d61696e0000000000000000000000000000000000000000000000000000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [12] : 48554d41494e0000000000000000000000000000000000000000000000000000
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000043
Arg [14] : 697066733a2f2f6261667962656961677a726c377472746f627a76786c797935
Arg [15] : 7679776471627173733273686e706c6d77756d3461707371347a71336d766336
Arg [16] : 79752f0000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| BASE | 100.00% | $0.999516 | 70 | $69.97 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.