Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 1,281 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Set Approval For... | 402216374 | 74 days ago | IN | 0 ETH | 0.00000046 | ||||
| Approve | 376038800 | 149 days ago | IN | 0 ETH | 0.00000028 | ||||
| Set Approval For... | 372064062 | 161 days ago | IN | 0 ETH | 0.00000096 | ||||
| Recover Eth | 364283773 | 183 days ago | IN | 0 ETH | 0.00000034 | ||||
| Safe Transfer Fr... | 364269811 | 183 days ago | IN | 0 ETH | 0.00000267 | ||||
| Set Approval For... | 352970598 | 216 days ago | IN | 0 ETH | 0.00000049 | ||||
| Approve | 346842114 | 234 days ago | IN | 0 ETH | 0.00000039 | ||||
| Approve | 346840237 | 234 days ago | IN | 0 ETH | 0.00000051 | ||||
| Approve | 346839961 | 234 days ago | IN | 0 ETH | 0.00000054 | ||||
| Approve | 346839834 | 234 days ago | IN | 0 ETH | 0.00000059 | ||||
| Approve | 346835554 | 234 days ago | IN | 0 ETH | 0.00000037 | ||||
| Approve | 346656416 | 234 days ago | IN | 0 ETH | 0.00000041 | ||||
| Approve | 346656307 | 234 days ago | IN | 0 ETH | 0.00000041 | ||||
| Approve | 346656134 | 234 days ago | IN | 0 ETH | 0.00000042 | ||||
| Approve | 346656039 | 234 days ago | IN | 0 ETH | 0.00000041 | ||||
| Approve | 346655970 | 234 days ago | IN | 0 ETH | 0.00000061 | ||||
| Approve | 344919734 | 239 days ago | IN | 0 ETH | 0.00000037 | ||||
| Approve | 344919445 | 239 days ago | IN | 0 ETH | 0.00000037 | ||||
| Approve | 344918579 | 239 days ago | IN | 0 ETH | 0.00000036 | ||||
| Approve | 344916549 | 239 days ago | IN | 0 ETH | 0.00000035 | ||||
| Approve | 344915578 | 239 days ago | IN | 0 ETH | 0.00000036 | ||||
| Approve | 344915070 | 239 days ago | IN | 0 ETH | 0.00000036 | ||||
| Approve | 344914892 | 239 days ago | IN | 0 ETH | 0.00000036 | ||||
| Approve | 343588828 | 243 days ago | IN | 0 ETH | 0.00000044 | ||||
| Approve | 343586909 | 243 days ago | IN | 0 ETH | 0.00000046 |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Katana
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@kenshi.io/vrf-consumer/contracts/VRFUtils.sol";
contract Katana is ERC721, ERC721Enumerable, AccessControl {
using SafeERC20 for IERC20;
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant ORACLE_ROLE = keccak256("ORACLE_ROLE");
mapping(uint256 => bool) private _alreadyFulfilled;
mapping(uint256 => address) private _requestMap;
VRFUtils private _utils;
uint256 private _price = 0.15 ether;
uint256 private _pending = 0;
uint256 private _requestId = 0;
address private _seller;
uint256[] private _available;
constructor(bytes memory publicKey) ERC721("Katana", "KAT") {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(MINTER_ROLE, msg.sender);
_seller = msg.sender;
_utils = new VRFUtils();
_utils.setPublicKey(publicKey);
}
function _baseURI() internal pure override returns (string memory) {
return "https://nft.kenshi.io/katana/";
}
function setPrice(uint256 price) external onlyRole(DEFAULT_ADMIN_ROLE) {
_price = price;
}
function getPrice() external view returns (uint256) {
return _price;
}
function getAvailable() external view returns (uint256[] memory) {
return _available;
}
function setSeller(address seller) external onlyRole(DEFAULT_ADMIN_ROLE) {
_seller = seller;
}
function safeMint(
address to,
uint256 tokenId
) public onlyRole(MINTER_ROLE) {
_safeMint(to, tokenId);
}
function safeMintToSeller(uint256 tokenId) public onlyRole(MINTER_ROLE) {
_safeMint(_seller, tokenId);
_available.push(tokenId);
}
function batchSafeMintToSeller(
uint256 start,
uint256 count
) public onlyRole(MINTER_ROLE) {
for (uint i = 0; i < count; i++) {
safeMintToSeller(i + start);
}
}
event RandomMintRequested(uint256 requestId);
function mintRandom(address to) public payable {
require(
msg.value >= _price,
"Value is lower than the NFT minting price"
);
require(_available.length > _pending, "No more NFTs to sell");
uint256 requestId = _requestId++;
_pending++;
_requestMap[requestId] = to;
emit RandomMintRequested(requestId);
}
function batchMintRandom(address to, uint256 count) public payable {
require(count > 0, "Can't mint zero NFTs");
require(
msg.value >= _price * count,
"Value is lower than the NFT minting price"
);
require(_available.length > _pending + count, "Not enough supply left");
for (uint i = 0; i < count; i++) {
uint256 requestId = _requestId++;
_pending++;
_requestMap[requestId] = to;
emit RandomMintRequested(requestId);
}
}
function onRandomness(
uint256[4] memory proof,
bytes memory message,
uint256[2] memory uPoint,
uint256[4] memory vComponents,
uint256 requestId
) external onlyRole(ORACLE_ROLE) {
require(!_alreadyFulfilled[requestId], "Already fulfilled");
bool isValid = _utils.fastVerify(proof, message, uPoint, vComponents);
require(isValid, "Delivered randomness is not valid!");
bytes32 beta = _utils.gammaToHash(proof[0], proof[1]);
uint256 randomness = uint256(beta);
_alreadyFulfilled[requestId] = true;
address to = _requestMap[requestId];
_pending--;
uint256 index = randomness % _available.length;
uint256 tokenId = _available[index];
_available[index] = _available[_available.length - 1];
_available.pop();
safeTransferFrom(_seller, to, tokenId);
}
function tokensOfOwner(
address owner
) external view returns (uint256[] memory) {
uint256 balance = balanceOf(owner);
uint256[] memory tokens = new uint256[](balance);
for (uint i = 0; i < balance; i++) {
tokens[i] = tokenOfOwnerByIndex(owner, i);
}
return tokens;
}
// The following functions are overrides required by Solidity.
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId,
uint256 batchSize
) internal override(ERC721, ERC721Enumerable) {
super._beforeTokenTransfer(from, to, tokenId, batchSize);
}
function supportsInterface(
bytes4 interfaceId
)
public
view
override(ERC721, ERC721Enumerable, AccessControl)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
// Recover ETH and ERC20 tokens
function recoverEth(
address payable to
) public onlyRole(DEFAULT_ADMIN_ROLE) {
(bool sent, ) = to.call{value: address(this).balance}("");
require(sent, "Failed to send Ether");
}
function recoverERC20(
address token,
address recipient,
uint256 amount
) external onlyRole(DEFAULT_ADMIN_ROLE) {
IERC20(token).safeTransfer(recipient, amount);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;
import "./lib/VRF.sol";
/**
* @title Test Helper for the VRF contract
* @dev The aim of this contract is twofold:
* 1. Raise the visibility modifier of VRF contract functions for testing purposes
* 2. Removal of the `pure` modifier to allow gas consumption analysis
* @author Witnet Foundation
*/
contract VRFUtils {
address private _owner;
uint256[2] private _publicKey;
constructor() {
_owner = msg.sender;
}
/**
* @dev Sets the public key used for VRF verification.
*/
function setPublicKey(bytes memory publicKey) public {
require(msg.sender == _owner, "Only owner");
_publicKey = VRF.decodePoint(publicKey);
}
/**
* @dev Get the public key used for VRF verification.
*/
function getPublicKey() public view returns (bytes memory) {
return VRF.encodePoint(_publicKey[0], _publicKey[1]);
}
function decodeProof(bytes memory _proof)
public
pure
returns (uint256[4] memory)
{
return VRF.decodeProof(_proof);
}
function decodePoint(bytes memory _point)
public
pure
returns (uint256[2] memory)
{
return VRF.decodePoint(_point);
}
function computeFastVerifyParams(
uint256[2] memory publicKey,
uint256[4] memory proof,
bytes memory message
) public pure returns (uint256[2] memory, uint256[4] memory) {
return VRF.computeFastVerifyParams(publicKey, proof, message);
}
function computeFastVerifyParams(
uint256[4] memory proof,
bytes memory message
) public view returns (uint256[2] memory, uint256[4] memory) {
return VRF.computeFastVerifyParams(_publicKey, proof, message);
}
function verify(
uint256[2] memory publicKey,
uint256[4] memory proof,
bytes memory message
) public pure returns (bool) {
return VRF.verify(publicKey, proof, message);
}
function verify(uint256[4] memory proof, bytes memory message)
public
view
returns (bool)
{
return VRF.verify(_publicKey, proof, message);
}
function fastVerify(
uint256[2] memory publicKey,
uint256[4] memory proof,
bytes memory message,
uint256[2] memory uPoint,
uint256[4] memory vComponents
) public pure returns (bool) {
return VRF.fastVerify(publicKey, proof, message, uPoint, vComponents);
}
function fastVerify(
uint256[4] memory proof,
bytes memory message,
uint256[2] memory uPoint,
uint256[4] memory vComponents
) public view returns (bool) {
return VRF.fastVerify(_publicKey, proof, message, uPoint, vComponents);
}
function gammaToHash(uint256 _gammaX, uint256 _gammaY)
public
pure
returns (bytes32)
{
return VRF.gammaToHash(_gammaX, _gammaY);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to
* 0 before setting it to a non-zero value.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)
pragma solidity ^0.8.0;
/**
* @title Counters
* @author Matt Condon (@shrugs)
* @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
* of elements in a mapping, issuing ERC721 ids, or counting request ids.
*
* Include with `using Counters for Counters.Counter;`
*/
library Counters {
struct Counter {
// This variable should never be directly accessed by users of the library: interactions must be restricted to
// the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
// this feature: see https://github.com/ethereum/solidity/issues/4637
uint256 _value; // default: 0
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
unchecked {
counter._value += 1;
}
}
function decrement(Counter storage counter) internal {
uint256 value = counter._value;
require(value > 0, "Counter: decrement overflow");
unchecked {
counter._value = value - 1;
}
}
function reset(Counter storage counter) internal {
counter._value = 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Enumerable.sol)
pragma solidity ^0.8.0;
import "../ERC721.sol";
import "./IERC721Enumerable.sol";
/**
* @dev This implements an optional extension of {ERC721} defined in the EIP that adds
* enumerability of all the token ids in the contract as well as all token ids owned by each
* account.
*/
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
// Mapping from owner to list of owned token IDs
mapping(address => mapping(uint256 => uint256)) private _ownedTokens;
// Mapping from token ID to index of the owner tokens list
mapping(uint256 => uint256) private _ownedTokensIndex;
// Array with all token ids, used for enumeration
uint256[] private _allTokens;
// Mapping from token id to position in the allTokens array
mapping(uint256 => uint256) private _allTokensIndex;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
return _ownedTokens[owner][index];
}
/**
* @dev See {IERC721Enumerable-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _allTokens.length;
}
/**
* @dev See {IERC721Enumerable-tokenByIndex}.
*/
function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
return _allTokens[index];
}
/**
* @dev See {ERC721-_beforeTokenTransfer}.
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 firstTokenId,
uint256 batchSize
) internal virtual override {
super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
if (batchSize > 1) {
// Will only trigger during construction. Batch transferring (minting) is not available afterwards.
revert("ERC721Enumerable: consecutive transfers not supported");
}
uint256 tokenId = firstTokenId;
if (from == address(0)) {
_addTokenToAllTokensEnumeration(tokenId);
} else if (from != to) {
_removeTokenFromOwnerEnumeration(from, tokenId);
}
if (to == address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId);
} else if (to != from) {
_addTokenToOwnerEnumeration(to, tokenId);
}
}
/**
* @dev Private function to add a token to this extension's ownership-tracking data structures.
* @param to address representing the new owner of the given token ID
* @param tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
uint256 length = ERC721.balanceOf(to);
_ownedTokens[to][length] = tokenId;
_ownedTokensIndex[tokenId] = length;
}
/**
* @dev Private function to add a token to this extension's token tracking data structures.
* @param tokenId uint256 ID of the token to be added to the tokens list
*/
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
/**
* @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
* while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
* gas optimizations e.g. when performing a transfer operation (avoiding double writes).
* This has O(1) time complexity, but alters the order of the _ownedTokens array.
* @param from address representing the previous owner of the given token ID
* @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
// To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
uint256 tokenIndex = _ownedTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
}
// This also deletes the contents at the last position of the array
delete _ownedTokensIndex[tokenId];
delete _ownedTokens[from][lastTokenIndex];
}
/**
* @dev Private function to remove a token from this extension's token tracking data structures.
* This has O(1) time complexity, but alters the order of the _allTokens array.
* @param tokenId uint256 ID of the token to be removed from the tokens list
*/
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
// To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = _allTokens.length - 1;
uint256 tokenIndex = _allTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
// rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
// an 'if' statement (like in _removeTokenFromOwnerEnumeration)
uint256 lastTokenId = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
// This also deletes the contents at the last position of the array
delete _allTokensIndex[tokenId];
_allTokens.pop();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/ERC721.sol)
pragma solidity ^0.8.0;
import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./extensions/IERC721Metadata.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/Strings.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
* the Metadata extension, but not including the Enumerable extension, which is available separately as
* {ERC721Enumerable}.
*/
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
using Address for address;
using Strings for uint256;
// Token name
string private _name;
// Token symbol
string private _symbol;
// Mapping from token ID to owner address
mapping(uint256 => address) private _owners;
// Mapping owner address to token count
mapping(address => uint256) private _balances;
// Mapping from token ID to approved address
mapping(uint256 => address) private _tokenApprovals;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/
function balanceOf(address owner) public view virtual override returns (uint256) {
require(owner != address(0), "ERC721: address zero is not a valid owner");
return _balances[owner];
}
/**
* @dev See {IERC721-ownerOf}.
*/
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
address owner = _ownerOf(tokenId);
require(owner != address(0), "ERC721: invalid token ID");
return owner;
}
/**
* @dev See {IERC721Metadata-name}.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
_requireMinted(tokenId);
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overridden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return "";
}
/**
* @dev See {IERC721-approve}.
*/
function approve(address to, uint256 tokenId) public virtual override {
address owner = ERC721.ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(
_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
"ERC721: approve caller is not token owner or approved for all"
);
_approve(to, tokenId);
}
/**
* @dev See {IERC721-getApproved}.
*/
function getApproved(uint256 tokenId) public view virtual override returns (address) {
_requireMinted(tokenId);
return _tokenApprovals[tokenId];
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/
function transferFrom(address from, address to, uint256 tokenId) public virtual override {
//solhint-disable-next-line max-line-length
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
_transfer(from, to, tokenId);
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
_safeTransfer(from, to, tokenId, data);
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* `data` is additional data, it has no specified format and it is sent in call to `to`.
*
* This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
* implement alternative mechanisms to perform token transfer, such as signature-based.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual {
_transfer(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer");
}
/**
* @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
*/
function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
return _owners[tokenId];
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted (`_mint`),
* and stop existing when they are burned (`_burn`).
*/
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _ownerOf(tokenId) != address(0);
}
/**
* @dev Returns whether `spender` is allowed to manage `tokenId`.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
address owner = ERC721.ownerOf(tokenId);
return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
}
/**
* @dev Safely mints `tokenId` and transfers it to `to`.
*
* Requirements:
*
* - `tokenId` must not exist.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeMint(address to, uint256 tokenId) internal virtual {
_safeMint(to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
/**
* @dev Mints `tokenId` and transfers it to `to`.
*
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
*
* Requirements:
*
* - `tokenId` must not exist.
* - `to` cannot be the zero address.
*
* Emits a {Transfer} event.
*/
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId, 1);
// Check that tokenId was not minted by `_beforeTokenTransfer` hook
require(!_exists(tokenId), "ERC721: token already minted");
unchecked {
// Will not overflow unless all 2**256 token ids are minted to the same owner.
// Given that tokens are minted one by one, it is impossible in practice that
// this ever happens. Might change if we allow batch minting.
// The ERC fails to describe this case.
_balances[to] += 1;
}
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
_afterTokenTransfer(address(0), to, tokenId, 1);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
* This is an internal function that does not check if the sender is authorized to operate on the token.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId) internal virtual {
address owner = ERC721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId, 1);
// Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook
owner = ERC721.ownerOf(tokenId);
// Clear approvals
delete _tokenApprovals[tokenId];
unchecked {
// Cannot overflow, as that would require more tokens to be burned/transferred
// out than the owner initially received through minting and transferring in.
_balances[owner] -= 1;
}
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
_afterTokenTransfer(owner, address(0), tokenId, 1);
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/
function _transfer(address from, address to, uint256 tokenId) internal virtual {
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId, 1);
// Check that tokenId was not transferred by `_beforeTokenTransfer` hook
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
// Clear approvals from the previous owner
delete _tokenApprovals[tokenId];
unchecked {
// `_balances[from]` cannot overflow for the same reason as described in `_burn`:
// `from`'s balance is the number of token held, which is at least one before the current
// transfer.
// `_balances[to]` could overflow in the conditions described in `_mint`. That would require
// all 2**256 token ids to be minted, which in practice is impossible.
_balances[from] -= 1;
_balances[to] += 1;
}
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
_afterTokenTransfer(from, to, tokenId, 1);
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* Emits an {Approval} event.
*/
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits an {ApprovalForAll} event.
*/
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
require(owner != operator, "ERC721: approve to caller");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Reverts if the `tokenId` has not been minted yet.
*/
function _requireMinted(uint256 tokenId) internal view virtual {
require(_exists(tokenId), "ERC721: invalid token ID");
}
/**
* @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
* The call is not executed if the target address is not a contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param data bytes optional data to send along with the call
* @return bool whether the call correctly returned the expected magic value
*/
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory data
) private returns (bool) {
if (to.isContract()) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
/**
* @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is
* used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`.
* - When `from` is zero, the tokens will be minted for `to`.
* - When `to` is zero, ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
* - `batchSize` is non-zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {}
/**
* @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is
* used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`.
* - When `from` is zero, the tokens were minted for `to`.
* - When `to` is zero, ``from``'s tokens were burned.
* - `from` and `to` are never both zero.
* - `batchSize` is non-zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {}
/**
* @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
*
* WARNING: Anyone calling this MUST ensure that the balances remain consistent with the ownership. The invariant
* being that for any address `a` the value returned by `balanceOf(a)` must be equal to the number of tokens such
* that `ownerOf(tokenId)` is `a`.
*/
// solhint-disable-next-line func-name-mixedcase
function __unsafe_increaseBalance(address account, uint256 amount) internal {
_balances[account] += amount;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)
pragma solidity ^0.8.0;
import "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Enumerable is IERC721 {
/**
* @dev Returns the total amount of tokens stored by the contract.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/
function tokenByIndex(uint256 index) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 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 v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;
import "./ecc/EllipticCurve.sol";
/**
* @title Verifiable Random Functions (VRF)
* @notice Library verifying VRF proofs using the `Secp256k1` curve and the `SHA256` hash function.
* @dev This library follows the algorithms described in [VRF-draft-10](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-10) and [RFC6979](https://tools.ietf.org/html/rfc6979).
* It supports the _SECP256K1_SHA256_TAI_ cipher suite, i.e. the aforementioned algorithms using `SHA256` and the `Secp256k1` curve.
* @author Witnet Foundation / Kenshi
*/
library VRF {
/**
* Secp256k1 parameters
*/
// Generator coordinate `x` of the EC curve
uint256 public constant GX =
0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798;
// Generator coordinate `y` of the EC curve
uint256 public constant GY =
0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8;
// Constant `a` of EC equation
uint256 public constant AA = 0;
// Constant `b` of EC equation
uint256 public constant BB = 7;
// Prime number of the curve
uint256 public constant PP =
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
// Order of the curve
uint256 public constant NN =
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
/// @dev Public key derivation from private key.
/// Warning: this function should not be used to derive your public key as it would expose the private key.
/// @param _d The scalar
/// @param _x The coordinate x
/// @param _y The coordinate y
/// @return (qx, qy) The derived point
function derivePoint(
uint256 _d,
uint256 _x,
uint256 _y
) internal pure returns (uint256, uint256) {
return EllipticCurve.ecMul(_d, _x, _y, AA, PP);
}
/// @dev Function to derive the `y` coordinate given the `x` coordinate and the parity byte (`0x03` for odd `y` and `0x04` for even `y`).
/// @param _yByte The parity byte following the ec point compressed format
/// @param _x The coordinate `x` of the point
/// @return The coordinate `y` of the point
function deriveY(uint8 _yByte, uint256 _x) internal pure returns (uint256) {
return EllipticCurve.deriveY(_yByte, _x, AA, BB, PP);
}
/// @dev Computes the VRF hash output as result of the digest of a ciphersuite-dependent prefix
/// concatenated with the gamma point
/// @param _gammaX The x-coordinate of the gamma EC point
/// @param _gammaY The y-coordinate of the gamma EC point
/// @return The VRF hash ouput as shas256 digest
function gammaToHash(uint256 _gammaX, uint256 _gammaY)
internal
pure
returns (bytes32)
{
bytes memory c = abi.encodePacked(
// Cipher suite code (SECP256K1-SHA256-TAI is 0xFE)
uint8(0xFE),
// 0x03
uint8(0x03),
// Compressed Gamma Point
encodePoint(_gammaX, _gammaY),
uint8(0x0)
);
return sha256(c);
}
/// @dev VRF verification by providing the public key, the message and the VRF proof.
/// This function computes several elliptic curve operations which may lead to extensive gas consumption.
/// @param _publicKey The public key as an array composed of `[pubKey-x, pubKey-y]`
/// @param _proof The VRF proof as an array composed of `[gamma-x, gamma-y, c, s]`
/// @param _message The message (in bytes) used for computing the VRF
/// @return true, if VRF proof is valid
function verify(
uint256[2] memory _publicKey,
uint256[4] memory _proof,
bytes memory _message
) internal pure returns (bool) {
// Step 2: Hash to try and increment (outputs a hashed value, a finite EC point in G)
(uint256 hPointX, uint256 hPointY) = hashToTryAndIncrement(
_publicKey,
_message
);
// Step 3: U = s*B - c*Y (where B is the generator)
(uint256 uPointX, uint256 uPointY) = ecMulSubMul(
_proof[3],
GX,
GY,
_proof[2],
_publicKey[0],
_publicKey[1]
);
// Step 4: V = s*H - c*Gamma
(uint256 vPointX, uint256 vPointY) = ecMulSubMul(
_proof[3],
hPointX,
hPointY,
_proof[2],
_proof[0],
_proof[1]
);
// Step 5: derived c from hash points(...)
bytes16 derivedC = hashPoints(
hPointX,
hPointY,
_proof[0],
_proof[1],
uPointX,
uPointY,
vPointX,
vPointY
);
// Step 6: Check validity c == c'
return uint128(derivedC) == _proof[2];
}
/// @dev VRF fast verification by providing the public key, the message, the VRF proof and several intermediate elliptic curve points that enable the verification shortcut.
/// This function leverages the EVM's `ecrecover` precompile to verify elliptic curve multiplications by decreasing the security from 32 to 20 bytes.
/// Based on the original idea of Vitalik Buterin: https://ethresear.ch/t/you-can-kinda-abuse-ecrecover-to-do-ecmul-in-secp256k1-today/2384/9
/// @param _publicKey The public key as an array composed of `[pubKey-x, pubKey-y]`
/// @param _proof The VRF proof as an array composed of `[gamma-x, gamma-y, c, s]`
/// @param _message The message (in bytes) used for computing the VRF
/// @param _uPoint The `u` EC point defined as `U = s*B - c*Y`
/// @param _vComponents The components required to compute `v` as `V = s*H - c*Gamma`
/// @return true, if VRF proof is valid
function fastVerify(
uint256[2] memory _publicKey,
uint256[4] memory _proof,
bytes memory _message,
uint256[2] memory _uPoint,
uint256[4] memory _vComponents
) internal pure returns (bool) {
// Step 2: Hash to try and increment -> hashed value, a finite EC point in G
(uint256 hPointX, uint256 hPointY) = hashToTryAndIncrement(
_publicKey,
_message
);
// Step 3 & Step 4:
// U = s*B - c*Y (where B is the generator)
// V = s*H - c*Gamma
if (
!ecMulSubMulVerify(
_proof[3],
_proof[2],
_publicKey[0],
_publicKey[1],
_uPoint[0],
_uPoint[1]
) ||
!ecMulVerify(
_proof[3],
hPointX,
hPointY,
_vComponents[0],
_vComponents[1]
) ||
!ecMulVerify(
_proof[2],
_proof[0],
_proof[1],
_vComponents[2],
_vComponents[3]
)
) {
return false;
}
(uint256 vPointX, uint256 vPointY) = EllipticCurve.ecSub(
_vComponents[0],
_vComponents[1],
_vComponents[2],
_vComponents[3],
AA,
PP
);
// Step 5: derived c from hash points(...)
bytes16 derivedC = hashPoints(
hPointX,
hPointY,
_proof[0],
_proof[1],
_uPoint[0],
_uPoint[1],
vPointX,
vPointY
);
// Step 6: Check validity c == c'
return uint128(derivedC) == _proof[2];
}
/// @dev Decode VRF proof from bytes
/// @param _proof The VRF proof as bytes
/// @return The VRF proof as an array composed of `[gamma-x, gamma-y, c, s]`
function decodeProof(bytes memory _proof)
internal
pure
returns (uint256[4] memory)
{
require(_proof.length == 81, "Malformed VRF proof");
uint8 gammaSign;
uint256 gammaX;
uint128 c;
uint256 s;
assembly {
gammaSign := mload(add(_proof, 1))
gammaX := mload(add(_proof, 33))
c := mload(add(_proof, 49))
s := mload(add(_proof, 81))
}
uint256 gammaY = deriveY(gammaSign, gammaX);
return [gammaX, gammaY, c, s];
}
/// @dev Decode EC point from bytes
/// @param _point The EC point as bytes
/// @return The point as `[point-x, point-y]`
function decodePoint(bytes memory _point)
internal
pure
returns (uint256[2] memory)
{
require(_point.length == 33, "Malformed compressed EC point");
uint8 sign;
uint256 x;
assembly {
sign := mload(add(_point, 1))
x := mload(add(_point, 33))
}
uint256 y = deriveY(sign, x);
return [x, y];
}
/// @dev Compute the parameters (EC points) required for the VRF fast verification function.
/// @param _publicKey The public key as an array composed of `[pubKey-x, pubKey-y]`
/// @param _proof The VRF proof as an array composed of `[gamma-x, gamma-y, c, s]`
/// @param _message The message (in bytes) used for computing the VRF
/// @return The fast verify required parameters as the tuple `([uPointX, uPointY], [sHX, sHY, cGammaX, cGammaY])`
function computeFastVerifyParams(
uint256[2] memory _publicKey,
uint256[4] memory _proof,
bytes memory _message
) internal pure returns (uint256[2] memory, uint256[4] memory) {
// Requirements for Step 3: U = s*B - c*Y (where B is the generator)
(uint256 hPointX, uint256 hPointY) = hashToTryAndIncrement(
_publicKey,
_message
);
(uint256 uPointX, uint256 uPointY) = ecMulSubMul(
_proof[3],
GX,
GY,
_proof[2],
_publicKey[0],
_publicKey[1]
);
// Requirements for Step 4: V = s*H - c*Gamma
(uint256 sHX, uint256 sHY) = derivePoint(_proof[3], hPointX, hPointY);
(uint256 cGammaX, uint256 cGammaY) = derivePoint(
_proof[2],
_proof[0],
_proof[1]
);
return ([uPointX, uPointY], [sHX, sHY, cGammaX, cGammaY]);
}
/// @dev Function to convert a `Hash(PK|DATA)` to a point in the curve as defined in [VRF-draft-04](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-04).
/// Used in Step 2 of VRF verification function.
/// @param _publicKey The public key as an array composed of `[pubKey-x, pubKey-y]`
/// @param _message The message used for computing the VRF
/// @return The hash point in affine cooridnates
function hashToTryAndIncrement(
uint256[2] memory _publicKey,
bytes memory _message
) internal pure returns (uint256, uint256) {
// Step 1: public key to bytes
// Step 2: V = cipher_suite | 0x01 | public_key_bytes | message | ctr | 0x0
bytes memory c = abi.encodePacked(
// Cipher suite code (SECP256K1-SHA256-TAI is 0xFE)
uint8(254),
// 0x01
uint8(1),
// Public Key
encodePoint(_publicKey[0], _publicKey[1]),
// Message
_message
);
// Step 3: find a valid EC point
// Loop over counter ctr starting at 0x00 and do hash
for (uint8 ctr = 0; ctr < 256; ctr++) {
// Counter update
// c[cLength-1] = byte(ctr);
bytes32 sha = sha256(abi.encodePacked(c, ctr, uint8(0)));
// Step 4: arbitraty string to point and check if it is on curve
uint256 hPointX = uint256(sha);
uint256 hPointY = deriveY(2, hPointX);
if (EllipticCurve.isOnCurve(hPointX, hPointY, AA, BB, PP)) {
// Step 5 (omitted): calculate H (cofactor is 1 on secp256k1)
// If H is not "INVALID" and cofactor > 1, set H = cofactor * H
return (hPointX, hPointY);
}
}
revert("No valid point was found");
}
/// @dev Function to hash a certain set of points as specified in [VRF-draft-04](https://tools.ietf.org/pdf/draft-irtf-cfrg-vrf-04).
/// Used in Step 5 of VRF verification function.
/// @param _hPointX The coordinate `x` of point `H`
/// @param _hPointY The coordinate `y` of point `H`
/// @param _gammaX The coordinate `x` of the point `Gamma`
/// @param _gammaX The coordinate `y` of the point `Gamma`
/// @param _uPointX The coordinate `x` of point `U`
/// @param _uPointY The coordinate `y` of point `U`
/// @param _vPointX The coordinate `x` of point `V`
/// @param _vPointY The coordinate `y` of point `V`
/// @return The first half of the digest of the points using SHA256
function hashPoints(
uint256 _hPointX,
uint256 _hPointY,
uint256 _gammaX,
uint256 _gammaY,
uint256 _uPointX,
uint256 _uPointY,
uint256 _vPointX,
uint256 _vPointY
) internal pure returns (bytes16) {
bytes memory c = abi.encodePacked(
// Ciphersuite 0xFE
uint8(254),
// Prefix 0x02
uint8(2),
// Points to Bytes
encodePoint(_hPointX, _hPointY),
encodePoint(_gammaX, _gammaY),
encodePoint(_uPointX, _uPointY),
encodePoint(_vPointX, _vPointY),
uint8(0)
);
// Hash bytes and truncate
bytes32 sha = sha256(c);
bytes16 half1;
assembly {
let freemem_pointer := mload(0x40)
mstore(add(freemem_pointer, 0x00), sha)
half1 := mload(add(freemem_pointer, 0x00))
}
return half1;
}
/// @dev Encode an EC point to bytes
/// @param _x The coordinate `x` of the point
/// @param _y The coordinate `y` of the point
/// @return The point coordinates as bytes
function encodePoint(uint256 _x, uint256 _y)
internal
pure
returns (bytes memory)
{
uint8 prefix = uint8(2 + (_y % 2));
return abi.encodePacked(prefix, _x);
}
/// @dev Substracts two key derivation functionsas `s1*A - s2*B`.
/// @param _scalar1 The scalar `s1`
/// @param _a1 The `x` coordinate of point `A`
/// @param _a2 The `y` coordinate of point `A`
/// @param _scalar2 The scalar `s2`
/// @param _b1 The `x` coordinate of point `B`
/// @param _b2 The `y` coordinate of point `B`
/// @return The derived point in affine cooridnates
function ecMulSubMul(
uint256 _scalar1,
uint256 _a1,
uint256 _a2,
uint256 _scalar2,
uint256 _b1,
uint256 _b2
) internal pure returns (uint256, uint256) {
(uint256 m1, uint256 m2) = derivePoint(_scalar1, _a1, _a2);
(uint256 n1, uint256 n2) = derivePoint(_scalar2, _b1, _b2);
(uint256 r1, uint256 r2) = EllipticCurve.ecSub(m1, m2, n1, n2, AA, PP);
return (r1, r2);
}
/// @dev Verify an Elliptic Curve multiplication of the form `(qx,qy) = scalar*(x,y)` by using the precompiled `ecrecover` function.
/// The usage of the precompiled `ecrecover` function decreases the security from 32 to 20 bytes.
/// Based on the original idea of Vitalik Buterin: https://ethresear.ch/t/you-can-kinda-abuse-ecrecover-to-do-ecmul-in-secp256k1-today/2384/9
/// @param _scalar The scalar of the point multiplication
/// @param _x The coordinate `x` of the point
/// @param _y The coordinate `y` of the point
/// @param _qx The coordinate `x` of the multiplication result
/// @param _qy The coordinate `y` of the multiplication result
/// @return true, if first 20 bytes match
function ecMulVerify(
uint256 _scalar,
uint256 _x,
uint256 _y,
uint256 _qx,
uint256 _qy
) internal pure returns (bool) {
address result = ecrecover(
0,
_y % 2 != 0 ? 28 : 27,
bytes32(_x),
bytes32(mulmod(_scalar, _x, NN))
);
return pointToAddress(_qx, _qy) == result;
}
/// @dev Verify an Elliptic Curve operation of the form `Q = scalar1*(gx,gy) - scalar2*(x,y)` by using the precompiled `ecrecover` function, where `(gx,gy)` is the generator of the EC.
/// The usage of the precompiled `ecrecover` function decreases the security from 32 to 20 bytes.
/// Based on SolCrypto library: https://github.com/HarryR/solcrypto
/// @param _scalar1 The scalar of the multiplication of `(gx,gy)`
/// @param _scalar2 The scalar of the multiplication of `(x,y)`
/// @param _x The coordinate `x` of the point to be mutiply by `scalar2`
/// @param _y The coordinate `y` of the point to be mutiply by `scalar2`
/// @param _qx The coordinate `x` of the equation result
/// @param _qy The coordinate `y` of the equation result
/// @return true, if first 20 bytes match
function ecMulSubMulVerify(
uint256 _scalar1,
uint256 _scalar2,
uint256 _x,
uint256 _y,
uint256 _qx,
uint256 _qy
) internal pure returns (bool) {
uint256 scalar1 = (NN - _scalar1) % NN;
scalar1 = mulmod(scalar1, _x, NN);
uint256 scalar2 = (NN - _scalar2) % NN;
address result = ecrecover(
bytes32(scalar1),
_y % 2 != 0 ? 28 : 27,
bytes32(_x),
bytes32(mulmod(scalar2, _x, NN))
);
return pointToAddress(_qx, _qy) == result;
}
/// @dev Gets the address corresponding to the EC point digest (keccak256), i.e. the first 20 bytes of the digest.
/// This function is used for performing a fast EC multiplication verification.
/// @param _x The coordinate `x` of the point
/// @param _y The coordinate `y` of the point
/// @return The address of the EC point digest (keccak256)
function pointToAddress(uint256 _x, uint256 _y)
internal
pure
returns (address)
{
return
address(
uint160(
uint256(keccak256(abi.encodePacked(_x, _y))) &
0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
)
);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;
/**
* @title Elliptic Curve Library
* @dev Library providing arithmetic operations over elliptic curves.
* This library does not check whether the inserted points belong to the curve
* `isOnCurve` function should be used by the library user to check the aforementioned statement.
* @author Witnet Foundation
*/
library EllipticCurve {
// Pre-computed constant for 2 ** 255
uint256 private constant U255_MAX_PLUS_1 =
57896044618658097711785492504343953926634992332820282019728792003956564819968;
/// @dev Modular euclidean inverse of a number (mod p).
/// @param _x The number
/// @param _pp The modulus
/// @return q such that x*q = 1 (mod _pp)
function invMod(uint256 _x, uint256 _pp) internal pure returns (uint256) {
require(_x != 0 && _x != _pp && _pp != 0, "Invalid number");
uint256 q = 0;
uint256 newT = 1;
uint256 r = _pp;
uint256 t;
while (_x != 0) {
t = r / _x;
(q, newT) = (newT, addmod(q, (_pp - mulmod(t, newT, _pp)), _pp));
(r, _x) = (_x, r - t * _x);
}
return q;
}
/// @dev Modular exponentiation, b^e % _pp.
/// Source: https://github.com/androlo/standard-contracts/blob/master/contracts/src/crypto/ECCMath.sol
/// @param _base base
/// @param _exp exponent
/// @param _pp modulus
/// @return r such that r = b**e (mod _pp)
function expMod(
uint256 _base,
uint256 _exp,
uint256 _pp
) internal pure returns (uint256) {
require(_pp != 0, "Modulus is zero");
if (_base == 0) return 0;
if (_exp == 0) return 1;
uint256 r = 1;
uint256 bit = U255_MAX_PLUS_1;
assembly {
for {
} gt(bit, 0) {
} {
r := mulmod(
mulmod(r, r, _pp),
exp(_base, iszero(iszero(and(_exp, bit)))),
_pp
)
r := mulmod(
mulmod(r, r, _pp),
exp(_base, iszero(iszero(and(_exp, div(bit, 2))))),
_pp
)
r := mulmod(
mulmod(r, r, _pp),
exp(_base, iszero(iszero(and(_exp, div(bit, 4))))),
_pp
)
r := mulmod(
mulmod(r, r, _pp),
exp(_base, iszero(iszero(and(_exp, div(bit, 8))))),
_pp
)
bit := div(bit, 16)
}
}
return r;
}
/// @dev Converts a point (x, y, z) expressed in Jacobian coordinates to affine coordinates (x', y', 1).
/// @param _x coordinate x
/// @param _y coordinate y
/// @param _z coordinate z
/// @param _pp the modulus
/// @return (x', y') affine coordinates
function toAffine(
uint256 _x,
uint256 _y,
uint256 _z,
uint256 _pp
) internal pure returns (uint256, uint256) {
uint256 zInv = invMod(_z, _pp);
uint256 zInv2 = mulmod(zInv, zInv, _pp);
uint256 x2 = mulmod(_x, zInv2, _pp);
uint256 y2 = mulmod(_y, mulmod(zInv, zInv2, _pp), _pp);
return (x2, y2);
}
/// @dev Derives the y coordinate from a compressed-format point x [[SEC-1]](https://www.secg.org/SEC1-Ver-1.0.pdf).
/// @param _prefix parity byte (0x02 even, 0x03 odd)
/// @param _x coordinate x
/// @param _aa constant of curve
/// @param _bb constant of curve
/// @param _pp the modulus
/// @return y coordinate y
function deriveY(
uint8 _prefix,
uint256 _x,
uint256 _aa,
uint256 _bb,
uint256 _pp
) internal pure returns (uint256) {
require(
_prefix == 0x02 || _prefix == 0x03,
"Invalid compressed EC point prefix"
);
// x^3 + ax + b
uint256 y2 = addmod(
mulmod(_x, mulmod(_x, _x, _pp), _pp),
addmod(mulmod(_x, _aa, _pp), _bb, _pp),
_pp
);
y2 = expMod(y2, (_pp + 1) / 4, _pp);
// uint256 cmp = yBit ^ y_ & 1;
uint256 y = (y2 + _prefix) % 2 == 0 ? y2 : _pp - y2;
return y;
}
/// @dev Check whether point (x,y) is on curve defined by a, b, and _pp.
/// @param _x coordinate x of P1
/// @param _y coordinate y of P1
/// @param _aa constant of curve
/// @param _bb constant of curve
/// @param _pp the modulus
/// @return true if x,y in the curve, false else
function isOnCurve(
uint256 _x,
uint256 _y,
uint256 _aa,
uint256 _bb,
uint256 _pp
) internal pure returns (bool) {
if (0 == _x || _x >= _pp || 0 == _y || _y >= _pp) {
return false;
}
// y^2
uint256 lhs = mulmod(_y, _y, _pp);
// x^3
uint256 rhs = mulmod(mulmod(_x, _x, _pp), _x, _pp);
if (_aa != 0) {
// x^3 + a*x
rhs = addmod(rhs, mulmod(_x, _aa, _pp), _pp);
}
if (_bb != 0) {
// x^3 + a*x + b
rhs = addmod(rhs, _bb, _pp);
}
return lhs == rhs;
}
/// @dev Calculate inverse (x, -y) of point (x, y).
/// @param _x coordinate x of P1
/// @param _y coordinate y of P1
/// @param _pp the modulus
/// @return (x, -y)
function ecInv(
uint256 _x,
uint256 _y,
uint256 _pp
) internal pure returns (uint256, uint256) {
return (_x, (_pp - _y) % _pp);
}
/// @dev Add two points (x1, y1) and (x2, y2) in affine coordinates.
/// @param _x1 coordinate x of P1
/// @param _y1 coordinate y of P1
/// @param _x2 coordinate x of P2
/// @param _y2 coordinate y of P2
/// @param _aa constant of the curve
/// @param _pp the modulus
/// @return (qx, qy) = P1+P2 in affine coordinates
function ecAdd(
uint256 _x1,
uint256 _y1,
uint256 _x2,
uint256 _y2,
uint256 _aa,
uint256 _pp
) internal pure returns (uint256, uint256) {
uint256 x = 0;
uint256 y = 0;
uint256 z = 0;
// Double if x1==x2 else add
if (_x1 == _x2) {
// y1 = -y2 mod p
if (addmod(_y1, _y2, _pp) == 0) {
return (0, 0);
} else {
// P1 = P2
(x, y, z) = jacDouble(_x1, _y1, 1, _aa, _pp);
}
} else {
(x, y, z) = jacAdd(_x1, _y1, 1, _x2, _y2, 1, _pp);
}
// Get back to affine
return toAffine(x, y, z, _pp);
}
/// @dev Substract two points (x1, y1) and (x2, y2) in affine coordinates.
/// @param _x1 coordinate x of P1
/// @param _y1 coordinate y of P1
/// @param _x2 coordinate x of P2
/// @param _y2 coordinate y of P2
/// @param _aa constant of the curve
/// @param _pp the modulus
/// @return (qx, qy) = P1-P2 in affine coordinates
function ecSub(
uint256 _x1,
uint256 _y1,
uint256 _x2,
uint256 _y2,
uint256 _aa,
uint256 _pp
) internal pure returns (uint256, uint256) {
// invert square
(uint256 x, uint256 y) = ecInv(_x2, _y2, _pp);
// P1-square
return ecAdd(_x1, _y1, x, y, _aa, _pp);
}
/// @dev Multiply point (x1, y1, z1) times d in affine coordinates.
/// @param _k scalar to multiply
/// @param _x coordinate x of P1
/// @param _y coordinate y of P1
/// @param _aa constant of the curve
/// @param _pp the modulus
/// @return (qx, qy) = d*P in affine coordinates
function ecMul(
uint256 _k,
uint256 _x,
uint256 _y,
uint256 _aa,
uint256 _pp
) internal pure returns (uint256, uint256) {
// Jacobian multiplication
(uint256 x1, uint256 y1, uint256 z1) = jacMul(_k, _x, _y, 1, _aa, _pp);
// Get back to affine
return toAffine(x1, y1, z1, _pp);
}
/// @dev Adds two points (x1, y1, z1) and (x2 y2, z2).
/// @param _x1 coordinate x of P1
/// @param _y1 coordinate y of P1
/// @param _z1 coordinate z of P1
/// @param _x2 coordinate x of square
/// @param _y2 coordinate y of square
/// @param _z2 coordinate z of square
/// @param _pp the modulus
/// @return (qx, qy, qz) P1+square in Jacobian
function jacAdd(
uint256 _x1,
uint256 _y1,
uint256 _z1,
uint256 _x2,
uint256 _y2,
uint256 _z2,
uint256 _pp
)
internal
pure
returns (
uint256,
uint256,
uint256
)
{
if (_x1 == 0 && _y1 == 0) return (_x2, _y2, _z2);
if (_x2 == 0 && _y2 == 0) return (_x1, _y1, _z1);
// We follow the equations described in https://pdfs.semanticscholar.org/5c64/29952e08025a9649c2b0ba32518e9a7fb5c2.pdf Section 5
uint256[4] memory zs; // z1^2, z1^3, z2^2, z2^3
zs[0] = mulmod(_z1, _z1, _pp);
zs[1] = mulmod(_z1, zs[0], _pp);
zs[2] = mulmod(_z2, _z2, _pp);
zs[3] = mulmod(_z2, zs[2], _pp);
// u1, s1, u2, s2
zs = [
mulmod(_x1, zs[2], _pp),
mulmod(_y1, zs[3], _pp),
mulmod(_x2, zs[0], _pp),
mulmod(_y2, zs[1], _pp)
];
// In case of zs[0] == zs[2] && zs[1] == zs[3], double function should be used
require(
zs[0] != zs[2] || zs[1] != zs[3],
"Use jacDouble function instead"
);
uint256[4] memory hr;
//h
hr[0] = addmod(zs[2], _pp - zs[0], _pp);
//r
hr[1] = addmod(zs[3], _pp - zs[1], _pp);
//h^2
hr[2] = mulmod(hr[0], hr[0], _pp);
// h^3
hr[3] = mulmod(hr[2], hr[0], _pp);
// qx = -h^3 -2u1h^2+r^2
uint256 qx = addmod(mulmod(hr[1], hr[1], _pp), _pp - hr[3], _pp);
qx = addmod(qx, _pp - mulmod(2, mulmod(zs[0], hr[2], _pp), _pp), _pp);
// qy = -s1*z1*h^3+r(u1*h^2 -x^3)
uint256 qy = mulmod(
hr[1],
addmod(mulmod(zs[0], hr[2], _pp), _pp - qx, _pp),
_pp
);
qy = addmod(qy, _pp - mulmod(zs[1], hr[3], _pp), _pp);
// qz = h*z1*z2
uint256 qz = mulmod(hr[0], mulmod(_z1, _z2, _pp), _pp);
return (qx, qy, qz);
}
/// @dev Doubles a points (x, y, z).
/// @param _x coordinate x of P1
/// @param _y coordinate y of P1
/// @param _z coordinate z of P1
/// @param _aa the a scalar in the curve equation
/// @param _pp the modulus
/// @return (qx, qy, qz) 2P in Jacobian
function jacDouble(
uint256 _x,
uint256 _y,
uint256 _z,
uint256 _aa,
uint256 _pp
)
internal
pure
returns (
uint256,
uint256,
uint256
)
{
if (_z == 0) return (_x, _y, _z);
// We follow the equations described in https://pdfs.semanticscholar.org/5c64/29952e08025a9649c2b0ba32518e9a7fb5c2.pdf Section 5
// Note: there is a bug in the paper regarding the m parameter, M=3*(x1^2)+a*(z1^4)
// x, y, z at this point represent the squares of _x, _y, _z
uint256 x = mulmod(_x, _x, _pp); //x1^2
uint256 y = mulmod(_y, _y, _pp); //y1^2
uint256 z = mulmod(_z, _z, _pp); //z1^2
// s
uint256 s = mulmod(4, mulmod(_x, y, _pp), _pp);
// m
uint256 m = addmod(
mulmod(3, x, _pp),
mulmod(_aa, mulmod(z, z, _pp), _pp),
_pp
);
// x, y, z at this point will be reassigned and rather represent qx, qy, qz from the paper
// This allows to reduce the gas cost and stack footprint of the algorithm
// qx
x = addmod(mulmod(m, m, _pp), _pp - addmod(s, s, _pp), _pp);
// qy = -8*y1^4 + M(S-T)
y = addmod(
mulmod(m, addmod(s, _pp - x, _pp), _pp),
_pp - mulmod(8, mulmod(y, y, _pp), _pp),
_pp
);
// qz = 2*y1*z1
z = mulmod(2, mulmod(_y, _z, _pp), _pp);
return (x, y, z);
}
/// @dev Multiply point (x, y, z) times d.
/// @param _d scalar to multiply
/// @param _x coordinate x of P1
/// @param _y coordinate y of P1
/// @param _z coordinate z of P1
/// @param _aa constant of curve
/// @param _pp the modulus
/// @return (qx, qy, qz) d*P1 in Jacobian
function jacMul(
uint256 _d,
uint256 _x,
uint256 _y,
uint256 _z,
uint256 _aa,
uint256 _pp
)
internal
pure
returns (
uint256,
uint256,
uint256
)
{
// Early return in case that `_d == 0`
if (_d == 0) {
return (_x, _y, _z);
}
uint256 remaining = _d;
uint256 qx = 0;
uint256 qy = 0;
uint256 qz = 1;
// Double and add algorithm
while (remaining != 0) {
if ((remaining & 1) != 0) {
(qx, qy, qz) = jacAdd(qx, qy, qz, _x, _y, _z, _pp);
}
remaining = remaining / 2;
(_x, _y, _z) = jacDouble(_x, _y, _z, _aa, _pp);
}
return (qx, qy, qz);
}
}{
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"bytes","name":"publicKey","type":"bytes"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","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":false,"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"RandomMintRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORACLE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"batchMintRandom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"batchSafeMintToSeller","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAvailable","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mintRandom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[4]","name":"proof","type":"uint256[4]"},{"internalType":"bytes","name":"message","type":"bytes"},{"internalType":"uint256[2]","name":"uPoint","type":"uint256[2]"},{"internalType":"uint256[4]","name":"vComponents","type":"uint256[4]"},{"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"onRandomness","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"to","type":"address"}],"name":"recoverEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeMintToSeller","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","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":"tokenId","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":"uint256","name":"price","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"seller","type":"address"}],"name":"setSeller","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":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"tokensOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","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":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6080604052670214e8348c4f0000600e556000600f5560006010553480156200002757600080fd5b50604051620094633803806200946383398181016040528101906200004d919062000571565b6040518060400160405280600681526020017f4b6174616e6100000000000000000000000000000000000000000000000000008152506040518060400160405280600381526020017f4b415400000000000000000000000000000000000000000000000000000000008152508160009081620000ca91906200080d565b508060019081620000dc91906200080d565b505050620000f46000801b336200026b60201b60201c565b620001267f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6336200026b60201b60201c565b33601160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040516200017590620003d0565b604051809103906000f08015801562000192573d6000803e3d6000fd5b50600d60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a91d58b4826040518263ffffffff1660e01b815260040162000230919062000951565b600060405180830381600087803b1580156200024b57600080fd5b505af115801562000260573d6000803e3d6000fd5b505050505062000975565b6200027d82826200035d60201b60201c565b62000359576001600a600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550620002fe620003c860201b60201c565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000600a600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b600033905090565b6134718062005ff283390190565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6200044782620003fc565b810181811067ffffffffffffffff821117156200046957620004686200040d565b5b80604052505050565b60006200047e620003de565b90506200048c82826200043c565b919050565b600067ffffffffffffffff821115620004af57620004ae6200040d565b5b620004ba82620003fc565b9050602081019050919050565b60005b83811015620004e7578082015181840152602081019050620004ca565b60008484015250505050565b60006200050a620005048462000491565b62000472565b905082815260208101848484011115620005295762000528620003f7565b5b62000536848285620004c7565b509392505050565b600082601f830112620005565762000555620003f2565b5b815162000568848260208601620004f3565b91505092915050565b6000602082840312156200058a5762000589620003e8565b5b600082015167ffffffffffffffff811115620005ab57620005aa620003ed565b5b620005b9848285016200053e565b91505092915050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200061557607f821691505b6020821081036200062b576200062a620005cd565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620006957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000656565b620006a1868362000656565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620006ee620006e8620006e284620006b9565b620006c3565b620006b9565b9050919050565b6000819050919050565b6200070a83620006cd565b620007226200071982620006f5565b84845462000663565b825550505050565b600090565b620007396200072a565b62000746818484620006ff565b505050565b5b818110156200076e57620007626000826200072f565b6001810190506200074c565b5050565b601f821115620007bd57620007878162000631565b620007928462000646565b81016020851015620007a2578190505b620007ba620007b18562000646565b8301826200074b565b50505b505050565b600082821c905092915050565b6000620007e260001984600802620007c2565b1980831691505092915050565b6000620007fd8383620007cf565b9150826002028217905092915050565b6200081882620005c2565b67ffffffffffffffff8111156200083457620008336200040d565b5b620008408254620005fc565b6200084d82828562000772565b600060209050601f83116001811462000885576000841562000870578287015190505b6200087c8582620007ef565b865550620008ec565b601f198416620008958662000631565b60005b82811015620008bf5784890151825560018201915060208501945060208101905062000898565b86831015620008df5784890151620008db601f891682620007cf565b8355505b6001600288020188555050505b505050505050565b600081519050919050565b600082825260208201905092915050565b60006200091d82620008f4565b620009298185620008ff565b93506200093b818560208601620004c7565b6200094681620003fc565b840191505092915050565b600060208201905081810360008301526200096d818462000910565b905092915050565b61566d80620009856000396000f3fe6080604052600436106102195760003560e01c80637e5c8b7f11610123578063a22cb465116100ab578063d547741f1161006f578063d547741f146107fa578063e985e9c514610823578063e99d286614610860578063f89ab3b014610889578063f9cc0605146108b257610219565b8063a22cb46514610724578063b88d4fde1461074d578063c87b56dd14610776578063d1cea4ec146107b3578063d5391393146107cf57610219565b806391d14854116100f257806391d148541461063d57806395d89b411461067a57806398d5fdca146106a5578063a1448194146106d0578063a217fddf146106f957610219565b80637e5c8b7f146105925780638271e707146105bb5780638462151c146105d757806391b7f5ed1461061457610219565b8063248a9ca3116101a657806342842e0e1161017557806342842e0e146104895780634f6ccce7146104b25780636352211e146104ef57806370a082311461052c5780637504db3e1461056957610219565b8063248a9ca3146103bd5780632f2ff15d146103fa5780632f745c591461042357806336568abe1461046057610219565b8063081812fc116101ed578063081812fc146102da578063095ea7b3146103175780631171bda91461034057806318160ddd1461036957806323b872dd1461039457610219565b80627119d11461021e57806301ffc9a71461024757806306fdde031461028457806307e2cea5146102af575b600080fd5b34801561022a57600080fd5b5061024560048036038101906102409190613ab4565b6108dd565b005b34801561025357600080fd5b5061026e60048036038101906102699190613ba5565b610c91565b60405161027b9190613bed565b60405180910390f35b34801561029057600080fd5b50610299610ca3565b6040516102a69190613c87565b60405180910390f35b3480156102bb57600080fd5b506102c4610d35565b6040516102d19190613cc2565b60405180910390f35b3480156102e657600080fd5b5061030160048036038101906102fc9190613cdd565b610d59565b60405161030e9190613d4b565b60405180910390f35b34801561032357600080fd5b5061033e60048036038101906103399190613d92565b610d9f565b005b34801561034c57600080fd5b5061036760048036038101906103629190613dd2565b610eb6565b005b34801561037557600080fd5b5061037e610ef4565b60405161038b9190613e34565b60405180910390f35b3480156103a057600080fd5b506103bb60048036038101906103b69190613dd2565b610f01565b005b3480156103c957600080fd5b506103e460048036038101906103df9190613e7b565b610f61565b6040516103f19190613cc2565b60405180910390f35b34801561040657600080fd5b50610421600480360381019061041c9190613ea8565b610f81565b005b34801561042f57600080fd5b5061044a60048036038101906104459190613d92565b610fa2565b6040516104579190613e34565b60405180910390f35b34801561046c57600080fd5b5061048760048036038101906104829190613ea8565b611047565b005b34801561049557600080fd5b506104b060048036038101906104ab9190613dd2565b6110ca565b005b3480156104be57600080fd5b506104d960048036038101906104d49190613cdd565b6110ea565b6040516104e69190613e34565b60405180910390f35b3480156104fb57600080fd5b5061051660048036038101906105119190613cdd565b61115b565b6040516105239190613d4b565b60405180910390f35b34801561053857600080fd5b50610553600480360381019061054e9190613ee8565b6111e1565b6040516105609190613e34565b60405180910390f35b34801561057557600080fd5b50610590600480360381019061058b9190613f53565b611298565b005b34801561059e57600080fd5b506105b960048036038101906105b49190613f80565b611356565b005b6105d560048036038101906105d09190613d92565b6113b8565b005b3480156105e357600080fd5b506105fe60048036038101906105f99190613ee8565b61157f565b60405161060b919061407e565b60405180910390f35b34801561062057600080fd5b5061063b60048036038101906106369190613cdd565b61162d565b005b34801561064957600080fd5b50610664600480360381019061065f9190613ea8565b611645565b6040516106719190613bed565b60405180910390f35b34801561068657600080fd5b5061068f6116b0565b60405161069c9190613c87565b60405180910390f35b3480156106b157600080fd5b506106ba611742565b6040516106c79190613e34565b60405180910390f35b3480156106dc57600080fd5b506106f760048036038101906106f29190613d92565b61174c565b005b34801561070557600080fd5b5061070e611785565b60405161071b9190613cc2565b60405180910390f35b34801561073057600080fd5b5061074b600480360381019061074691906140cc565b61178c565b005b34801561075957600080fd5b50610774600480360381019061076f919061410c565b6117a2565b005b34801561078257600080fd5b5061079d60048036038101906107989190613cdd565b611804565b6040516107aa9190613c87565b60405180910390f35b6107cd60048036038101906107c89190613ee8565b61186c565b005b3480156107db57600080fd5b506107e46119ba565b6040516107f19190613cc2565b60405180910390f35b34801561080657600080fd5b50610821600480360381019061081c9190613ea8565b6119de565b005b34801561082f57600080fd5b5061084a6004803603810190610845919061418f565b6119ff565b6040516108579190613bed565b60405180910390f35b34801561086c57600080fd5b5061088760048036038101906108829190613ee8565b611a93565b005b34801561089557600080fd5b506108b060048036038101906108ab9190613cdd565b611ae5565b005b3480156108be57600080fd5b506108c7611b68565b6040516108d4919061407e565b60405180910390f35b7f68e79a7bf1e0bc45d0a330c573bc367f9cf464fd326078812f301165fbda4ef161090781611bc0565b600b600083815260200190815260200160002060009054906101000a900460ff1615610968576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161095f9061421b565b60405180910390fd5b6000600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c32a82ea888888886040518563ffffffff1660e01b81526004016109cb9493929190614398565b602060405180830381865afa1580156109e8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0c91906143fa565b905080610a4e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a4590614499565b60405180910390fd5b6000600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635f09834189600060048110610aa257610aa16144b9565b5b60200201518a600160048110610abb57610aba6144b9565b5b60200201516040518363ffffffff1660e01b8152600401610add9291906144e8565b602060405180830381865afa158015610afa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b1e9190614526565b905060008160001c90506001600b600087815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600c600087815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600f6000815480929190610b9f90614582565b9190505550600060128054905083610bb791906145da565b9050600060128281548110610bcf57610bce6144b9565b5b9060005260206000200154905060126001601280549050610bf0919061460b565b81548110610c0157610c006144b9565b5b906000526020600020015460128381548110610c2057610c1f6144b9565b5b90600052602060002001819055506012805480610c4057610c3f61463f565b5b60019003818190600052602060002001600090559055610c83601160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1684836110ca565b505050505050505050505050565b6000610c9c82611bd4565b9050919050565b606060008054610cb29061469d565b80601f0160208091040260200160405190810160405280929190818152602001828054610cde9061469d565b8015610d2b5780601f10610d0057610100808354040283529160200191610d2b565b820191906000526020600020905b815481529060010190602001808311610d0e57829003601f168201915b5050505050905090565b7f68e79a7bf1e0bc45d0a330c573bc367f9cf464fd326078812f301165fbda4ef181565b6000610d6482611c4e565b6004600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6000610daa8261115b565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610e1a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e1190614740565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16610e39611c99565b73ffffffffffffffffffffffffffffffffffffffff161480610e685750610e6781610e62611c99565b6119ff565b5b610ea7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e9e906147d2565b60405180910390fd5b610eb18383611ca1565b505050565b6000801b610ec381611bc0565b610eee83838673ffffffffffffffffffffffffffffffffffffffff16611d5a9092919063ffffffff16565b50505050565b6000600880549050905090565b610f12610f0c611c99565b82611de0565b610f51576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f4890614864565b60405180910390fd5b610f5c838383611e75565b505050565b6000600a6000838152602001908152602001600020600101549050919050565b610f8a82610f61565b610f9381611bc0565b610f9d838361216e565b505050565b6000610fad836111e1565b8210610fee576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe5906148f6565b60405180910390fd5b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002054905092915050565b61104f611c99565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146110bc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110b390614988565b60405180910390fd5b6110c6828261224f565b5050565b6110e5838383604051806020016040528060008152506117a2565b505050565b60006110f4610ef4565b8210611135576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161112c90614a1a565b60405180910390fd5b60088281548110611149576111486144b9565b5b90600052602060002001549050919050565b60008061116783612331565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036111d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111cf90614a86565b60405180910390fd5b80915050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611251576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161124890614b18565b60405180910390fd5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000801b6112a581611bc0565b60008273ffffffffffffffffffffffffffffffffffffffff16476040516112cb90614b69565b60006040518083038185875af1925050503d8060008114611308576040519150601f19603f3d011682016040523d82523d6000602084013e61130d565b606091505b5050905080611351576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161134890614bca565b60405180910390fd5b505050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a661138081611bc0565b60005b828110156113b25761139f848261139a9190614bea565b611ae5565b80806113aa90614c1e565b915050611383565b50505050565b600081116113fb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113f290614cb2565b60405180910390fd5b80600e546114099190614cd2565b34101561144b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161144290614d86565b60405180910390fd5b80600f546114599190614bea565b6012805490501161149f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161149690614df2565b60405180910390fd5b60005b8181101561157a576000601060008154809291906114bf90614c1e565b919050559050600f60008154809291906114d890614c1e565b919050555083600c600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f360f498aa1f3d1dd6165e739ca66c0856a6adbe07c8908b10b9e28375005c7dc8160405161155e9190613e34565b60405180910390a150808061157290614c1e565b9150506114a2565b505050565b6060600061158c836111e1565b905060008167ffffffffffffffff8111156115aa576115a96137e7565b5b6040519080825280602002602001820160405280156115d85781602001602082028036833780820191505090505b50905060005b82811015611622576115f08582610fa2565b828281518110611603576116026144b9565b5b602002602001018181525050808061161a90614c1e565b9150506115de565b508092505050919050565b6000801b61163a81611bc0565b81600e819055505050565b6000600a600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6060600180546116bf9061469d565b80601f01602080910402602001604051908101604052809291908181526020018280546116eb9061469d565b80156117385780601f1061170d57610100808354040283529160200191611738565b820191906000526020600020905b81548152906001019060200180831161171b57829003601f168201915b5050505050905090565b6000600e54905090565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a661177681611bc0565b611780838361236e565b505050565b6000801b81565b61179e611797611c99565b838361238c565b5050565b6117b36117ad611c99565b83611de0565b6117f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117e990614864565b60405180910390fd5b6117fe848484846124f8565b50505050565b606061180f82611c4e565b6000611819612554565b905060008151116118395760405180602001604052806000815250611864565b8061184384612591565b604051602001611854929190614e4e565b6040516020818303038152906040525b915050919050565b600e543410156118b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118a890614d86565b60405180910390fd5b600f54601280549050116118fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118f190614ebe565b60405180910390fd5b60006010600081548092919061190f90614c1e565b919050559050600f600081548092919061192890614c1e565b919050555081600c600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f360f498aa1f3d1dd6165e739ca66c0856a6adbe07c8908b10b9e28375005c7dc816040516119ae9190613e34565b60405180910390a15050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6119e782610f61565b6119f081611bc0565b6119fa838361224f565b505050565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6000801b611aa081611bc0565b81601160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6611b0f81611bc0565b611b3b601160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168361236e565b60128290806001815401808255809150506001900390600052602060002001600090919091909150555050565b60606012805480602002602001604051908101604052809291908181526020018280548015611bb657602002820191906000526020600020905b815481526020019060010190808311611ba2575b5050505050905090565b611bd181611bcc611c99565b61265f565b50565b60007f7965db0b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480611c475750611c46826126e4565b5b9050919050565b611c578161275e565b611c96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c8d90614a86565b60405180910390fd5b50565b600033905090565b816004600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff16611d148361115b565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b611ddb8363a9059cbb60e01b8484604051602401611d79929190614ede565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061279f565b505050565b600080611dec8361115b565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480611e2e5750611e2d81856119ff565b5b80611e6c57508373ffffffffffffffffffffffffffffffffffffffff16611e5484610d59565b73ffffffffffffffffffffffffffffffffffffffff16145b91505092915050565b8273ffffffffffffffffffffffffffffffffffffffff16611e958261115b565b73ffffffffffffffffffffffffffffffffffffffff1614611eeb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ee290614f79565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611f5a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f519061500b565b60405180910390fd5b611f678383836001612867565b8273ffffffffffffffffffffffffffffffffffffffff16611f878261115b565b73ffffffffffffffffffffffffffffffffffffffff1614611fdd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fd490614f79565b60405180910390fd5b6004600082815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055506001600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a46121698383836001612879565b505050565b6121788282611645565b61224b576001600a600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506121f0611c99565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6122598282611645565b1561232d576000600a600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506122d2611c99565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45b5050565b60006002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b61238882826040518060200160405280600081525061287f565b5050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036123fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123f190615077565b60405180910390fd5b80600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516124eb9190613bed565b60405180910390a3505050565b612503848484611e75565b61250f848484846128da565b61254e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161254590615109565b60405180910390fd5b50505050565b60606040518060400160405280601d81526020017f68747470733a2f2f6e66742e6b656e7368692e696f2f6b6174616e612f000000815250905090565b6060600060016125a084612a61565b01905060008167ffffffffffffffff8111156125bf576125be6137e7565b5b6040519080825280601f01601f1916602001820160405280156125f15781602001600182028036833780820191505090505b509050600082602001820190505b600115612654578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8581612648576126476145ab565b5b049450600085036125ff575b819350505050919050565b6126698282611645565b6126e05761267681612bb4565b6126848360001c6020612be1565b6040516020016126959291906151c1565b6040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126d79190613c87565b60405180910390fd5b5050565b60007f780e9d63000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480612757575061275682612e1d565b5b9050919050565b60008073ffffffffffffffffffffffffffffffffffffffff1661278083612331565b73ffffffffffffffffffffffffffffffffffffffff1614159050919050565b6000612801826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612eff9092919063ffffffff16565b905060008151148061282357508080602001905181019061282291906143fa565b5b612862576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128599061526d565b60405180910390fd5b505050565b61287384848484612f17565b50505050565b50505050565b6128898383613075565b61289660008484846128da565b6128d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128cc90615109565b60405180910390fd5b505050565b60006128fb8473ffffffffffffffffffffffffffffffffffffffff16613292565b15612a54578373ffffffffffffffffffffffffffffffffffffffff1663150b7a02612924611c99565b8786866040518563ffffffff1660e01b8152600401612946949392919061528d565b6020604051808303816000875af192505050801561298257506040513d601f19601f8201168201806040525081019061297f91906152ee565b60015b612a04573d80600081146129b2576040519150601f19603f3d011682016040523d82523d6000602084013e6129b7565b606091505b5060008151036129fc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129f390615109565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614915050612a59565b600190505b949350505050565b600080600090507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612abf577a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008381612ab557612ab46145ab565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310612afc576d04ee2d6d415b85acef81000000008381612af257612af16145ab565b5b0492506020810190505b662386f26fc100008310612b2b57662386f26fc100008381612b2157612b206145ab565b5b0492506010810190505b6305f5e1008310612b54576305f5e1008381612b4a57612b496145ab565b5b0492506008810190505b6127108310612b79576127108381612b6f57612b6e6145ab565b5b0492506004810190505b60648310612b9c5760648381612b9257612b916145ab565b5b0492506002810190505b600a8310612bab576001810190505b80915050919050565b6060612bda8273ffffffffffffffffffffffffffffffffffffffff16601460ff16612be1565b9050919050565b606060006002836002612bf49190614cd2565b612bfe9190614bea565b67ffffffffffffffff811115612c1757612c166137e7565b5b6040519080825280601f01601f191660200182016040528015612c495781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612c8157612c806144b9565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612ce557612ce46144b9565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002612d259190614cd2565b612d2f9190614bea565b90505b6001811115612dcf577f3031323334353637383961626364656600000000000000000000000000000000600f861660108110612d7157612d706144b9565b5b1a60f81b828281518110612d8857612d876144b9565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c945080612dc890614582565b9050612d32565b5060008414612e13576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e0a90615367565b60405180910390fd5b8091505092915050565b60007f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480612ee857507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80612ef85750612ef7826132b5565b5b9050919050565b6060612f0e848460008561331f565b90509392505050565b612f23848484846133ec565b6001811115612f67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f5e906153f9565b60405180910390fd5b6000829050600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612fae57612fa9816133f2565b612fed565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614612fec57612feb858261343b565b5b5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361302f5761302a816135a8565b61306e565b8473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161461306d5761306c8482613679565b5b5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036130e4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130db90615465565b60405180910390fd5b6130ed8161275e565b1561312d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613124906154d1565b60405180910390fd5b61313b600083836001612867565b6131448161275e565b15613184576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161317b906154d1565b60405180910390fd5b6001600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a461328e600083836001612879565b5050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b606082471015613364576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161335b90615563565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161338d91906155b4565b60006040518083038185875af1925050503d80600081146133ca576040519150601f19603f3d011682016040523d82523d6000602084013e6133cf565b606091505b50915091506133e0878383876136f8565b92505050949350505050565b50505050565b6008805490506009600083815260200190815260200160002081905550600881908060018154018082558091505060019003906000526020600020016000909190919091505550565b60006001613448846111e1565b613452919061460b565b9050600060076000848152602001908152602001600020549050818114613537576000600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002054905080600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002081905550816007600083815260200190815260200160002081905550505b6007600084815260200190815260200160002060009055600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008381526020019081526020016000206000905550505050565b600060016008805490506135bc919061460b565b90506000600960008481526020019081526020016000205490506000600883815481106135ec576135eb6144b9565b5b90600052602060002001549050806008838154811061360e5761360d6144b9565b5b90600052602060002001819055508160096000838152602001908152602001600020819055506009600085815260200190815260200160002060009055600880548061365d5761365c61463f565b5b6001900381819060005260206000200160009055905550505050565b6000613684836111e1565b905081600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002081905550806007600084815260200190815260200160002081905550505050565b6060831561375a5760008351036137525761371285613292565b613751576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161374890615617565b60405180910390fd5b5b829050613765565b613764838361376d565b5b949350505050565b6000825111156137805781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137b49190613c87565b60405180910390fd5b6000604051905090565b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61381f826137d6565b810181811067ffffffffffffffff8211171561383e5761383d6137e7565b5b80604052505050565b60006138516137bd565b905061385d8282613816565b919050565b600067ffffffffffffffff82111561387d5761387c6137e7565b5b602082029050919050565b600080fd5b6000819050919050565b6138a08161388d565b81146138ab57600080fd5b50565b6000813590506138bd81613897565b92915050565b60006138d66138d184613862565b613847565b905080602084028301858111156138f0576138ef613888565b5b835b81811015613919578061390588826138ae565b8452602084019350506020810190506138f2565b5050509392505050565b600082601f830112613938576139376137d1565b5b60046139458482856138c3565b91505092915050565b600080fd5b600067ffffffffffffffff82111561396e5761396d6137e7565b5b613977826137d6565b9050602081019050919050565b82818337600083830152505050565b60006139a66139a184613953565b613847565b9050828152602081018484840111156139c2576139c161394e565b5b6139cd848285613984565b509392505050565b600082601f8301126139ea576139e96137d1565b5b81356139fa848260208601613993565b91505092915050565b600067ffffffffffffffff821115613a1e57613a1d6137e7565b5b602082029050919050565b6000613a3c613a3784613a03565b613847565b90508060208402830185811115613a5657613a55613888565b5b835b81811015613a7f5780613a6b88826138ae565b845260208401935050602081019050613a58565b5050509392505050565b600082601f830112613a9e57613a9d6137d1565b5b6002613aab848285613a29565b91505092915050565b60008060008060006101808688031215613ad157613ad06137c7565b5b6000613adf88828901613923565b955050608086013567ffffffffffffffff811115613b0057613aff6137cc565b5b613b0c888289016139d5565b94505060a0613b1d88828901613a89565b93505060e0613b2e88828901613923565b925050610160613b40888289016138ae565b9150509295509295909350565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613b8281613b4d565b8114613b8d57600080fd5b50565b600081359050613b9f81613b79565b92915050565b600060208284031215613bbb57613bba6137c7565b5b6000613bc984828501613b90565b91505092915050565b60008115159050919050565b613be781613bd2565b82525050565b6000602082019050613c026000830184613bde565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613c42578082015181840152602081019050613c27565b60008484015250505050565b6000613c5982613c08565b613c638185613c13565b9350613c73818560208601613c24565b613c7c816137d6565b840191505092915050565b60006020820190508181036000830152613ca18184613c4e565b905092915050565b6000819050919050565b613cbc81613ca9565b82525050565b6000602082019050613cd76000830184613cb3565b92915050565b600060208284031215613cf357613cf26137c7565b5b6000613d01848285016138ae565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613d3582613d0a565b9050919050565b613d4581613d2a565b82525050565b6000602082019050613d606000830184613d3c565b92915050565b613d6f81613d2a565b8114613d7a57600080fd5b50565b600081359050613d8c81613d66565b92915050565b60008060408385031215613da957613da86137c7565b5b6000613db785828601613d7d565b9250506020613dc8858286016138ae565b9150509250929050565b600080600060608486031215613deb57613dea6137c7565b5b6000613df986828701613d7d565b9350506020613e0a86828701613d7d565b9250506040613e1b868287016138ae565b9150509250925092565b613e2e8161388d565b82525050565b6000602082019050613e496000830184613e25565b92915050565b613e5881613ca9565b8114613e6357600080fd5b50565b600081359050613e7581613e4f565b92915050565b600060208284031215613e9157613e906137c7565b5b6000613e9f84828501613e66565b91505092915050565b60008060408385031215613ebf57613ebe6137c7565b5b6000613ecd85828601613e66565b9250506020613ede85828601613d7d565b9150509250929050565b600060208284031215613efe57613efd6137c7565b5b6000613f0c84828501613d7d565b91505092915050565b6000613f2082613d0a565b9050919050565b613f3081613f15565b8114613f3b57600080fd5b50565b600081359050613f4d81613f27565b92915050565b600060208284031215613f6957613f686137c7565b5b6000613f7784828501613f3e565b91505092915050565b60008060408385031215613f9757613f966137c7565b5b6000613fa5858286016138ae565b9250506020613fb6858286016138ae565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b613ff58161388d565b82525050565b60006140078383613fec565b60208301905092915050565b6000602082019050919050565b600061402b82613fc0565b6140358185613fcb565b935061404083613fdc565b8060005b838110156140715781516140588882613ffb565b975061406383614013565b925050600181019050614044565b5085935050505092915050565b600060208201905081810360008301526140988184614020565b905092915050565b6140a981613bd2565b81146140b457600080fd5b50565b6000813590506140c6816140a0565b92915050565b600080604083850312156140e3576140e26137c7565b5b60006140f185828601613d7d565b9250506020614102858286016140b7565b9150509250929050565b60008060008060808587031215614126576141256137c7565b5b600061413487828801613d7d565b945050602061414587828801613d7d565b9350506040614156878288016138ae565b925050606085013567ffffffffffffffff811115614177576141766137cc565b5b614183878288016139d5565b91505092959194509250565b600080604083850312156141a6576141a56137c7565b5b60006141b485828601613d7d565b92505060206141c585828601613d7d565b9150509250929050565b7f416c72656164792066756c66696c6c6564000000000000000000000000000000600082015250565b6000614205601183613c13565b9150614210826141cf565b602082019050919050565b60006020820190508181036000830152614234816141f8565b9050919050565b600060049050919050565b600081905092915050565b6000819050919050565b6000602082019050919050565b6142718161423b565b61427b8184614246565b925061428682614251565b8060005b838110156142b757815161429e8782613ffb565b96506142a98361425b565b92505060018101905061428a565b505050505050565b600081519050919050565b600082825260208201905092915050565b60006142e6826142bf565b6142f081856142ca565b9350614300818560208601613c24565b614309816137d6565b840191505092915050565b600060029050919050565b600081905092915050565b6000819050919050565b6000602082019050919050565b61434a81614314565b614354818461431f565b925061435f8261432a565b8060005b838110156143905781516143778782613ffb565b965061438283614334565b925050600181019050614363565b505050505050565b6000610160820190506143ae6000830187614268565b81810360808301526143c081866142db565b90506143cf60a0830185614341565b6143dc60e0830184614268565b95945050505050565b6000815190506143f4816140a0565b92915050565b6000602082840312156144105761440f6137c7565b5b600061441e848285016143e5565b91505092915050565b7f44656c6976657265642072616e646f6d6e657373206973206e6f742076616c6960008201527f6421000000000000000000000000000000000000000000000000000000000000602082015250565b6000614483602283613c13565b915061448e82614427565b604082019050919050565b600060208201905081810360008301526144b281614476565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006040820190506144fd6000830185613e25565b61450a6020830184613e25565b9392505050565b60008151905061452081613e4f565b92915050565b60006020828403121561453c5761453b6137c7565b5b600061454a84828501614511565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061458d8261388d565b9150600082036145a05761459f614553565b5b600182039050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006145e58261388d565b91506145f08361388d565b925082614600576145ff6145ab565b5b828206905092915050565b60006146168261388d565b91506146218361388d565b925082820390508181111561463957614638614553565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806146b557607f821691505b6020821081036146c8576146c761466e565b5b50919050565b7f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b600061472a602183613c13565b9150614735826146ce565b604082019050919050565b600060208201905081810360008301526147598161471d565b9050919050565b7f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60008201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000602082015250565b60006147bc603d83613c13565b91506147c782614760565b604082019050919050565b600060208201905081810360008301526147eb816147af565b9050919050565b7f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560008201527f72206f7220617070726f76656400000000000000000000000000000000000000602082015250565b600061484e602d83613c13565b9150614859826147f2565b604082019050919050565b6000602082019050818103600083015261487d81614841565b9050919050565b7f455243373231456e756d657261626c653a206f776e657220696e646578206f7560008201527f74206f6620626f756e6473000000000000000000000000000000000000000000602082015250565b60006148e0602b83613c13565b91506148eb82614884565b604082019050919050565b6000602082019050818103600083015261490f816148d3565b9050919050565b7f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008201527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015250565b6000614972602f83613c13565b915061497d82614916565b604082019050919050565b600060208201905081810360008301526149a181614965565b9050919050565b7f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60008201527f7574206f6620626f756e64730000000000000000000000000000000000000000602082015250565b6000614a04602c83613c13565b9150614a0f826149a8565b604082019050919050565b60006020820190508181036000830152614a33816149f7565b9050919050565b7f4552433732313a20696e76616c696420746f6b656e2049440000000000000000600082015250565b6000614a70601883613c13565b9150614a7b82614a3a565b602082019050919050565b60006020820190508181036000830152614a9f81614a63565b9050919050565b7f4552433732313a2061646472657373207a65726f206973206e6f74206120766160008201527f6c6964206f776e65720000000000000000000000000000000000000000000000602082015250565b6000614b02602983613c13565b9150614b0d82614aa6565b604082019050919050565b60006020820190508181036000830152614b3181614af5565b9050919050565b600081905092915050565b50565b6000614b53600083614b38565b9150614b5e82614b43565b600082019050919050565b6000614b7482614b46565b9150819050919050565b7f4661696c656420746f2073656e64204574686572000000000000000000000000600082015250565b6000614bb4601483613c13565b9150614bbf82614b7e565b602082019050919050565b60006020820190508181036000830152614be381614ba7565b9050919050565b6000614bf58261388d565b9150614c008361388d565b9250828201905080821115614c1857614c17614553565b5b92915050565b6000614c298261388d565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614c5b57614c5a614553565b5b600182019050919050565b7f43616e2774206d696e74207a65726f204e465473000000000000000000000000600082015250565b6000614c9c601483613c13565b9150614ca782614c66565b602082019050919050565b60006020820190508181036000830152614ccb81614c8f565b9050919050565b6000614cdd8261388d565b9150614ce88361388d565b9250828202614cf68161388d565b91508282048414831517614d0d57614d0c614553565b5b5092915050565b7f56616c7565206973206c6f776572207468616e20746865204e4654206d696e7460008201527f696e672070726963650000000000000000000000000000000000000000000000602082015250565b6000614d70602983613c13565b9150614d7b82614d14565b604082019050919050565b60006020820190508181036000830152614d9f81614d63565b9050919050565b7f4e6f7420656e6f75676820737570706c79206c65667400000000000000000000600082015250565b6000614ddc601683613c13565b9150614de782614da6565b602082019050919050565b60006020820190508181036000830152614e0b81614dcf565b9050919050565b600081905092915050565b6000614e2882613c08565b614e328185614e12565b9350614e42818560208601613c24565b80840191505092915050565b6000614e5a8285614e1d565b9150614e668284614e1d565b91508190509392505050565b7f4e6f206d6f7265204e46547320746f2073656c6c000000000000000000000000600082015250565b6000614ea8601483613c13565b9150614eb382614e72565b602082019050919050565b60006020820190508181036000830152614ed781614e9b565b9050919050565b6000604082019050614ef36000830185613d3c565b614f006020830184613e25565b9392505050565b7f4552433732313a207472616e736665722066726f6d20696e636f72726563742060008201527f6f776e6572000000000000000000000000000000000000000000000000000000602082015250565b6000614f63602583613c13565b9150614f6e82614f07565b604082019050919050565b60006020820190508181036000830152614f9281614f56565b9050919050565b7f4552433732313a207472616e7366657220746f20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b6000614ff5602483613c13565b915061500082614f99565b604082019050919050565b6000602082019050818103600083015261502481614fe8565b9050919050565b7f4552433732313a20617070726f766520746f2063616c6c657200000000000000600082015250565b6000615061601983613c13565b915061506c8261502b565b602082019050919050565b6000602082019050818103600083015261509081615054565b9050919050565b7f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560008201527f63656976657220696d706c656d656e7465720000000000000000000000000000602082015250565b60006150f3603283613c13565b91506150fe82615097565b604082019050919050565b60006020820190508181036000830152615122816150e6565b9050919050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b600061515f601783614e12565b915061516a82615129565b601782019050919050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b60006151ab601183614e12565b91506151b682615175565b601182019050919050565b60006151cc82615152565b91506151d88285614e1d565b91506151e38261519e565b91506151ef8284614e1d565b91508190509392505050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b6000615257602a83613c13565b9150615262826151fb565b604082019050919050565b600060208201905081810360008301526152868161524a565b9050919050565b60006080820190506152a26000830187613d3c565b6152af6020830186613d3c565b6152bc6040830185613e25565b81810360608301526152ce81846142db565b905095945050505050565b6000815190506152e881613b79565b92915050565b600060208284031215615304576153036137c7565b5b6000615312848285016152d9565b91505092915050565b7f537472696e67733a20686578206c656e67746820696e73756666696369656e74600082015250565b6000615351602083613c13565b915061535c8261531b565b602082019050919050565b6000602082019050818103600083015261538081615344565b9050919050565b7f455243373231456e756d657261626c653a20636f6e736563757469766520747260008201527f616e7366657273206e6f7420737570706f727465640000000000000000000000602082015250565b60006153e3603583613c13565b91506153ee82615387565b604082019050919050565b60006020820190508181036000830152615412816153d6565b9050919050565b7f4552433732313a206d696e7420746f20746865207a65726f2061646472657373600082015250565b600061544f602083613c13565b915061545a82615419565b602082019050919050565b6000602082019050818103600083015261547e81615442565b9050919050565b7f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000600082015250565b60006154bb601c83613c13565b91506154c682615485565b602082019050919050565b600060208201905081810360008301526154ea816154ae565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b600061554d602683613c13565b9150615558826154f1565b604082019050919050565b6000602082019050818103600083015261557c81615540565b9050919050565b600061558e826142bf565b6155988185614b38565b93506155a8818560208601613c24565b80840191505092915050565b60006155c08284615583565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000615601601d83613c13565b915061560c826155cb565b602082019050919050565b60006020820190508181036000830152615630816155f4565b905091905056fea264697066735822122072dc244ce928442add844615cf261d0c664474398a1d004fc322961123a59dc764736f6c63430008130033608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550613411806100606000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063a91d58b411610071578063a91d58b41461018c578063bbe95b4c146101a8578063c32a82ea146101d8578063c95ac47a14610208578063c9d4ef1f14610239578063d1b4137214610269576100a9565b80632e334452146100ae578063404568b5146100cc57806345899df4146100fc57806351cdea5f1461012c5780635f0983411461015c575b600080fd5b6100b661029a565b6040516100c3919061238e565b60405180910390f35b6100e660048036038101906100e191906125e5565b6102d6565b6040516100f3919061265c565b60405180910390f35b61011660048036038101906101119190612728565b610328565b604051610123919061265c565b60405180910390f35b610146600480360381019061014191906127c1565b610342565b60405161015391906128b5565b60405180910390f35b610176600480360381019061017191906128d0565b61035a565b6040516101839190612929565b60405180910390f35b6101a660048036038101906101a191906127c1565b61036e565b005b6101c260048036038101906101bd9190612944565b610419565b6040516101cf919061265c565b60405180910390f35b6101f260048036038101906101ed91906129b3565b61042f565b6040516101ff919061265c565b60405180910390f35b610222600480360381019061021d9190612944565b610485565b604051610230929190612abb565b60405180910390f35b610253600480360381019061024e91906127c1565b6104ac565b6040516102609190612ae4565b60405180910390f35b610283600480360381019061027e91906125e5565b6104c4565b604051610291929190612abb565b60405180910390f35b60606102d160016000600281106102b4576102b3612aff565b5b0154600180600281106102ca576102c9612aff565b5b0154610527565b905090565b60006103206001600280602002604051908101604052809291908260028015610314576020028201915b815481526020019060010190808311610300575b50505050508484610571565b905092915050565b60006103378686868686610732565b905095945050505050565b61034a61225d565b61035382610a29565b9050919050565b60006103668383610ab3565b905092915050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146103fc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103f390612b8b565b60405180910390fd5b61040581610a29565b600190600261041592919061227f565b5050565b6000610426848484610571565b90509392505050565b600061047b600160028060200260405190810160405280929190826002801561046d576020028201915b815481526020019060010190808311610459575b505050505086868686610732565b9050949350505050565b61048d61225d565b6104956122bf565b6104a0858585610b43565b91509150935093915050565b6104b46122bf565b6104bd82610ce7565b9050919050565b6104cc61225d565b6104d46122bf565b61051c6001600280602002604051908101604052809291908260028015610510576020028201915b8154815260200190600101908083116104fc575b50505050508585610b43565b915091509250929050565b606060006002836105389190612bda565b60026105449190612c3a565b90508084604051602001610559929190612cd2565b60405160208183030381529060405291505092915050565b60008060006105808685610da2565b915091506000806106358760036004811061059e5761059d612aff565b5b60200201517f79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817987f483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b88a6002600481106105f9576105f8612aff565b5b60200201518c60006002811061061257610611612aff565b5b60200201518d60016002811061062b5761062a612aff565b5b6020020151610f46565b915091506000806106aa8960036004811061065357610652612aff565b5b602002015187878c60026004811061066e5761066d612aff565b5b60200201518d60006004811061068757610686612aff565b5b60200201518e6001600481106106a05761069f612aff565b5b6020020151610f46565b9150915060006106f087878c6000600481106106c9576106c8612aff565b5b60200201518d6001600481106106e2576106e1612aff565b5b602002015189898989610fba565b90508960026004811061070657610705612aff565b5b60200201518160801c6fffffffffffffffffffffffffffffffff16149750505050505050509392505050565b60008060006107418887610da2565b915091506107e38760036004811061075c5761075b612aff565b5b60200201518860026004811061077557610774612aff565b5b60200201518a60006002811061078e5761078d612aff565b5b60200201518b6001600281106107a7576107a6612aff565b5b6020020151896000600281106107c0576107bf612aff565b5b60200201518a6001600281106107d9576107d8612aff565b5b602002015161108b565b1580610841575061083f8760036004811061080157610800612aff565b5b602002015183838760006004811061081c5761081b612aff565b5b60200201518860016004811061083557610834612aff565b5b6020020151611267565b155b806108ce57506108cc8760026004811061085e5761085d612aff565b5b60200201518860006004811061087757610876612aff565b5b6020020151896001600481106108905761088f612aff565b5b6020020151876002600481106108a9576108a8612aff565b5b6020020151886003600481106108c2576108c1612aff565b5b6020020151611267565b155b156108de57600092505050610a20565b600080610970866000600481106108f8576108f7612aff565b5b60200201518760016004811061091157610910612aff565b5b60200201518860026004811061092a57610929612aff565b5b60200201518960036004811061094357610942612aff565b5b602002015160007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f611353565b9150915060006109e685858c60006004811061098f5761098e612aff565b5b60200201518d6001600481106109a8576109a7612aff565b5b60200201518c6000600281106109c1576109c0612aff565b5b60200201518d6001600281106109da576109d9612aff565b5b60200201518989610fba565b9050896002600481106109fc576109fb612aff565b5b60200201518160801c6fffffffffffffffffffffffffffffffff1614955050505050505b95945050505050565b610a3161225d565b6021825114610a75576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a6c90612d4a565b60405180910390fd5b60008060018401519150602184015190506000610a928383611387565b90506040518060400160405280838152602001828152509350505050919050565b60008060fe6003610ac48686610527565b6000604051602001610ad99493929190612da6565b6040516020818303038152906040529050600281604051610afa9190612df0565b602060405180830381855afa158015610b17573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610b3a9190612e33565b91505092915050565b610b4b61225d565b610b536122bf565b600080610b608786610da2565b91509150600080610c1588600360048110610b7e57610b7d612aff565b5b60200201517f79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817987f483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b88b600260048110610bd957610bd8612aff565b5b60200201518d600060028110610bf257610bf1612aff565b5b60200201518e600160028110610c0b57610c0a612aff565b5b6020020151610f46565b91509150600080610c3f8a600360048110610c3357610c32612aff565b5b602002015187876113c0565b91509150600080610c998c600260048110610c5d57610c5c612aff565b5b60200201518d600060048110610c7657610c75612aff565b5b60200201518e600160048110610c8f57610c8e612aff565b5b60200201516113c0565b91509150604051806040016040528087815260200186815250604051806080016040528086815260200185815260200184815260200183815250995099505050505050505050935093915050565b610cef6122bf565b6051825114610d33576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d2a90612eac565b60405180910390fd5b600080600080600186015193506021860151925060318601519150605186015190506000610d618585611387565b90506040518060800160405280858152602001828152602001846fffffffffffffffffffffffffffffffff1681526020018381525095505050505050919050565b600080600060fe6001610de587600060028110610dc257610dc1612aff565b5b602002015188600160028110610ddb57610dda612aff565b5b6020020151610527565b86604051602001610df99493929190612ecc565b604051602081830303815290604052905060005b6101008160ff161015610f03576000600283836000604051602001610e3493929190612f12565b604051602081830303815290604052604051610e509190612df0565b602060405180830381855afa158015610e6d573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190610e909190612e33565b905060008160001c90506000610ea7600283611387565b9050610ed88282600060077ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f6113fd565b15610eed578181965096505050505050610f3f565b5050508080610efb90612f4b565b915050610e0d565b506040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f3690612fc0565b60405180910390fd5b9250929050565b600080600080610f578a8a8a6113c0565b91509150600080610f698989896113c0565b91509150600080610f9f8686868660007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f611353565b91509150818197509750505050505050965096945050505050565b60008060fe6002610fcb8c8c610527565b610fd58b8b610527565b610fdf8a8a610527565b610fe98989610527565b60006040516020016110019796959493929190612fe0565b604051602081830303815290604052905060006002826040516110249190612df0565b602060405180830381855afa158015611041573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906110649190612e33565b90506000604051826000820152600081015191505080935050505098975050505050505050565b6000807ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141887ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641416110db9190613051565b6110e59190612bda565b90507ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418061111657611115612bab565b5b868209905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141887ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036414161116a9190613051565b6111749190612bda565b9050600060018360001b600060028a61118d9190612bda565b0361119957601b61119c565b601c5b8a60001b7ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141806111cf576111ce612bab565b5b8c870960001b604051600081526020016040526040516111f29493929190613094565b6020604051602081039080840390855afa158015611214573d6000803e3d6000fd5b5050506020604051035190508073ffffffffffffffffffffffffffffffffffffffff1661124187876114cb565b73ffffffffffffffffffffffffffffffffffffffff161493505050509695505050505050565b600080600160008060028861127c9190612bda565b0361128857601b61128b565b601c5b8860001b7ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141806112be576112bd612bab565b5b8a8c0960001b604051600081526020016040526040516112e19493929190613121565b6020604051602081039080840390855afa158015611303573d6000803e3d6000fd5b5050506020604051035190508073ffffffffffffffffffffffffffffffffffffffff1661133085856114cb565b73ffffffffffffffffffffffffffffffffffffffff161491505095945050505050565b600080600080611364888887611517565b915091506113768a8a84848a8a61153e565b935093505050965096945050505050565b60006113b88383600060077ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f6115d1565b905092915050565b6000806113f185858560007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f6116ec565b91509150935093915050565b6000856000148061140e5750818610155b806114195750846000145b806114245750818510155b1561143257600090506114c2565b6000828061144357611442612bab565b5b86870990506000838061145957611458612bab565b5b88858061146957611468612bab565b5b8a8b090990506000861461149d57838061148657611485612bab565b5b848061149557611494612bab565b5b878a09820890505b600085146114ba5783806114b4576114b3612bab565b5b85820890505b808214925050505b95945050505050565b600073ffffffffffffffffffffffffffffffffffffffff83836040516020016114f5929190613166565b6040516020818303038152906040528051906020012060001c16905092915050565b600080848385856115289190613051565b6115329190612bda565b91509150935093915050565b6000806000806000888b03611594576000868061155e5761155d612bab565b5b898c080361157557600080945094505050506115c6565b6115838b8b60018a8a611726565b8093508194508295505050506115b2565b6115a58b8b60018c8c60018c6118e4565b8093508194508295505050505b6115be83838389611f63565b945094505050505b965096945050505050565b600060028660ff1614806115e8575060038660ff16145b611627576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161161e90613204565b60405180910390fd5b6000828061163857611637612bab565b5b838061164757611646612bab565b5b85858061165757611656612bab565b5b888a0908848061166a57611669612bab565b5b858061167957611678612bab565b5b898a0989090890506116a48160046001866116949190612c3a565b61169e9190613224565b85611fda565b905060008060028960ff16846116ba9190612c3a565b6116c49190612bda565b146116da5781846116d59190613051565b6116dc565b815b9050809250505095945050505050565b60008060008060006117038a8a8a60018b8b6120d2565b92509250925061171583838389611f63565b945094505050509550959350505050565b6000806000808603611740578787879250925092506118d9565b6000848061175157611750612bab565b5b898a0990506000858061176757611766612bab565b5b898a0990506000868061177d5761177c612bab565b5b898a0990506000878061179357611792612bab565b5b88806117a2576117a1612bab565b5b848e096004099050600088806117bb576117ba612bab565b5b89806117ca576117c9612bab565b5b8a806117d9576117d8612bab565b5b8586098c098a806117ed576117ec612bab565b5b87600309089050888061180357611802612bab565b5b898061181257611811612bab565b5b8384088a6118209190613051565b8a8061182f5761182e612bab565b5b838409089450888061184457611843612bab565b5b898061185357611852612bab565b5b8a8061186257611861612bab565b5b8687096008098a6118739190613051565b8a8061188257611881612bab565b5b8b8061189157611890612bab565b5b888d61189d9190613051565b8608840908935088806118b3576118b2612bab565b5b89806118c2576118c1612bab565b5b8c8e09600209925084848497509750975050505050505b955095509592505050565b6000806000808a1480156118f85750600089145b1561190b57868686925092509250611f56565b60008714801561191b5750600086145b1561192e57898989925092509250611f56565b6119366122bf565b848061194557611944612bab565b5b898a098160006004811061195c5761195b612aff565b5b602002018181525050848061197457611973612bab565b5b8160006004811061198857611987612aff565b5b60200201518a09816001600481106119a3576119a2612aff565b5b60200201818152505084806119bb576119ba612bab565b5b868709816002600481106119d2576119d1612aff565b5b60200201818152505084806119ea576119e9612bab565b5b816002600481106119fe576119fd612aff565b5b6020020151870981600360048110611a1957611a18612aff565b5b60200201818152505060405180608001604052808680611a3c57611a3b612bab565b5b83600260048110611a5057611a4f612aff565b5b60200201518e0981526020018680611a6b57611a6a612bab565b5b83600360048110611a7f57611a7e612aff565b5b60200201518d0981526020018680611a9a57611a99612bab565b5b83600060048110611aae57611aad612aff565b5b60200201518b0981526020018680611ac957611ac8612bab565b5b83600160048110611add57611adc612aff565b5b60200201518a09815250905080600260048110611afd57611afc612aff565b5b602002015181600060048110611b1657611b15612aff565b5b6020020151141580611b58575080600360048110611b3757611b36612aff565b5b602002015181600160048110611b5057611b4f612aff565b5b602002015114155b611b97576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b8e906132a1565b60405180910390fd5b611b9f6122bf565b8580611bae57611bad612bab565b5b82600060048110611bc257611bc1612aff565b5b602002015187611bd29190613051565b83600260048110611be657611be5612aff565b5b60200201510881600060048110611c0057611bff612aff565b5b6020020181815250508580611c1857611c17612bab565b5b82600160048110611c2c57611c2b612aff565b5b602002015187611c3c9190613051565b83600360048110611c5057611c4f612aff565b5b60200201510881600160048110611c6a57611c69612aff565b5b6020020181815250508580611c8257611c81612bab565b5b81600060048110611c9657611c95612aff565b5b602002015182600060048110611caf57611cae612aff565b5b60200201510981600260048110611cc957611cc8612aff565b5b6020020181815250508580611ce157611ce0612bab565b5b81600060048110611cf557611cf4612aff565b5b602002015182600260048110611d0e57611d0d612aff565b5b60200201510981600360048110611d2857611d27612aff565b5b60200201818152505060008680611d4257611d41612bab565b5b82600360048110611d5657611d55612aff565b5b602002015188611d669190613051565b8880611d7557611d74612bab565b5b84600160048110611d8957611d88612aff565b5b602002015185600160048110611da257611da1612aff565b5b6020020151090890508680611dba57611db9612bab565b5b8780611dc957611dc8612bab565b5b8880611dd857611dd7612bab565b5b84600260048110611dec57611deb612aff565b5b602002015186600060048110611e0557611e04612aff565b5b60200201510960020988611e199190613051565b8208905060008780611e2e57611e2d612bab565b5b8880611e3d57611e3c612bab565b5b838a611e499190613051565b8a80611e5857611e57612bab565b5b86600260048110611e6c57611e6b612aff565b5b602002015188600060048110611e8557611e84612aff565b5b6020020151090884600160048110611ea057611e9f612aff565b5b60200201510990508780611eb757611eb6612bab565b5b8880611ec657611ec5612bab565b5b84600360048110611eda57611ed9612aff565b5b602002015186600160048110611ef357611ef2612aff565b5b60200201510989611f049190613051565b8208905060008880611f1957611f18612bab565b5b8980611f2857611f27612bab565b5b8b8f0985600060048110611f3f57611f3e612aff565b5b602002015109905082828297509750975050505050505b9750975097945050505050565b6000806000611f728585612171565b905060008480611f8557611f84612bab565b5b828309905060008580611f9b57611f9a612bab565b5b828a09905060008680611fb157611fb0612bab565b5b8780611fc057611fbf612bab565b5b8486098a0990508181955095505050505094509492505050565b600080820361201e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120159061330d565b60405180910390fd5b6000840361202f57600090506120cb565b6000830361204057600190506120cb565b60006001905060007f800000000000000000000000000000000000000000000000000000000000000090505b60008111156120c557838186161515870a85848509099150836002820486161515870a85848509099150836004820486161515870a85848509099150836008820486161515870a8584850909915060108104905061206c565b81925050505b9392505050565b60008060008089036120ec57878787925092509250612165565b60008990506000806000600190505b60008414612157576000600185161461212a5761211d8383838f8f8f8e6118e4565b8093508194508295505050505b6002846121379190613224565b93506121468c8c8c8c8c611726565b809c50819d50829e505050506120fb565b828282965096509650505050505b96509650969350505050565b60008083141580156121835750818314155b8015612190575060008214155b6121cf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121c690613379565b60405180910390fd5b60008060019050600084905060005b600087146122505786826121f29190613224565b905082868061220457612203612bab565b5b878061221357612212612bab565b5b858409886122219190613051565b860880945081955050508687826122389190613399565b836122439190613051565b80985081935050506121de565b8394505050505092915050565b6040518060400160405280600290602082028036833780820191505090505090565b82600281019282156122ae579160200282015b828111156122ad578251825591602001919060010190612292565b5b5090506122bb91906122e1565b5090565b6040518060800160405280600490602082028036833780820191505090505090565b5b808211156122fa5760008160009055506001016122e2565b5090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561233857808201518184015260208101905061231d565b60008484015250505050565b6000601f19601f8301169050919050565b6000612360826122fe565b61236a8185612309565b935061237a81856020860161231a565b61238381612344565b840191505092915050565b600060208201905081810360008301526123a88184612355565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61240182612344565b810181811067ffffffffffffffff821117156124205761241f6123c9565b5b80604052505050565b60006124336123b0565b905061243f82826123f8565b919050565b600067ffffffffffffffff82111561245f5761245e6123c9565b5b602082029050919050565b600080fd5b6000819050919050565b6124828161246f565b811461248d57600080fd5b50565b60008135905061249f81612479565b92915050565b60006124b86124b384612444565b612429565b905080602084028301858111156124d2576124d161246a565b5b835b818110156124fb57806124e78882612490565b8452602084019350506020810190506124d4565b5050509392505050565b600082601f83011261251a576125196123c4565b5b60046125278482856124a5565b91505092915050565b600080fd5b600067ffffffffffffffff8211156125505761254f6123c9565b5b61255982612344565b9050602081019050919050565b82818337600083830152505050565b600061258861258384612535565b612429565b9050828152602081018484840111156125a4576125a3612530565b5b6125af848285612566565b509392505050565b600082601f8301126125cc576125cb6123c4565b5b81356125dc848260208601612575565b91505092915050565b60008060a083850312156125fc576125fb6123ba565b5b600061260a85828601612505565b925050608083013567ffffffffffffffff81111561262b5761262a6123bf565b5b612637858286016125b7565b9150509250929050565b60008115159050919050565b61265681612641565b82525050565b6000602082019050612671600083018461264d565b92915050565b600067ffffffffffffffff821115612692576126916123c9565b5b602082029050919050565b60006126b06126ab84612677565b612429565b905080602084028301858111156126ca576126c961246a565b5b835b818110156126f357806126df8882612490565b8452602084019350506020810190506126cc565b5050509392505050565b600082601f830112612712576127116123c4565b5b600261271f84828561269d565b91505092915050565b60008060008060006101a08688031215612745576127446123ba565b5b6000612753888289016126fd565b955050604061276488828901612505565b94505060c086013567ffffffffffffffff811115612785576127846123bf565b5b612791888289016125b7565b93505060e06127a2888289016126fd565b9250506101206127b488828901612505565b9150509295509295909350565b6000602082840312156127d7576127d66123ba565b5b600082013567ffffffffffffffff8111156127f5576127f46123bf565b5b612801848285016125b7565b91505092915050565b600060029050919050565b600081905092915050565b6000819050919050565b6128338161246f565b82525050565b6000612845838361282a565b60208301905092915050565b6000602082019050919050565b6128678161280a565b6128718184612815565b925061287c82612820565b8060005b838110156128ad5781516128948782612839565b965061289f83612851565b925050600181019050612880565b505050505050565b60006040820190506128ca600083018461285e565b92915050565b600080604083850312156128e7576128e66123ba565b5b60006128f585828601612490565b925050602061290685828601612490565b9150509250929050565b6000819050919050565b61292381612910565b82525050565b600060208201905061293e600083018461291a565b92915050565b600080600060e0848603121561295d5761295c6123ba565b5b600061296b868287016126fd565b935050604061297c86828701612505565b92505060c084013567ffffffffffffffff81111561299d5761299c6123bf565b5b6129a9868287016125b7565b9150509250925092565b60008060008061016085870312156129ce576129cd6123ba565b5b60006129dc87828801612505565b945050608085013567ffffffffffffffff8111156129fd576129fc6123bf565b5b612a09878288016125b7565b93505060a0612a1a878288016126fd565b92505060e0612a2b87828801612505565b91505092959194509250565b600060049050919050565b600081905092915050565b6000819050919050565b6000602082019050919050565b612a6d81612a37565b612a778184612a42565b9250612a8282612a4d565b8060005b83811015612ab3578151612a9a8782612839565b9650612aa583612a57565b925050600181019050612a86565b505050505050565b600060c082019050612ad0600083018561285e565b612add6040830184612a64565b9392505050565b6000608082019050612af96000830184612a64565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082825260208201905092915050565b7f4f6e6c79206f776e657200000000000000000000000000000000000000000000600082015250565b6000612b75600a83612b2e565b9150612b8082612b3f565b602082019050919050565b60006020820190508181036000830152612ba481612b68565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000612be58261246f565b9150612bf08361246f565b925082612c0057612bff612bab565b5b828206905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612c458261246f565b9150612c508361246f565b9250828201905080821115612c6857612c67612c0b565b5b92915050565b600060ff82169050919050565b60008160f81b9050919050565b6000612c9382612c7b565b9050919050565b612cab612ca682612c6e565b612c88565b82525050565b6000819050919050565b612ccc612cc78261246f565b612cb1565b82525050565b6000612cde8285612c9a565b600182019150612cee8284612cbb565b6020820191508190509392505050565b7f4d616c666f726d656420636f6d7072657373656420454320706f696e74000000600082015250565b6000612d34601d83612b2e565b9150612d3f82612cfe565b602082019050919050565b60006020820190508181036000830152612d6381612d27565b9050919050565b600081905092915050565b6000612d80826122fe565b612d8a8185612d6a565b9350612d9a81856020860161231a565b80840191505092915050565b6000612db28287612c9a565b600182019150612dc28286612c9a565b600182019150612dd28285612d75565b9150612dde8284612c9a565b60018201915081905095945050505050565b6000612dfc8284612d75565b915081905092915050565b612e1081612910565b8114612e1b57600080fd5b50565b600081519050612e2d81612e07565b92915050565b600060208284031215612e4957612e486123ba565b5b6000612e5784828501612e1e565b91505092915050565b7f4d616c666f726d6564205652462070726f6f6600000000000000000000000000600082015250565b6000612e96601383612b2e565b9150612ea182612e60565b602082019050919050565b60006020820190508181036000830152612ec581612e89565b9050919050565b6000612ed88287612c9a565b600182019150612ee88286612c9a565b600182019150612ef88285612d75565b9150612f048284612d75565b915081905095945050505050565b6000612f1e8286612d75565b9150612f2a8285612c9a565b600182019150612f3a8284612c9a565b600182019150819050949350505050565b6000612f5682612c6e565b915060ff8203612f6957612f68612c0b565b5b600182019050919050565b7f4e6f2076616c696420706f696e742077617320666f756e640000000000000000600082015250565b6000612faa601883612b2e565b9150612fb582612f74565b602082019050919050565b60006020820190508181036000830152612fd981612f9d565b9050919050565b6000612fec828a612c9a565b600182019150612ffc8289612c9a565b60018201915061300c8288612d75565b91506130188287612d75565b91506130248286612d75565b91506130308285612d75565b915061303c8284612c9a565b60018201915081905098975050505050505050565b600061305c8261246f565b91506130678361246f565b925082820390508181111561307f5761307e612c0b565b5b92915050565b61308e81612c6e565b82525050565b60006080820190506130a9600083018761291a565b6130b66020830186613085565b6130c3604083018561291a565b6130d0606083018461291a565b95945050505050565b6000819050919050565b60008160001b9050919050565b600061310b613106613101846130d9565b6130e3565b612910565b9050919050565b61311b816130f0565b82525050565b60006080820190506131366000830187613112565b6131436020830186613085565b613150604083018561291a565b61315d606083018461291a565b95945050505050565b60006131728285612cbb565b6020820191506131828284612cbb565b6020820191508190509392505050565b7f496e76616c696420636f6d7072657373656420454320706f696e74207072656660008201527f6978000000000000000000000000000000000000000000000000000000000000602082015250565b60006131ee602283612b2e565b91506131f982613192565b604082019050919050565b6000602082019050818103600083015261321d816131e1565b9050919050565b600061322f8261246f565b915061323a8361246f565b92508261324a57613249612bab565b5b828204905092915050565b7f557365206a6163446f75626c652066756e6374696f6e20696e73746561640000600082015250565b600061328b601e83612b2e565b915061329682613255565b602082019050919050565b600060208201905081810360008301526132ba8161327e565b9050919050565b7f4d6f64756c7573206973207a65726f0000000000000000000000000000000000600082015250565b60006132f7600f83612b2e565b9150613302826132c1565b602082019050919050565b60006020820190508181036000830152613326816132ea565b9050919050565b7f496e76616c6964206e756d626572000000000000000000000000000000000000600082015250565b6000613363600e83612b2e565b915061336e8261332d565b602082019050919050565b6000602082019050818103600083015261339281613356565b9050919050565b60006133a48261246f565b91506133af8361246f565b92508282026133bd8161246f565b915082820484148315176133d4576133d3612c0b565b5b509291505056fea2646970667358221220300e8bcad70db3dc5f6ccc29e91622941769ae3fa3737249f24091027db01cfa64736f6c634300081300330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002103e8de8573cb66fba7ac716eb8ef0e2b0e2839fd32ed09fb4a44c22ae38e696af600000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106102195760003560e01c80637e5c8b7f11610123578063a22cb465116100ab578063d547741f1161006f578063d547741f146107fa578063e985e9c514610823578063e99d286614610860578063f89ab3b014610889578063f9cc0605146108b257610219565b8063a22cb46514610724578063b88d4fde1461074d578063c87b56dd14610776578063d1cea4ec146107b3578063d5391393146107cf57610219565b806391d14854116100f257806391d148541461063d57806395d89b411461067a57806398d5fdca146106a5578063a1448194146106d0578063a217fddf146106f957610219565b80637e5c8b7f146105925780638271e707146105bb5780638462151c146105d757806391b7f5ed1461061457610219565b8063248a9ca3116101a657806342842e0e1161017557806342842e0e146104895780634f6ccce7146104b25780636352211e146104ef57806370a082311461052c5780637504db3e1461056957610219565b8063248a9ca3146103bd5780632f2ff15d146103fa5780632f745c591461042357806336568abe1461046057610219565b8063081812fc116101ed578063081812fc146102da578063095ea7b3146103175780631171bda91461034057806318160ddd1461036957806323b872dd1461039457610219565b80627119d11461021e57806301ffc9a71461024757806306fdde031461028457806307e2cea5146102af575b600080fd5b34801561022a57600080fd5b5061024560048036038101906102409190613ab4565b6108dd565b005b34801561025357600080fd5b5061026e60048036038101906102699190613ba5565b610c91565b60405161027b9190613bed565b60405180910390f35b34801561029057600080fd5b50610299610ca3565b6040516102a69190613c87565b60405180910390f35b3480156102bb57600080fd5b506102c4610d35565b6040516102d19190613cc2565b60405180910390f35b3480156102e657600080fd5b5061030160048036038101906102fc9190613cdd565b610d59565b60405161030e9190613d4b565b60405180910390f35b34801561032357600080fd5b5061033e60048036038101906103399190613d92565b610d9f565b005b34801561034c57600080fd5b5061036760048036038101906103629190613dd2565b610eb6565b005b34801561037557600080fd5b5061037e610ef4565b60405161038b9190613e34565b60405180910390f35b3480156103a057600080fd5b506103bb60048036038101906103b69190613dd2565b610f01565b005b3480156103c957600080fd5b506103e460048036038101906103df9190613e7b565b610f61565b6040516103f19190613cc2565b60405180910390f35b34801561040657600080fd5b50610421600480360381019061041c9190613ea8565b610f81565b005b34801561042f57600080fd5b5061044a60048036038101906104459190613d92565b610fa2565b6040516104579190613e34565b60405180910390f35b34801561046c57600080fd5b5061048760048036038101906104829190613ea8565b611047565b005b34801561049557600080fd5b506104b060048036038101906104ab9190613dd2565b6110ca565b005b3480156104be57600080fd5b506104d960048036038101906104d49190613cdd565b6110ea565b6040516104e69190613e34565b60405180910390f35b3480156104fb57600080fd5b5061051660048036038101906105119190613cdd565b61115b565b6040516105239190613d4b565b60405180910390f35b34801561053857600080fd5b50610553600480360381019061054e9190613ee8565b6111e1565b6040516105609190613e34565b60405180910390f35b34801561057557600080fd5b50610590600480360381019061058b9190613f53565b611298565b005b34801561059e57600080fd5b506105b960048036038101906105b49190613f80565b611356565b005b6105d560048036038101906105d09190613d92565b6113b8565b005b3480156105e357600080fd5b506105fe60048036038101906105f99190613ee8565b61157f565b60405161060b919061407e565b60405180910390f35b34801561062057600080fd5b5061063b60048036038101906106369190613cdd565b61162d565b005b34801561064957600080fd5b50610664600480360381019061065f9190613ea8565b611645565b6040516106719190613bed565b60405180910390f35b34801561068657600080fd5b5061068f6116b0565b60405161069c9190613c87565b60405180910390f35b3480156106b157600080fd5b506106ba611742565b6040516106c79190613e34565b60405180910390f35b3480156106dc57600080fd5b506106f760048036038101906106f29190613d92565b61174c565b005b34801561070557600080fd5b5061070e611785565b60405161071b9190613cc2565b60405180910390f35b34801561073057600080fd5b5061074b600480360381019061074691906140cc565b61178c565b005b34801561075957600080fd5b50610774600480360381019061076f919061410c565b6117a2565b005b34801561078257600080fd5b5061079d60048036038101906107989190613cdd565b611804565b6040516107aa9190613c87565b60405180910390f35b6107cd60048036038101906107c89190613ee8565b61186c565b005b3480156107db57600080fd5b506107e46119ba565b6040516107f19190613cc2565b60405180910390f35b34801561080657600080fd5b50610821600480360381019061081c9190613ea8565b6119de565b005b34801561082f57600080fd5b5061084a6004803603810190610845919061418f565b6119ff565b6040516108579190613bed565b60405180910390f35b34801561086c57600080fd5b5061088760048036038101906108829190613ee8565b611a93565b005b34801561089557600080fd5b506108b060048036038101906108ab9190613cdd565b611ae5565b005b3480156108be57600080fd5b506108c7611b68565b6040516108d4919061407e565b60405180910390f35b7f68e79a7bf1e0bc45d0a330c573bc367f9cf464fd326078812f301165fbda4ef161090781611bc0565b600b600083815260200190815260200160002060009054906101000a900460ff1615610968576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161095f9061421b565b60405180910390fd5b6000600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c32a82ea888888886040518563ffffffff1660e01b81526004016109cb9493929190614398565b602060405180830381865afa1580156109e8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0c91906143fa565b905080610a4e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a4590614499565b60405180910390fd5b6000600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635f09834189600060048110610aa257610aa16144b9565b5b60200201518a600160048110610abb57610aba6144b9565b5b60200201516040518363ffffffff1660e01b8152600401610add9291906144e8565b602060405180830381865afa158015610afa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b1e9190614526565b905060008160001c90506001600b600087815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600c600087815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600f6000815480929190610b9f90614582565b9190505550600060128054905083610bb791906145da565b9050600060128281548110610bcf57610bce6144b9565b5b9060005260206000200154905060126001601280549050610bf0919061460b565b81548110610c0157610c006144b9565b5b906000526020600020015460128381548110610c2057610c1f6144b9565b5b90600052602060002001819055506012805480610c4057610c3f61463f565b5b60019003818190600052602060002001600090559055610c83601160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1684836110ca565b505050505050505050505050565b6000610c9c82611bd4565b9050919050565b606060008054610cb29061469d565b80601f0160208091040260200160405190810160405280929190818152602001828054610cde9061469d565b8015610d2b5780601f10610d0057610100808354040283529160200191610d2b565b820191906000526020600020905b815481529060010190602001808311610d0e57829003601f168201915b5050505050905090565b7f68e79a7bf1e0bc45d0a330c573bc367f9cf464fd326078812f301165fbda4ef181565b6000610d6482611c4e565b6004600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6000610daa8261115b565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610e1a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e1190614740565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16610e39611c99565b73ffffffffffffffffffffffffffffffffffffffff161480610e685750610e6781610e62611c99565b6119ff565b5b610ea7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e9e906147d2565b60405180910390fd5b610eb18383611ca1565b505050565b6000801b610ec381611bc0565b610eee83838673ffffffffffffffffffffffffffffffffffffffff16611d5a9092919063ffffffff16565b50505050565b6000600880549050905090565b610f12610f0c611c99565b82611de0565b610f51576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f4890614864565b60405180910390fd5b610f5c838383611e75565b505050565b6000600a6000838152602001908152602001600020600101549050919050565b610f8a82610f61565b610f9381611bc0565b610f9d838361216e565b505050565b6000610fad836111e1565b8210610fee576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe5906148f6565b60405180910390fd5b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002054905092915050565b61104f611c99565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146110bc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110b390614988565b60405180910390fd5b6110c6828261224f565b5050565b6110e5838383604051806020016040528060008152506117a2565b505050565b60006110f4610ef4565b8210611135576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161112c90614a1a565b60405180910390fd5b60088281548110611149576111486144b9565b5b90600052602060002001549050919050565b60008061116783612331565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036111d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111cf90614a86565b60405180910390fd5b80915050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611251576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161124890614b18565b60405180910390fd5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000801b6112a581611bc0565b60008273ffffffffffffffffffffffffffffffffffffffff16476040516112cb90614b69565b60006040518083038185875af1925050503d8060008114611308576040519150601f19603f3d011682016040523d82523d6000602084013e61130d565b606091505b5050905080611351576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161134890614bca565b60405180910390fd5b505050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a661138081611bc0565b60005b828110156113b25761139f848261139a9190614bea565b611ae5565b80806113aa90614c1e565b915050611383565b50505050565b600081116113fb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113f290614cb2565b60405180910390fd5b80600e546114099190614cd2565b34101561144b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161144290614d86565b60405180910390fd5b80600f546114599190614bea565b6012805490501161149f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161149690614df2565b60405180910390fd5b60005b8181101561157a576000601060008154809291906114bf90614c1e565b919050559050600f60008154809291906114d890614c1e565b919050555083600c600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f360f498aa1f3d1dd6165e739ca66c0856a6adbe07c8908b10b9e28375005c7dc8160405161155e9190613e34565b60405180910390a150808061157290614c1e565b9150506114a2565b505050565b6060600061158c836111e1565b905060008167ffffffffffffffff8111156115aa576115a96137e7565b5b6040519080825280602002602001820160405280156115d85781602001602082028036833780820191505090505b50905060005b82811015611622576115f08582610fa2565b828281518110611603576116026144b9565b5b602002602001018181525050808061161a90614c1e565b9150506115de565b508092505050919050565b6000801b61163a81611bc0565b81600e819055505050565b6000600a600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6060600180546116bf9061469d565b80601f01602080910402602001604051908101604052809291908181526020018280546116eb9061469d565b80156117385780601f1061170d57610100808354040283529160200191611738565b820191906000526020600020905b81548152906001019060200180831161171b57829003601f168201915b5050505050905090565b6000600e54905090565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a661177681611bc0565b611780838361236e565b505050565b6000801b81565b61179e611797611c99565b838361238c565b5050565b6117b36117ad611c99565b83611de0565b6117f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117e990614864565b60405180910390fd5b6117fe848484846124f8565b50505050565b606061180f82611c4e565b6000611819612554565b905060008151116118395760405180602001604052806000815250611864565b8061184384612591565b604051602001611854929190614e4e565b6040516020818303038152906040525b915050919050565b600e543410156118b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118a890614d86565b60405180910390fd5b600f54601280549050116118fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118f190614ebe565b60405180910390fd5b60006010600081548092919061190f90614c1e565b919050559050600f600081548092919061192890614c1e565b919050555081600c600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f360f498aa1f3d1dd6165e739ca66c0856a6adbe07c8908b10b9e28375005c7dc816040516119ae9190613e34565b60405180910390a15050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6119e782610f61565b6119f081611bc0565b6119fa838361224f565b505050565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6000801b611aa081611bc0565b81601160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6611b0f81611bc0565b611b3b601160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168361236e565b60128290806001815401808255809150506001900390600052602060002001600090919091909150555050565b60606012805480602002602001604051908101604052809291908181526020018280548015611bb657602002820191906000526020600020905b815481526020019060010190808311611ba2575b5050505050905090565b611bd181611bcc611c99565b61265f565b50565b60007f7965db0b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480611c475750611c46826126e4565b5b9050919050565b611c578161275e565b611c96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c8d90614a86565b60405180910390fd5b50565b600033905090565b816004600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff16611d148361115b565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b611ddb8363a9059cbb60e01b8484604051602401611d79929190614ede565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061279f565b505050565b600080611dec8361115b565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480611e2e5750611e2d81856119ff565b5b80611e6c57508373ffffffffffffffffffffffffffffffffffffffff16611e5484610d59565b73ffffffffffffffffffffffffffffffffffffffff16145b91505092915050565b8273ffffffffffffffffffffffffffffffffffffffff16611e958261115b565b73ffffffffffffffffffffffffffffffffffffffff1614611eeb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ee290614f79565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611f5a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f519061500b565b60405180910390fd5b611f678383836001612867565b8273ffffffffffffffffffffffffffffffffffffffff16611f878261115b565b73ffffffffffffffffffffffffffffffffffffffff1614611fdd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fd490614f79565b60405180910390fd5b6004600082815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055506001600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a46121698383836001612879565b505050565b6121788282611645565b61224b576001600a600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506121f0611c99565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6122598282611645565b1561232d576000600a600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506122d2611c99565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45b5050565b60006002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b61238882826040518060200160405280600081525061287f565b5050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036123fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123f190615077565b60405180910390fd5b80600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516124eb9190613bed565b60405180910390a3505050565b612503848484611e75565b61250f848484846128da565b61254e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161254590615109565b60405180910390fd5b50505050565b60606040518060400160405280601d81526020017f68747470733a2f2f6e66742e6b656e7368692e696f2f6b6174616e612f000000815250905090565b6060600060016125a084612a61565b01905060008167ffffffffffffffff8111156125bf576125be6137e7565b5b6040519080825280601f01601f1916602001820160405280156125f15781602001600182028036833780820191505090505b509050600082602001820190505b600115612654578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8581612648576126476145ab565b5b049450600085036125ff575b819350505050919050565b6126698282611645565b6126e05761267681612bb4565b6126848360001c6020612be1565b6040516020016126959291906151c1565b6040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126d79190613c87565b60405180910390fd5b5050565b60007f780e9d63000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480612757575061275682612e1d565b5b9050919050565b60008073ffffffffffffffffffffffffffffffffffffffff1661278083612331565b73ffffffffffffffffffffffffffffffffffffffff1614159050919050565b6000612801826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612eff9092919063ffffffff16565b905060008151148061282357508080602001905181019061282291906143fa565b5b612862576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128599061526d565b60405180910390fd5b505050565b61287384848484612f17565b50505050565b50505050565b6128898383613075565b61289660008484846128da565b6128d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128cc90615109565b60405180910390fd5b505050565b60006128fb8473ffffffffffffffffffffffffffffffffffffffff16613292565b15612a54578373ffffffffffffffffffffffffffffffffffffffff1663150b7a02612924611c99565b8786866040518563ffffffff1660e01b8152600401612946949392919061528d565b6020604051808303816000875af192505050801561298257506040513d601f19601f8201168201806040525081019061297f91906152ee565b60015b612a04573d80600081146129b2576040519150601f19603f3d011682016040523d82523d6000602084013e6129b7565b606091505b5060008151036129fc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129f390615109565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614915050612a59565b600190505b949350505050565b600080600090507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612abf577a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008381612ab557612ab46145ab565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310612afc576d04ee2d6d415b85acef81000000008381612af257612af16145ab565b5b0492506020810190505b662386f26fc100008310612b2b57662386f26fc100008381612b2157612b206145ab565b5b0492506010810190505b6305f5e1008310612b54576305f5e1008381612b4a57612b496145ab565b5b0492506008810190505b6127108310612b79576127108381612b6f57612b6e6145ab565b5b0492506004810190505b60648310612b9c5760648381612b9257612b916145ab565b5b0492506002810190505b600a8310612bab576001810190505b80915050919050565b6060612bda8273ffffffffffffffffffffffffffffffffffffffff16601460ff16612be1565b9050919050565b606060006002836002612bf49190614cd2565b612bfe9190614bea565b67ffffffffffffffff811115612c1757612c166137e7565b5b6040519080825280601f01601f191660200182016040528015612c495781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612c8157612c806144b9565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612ce557612ce46144b9565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002612d259190614cd2565b612d2f9190614bea565b90505b6001811115612dcf577f3031323334353637383961626364656600000000000000000000000000000000600f861660108110612d7157612d706144b9565b5b1a60f81b828281518110612d8857612d876144b9565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c945080612dc890614582565b9050612d32565b5060008414612e13576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e0a90615367565b60405180910390fd5b8091505092915050565b60007f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480612ee857507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80612ef85750612ef7826132b5565b5b9050919050565b6060612f0e848460008561331f565b90509392505050565b612f23848484846133ec565b6001811115612f67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f5e906153f9565b60405180910390fd5b6000829050600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612fae57612fa9816133f2565b612fed565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614612fec57612feb858261343b565b5b5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361302f5761302a816135a8565b61306e565b8473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161461306d5761306c8482613679565b5b5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036130e4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130db90615465565b60405180910390fd5b6130ed8161275e565b1561312d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613124906154d1565b60405180910390fd5b61313b600083836001612867565b6131448161275e565b15613184576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161317b906154d1565b60405180910390fd5b6001600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a461328e600083836001612879565b5050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b606082471015613364576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161335b90615563565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161338d91906155b4565b60006040518083038185875af1925050503d80600081146133ca576040519150601f19603f3d011682016040523d82523d6000602084013e6133cf565b606091505b50915091506133e0878383876136f8565b92505050949350505050565b50505050565b6008805490506009600083815260200190815260200160002081905550600881908060018154018082558091505060019003906000526020600020016000909190919091505550565b60006001613448846111e1565b613452919061460b565b9050600060076000848152602001908152602001600020549050818114613537576000600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002054905080600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002081905550816007600083815260200190815260200160002081905550505b6007600084815260200190815260200160002060009055600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008381526020019081526020016000206000905550505050565b600060016008805490506135bc919061460b565b90506000600960008481526020019081526020016000205490506000600883815481106135ec576135eb6144b9565b5b90600052602060002001549050806008838154811061360e5761360d6144b9565b5b90600052602060002001819055508160096000838152602001908152602001600020819055506009600085815260200190815260200160002060009055600880548061365d5761365c61463f565b5b6001900381819060005260206000200160009055905550505050565b6000613684836111e1565b905081600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002081905550806007600084815260200190815260200160002081905550505050565b6060831561375a5760008351036137525761371285613292565b613751576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161374890615617565b60405180910390fd5b5b829050613765565b613764838361376d565b5b949350505050565b6000825111156137805781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137b49190613c87565b60405180910390fd5b6000604051905090565b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61381f826137d6565b810181811067ffffffffffffffff8211171561383e5761383d6137e7565b5b80604052505050565b60006138516137bd565b905061385d8282613816565b919050565b600067ffffffffffffffff82111561387d5761387c6137e7565b5b602082029050919050565b600080fd5b6000819050919050565b6138a08161388d565b81146138ab57600080fd5b50565b6000813590506138bd81613897565b92915050565b60006138d66138d184613862565b613847565b905080602084028301858111156138f0576138ef613888565b5b835b81811015613919578061390588826138ae565b8452602084019350506020810190506138f2565b5050509392505050565b600082601f830112613938576139376137d1565b5b60046139458482856138c3565b91505092915050565b600080fd5b600067ffffffffffffffff82111561396e5761396d6137e7565b5b613977826137d6565b9050602081019050919050565b82818337600083830152505050565b60006139a66139a184613953565b613847565b9050828152602081018484840111156139c2576139c161394e565b5b6139cd848285613984565b509392505050565b600082601f8301126139ea576139e96137d1565b5b81356139fa848260208601613993565b91505092915050565b600067ffffffffffffffff821115613a1e57613a1d6137e7565b5b602082029050919050565b6000613a3c613a3784613a03565b613847565b90508060208402830185811115613a5657613a55613888565b5b835b81811015613a7f5780613a6b88826138ae565b845260208401935050602081019050613a58565b5050509392505050565b600082601f830112613a9e57613a9d6137d1565b5b6002613aab848285613a29565b91505092915050565b60008060008060006101808688031215613ad157613ad06137c7565b5b6000613adf88828901613923565b955050608086013567ffffffffffffffff811115613b0057613aff6137cc565b5b613b0c888289016139d5565b94505060a0613b1d88828901613a89565b93505060e0613b2e88828901613923565b925050610160613b40888289016138ae565b9150509295509295909350565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613b8281613b4d565b8114613b8d57600080fd5b50565b600081359050613b9f81613b79565b92915050565b600060208284031215613bbb57613bba6137c7565b5b6000613bc984828501613b90565b91505092915050565b60008115159050919050565b613be781613bd2565b82525050565b6000602082019050613c026000830184613bde565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613c42578082015181840152602081019050613c27565b60008484015250505050565b6000613c5982613c08565b613c638185613c13565b9350613c73818560208601613c24565b613c7c816137d6565b840191505092915050565b60006020820190508181036000830152613ca18184613c4e565b905092915050565b6000819050919050565b613cbc81613ca9565b82525050565b6000602082019050613cd76000830184613cb3565b92915050565b600060208284031215613cf357613cf26137c7565b5b6000613d01848285016138ae565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613d3582613d0a565b9050919050565b613d4581613d2a565b82525050565b6000602082019050613d606000830184613d3c565b92915050565b613d6f81613d2a565b8114613d7a57600080fd5b50565b600081359050613d8c81613d66565b92915050565b60008060408385031215613da957613da86137c7565b5b6000613db785828601613d7d565b9250506020613dc8858286016138ae565b9150509250929050565b600080600060608486031215613deb57613dea6137c7565b5b6000613df986828701613d7d565b9350506020613e0a86828701613d7d565b9250506040613e1b868287016138ae565b9150509250925092565b613e2e8161388d565b82525050565b6000602082019050613e496000830184613e25565b92915050565b613e5881613ca9565b8114613e6357600080fd5b50565b600081359050613e7581613e4f565b92915050565b600060208284031215613e9157613e906137c7565b5b6000613e9f84828501613e66565b91505092915050565b60008060408385031215613ebf57613ebe6137c7565b5b6000613ecd85828601613e66565b9250506020613ede85828601613d7d565b9150509250929050565b600060208284031215613efe57613efd6137c7565b5b6000613f0c84828501613d7d565b91505092915050565b6000613f2082613d0a565b9050919050565b613f3081613f15565b8114613f3b57600080fd5b50565b600081359050613f4d81613f27565b92915050565b600060208284031215613f6957613f686137c7565b5b6000613f7784828501613f3e565b91505092915050565b60008060408385031215613f9757613f966137c7565b5b6000613fa5858286016138ae565b9250506020613fb6858286016138ae565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b613ff58161388d565b82525050565b60006140078383613fec565b60208301905092915050565b6000602082019050919050565b600061402b82613fc0565b6140358185613fcb565b935061404083613fdc565b8060005b838110156140715781516140588882613ffb565b975061406383614013565b925050600181019050614044565b5085935050505092915050565b600060208201905081810360008301526140988184614020565b905092915050565b6140a981613bd2565b81146140b457600080fd5b50565b6000813590506140c6816140a0565b92915050565b600080604083850312156140e3576140e26137c7565b5b60006140f185828601613d7d565b9250506020614102858286016140b7565b9150509250929050565b60008060008060808587031215614126576141256137c7565b5b600061413487828801613d7d565b945050602061414587828801613d7d565b9350506040614156878288016138ae565b925050606085013567ffffffffffffffff811115614177576141766137cc565b5b614183878288016139d5565b91505092959194509250565b600080604083850312156141a6576141a56137c7565b5b60006141b485828601613d7d565b92505060206141c585828601613d7d565b9150509250929050565b7f416c72656164792066756c66696c6c6564000000000000000000000000000000600082015250565b6000614205601183613c13565b9150614210826141cf565b602082019050919050565b60006020820190508181036000830152614234816141f8565b9050919050565b600060049050919050565b600081905092915050565b6000819050919050565b6000602082019050919050565b6142718161423b565b61427b8184614246565b925061428682614251565b8060005b838110156142b757815161429e8782613ffb565b96506142a98361425b565b92505060018101905061428a565b505050505050565b600081519050919050565b600082825260208201905092915050565b60006142e6826142bf565b6142f081856142ca565b9350614300818560208601613c24565b614309816137d6565b840191505092915050565b600060029050919050565b600081905092915050565b6000819050919050565b6000602082019050919050565b61434a81614314565b614354818461431f565b925061435f8261432a565b8060005b838110156143905781516143778782613ffb565b965061438283614334565b925050600181019050614363565b505050505050565b6000610160820190506143ae6000830187614268565b81810360808301526143c081866142db565b90506143cf60a0830185614341565b6143dc60e0830184614268565b95945050505050565b6000815190506143f4816140a0565b92915050565b6000602082840312156144105761440f6137c7565b5b600061441e848285016143e5565b91505092915050565b7f44656c6976657265642072616e646f6d6e657373206973206e6f742076616c6960008201527f6421000000000000000000000000000000000000000000000000000000000000602082015250565b6000614483602283613c13565b915061448e82614427565b604082019050919050565b600060208201905081810360008301526144b281614476565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006040820190506144fd6000830185613e25565b61450a6020830184613e25565b9392505050565b60008151905061452081613e4f565b92915050565b60006020828403121561453c5761453b6137c7565b5b600061454a84828501614511565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061458d8261388d565b9150600082036145a05761459f614553565b5b600182039050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006145e58261388d565b91506145f08361388d565b925082614600576145ff6145ab565b5b828206905092915050565b60006146168261388d565b91506146218361388d565b925082820390508181111561463957614638614553565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806146b557607f821691505b6020821081036146c8576146c761466e565b5b50919050565b7f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b600061472a602183613c13565b9150614735826146ce565b604082019050919050565b600060208201905081810360008301526147598161471d565b9050919050565b7f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60008201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000602082015250565b60006147bc603d83613c13565b91506147c782614760565b604082019050919050565b600060208201905081810360008301526147eb816147af565b9050919050565b7f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560008201527f72206f7220617070726f76656400000000000000000000000000000000000000602082015250565b600061484e602d83613c13565b9150614859826147f2565b604082019050919050565b6000602082019050818103600083015261487d81614841565b9050919050565b7f455243373231456e756d657261626c653a206f776e657220696e646578206f7560008201527f74206f6620626f756e6473000000000000000000000000000000000000000000602082015250565b60006148e0602b83613c13565b91506148eb82614884565b604082019050919050565b6000602082019050818103600083015261490f816148d3565b9050919050565b7f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008201527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015250565b6000614972602f83613c13565b915061497d82614916565b604082019050919050565b600060208201905081810360008301526149a181614965565b9050919050565b7f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60008201527f7574206f6620626f756e64730000000000000000000000000000000000000000602082015250565b6000614a04602c83613c13565b9150614a0f826149a8565b604082019050919050565b60006020820190508181036000830152614a33816149f7565b9050919050565b7f4552433732313a20696e76616c696420746f6b656e2049440000000000000000600082015250565b6000614a70601883613c13565b9150614a7b82614a3a565b602082019050919050565b60006020820190508181036000830152614a9f81614a63565b9050919050565b7f4552433732313a2061646472657373207a65726f206973206e6f74206120766160008201527f6c6964206f776e65720000000000000000000000000000000000000000000000602082015250565b6000614b02602983613c13565b9150614b0d82614aa6565b604082019050919050565b60006020820190508181036000830152614b3181614af5565b9050919050565b600081905092915050565b50565b6000614b53600083614b38565b9150614b5e82614b43565b600082019050919050565b6000614b7482614b46565b9150819050919050565b7f4661696c656420746f2073656e64204574686572000000000000000000000000600082015250565b6000614bb4601483613c13565b9150614bbf82614b7e565b602082019050919050565b60006020820190508181036000830152614be381614ba7565b9050919050565b6000614bf58261388d565b9150614c008361388d565b9250828201905080821115614c1857614c17614553565b5b92915050565b6000614c298261388d565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614c5b57614c5a614553565b5b600182019050919050565b7f43616e2774206d696e74207a65726f204e465473000000000000000000000000600082015250565b6000614c9c601483613c13565b9150614ca782614c66565b602082019050919050565b60006020820190508181036000830152614ccb81614c8f565b9050919050565b6000614cdd8261388d565b9150614ce88361388d565b9250828202614cf68161388d565b91508282048414831517614d0d57614d0c614553565b5b5092915050565b7f56616c7565206973206c6f776572207468616e20746865204e4654206d696e7460008201527f696e672070726963650000000000000000000000000000000000000000000000602082015250565b6000614d70602983613c13565b9150614d7b82614d14565b604082019050919050565b60006020820190508181036000830152614d9f81614d63565b9050919050565b7f4e6f7420656e6f75676820737570706c79206c65667400000000000000000000600082015250565b6000614ddc601683613c13565b9150614de782614da6565b602082019050919050565b60006020820190508181036000830152614e0b81614dcf565b9050919050565b600081905092915050565b6000614e2882613c08565b614e328185614e12565b9350614e42818560208601613c24565b80840191505092915050565b6000614e5a8285614e1d565b9150614e668284614e1d565b91508190509392505050565b7f4e6f206d6f7265204e46547320746f2073656c6c000000000000000000000000600082015250565b6000614ea8601483613c13565b9150614eb382614e72565b602082019050919050565b60006020820190508181036000830152614ed781614e9b565b9050919050565b6000604082019050614ef36000830185613d3c565b614f006020830184613e25565b9392505050565b7f4552433732313a207472616e736665722066726f6d20696e636f72726563742060008201527f6f776e6572000000000000000000000000000000000000000000000000000000602082015250565b6000614f63602583613c13565b9150614f6e82614f07565b604082019050919050565b60006020820190508181036000830152614f9281614f56565b9050919050565b7f4552433732313a207472616e7366657220746f20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b6000614ff5602483613c13565b915061500082614f99565b604082019050919050565b6000602082019050818103600083015261502481614fe8565b9050919050565b7f4552433732313a20617070726f766520746f2063616c6c657200000000000000600082015250565b6000615061601983613c13565b915061506c8261502b565b602082019050919050565b6000602082019050818103600083015261509081615054565b9050919050565b7f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560008201527f63656976657220696d706c656d656e7465720000000000000000000000000000602082015250565b60006150f3603283613c13565b91506150fe82615097565b604082019050919050565b60006020820190508181036000830152615122816150e6565b9050919050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b600061515f601783614e12565b915061516a82615129565b601782019050919050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b60006151ab601183614e12565b91506151b682615175565b601182019050919050565b60006151cc82615152565b91506151d88285614e1d565b91506151e38261519e565b91506151ef8284614e1d565b91508190509392505050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b6000615257602a83613c13565b9150615262826151fb565b604082019050919050565b600060208201905081810360008301526152868161524a565b9050919050565b60006080820190506152a26000830187613d3c565b6152af6020830186613d3c565b6152bc6040830185613e25565b81810360608301526152ce81846142db565b905095945050505050565b6000815190506152e881613b79565b92915050565b600060208284031215615304576153036137c7565b5b6000615312848285016152d9565b91505092915050565b7f537472696e67733a20686578206c656e67746820696e73756666696369656e74600082015250565b6000615351602083613c13565b915061535c8261531b565b602082019050919050565b6000602082019050818103600083015261538081615344565b9050919050565b7f455243373231456e756d657261626c653a20636f6e736563757469766520747260008201527f616e7366657273206e6f7420737570706f727465640000000000000000000000602082015250565b60006153e3603583613c13565b91506153ee82615387565b604082019050919050565b60006020820190508181036000830152615412816153d6565b9050919050565b7f4552433732313a206d696e7420746f20746865207a65726f2061646472657373600082015250565b600061544f602083613c13565b915061545a82615419565b602082019050919050565b6000602082019050818103600083015261547e81615442565b9050919050565b7f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000600082015250565b60006154bb601c83613c13565b91506154c682615485565b602082019050919050565b600060208201905081810360008301526154ea816154ae565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b600061554d602683613c13565b9150615558826154f1565b604082019050919050565b6000602082019050818103600083015261557c81615540565b9050919050565b600061558e826142bf565b6155988185614b38565b93506155a8818560208601613c24565b80840191505092915050565b60006155c08284615583565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000615601601d83613c13565b915061560c826155cb565b602082019050919050565b60006020820190508181036000830152615630816155f4565b905091905056fea264697066735822122072dc244ce928442add844615cf261d0c664474398a1d004fc322961123a59dc764736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002103e8de8573cb66fba7ac716eb8ef0e2b0e2839fd32ed09fb4a44c22ae38e696af600000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : publicKey (bytes): 0x03e8de8573cb66fba7ac716eb8ef0e2b0e2839fd32ed09fb4a44c22ae38e696af6
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000021
Arg [2] : 03e8de8573cb66fba7ac716eb8ef0e2b0e2839fd32ed09fb4a44c22ae38e696a
Arg [3] : f600000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.