Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
Battleshipz
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721RoyaltyUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/Base64Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/cryptography/MerkleProofUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "closedsea/src/OperatorFilterer.sol"; import "./ShipSVGUpgradeable.sol"; import "./ShipAssetsUpgradeable.sol"; import "./ShipArmoryUpgradeable.sol"; contract Battleshipz is Initializable, ERC721Upgradeable, OperatorFilterer, PausableUpgradeable, AccessControlUpgradeable, ERC721RoyaltyUpgradeable, ReentrancyGuardUpgradeable { using CountersUpgradeable for CountersUpgradeable.Counter; ShipAssetsUpgradeable public shipAssetsUpgradeable; ShipSVGUpgradeable public shipSVGUpgradeable; bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); CountersUpgradeable.Counter private _tokenIdCounter; /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } mapping(uint256 => uint256) internal seeds; uint256 public maxSupply; uint256 public totalMinted; uint256 public mintPrice; uint256 public maxMint; string public saleType; bool public publicSaleLive; bool public whitelistSaleLive; uint256 public whitelistSupply; uint256 public publicSupply; bytes32 public merkleRoot; mapping(address => bool) public whitelistClaimed; bool public operatorFilteringEnabled; ShipArmoryUpgradeable public shipArmoryUpgradeable; // @deprecated -- use shipArmoryUpgradeable instead mapping(address => mapping(uint256 => ShipArmoryUpgradeable.EquippedPart[])) public equippedUserParts; // @deprecated -- use shipArmoryUpgradeable instead mapping(address => mapping(uint256 => bytes32)) public equippedUserSkins; function initialize( ShipSVGUpgradeable _shipSVGUpgradeable, ShipAssetsUpgradeable _shipAssetsUpgradeable ) public initializer { __ERC721_init("Battleshipz", "SHIPZ"); __Pausable_init(); __AccessControl_init(); shipSVGUpgradeable = _shipSVGUpgradeable; shipAssetsUpgradeable = _shipAssetsUpgradeable; _registerForOperatorFiltering(); operatorFilteringEnabled = true; // Set royalty receiver to the contract creator, // at 6.5% (default denominator is 10000). _setDefaultRoyalty(msg.sender, 650); _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); _grantRole(PAUSER_ROLE, msg.sender); maxSupply = 10000; totalMinted = 0; mintPrice = 0.005 ether; maxMint = 5; saleType = "whitelist"; publicSaleLive = false; whitelistSaleLive = false; whitelistSupply = 5000; publicSupply = 5000; merkleRoot = 0xb1fdc7a0eaa5b56209817635a86bed9e86c149fbb2a0dff83a2af2a797065e70; } function initializeV2( ShipArmoryUpgradeable _shipArmoryUpgradeable ) external onlyRole(DEFAULT_ADMIN_ROLE) { shipArmoryUpgradeable = _shipArmoryUpgradeable; } function _beforeTokenTransfer( address from, address to, uint256 tokenId, uint256 batchSize ) internal override whenNotPaused { super._beforeTokenTransfer(from, to, tokenId, batchSize); } function createPartTrait( ShipAssetsUpgradeable.Part[7] memory parts ) internal pure returns (string memory) { string memory partTraits = ""; for (uint i = 0; i < parts.length; i++) { if (equal(parts[i].name, "Empty")) { continue; } partTraits = string.concat( partTraits, string( abi.encodePacked( partTraits, '{"trait_type": "', parts[i].name, '",', '"value": "', parts[i].rarity, '"},' ) ) ); } bytes memory bStr = bytes(partTraits); bStr[bStr.length - 1] = " "; partTraits = string(bStr); return partTraits; } function createPartTraits( ShipAssetsUpgradeable.Battleship memory ship ) internal pure returns (string memory) { return string.concat( createPartTrait(ship.outerParts), ",", createPartTrait(ship.innerParts), ",", createPartTrait(ship.middleParts) ); } function getRarityWeight( string memory rarity ) internal pure returns (uint) { if (equal(rarity, "Common")) { return 1; } else if (equal(rarity, "Uncommon")) { return 2; } else if (equal(rarity, "Rare")) { return 3; } else if (equal(rarity, "Epic")) { return 4; } else if (equal(rarity, "Legendary")) { return 5; } else { return 0; } } function getTotalRarityWeightForRow( ShipAssetsUpgradeable.Part[7] memory parts ) public pure returns (uint256, uint256) { uint256 total = 0; uint256 nonEmptyParts = 0; for (uint256 i = 0; i < parts.length; i++) { if (!equal(parts[i].name, "Empty")) { uint256 v = getRarityWeight(parts[i].rarity); total += v; nonEmptyParts++; } } return (total, nonEmptyParts); } function getShipPartsRarity( ShipAssetsUpgradeable.Battleship memory ship ) public pure returns (string memory) { (uint256 outerTotal, uint256 outerCount) = getTotalRarityWeightForRow( ship.outerParts ); (uint256 innerTotal, uint256 innerCount) = getTotalRarityWeightForRow( ship.innerParts ); (uint256 middleTotal, uint256 middleCount) = getTotalRarityWeightForRow( ship.middleParts ); uint256 totalWeight = outerTotal + innerTotal + middleTotal; uint256 totalParts = outerCount + innerCount + middleCount; uint256 maxTotalWeight = totalParts * 5; uint256 normalizedWeightedRarity = (totalWeight * 100) / maxTotalWeight; if (normalizedWeightedRarity >= 0 && normalizedWeightedRarity <= 20) { return "Common"; } else if ( normalizedWeightedRarity > 20 && normalizedWeightedRarity <= 40 ) { return "Uncommon"; } else if ( normalizedWeightedRarity > 40 && normalizedWeightedRarity <= 60 ) { return "Rare"; } else if ( normalizedWeightedRarity > 60 && normalizedWeightedRarity <= 80 ) { return "Epic"; } else if ( normalizedWeightedRarity > 80 && normalizedWeightedRarity <= 100 ) { return "Legendary"; } else { return "Unknown"; } } function tokenURI( uint256 tokenId ) public view override returns (string memory) { uint256 seed = seeds[tokenId]; address ownerAddr = ownerOf(tokenId); ShipAssetsUpgradeable.Battleship memory ship = shipArmoryUpgradeable .buildShipWithEquippedItems( seed, shipArmoryUpgradeable.getEquippedUserParts(ownerAddr, tokenId), shipArmoryUpgradeable.getEquippedUserSkin(ownerAddr, tokenId) ); string memory svgElem = shipSVGUpgradeable.createBattleshipSVG(ship); string memory json = Base64Upgradeable.encode( bytes( string( abi.encodePacked( '{"name": "Battleshipz: ', StringsUpgradeable.toString(tokenId), '", "description": "An ASCII-animated space adventure, invade the blockchain with 100% On-Chain Battleshipz.", "image": "data:image/svg+xml;base64,', Base64Upgradeable.encode(bytes(svgElem)), '","attributes": [{"trait_type":"Class", "value": "', ship.classType, '"}, {"trait_type": "Parts Rarity", "value": "', getShipPartsRarity(ship), '"}, {"trait_type": "Skin", "value": "', ship.skin.name, '"}', "]}" ) ) ) ); string memory output = ""; output = string( abi.encodePacked("data:application/json;base64,", json) ); return output; } function tokensOfOwner( address owner ) public view returns (uint256[] memory) { uint256 tokenCount = balanceOf(owner); uint256[] memory tokens = new uint256[](tokenCount); uint256 index = 0; for (uint256 i = 0; i < maxSupply; i++) { if (index == tokenCount) { break; } if (_exists(i) && ownerOf(i) == owner) { tokens[index] = i; index++; } } return tokens; } // transfer functions function setApprovalForAll( address operator, bool approved ) public override onlyAllowedOperatorApproval(operator) { super.setApprovalForAll(operator, approved); } function approve( address operator, uint256 tokenId ) public override onlyAllowedOperatorApproval(operator) { super.approve(operator, tokenId); } function transferFrom( address from, address to, uint256 tokenId ) public override onlyAllowedOperator(from) { super.transferFrom(from, to, tokenId); } function safeTransferFrom( address from, address to, uint256 tokenId ) public override onlyAllowedOperator(from) { super.safeTransferFrom(from, to, tokenId); } function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory data ) public override onlyAllowedOperator(from) { super.safeTransferFrom(from, to, tokenId, data); } // admin functions function setMerkleRoot( bytes32 _merkleRoot ) public onlyRole(DEFAULT_ADMIN_ROLE) { merkleRoot = _merkleRoot; } function withdraw( uint amount ) external onlyRole(DEFAULT_ADMIN_ROLE) nonReentrant { (bool success, ) = (msg.sender).call{value: amount}(""); require(success, "Transfer failed!"); } function pause() public onlyRole(PAUSER_ROLE) { _pause(); } function unpause() public onlyRole(PAUSER_ROLE) { _unpause(); } function setOperatorFilteringEnabled( bool value ) public onlyRole(DEFAULT_ADMIN_ROLE) { operatorFilteringEnabled = value; } function _operatorFilteringEnabled() internal view override returns (bool) { return operatorFilteringEnabled; } function setDefaultRoyalty( address receiver, uint96 feeNumerator ) public onlyRole(DEFAULT_ADMIN_ROLE) { _setDefaultRoyalty(receiver, feeNumerator); } function setPublicSaleLive( bool isLive ) external onlyRole(DEFAULT_ADMIN_ROLE) { if (isLive) { saleType = "public"; } publicSaleLive = isLive; } function setWhitelistSaleLive( bool isLive ) public onlyRole(DEFAULT_ADMIN_ROLE) { if (isLive) { saleType = "whitelist"; } whitelistSaleLive = isLive; } function setPublicSupply( uint256 _publicSupply ) external onlyRole(DEFAULT_ADMIN_ROLE) { publicSupply = _publicSupply; } function setWhitelistSupply( uint256 _whitelistSupply ) external onlyRole(DEFAULT_ADMIN_ROLE) { whitelistSupply = _whitelistSupply; } function setMintPrice( uint256 _mintPrice ) external onlyRole(DEFAULT_ADMIN_ROLE) { mintPrice = _mintPrice; } function setMaxMint( uint256 _maxMint ) external onlyRole(DEFAULT_ADMIN_ROLE) { maxMint = _maxMint; } modifier nonContract() { require(tx.origin == msg.sender, "Contracts not allowed to mint"); _; } function generateSeed(uint256 tokenId) public view returns (uint256) { return uint256( keccak256( abi.encodePacked( tokenId, blockhash(block.number - 1), block.timestamp ) ) ); } function getSeed(uint256 tokenId) public view returns (uint256) { return seeds[tokenId]; } function whitelistMint( uint256 quantity, bytes32[] calldata _merkleProof ) external payable nonContract { require( balanceOf(_msgSender()) <= maxMint, "Max mint per wallet reached" ); require(whitelistSaleLive, "Wl sale not live yet"); bytes32 leaf = keccak256(abi.encodePacked(msg.sender)); require( MerkleProofUpgradeable.verify(_merkleProof, merkleRoot, leaf), "Not whitelisted" ); require(quantity <= maxMint, "Max mint exceeded"); unchecked { require(totalMinted + quantity <= maxSupply, "Exceeds max supply"); require( totalMinted + quantity <= whitelistSupply, "Max wl mint exceeded" ); } require(msg.value >= quantity * mintPrice, "Not enough ether"); for (uint32 i; i < quantity; ) { uint256 tokenId = _tokenIdCounter.current(); _tokenIdCounter.increment(); uint256 seed = generateSeed(tokenId); seeds[tokenId] = seed; _safeMint(_msgSender(), tokenId); unchecked { ++totalMinted; ++i; } } } function publicMint( uint256 quantity ) external payable nonContract nonReentrant { require( balanceOf(_msgSender()) <= maxMint, "Max mint per wallet reached" ); require(publicSaleLive, "Public sale not live yet"); require(quantity <= maxMint, "Max mint exceeded"); unchecked { require(totalMinted + quantity <= maxSupply, "Exceeds max supply"); require( totalMinted + quantity <= publicSupply, "Max public mint exceeded" ); } require(msg.value >= quantity * mintPrice, "Not enough ether"); for (uint32 i; i < quantity; ) { uint256 tokenId = _tokenIdCounter.current(); _tokenIdCounter.increment(); uint256 seed = generateSeed(tokenId); seeds[tokenId] = seed; _safeMint(_msgSender(), tokenId); unchecked { ++totalMinted; ++i; } } } function setShipSVGUpgradeable( ShipSVGUpgradeable _shipSVGUpgradeable ) external onlyRole(DEFAULT_ADMIN_ROLE) { shipSVGUpgradeable = _shipSVGUpgradeable; } function setShipAssetsUpgradeable( ShipAssetsUpgradeable _shipAssetsUpgradeable ) external onlyRole(DEFAULT_ADMIN_ROLE) { shipAssetsUpgradeable = _shipAssetsUpgradeable; } function equal( string memory a, string memory b ) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } // The following functions are overrides required by Solidity. function supportsInterface( bytes4 interfaceId ) public view override( ERC721Upgradeable, AccessControlUpgradeable, ERC721RoyaltyUpgradeable ) returns (bool) { return super.supportsInterface(interfaceId); } function _burn( uint256 tokenId ) internal virtual override(ERC721Upgradeable, ERC721RoyaltyUpgradeable) { super._burn(tokenId); _resetTokenRoyalty(tokenId); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControlUpgradeable.sol"; import "../utils/ContextUpgradeable.sol"; import "../utils/StringsUpgradeable.sol"; import "../utils/introspection/ERC165Upgradeable.sol"; import "../proxy/utils/Initializable.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: * * ``` * 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}: * * ``` * 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. */ abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable { function __AccessControl_init() internal onlyInitializing { } function __AccessControl_init_unchained() internal onlyInitializing { } 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(IAccessControlUpgradeable).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 ", StringsUpgradeable.toHexString(account), " is missing role ", StringsUpgradeable.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()); } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// 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 IAccessControlUpgradeable { /** * @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 // OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165Upgradeable.sol"; /** * @dev Interface for the NFT Royalty Standard. * * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal * support for royalty payments across all NFT marketplaces and ecosystem participants. * * _Available since v4.5._ */ interface IERC2981Upgradeable is IERC165Upgradeable { /** * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. */ function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal onlyInitializing { __Pausable_init_unchained(); } function __Pausable_init_unchained() internal onlyInitializing { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/common/ERC2981.sol) pragma solidity ^0.8.0; import "../../interfaces/IERC2981Upgradeable.sol"; import "../../utils/introspection/ERC165Upgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information. * * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first. * * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the * fee is specified in basis points by default. * * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. * * _Available since v4.5._ */ abstract contract ERC2981Upgradeable is Initializable, IERC2981Upgradeable, ERC165Upgradeable { function __ERC2981_init() internal onlyInitializing { } function __ERC2981_init_unchained() internal onlyInitializing { } struct RoyaltyInfo { address receiver; uint96 royaltyFraction; } RoyaltyInfo private _defaultRoyaltyInfo; mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165Upgradeable, ERC165Upgradeable) returns (bool) { return interfaceId == type(IERC2981Upgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @inheritdoc IERC2981Upgradeable */ function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view virtual override returns (address, uint256) { RoyaltyInfo memory royalty = _tokenRoyaltyInfo[_tokenId]; if (royalty.receiver == address(0)) { royalty = _defaultRoyaltyInfo; } uint256 royaltyAmount = (_salePrice * royalty.royaltyFraction) / _feeDenominator(); return (royalty.receiver, royaltyAmount); } /** * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an * override. */ function _feeDenominator() internal pure virtual returns (uint96) { return 10000; } /** * @dev Sets the royalty information that all ids in this contract will default to. * * Requirements: * * - `receiver` cannot be the zero address. * - `feeNumerator` cannot be greater than the fee denominator. */ function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); require(receiver != address(0), "ERC2981: invalid receiver"); _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator); } /** * @dev Removes default royalty information. */ function _deleteDefaultRoyalty() internal virtual { delete _defaultRoyaltyInfo; } /** * @dev Sets the royalty information for a specific token id, overriding the global default. * * Requirements: * * - `receiver` cannot be the zero address. * - `feeNumerator` cannot be greater than the fee denominator. */ function _setTokenRoyalty( uint256 tokenId, address receiver, uint96 feeNumerator ) internal virtual { require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); require(receiver != address(0), "ERC2981: Invalid parameters"); _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator); } /** * @dev Resets royalty information for the token id back to the global default. */ function _resetTokenRoyalty(uint256 tokenId) internal virtual { delete _tokenRoyaltyInfo[tokenId]; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[48] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.2) (token/ERC721/ERC721.sol) pragma solidity ^0.8.0; import "./IERC721Upgradeable.sol"; import "./IERC721ReceiverUpgradeable.sol"; import "./extensions/IERC721MetadataUpgradeable.sol"; import "../../utils/AddressUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import "../../utils/StringsUpgradeable.sol"; import "../../utils/introspection/ERC165Upgradeable.sol"; import "../../proxy/utils/Initializable.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 ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable { using AddressUpgradeable for address; using StringsUpgradeable 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. */ function __ERC721_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC721_init_unchained(name_, symbol_); } function __ERC721_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) { return interfaceId == type(IERC721Upgradeable).interfaceId || interfaceId == type(IERC721MetadataUpgradeable).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 = ERC721Upgradeable.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 = ERC721Upgradeable.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 = ERC721Upgradeable.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId, 1); // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook owner = ERC721Upgradeable.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(ERC721Upgradeable.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(ERC721Upgradeable.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(ERC721Upgradeable.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 IERC721ReceiverUpgradeable(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { return retval == IERC721ReceiverUpgradeable.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; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[44] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Royalty.sol) pragma solidity ^0.8.0; import "../ERC721Upgradeable.sol"; import "../../common/ERC2981Upgradeable.sol"; import "../../../utils/introspection/ERC165Upgradeable.sol"; import "../../../proxy/utils/Initializable.sol"; /** * @dev Extension of ERC721 with the ERC2981 NFT Royalty Standard, a standardized way to retrieve royalty payment * information. * * Royalty information can be specified globally for all token ids via {ERC2981-_setDefaultRoyalty}, and/or individually for * specific token ids via {ERC2981-_setTokenRoyalty}. The latter takes precedence over the first. * * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. * * _Available since v4.5._ */ abstract contract ERC721RoyaltyUpgradeable is Initializable, ERC2981Upgradeable, ERC721Upgradeable { function __ERC721Royalty_init() internal onlyInitializing { } function __ERC721Royalty_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Upgradeable, ERC2981Upgradeable) returns (bool) { return super.supportsInterface(interfaceId); } /** * @dev See {ERC721-_burn}. This override additionally clears the royalty information for the token. */ function _burn(uint256 tokenId) internal virtual override { super._burn(tokenId); _resetTokenRoyalty(tokenId); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721Upgradeable.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721MetadataUpgradeable is IERC721Upgradeable { /** * @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 IERC721ReceiverUpgradeable { /** * @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.8.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165Upgradeable.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721Upgradeable is IERC165Upgradeable { /** * @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.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [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://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return 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 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 (last updated v4.7.0) (utils/Base64.sol) pragma solidity ^0.8.0; /** * @dev Provides a set of functions to operate with Base64 strings. * * _Available since v4.5._ */ library Base64Upgradeable { /** * @dev Base64 Encoding/Decoding Table */ string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** * @dev Converts a `bytes` to its Bytes64 `string` representation. */ function encode(bytes memory data) internal pure returns (string memory) { /** * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol */ if (data.length == 0) return ""; // Loads the table into memory string memory table = _TABLE; // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter // and split into 4 numbers of 6 bits. // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up // - `data.length + 2` -> Round up // - `/ 3` -> Number of 3-bytes chunks // - `4 *` -> 4 characters for each chunk string memory result = new string(4 * ((data.length + 2) / 3)); /// @solidity memory-safe-assembly assembly { // Prepare the lookup table (skip the first "length" byte) let tablePtr := add(table, 1) // Prepare result pointer, jump over length let resultPtr := add(result, 32) // Run over the input, 3 bytes at a time for { let dataPtr := data let endPtr := add(data, mload(data)) } lt(dataPtr, endPtr) { } { // Advance 3 bytes dataPtr := add(dataPtr, 3) let input := mload(dataPtr) // To write each character, shift the 3 bytes (18 bits) chunk // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) // and apply logical AND with 0x3F which is the number of // the previous character in the ASCII table prior to the Base64 Table // The result is then added to the table to get the character to write, // and finally write it in the result pointer but with a left shift // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) resultPtr := add(resultPtr, 1) // Advance mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) resultPtr := add(resultPtr, 1) // Advance mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) resultPtr := add(resultPtr, 1) // Advance mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) resultPtr := add(resultPtr, 1) // Advance } // When data `bytes` is not exactly 3 bytes long // it is padded with `=` characters at the end switch mod(mload(data), 3) case 1 { mstore8(sub(resultPtr, 1), 0x3d) mstore8(sub(resultPtr, 2), 0x3d) } case 2 { mstore8(sub(resultPtr, 1), 0x3d) } } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// 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 CountersUpgradeable { 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.8.0) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.0; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The tree and the proofs can be generated using our * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. * You will find a quickstart guide in the readme. * * WARNING: You should avoid using leaf values that are 64 bytes long prior to * hashing, or use a hash function other than keccak256 for hashing leaves. * This is because the concatenation of a sorted pair of internal nodes in * the merkle tree could be reinterpreted as a leaf value. * OpenZeppelin's JavaScript library generates merkle trees that are safe * against this attack out of the box. */ library MerkleProofUpgradeable { /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify( bytes32[] memory proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProof(proof, leaf) == root; } /** * @dev Calldata version of {verify} * * _Available since v4.7._ */ function verifyCalldata( bytes32[] calldata proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProofCalldata(proof, leaf) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. When processing the proof, the pairs * of leafs & pre-images are assumed to be sorted. * * _Available since v4.4._ */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Calldata version of {processProof} * * _Available since v4.7._ */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function multiProofVerify( bytes32[] memory proof, bool[] memory proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProof(proof, proofFlags, leaves) == root; } /** * @dev Calldata version of {multiProofVerify} * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function multiProofVerifyCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProofCalldata(proof, proofFlags, leaves) == root; } /** * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false * respectively. * * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). * * _Available since v4.7._ */ function processMultiProof( bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function processMultiProofCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _efficientHash(a, b) : _efficientHash(b, a); } function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165Upgradeable.sol"; import "../../proxy/utils/Initializable.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 ERC165Upgradeable is Initializable, IERC165Upgradeable { function __ERC165_init() internal onlyInitializing { } function __ERC165_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165Upgradeable).interfaceId; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// 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 IERC165Upgradeable { /** * @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/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/MathUpgradeable.sol"; /** * @dev String operations. */ library StringsUpgradeable { 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 = MathUpgradeable.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 `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, MathUpgradeable.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); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Optimized and flexible operator filterer to abide to OpenSea's /// mandatory on-chain royalty enforcement in order for new collections to /// receive royalties. /// For more information, see: /// See: https://github.com/ProjectOpenSea/operator-filter-registry abstract contract OperatorFilterer { /// @dev The default OpenSea operator blocklist subscription. address internal constant _DEFAULT_SUBSCRIPTION = 0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6; /// @dev The OpenSea operator filter registry. address internal constant _OPERATOR_FILTER_REGISTRY = 0x000000000000AAeB6D7670E522A718067333cd4E; /// @dev Registers the current contract to OpenSea's operator filter, /// and subscribe to the default OpenSea operator blocklist. /// Note: Will not revert nor update existing settings for repeated registration. function _registerForOperatorFiltering() internal virtual { _registerForOperatorFiltering(_DEFAULT_SUBSCRIPTION, true); } /// @dev Registers the current contract to OpenSea's operator filter. /// Note: Will not revert nor update existing settings for repeated registration. function _registerForOperatorFiltering(address subscriptionOrRegistrantToCopy, bool subscribe) internal virtual { /// @solidity memory-safe-assembly assembly { let functionSelector := 0x7d3e3dbe // `registerAndSubscribe(address,address)`. // Clean the upper 96 bits of `subscriptionOrRegistrantToCopy` in case they are dirty. subscriptionOrRegistrantToCopy := shr(96, shl(96, subscriptionOrRegistrantToCopy)) for {} iszero(subscribe) {} { if iszero(subscriptionOrRegistrantToCopy) { functionSelector := 0x4420e486 // `register(address)`. break } functionSelector := 0xa0af2903 // `registerAndCopyEntries(address,address)`. break } // Store the function selector. mstore(0x00, shl(224, functionSelector)) // Store the `address(this)`. mstore(0x04, address()) // Store the `subscriptionOrRegistrantToCopy`. mstore(0x24, subscriptionOrRegistrantToCopy) // Register into the registry. if iszero(call(gas(), _OPERATOR_FILTER_REGISTRY, 0, 0x00, 0x44, 0x00, 0x04)) { // If the function selector has not been overwritten, // it is an out-of-gas error. if eq(shr(224, mload(0x00)), functionSelector) { // To prevent gas under-estimation. revert(0, 0) } } // Restore the part of the free memory pointer that was overwritten, // which is guaranteed to be zero, because of Solidity's memory size limits. mstore(0x24, 0) } } /// @dev Modifier to guard a function and revert if the caller is a blocked operator. modifier onlyAllowedOperator(address from) virtual { if (from != msg.sender) { if (!_isPriorityOperator(msg.sender)) { if (_operatorFilteringEnabled()) _revertIfBlocked(msg.sender); } } _; } /// @dev Modifier to guard a function from approving a blocked operator.. modifier onlyAllowedOperatorApproval(address operator) virtual { if (!_isPriorityOperator(operator)) { if (_operatorFilteringEnabled()) _revertIfBlocked(operator); } _; } /// @dev Helper function that reverts if the `operator` is blocked by the registry. function _revertIfBlocked(address operator) private view { /// @solidity memory-safe-assembly assembly { // Store the function selector of `isOperatorAllowed(address,address)`, // shifted left by 6 bytes, which is enough for 8tb of memory. // We waste 6-3 = 3 bytes to save on 6 runtime gas (PUSH1 0x224 SHL). mstore(0x00, 0xc6171134001122334455) // Store the `address(this)`. mstore(0x1a, address()) // Store the `operator`. mstore(0x3a, operator) // `isOperatorAllowed` always returns true if it does not revert. if iszero(staticcall(gas(), _OPERATOR_FILTER_REGISTRY, 0x16, 0x44, 0x00, 0x00)) { // Bubble up the revert if the staticcall reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } // We'll skip checking if `from` is inside the blacklist. // Even though that can block transferring out of wrapper contracts, // we don't want tokens to be stuck. // Restore the part of the free memory pointer that was overwritten, // which is guaranteed to be zero, if less than 8tb of memory is used. mstore(0x3a, 0) } } /// @dev For deriving contracts to override, so that operator filtering /// can be turned on / off. /// Returns true by default. function _operatorFilteringEnabled() internal view virtual returns (bool) { return true; } /// @dev For deriving contracts to override, so that preferred marketplaces can /// skip operator filtering, helping users save gas. /// Returns false for all inputs by default. function _isPriorityOperator(address) internal view virtual returns (bool) { return false; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import "./ShipAssetsUpgradeable.sol"; import "./Battleshipz.sol"; import "./ShipBuilderUpgradeable.sol"; contract ShipArmoryUpgradeable is Initializable, AccessControlUpgradeable { /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } ShipAssetsUpgradeable public shipAssetsUpgradeable; bytes32[] public partIds; mapping(bytes32 => ShipAssetsUpgradeable.Part) public parts; mapping(address => bytes32[]) public userParts; bytes32[] public skinIds; mapping(bytes32 => ShipAssetsUpgradeable.Skin) public skins; mapping(address => bytes32[]) public userSkins; struct EquippedPart { bytes32 partId; uint256 x; uint256 y; } struct RedeemAndEquipData { uint256 tokenId; bytes32 skinId; EquippedPart part; bytes32 uid; uint8 v; bytes32 r; bytes32 s; } mapping(address => mapping(uint256 => EquippedPart[])) public equippedUserParts; // @deprecated -- use shipArmoryUpgradeable instead mapping(address => mapping(uint256 => bytes32)) public equippedUserSkins; address rewardSigner; mapping(bytes32 => bool) private usedSignatures; Battleshipz public battleshipz; ShipBuilderUpgradeable public shipBuilderUpgradeable; function initialize( ShipAssetsUpgradeable _shipAssetsUpgradeable ) public initializer { __AccessControl_init(); _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); shipAssetsUpgradeable = _shipAssetsUpgradeable; } function initializeV2( Battleshipz _battleshipz, ShipBuilderUpgradeable _shipBuilderUpgradeable, address _rewardSigner ) external onlyRole(DEFAULT_ADMIN_ROLE) { rewardSigner = _rewardSigner; battleshipz = _battleshipz; shipBuilderUpgradeable = _shipBuilderUpgradeable; } function setRewardSigner( address _rewardSigner ) external onlyRole(DEFAULT_ADMIN_ROLE) { rewardSigner = _rewardSigner; } function createEquippedPart( bytes32 partId, uint256 x, uint256 y ) public pure returns (EquippedPart memory) { return EquippedPart({partId: partId, x: x, y: y}); } function buildShipWithEquippedItems( uint256 seed, EquippedPart[] memory equippedParts, bytes32 equippedSkinId ) public view returns (ShipAssetsUpgradeable.Battleship memory) { // Build the ship using the normal buildBattleship function ShipAssetsUpgradeable.Battleship memory battleship = shipBuilderUpgradeable.buildBattleship(seed); // Override the parts with the equipped parts following the rules for (uint256 i = 0; i < equippedParts.length; i++) { EquippedPart memory equippedPart = equippedParts[i]; ShipAssetsUpgradeable.Part memory part = parts[ equippedParts[i].partId ]; if (isPartCompatible(seed, equippedParts[i])) { if (equippedPart.x == 0) { battleship.outerParts[equippedPart.y] = part; } else if (equippedPart.x == 1) { battleship.innerParts[equippedPart.y] = part; } else if (equippedPart.x == 2) { battleship.middleParts[equippedPart.y] = part; } } } if (equippedSkinId != bytes32(0)) { battleship.skin = skins[equippedSkinId]; } return battleship; } function isPartCompatible( uint256 seed, EquippedPart memory equippedPart ) public view returns (bool) { ShipAssetsUpgradeable.Battleship memory battleship = shipBuilderUpgradeable.buildBattleship(seed); ShipAssetsUpgradeable.Part memory part = parts[equippedPart.partId]; // Check if x, y index is within bounds if ( equippedPart.x >= 0 && equippedPart.x < 3 && equippedPart.y >= 0 && equippedPart.y < 7 ) { // Get the part at the specified x, y index ShipAssetsUpgradeable.Part memory targetPart; if (equippedPart.x == 0) { targetPart = battleship.outerParts[equippedPart.y]; } else if (equippedPart.x == 1) { targetPart = battleship.innerParts[equippedPart.y]; } else if (equippedPart.x == 2) { targetPart = battleship.middleParts[equippedPart.y]; } if ( keccak256(bytes(part.name)) == keccak256(bytes("Cosmetic")) && keccak256(bytes(targetPart.name)) == keccak256(bytes("Empty")) ) { return true; } // Check if the target part's name matches the equipped part's name if ( keccak256(bytes(targetPart.name)) == keccak256(bytes(part.name)) ) { return true; } } return false; } function getUserParts( address _user ) public view returns (ShipAssetsUpgradeable.Part[] memory) { uint256 numberOfParts = userParts[_user].length; ShipAssetsUpgradeable.Part[] memory userPartsArray = new ShipAssetsUpgradeable.Part[]( numberOfParts ); for (uint256 i = 0; i < numberOfParts; i++) { userPartsArray[i] = parts[userParts[_user][i]]; } return userPartsArray; } function getAllParts() public view returns (ShipAssetsUpgradeable.Part[] memory) { uint256 numberOfParts = partIds.length; ShipAssetsUpgradeable.Part[] memory allParts = new ShipAssetsUpgradeable.Part[](numberOfParts); for (uint256 i = 0; i < numberOfParts; i++) { allParts[i] = parts[partIds[i]]; } return allParts; } function batchAddParts( ShipAssetsUpgradeable.Part[] memory _parts ) external onlyRole(DEFAULT_ADMIN_ROLE) returns (bytes32[] memory) { bytes32[] memory newPartIds = new bytes32[](_parts.length); for (uint256 i = 0; i < _parts.length; i++) { bytes32 uniqueIdentifier = keccak256( abi.encodePacked( _parts[i].name, _parts[i].value, _parts[i].rarity ) ); bool found = false; for (uint256 s = 0; s < partIds.length; s++) { if (partIds[s] == uniqueIdentifier) { found = true; } } require(!found, "Part already exists"); partIds.push(uniqueIdentifier); newPartIds[i] = uniqueIdentifier; parts[uniqueIdentifier] = _parts[i]; } return newPartIds; } function batchGrantPart( address[] memory _user, bytes32[] memory _partIds ) external onlyRole(DEFAULT_ADMIN_ROLE) { for (uint256 i = 0; i < _partIds.length; i++) { // make sure it exists bool found = false; for (uint256 s = 0; s < partIds.length; s++) { if (partIds[s] == _partIds[i]) { found = true; } } require(found, "Part does not exist"); for (uint256 n = 0; n < _user.length; n++) { userParts[_user[n]].push(_partIds[i]); } } } function getUserSkins( address _user ) public view returns (ShipAssetsUpgradeable.Skin[] memory) { uint256 numberOfSkins = userSkins[_user].length; ShipAssetsUpgradeable.Skin[] memory userSkinsArray = new ShipAssetsUpgradeable.Skin[]( numberOfSkins ); for (uint256 i = 0; i < numberOfSkins; i++) { userSkinsArray[i] = skins[userSkins[_user][i]]; } return userSkinsArray; } function getUserPartIds( address _user ) public view returns (bytes32[] memory) { return userParts[_user]; } function getUserSkinIds( address _user ) public view returns (bytes32[] memory) { return userSkins[_user]; } function getAllSkinIds() public view returns (bytes32[] memory) { return skinIds; } function getAllPartIds() public view returns (bytes32[] memory) { return partIds; } function getAllSkins() public view returns (ShipAssetsUpgradeable.Skin[] memory) { uint256 numberOfSkins = skinIds.length; ShipAssetsUpgradeable.Skin[] memory allSkins = new ShipAssetsUpgradeable.Skin[](numberOfSkins); for (uint256 i = 0; i < numberOfSkins; i++) { allSkins[i] = skins[skinIds[i]]; } return allSkins; } function batchAddSkins( ShipAssetsUpgradeable.Skin[] memory _skins ) external onlyRole(DEFAULT_ADMIN_ROLE) returns (bytes32[] memory) { bytes32[] memory newSkinIds = new bytes32[](_skins.length); for (uint256 i = 0; i < _skins.length; i++) { bytes32 uniqueIdentifier = keccak256( abi.encodePacked(_skins[i].name) ); bool found = false; for (uint256 s = 0; s < skinIds.length; s++) { if (skinIds[s] == uniqueIdentifier) { found = true; } } require(!found, "Skin already exists"); skinIds.push(uniqueIdentifier); newSkinIds[i] = uniqueIdentifier; skins[uniqueIdentifier] = _skins[i]; } return newSkinIds; } function batchGrantSkin( address[] memory _user, bytes32[] memory _skinIds ) external onlyRole(DEFAULT_ADMIN_ROLE) { for (uint256 i = 0; i < _skinIds.length; i++) { // make sure it exists bool found = false; for (uint256 s = 0; s < skinIds.length; s++) { if (skinIds[s] == _skinIds[i]) { found = true; } } require(found, "Skin does not exist"); for (uint256 n = 0; n < _user.length; n++) { userSkins[_user[n]].push(_skinIds[i]); } } } function equipUserPart( uint256 tokenId, bytes32 partId, uint256 x, uint256 y ) public { require( battleshipz.ownerOf(tokenId) == msg.sender, "Caller must own the token" ); bool found = false; uint256 i; uint amtOwned = 0; bytes32[] memory _userPartIds = getUserPartIds(msg.sender); for (i = 0; i < _userPartIds.length; i++) { if (_userPartIds[i] == partId) { amtOwned++; found = true; } } require(found, "Part not owned by user"); uint seed = battleshipz.getSeed(tokenId); ShipArmoryUpgradeable.EquippedPart memory equippedPart = createEquippedPart(partId, x, y); require( isPartCompatible(seed, equippedPart), "Part is not compatible with the ship at this location" ); // iterate through all equipped parts and make sure the part is not already equipped // users can own more than one of the same part, just make sure there are remaining parts to equip in this context uint[] memory ownedTokenIds = battleshipz.tokensOfOwner(msg.sender); uint amtEquipped = 0; for (i = 0; i < ownedTokenIds.length; i++) { uint256 ownedTokenId = ownedTokenIds[i]; for ( uint256 j = 0; j < equippedUserParts[msg.sender][ownedTokenId].length; j++ ) { if ( equippedUserParts[msg.sender][ownedTokenId][j].partId == partId ) { amtEquipped++; } } } require(amtEquipped < amtOwned, "Part is already equipped"); equippedUserParts[msg.sender][tokenId].push(equippedPart); } function equipUserSkin(uint256 tokenId, bytes32 skinId) public { require( battleshipz.ownerOf(tokenId) == msg.sender, "Caller must own the token" ); bool found = false; uint256 i; uint amtOwned = 0; bytes32[] memory _skinIds = getUserSkinIds(msg.sender); for (i = 0; i < _skinIds.length; i++) { if (_skinIds[i] == skinId) { found = true; amtOwned++; } } require(found, "Skin not owned by user"); uint[] memory ownedTokenIds = battleshipz.tokensOfOwner(msg.sender); uint amtEquipped = 0; for (i = 0; i < ownedTokenIds.length; i++) { uint256 ownedTokenId = ownedTokenIds[i]; if (equippedUserSkins[msg.sender][ownedTokenId] == skinId) { amtEquipped++; } } require(amtEquipped < amtOwned, "Skin is already equipped"); equippedUserSkins[msg.sender][tokenId] = skinId; } function getEquippedUserParts( address user, uint256 tokenId ) public view returns (ShipArmoryUpgradeable.EquippedPart[] memory) { return equippedUserParts[user][tokenId]; } function getEquippedUserSkin( address user, uint256 tokenId ) public view returns (bytes32) { return equippedUserSkins[user][tokenId]; } function batchRedeemAndEquip(RedeemAndEquipData[] memory data) external { for (uint256 i = 0; i < data.length; i++) { if (data[i].skinId != bytes32(0)) { redeemReward( msg.sender, data[i].skinId, data[i].uid, data[i].v, data[i].r, data[i].s, false ); equipUserSkin(data[i].tokenId, data[i].skinId); } else if (data[i].part.partId != bytes32(0)) { redeemReward( msg.sender, data[i].part.partId, data[i].uid, data[i].v, data[i].r, data[i].s, true ); equipUserPart( data[i].tokenId, data[i].part.partId, data[i].part.x, data[i].part.y ); } else { revert("Invalid data"); } } } function redeemReward( address _recipient, bytes32 _rewardId, bytes32 uid, uint8 v, bytes32 r, bytes32 s, bool isPart ) public { require(msg.sender == _recipient, "Sender must be the recipient"); bool found = false; if (isPart) { for (uint256 i = 0; i < partIds.length; i++) { if (partIds[i] == _rewardId) { found = true; } } } else { for (uint256 i = 0; i < skinIds.length; i++) { if (skinIds[i] == _rewardId) { found = true; } } } require(found, "Part or Skin does not exist"); // Create the message with the reward recipient's address and the part id bytes memory message = abi.encodePacked(_recipient, _rewardId, uid); // Calculate the message hash bytes32 messageHash = keccak256(message); // Check if the signature has already been used require(!usedSignatures[messageHash], "Signature already used"); usedSignatures[messageHash] = true; // Recreate the message hash by prefixing it with the standard Ethereum Signed Message prefix bytes32 prefixedHash = keccak256( abi.encodePacked("\x19Ethereum Signed Message:\n32", messageHash) ); // Recover the signer's address from the signature address recoveredSigner = ecrecover(prefixedHash, v, r, s); // Compare the recovered signer's address with the provided signer's address require(recoveredSigner == rewardSigner, "Invalid signature"); if (isPart) { userParts[_recipient].push(_rewardId); } else { userSkins[_recipient].push(_rewardId); } } function equal( string memory a, string memory b ) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; contract ShipAssetsUpgradeable is Initializable { /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } struct Battleship { uint seed; string classType; Part[7] outerParts; Part[7] innerParts; Part[7] middleParts; Skin skin; } struct Part { string name; string value; string rarity; } mapping(string => mapping(uint => Part[])) public partsRarity; struct Skin { string name; string color; string thrusterColor; string[7][3] partColors; string rarity; } function initialize() public initializer { uint commonPartsIdx = 0; uint uncommonPartsIdx = 1; uint rarePartsIdx = 2; uint epicPartsIdx = 3; uint legendaryPartsIdx = 4; partsRarity["Thruster"][commonPartsIdx].push( Part({name: "Thruster", value: "~~]", rarity: "Common"}) ); partsRarity["Thruster"][commonPartsIdx].push( Part({name: "Thruster", value: "--]", rarity: "Common"}) ); partsRarity["Thruster"][uncommonPartsIdx].push( Part({name: "Thruster", value: "-=]", rarity: "Uncommon"}) ); partsRarity["Thruster"][uncommonPartsIdx].push( Part({name: "Thruster", value: "~=]", rarity: "Uncommon"}) ); partsRarity["Thruster"][rarePartsIdx].push( Part({name: "Thruster", value: "==)", rarity: "Rare"}) ); partsRarity["Thruster"][rarePartsIdx].push( Part({name: "Thruster", value: "=:)", rarity: "Rare"}) ); partsRarity["Thruster"][epicPartsIdx].push( Part({name: "Thruster", value: "==}", rarity: "Epic"}) ); partsRarity["Thruster"][epicPartsIdx].push( Part({name: "Thruster", value: "=:}", rarity: "Epic"}) ); partsRarity["Thruster"][legendaryPartsIdx].push( Part({name: "Thruster", value: "==]", rarity: "Legendary"}) ); partsRarity["Thruster"][legendaryPartsIdx].push( Part({name: "Thruster", value: "=:]", rarity: "Legendary"}) ); partsRarity["Shield"][commonPartsIdx].push( Part({name: "Shield", value: ")*)", rarity: "Common"}) ); partsRarity["Shield"][commonPartsIdx].push( Part({name: "Shield", value: ")))", rarity: "Common"}) ); partsRarity["Shield"][uncommonPartsIdx].push( Part({name: "Shield", value: ")*]", rarity: "Uncommon"}) ); partsRarity["Shield"][uncommonPartsIdx].push( Part({name: "Shield", value: "))]", rarity: "Uncommon"}) ); partsRarity["Shield"][rarePartsIdx].push( Part({name: "Shield", value: ")/]", rarity: "Rare"}) ); partsRarity["Shield"][rarePartsIdx].push( Part({name: "Shield", value: ")]]", rarity: "Rare"}) ); partsRarity["Shield"][epicPartsIdx].push( Part({name: "Shield", value: "]|]", rarity: "Epic"}) ); partsRarity["Shield"][epicPartsIdx].push( Part({name: "Shield", value: "]]]", rarity: "Epic"}) ); partsRarity["Shield"][legendaryPartsIdx].push( Part({name: "Shield", value: ">^>", rarity: "Legendary"}) ); partsRarity["Shield"][legendaryPartsIdx].push( Part({name: "Shield", value: ">>>", rarity: "Legendary"}) ); partsRarity["Cargo"][commonPartsIdx].push( Part({name: "Cargo", value: "(%)", rarity: "Common"}) ); partsRarity["Cargo"][commonPartsIdx].push( Part({name: "Cargo", value: "( )", rarity: "Common"}) ); partsRarity["Cargo"][uncommonPartsIdx].push( Part({name: "Cargo", value: "{%}", rarity: "Uncommon"}) ); partsRarity["Cargo"][uncommonPartsIdx].push( Part({name: "Cargo", value: "{ }", rarity: "Uncommon"}) ); partsRarity["Cargo"][rarePartsIdx].push( Part({name: "Cargo", value: "[%]", rarity: "Rare"}) ); partsRarity["Cargo"][rarePartsIdx].push( Part({name: "Cargo", value: "[ ]", rarity: "Rare"}) ); partsRarity["Cargo"][epicPartsIdx].push( Part({name: "Cargo", value: "[^]", rarity: "Epic"}) ); partsRarity["Cargo"][legendaryPartsIdx].push( Part({name: "Cargo", value: "[-]", rarity: "Legendary"}) ); partsRarity["Blaster"][commonPartsIdx].push( Part({name: "Blaster", value: ")~~", rarity: "Common"}) ); partsRarity["Blaster"][commonPartsIdx].push( Part({name: "Blaster", value: ")--", rarity: "Common"}) ); partsRarity["Blaster"][uncommonPartsIdx].push( Part({name: "Blaster", value: ")=-", rarity: "Uncommon"}) ); partsRarity["Blaster"][uncommonPartsIdx].push( Part({name: "Blaster", value: ")=~", rarity: "Uncommon"}) ); partsRarity["Blaster"][rarePartsIdx].push( Part({name: "Blaster", value: "}=+", rarity: "Rare"}) ); partsRarity["Blaster"][rarePartsIdx].push( Part({name: "Blaster", value: "}==", rarity: "Rare"}) ); partsRarity["Blaster"][epicPartsIdx].push( Part({name: "Blaster", value: ")>>", rarity: "Epic"}) ); partsRarity["Blaster"][epicPartsIdx].push( Part({name: "Blaster", value: ")=>", rarity: "Epic"}) ); partsRarity["Blaster"][legendaryPartsIdx].push( Part({name: "Blaster", value: "]>>", rarity: "Legendary"}) ); partsRarity["Blaster"][legendaryPartsIdx].push( Part({name: "Blaster", value: "]=>", rarity: "Legendary"}) ); partsRarity["Nosecone"][commonPartsIdx].push( Part({name: "Nosecone", value: "::>", rarity: "Common"}) ); partsRarity["Nosecone"][commonPartsIdx].push( Part({name: "Nosecone", value: "**>", rarity: "Common"}) ); partsRarity["Nosecone"][uncommonPartsIdx].push( Part({name: "Nosecone", value: "}}>", rarity: "Uncommon"}) ); partsRarity["Nosecone"][uncommonPartsIdx].push( Part({name: "Nosecone", value: ") >", rarity: "Uncommon"}) ); partsRarity["Nosecone"][rarePartsIdx].push( Part({name: "Nosecone", value: "::}", rarity: "Rare"}) ); partsRarity["Nosecone"][epicPartsIdx].push( Part({name: "Nosecone", value: "}:}", rarity: "Epic"}) ); partsRarity["Nosecone"][epicPartsIdx].push( Part({name: "Nosecone", value: "} }", rarity: "Epic"}) ); partsRarity["Nosecone"][legendaryPartsIdx].push( Part({name: "Nosecone", value: ">*>", rarity: "Legendary"}) ); partsRarity["Nosecone"][legendaryPartsIdx].push( Part({name: "Nosecone", value: "> >", rarity: "Legendary"}) ); partsRarity["Cockpit"][commonPartsIdx].push( Part({name: "Cockpit", value: ":o ", rarity: "Common"}) ); partsRarity["Cockpit"][commonPartsIdx].push( Part({name: "Cockpit", value: " o ", rarity: "Common"}) ); partsRarity["Cockpit"][uncommonPartsIdx].push( Part({name: "Cockpit", value: ":O ", rarity: "Uncommon"}) ); partsRarity["Cockpit"][uncommonPartsIdx].push( Part({name: "Cockpit", value: " O ", rarity: "Uncommon"}) ); partsRarity["Cockpit"][rarePartsIdx].push( Part({name: "Cockpit", value: " 0 ", rarity: "Rare"}) ); partsRarity["Cockpit"][epicPartsIdx].push( Part({name: "Cockpit", value: "OoO", rarity: "Epic"}) ); partsRarity["Cockpit"][epicPartsIdx].push( Part({name: "Cockpit", value: "o0o", rarity: "Epic"}) ); partsRarity["Cockpit"][legendaryPartsIdx].push( Part({name: "Cockpit", value: "000", rarity: "Legendary"}) ); partsRarity["Cockpit"][legendaryPartsIdx].push( Part({name: "Cockpit", value: "0O0", rarity: "Legendary"}) ); partsRarity["Aero"][commonPartsIdx].push( Part({name: "Aero", value: "__)", rarity: "Common"}) ); partsRarity["Aero"][uncommonPartsIdx].push( Part({name: "Aero", value: "_))", rarity: "Uncommon"}) ); partsRarity["Aero"][rarePartsIdx].push( Part({name: "Aero", value: "__}", rarity: "Rare"}) ); partsRarity["Aero"][epicPartsIdx].push( Part({name: "Aero", value: "_//", rarity: "Epic"}) ); partsRarity["Aero"][epicPartsIdx].push( Part({name: "Aero", value: "__/", rarity: "Epic"}) ); partsRarity["Aero"][legendaryPartsIdx].push( Part({name: "Aero", value: "/_/", rarity: "Legendary"}) ); partsRarity["Aero"][legendaryPartsIdx].push( Part({name: "Aero", value: "__>", rarity: "Legendary"}) ); } function getPartsRarity( string memory partType, uint idx ) public view returns (Part[] memory) { return partsRarity[partType][idx]; } function createBattleship( uint seed, string memory classType, Part[7] memory outerParts, Part[7] memory innerParts, Part[7] memory middleParts, Skin memory skin ) public pure returns (Battleship memory) { Battleship memory ship = Battleship({ seed: seed, classType: classType, outerParts: outerParts, innerParts: innerParts, middleParts: middleParts, skin: skin }); return ship; } function createSkin( string memory name, string memory color, string memory thrusterColor, string[7][3] memory partColors, string memory rarity ) public pure returns (Skin memory) { Skin memory skin = Skin({ name: name, color: color, thrusterColor: thrusterColor, partColors: partColors, rarity: rarity }); return skin; } function createPart( string memory name, string memory value, string memory rarity ) public pure returns (Part memory) { Part memory part = Part({name: name, value: value, rarity: rarity}); return part; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import "./ShipAssetsUpgradeable.sol"; contract ShipBuilderUpgradeable is Initializable, AccessControlUpgradeable { /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } ShipAssetsUpgradeable public shipAssetsUpgradeable; function initialize( ShipAssetsUpgradeable _shipAssetsUpgradeable ) public initializer { __AccessControl_init(); _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); shipAssetsUpgradeable = _shipAssetsUpgradeable; } function getRandomIndexBasedOnRarity( uint256 seed ) public pure returns (uint256) { uint randomNumber = seed % 100; uint[5] memory rarityIndices = [ uint(0), uint(1), uint(2), uint(3), uint(4) ]; uint[5] memory weights = [ uint(35), uint(30), uint(20), uint(10), uint(5) ]; for (uint i = 0; i < weights.length; i++) { if (randomNumber < weights[i]) { return rarityIndices[i]; } randomNumber -= weights[i]; } return 0; } function generateRandomNeonColor( uint seed ) public pure returns (string memory) { uint[3] memory colors = [ uint(seed % 255), uint(seed % 255), uint(seed % 255) ]; uint randIdx = seed % colors.length; colors[randIdx] = 255; uint randIdx2 = seed % colors.length; while (randIdx2 == randIdx) { randIdx2 = ++seed % colors.length; } colors[randIdx2] = 0; return string.concat( "rgb(", StringsUpgradeable.toString(colors[0]), ",", StringsUpgradeable.toString(colors[1]), ",", StringsUpgradeable.toString(colors[2]), ")" ); } function getRandomClass(uint256 seed) public pure returns (string memory) { string[5] memory classes = [ "Fighter", "Cruiser", "Gunship", "Voyager", "Alien" ]; return classes[seed % classes.length]; } function getRandomPart( uint256 seed, string memory partType, uint partVariance ) public view returns (ShipAssetsUpgradeable.Part memory) { string memory emptyPartType = "Empty"; if (equal(partType, emptyPartType)) { return shipAssetsUpgradeable.createPart({ name: "Empty", value: " ", rarity: "Common" }); } uint idx = getRandomIndexBasedOnRarity(seed + partVariance); return shipAssetsUpgradeable.getPartsRarity(partType, idx)[ seed % shipAssetsUpgradeable.getPartsRarity(partType, idx).length ]; } function getRandomParts( uint seed, string[7] memory partTypes, uint[7] memory partVariance ) public view returns (ShipAssetsUpgradeable.Part[7] memory) { ShipAssetsUpgradeable.Part[7] memory parts; for (uint i = 0; i < partTypes.length; i++) { parts[i] = getRandomPart(seed, partTypes[i], partVariance[i]); } return parts; } function getPartVariances() public pure returns (uint256[7][3] memory) { return [ [ uint256(1), uint256(3), uint256(5), uint256(8), uint256(13), uint256(21), uint256(34) ], [ uint256(2), uint256(3), uint256(5), uint256(7), uint256(11), uint256(13), uint256(15) ], [ uint256(4), uint256(8), uint256(16), uint256(32), uint256(64), uint256(128), uint256(256) ] ]; } function getLayouts() public pure returns (string[7][3][5] memory) { return [ // fighter [ [ "Empty", "Empty", "Aero", "Nosecone", "Empty", "Empty", "Empty" ], [ "Empty", "Empty", "Aero", "Aero", "Nosecone", "Empty", "Empty" ], [ "Empty", "Thruster", "Shield", "Cockpit", "Nosecone", "Blaster", "Empty" ] ], // cruiser [ [ "Empty", "Thruster", "Blaster", "Empty", "Empty", "Empty", "Empty" ], [ "Empty", "Thruster", "Cargo", "Blaster", "Empty", "Empty", "Empty" ], [ "Empty", "Nosecone", "Shield", "Shield", "Cockpit", "Nosecone", "Empty" ] ], // gunship [ [ "Empty", "Empty", "Thruster", "Blaster", "Empty", "Empty", "Empty" ], [ "Empty", "Thruster", "Aero", "Aero", "Blaster", "Empty", "Empty" ], [ "Empty", "Empty", "Shield", "Cargo", "Cockpit", "Blaster", "Empty" ] ], // voyager [ [ "Empty", "Thruster", "Aero", "Aero", "Blaster", "Empty", "Empty" ], [ "Empty", "Thruster", "Nosecone", "Empty", "Empty", "Empty", "Empty" ], [ "Empty", "Thruster", "Shield", "Cargo", "Cockpit", "Nosecone", "Empty" ] ], // alien [ [ "Empty", "Thruster", "Aero", "Aero", "Aero", "Blaster", "Empty" ], [ "Empty", "Thruster", "Shield", "Shield", "Blaster", "Empty", "Empty" ], [ "Empty", "Empty", "Cockpit", "Nosecone", "Empty", "Empty", "Empty" ] ] ]; } function buildBattleship( uint256 seed ) public view returns (ShipAssetsUpgradeable.Battleship memory) { string memory classType = getRandomClass(seed); string memory color = generateRandomNeonColor(seed); string memory thrusterColor = generateRandomNeonColor( seed % getPartVariances()[2][seed % getPartVariances()[2].length] ); string[7][3] memory partColors = [ [color, color, color, color, color, color, color], [color, color, color, color, color, color, color], [color, color, color, color, color, color, color] ]; ShipAssetsUpgradeable.Skin memory skin = shipAssetsUpgradeable .createSkin("Default", color, thrusterColor, partColors, "Common"); uint layoutIdx; if (equal(classType, "Fighter")) { layoutIdx = 0; } else if (equal(classType, "Cruiser")) { layoutIdx = 1; } else if (equal(classType, "Gunship")) { layoutIdx = 2; } else if (equal(classType, "Voyager")) { layoutIdx = 3; } else if (equal(classType, "Alien")) { layoutIdx = 4; } else { revert("Invalid class type"); } return shipAssetsUpgradeable.createBattleship( seed, classType, getRandomParts( seed, getLayouts()[layoutIdx][0], getPartVariances()[0] ), getRandomParts( seed, getLayouts()[layoutIdx][1], getPartVariances()[1] ), getRandomParts( seed, getLayouts()[layoutIdx][2], getPartVariances()[2] ), skin ); } function equal( string memory a, string memory b ) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/Base64Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; import "./ShipAssetsUpgradeable.sol"; contract ShipSVGUpgradeable is Initializable, AccessControlUpgradeable { /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } ShipAssetsUpgradeable public shipAssetsUpgradeable; function initialize( ShipAssetsUpgradeable _shipAssetsUpgradeable ) public initializer { shipAssetsUpgradeable = _shipAssetsUpgradeable; } function setShipAssetsUpgradeable( ShipAssetsUpgradeable _shipAssetsUpgradeable ) external onlyRole(DEFAULT_ADMIN_ROLE) { shipAssetsUpgradeable = _shipAssetsUpgradeable; } // element functions function createStyleElement( string memory child ) public pure returns (string memory) { return string.concat("<style>", child, "</style>"); } function createTextElement( string memory child, bool flipped ) public pure returns (string memory) { if (flipped) { return string.concat( '<text transform="scale(1,-1)">', child, "</text>" ); } return string.concat("<text>", child, "</text>"); } function createStyleElements( string memory color, string memory thrusterColor ) public pure returns (string memory) { string memory output = ""; string memory cssStyleElem = createStyleElement( string.concat( "tspan { text-anchor: middle; dominant-baseline: middle; font-family: Courier; font-size: 25px; white-space: pre; alignment-baseline: middle; fill: ", color, " }" " .thruster { fill: ", thrusterColor, "; animation: fadeInRight ease 0.10s alternate infinite; -webkit-animation: fadeInRight ease 0.10s alternate infinite; -moz-animation: fadeInRight ease 0.10s alternate infinite; -o-animation: fadeInRight ease 0.10s alternate infinite; -ms-animation: fadeInRight ease 0.10s alternate infinite; } @keyframes fadeInRight { from { opacity: 0; transform: translateX(300px); } to { opacity: 1; } } @-moz-keyframes fadeInRight { from { opacity: 0; transform: translateX(300px); } to { opacity: 1; } } @-webkit-keyframes fadeInRight { from { opacity: 0; transform: translateX(300px); } to { opacity: 1; } } @-o-keyframes fadeInRight { from { opacity: 0; transform: translateX(300px); } to { opacity: 1; } } @-ms-keyframes fadeInRight { from { opacity: 0; transform: translateX(300px); } to { opacity: 1; } }" ) ); string memory backgroundElement = createStyleElement( "svg { background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzNTAgMzUwIiBoZWlnaHQ9IjEwMCUiIHdpZHRoPSIxMDAlIj48c3R5bGU+dHNwYW4ge2ZvbnQtZmFtaWx5OiBDb3VyaWVyO308L3N0eWxlPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiLz48dGV4dCBmb250LXNpemU9IjEyIiBmaWxsPSIjZmZmIj48dHNwYW4geD0iMTAwIiB5PSI1MCI+MDwvdHNwYW4+PHRzcGFuIHg9IjI4MCIgeT0iMTMwIj5PPC90c3Bhbj48dHNwYW4geD0iNTAiIHk9IjIwMCI+TzwvdHNwYW4+PHRzcGFuIHg9IjI4MCIgeT0iMzIwIj5PPC90c3Bhbj48dHNwYW4geD0iMTc1IiB5PSIxNzUiPm88L3RzcGFuPjx0c3BhbiB4PSIxNTAiIHk9IjI5MCI+bzwvdHNwYW4+PHRzcGFuIHg9IjMwMCIgeT0iMjAiPi48L3RzcGFuPjx0c3BhbiB4PSIyMDAiIHk9IjcwIj4uPC90c3Bhbj48dHNwYW4geD0iMzEwIiB5PSIyNTAiPi48L3RzcGFuPjx0c3BhbiB4PSI0MCIgeT0iMzEwIj4uPC90c3Bhbj48dHNwYW4geD0iMzAiIHk9IjkwIj4uPC90c3Bhbj48L3RleHQ+PC9zdmc+'); width: 350px; height: 350px; -webkit-animation: l_2_r 13s linear infinite; animation: l_2_r 13s linear infinite; } @-webkit-keyframes l_2_r { from {background-position: 0 0;} to {background-position: -1000px 0;} } @keyframes l_2_r { from {background-position: 0 0;} to {background-position: -1000px 0;} }" ); output = string.concat(cssStyleElem, backgroundElement); return output; } function createSvgElement( string memory attrs, string memory child ) public pure returns (string memory) { string memory output = ""; output = string.concat("<svg ", attrs, ">", child, "</svg>"); return output; } function createTspanElement( string memory child, uint x, uint y, bool flipped ) public pure returns (string memory) { string memory output = ""; // Positioning Styling string memory xStr = StringsUpgradeable.toString(x); string memory yStr = StringsUpgradeable.toString(y); string memory isFlipped = ""; if (flipped) { isFlipped = "-"; } string memory xAttr = string.concat("x='", "", xStr, "%'"); string memory yAttr = string.concat("y='", isFlipped, yStr, "%'"); string memory attrs = string.concat(xAttr, " ", yAttr); output = string.concat("<tspan ", attrs, ">", child, "</tspan>"); return output; } function createTspanRow( ShipAssetsUpgradeable.Part[7] memory tspanParts, uint x, uint y, bool isFlipped, string[7] memory colors ) public pure returns (string memory) { string memory output = ""; string memory row = ""; for (uint i = 0; i < tspanParts.length; i++) { if (equal(tspanParts[i].name, "Thruster")) { string memory flames = slice(1, 2, tspanParts[i].value); string memory booster = slice(3, 3, tspanParts[i].value); row = string.concat( row, '<tspan class="thruster">', flames, string.concat( '</tspan><tspan style="fill:', colors[i], '">' ), booster, "</tspan>" ); continue; } row = string.concat( row, string.concat('<tspan style="fill:', colors[i], '">'), tspanParts[i].value, "</tspan>" ); } output = createTspanElement(row, x, y, isFlipped); return output; } function createTspanRows( ShipAssetsUpgradeable.Battleship memory ship, bool onlyFlipped ) public pure returns (string memory tspanRows) { uint x = 50; if (onlyFlipped) { string memory outerRow = createTspanRow( ship.outerParts, x, 36, onlyFlipped, ship.skin.partColors[0] ); string memory innerRow = createTspanRow( ship.innerParts, x, 43, onlyFlipped, ship.skin.partColors[1] ); return string.concat(outerRow, innerRow); } string memory middleRow = createTspanRow( ship.middleParts, x, 50, onlyFlipped, ship.skin.partColors[2] ); string memory innerRow2 = createTspanRow( ship.innerParts, x, 57, onlyFlipped, ship.skin.partColors[1] ); string memory outerRow2 = createTspanRow( ship.outerParts, x, 64, onlyFlipped, ship.skin.partColors[0] ); return string.concat(middleRow, innerRow2, outerRow2); } function createBattleshipSVG( ShipAssetsUpgradeable.Battleship memory ship ) public pure returns (string memory) { string memory styleElems = createStyleElements( ship.skin.color, ship.skin.thrusterColor ); string memory textElem1 = createTextElement( createTspanRows(ship, true), true ); string memory textElem2 = createTextElement( createTspanRows(ship, false), false ); string memory childSvgElems = string.concat( styleElems, textElem1, textElem2 ); string memory svgElem = createSvgElement( ' xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350"', childSvgElems ); return svgElem; } // utils function slice( uint256 begin, uint256 end, string memory text ) public pure returns (string memory) { bytes memory a = new bytes(end - begin + 1); for (uint i = 0; i <= end - begin; i++) { a[i] = bytes(text)[i + begin - 1]; } return string(a); } function equal( string memory a, string memory b ) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"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":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","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":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"equippedUserParts","outputs":[{"internalType":"bytes32","name":"partId","type":"bytes32"},{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"equippedUserSkins","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"generateSeed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getSeed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"string","name":"classType","type":"string"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"value","type":"string"},{"internalType":"string","name":"rarity","type":"string"}],"internalType":"struct ShipAssetsUpgradeable.Part[7]","name":"outerParts","type":"tuple[7]"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"value","type":"string"},{"internalType":"string","name":"rarity","type":"string"}],"internalType":"struct ShipAssetsUpgradeable.Part[7]","name":"innerParts","type":"tuple[7]"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"value","type":"string"},{"internalType":"string","name":"rarity","type":"string"}],"internalType":"struct ShipAssetsUpgradeable.Part[7]","name":"middleParts","type":"tuple[7]"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"color","type":"string"},{"internalType":"string","name":"thrusterColor","type":"string"},{"internalType":"string[7][3]","name":"partColors","type":"string[7][3]"},{"internalType":"string","name":"rarity","type":"string"}],"internalType":"struct ShipAssetsUpgradeable.Skin","name":"skin","type":"tuple"}],"internalType":"struct ShipAssetsUpgradeable.Battleship","name":"ship","type":"tuple"}],"name":"getShipPartsRarity","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"value","type":"string"},{"internalType":"string","name":"rarity","type":"string"}],"internalType":"struct ShipAssetsUpgradeable.Part[7]","name":"parts","type":"tuple[7]"}],"name":"getTotalRarityWeightForRow","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","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":"contract ShipSVGUpgradeable","name":"_shipSVGUpgradeable","type":"address"},{"internalType":"contract ShipAssetsUpgradeable","name":"_shipAssetsUpgradeable","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ShipArmoryUpgradeable","name":"_shipArmoryUpgradeable","type":"address"}],"name":"initializeV2","outputs":[],"stateMutability":"nonpayable","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":[],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operatorFilteringEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"publicMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"publicSaleLive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publicSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"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":"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":[],"name":"saleType","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"setDefaultRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxMint","type":"uint256"}],"name":"setMaxMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_mintPrice","type":"uint256"}],"name":"setMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"value","type":"bool"}],"name":"setOperatorFilteringEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isLive","type":"bool"}],"name":"setPublicSaleLive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_publicSupply","type":"uint256"}],"name":"setPublicSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ShipAssetsUpgradeable","name":"_shipAssetsUpgradeable","type":"address"}],"name":"setShipAssetsUpgradeable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ShipSVGUpgradeable","name":"_shipSVGUpgradeable","type":"address"}],"name":"setShipSVGUpgradeable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isLive","type":"bool"}],"name":"setWhitelistSaleLive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_whitelistSupply","type":"uint256"}],"name":"setWhitelistSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shipArmoryUpgradeable","outputs":[{"internalType":"contract ShipArmoryUpgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"shipAssetsUpgradeable","outputs":[{"internalType":"contract ShipAssetsUpgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"shipSVGUpgradeable","outputs":[{"internalType":"contract ShipSVGUpgradeable","name":"","type":"address"}],"stateMutability":"view","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":"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":"totalMinted","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"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelistClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes32[]","name":"_merkleProof","type":"bytes32[]"}],"name":"whitelistMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"whitelistSaleLive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whitelistSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b620000e4565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015620000e2576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b614f7780620000f46000396000f3fe6080604052600436106103ad5760003560e01c80636352211e116101e7578063b7c0b8e81161010d578063d5abeb01116100a0578063e985e9c51161006f578063e985e9c514610b29578063ee1c96a214610b72578063f4a0a52814610bab578063fb796e6c14610bcb57600080fd5b8063d5abeb0114610a91578063db4bec4414610aa8578063e0d4ea3714610ad9578063e63ab1e914610b0757600080fd5b8063c97441ee116100dc578063c97441ee14610a1d578063d2cab05614610a3d578063d325010614610a50578063d547741f14610a7157600080fd5b8063b7c0b8e81461099d578063b88d4fde146109bd578063c7347c03146109dd578063c87b56dd146109fd57600080fd5b80638462151c1161018557806396173519116101545780639617351914610931578063a217fddf14610951578063a22cb46514610966578063a2309ff81461098657600080fd5b80638462151c1461089a578063906db03b146108c757806391d14854146108fc57806395d89b411461091c57600080fd5b80637501f741116101c15780637501f741146108135780637cb647591461082a5780637f2fee431461084a5780638456cb591461088557600080fd5b80636352211e146107bc5780636817c76c146107dc57806370a08231146107f357600080fd5b80632f2ff15d116102d75780634eebbb3b1161026a578063572316401161023957806357231640146107585780635bcc7928146107785780635c975abb1461078d5780635e84d723146107a557600080fd5b80634eebbb3b146106d2578063519d474e146106f2578063547520fe1461071857806355a63bf41461073857600080fd5b80633f4ba83a116102a65780633f4ba83a1461065d578063424611c31461067257806342842e0e14610692578063485cc955146106b257600080fd5b80632f2ff15d146105e657806333e614131461060657806336568abe1461061d5780633ca5d0581461063d57600080fd5b806326aa420a1161034f5780632db115441161031e5780632db115441461057b5780632e1a7d4d1461058e5780632eb4a7ab146105ae5780632f1a8fcf146105c557600080fd5b806326aa420a146104e157806326d938001461050157806329b6eca91461051c5780632a55205a1461053c57600080fd5b8063081812fc1161038b578063081812fc1461042b578063095ea7b31461046357806323b872dd14610483578063248a9ca3146104a357600080fd5b806301ffc9a7146103b257806304634d8d146103e757806306fdde0314610409575b600080fd5b3480156103be57600080fd5b506103d26103cd366004613847565b610be6565b60405190151581526020015b60405180910390f35b3480156103f357600080fd5b50610407610402366004613879565b610bf7565b005b34801561041557600080fd5b5061041e610c11565b6040516103de919061390e565b34801561043757600080fd5b5061044b610446366004613921565b610ca3565b6040516001600160a01b0390911681526020016103de565b34801561046f57600080fd5b5061040761047e36600461393a565b610cca565b34801561048f57600080fd5b5061040761049e366004613966565b610cea565b3480156104af57600080fd5b506104d36104be366004613921565b600090815260fb602052604090206001015490565b6040519081526020016103de565b3480156104ed57600080fd5b506104076104fc366004613921565b610d21565b34801561050d57600080fd5b5061019a546103d29060ff1681565b34801561052857600080fd5b506104076105373660046139a7565b610d33565b34801561054857600080fd5b5061055c6105573660046139c4565b610d68565b604080516001600160a01b0390931683526020830191909152016103de565b610407610589366004613921565b610e14565b34801561059a57600080fd5b506104076105a9366004613921565b6110d6565b3480156105ba57600080fd5b506104d361019d5481565b3480156105d157600080fd5b506101925461044b906001600160a01b031681565b3480156105f257600080fd5b506104076106013660046139e6565b611184565b34801561061257600080fd5b506104d361019b5481565b34801561062957600080fd5b506104076106383660046139e6565b6111a9565b34801561064957600080fd5b50610407610658366004613a1b565b611223565b34801561066957600080fd5b50610407611276565b34801561067e57600080fd5b506104d361068d366004613921565b611296565b34801561069e57600080fd5b506104076106ad366004613966565b6112dd565b3480156106be57600080fd5b506104076106cd366004613a36565b61130e565b3480156106de57600080fd5b5061019a546103d290610100900460ff1681565b3480156106fe57600080fd5b5061019f5461044b9061010090046001600160a01b031681565b34801561072457600080fd5b50610407610733366004613921565b611575565b34801561074457600080fd5b50610407610753366004613921565b611587565b34801561076457600080fd5b5061041e610773366004613e61565b611599565b34801561078457600080fd5b5061041e6117a3565b34801561079957600080fd5b5060c95460ff166103d2565b3480156107b157600080fd5b506104d361019c5481565b3480156107c857600080fd5b5061044b6107d7366004613921565b611832565b3480156107e857600080fd5b506104d36101975481565b3480156107ff57600080fd5b506104d361080e3660046139a7565b611892565b34801561081f57600080fd5b506104d36101985481565b34801561083657600080fd5b50610407610845366004613921565b611918565b34801561085657600080fd5b5061086a610865366004613f67565b61192a565b604080519384526020840192909252908201526060016103de565b34801561089157600080fd5b5061040761197b565b3480156108a657600080fd5b506108ba6108b53660046139a7565b61199b565b6040516103de9190613f9c565b3480156108d357600080fd5b506108e76108e2366004613fd4565b611a92565b604080519283526020830191909152016103de565b34801561090857600080fd5b506103d26109173660046139e6565b611b6c565b34801561092857600080fd5b5061041e611b97565b34801561093d57600080fd5b5061040761094c3660046139a7565b611ba6565b34801561095d57600080fd5b506104d3600081565b34801561097257600080fd5b50610407610981366004614008565b611bd5565b34801561099257600080fd5b506104d36101965481565b3480156109a957600080fd5b506104076109b8366004613a1b565b611bf5565b3480156109c957600080fd5b506104076109d836600461403d565b611c15565b3480156109e957600080fd5b506104076109f83660046139a7565b611c4e565b348015610a0957600080fd5b5061041e610a18366004613921565b611c7d565b348015610a2957600080fd5b50610407610a38366004613a1b565b611f16565b610407610a4b3660046140bc565b611f73565b348015610a5c57600080fd5b506101915461044b906001600160a01b031681565b348015610a7d57600080fd5b50610407610a8c3660046139e6565b6122c3565b348015610a9d57600080fd5b506104d36101955481565b348015610ab457600080fd5b506103d2610ac33660046139a7565b61019e6020526000908152604090205460ff1681565b348015610ae557600080fd5b506104d3610af4366004613921565b6000908152610194602052604090205490565b348015610b1357600080fd5b506104d3600080516020614f2283398151915281565b348015610b3557600080fd5b506103d2610b44366004613a36565b6001600160a01b039182166000908152609c6020908152604080832093909416825291909152205460ff1690565b348015610b7e57600080fd5b506104d3610b8d36600461393a565b6101a160209081526000928352604080842090915290825290205481565b348015610bb757600080fd5b50610407610bc6366004613921565b6122e8565b348015610bd757600080fd5b5061019f546103d29060ff1681565b6000610bf1826122fa565b92915050565b6000610c0281612305565b610c0c838361230f565b505050565b606060978054610c209061413a565b80601f0160208091040260200160405190810160405280929190818152602001828054610c4c9061413a565b8015610c995780601f10610c6e57610100808354040283529160200191610c99565b820191906000526020600020905b815481529060010190602001808311610c7c57829003601f168201915b5050505050905090565b6000610cae8261240c565b506000908152609b60205260409020546001600160a01b031690565b8161019f5460ff1615610ce057610ce08161246b565b610c0c83836124af565b826001600160a01b0381163314610d105761019f5460ff1615610d1057610d103361246b565b610d1b8484846125bf565b50505050565b6000610d2c81612305565b5061019c55565b6000610d3e81612305565b5061019f80546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60008281526066602090815260408083208151808301909252546001600160a01b038116808352600160a01b9091046001600160601b0316928201929092528291610ddd5750604080518082019091526065546001600160a01b0381168252600160a01b90046001600160601b031660208201525b602081015160009061271090610dfc906001600160601b03168761418a565b610e0691906141a1565b915196919550909350505050565b323314610e685760405162461bcd60e51b815260206004820152601d60248201527f436f6e747261637473206e6f7420616c6c6f77656420746f206d696e7400000060448201526064015b60405180910390fd5b610e706125f0565b61019854610e7d33611892565b1115610ecb5760405162461bcd60e51b815260206004820152601b60248201527f4d6178206d696e74207065722077616c6c6574207265616368656400000000006044820152606401610e5f565b61019a5460ff16610f1e5760405162461bcd60e51b815260206004820152601860248201527f5075626c69632073616c65206e6f74206c6976652079657400000000000000006044820152606401610e5f565b61019854811115610f655760405162461bcd60e51b815260206004820152601160248201527013585e081b5a5b9d08195e18d959591959607a1b6044820152606401610e5f565b610195548161019654011115610fb25760405162461bcd60e51b815260206004820152601260248201527145786365656473206d617820737570706c7960701b6044820152606401610e5f565b61019c54816101965401111561100a5760405162461bcd60e51b815260206004820152601860248201527f4d6178207075626c6963206d696e7420657863656564656400000000000000006044820152606401610e5f565b61019754611018908261418a565b34101561105a5760405162461bcd60e51b815260206004820152601060248201526f2737ba1032b737bab3b41032ba3432b960811b6044820152606401610e5f565b60005b818163ffffffff1610156110c75760006110776101935490565b905061108861019380546001019055565b600061109382611296565b60008381526101946020526040902081905590506110b2335b8361264b565b5050610196805460019081019091550161105d565b506110d3600161015f55565b50565b60006110e181612305565b6110e96125f0565b604051600090339084908381818185875af1925050503d806000811461112b576040519150601f19603f3d011682016040523d82523d6000602084013e611130565b606091505b50509050806111745760405162461bcd60e51b815260206004820152601060248201526f5472616e73666572206661696c65642160801b6044820152606401610e5f565b50611180600161015f55565b5050565b600082815260fb602052604090206001015461119f81612305565b610c0c8383612665565b6001600160a01b03811633146112195760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610e5f565b61118082826126eb565b600061122e81612305565b8115611261576040805180820190915260068152657075626c696360d01b60208201526101999061125f9082614211565b505b5061019a805460ff1916911515919091179055565b600080516020614f2283398151915261128e81612305565b6110d3612752565b6000816112a46001436142d0565b60408051602081019390935290409082015242606082015260800160408051601f19818403018152919052805160209091012092915050565b826001600160a01b03811633146113035761019f5460ff1615611303576113033361246b565b610d1b8484846127a4565b600054610100900460ff161580801561132e5750600054600160ff909116105b806113485750303b158015611348575060005460ff166001145b6113ab5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610e5f565b6000805460ff1916600117905580156113ce576000805461ff0019166101001790555b6114186040518060400160405280600b81526020016a2130ba3a3632b9b434b83d60a91b8152506040518060400160405280600581526020016429a424a82d60d91b8152506127bf565b6114206127f0565b611428612821565b61019280546001600160a01b038086166001600160a01b031992831617909255610191805492851692909116919091179055611462612848565b61019f805460ff1916600117905561147c3361028a61230f565b611487600033612665565b61149f600080516020614f2283398151915233612665565b612710610195556000610196556611c37937e08000610197556005610198556040805180820190915260098152681dda1a5d195b1a5cdd60ba1b6020820152610199906114ec9082614211565b5061019a805461ffff1916905561138861019b81905561019c557fb1fdc7a0eaa5b56209817635a86bed9e86c149fbb2a0dff83a2af2a797065e7061019d558015610c0c576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050565b600061158081612305565b5061019855565b600061159281612305565b5061019b55565b60606000806115ab8460400151611a92565b915091506000806115bf8660600151611a92565b915091506000806115d38860800151611a92565b90925090506000826115e586896142e3565b6115ef91906142e3565b90506000826115fe86896142e3565b61160891906142e3565b9050600061161782600561418a565b905060008161162785606461418a565b61163191906141a1565b90506014811161166857505060408051808201909152600681526521b7b6b6b7b760d11b60208201529a9950505050505050505050565b601481118015611679575060288111155b156116ad5750506040805180820190915260088152672ab731b7b6b6b7b760c11b60208201529a9950505050505050505050565b6028811180156116be5750603c8111155b156116ee5750506040805180820190915260048152635261726560e01b60208201529a9950505050505050505050565b603c811180156116ff575060508111155b1561172f5750506040805180820190915260048152634570696360e01b60208201529a9950505050505050505050565b605081118015611740575060648111155b156117755750506040805180820190915260098152684c6567656e6461727960b81b60208201529a9950505050505050505050565b50506040805180820190915260078152662ab735b737bbb760c91b60208201529a9950505050505050505050565b61019980546117b19061413a565b80601f01602080910402602001604051908101604052809291908181526020018280546117dd9061413a565b801561182a5780601f106117ff5761010080835404028352916020019161182a565b820191906000526020600020905b81548152906001019060200180831161180d57829003601f168201915b505050505081565b6000818152609960205260408120546001600160a01b031680610bf15760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610e5f565b60006001600160a01b0382166118fc5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610e5f565b506001600160a01b03166000908152609a602052604090205490565b600061192381612305565b5061019d55565b6101a0602052826000526040600020602052816000526040600020818154811061195357600080fd5b6000918252602090912060039091020180546001820154600290920154909450909250905083565b600080516020614f2283398151915261199381612305565b6110d3612867565b606060006119a883611892565b90506000816001600160401b038111156119c4576119c4613a64565b6040519080825280602002602001820160405280156119ed578160200160208202803683370190505b5090506000805b61019554811015611a8857818414611a88576000818152609960205260409020546001600160a01b031615158015611a455750856001600160a01b0316611a3a82611832565b6001600160a01b0316145b15611a765780838381518110611a5d57611a5d6142f6565b602090810291909101015281611a728161430c565b9250505b80611a808161430c565b9150506119f4565b5090949350505050565b60008060008060005b6007811015611b6157611b09868260078110611ab957611ab96142f6565b6020908102919091015151604080518082019091526005815264456d70747960d81b9083015280519101207fc4ce3210982aa6fc94dabe46dc1dbf454d54a3a2fbc51d2ae982e47c784f46081490565b611b4f576000611b32878360078110611b2457611b246142f6565b6020020151604001516128a4565b9050611b3e81856142e3565b935082611b4a8161430c565b935050505b80611b598161430c565b915050611a9b565b509094909350915050565b600091825260fb602090815260408084206001600160a01b0393909316845291905290205460ff1690565b606060988054610c209061413a565b6000611bb181612305565b5061019180546001600160a01b0319166001600160a01b0392909216919091179055565b8161019f5460ff1615611beb57611beb8161246b565b610c0c8383612a4f565b6000611c0081612305565b5061019f805460ff1916911515919091179055565b836001600160a01b0381163314611c3b5761019f5460ff1615611c3b57611c3b3361246b565b611c4785858585612a5a565b5050505050565b6000611c5981612305565b5061019280546001600160a01b0319166001600160a01b0392909216919091179055565b60008181526101946020526040812054606091611c9984611832565b61019f54604051633656970960e11b81526001600160a01b0380841660048301526024820188905292935060009261010090920490911690636f4af3709085908390636cad2e1290604401600060405180830381865afa158015611d01573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d299190810190614325565b61019f5460405163553a74e560e01b81526001600160a01b038881166004830152602482018c90526101009092049091169063553a74e590604401602060405180830381865afa158015611d81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da591906143f8565b6040518463ffffffff1660e01b8152600401611dc393929190614411565b600060405180830381865afa158015611de0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e089190810190614743565b6101925460405163074e768b60e21b81529192506000916001600160a01b0390911690631d39da2c90611e3f9085906004016148b4565b600060405180830381865afa158015611e5c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e849190810190614a26565b90506000611ed9611e9488612a8c565b611e9d84612b1e565b8560200151611eab87611599565b60a088015151604051611ec5959493929190602001614a76565b604051602081830303815290604052612b1e565b604080516020808201835260008252915192935091611efa91849101614c87565b60408051601f1981840301815291905298975050505050505050565b6000611f2181612305565b8115611f57576040805180820190915260098152681dda1a5d195b1a5cdd60ba1b602082015261019990611f559082614211565b505b5061019a80549115156101000261ff0019909216919091179055565b323314611fc25760405162461bcd60e51b815260206004820152601d60248201527f436f6e747261637473206e6f7420616c6c6f77656420746f206d696e740000006044820152606401610e5f565b61019854611fcf33611892565b111561201d5760405162461bcd60e51b815260206004820152601b60248201527f4d6178206d696e74207065722077616c6c6574207265616368656400000000006044820152606401610e5f565b61019a54610100900460ff1661206c5760405162461bcd60e51b815260206004820152601460248201527315db081cd85b19481b9bdd081b1a5d99481e595d60621b6044820152606401610e5f565b6040516bffffffffffffffffffffffff193360601b1660208201526000906034016040516020818303038152906040528051906020012090506120e78383808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505061019d549150849050612c70565b6121255760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610e5f565b6101985484111561216c5760405162461bcd60e51b815260206004820152601160248201527013585e081b5a5b9d08195e18d959591959607a1b6044820152606401610e5f565b6101955484610196540111156121b95760405162461bcd60e51b815260206004820152601260248201527145786365656473206d617820737570706c7960701b6044820152606401610e5f565b61019b5484610196540111156122085760405162461bcd60e51b815260206004820152601460248201527313585e081ddb081b5a5b9d08195e18d95959195960621b6044820152606401610e5f565b61019754612216908561418a565b3410156122585760405162461bcd60e51b815260206004820152601060248201526f2737ba1032b737bab3b41032ba3432b960811b6044820152606401610e5f565b60005b848163ffffffff161015611c475760006122756101935490565b905061228661019380546001019055565b600061229182611296565b60008381526101946020526040902081905590506122ae336110ac565b5050610196805460019081019091550161225b565b600082815260fb60205260409020600101546122de81612305565b610c0c83836126eb565b60006122f381612305565b5061019755565b6000610bf182612c86565b6110d38133612cab565b6127106001600160601b038216111561237d5760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b6064820152608401610e5f565b6001600160a01b0382166123d35760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401610e5f565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217606555565b6000818152609960205260409020546001600160a01b03166110d35760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610e5f565b69c617113400112233445560005230601a5280603a52600080604460166daaeb6d7670e522a718067333cd4e5afa6124a7573d6000803e3d6000fd5b6000603a5250565b60006124ba82611832565b9050806001600160a01b0316836001600160a01b0316036125275760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610e5f565b336001600160a01b038216148061254357506125438133610b44565b6125b55760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610e5f565b610c0c8383612d04565b6125c93382612d72565b6125e55760405162461bcd60e51b8152600401610e5f90614ccc565b610c0c838383612df1565b600261015f54036126435760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e5f565b600261015f55565b611180828260405180602001604052806000815250612f62565b61266f8282611b6c565b61118057600082815260fb602090815260408083206001600160a01b03851684529091529020805460ff191660011790556126a73390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6126f58282611b6c565b1561118057600082815260fb602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b61275a612f95565b60c9805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b610c0c83838360405180602001604052806000815250611c15565b600054610100900460ff166127e65760405162461bcd60e51b8152600401610e5f90614d19565b6111808282612fde565b600054610100900460ff166128175760405162461bcd60e51b8152600401610e5f90614d19565b61281f61301e565b565b600054610100900460ff1661281f5760405162461bcd60e51b8152600401610e5f90614d19565b61281f733cc6cdda760b79bafa08df41ecfa224f810dceb66001613051565b61286f6130c6565b60c9805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586127873390565b60408051808201909152600681526521b7b6b6b7b760d11b6020918201528151908201206000907f3b031f7f29326d3f445a56aaa83a78114c260f1e40af44c50964d9edf6271f4a036128f957506001919050565b6040805180820190915260088152672ab731b7b6b6b7b760c11b6020918201528251908301207f2a19cece7381d374050418c2bff2b7de5d6ca0adbe97e81c12b0540ace359d200361294d57506002919050565b6040805180820190915260048152635261726560e01b6020918201528251908301207fd02e3141a8e0af092cd3cce39f1f91e61e81a816e83e58a487f98f6c3b238dfa0361299d57506003919050565b6040805180820190915260048152634570696360e01b6020918201528251908301207f6764d804d57285ae9d4c42cc380377d3d0ee9b90ff9eeccaa32d3b2e3e8d7f17036129ed57506004919050565b6040805180820190915260098152684c6567656e6461727960b81b6020918201528251908301207f181ebe3a8fa130246d49bfd123ac54849b05bdcd02c6b1322c78de2a3988a31003612a4257506005919050565b506000919050565b919050565b61118033838361310c565b612a643383612d72565b612a805760405162461bcd60e51b8152600401610e5f90614ccc565b610d1b848484846131da565b60606000612a998361320d565b60010190506000816001600160401b03811115612ab857612ab8613a64565b6040519080825280601f01601f191660200182016040528015612ae2576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612aec57509392505050565b60608151600003612b3d57505060408051602081019091526000815290565b6000604051806060016040528060408152602001614ee26040913990506000600384516002612b6c91906142e3565b612b7691906141a1565b612b8190600461418a565b6001600160401b03811115612b9857612b98613a64565b6040519080825280601f01601f191660200182016040528015612bc2576020820181803683370190505b509050600182016020820185865187015b80821015612c2e576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250612bd3565b5050600386510660018114612c4a5760028114612c5d57612c65565b603d6001830353603d6002830353612c65565b603d60018303535b509195945050505050565b600082612c7d85846132e5565b14949350505050565b60006001600160e01b03198216637965db0b60e01b1480610bf15750610bf182613332565b612cb58282611b6c565b61118057612cc281613372565b612ccd836020613384565b604051602001612cde929190614d64565b60408051601f198184030181529082905262461bcd60e51b8252610e5f9160040161390e565b6000818152609b6020526040902080546001600160a01b0319166001600160a01b0384169081179091558190612d3982611832565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600080612d7e83611832565b9050806001600160a01b0316846001600160a01b03161480612dc557506001600160a01b038082166000908152609c602090815260408083209388168352929052205460ff165b80612de95750836001600160a01b0316612dde84610ca3565b6001600160a01b0316145b949350505050565b826001600160a01b0316612e0482611832565b6001600160a01b031614612e2a5760405162461bcd60e51b8152600401610e5f90614dd9565b6001600160a01b038216612e8c5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610e5f565b612e998383836001613526565b826001600160a01b0316612eac82611832565b6001600160a01b031614612ed25760405162461bcd60e51b8152600401610e5f90614dd9565b6000818152609b6020908152604080832080546001600160a01b03199081169091556001600160a01b03878116808652609a8552838620805460001901905590871680865283862080546001019055868652609990945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b612f6c8383613533565b612f7960008484846136cc565b610c0c5760405162461bcd60e51b8152600401610e5f90614e1e565b60c95460ff1661281f5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610e5f565b600054610100900460ff166130055760405162461bcd60e51b8152600401610e5f90614d19565b60976130118382614211565b506098610c0c8282614211565b600054610100900460ff166130455760405162461bcd60e51b8152600401610e5f90614d19565b60c9805460ff19169055565b6001600160a01b0390911690637d3e3dbe8161307e57826130775750634420e48661307e565b5063a0af29035b8060e01b60005230600452826024526004600060446000806daaeb6d7670e522a718067333cd4e5af16130bc578060005160e01c036130bc57600080fd5b5060006024525050565b60c95460ff161561281f5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610e5f565b816001600160a01b0316836001600160a01b03160361316d5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610e5f565b6001600160a01b038381166000818152609c6020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6131e5848484612df1565b6131f1848484846136cc565b610d1b5760405162461bcd60e51b8152600401610e5f90614e1e565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061324c5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310613278576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061329657662386f26fc10000830492506010015b6305f5e10083106132ae576305f5e100830492506008015b61271083106132c257612710830492506004015b606483106132d4576064830492506002015b600a8310610bf15760010192915050565b600081815b845181101561332a5761331682868381518110613309576133096142f6565b60200260200101516137cd565b9150806133228161430c565b9150506132ea565b509392505050565b60006001600160e01b031982166380ac58cd60e01b148061336357506001600160e01b03198216635b5e139f60e01b145b80610bf15750610bf1826137fc565b6060610bf16001600160a01b03831660145b6060600061339383600261418a565b61339e9060026142e3565b6001600160401b038111156133b5576133b5613a64565b6040519080825280601f01601f1916602001820160405280156133df576020820181803683370190505b509050600360fc1b816000815181106133fa576133fa6142f6565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110613429576134296142f6565b60200101906001600160f81b031916908160001a905350600061344d84600261418a565b6134589060016142e3565b90505b60018111156134d0576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061348c5761348c6142f6565b1a60f81b8282815181106134a2576134a26142f6565b60200101906001600160f81b031916908160001a90535060049490941c936134c981614e70565b905061345b565b50831561351f5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610e5f565b9392505050565b61352e6130c6565b610d1b565b6001600160a01b0382166135895760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610e5f565b6000818152609960205260409020546001600160a01b0316156135ee5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610e5f565b6135fc600083836001613526565b6000818152609960205260409020546001600160a01b0316156136615760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610e5f565b6001600160a01b0382166000818152609a6020908152604080832080546001019055848352609990915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60006001600160a01b0384163b156137c257604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290613710903390899088908890600401614e87565b6020604051808303816000875af192505050801561374b575060408051601f3d908101601f1916820190925261374891810190614ec4565b60015b6137a8573d808015613779576040519150601f19603f3d011682016040523d82523d6000602084013e61377e565b606091505b5080516000036137a05760405162461bcd60e51b8152600401610e5f90614e1e565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050612de9565b506001949350505050565b60008183106137e957600082815260208490526040902061351f565b600083815260208390526040902061351f565b60006001600160e01b0319821663152a902d60e11b1480610bf157506301ffc9a760e01b6001600160e01b0319831614610bf1565b6001600160e01b0319811681146110d357600080fd5b60006020828403121561385957600080fd5b813561351f81613831565b6001600160a01b03811681146110d357600080fd5b6000806040838503121561388c57600080fd5b823561389781613864565b915060208301356001600160601b03811681146138b357600080fd5b809150509250929050565b60005b838110156138d95781810151838201526020016138c1565b50506000910152565b600081518084526138fa8160208601602086016138be565b601f01601f19169290920160200192915050565b60208152600061351f60208301846138e2565b60006020828403121561393357600080fd5b5035919050565b6000806040838503121561394d57600080fd5b823561395881613864565b946020939093013593505050565b60008060006060848603121561397b57600080fd5b833561398681613864565b9250602084013561399681613864565b929592945050506040919091013590565b6000602082840312156139b957600080fd5b813561351f81613864565b600080604083850312156139d757600080fd5b50508035926020909101359150565b600080604083850312156139f957600080fd5b8235915060208301356138b381613864565b80358015158114612a4a57600080fd5b600060208284031215613a2d57600080fd5b61351f82613a0b565b60008060408385031215613a4957600080fd5b8235613a5481613864565b915060208301356138b381613864565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715613a9c57613a9c613a64565b60405290565b60405160a081016001600160401b0381118282101715613a9c57613a9c613a64565b60405160c081016001600160401b0381118282101715613a9c57613a9c613a64565b60405160e081016001600160401b0381118282101715613a9c57613a9c613a64565b604051601f8201601f191681016001600160401b0381118282101715613b3057613b30613a64565b604052919050565b60006001600160401b03821115613b5157613b51613a64565b50601f01601f191660200190565b6000613b72613b6d84613b38565b613b08565b9050828152838383011115613b8657600080fd5b828260208301376000602084830101529392505050565b600082601f830112613bae57600080fd5b61351f83833560208501613b5f565b600082601f830112613bce57600080fd5b613bd6613ae6565b8060e0840185811115613be857600080fd5b845b81811015613ca45780356001600160401b0380821115613c0a5760008081fd5b908701906060828a031215613c1f5760008081fd5b613c27613a7a565b823582811115613c375760008081fd5b613c438b828601613b9d565b82525060208084013583811115613c5a5760008081fd5b613c668c828701613b9d565b828401525060408085013584811115613c7f5760008081fd5b613c8b8d828801613b9d565b9184019190915250908752909501945050602001613bea565b509095945050505050565b6000601f8381840112613cc157600080fd5b613cc9613a7a565b806060850186811115613cdb57600080fd5b855b81811015613d785780356001600160401b0380821115613cfd5760008081fd5b81890191508987830112613d115760008081fd5b613d19613ae6565b8060e084018c811115613d2c5760008081fd5b845b81811015613d6157803585811115613d465760008081fd5b613d528f828901613b9d565b85525060209384019301613d2e565b505087525050602094850194919091019050613cdd565b50909695505050505050565b600060a08284031215613d9657600080fd5b613d9e613aa2565b905081356001600160401b0380821115613db757600080fd5b613dc385838601613b9d565b83526020840135915080821115613dd957600080fd5b613de585838601613b9d565b60208401526040840135915080821115613dfe57600080fd5b613e0a85838601613b9d565b60408401526060840135915080821115613e2357600080fd5b613e2f85838601613caf565b60608401526080840135915080821115613e4857600080fd5b50613e5584828501613b9d565b60808301525092915050565b600060208284031215613e7357600080fd5b81356001600160401b0380821115613e8a57600080fd5b9083019060c08286031215613e9e57600080fd5b613ea6613ac4565b82358152602083013582811115613ebc57600080fd5b613ec887828601613b9d565b602083015250604083013582811115613ee057600080fd5b613eec87828601613bbd565b604083015250606083013582811115613f0457600080fd5b613f1087828601613bbd565b606083015250608083013582811115613f2857600080fd5b613f3487828601613bbd565b60808301525060a083013582811115613f4c57600080fd5b613f5887828601613d84565b60a08301525095945050505050565b600080600060608486031215613f7c57600080fd5b8335613f8781613864565b95602085013595506040909401359392505050565b6020808252825182820181905260009190848201906040850190845b81811015613d7857835183529284019291840191600101613fb8565b600060208284031215613fe657600080fd5b81356001600160401b03811115613ffc57600080fd5b612de984828501613bbd565b6000806040838503121561401b57600080fd5b823561402681613864565b915061403460208401613a0b565b90509250929050565b6000806000806080858703121561405357600080fd5b843561405e81613864565b9350602085013561406e81613864565b92506040850135915060608501356001600160401b0381111561409057600080fd5b8501601f810187136140a157600080fd5b6140b087823560208401613b5f565b91505092959194509250565b6000806000604084860312156140d157600080fd5b8335925060208401356001600160401b03808211156140ef57600080fd5b818601915086601f83011261410357600080fd5b81358181111561411257600080fd5b8760208260051b850101111561412757600080fd5b6020830194508093505050509250925092565b600181811c9082168061414e57607f821691505b60208210810361416e57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610bf157610bf1614174565b6000826141be57634e487b7160e01b600052601260045260246000fd5b500490565b601f821115610c0c57600081815260208120601f850160051c810160208610156141ea5750805b601f850160051c820191505b81811015614209578281556001016141f6565b505050505050565b81516001600160401b0381111561422a5761422a613a64565b61423e81614238845461413a565b846141c3565b602080601f831160018114614273576000841561425b5750858301515b600019600386901b1c1916600185901b178555614209565b600085815260208120601f198616915b828110156142a257888601518255948401946001909101908401614283565b50858210156142c05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b81810381811115610bf157610bf1614174565b80820180821115610bf157610bf1614174565b634e487b7160e01b600052603260045260246000fd5b60006001820161431e5761431e614174565b5060010190565b6000602080838503121561433857600080fd5b82516001600160401b038082111561434f57600080fd5b818501915085601f83011261436357600080fd5b81518181111561437557614375613a64565b614383848260051b01613b08565b818152848101925060609182028401850191888311156143a257600080fd5b938501935b828510156143ec5780858a0312156143bf5760008081fd5b6143c7613a7a565b85518152868601518782015260408087015190820152845293840193928501926143a7565b50979650505050505050565b60006020828403121561440a57600080fd5b5051919050565b6000606080830186845260208281860152818751808452608087019150828901935060005b81811015614466578451805184528481015185850152604090810151908401529383019391850191600101614436565b505080945050505050826040830152949350505050565b600082601f83011261448e57600080fd5b815161449c613b6d82613b38565b8181528460208386010111156144b157600080fd5b612de98260208301602087016138be565b600082601f8301126144d357600080fd5b6144db613ae6565b8060e08401858111156144ed57600080fd5b845b81811015613ca45780516001600160401b038082111561450f5760008081fd5b908701906060828a0312156145245760008081fd5b61452c613a7a565b82518281111561453c5760008081fd5b6145488b82860161447d565b8252506020808401518381111561455f5760008081fd5b61456b8c82870161447d565b8284015250604080850151848111156145845760008081fd5b6145908d82880161447d565b91840191909152509087529095019450506020016144ef565b6000601f83818401126145bb57600080fd5b6145c3613a7a565b8060608501868111156145d557600080fd5b855b81811015613d785780516001600160401b03808211156145f75760008081fd5b8189019150898783011261460b5760008081fd5b614613613ae6565b8060e084018c8111156146265760008081fd5b845b8181101561465b578051858111156146405760008081fd5b61464c8f82890161447d565b85525060209384019301614628565b5050875250506020948501949190910190506145d7565b600060a0828403121561468457600080fd5b61468c613aa2565b905081516001600160401b03808211156146a557600080fd5b6146b18583860161447d565b835260208401519150808211156146c757600080fd5b6146d38583860161447d565b602084015260408401519150808211156146ec57600080fd5b6146f88583860161447d565b6040840152606084015191508082111561471157600080fd5b61471d858386016145a9565b6060840152608084015191508082111561473657600080fd5b50613e558482850161447d565b60006020828403121561475557600080fd5b81516001600160401b038082111561476c57600080fd5b9083019060c0828603121561478057600080fd5b614788613ac4565b8251815260208301518281111561479e57600080fd5b6147aa8782860161447d565b6020830152506040830151828111156147c257600080fd5b6147ce878286016144c2565b6040830152506060830151828111156147e657600080fd5b6147f2878286016144c2565b60608301525060808301518281111561480a57600080fd5b614816878286016144c2565b60808301525060a08301518281111561482e57600080fd5b613f5887828601614672565b60008260e081018360005b6007811015613ca4578383038752815160608151818652614868828701826138e2565b9150506020808301518683038288015261488283826138e2565b9250506040808401519350868303818801525061489f82846138e2565b99810199955093909301925050600101614845565b6000602080835260e08451828501528185015160c060408601526148da828601826138e2565b90506040860151601f19808784030160608801526148f8838361483a565b92506060880151915080878403016080880152614915838361483a565b925060808801519150808784030160a0880152614932838361483a565b925060a08801519150808784030160c088015250805160a0835261495960a08401826138e2565b9050848201518382038685015261497082826138e2565b9150506040820151838203604085015261498a82826138e2565b9150506060820151838203606085015281829050606083016000805b60038110156149fc5785830384528451838a8101845b60078110156149e75786820383526149d58285516138e2565b938e0193928e019291506001016149bc565b50968c0196958c0195945050506001016149a6565b5050608085015197508581036080870152614a1781896138e2565b9b9a5050505050505050505050565b600060208284031215614a3857600080fd5b81516001600160401b03811115614a4e57600080fd5b612de98482850161447d565b60008151614a6c8185602086016138be565b9290920192915050565b7f7b226e616d65223a2022426174746c65736869707a3a20000000000000000000815260008651614aae816017850160208b016138be565b7f222c20226465736372697074696f6e223a2022416e2041534349492d616e696d6017918401918201527f6174656420737061636520616476656e747572652c20696e766164652074686560378201527f20626c6f636b636861696e20776974682031303025204f6e2d436861696e204260578201527f6174746c65736869707a2e222c2022696d616765223a2022646174613a696d6160778201527119d94bdcdd99cade1b5b0ed8985cd94d8d0b60721b60978201528651614b788160a9840160208b016138be565b7f222c2261747472696275746573223a205b7b2274726169745f74797065223a2260a992909101918201527121b630b9b9911610113b30b63ab2911d101160711b60c9820152614c7b614c6d614c5f614c59614c22614c1c614bdd60db88018d614a5a565b7f227d2c207b2274726169745f74797065223a202250617274732052617269747981526c111610113b30b63ab2911d101160991b6020820152602d0190565b8a614a5a565b7f227d2c207b2274726169745f74797065223a2022536b696e222c202276616c7581526432911d101160d91b602082015260250190565b87614a5a565b61227d60f01b815260020190565b615d7d60f01b815260020190565b98975050505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251614cbf81601d8501602087016138be565b91909101601d0192915050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351614d9c8160178501602088016138be565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351614dcd8160288401602088016138be565b01602801949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b600081614e7f57614e7f614174565b506000190190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090614eba908301846138e2565b9695505050505050565b600060208284031215614ed657600080fd5b815161351f8161383156fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862aa2646970667358221220f2c742df7fc218f74ccb2f7f40d69048917ccac2a44158d0179317711f73e65664736f6c63430008120033
Deployed Bytecode
0x6080604052600436106103ad5760003560e01c80636352211e116101e7578063b7c0b8e81161010d578063d5abeb01116100a0578063e985e9c51161006f578063e985e9c514610b29578063ee1c96a214610b72578063f4a0a52814610bab578063fb796e6c14610bcb57600080fd5b8063d5abeb0114610a91578063db4bec4414610aa8578063e0d4ea3714610ad9578063e63ab1e914610b0757600080fd5b8063c97441ee116100dc578063c97441ee14610a1d578063d2cab05614610a3d578063d325010614610a50578063d547741f14610a7157600080fd5b8063b7c0b8e81461099d578063b88d4fde146109bd578063c7347c03146109dd578063c87b56dd146109fd57600080fd5b80638462151c1161018557806396173519116101545780639617351914610931578063a217fddf14610951578063a22cb46514610966578063a2309ff81461098657600080fd5b80638462151c1461089a578063906db03b146108c757806391d14854146108fc57806395d89b411461091c57600080fd5b80637501f741116101c15780637501f741146108135780637cb647591461082a5780637f2fee431461084a5780638456cb591461088557600080fd5b80636352211e146107bc5780636817c76c146107dc57806370a08231146107f357600080fd5b80632f2ff15d116102d75780634eebbb3b1161026a578063572316401161023957806357231640146107585780635bcc7928146107785780635c975abb1461078d5780635e84d723146107a557600080fd5b80634eebbb3b146106d2578063519d474e146106f2578063547520fe1461071857806355a63bf41461073857600080fd5b80633f4ba83a116102a65780633f4ba83a1461065d578063424611c31461067257806342842e0e14610692578063485cc955146106b257600080fd5b80632f2ff15d146105e657806333e614131461060657806336568abe1461061d5780633ca5d0581461063d57600080fd5b806326aa420a1161034f5780632db115441161031e5780632db115441461057b5780632e1a7d4d1461058e5780632eb4a7ab146105ae5780632f1a8fcf146105c557600080fd5b806326aa420a146104e157806326d938001461050157806329b6eca91461051c5780632a55205a1461053c57600080fd5b8063081812fc1161038b578063081812fc1461042b578063095ea7b31461046357806323b872dd14610483578063248a9ca3146104a357600080fd5b806301ffc9a7146103b257806304634d8d146103e757806306fdde0314610409575b600080fd5b3480156103be57600080fd5b506103d26103cd366004613847565b610be6565b60405190151581526020015b60405180910390f35b3480156103f357600080fd5b50610407610402366004613879565b610bf7565b005b34801561041557600080fd5b5061041e610c11565b6040516103de919061390e565b34801561043757600080fd5b5061044b610446366004613921565b610ca3565b6040516001600160a01b0390911681526020016103de565b34801561046f57600080fd5b5061040761047e36600461393a565b610cca565b34801561048f57600080fd5b5061040761049e366004613966565b610cea565b3480156104af57600080fd5b506104d36104be366004613921565b600090815260fb602052604090206001015490565b6040519081526020016103de565b3480156104ed57600080fd5b506104076104fc366004613921565b610d21565b34801561050d57600080fd5b5061019a546103d29060ff1681565b34801561052857600080fd5b506104076105373660046139a7565b610d33565b34801561054857600080fd5b5061055c6105573660046139c4565b610d68565b604080516001600160a01b0390931683526020830191909152016103de565b610407610589366004613921565b610e14565b34801561059a57600080fd5b506104076105a9366004613921565b6110d6565b3480156105ba57600080fd5b506104d361019d5481565b3480156105d157600080fd5b506101925461044b906001600160a01b031681565b3480156105f257600080fd5b506104076106013660046139e6565b611184565b34801561061257600080fd5b506104d361019b5481565b34801561062957600080fd5b506104076106383660046139e6565b6111a9565b34801561064957600080fd5b50610407610658366004613a1b565b611223565b34801561066957600080fd5b50610407611276565b34801561067e57600080fd5b506104d361068d366004613921565b611296565b34801561069e57600080fd5b506104076106ad366004613966565b6112dd565b3480156106be57600080fd5b506104076106cd366004613a36565b61130e565b3480156106de57600080fd5b5061019a546103d290610100900460ff1681565b3480156106fe57600080fd5b5061019f5461044b9061010090046001600160a01b031681565b34801561072457600080fd5b50610407610733366004613921565b611575565b34801561074457600080fd5b50610407610753366004613921565b611587565b34801561076457600080fd5b5061041e610773366004613e61565b611599565b34801561078457600080fd5b5061041e6117a3565b34801561079957600080fd5b5060c95460ff166103d2565b3480156107b157600080fd5b506104d361019c5481565b3480156107c857600080fd5b5061044b6107d7366004613921565b611832565b3480156107e857600080fd5b506104d36101975481565b3480156107ff57600080fd5b506104d361080e3660046139a7565b611892565b34801561081f57600080fd5b506104d36101985481565b34801561083657600080fd5b50610407610845366004613921565b611918565b34801561085657600080fd5b5061086a610865366004613f67565b61192a565b604080519384526020840192909252908201526060016103de565b34801561089157600080fd5b5061040761197b565b3480156108a657600080fd5b506108ba6108b53660046139a7565b61199b565b6040516103de9190613f9c565b3480156108d357600080fd5b506108e76108e2366004613fd4565b611a92565b604080519283526020830191909152016103de565b34801561090857600080fd5b506103d26109173660046139e6565b611b6c565b34801561092857600080fd5b5061041e611b97565b34801561093d57600080fd5b5061040761094c3660046139a7565b611ba6565b34801561095d57600080fd5b506104d3600081565b34801561097257600080fd5b50610407610981366004614008565b611bd5565b34801561099257600080fd5b506104d36101965481565b3480156109a957600080fd5b506104076109b8366004613a1b565b611bf5565b3480156109c957600080fd5b506104076109d836600461403d565b611c15565b3480156109e957600080fd5b506104076109f83660046139a7565b611c4e565b348015610a0957600080fd5b5061041e610a18366004613921565b611c7d565b348015610a2957600080fd5b50610407610a38366004613a1b565b611f16565b610407610a4b3660046140bc565b611f73565b348015610a5c57600080fd5b506101915461044b906001600160a01b031681565b348015610a7d57600080fd5b50610407610a8c3660046139e6565b6122c3565b348015610a9d57600080fd5b506104d36101955481565b348015610ab457600080fd5b506103d2610ac33660046139a7565b61019e6020526000908152604090205460ff1681565b348015610ae557600080fd5b506104d3610af4366004613921565b6000908152610194602052604090205490565b348015610b1357600080fd5b506104d3600080516020614f2283398151915281565b348015610b3557600080fd5b506103d2610b44366004613a36565b6001600160a01b039182166000908152609c6020908152604080832093909416825291909152205460ff1690565b348015610b7e57600080fd5b506104d3610b8d36600461393a565b6101a160209081526000928352604080842090915290825290205481565b348015610bb757600080fd5b50610407610bc6366004613921565b6122e8565b348015610bd757600080fd5b5061019f546103d29060ff1681565b6000610bf1826122fa565b92915050565b6000610c0281612305565b610c0c838361230f565b505050565b606060978054610c209061413a565b80601f0160208091040260200160405190810160405280929190818152602001828054610c4c9061413a565b8015610c995780601f10610c6e57610100808354040283529160200191610c99565b820191906000526020600020905b815481529060010190602001808311610c7c57829003601f168201915b5050505050905090565b6000610cae8261240c565b506000908152609b60205260409020546001600160a01b031690565b8161019f5460ff1615610ce057610ce08161246b565b610c0c83836124af565b826001600160a01b0381163314610d105761019f5460ff1615610d1057610d103361246b565b610d1b8484846125bf565b50505050565b6000610d2c81612305565b5061019c55565b6000610d3e81612305565b5061019f80546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60008281526066602090815260408083208151808301909252546001600160a01b038116808352600160a01b9091046001600160601b0316928201929092528291610ddd5750604080518082019091526065546001600160a01b0381168252600160a01b90046001600160601b031660208201525b602081015160009061271090610dfc906001600160601b03168761418a565b610e0691906141a1565b915196919550909350505050565b323314610e685760405162461bcd60e51b815260206004820152601d60248201527f436f6e747261637473206e6f7420616c6c6f77656420746f206d696e7400000060448201526064015b60405180910390fd5b610e706125f0565b61019854610e7d33611892565b1115610ecb5760405162461bcd60e51b815260206004820152601b60248201527f4d6178206d696e74207065722077616c6c6574207265616368656400000000006044820152606401610e5f565b61019a5460ff16610f1e5760405162461bcd60e51b815260206004820152601860248201527f5075626c69632073616c65206e6f74206c6976652079657400000000000000006044820152606401610e5f565b61019854811115610f655760405162461bcd60e51b815260206004820152601160248201527013585e081b5a5b9d08195e18d959591959607a1b6044820152606401610e5f565b610195548161019654011115610fb25760405162461bcd60e51b815260206004820152601260248201527145786365656473206d617820737570706c7960701b6044820152606401610e5f565b61019c54816101965401111561100a5760405162461bcd60e51b815260206004820152601860248201527f4d6178207075626c6963206d696e7420657863656564656400000000000000006044820152606401610e5f565b61019754611018908261418a565b34101561105a5760405162461bcd60e51b815260206004820152601060248201526f2737ba1032b737bab3b41032ba3432b960811b6044820152606401610e5f565b60005b818163ffffffff1610156110c75760006110776101935490565b905061108861019380546001019055565b600061109382611296565b60008381526101946020526040902081905590506110b2335b8361264b565b5050610196805460019081019091550161105d565b506110d3600161015f55565b50565b60006110e181612305565b6110e96125f0565b604051600090339084908381818185875af1925050503d806000811461112b576040519150601f19603f3d011682016040523d82523d6000602084013e611130565b606091505b50509050806111745760405162461bcd60e51b815260206004820152601060248201526f5472616e73666572206661696c65642160801b6044820152606401610e5f565b50611180600161015f55565b5050565b600082815260fb602052604090206001015461119f81612305565b610c0c8383612665565b6001600160a01b03811633146112195760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610e5f565b61118082826126eb565b600061122e81612305565b8115611261576040805180820190915260068152657075626c696360d01b60208201526101999061125f9082614211565b505b5061019a805460ff1916911515919091179055565b600080516020614f2283398151915261128e81612305565b6110d3612752565b6000816112a46001436142d0565b60408051602081019390935290409082015242606082015260800160408051601f19818403018152919052805160209091012092915050565b826001600160a01b03811633146113035761019f5460ff1615611303576113033361246b565b610d1b8484846127a4565b600054610100900460ff161580801561132e5750600054600160ff909116105b806113485750303b158015611348575060005460ff166001145b6113ab5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610e5f565b6000805460ff1916600117905580156113ce576000805461ff0019166101001790555b6114186040518060400160405280600b81526020016a2130ba3a3632b9b434b83d60a91b8152506040518060400160405280600581526020016429a424a82d60d91b8152506127bf565b6114206127f0565b611428612821565b61019280546001600160a01b038086166001600160a01b031992831617909255610191805492851692909116919091179055611462612848565b61019f805460ff1916600117905561147c3361028a61230f565b611487600033612665565b61149f600080516020614f2283398151915233612665565b612710610195556000610196556611c37937e08000610197556005610198556040805180820190915260098152681dda1a5d195b1a5cdd60ba1b6020820152610199906114ec9082614211565b5061019a805461ffff1916905561138861019b81905561019c557fb1fdc7a0eaa5b56209817635a86bed9e86c149fbb2a0dff83a2af2a797065e7061019d558015610c0c576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050565b600061158081612305565b5061019855565b600061159281612305565b5061019b55565b60606000806115ab8460400151611a92565b915091506000806115bf8660600151611a92565b915091506000806115d38860800151611a92565b90925090506000826115e586896142e3565b6115ef91906142e3565b90506000826115fe86896142e3565b61160891906142e3565b9050600061161782600561418a565b905060008161162785606461418a565b61163191906141a1565b90506014811161166857505060408051808201909152600681526521b7b6b6b7b760d11b60208201529a9950505050505050505050565b601481118015611679575060288111155b156116ad5750506040805180820190915260088152672ab731b7b6b6b7b760c11b60208201529a9950505050505050505050565b6028811180156116be5750603c8111155b156116ee5750506040805180820190915260048152635261726560e01b60208201529a9950505050505050505050565b603c811180156116ff575060508111155b1561172f5750506040805180820190915260048152634570696360e01b60208201529a9950505050505050505050565b605081118015611740575060648111155b156117755750506040805180820190915260098152684c6567656e6461727960b81b60208201529a9950505050505050505050565b50506040805180820190915260078152662ab735b737bbb760c91b60208201529a9950505050505050505050565b61019980546117b19061413a565b80601f01602080910402602001604051908101604052809291908181526020018280546117dd9061413a565b801561182a5780601f106117ff5761010080835404028352916020019161182a565b820191906000526020600020905b81548152906001019060200180831161180d57829003601f168201915b505050505081565b6000818152609960205260408120546001600160a01b031680610bf15760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610e5f565b60006001600160a01b0382166118fc5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610e5f565b506001600160a01b03166000908152609a602052604090205490565b600061192381612305565b5061019d55565b6101a0602052826000526040600020602052816000526040600020818154811061195357600080fd5b6000918252602090912060039091020180546001820154600290920154909450909250905083565b600080516020614f2283398151915261199381612305565b6110d3612867565b606060006119a883611892565b90506000816001600160401b038111156119c4576119c4613a64565b6040519080825280602002602001820160405280156119ed578160200160208202803683370190505b5090506000805b61019554811015611a8857818414611a88576000818152609960205260409020546001600160a01b031615158015611a455750856001600160a01b0316611a3a82611832565b6001600160a01b0316145b15611a765780838381518110611a5d57611a5d6142f6565b602090810291909101015281611a728161430c565b9250505b80611a808161430c565b9150506119f4565b5090949350505050565b60008060008060005b6007811015611b6157611b09868260078110611ab957611ab96142f6565b6020908102919091015151604080518082019091526005815264456d70747960d81b9083015280519101207fc4ce3210982aa6fc94dabe46dc1dbf454d54a3a2fbc51d2ae982e47c784f46081490565b611b4f576000611b32878360078110611b2457611b246142f6565b6020020151604001516128a4565b9050611b3e81856142e3565b935082611b4a8161430c565b935050505b80611b598161430c565b915050611a9b565b509094909350915050565b600091825260fb602090815260408084206001600160a01b0393909316845291905290205460ff1690565b606060988054610c209061413a565b6000611bb181612305565b5061019180546001600160a01b0319166001600160a01b0392909216919091179055565b8161019f5460ff1615611beb57611beb8161246b565b610c0c8383612a4f565b6000611c0081612305565b5061019f805460ff1916911515919091179055565b836001600160a01b0381163314611c3b5761019f5460ff1615611c3b57611c3b3361246b565b611c4785858585612a5a565b5050505050565b6000611c5981612305565b5061019280546001600160a01b0319166001600160a01b0392909216919091179055565b60008181526101946020526040812054606091611c9984611832565b61019f54604051633656970960e11b81526001600160a01b0380841660048301526024820188905292935060009261010090920490911690636f4af3709085908390636cad2e1290604401600060405180830381865afa158015611d01573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d299190810190614325565b61019f5460405163553a74e560e01b81526001600160a01b038881166004830152602482018c90526101009092049091169063553a74e590604401602060405180830381865afa158015611d81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da591906143f8565b6040518463ffffffff1660e01b8152600401611dc393929190614411565b600060405180830381865afa158015611de0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e089190810190614743565b6101925460405163074e768b60e21b81529192506000916001600160a01b0390911690631d39da2c90611e3f9085906004016148b4565b600060405180830381865afa158015611e5c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e849190810190614a26565b90506000611ed9611e9488612a8c565b611e9d84612b1e565b8560200151611eab87611599565b60a088015151604051611ec5959493929190602001614a76565b604051602081830303815290604052612b1e565b604080516020808201835260008252915192935091611efa91849101614c87565b60408051601f1981840301815291905298975050505050505050565b6000611f2181612305565b8115611f57576040805180820190915260098152681dda1a5d195b1a5cdd60ba1b602082015261019990611f559082614211565b505b5061019a80549115156101000261ff0019909216919091179055565b323314611fc25760405162461bcd60e51b815260206004820152601d60248201527f436f6e747261637473206e6f7420616c6c6f77656420746f206d696e740000006044820152606401610e5f565b61019854611fcf33611892565b111561201d5760405162461bcd60e51b815260206004820152601b60248201527f4d6178206d696e74207065722077616c6c6574207265616368656400000000006044820152606401610e5f565b61019a54610100900460ff1661206c5760405162461bcd60e51b815260206004820152601460248201527315db081cd85b19481b9bdd081b1a5d99481e595d60621b6044820152606401610e5f565b6040516bffffffffffffffffffffffff193360601b1660208201526000906034016040516020818303038152906040528051906020012090506120e78383808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505061019d549150849050612c70565b6121255760405162461bcd60e51b815260206004820152600f60248201526e139bdd081dda1a5d195b1a5cdd1959608a1b6044820152606401610e5f565b6101985484111561216c5760405162461bcd60e51b815260206004820152601160248201527013585e081b5a5b9d08195e18d959591959607a1b6044820152606401610e5f565b6101955484610196540111156121b95760405162461bcd60e51b815260206004820152601260248201527145786365656473206d617820737570706c7960701b6044820152606401610e5f565b61019b5484610196540111156122085760405162461bcd60e51b815260206004820152601460248201527313585e081ddb081b5a5b9d08195e18d95959195960621b6044820152606401610e5f565b61019754612216908561418a565b3410156122585760405162461bcd60e51b815260206004820152601060248201526f2737ba1032b737bab3b41032ba3432b960811b6044820152606401610e5f565b60005b848163ffffffff161015611c475760006122756101935490565b905061228661019380546001019055565b600061229182611296565b60008381526101946020526040902081905590506122ae336110ac565b5050610196805460019081019091550161225b565b600082815260fb60205260409020600101546122de81612305565b610c0c83836126eb565b60006122f381612305565b5061019755565b6000610bf182612c86565b6110d38133612cab565b6127106001600160601b038216111561237d5760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b6064820152608401610e5f565b6001600160a01b0382166123d35760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401610e5f565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217606555565b6000818152609960205260409020546001600160a01b03166110d35760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610e5f565b69c617113400112233445560005230601a5280603a52600080604460166daaeb6d7670e522a718067333cd4e5afa6124a7573d6000803e3d6000fd5b6000603a5250565b60006124ba82611832565b9050806001600160a01b0316836001600160a01b0316036125275760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610e5f565b336001600160a01b038216148061254357506125438133610b44565b6125b55760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610e5f565b610c0c8383612d04565b6125c93382612d72565b6125e55760405162461bcd60e51b8152600401610e5f90614ccc565b610c0c838383612df1565b600261015f54036126435760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610e5f565b600261015f55565b611180828260405180602001604052806000815250612f62565b61266f8282611b6c565b61118057600082815260fb602090815260408083206001600160a01b03851684529091529020805460ff191660011790556126a73390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6126f58282611b6c565b1561118057600082815260fb602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b61275a612f95565b60c9805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b610c0c83838360405180602001604052806000815250611c15565b600054610100900460ff166127e65760405162461bcd60e51b8152600401610e5f90614d19565b6111808282612fde565b600054610100900460ff166128175760405162461bcd60e51b8152600401610e5f90614d19565b61281f61301e565b565b600054610100900460ff1661281f5760405162461bcd60e51b8152600401610e5f90614d19565b61281f733cc6cdda760b79bafa08df41ecfa224f810dceb66001613051565b61286f6130c6565b60c9805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586127873390565b60408051808201909152600681526521b7b6b6b7b760d11b6020918201528151908201206000907f3b031f7f29326d3f445a56aaa83a78114c260f1e40af44c50964d9edf6271f4a036128f957506001919050565b6040805180820190915260088152672ab731b7b6b6b7b760c11b6020918201528251908301207f2a19cece7381d374050418c2bff2b7de5d6ca0adbe97e81c12b0540ace359d200361294d57506002919050565b6040805180820190915260048152635261726560e01b6020918201528251908301207fd02e3141a8e0af092cd3cce39f1f91e61e81a816e83e58a487f98f6c3b238dfa0361299d57506003919050565b6040805180820190915260048152634570696360e01b6020918201528251908301207f6764d804d57285ae9d4c42cc380377d3d0ee9b90ff9eeccaa32d3b2e3e8d7f17036129ed57506004919050565b6040805180820190915260098152684c6567656e6461727960b81b6020918201528251908301207f181ebe3a8fa130246d49bfd123ac54849b05bdcd02c6b1322c78de2a3988a31003612a4257506005919050565b506000919050565b919050565b61118033838361310c565b612a643383612d72565b612a805760405162461bcd60e51b8152600401610e5f90614ccc565b610d1b848484846131da565b60606000612a998361320d565b60010190506000816001600160401b03811115612ab857612ab8613a64565b6040519080825280601f01601f191660200182016040528015612ae2576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612aec57509392505050565b60608151600003612b3d57505060408051602081019091526000815290565b6000604051806060016040528060408152602001614ee26040913990506000600384516002612b6c91906142e3565b612b7691906141a1565b612b8190600461418a565b6001600160401b03811115612b9857612b98613a64565b6040519080825280601f01601f191660200182016040528015612bc2576020820181803683370190505b509050600182016020820185865187015b80821015612c2e576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250612bd3565b5050600386510660018114612c4a5760028114612c5d57612c65565b603d6001830353603d6002830353612c65565b603d60018303535b509195945050505050565b600082612c7d85846132e5565b14949350505050565b60006001600160e01b03198216637965db0b60e01b1480610bf15750610bf182613332565b612cb58282611b6c565b61118057612cc281613372565b612ccd836020613384565b604051602001612cde929190614d64565b60408051601f198184030181529082905262461bcd60e51b8252610e5f9160040161390e565b6000818152609b6020526040902080546001600160a01b0319166001600160a01b0384169081179091558190612d3982611832565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600080612d7e83611832565b9050806001600160a01b0316846001600160a01b03161480612dc557506001600160a01b038082166000908152609c602090815260408083209388168352929052205460ff165b80612de95750836001600160a01b0316612dde84610ca3565b6001600160a01b0316145b949350505050565b826001600160a01b0316612e0482611832565b6001600160a01b031614612e2a5760405162461bcd60e51b8152600401610e5f90614dd9565b6001600160a01b038216612e8c5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610e5f565b612e998383836001613526565b826001600160a01b0316612eac82611832565b6001600160a01b031614612ed25760405162461bcd60e51b8152600401610e5f90614dd9565b6000818152609b6020908152604080832080546001600160a01b03199081169091556001600160a01b03878116808652609a8552838620805460001901905590871680865283862080546001019055868652609990945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b612f6c8383613533565b612f7960008484846136cc565b610c0c5760405162461bcd60e51b8152600401610e5f90614e1e565b60c95460ff1661281f5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610e5f565b600054610100900460ff166130055760405162461bcd60e51b8152600401610e5f90614d19565b60976130118382614211565b506098610c0c8282614211565b600054610100900460ff166130455760405162461bcd60e51b8152600401610e5f90614d19565b60c9805460ff19169055565b6001600160a01b0390911690637d3e3dbe8161307e57826130775750634420e48661307e565b5063a0af29035b8060e01b60005230600452826024526004600060446000806daaeb6d7670e522a718067333cd4e5af16130bc578060005160e01c036130bc57600080fd5b5060006024525050565b60c95460ff161561281f5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610e5f565b816001600160a01b0316836001600160a01b03160361316d5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610e5f565b6001600160a01b038381166000818152609c6020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6131e5848484612df1565b6131f1848484846136cc565b610d1b5760405162461bcd60e51b8152600401610e5f90614e1e565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061324c5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310613278576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061329657662386f26fc10000830492506010015b6305f5e10083106132ae576305f5e100830492506008015b61271083106132c257612710830492506004015b606483106132d4576064830492506002015b600a8310610bf15760010192915050565b600081815b845181101561332a5761331682868381518110613309576133096142f6565b60200260200101516137cd565b9150806133228161430c565b9150506132ea565b509392505050565b60006001600160e01b031982166380ac58cd60e01b148061336357506001600160e01b03198216635b5e139f60e01b145b80610bf15750610bf1826137fc565b6060610bf16001600160a01b03831660145b6060600061339383600261418a565b61339e9060026142e3565b6001600160401b038111156133b5576133b5613a64565b6040519080825280601f01601f1916602001820160405280156133df576020820181803683370190505b509050600360fc1b816000815181106133fa576133fa6142f6565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110613429576134296142f6565b60200101906001600160f81b031916908160001a905350600061344d84600261418a565b6134589060016142e3565b90505b60018111156134d0576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061348c5761348c6142f6565b1a60f81b8282815181106134a2576134a26142f6565b60200101906001600160f81b031916908160001a90535060049490941c936134c981614e70565b905061345b565b50831561351f5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610e5f565b9392505050565b61352e6130c6565b610d1b565b6001600160a01b0382166135895760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610e5f565b6000818152609960205260409020546001600160a01b0316156135ee5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610e5f565b6135fc600083836001613526565b6000818152609960205260409020546001600160a01b0316156136615760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610e5f565b6001600160a01b0382166000818152609a6020908152604080832080546001019055848352609990915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60006001600160a01b0384163b156137c257604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290613710903390899088908890600401614e87565b6020604051808303816000875af192505050801561374b575060408051601f3d908101601f1916820190925261374891810190614ec4565b60015b6137a8573d808015613779576040519150601f19603f3d011682016040523d82523d6000602084013e61377e565b606091505b5080516000036137a05760405162461bcd60e51b8152600401610e5f90614e1e565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050612de9565b506001949350505050565b60008183106137e957600082815260208490526040902061351f565b600083815260208390526040902061351f565b60006001600160e01b0319821663152a902d60e11b1480610bf157506301ffc9a760e01b6001600160e01b0319831614610bf1565b6001600160e01b0319811681146110d357600080fd5b60006020828403121561385957600080fd5b813561351f81613831565b6001600160a01b03811681146110d357600080fd5b6000806040838503121561388c57600080fd5b823561389781613864565b915060208301356001600160601b03811681146138b357600080fd5b809150509250929050565b60005b838110156138d95781810151838201526020016138c1565b50506000910152565b600081518084526138fa8160208601602086016138be565b601f01601f19169290920160200192915050565b60208152600061351f60208301846138e2565b60006020828403121561393357600080fd5b5035919050565b6000806040838503121561394d57600080fd5b823561395881613864565b946020939093013593505050565b60008060006060848603121561397b57600080fd5b833561398681613864565b9250602084013561399681613864565b929592945050506040919091013590565b6000602082840312156139b957600080fd5b813561351f81613864565b600080604083850312156139d757600080fd5b50508035926020909101359150565b600080604083850312156139f957600080fd5b8235915060208301356138b381613864565b80358015158114612a4a57600080fd5b600060208284031215613a2d57600080fd5b61351f82613a0b565b60008060408385031215613a4957600080fd5b8235613a5481613864565b915060208301356138b381613864565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715613a9c57613a9c613a64565b60405290565b60405160a081016001600160401b0381118282101715613a9c57613a9c613a64565b60405160c081016001600160401b0381118282101715613a9c57613a9c613a64565b60405160e081016001600160401b0381118282101715613a9c57613a9c613a64565b604051601f8201601f191681016001600160401b0381118282101715613b3057613b30613a64565b604052919050565b60006001600160401b03821115613b5157613b51613a64565b50601f01601f191660200190565b6000613b72613b6d84613b38565b613b08565b9050828152838383011115613b8657600080fd5b828260208301376000602084830101529392505050565b600082601f830112613bae57600080fd5b61351f83833560208501613b5f565b600082601f830112613bce57600080fd5b613bd6613ae6565b8060e0840185811115613be857600080fd5b845b81811015613ca45780356001600160401b0380821115613c0a5760008081fd5b908701906060828a031215613c1f5760008081fd5b613c27613a7a565b823582811115613c375760008081fd5b613c438b828601613b9d565b82525060208084013583811115613c5a5760008081fd5b613c668c828701613b9d565b828401525060408085013584811115613c7f5760008081fd5b613c8b8d828801613b9d565b9184019190915250908752909501945050602001613bea565b509095945050505050565b6000601f8381840112613cc157600080fd5b613cc9613a7a565b806060850186811115613cdb57600080fd5b855b81811015613d785780356001600160401b0380821115613cfd5760008081fd5b81890191508987830112613d115760008081fd5b613d19613ae6565b8060e084018c811115613d2c5760008081fd5b845b81811015613d6157803585811115613d465760008081fd5b613d528f828901613b9d565b85525060209384019301613d2e565b505087525050602094850194919091019050613cdd565b50909695505050505050565b600060a08284031215613d9657600080fd5b613d9e613aa2565b905081356001600160401b0380821115613db757600080fd5b613dc385838601613b9d565b83526020840135915080821115613dd957600080fd5b613de585838601613b9d565b60208401526040840135915080821115613dfe57600080fd5b613e0a85838601613b9d565b60408401526060840135915080821115613e2357600080fd5b613e2f85838601613caf565b60608401526080840135915080821115613e4857600080fd5b50613e5584828501613b9d565b60808301525092915050565b600060208284031215613e7357600080fd5b81356001600160401b0380821115613e8a57600080fd5b9083019060c08286031215613e9e57600080fd5b613ea6613ac4565b82358152602083013582811115613ebc57600080fd5b613ec887828601613b9d565b602083015250604083013582811115613ee057600080fd5b613eec87828601613bbd565b604083015250606083013582811115613f0457600080fd5b613f1087828601613bbd565b606083015250608083013582811115613f2857600080fd5b613f3487828601613bbd565b60808301525060a083013582811115613f4c57600080fd5b613f5887828601613d84565b60a08301525095945050505050565b600080600060608486031215613f7c57600080fd5b8335613f8781613864565b95602085013595506040909401359392505050565b6020808252825182820181905260009190848201906040850190845b81811015613d7857835183529284019291840191600101613fb8565b600060208284031215613fe657600080fd5b81356001600160401b03811115613ffc57600080fd5b612de984828501613bbd565b6000806040838503121561401b57600080fd5b823561402681613864565b915061403460208401613a0b565b90509250929050565b6000806000806080858703121561405357600080fd5b843561405e81613864565b9350602085013561406e81613864565b92506040850135915060608501356001600160401b0381111561409057600080fd5b8501601f810187136140a157600080fd5b6140b087823560208401613b5f565b91505092959194509250565b6000806000604084860312156140d157600080fd5b8335925060208401356001600160401b03808211156140ef57600080fd5b818601915086601f83011261410357600080fd5b81358181111561411257600080fd5b8760208260051b850101111561412757600080fd5b6020830194508093505050509250925092565b600181811c9082168061414e57607f821691505b60208210810361416e57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610bf157610bf1614174565b6000826141be57634e487b7160e01b600052601260045260246000fd5b500490565b601f821115610c0c57600081815260208120601f850160051c810160208610156141ea5750805b601f850160051c820191505b81811015614209578281556001016141f6565b505050505050565b81516001600160401b0381111561422a5761422a613a64565b61423e81614238845461413a565b846141c3565b602080601f831160018114614273576000841561425b5750858301515b600019600386901b1c1916600185901b178555614209565b600085815260208120601f198616915b828110156142a257888601518255948401946001909101908401614283565b50858210156142c05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b81810381811115610bf157610bf1614174565b80820180821115610bf157610bf1614174565b634e487b7160e01b600052603260045260246000fd5b60006001820161431e5761431e614174565b5060010190565b6000602080838503121561433857600080fd5b82516001600160401b038082111561434f57600080fd5b818501915085601f83011261436357600080fd5b81518181111561437557614375613a64565b614383848260051b01613b08565b818152848101925060609182028401850191888311156143a257600080fd5b938501935b828510156143ec5780858a0312156143bf5760008081fd5b6143c7613a7a565b85518152868601518782015260408087015190820152845293840193928501926143a7565b50979650505050505050565b60006020828403121561440a57600080fd5b5051919050565b6000606080830186845260208281860152818751808452608087019150828901935060005b81811015614466578451805184528481015185850152604090810151908401529383019391850191600101614436565b505080945050505050826040830152949350505050565b600082601f83011261448e57600080fd5b815161449c613b6d82613b38565b8181528460208386010111156144b157600080fd5b612de98260208301602087016138be565b600082601f8301126144d357600080fd5b6144db613ae6565b8060e08401858111156144ed57600080fd5b845b81811015613ca45780516001600160401b038082111561450f5760008081fd5b908701906060828a0312156145245760008081fd5b61452c613a7a565b82518281111561453c5760008081fd5b6145488b82860161447d565b8252506020808401518381111561455f5760008081fd5b61456b8c82870161447d565b8284015250604080850151848111156145845760008081fd5b6145908d82880161447d565b91840191909152509087529095019450506020016144ef565b6000601f83818401126145bb57600080fd5b6145c3613a7a565b8060608501868111156145d557600080fd5b855b81811015613d785780516001600160401b03808211156145f75760008081fd5b8189019150898783011261460b5760008081fd5b614613613ae6565b8060e084018c8111156146265760008081fd5b845b8181101561465b578051858111156146405760008081fd5b61464c8f82890161447d565b85525060209384019301614628565b5050875250506020948501949190910190506145d7565b600060a0828403121561468457600080fd5b61468c613aa2565b905081516001600160401b03808211156146a557600080fd5b6146b18583860161447d565b835260208401519150808211156146c757600080fd5b6146d38583860161447d565b602084015260408401519150808211156146ec57600080fd5b6146f88583860161447d565b6040840152606084015191508082111561471157600080fd5b61471d858386016145a9565b6060840152608084015191508082111561473657600080fd5b50613e558482850161447d565b60006020828403121561475557600080fd5b81516001600160401b038082111561476c57600080fd5b9083019060c0828603121561478057600080fd5b614788613ac4565b8251815260208301518281111561479e57600080fd5b6147aa8782860161447d565b6020830152506040830151828111156147c257600080fd5b6147ce878286016144c2565b6040830152506060830151828111156147e657600080fd5b6147f2878286016144c2565b60608301525060808301518281111561480a57600080fd5b614816878286016144c2565b60808301525060a08301518281111561482e57600080fd5b613f5887828601614672565b60008260e081018360005b6007811015613ca4578383038752815160608151818652614868828701826138e2565b9150506020808301518683038288015261488283826138e2565b9250506040808401519350868303818801525061489f82846138e2565b99810199955093909301925050600101614845565b6000602080835260e08451828501528185015160c060408601526148da828601826138e2565b90506040860151601f19808784030160608801526148f8838361483a565b92506060880151915080878403016080880152614915838361483a565b925060808801519150808784030160a0880152614932838361483a565b925060a08801519150808784030160c088015250805160a0835261495960a08401826138e2565b9050848201518382038685015261497082826138e2565b9150506040820151838203604085015261498a82826138e2565b9150506060820151838203606085015281829050606083016000805b60038110156149fc5785830384528451838a8101845b60078110156149e75786820383526149d58285516138e2565b938e0193928e019291506001016149bc565b50968c0196958c0195945050506001016149a6565b5050608085015197508581036080870152614a1781896138e2565b9b9a5050505050505050505050565b600060208284031215614a3857600080fd5b81516001600160401b03811115614a4e57600080fd5b612de98482850161447d565b60008151614a6c8185602086016138be565b9290920192915050565b7f7b226e616d65223a2022426174746c65736869707a3a20000000000000000000815260008651614aae816017850160208b016138be565b7f222c20226465736372697074696f6e223a2022416e2041534349492d616e696d6017918401918201527f6174656420737061636520616476656e747572652c20696e766164652074686560378201527f20626c6f636b636861696e20776974682031303025204f6e2d436861696e204260578201527f6174746c65736869707a2e222c2022696d616765223a2022646174613a696d6160778201527119d94bdcdd99cade1b5b0ed8985cd94d8d0b60721b60978201528651614b788160a9840160208b016138be565b7f222c2261747472696275746573223a205b7b2274726169745f74797065223a2260a992909101918201527121b630b9b9911610113b30b63ab2911d101160711b60c9820152614c7b614c6d614c5f614c59614c22614c1c614bdd60db88018d614a5a565b7f227d2c207b2274726169745f74797065223a202250617274732052617269747981526c111610113b30b63ab2911d101160991b6020820152602d0190565b8a614a5a565b7f227d2c207b2274726169745f74797065223a2022536b696e222c202276616c7581526432911d101160d91b602082015260250190565b87614a5a565b61227d60f01b815260020190565b615d7d60f01b815260020190565b98975050505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251614cbf81601d8501602087016138be565b91909101601d0192915050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351614d9c8160178501602088016138be565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351614dcd8160288401602088016138be565b01602801949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b600081614e7f57614e7f614174565b506000190190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090614eba908301846138e2565b9695505050505050565b600060208284031215614ed657600080fd5b815161351f8161383156fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862aa2646970667358221220f2c742df7fc218f74ccb2f7f40d69048917ccac2a44158d0179317711f73e65664736f6c63430008120033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.