Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
ERC721Miya
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.23; import {ERC721M} from "../lib/ERC721M/src/ERC721M.sol"; interface IMiyaMints { function deployVault(address alignmentVault, uint96 vaultId, bytes32 salt) external returns (address); function ownershipChanged(address oldOwner, address newOwner) external; } contract ERC721Miya is ERC721M { address public miyaMints; constructor() payable { _disableInitializers(); } // Initialize contract, should be called immediately after deployment, ideally by factory function initialize( string memory name_, string memory symbol_, string memory baseURI_, uint40 _maxSupply, uint16 _royalty, uint16 _allocation, address _owner, address _alignedNft, uint80 _price, uint96 _vaultId, bytes32 _salt ) external payable override initializer { // Confirm mint alignment allocation is within valid range if (_allocation < 500) revert NotAligned(); // Require allocation be >= 5% if (_allocation > _DENOMINATOR_BPS || _royalty > _MAX_ROYALTY_BPS) revert Invalid(); // Require allocation be <= 100% minAllocation = _allocation; maxAllocation = _allocation; _setTokenRoyalty(0, _owner, uint96(_royalty)); _setDefaultRoyalty(_owner, uint96(_royalty)); // Initialize ownership _initializeOwner(_owner); // Set all values _name = name_; _symbol = symbol_; _baseURI = baseURI_; maxSupply = _maxSupply; price = _price; miyaMints = msg.sender; // Deploy AlignmentVault address deployedAV; deployedAV = IMiyaMints(msg.sender).deployVault(_alignedNft, _vaultId, _salt); alignmentVault = deployedAV; // Send initialize payment (if any) to vault if (msg.value > 0) { (bool success,) = payable(deployedAV).call{value: msg.value}(""); if (!success) revert TransferFailed(); } } // Overrides to tell MiyaMints.sol about ownership changes function transferOwnership(address newOwner) public payable override onlyOwner { IMiyaMints(miyaMints).ownershipChanged(owner(), newOwner); super.transferOwnership(newOwner); } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.23; // >>>>>>>>>>>> [ IMPORTS ] <<<<<<<<<<<< import {ERC721x} from "../lib/ERC721x/src/erc721/ERC721x.sol"; import {ERC2981} from "../lib/solady/src/tokens/ERC2981.sol"; import {Initializable} from "../lib/solady/src/utils/Initializable.sol"; import {ReentrancyGuard} from "../lib/solady/src/utils/ReentrancyGuard.sol"; import {EnumerableSetLib} from "../lib/solady/src/utils/EnumerableSetLib.sol"; import {LibString} from "../lib/solady/src/utils/LibString.sol"; import {FixedPointMathLib as FPML} from "../lib/solady/src/utils/FixedPointMathLib.sol"; import {MerkleProofLib} from "../lib/solady/src/utils/MerkleProofLib.sol"; import {IERC20} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol"; import {IERC721} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol"; //import {console2} from "../lib/forge-std/src/console2.sol"; // >>>>>>>>>>>> [ INTERFACES ] <<<<<<<<<<<< interface IAsset { function balanceOf(address holder) external returns (uint256); } interface IAlignmentVaultMinimal { function vault() external view returns (address); function alignedNft() external view returns (address); } interface IFactory { function deploy(address alignedNft, uint96 vaultId) external returns (address); function deployDeterministic(address alignedNft, uint96 vaultId, bytes32 salt) external returns (address); } /** * @title ERC721M * @author Zodomo.eth (Farcaster/Telegram/Discord/Github: @zodomo, X: @0xZodomo, Email: [email protected]) * @notice A NFT template that can be configured to automatically send a portion of mint funds to an AlignmentVault * @custom:github https://github.com/Zodomo/ERC721M */ contract ERC721M is ERC721x, ERC2981, Initializable, ReentrancyGuard { using LibString for uint256; // Used to convert uint256 tokenId to string for tokenURI() using EnumerableSetLib for EnumerableSetLib.Uint256Set; using EnumerableSetLib for EnumerableSetLib.AddressSet; // >>>>>>>>>>>> [ ERRORS ] <<<<<<<<<<<< error Invalid(); error MintCap(); error URILocked(); error NotAligned(); error MintClosed(); error Blacklisted(); error TransferFailed(); error NothingToClaim(); error ExcessiveClaim(); error RoyaltiesDisabled(); error InsufficientPayment(); // >>>>>>>>>>>> [ EVENTS ] <<<<<<<<<<<< event URILock(); event MintOpen(); event RoyaltyDisabled(); event Withdraw(address indexed to, uint256 indexed amount); event PriceUpdate(uint80 indexed price); event SupplyUpdate(uint40 indexed supply); event AlignmentUpdate(uint16 indexed minAllocation, uint16 indexed maxAllocation); event BlacklistUpdate(address[] indexed blacklistedAssets, bool indexed status); event ReferralFeePaid(address indexed referral, uint256 indexed amount); event ReferralFeeUpdate(uint16 indexed referralFee); event BatchMetadataUpdate(uint256 indexed fromTokenId, uint256 indexed toTokenId); event ContractMetadataUpdate(string indexed uri); event RoyaltyUpdate(uint256 indexed tokenId, address indexed receiver, uint96 indexed royaltyFee); event CustomMintDeleted(uint8 indexed listId); event CustomMintDisabled(uint8 indexed listId); event CustomMintRepriced(uint8 indexed listId, uint80 indexed price); event CustomMintReenabled(uint8 indexed listId, uint40 indexed claimable); event CustomMintConfigured(bytes32 indexed merkleRoot, uint8 indexed listId, uint40 indexed amount); // >>>>>>>>>>>> [ STORAGE ] <<<<<<<<<<<< struct CustomMint { bytes32 root; uint40 issued; uint40 claimable; uint40 supply; uint80 price; } // Address of AlignmentVaultFactory, used when deploying AlignmentVault address public constant vaultFactory = 0xe3d5e8e972291bDbdA57159481028A77fb8F055A; uint16 internal constant _MAX_ROYALTY_BPS = 1000; uint16 internal constant _DENOMINATOR_BPS = 10000; EnumerableSetLib.AddressSet internal _blacklist; EnumerableSetLib.Uint256Set internal _customMintLists; string internal _name; string internal _symbol; string internal _baseURI; string internal _contractURI; uint40 internal _totalSupply; uint80 public price; uint40 public maxSupply; uint16 public minAllocation; uint16 public maxAllocation; uint16 public referralFee; bool public uriLocked; bool public mintOpen; address public alignmentVault; mapping(uint8 listId => CustomMint) public customMintData; mapping(address user => mapping(uint8 listId => uint256 claimed)) public customClaims; // >>>>>>>>>>>> [ MODIFIERS ] <<<<<<<<<<<< modifier mintable(uint256 amount) { if (!mintOpen) revert MintClosed(); if (_totalSupply + amount > maxSupply) revert MintCap(); _; } // >>>>>>>>>>>> [ CONSTRUCTION / INITIALIZATION ] <<<<<<<<<<<< // Constructor is kept empty in order to make the template compatible with ERC-1167 proxy factories constructor() payable {} // Initialize contract, should be called immediately after deployment, ideally by factory function initialize( string memory name_, // Collection name ("Milady") string memory symbol_, // Collection symbol ("MIL") string memory baseURI_, // ipfs://... uint40 _maxSupply, // Max supply (~1.099T max) uint16 _royalty, // Percentage in basis points (420 == 4.20%) uint16 _allocation, // Minimum Percentage of mint funds to AlignmentVault in basis points, minimum of 5% (777 == 7.77%) address _owner, // Collection contract owner address _alignedNft, // Address of NFT to configure AlignmentVault for, must have NFTX vault! uint80 _price, // Price (~1.2M ETH max) uint96 _vaultId, // NFTX Vault ID, please check! bytes32 _salt // AV Deployment salt ) external payable virtual initializer { // Confirm mint alignment allocation is within valid range if (_allocation < 500) revert NotAligned(); // Require allocation be >= 5% if (_allocation > _DENOMINATOR_BPS || _royalty > _MAX_ROYALTY_BPS) revert Invalid(); // Require allocation and royalty be <= 100% minAllocation = _allocation; maxAllocation = _allocation; _setTokenRoyalty(0, _owner, _royalty); _setDefaultRoyalty(_owner, _royalty); // Initialize ownership _initializeOwner(_owner); // Set all values _name = name_; _symbol = symbol_; _baseURI = baseURI_; maxSupply = _maxSupply; price = _price; // Deploy AlignmentVault address deployedAV; if (_salt == bytes32("")) deployedAV = IFactory(vaultFactory).deploy(_alignedNft, _vaultId); else deployedAV = IFactory(vaultFactory).deployDeterministic(_alignedNft, _vaultId, _salt); alignmentVault = deployedAV; // Send initialize payment (if any) to vault if (msg.value > 0) { (bool success,) = payable(deployedAV).call{ value: msg.value }(""); if (!success) revert TransferFailed(); } } // Disables further initialization, it is best practice to use this post-initialization // If a deployed contract should not be initializable, call this to prevent that function disableInitializers() external virtual { _disableInitializers(); } // >>>>>>>>>>>> [ VIEW / METADATA FUNCTIONS ] <<<<<<<<<<<< function name() public view virtual override returns (string memory) { return _name; } function symbol() public view virtual override returns (string memory) { return _symbol; } function baseURI() public view virtual returns (string memory) { return _baseURI; } function contractURI() public view virtual returns (string memory) { return LibString.concat(_baseURI, "contract.json"); } function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { if (!_exists(tokenId)) revert TokenDoesNotExist(); string memory newBaseURI = baseURI(); return (bytes(newBaseURI).length > 0 ? string(abi.encodePacked(newBaseURI, tokenId.toString())) : ""); } function totalSupply() public view virtual returns (uint256) { return _totalSupply; } // Override to add royalty interface. ERC721, ERC721Metadata, and ERC721x are present in the ERC721x override function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721x, ERC2981) returns (bool) { return ERC721x.supportsInterface(interfaceId) || ERC2981.supportsInterface(interfaceId); } function getBlacklist() public view virtual returns (address[] memory) { return _blacklist.values(); } function getCustomMintListIds() external view virtual returns (uint256[] memory) { return _customMintLists.values(); } // >>>>>>>>>>>> [ INTERNAL FUNCTIONS ] <<<<<<<<<<<< // Simple ownership check to reduce code reuse function _checkOwnership() internal virtual { // Cache owner address to save gas address owner = owner(); // If contract is owned and caller isn't them, revert. If renounced, still process vault action. if (owner != address(0) && owner != msg.sender) revert Unauthorized(); } // Blacklist function to prevent mints to and from holders of prohibited assets, applied even if recipient isn't minter function _enforceBlacklist(address minter, address recipient) internal virtual { address[] memory blacklist = _blacklist.values(); uint256 count; for (uint256 i = 1; i < blacklist.length;) { unchecked { count += IAsset(blacklist[i]).balanceOf(minter); count += IAsset(blacklist[i]).balanceOf(recipient); if (count > 0) revert Blacklisted(); ++i; } } } // >>>>>>>>>>>> [ MINT LOGIC ] <<<<<<<<<<<< // Solady ERC721 _mint override to implement mint funds alignment and blacklist function _mint(address recipient, uint256 amount, address referral, uint16 allocation) internal { // Prevent bad inputs if (recipient == address(0) || amount == 0) revert Invalid(); // Ensure minter and recipient don't hold blacklisted assets _enforceBlacklist(msg.sender, recipient); // Ensure allocation set by the user is in the range between minAllocation and maxAllocation if(allocation < minAllocation || allocation > maxAllocation) revert Invalid(); // Calculate allocation uint256 mintAlloc = FPML.fullMulDivUp(allocation, msg.value, _DENOMINATOR_BPS); if (msg.value > 0) { // Send aligned amount to AlignmentVault (success is intentionally not read to save gas as it cannot fail) payable(alignmentVault).call{value: mintAlloc}(""); // If referral isn't address(0), process sending referral fee // Reentrancy is handled by applying ReentrancyGuard to referral mint function [mint(address, uint256, address)] if (referral != address(0)) { uint256 referralAlloc = FPML.mulDivUp(referralFee, msg.value, _DENOMINATOR_BPS); (bool success, ) = payable(referral).call{value: referralAlloc}(""); if (!success) revert TransferFailed(); emit ReferralFeePaid(referral, referralAlloc); } } // Process ERC721 mints // totalSupply is read once externally from loop to reduce SLOADs to save gas uint256 supply = _totalSupply; for (uint256 i; i < amount;) { _mint(recipient, ++supply); unchecked { ++i; } } unchecked { _totalSupply += uint40(amount); } } // Standard mint function that supports batch minting and custom allocation function mint(address recipient, uint256 amount, uint16 allocation) public payable virtual mintable(amount) { if (msg.value < (price * amount)) revert InsufficientPayment(); _mint(recipient, amount, address(0), allocation); } // Standard batch mint with custom allocation support and referral fee support function mint(address recipient, uint256 amount, address referral, uint16 allocation) public payable virtual mintable(amount) nonReentrant { if (referral == msg.sender) revert Invalid(); if (msg.value < (price * amount)) revert InsufficientPayment(); _mint(recipient, amount, referral, allocation); } // Standard mint function that supports batch minting function mint(address recipient, uint256 amount) public payable virtual mintable(amount) { if (msg.value < (price * amount)) revert InsufficientPayment(); _mint(recipient, amount, address(0), minAllocation); } // Standard batch mint with referral fee support function mint(address recipient, uint256 amount, address referral) public payable virtual mintable(amount) nonReentrant { if (referral == msg.sender) revert Invalid(); if (msg.value < (price * amount)) revert InsufficientPayment(); _mint(recipient, amount, referral, minAllocation); } // Standard single-unit mint to msg.sender (implemented for max scannner compatibility) function mint() public payable virtual mintable(1) { if (msg.value < price) revert InsufficientPayment(); _mint(msg.sender, 1, address(0), minAllocation); } // Standard multi-unit mint to msg.sender (implemented for max scanner compatibility) function mint(uint256 amount) public payable virtual mintable(amount) { if (msg.value < (price * amount)) revert InsufficientPayment(); _mint(msg.sender, amount, address(0), minAllocation); } // Whitelisted mint using merkle proofs function customMint(bytes32[] calldata proof, uint8 listId, address recipient, uint40 amount, address referral) public payable virtual mintable(amount) nonReentrant { if (!_customMintLists.contains(listId)) revert Invalid(); CustomMint storage mintData = customMintData[listId]; if (amount > mintData.supply) revert MintCap(); if (customClaims[msg.sender][listId] + amount > mintData.claimable) revert ExcessiveClaim(); if (msg.value < amount * mintData.price) revert InsufficientPayment(); bytes32 leaf = keccak256(abi.encodePacked(msg.sender)); if (!MerkleProofLib.verifyCalldata(proof, mintData.root, leaf)) revert NothingToClaim(); unchecked { customClaims[msg.sender][listId] += amount; mintData.supply -= amount; } _mint(recipient, amount, referral, minAllocation); } // >>>>>>>>>>>> [ PERMISSIONED / OWNER FUNCTIONS ] <<<<<<<<<<<< // Set referral fee, must be < (_DENOMINATOR_BPS - allocation) function setReferralFee(uint16 newReferralFee) external virtual onlyOwner { if (newReferralFee > (_DENOMINATOR_BPS - maxAllocation)) revert Invalid(); referralFee = newReferralFee; emit ReferralFeeUpdate(newReferralFee); } // Update baseURI for entire collection function setBaseURI(string memory newBaseURI) external virtual onlyOwner { if (uriLocked) revert URILocked(); _baseURI = newBaseURI; emit BatchMetadataUpdate(0, maxSupply); } // Permanently lock collection URI function lockURI() external virtual onlyOwner { uriLocked = true; emit URILock(); } // Update ETH mint price function setPrice(uint80 newPrice) external virtual onlyOwner { price = newPrice; emit PriceUpdate(newPrice); } // Set default royalty receiver and royalty fee function setRoyalties(address recipient, uint96 royaltyFee) external virtual onlyOwner { if (royaltyFee > _MAX_ROYALTY_BPS) revert Invalid(); // Revert if royalties are disabled (address receiver,) = royaltyInfo(0, 0); if (receiver == address(0)) revert RoyaltiesDisabled(); // Royalty recipient of nonexistent tokenId 0 is used as royalty status indicator, address(0) == disabled _setTokenRoyalty(0, recipient, royaltyFee); _setDefaultRoyalty(recipient, royaltyFee); emit RoyaltyUpdate(0, recipient, royaltyFee); } // Set royalty receiver and royalty fee for a specific tokenId function setRoyaltiesForId( uint256 tokenId, address recipient, uint96 royaltyFee ) external virtual onlyOwner { if (royaltyFee > _MAX_ROYALTY_BPS) revert Invalid(); // Revert if royalties are disabled (address receiver,) = royaltyInfo(0, 0); if (receiver == address(0)) revert RoyaltiesDisabled(); // Revert if resetting tokenId 0 as it is utilized for royalty enablement status if (tokenId == 0) revert Invalid(); // Reset token royalty if fee is 0, else set it if (royaltyFee == 0) _resetTokenRoyalty(tokenId); else _setTokenRoyalty(tokenId, recipient, royaltyFee); emit RoyaltyUpdate(tokenId, recipient, royaltyFee); } // Set arbitrary custom mint lists using merkle trees, can be reconfigured // NOTE: Cannot retroactively reduce mintable amount below minted supply for custom mint list function setCustomMint(bytes32 _root, uint8 listId, uint40 amount, uint40 _claimable, uint80 newPrice) external virtual onlyOwner { if (!_customMintLists.contains(listId)) _customMintLists.add(listId); CustomMint memory mintData = customMintData[listId]; // Validate adjustment doesn't decrease amount below custom minted count if (mintData.issued != 0 && mintData.issued - mintData.supply > amount) revert Invalid(); uint40 supply; unchecked { // Set amount as supply if new custom mint if (mintData.issued == 0) supply = amount; // Properly adjust existing supply else { supply = amount >= mintData.issued ? mintData.supply + (amount - mintData.issued) : mintData.supply - (mintData.issued - amount); } } customMintData[listId] = CustomMint({ root: _root, issued: amount, claimable: _claimable, supply: supply, price: newPrice }); emit CustomMintConfigured(_root, listId, amount); } // Reduces claimable supply for custom list to 0 function disableCustomMint(uint8 listId) external virtual onlyOwner { if (!_customMintLists.contains(listId)) revert Invalid(); customMintData[listId].claimable = 0; emit CustomMintDisabled(listId); } // Reenables custom mint by setting claimable amount function reenableCustomMint(uint8 listId, uint40 _claimable) external virtual onlyOwner { if (!_customMintLists.contains(listId)) revert Invalid(); uint40 issued = customMintData[listId].issued; uint40 claimable = _claimable <= issued ? _claimable : issued; customMintData[listId].claimable = claimable; emit CustomMintReenabled(listId, claimable); } // Reprice custom mint function repriceCustomMint(uint8 listId, uint80 newPrice) external virtual onlyOwner { if (!_customMintLists.contains(listId)) revert Invalid(); customMintData[listId].price = newPrice; emit CustomMintRepriced(listId, newPrice); } // Completely nukes a custom mint list to minimal state function nukeCustomMint(uint8 listId) external virtual onlyOwner { CustomMint memory mintData = customMintData[listId]; if (mintData.issued == mintData.supply) { if (_customMintLists.contains(listId)) _customMintLists.remove(listId); delete customMintData[listId]; emit CustomMintDeleted(listId); } else { customMintData[listId] = CustomMint({ root: bytes32(""), issued: mintData.issued - mintData.supply, claimable: 0, supply: 0, price: 0 }); emit CustomMintConfigured(bytes32(""), listId, 0); } } // Irreversibly disable royalties by resetting tokenId 0 royalty to (address(0), 0) and deleting default royalty info function disableRoyalties() external virtual onlyOwner { _deleteDefaultRoyalty(); _resetTokenRoyalty(0); emit RoyaltyDisabled(); } // Configure which assets are on blacklist function setBlacklist(address[] memory blacklistedAssets, bool status) external virtual onlyOwner { for (uint256 i; i < blacklistedAssets.length; ++i) { if (status) _blacklist.add(blacklistedAssets[i]); else _blacklist.remove(blacklistedAssets[i]); } emit BlacklistUpdate(blacklistedAssets, status); } // Open mint functions function openMint() external virtual onlyOwner { mintOpen = true; emit MintOpen(); } // Increase mint alignment allocation // NOTE: There will be no function to decrease this value. This operation is one-way only. function increaseAlignment(uint16 newMinAllocation, uint16 newMaxAllocation) external virtual onlyOwner { uint16 _minAllocation = minAllocation; if (newMaxAllocation < _minAllocation) revert Invalid(); // Prevent oversetting alignment (keeping maxAllocation in mind) if (newMaxAllocation + referralFee > _DENOMINATOR_BPS) revert Invalid(); // Prevent alignment deception (changing it last mint) by locking minAllocation in at 50% minted if (totalSupply() < maxSupply / 2) { if (newMinAllocation < _minAllocation || newMinAllocation > newMaxAllocation) revert Invalid(); minAllocation = newMinAllocation; } else newMinAllocation = _minAllocation; maxAllocation = newMaxAllocation; emit AlignmentUpdate(newMinAllocation, newMaxAllocation); } // Decrease token maxSupply // NOTE: There is and will be no function to increase supply. This operation is one-way only. function decreaseSupply(uint40 newMaxSupply) external virtual onlyOwner { if (newMaxSupply >= maxSupply || newMaxSupply < totalSupply()) revert Invalid(); maxSupply = newMaxSupply; emit SupplyUpdate(newMaxSupply); } // Withdraw non-allocated mint funds function withdrawFunds(address recipient, uint256 amount) external virtual nonReentrant { // Cache owner address to save gas address owner = owner(); uint256 balance = address(this).balance; if (recipient == address(0)) revert Invalid(); // If contract is owned and caller isn't them, revert. if (owner != address(0) && owner != msg.sender) revert Unauthorized(); // If contract is renounced, convert recipient to vault and withdraw all funds to it if (owner == address(0)) { recipient = alignmentVault; amount = balance; } // Instead of reverting for overage, simply overwrite amount with balance if (amount > balance) amount = balance; // Process withdrawal (bool success,) = payable(recipient).call{ value: amount }(""); if (!success) revert TransferFailed(); emit Withdraw(recipient, amount); } // >>>>>>>>>>>> [ ASSET HANDLING ] <<<<<<<<<<<< // Internal handling for receive() and fallback() to reduce code length function _processPayment() internal { if (mintOpen) mint(msg.sender, (msg.value / price)); else { // Calculate allocation and split paymeent accordingly uint256 mintAlloc = FPML.fullMulDivUp(minAllocation, msg.value, _DENOMINATOR_BPS); // Success when transferring to vault isn't checked because transfers to vault cant fail payable(alignmentVault).call{ value: mintAlloc }(""); // Reentrancy risk is ignored here because if owner wants to withdraw that way that's their prerogative // But if transfer to owner fails for any reason, it will be sent to the vault (bool success,) = payable(owner()).call{ value: msg.value - mintAlloc }(""); if (!success) payable(alignmentVault).call{ value: msg.value - mintAlloc }(""); } } // Rescue non-aligned tokens from contract, else send aligned tokens to vault function rescueERC20(address addr, address recipient) external virtual onlyOwner { uint256 balance = IERC20(addr).balanceOf(address(this)); if (addr == IAlignmentVaultMinimal(alignmentVault).vault()) { IERC20(addr).transfer(alignmentVault, balance); } else { IERC20(addr).transfer(recipient, balance); } } // Rescue non-aligned NFTs from contract, else send aligned NFTs to vault function rescueERC721(address addr, address recipient, uint256 tokenId) external virtual onlyOwner { if (addr == IAlignmentVaultMinimal(alignmentVault).alignedNft()) { IERC721(addr).safeTransferFrom(address(this), alignmentVault, tokenId); } else { IERC721(addr).transferFrom(address(this), recipient, tokenId); } } // Forward aligned NFTs to vault, revert if sent other NFTs function onERC721Received(address, address, uint256 tokenId, bytes calldata) external virtual returns (bytes4) { address nft = IAlignmentVaultMinimal(alignmentVault).alignedNft(); if (msg.sender == nft) IERC721(nft).safeTransferFrom(address(this), alignmentVault, tokenId); else revert NotAligned(); return ERC721M.onERC721Received.selector; } // Process all received ETH payments receive() external payable virtual { _processPayment(); } // Forward calldata and payment to AlignmentVault. Used if ERC721M is AlignmentVault owner. // Calling this contract using the IAlignmentVaultMinimal interface will trigger this fallback. fallback() external payable virtual { assembly { // Store the target contract address from the storage variable let target := sload(alignmentVault.slot) // Store the calldata size in memory let calldataSize := calldatasize() // Copy the calldata to memory calldatacopy(0x0, 0x0, calldataSize) // Forward the calldata and msg.value to the target contract let result := call(gas(), target, callvalue(), 0x0, calldataSize, 0x0, 0x0) // Revert with the returned data if the call failed if iszero(result) { returndatacopy(0x0, 0x0, returndatasize()) revert(0x0, returndatasize()) } // Return the returned data if the call succeeded returndatacopy(0x0, 0x0, returndatasize()) return(0x0, returndatasize()) } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.23; /* * ,_, * (',') * {/"\} * -"-"- */ import {ERC721} from "../../lib/solady/src/tokens/ERC721.sol"; import {LockRegistry} from "../LockRegistry.sol"; import {IERC721x} from "../interfaces/IERC721x.sol"; abstract contract ERC721x is ERC721, LockRegistry { /* * bytes4(keccak256('freeId(uint256,address)')) == 0x94d216d6 * bytes4(keccak256('isUnlocked(uint256)')) == 0x72abc8b7 * bytes4(keccak256('lockCount(uint256)')) == 0x650b00f6 * bytes4(keccak256('lockId(uint256)')) == 0x2799cde0 * bytes4(keccak256('lockMap(uint256,uint256)')) == 0x2cba8123 * bytes4(keccak256('lockMapIndex(uint256,address)')) == 0x09308e5d * bytes4(keccak256('unlockId(uint256)')) == 0x40a9c8df * bytes4(keccak256('approvedContract(address)')) == 0xb1a6505f * * => 0x94d216d6 ^ 0x72abc8b7 ^ 0x650b00f6 ^ 0x2799cde0 ^ * 0x2cba8123 ^ 0x09308e5d ^ 0x40a9c8df ^ 0xb1a6505f == 0x706e8489 */ bytes4 private constant _INTERFACEtokenId_ERC721x = 0x706e8489; function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721) returns (bool) { return interfaceId == _INTERFACEtokenId_ERC721x || super.supportsInterface(interfaceId); } function transferFrom(address from, address to, uint256 tokenId) public payable override virtual { if (!isUnlocked(tokenId)) revert IERC721x.Locked(tokenId); ERC721.transferFrom(from, to, tokenId); } function safeTransferFrom(address from, address to, uint256 tokenId) public payable override virtual { if (!isUnlocked(tokenId)) revert IERC721x.Locked(tokenId); ERC721.safeTransferFrom(from, to, tokenId); } function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) public payable override virtual { if (!isUnlocked(tokenId)) revert IERC721x.Locked(tokenId); ERC721.safeTransferFrom(from, to, tokenId, data); } function lockId(uint256 tokenId) public override virtual { if (!_exists(tokenId)) revert TokenDoesNotExist(); _lockId(tokenId); } function unlockId(uint256 tokenId) public override virtual { if (!_exists(tokenId)) revert TokenDoesNotExist(); _unlockId(tokenId); } function freeId(uint256 tokenId, address lockingContract) public override virtual { if (!_exists(tokenId)) revert TokenDoesNotExist(); _freeId(tokenId, lockingContract); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC2981 NFT Royalty Standard implementation. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC2981.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/common/ERC2981.sol) abstract contract ERC2981 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The royalty fee numerator exceeds the fee denominator. error RoyaltyOverflow(); /// @dev The royalty receiver cannot be the zero address. error RoyaltyReceiverIsZeroAddress(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The default royalty info is given by: /// ``` /// let packed := sload(_ERC2981_MASTER_SLOT_SEED) /// let receiver := shr(96, packed) /// let royaltyFraction := xor(packed, shl(96, receiver)) /// ``` /// /// The per token royalty info is given by. /// ``` /// mstore(0x00, tokenId) /// mstore(0x20, _ERC2981_MASTER_SLOT_SEED) /// let packed := sload(keccak256(0x00, 0x40)) /// let receiver := shr(96, packed) /// let royaltyFraction := xor(packed, shl(96, receiver)) /// ``` uint256 private constant _ERC2981_MASTER_SLOT_SEED = 0xaa4ec00224afccfdb7; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC2981 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Checks that `_feeDenominator` is non-zero. constructor() { require(_feeDenominator() != 0, "Fee denominator cannot be zero."); } /// @dev Returns the denominator for the royalty amount. /// Defaults to 10000, which represents fees in basis points. /// Override this function to return a custom amount if needed. function _feeDenominator() internal pure virtual returns (uint96) { return 10000; } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC2981: 0x2a55205a. result := or(eq(s, 0x01ffc9a7), eq(s, 0x2a55205a)) } } /// @dev Returns the `receiver` and `royaltyAmount` for `tokenId` sold at `salePrice`. function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual returns (address receiver, uint256 royaltyAmount) { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) let packed := sload(keccak256(0x00, 0x40)) receiver := shr(96, packed) if iszero(receiver) { packed := sload(mload(0x20)) receiver := shr(96, packed) } let x := salePrice let y := xor(packed, shl(96, receiver)) // `feeNumerator`. // Overflow check, equivalent to `require(y == 0 || x <= type(uint256).max / y)`. // Out-of-gas revert. Should not be triggered in practice, but included for safety. returndatacopy(returndatasize(), returndatasize(), mul(y, gt(x, div(not(0), y)))) royaltyAmount := div(mul(x, y), feeDenominator) } } /// @dev Sets the default royalty `receiver` and `feeNumerator`. /// /// Requirements: /// - `receiver` must not be the zero address. /// - `feeNumerator` must not be greater than the fee denominator. function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { feeNumerator := shr(160, shl(160, feeNumerator)) if gt(feeNumerator, feeDenominator) { mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`. revert(0x1c, 0x04) } let packed := shl(96, receiver) if iszero(packed) { mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`. revert(0x1c, 0x04) } sstore(_ERC2981_MASTER_SLOT_SEED, or(packed, feeNumerator)) } } /// @dev Sets the default royalty `receiver` and `feeNumerator` to zero. function _deleteDefaultRoyalty() internal virtual { /// @solidity memory-safe-assembly assembly { sstore(_ERC2981_MASTER_SLOT_SEED, 0) } } /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId`. /// /// Requirements: /// - `receiver` must not be the zero address. /// - `feeNumerator` must not be greater than the fee denominator. function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { feeNumerator := shr(160, shl(160, feeNumerator)) if gt(feeNumerator, feeDenominator) { mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`. revert(0x1c, 0x04) } let packed := shl(96, receiver) if iszero(packed) { mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`. revert(0x1c, 0x04) } mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) sstore(keccak256(0x00, 0x40), or(packed, feeNumerator)) } } /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId` to zero. function _resetTokenRoyalty(uint256 tokenId) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) sstore(keccak256(0x00, 0x40), 0) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Initializable mixin for the upgradeable contracts. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Initializable.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/proxy/utils/Initializable.sol) abstract contract Initializable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The contract is already initialized. error InvalidInitialization(); /// @dev The contract is not initializing. error NotInitializing(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Triggered when the contract has been initialized. event Initialized(uint64 version); /// @dev `keccak256(bytes("Initialized(uint64)"))`. bytes32 private constant _INTIALIZED_EVENT_SIGNATURE = 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The default initializable slot is given by: /// `bytes32(~uint256(uint32(bytes4(keccak256("_INITIALIZABLE_SLOT")))))`. /// /// Bits Layout: /// - [0] `initializing` /// - [1..64] `initializedVersion` bytes32 private constant _INITIALIZABLE_SLOT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf601132; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return a custom storage slot if required. function _initializableSlot() internal pure virtual returns (bytes32) { return _INITIALIZABLE_SLOT; } /// @dev Guards an initializer function so that it can be invoked at most once. /// /// You can guard a function with `onlyInitializing` such that it can be called /// through a function guarded with `initializer`. /// /// This is similar to `reinitializer(1)`, except that in the context of a constructor, /// an `initializer` guarded function can be invoked multiple times. /// This can be useful during testing and is not expected to be used in production. /// /// Emits an {Initialized} event. modifier initializer() virtual { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { let i := sload(s) // Set `initializing` to 1, `initializedVersion` to 1. sstore(s, 3) // If `!(initializing == 0 && initializedVersion == 0)`. if i { // If `!(address(this).code.length == 0 && initializedVersion == 1)`. if iszero(lt(extcodesize(address()), eq(shr(1, i), 1))) { mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`. revert(0x1c, 0x04) } s := shl(shl(255, i), s) // Skip initializing if `initializing == 1`. } } _; /// @solidity memory-safe-assembly assembly { if s { // Set `initializing` to 0, `initializedVersion` to 1. sstore(s, 2) // Emit the {Initialized} event. mstore(0x20, 1) log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE) } } } /// @dev Guards an reinitialzer function so that it can be invoked at most once. /// /// You can guard a function with `onlyInitializing` such that it can be called /// through a function guarded with `reinitializer`. /// /// Emits an {Initialized} event. modifier reinitializer(uint64 version) virtual { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { version := and(version, 0xffffffffffffffff) // Clean upper bits. let i := sload(s) // If `initializing == 1 || initializedVersion >= version`. if iszero(lt(and(i, 1), lt(shr(1, i), version))) { mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`. revert(0x1c, 0x04) } // Set `initializing` to 1, `initializedVersion` to `version`. sstore(s, or(1, shl(1, version))) } _; /// @solidity memory-safe-assembly assembly { // Set `initializing` to 0, `initializedVersion` to `version`. sstore(s, shl(1, version)) // Emit the {Initialized} event. mstore(0x20, version) log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE) } } /// @dev Guards a function such that it can only be called in the scope /// of a function guarded with `initializer` or `reinitializer`. modifier onlyInitializing() virtual { _checkInitializing(); _; } /// @dev Reverts if the contract is not initializing. function _checkInitializing() internal view virtual { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { if iszero(and(1, sload(s))) { mstore(0x00, 0xd7e6bcf8) // `NotInitializing()`. revert(0x1c, 0x04) } } } /// @dev Locks any future initializations by setting the initialized version to `2**64 - 1`. /// /// Calling this in the constructor will prevent the contract from being initialized /// or reinitialized. 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 called. function _disableInitializers() internal virtual { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { let i := sload(s) if and(i, 1) { mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`. revert(0x1c, 0x04) } let uint64max := shr(192, s) // Computed to save bytecode. if iszero(eq(shr(1, i), uint64max)) { // Set `initializing` to 0, `initializedVersion` to `2**64 - 1`. sstore(s, shl(1, uint64max)) // Emit the {Initialized} event. mstore(0x20, uint64max) log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE) } } } /// @dev Returns the highest version that has been initialized. function _getInitializedVersion() internal view virtual returns (uint64 version) { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { version := shr(1, sload(s)) } } /// @dev Returns whether the contract is currently initializing. function _isInitializing() internal view virtual returns (bool result) { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { result := and(1, sload(s)) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Reentrancy guard mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuard.sol) abstract contract ReentrancyGuard { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Unauthorized reentrant call. error Reentrancy(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to: `uint72(bytes9(keccak256("_REENTRANCY_GUARD_SLOT")))`. /// 9 bytes is large enough to avoid collisions with lower slots, /// but not too large to result in excessive bytecode bloat. uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* REENTRANCY GUARD */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Guards a function from reentrancy. modifier nonReentrant() virtual { /// @solidity memory-safe-assembly assembly { if eq(sload(_REENTRANCY_GUARD_SLOT), address()) { mstore(0x00, 0xab143c06) // `Reentrancy()`. revert(0x1c, 0x04) } sstore(_REENTRANCY_GUARD_SLOT, address()) } _; /// @solidity memory-safe-assembly assembly { sstore(_REENTRANCY_GUARD_SLOT, codesize()) } } /// @dev Guards a view function from read-only reentrancy. modifier nonReadReentrant() virtual { /// @solidity memory-safe-assembly assembly { if eq(sload(_REENTRANCY_GUARD_SLOT), address()) { mstore(0x00, 0xab143c06) // `Reentrancy()`. revert(0x1c, 0x04) } } _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for managing enumerable sets in storage. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibMap.sol) /// /// @dev Note: /// In many applications, the number of elements in an enumerable set is small. /// This enumerable set implementation avoids storing the length and indices /// for up to 3 elements. Once the length exceeds 3 for the first time, the length /// and indices will be initialized. The amortized cost of adding elements is O(1). /// /// The AddressSet implementation packs the length with the 0th entry. library EnumerableSetLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The index must be less than the length. error IndexOutOfBounds(); /// @dev The value cannot be the zero sentinel. error ValueIsZeroSentinel(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev A sentinel value to denote the zero value in storage. /// No elements can be equal to this value. /// `uint72(bytes9(keccak256(bytes("_ZERO_SENTINEL"))))`. uint256 private constant _ZERO_SENTINEL = 0xfbb67fda52d4bfb8bf; /// @dev The storage layout is given by: /// ``` /// mstore(0x04, _ENUMERABLE_ADDRESS_SET_SLOT_SEED) /// mstore(0x00, set.slot) /// let rootSlot := keccak256(0x00, 0x24) /// mstore(0x20, rootSlot) /// mstore(0x00, shr(96, shl(96, value))) /// let positionSlot := keccak256(0x00, 0x40) /// let valueSlot := add(rootSlot, sload(positionSlot)) /// let valueInStorage := shr(96, sload(valueSlot)) /// let lazyLength := shr(160, shl(160, sload(rootSlot))) /// ``` uint256 private constant _ENUMERABLE_ADDRESS_SET_SLOT_SEED = 0x978aab92; /// @dev The storage layout is given by: /// ``` /// mstore(0x04, _ENUMERABLE_WORD_SET_SLOT_SEED) /// mstore(0x00, set.slot) /// let rootSlot := keccak256(0x00, 0x24) /// mstore(0x20, rootSlot) /// mstore(0x00, value) /// let positionSlot := keccak256(0x00, 0x40) /// let valueSlot := add(rootSlot, sload(positionSlot)) /// let valueInStorage := sload(valueSlot) /// let lazyLength := sload(not(rootSlot)) /// ``` uint256 private constant _ENUMERABLE_WORD_SET_SLOT_SEED = 0x18fb5864; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev An enumerable address set in storage. struct AddressSet { uint256 _spacer; } /// @dev An enumerable bytes32 set in storage. struct Bytes32Set { uint256 _spacer; } /// @dev An enumerable uint256 set in storage. struct Uint256Set { uint256 _spacer; } /// @dev An enumerable int256 set in storage. struct Int256Set { uint256 _spacer; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* GETTERS / SETTERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of elements in the set. function length(AddressSet storage set) internal view returns (uint256 result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { let rootPacked := sload(rootSlot) let n := shr(160, shl(160, rootPacked)) result := shr(1, n) for {} iszero(or(iszero(shr(96, rootPacked)), n)) {} { result := 1 if iszero(sload(add(rootSlot, result))) { break } result := 2 if iszero(sload(add(rootSlot, result))) { break } result := 3 break } } } /// @dev Returns the number of elements in the set. function length(Bytes32Set storage set) internal view returns (uint256 result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { let n := sload(not(rootSlot)) result := shr(1, n) for {} iszero(n) {} { result := 0 if iszero(sload(add(rootSlot, result))) { break } result := 1 if iszero(sload(add(rootSlot, result))) { break } result := 2 if iszero(sload(add(rootSlot, result))) { break } result := 3 break } } } /// @dev Returns the number of elements in the set. function length(Uint256Set storage set) internal view returns (uint256 result) { result = length(_toBytes32Set(set)); } /// @dev Returns the number of elements in the set. function length(Int256Set storage set) internal view returns (uint256 result) { result = length(_toBytes32Set(set)); } /// @dev Returns whether `value` is in the set. function contains(AddressSet storage set, address value) internal view returns (bool result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { value := shr(96, shl(96, value)) if eq(value, _ZERO_SENTINEL) { mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. revert(0x1c, 0x04) } if iszero(value) { value := _ZERO_SENTINEL } let rootPacked := sload(rootSlot) for {} 1 {} { if iszero(shr(160, shl(160, rootPacked))) { result := 1 if eq(shr(96, rootPacked), value) { break } if eq(shr(96, sload(add(rootSlot, 1))), value) { break } if eq(shr(96, sload(add(rootSlot, 2))), value) { break } result := 0 break } mstore(0x20, rootSlot) mstore(0x00, value) result := iszero(iszero(sload(keccak256(0x00, 0x40)))) break } } } /// @dev Returns whether `value` is in the set. function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { if eq(value, _ZERO_SENTINEL) { mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. revert(0x1c, 0x04) } if iszero(value) { value := _ZERO_SENTINEL } for {} 1 {} { if iszero(sload(not(rootSlot))) { result := 1 if eq(sload(rootSlot), value) { break } if eq(sload(add(rootSlot, 1)), value) { break } if eq(sload(add(rootSlot, 2)), value) { break } result := 0 break } mstore(0x20, rootSlot) mstore(0x00, value) result := iszero(iszero(sload(keccak256(0x00, 0x40)))) break } } } /// @dev Returns whether `value` is in the set. function contains(Uint256Set storage set, uint256 value) internal view returns (bool result) { result = contains(_toBytes32Set(set), bytes32(value)); } /// @dev Returns whether `value` is in the set. function contains(Int256Set storage set, int256 value) internal view returns (bool result) { result = contains(_toBytes32Set(set), bytes32(uint256(value))); } /// @dev Adds `value` to the set. Returns whether `value` was not in the set. function add(AddressSet storage set, address value) internal returns (bool result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { value := shr(96, shl(96, value)) if eq(value, _ZERO_SENTINEL) { mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. revert(0x1c, 0x04) } if iszero(value) { value := _ZERO_SENTINEL } let rootPacked := sload(rootSlot) for { let n := shr(160, shl(160, rootPacked)) } 1 {} { mstore(0x20, rootSlot) if iszero(n) { let v0 := shr(96, rootPacked) if iszero(v0) { sstore(rootSlot, shl(96, value)) result := 1 break } if eq(v0, value) { break } let v1 := shr(96, sload(add(rootSlot, 1))) if iszero(v1) { sstore(add(rootSlot, 1), shl(96, value)) result := 1 break } if eq(v1, value) { break } let v2 := shr(96, sload(add(rootSlot, 2))) if iszero(v2) { sstore(add(rootSlot, 2), shl(96, value)) result := 1 break } if eq(v2, value) { break } mstore(0x00, v0) sstore(keccak256(0x00, 0x40), 1) mstore(0x00, v1) sstore(keccak256(0x00, 0x40), 2) mstore(0x00, v2) sstore(keccak256(0x00, 0x40), 3) rootPacked := or(rootPacked, 7) n := 7 } mstore(0x00, value) let p := keccak256(0x00, 0x40) if iszero(sload(p)) { n := shr(1, n) sstore(add(rootSlot, n), shl(96, value)) sstore(p, add(1, n)) sstore(rootSlot, add(2, rootPacked)) result := 1 break } break } } } /// @dev Adds `value` to the set. Returns whether `value` was not in the set. function add(Bytes32Set storage set, bytes32 value) internal returns (bool result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { if eq(value, _ZERO_SENTINEL) { mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. revert(0x1c, 0x04) } if iszero(value) { value := _ZERO_SENTINEL } for { let n := sload(not(rootSlot)) } 1 {} { mstore(0x20, rootSlot) if iszero(n) { let v0 := sload(rootSlot) if iszero(v0) { sstore(rootSlot, value) result := 1 break } if eq(v0, value) { break } let v1 := sload(add(rootSlot, 1)) if iszero(v1) { sstore(add(rootSlot, 1), value) result := 1 break } if eq(v1, value) { break } let v2 := sload(add(rootSlot, 2)) if iszero(v2) { sstore(add(rootSlot, 2), value) result := 1 break } if eq(v2, value) { break } mstore(0x00, v0) sstore(keccak256(0x00, 0x40), 1) mstore(0x00, v1) sstore(keccak256(0x00, 0x40), 2) mstore(0x00, v2) sstore(keccak256(0x00, 0x40), 3) n := 7 } mstore(0x00, value) let p := keccak256(0x00, 0x40) if iszero(sload(p)) { n := shr(1, n) sstore(add(rootSlot, n), value) sstore(p, add(1, n)) sstore(not(rootSlot), or(1, shl(1, add(1, n)))) result := 1 break } break } } } /// @dev Adds `value` to the set. Returns whether `value` was not in the set. function add(Uint256Set storage set, uint256 value) internal returns (bool result) { result = add(_toBytes32Set(set), bytes32(value)); } /// @dev Adds `value` to the set. Returns whether `value` was not in the set. function add(Int256Set storage set, int256 value) internal returns (bool result) { result = add(_toBytes32Set(set), bytes32(uint256(value))); } /// @dev Removes `value` from the set. Returns whether `value` was in the set. function remove(AddressSet storage set, address value) internal returns (bool result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { value := shr(96, shl(96, value)) if eq(value, _ZERO_SENTINEL) { mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. revert(0x1c, 0x04) } if iszero(value) { value := _ZERO_SENTINEL } let rootPacked := sload(rootSlot) for { let n := shr(160, shl(160, rootPacked)) } 1 {} { if iszero(n) { result := 1 if eq(shr(96, rootPacked), value) { sstore(rootSlot, sload(add(rootSlot, 1))) sstore(add(rootSlot, 1), sload(add(rootSlot, 2))) sstore(add(rootSlot, 2), 0) break } if eq(shr(96, sload(add(rootSlot, 1))), value) { sstore(add(rootSlot, 1), sload(add(rootSlot, 2))) sstore(add(rootSlot, 2), 0) break } if eq(shr(96, sload(add(rootSlot, 2))), value) { sstore(add(rootSlot, 2), 0) break } result := 0 break } mstore(0x20, rootSlot) mstore(0x00, value) let p := keccak256(0x00, 0x40) let position := sload(p) if iszero(position) { break } n := sub(shr(1, n), 1) if iszero(eq(sub(position, 1), n)) { let lastValue := shr(96, sload(add(rootSlot, n))) sstore(add(rootSlot, sub(position, 1)), shl(96, lastValue)) sstore(add(rootSlot, n), 0) mstore(0x00, lastValue) sstore(keccak256(0x00, 0x40), position) } sstore(rootSlot, or(shl(96, shr(96, sload(rootSlot))), or(shl(1, n), 1))) sstore(p, 0) result := 1 break } } } /// @dev Removes `value` from the set. Returns whether `value` was in the set. function remove(Bytes32Set storage set, bytes32 value) internal returns (bool result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { if eq(value, _ZERO_SENTINEL) { mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. revert(0x1c, 0x04) } if iszero(value) { value := _ZERO_SENTINEL } for { let n := sload(not(rootSlot)) } 1 {} { if iszero(n) { result := 1 if eq(sload(rootSlot), value) { sstore(rootSlot, sload(add(rootSlot, 1))) sstore(add(rootSlot, 1), sload(add(rootSlot, 2))) sstore(add(rootSlot, 2), 0) break } if eq(sload(add(rootSlot, 1)), value) { sstore(add(rootSlot, 1), sload(add(rootSlot, 2))) sstore(add(rootSlot, 2), 0) break } if eq(sload(add(rootSlot, 2)), value) { sstore(add(rootSlot, 2), 0) break } result := 0 break } mstore(0x20, rootSlot) mstore(0x00, value) let p := keccak256(0x00, 0x40) let position := sload(p) if iszero(position) { break } n := sub(shr(1, n), 1) if iszero(eq(sub(position, 1), n)) { let lastValue := sload(add(rootSlot, n)) sstore(add(rootSlot, sub(position, 1)), lastValue) sstore(add(rootSlot, n), 0) mstore(0x00, lastValue) sstore(keccak256(0x00, 0x40), position) } sstore(not(rootSlot), or(shl(1, n), 1)) sstore(p, 0) result := 1 break } } } /// @dev Removes `value` from the set. Returns whether `value` was in the set. function remove(Uint256Set storage set, uint256 value) internal returns (bool result) { result = remove(_toBytes32Set(set), bytes32(value)); } /// @dev Removes `value` from the set. Returns whether `value` was in the set. function remove(Int256Set storage set, int256 value) internal returns (bool result) { result = remove(_toBytes32Set(set), bytes32(uint256(value))); } /// @dev Returns all of the values in the set. /// Note: This can consume more gas than the block gas limit for large sets. function values(AddressSet storage set) internal view returns (address[] memory result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { let zs := _ZERO_SENTINEL let rootPacked := sload(rootSlot) let n := shr(160, shl(160, rootPacked)) result := mload(0x40) let o := add(0x20, result) let v := shr(96, rootPacked) mstore(o, mul(v, iszero(eq(v, zs)))) for {} 1 {} { if iszero(n) { if v { n := 1 v := shr(96, sload(add(rootSlot, n))) if v { n := 2 mstore(add(o, 0x20), mul(v, iszero(eq(v, zs)))) v := shr(96, sload(add(rootSlot, n))) if v { n := 3 mstore(add(o, 0x40), mul(v, iszero(eq(v, zs)))) } } } break } n := shr(1, n) for { let i := 1 } lt(i, n) { i := add(i, 1) } { v := shr(96, sload(add(rootSlot, i))) mstore(add(o, shl(5, i)), mul(v, iszero(eq(v, zs)))) } break } mstore(result, n) mstore(0x40, add(o, shl(5, n))) } } /// @dev Returns all of the values in the set. /// Note: This can consume more gas than the block gas limit for large sets. function values(Bytes32Set storage set) internal view returns (bytes32[] memory result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { let zs := _ZERO_SENTINEL let n := sload(not(rootSlot)) result := mload(0x40) let o := add(0x20, result) for {} 1 {} { if iszero(n) { let v := sload(rootSlot) if v { n := 1 mstore(o, mul(v, iszero(eq(v, zs)))) v := sload(add(rootSlot, n)) if v { n := 2 mstore(add(o, 0x20), mul(v, iszero(eq(v, zs)))) v := sload(add(rootSlot, n)) if v { n := 3 mstore(add(o, 0x40), mul(v, iszero(eq(v, zs)))) } } } break } n := shr(1, n) for { let i := 0 } lt(i, n) { i := add(i, 1) } { let v := sload(add(rootSlot, i)) mstore(add(o, shl(5, i)), mul(v, iszero(eq(v, zs)))) } break } mstore(result, n) mstore(0x40, add(o, shl(5, n))) } } /// @dev Returns all of the values in the set. /// Note: This can consume more gas than the block gas limit for large sets. function values(Uint256Set storage set) internal view returns (uint256[] memory result) { result = _toUints(values(_toBytes32Set(set))); } /// @dev Returns all of the values in the set. /// Note: This can consume more gas than the block gas limit for large sets. function values(Int256Set storage set) internal view returns (int256[] memory result) { result = _toInts(values(_toBytes32Set(set))); } /// @dev Returns the element at index `i` in the set. function at(AddressSet storage set, uint256 i) internal view returns (address result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { result := shr(96, sload(add(rootSlot, i))) result := mul(result, iszero(eq(result, _ZERO_SENTINEL))) } if (i >= length(set)) revert IndexOutOfBounds(); } /// @dev Returns the element at index `i` in the set. function at(Bytes32Set storage set, uint256 i) internal view returns (bytes32 result) { result = _rootSlot(set); /// @solidity memory-safe-assembly assembly { result := sload(add(result, i)) result := mul(result, iszero(eq(result, _ZERO_SENTINEL))) } if (i >= length(set)) revert IndexOutOfBounds(); } /// @dev Returns the element at index `i` in the set. function at(Uint256Set storage set, uint256 i) internal view returns (uint256 result) { result = uint256(at(_toBytes32Set(set), i)); } /// @dev Returns the element at index `i` in the set. function at(Int256Set storage set, uint256 i) internal view returns (int256 result) { result = int256(uint256(at(_toBytes32Set(set), i))); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the root slot. function _rootSlot(AddressSet storage s) private pure returns (bytes32 r) { /// @solidity memory-safe-assembly assembly { mstore(0x04, _ENUMERABLE_ADDRESS_SET_SLOT_SEED) mstore(0x00, s.slot) r := keccak256(0x00, 0x24) } } /// @dev Returns the root slot. function _rootSlot(Bytes32Set storage s) private pure returns (bytes32 r) { /// @solidity memory-safe-assembly assembly { mstore(0x04, _ENUMERABLE_WORD_SET_SLOT_SEED) mstore(0x00, s.slot) r := keccak256(0x00, 0x24) } } /// @dev Casts to a Bytes32Set. function _toBytes32Set(Uint256Set storage s) private pure returns (Bytes32Set storage c) { /// @solidity memory-safe-assembly assembly { c.slot := s.slot } } /// @dev Casts to a Bytes32Set. function _toBytes32Set(Int256Set storage s) private pure returns (Bytes32Set storage c) { /// @solidity memory-safe-assembly assembly { c.slot := s.slot } } /// @dev Casts to a uint256 array. function _toUints(bytes32[] memory a) private pure returns (uint256[] memory c) { /// @solidity memory-safe-assembly assembly { c := a } } /// @dev Casts to a int256 array. function _toInts(bytes32[] memory a) private pure returns (int256[] memory c) { /// @solidity memory-safe-assembly assembly { c := a } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for converting numbers into strings and other string operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) /// /// @dev Note: /// For performance and bytecode compactness, most of the string operations are restricted to /// byte strings (7-bit ASCII), except where otherwise specified. /// Usage of byte string operations on charsets with runes spanning two or more bytes /// can lead to undefined behavior. library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The length of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /// @dev The length of the string is more than 32 bytes. error TooBigForSmallString(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. str := add(mload(0x40), 0x80) // Update the free memory pointer to allocate. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 1)`. // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, length) } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory str) { if (value >= 0) { return toString(uint256(value)); } unchecked { str = toString(~uint256(value) + 1); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let length := mload(str) // Load the string length. mstore(str, 0x2d) // Store the '-' character. str := sub(str, 1) // Move back the string pointer by a byte. mstore(str, add(length, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2 + 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) { str = toHexStringNoPrefix(value, length); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. // We add 0x20 to the total and round down to a multiple of 0x20. // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f))) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(str, add(length, length)) let w := not(1) // Tsk. let temp := value // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for {} 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(str, start)) { break } } if temp { mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`. revert(0x1c, 0x04) } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := add(mload(str), 2) // Compute the length. mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero. str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := mload(str) // Get the length. str := add(str, o) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. str := add(mload(0x40), 0x80) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory str) { str = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(str, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { str := mload(0x40) // Allocate the memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(str, 0x80)) // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) str := add(str, 2) mstore(str, 40) let o := add(str, 0x20) mstore(add(o, 40), 0) value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory str) { str = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { let length := mload(raw) str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(str, add(length, length)) // Store the length of the output. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let o := add(str, 0x20) let end := add(raw, length) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let mask := shl(7, div(not(0), 255)) result := 1 let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, byte string operations are restricted // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets. // Usage of byte string operations on charsets with runes spanning two or more bytes // can lead to undefined behavior. /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`. function replace(string memory subject, string memory search, string memory replacement) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) let replacementLength := mload(replacement) subject := add(subject, 0x20) search := add(search, 0x20) replacement := add(replacement, 0x20) result := add(mload(0x40), 0x20) let subjectEnd := add(subject, subjectLength) if iszero(gt(searchLength, subjectLength)) { let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let o := 0 } 1 {} { mstore(add(result, o), mload(add(replacement, o))) o := add(o, 0x20) if iszero(lt(o, replacementLength)) { break } } result := add(result, replacementLength) subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } } let resultRemainder := result result := add(mload(0x40), 0x20) let k := add(sub(resultRemainder, result), sub(subjectEnd, subject)) // Copy the rest of the string one word at a time. for {} lt(subject, subjectEnd) {} { mstore(resultRemainder, mload(subject)) resultRemainder := add(resultRemainder, 0x20) subject := add(subject, 0x20) } result := sub(result, 0x20) let last := add(add(result, 0x20), k) // Zeroize the slot after the string. mstore(last, 0) mstore(0x40, add(last, 0x20)) // Allocate the memory. mstore(result, k) // Store the length. } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for { let subjectLength := mload(subject) } 1 {} { if iszero(mload(search)) { if iszero(gt(from, subjectLength)) { result := from break } result := subjectLength break } let searchLength := mload(search) let subjectStart := add(subject, 0x20) result := not(0) // Initialize to `NOT_FOUND`. subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLength), searchLength), 1) let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(add(search, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLength))) { break } if iszero(lt(searchLength, 0x20)) { for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, searchLength), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = indexOf(subject, search, 0); } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let searchLength := mload(search) if gt(searchLength, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), searchLength) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if eq(keccak256(subject, searchLength), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = lastIndexOf(subject, search, uint256(int256(-1))); } /// @dev Returns true if `search` is found in `subject`, false otherwise. function contains(string memory subject, string memory search) internal pure returns (bool) { return indexOf(subject, search) != NOT_FOUND; } /// @dev Returns whether `subject` starts with `search`. function startsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( iszero(gt(searchLength, mload(subject))), eq( keccak256(add(subject, 0x20), searchLength), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns whether `subject` ends with `search`. function endsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) let subjectLength := mload(subject) // Whether `search` is not longer than `subject`. let withinRange := iszero(gt(searchLength, subjectLength)) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( withinRange, eq( keccak256( // `subject + 0x20 + max(subjectLength - searchLength, 0)`. add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))), searchLength ), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(or(iszero(times), iszero(subjectLength))) { subject := add(subject, 0x20) result := mload(0x40) let output := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let o := 0 } 1 {} { mstore(add(output, o), mload(add(subject, o))) o := add(o, 0x20) if iszero(lt(o, subjectLength)) { break } } output := add(output, subjectLength) times := sub(times, 1) if iszero(times) { break } } mstore(output, 0) // Zeroize the slot after the string. let resultLength := sub(output, add(result, 0x20)) mstore(result, resultLength) // Store the length. // Allocate the memory. mstore(0x40, add(result, add(resultLength, 0x20))) } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(gt(subjectLength, end)) { end := subjectLength } if iszero(gt(subjectLength, start)) { start := subjectLength } if lt(start, end) { result := mload(0x40) let resultLength := sub(end, start) mstore(result, resultLength) subject := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let o := and(add(resultLength, 0x1f), w) } 1 {} { mstore(add(result, o), mload(add(subject, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(result, 0x20), resultLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(result, and(add(resultLength, 0x3f), w))) } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory result) { result = slice(subject, start, uint256(int256(-1))); } /// @dev Returns all the indices of `search` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory search) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) if iszero(gt(searchLength, subjectLength)) { subject := add(subject, 0x20) search := add(search, 0x20) result := add(mload(0x40), 0x20) let subjectStart := subject let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Append to `result`. mstore(result, sub(subject, subjectStart)) result := add(result, 0x20) // Advance `subject` by `searchLength`. subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } let resultEnd := result // Assign `result` to the free memory pointer. result := mload(0x40) // Store the length of `result`. mstore(result, shr(5, sub(resultEnd, add(result, 0x20)))) // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(resultEnd, 0x20)) } } } /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string. function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { uint256[] memory indices = indicesOf(subject, delimiter); /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(add(indicesEnd, w), mload(subject)) mstore(indices, add(mload(indices), 1)) let prevIndex := 0 for {} 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let elementLength := sub(index, prevIndex) mstore(element, elementLength) // Copy the `subject` one word at a time, backwards. for { let o := and(add(elementLength, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(element, 0x20), elementLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(element, and(add(elementLength, 0x3f), w))) // Store the `element` into the array. mstore(indexPtr, element) } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated string of `a` and `b`. /// Cheaper than `string.concat()` and does not de-align the free memory pointer. function concat(string memory a, string memory b) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let w := not(0x1f) result := mload(0x40) let aLength := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(aLength, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLength := mload(b) let output := add(result, aLength) // Copy `b` one word at a time, backwards. for { let o := and(add(bLength, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLength := add(aLength, bLength) let last := add(add(result, 0x20), totalLength) // Zeroize the slot after the string. mstore(last, 0) // Stores the length. mstore(result, totalLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 0x1f), w)) } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let length := mload(subject) if length { result := add(mload(0x40), 0x20) subject := add(subject, 1) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) let w := not(0) for { let o := length } 1 {} { o := add(o, w) let b := and(0xff, mload(add(subject, o))) mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20))) if iszero(o) { break } } result := mload(0x40) mstore(result, length) // Store the length. let last := add(add(result, 0x20), length) mstore(last, 0) // Zeroize the slot after the string. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } } /// @dev Returns a string from a small bytes32 string. /// `s` must be null-terminated, or behavior will be undefined. function fromSmallString(bytes32 s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let n := 0 for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'. mstore(result, n) let o := add(result, 0x20) mstore(o, s) mstore(add(o, n), 0) mstore(0x40, add(result, 0x40)) } } /// @dev Returns the small string, with all bytes after the first null byte zeroized. function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'. mstore(0x00, s) mstore(result, 0x00) result := mload(0x00) } } /// @dev Returns the string as a normalized null-terminated small string. function toSmallString(string memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(s) if iszero(lt(result, 33)) { mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`. revert(0x1c, 0x04) } result := shl(shl(3, sub(32, result)), mload(add(s, result))) } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(result, c) result := add(result, 1) continue } let t := shr(248, mload(c)) mstore(result, mload(and(t, 0x1f))) result := add(result, shr(5, t)) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(result, c) result := add(result, 1) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), c) result := add(result, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(result, mload(0x19)) // "\\u00XX". result := add(result, 6) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), mload(add(c, 8))) result := add(result, 2) } if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { result = escapeJSON(s, false); } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string. function eqs(string memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. let x := not(or(m, or(b, add(m, and(b, m))))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) } } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behavior is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. result := mload(0x40) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(0x40, add(result, 0x40)) // Zeroize the length slot. mstore(result, 0) // Store the length and bytes. mstore(add(result, 0x1f), packed) // Right pad with zeroes. mstore(add(add(result, 0x20), mload(result)), 0) } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLength := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes of `a` and `b`. or( shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))), mload(sub(add(b, 0x1e), aLength)) ), // `totalLength != 0 && totalLength < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLength, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behavior is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. resultA := mload(0x40) resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retUnpaddedSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(retStart, retUnpaddedSize), 0) // Store the return offset. mstore(retStart, 0x20) // End the transaction, returning the string. return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize))) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) library FixedPointMathLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The operation failed, as the output exceeds the maximum value of uint256. error ExpOverflow(); /// @dev The operation failed, as the output exceeds the maximum value of uint256. error FactorialOverflow(); /// @dev The operation failed, due to an overflow. error RPowOverflow(); /// @dev The mantissa is too big to fit. error MantissaOverflow(); /// @dev The operation failed, due to an multiplication overflow. error MulWadFailed(); /// @dev The operation failed, due to an multiplication overflow. error SMulWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error DivWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error SDivWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error MulDivFailed(); /// @dev The division failed, as the denominator is zero. error DivFailed(); /// @dev The full precision multiply-divide operation failed, either due /// to the result being larger than 256 bits, or a division by a zero. error FullMulDivFailed(); /// @dev The output is undefined, as the input is less-than-or-equal to zero. error LnWadUndefined(); /// @dev The input outside the acceptable domain. error OutOfDomain(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The scalar of ETH and most ERC20s. uint256 internal constant WAD = 1e18; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIMPLIFIED FIXED POINT OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `(x * y) / WAD` rounded down. function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if mul(y, gt(x, div(not(0), y))) { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down. function sMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`. if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) { mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`. revert(0x1c, 0x04) } z := sdiv(z, WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded up. function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if mul(y, gt(x, div(not(0), y))) { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD)) } } /// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks. function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD)) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`. if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function sDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, WAD) // Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`. if iszero(and(iszero(iszero(y)), eq(sdiv(z, WAD), x))) { mstore(0x00, 0x5c43740d) // `SDivWadFailed()`. revert(0x1c, 0x04) } z := sdiv(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded up. function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`. if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks. function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `x` to the power of `y`. /// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`. function powWad(int256 x, int256 y) internal pure returns (int256) { // Using `ln(x)` means `x` must be greater than 0. return expWad((lnWad(x) * y) / int256(WAD)); } /// @dev Returns `exp(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln function expWad(int256 x) internal pure returns (int256 r) { unchecked { // When the result is less than 0.5 we return zero. // This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`. if (x <= -41446531673892822313) return r; /// @solidity memory-safe-assembly assembly { // When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as // an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`. if iszero(slt(x, 135305999368893231589)) { mstore(0x00, 0xa37bfec9) // `ExpOverflow()`. revert(0x1c, 0x04) } } // `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96` // for more intermediate precision and a binary basis. This base conversion // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. x = (x << 78) / 5 ** 18; // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers // of two such that exp(x) = exp(x') * 2**k, where k is an integer. // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96; x = x - k * 54916777467707473351141471128; // `k` is in the range `[-61, 195]`. // Evaluate using a (6, 7)-term rational approximation. // `p` is made monic, we'll multiply by a scale factor later. int256 y = x + 1346386616545796478920950773328; y = ((y * x) >> 96) + 57155421227552351082224309758442; int256 p = y + x - 94201549194550492254356042504812; p = ((p * y) >> 96) + 28719021644029726153956944680412240; p = p * x + (4385272521454847904659076985693276 << 96); // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. int256 q = x - 2855989394907223263936484059900; q = ((q * x) >> 96) + 50020603652535783019961831881945; q = ((q * x) >> 96) - 533845033583426703283633433725380; q = ((q * x) >> 96) + 3604857256930695427073651918091429; q = ((q * x) >> 96) - 14423608567350463180887372962807573; q = ((q * x) >> 96) + 26449188498355588339934803723976023; /// @solidity memory-safe-assembly assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial won't have zeros in the domain as all its roots are complex. // No scaling is necessary because p is already `2**96` too large. r := sdiv(p, q) } // r should be in the range `(0.09, 0.25) * 2**96`. // We now need to multiply r by: // - The scale factor `s ≈ 6.031367120`. // - The `2**k` factor from the range reduction. // - The `1e18 / 2**96` factor for base conversion. // We do this all at once, with an intermediate result in `2**213` // basis, so the final right shift is always by a positive amount. r = int256( (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k) ); } } /// @dev Returns `ln(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln function lnWad(int256 x) internal pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // We want to convert `x` from `10**18` fixed point to `2**96` fixed point. // We do this by multiplying by `2**96 / 10**18`. But since // `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here // and add `ln(2**96 / 10**18)` at the end. // Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`. r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // We place the check here for more optimal stack operations. if iszero(sgt(x, 0)) { mstore(0x00, 0x1615e638) // `LnWadUndefined()`. revert(0x1c, 0x04) } // forgefmt: disable-next-item r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)) // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) x := shr(159, shl(r, x)) // Evaluate using a (8, 8)-term rational approximation. // `p` is made monic, we will multiply by a scale factor later. // forgefmt: disable-next-item let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir. sar(96, mul(add(43456485725739037958740375743393, sar(96, mul(add(24828157081833163892658089445524, sar(96, mul(add(3273285459638523848632254066296, x), x))), x))), x)), 11111509109440967052023855526967) p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857) p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526) p := sub(mul(p, x), shl(96, 795164235651350426258249787498)) // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. // `q` is monic by convention. let q := add(5573035233440673466300451813936, x) q := add(71694874799317883764090561454958, sar(96, mul(x, q))) q := add(283447036172924575727196451306956, sar(96, mul(x, q))) q := add(401686690394027663651624208769553, sar(96, mul(x, q))) q := add(204048457590392012362485061816622, sar(96, mul(x, q))) q := add(31853899698501571402653359427138, sar(96, mul(x, q))) q := add(909429971244387300277376558375, sar(96, mul(x, q))) // `p / q` is in the range `(0, 0.125) * 2**96`. // Finalization, we need to: // - Multiply by the scale factor `s = 5.549…`. // - Add `ln(2**96 / 10**18)`. // - Add `k * ln(2)`. // - Multiply by `10**18 / 2**96 = 5**18 >> 78`. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already `2**96` too large. p := sdiv(p, q) // Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`. p := mul(1677202110996718588342820967067443963516166, p) // Add `ln(2) * k * 5**18 * 2**192`. // forgefmt: disable-next-item p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p) // Add `ln(2**96 / 10**18) * 5**18 * 2**192`. p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p) // Base conversion: mul `2**18 / 2**192`. r := sar(174, p) } } /// @dev Returns `W_0(x)`, denominated in `WAD`. /// See: https://en.wikipedia.org/wiki/Lambert_W_function /// a.k.a. Product log function. This is an approximation of the principal branch. function lambertW0Wad(int256 x) internal pure returns (int256 w) { // forgefmt: disable-next-item unchecked { if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`. int256 wad = int256(WAD); int256 p = x; uint256 c; // Whether we need to avoid catastrophic cancellation. uint256 i = 4; // Number of iterations. if (w <= 0x1ffffffffffff) { if (-0x4000000000000 <= w) { i = 1; // Inputs near zero only take one step to converge. } else if (w <= -0x3ffffffffffffff) { i = 32; // Inputs near `-1/e` take very long to converge. } } else if (w >> 63 == 0) { /// @solidity memory-safe-assembly assembly { // Inline log2 for more performance, since the range is small. let v := shr(49, w) let l := shl(3, lt(0xff, v)) l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)), 49) w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13)) c := gt(l, 60) i := add(2, add(gt(l, 53), c)) } } else { int256 ll = lnWad(w = lnWad(w)); /// @solidity memory-safe-assembly assembly { // `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`. w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll)) i := add(3, iszero(shr(68, x))) c := iszero(shr(143, x)) } if (c == 0) { do { // If `x` is big, use Newton's so that intermediate values won't overflow. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := mul(w, div(e, wad)) w := sub(w, sdiv(sub(t, x), div(add(e, t), wad))) } if (p <= w) break; p = w; } while (--i != 0); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } return w; } } do { // Otherwise, use Halley's for faster convergence. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := add(w, wad) let s := sub(mul(w, e), mul(x, wad)) w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t))))) } if (p <= w) break; p = w; } while (--i != c); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } // For certain ranges of `x`, we'll use the quadratic-rate recursive formula of // R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation. if (c != 0) { int256 t = w | 1; /// @solidity memory-safe-assembly assembly { x := sdiv(mul(x, wad), t) } x = (t * (wad + lnWad(x))); /// @solidity memory-safe-assembly assembly { w := sdiv(x, add(wad, t)) } } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* GENERAL NUMBER UTILITIES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Calculates `floor(x * y / d)` with full precision. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { // 512-bit multiply `[p1 p0] = x * y`. // Compute the product mod `2**256` and mod `2**256 - 1` // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that `product = p1 * 2**256 + p0`. // Least significant 256 bits of the product. result := mul(x, y) // Temporarily use `result` as `p0` to save gas. let mm := mulmod(x, y, not(0)) // Most significant 256 bits of the product. let p1 := sub(mm, add(result, lt(mm, result))) // Handle non-overflow cases, 256 by 256 division. if iszero(p1) { if iszero(d) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } result := div(result, d) break } // Make sure the result is less than `2**256`. Also prevents `d == 0`. if iszero(gt(d, p1)) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } /*------------------- 512 by 256 division --------------------*/ // Make division exact by subtracting the remainder from `[p1 p0]`. // Compute remainder using mulmod. let r := mulmod(x, y, d) // `t` is the least significant bit of `d`. // Always greater or equal to 1. let t := and(d, sub(0, d)) // Divide `d` by `t`, which is a power of two. d := div(d, t) // Invert `d mod 2**256` // Now that `d` is an odd number, it has an inverse // modulo `2**256` such that `d * inv = 1 mod 2**256`. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, `d * inv = 1 mod 2**4`. let inv := xor(2, mul(3, d)) // Now use 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. inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128 result := mul( // Divide [p1 p0] by the factors of two. // Shift in bits from `p1` into `p0`. For this we need // to flip `t` such that it is `2**256 / t`. or( mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)), div(sub(result, r), t) ), // inverse mod 2**256 mul(inv, sub(2, mul(d, inv))) ) break } } } /// @dev Calculates `floor(x * y / d)` with full precision, rounded up. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Uniswap-v3-core under MIT license: /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) { result = fullMulDiv(x, y, d); /// @solidity memory-safe-assembly assembly { if mulmod(x, y, d) { result := add(result, 1) if iszero(result) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } } } } /// @dev Returns `floor(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := div(mul(x, y), d) } } /// @dev Returns `ceil(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d)) } } /// @dev Returns `ceil(x / d)`. /// Reverts if `d` is zero. function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { if iszero(d) { mstore(0x00, 0x65244e4e) // `DivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(x, d))), div(x, d)) } } /// @dev Returns `max(0, x - y)`. function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(gt(x, y), sub(x, y)) } } /// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`. /// Reverts if the computation overflows. function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`. if x { z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x` let half := shr(1, b) // Divide `b` by 2. // Divide `y` by 2 every iteration. for { y := shr(1, y) } y { y := shr(1, y) } { let xx := mul(x, x) // Store x squared. let xxRound := add(xx, half) // Round to the nearest number. // Revert if `xx + half` overflowed, or if `x ** 2` overflows. if or(lt(xxRound, xx), shr(128, x)) { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } x := div(xxRound, b) // Set `x` to scaled `xxRound`. // If `y` is odd: if and(y, 1) { let zx := mul(z, x) // Compute `z * x`. let zxRound := add(zx, half) // Round to the nearest number. // If `z * x` overflowed or `zx + half` overflowed: if or(xor(div(zx, x), z), lt(zxRound, zx)) { // Revert if `x` is non-zero. if iszero(iszero(x)) { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } } z := div(zxRound, b) // Return properly scaled `zxRound`. } } } } } /// @dev Returns the square root of `x`. function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // Let `y = x / 2**r`. We check `y >= 2**(k + 8)` // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`. let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffffff, shr(r, x)))) z := shl(shr(1, r), z) // Goal was to get `z*z*y` within a small factor of `x`. More iterations could // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`. // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small. // That's not possible if `x < 256` but we can just verify those cases exhaustively. // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`. // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`. // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps. // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)` // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`, // with largest error when `s = 1` and when `s = 256` or `1/256`. // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`. // Then we can estimate `sqrt(y)` using // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`. // There is no overflow risk here since `y < 2**136` after the first branch above. z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If `x+1` is a perfect square, the Babylonian method cycles between // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division z := sub(z, lt(div(x, z), z)) } } /// @dev Returns the cube root of `x`. /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license: /// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy function cbrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3))) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := sub(z, lt(div(x, mul(z, z)), z)) } } /// @dev Returns the square root of `x`, denominated in `WAD`. function sqrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { z = 10 ** 9; if (x <= type(uint256).max / 10 ** 36 - 1) { x *= 10 ** 18; z = 1; } z *= sqrt(x); } } /// @dev Returns the cube root of `x`, denominated in `WAD`. function cbrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { z = 10 ** 12; if (x <= (type(uint256).max / 10 ** 36) * 10 ** 18 - 1) { if (x >= type(uint256).max / 10 ** 36) { x *= 10 ** 18; z = 10 ** 6; } else { x *= 10 ** 36; z = 1; } } z *= cbrt(x); } } /// @dev Returns the factorial of `x`. function factorial(uint256 x) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if iszero(lt(x, 58)) { mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`. revert(0x1c, 0x04) } for { result := 1 } x { x := sub(x, 1) } { result := mul(result, x) } } } /// @dev Returns the log2 of `x`. /// Equivalent to computing the index of the most significant bit (MSB) of `x`. /// Returns 0 if `x` is zero. function log2(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)) } } /// @dev Returns the log2 of `x`, rounded up. /// Returns 0 if `x` is zero. function log2Up(uint256 x) internal pure returns (uint256 r) { r = log2(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(r, 1), x)) } } /// @dev Returns the log10 of `x`. /// Returns 0 if `x` is zero. function log10(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { if iszero(lt(x, 100000000000000000000000000000000000000)) { x := div(x, 100000000000000000000000000000000000000) r := 38 } if iszero(lt(x, 100000000000000000000)) { x := div(x, 100000000000000000000) r := add(r, 20) } if iszero(lt(x, 10000000000)) { x := div(x, 10000000000) r := add(r, 10) } if iszero(lt(x, 100000)) { x := div(x, 100000) r := add(r, 5) } r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999))))) } } /// @dev Returns the log10 of `x`, rounded up. /// Returns 0 if `x` is zero. function log10Up(uint256 x) internal pure returns (uint256 r) { r = log10(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(exp(10, r), x)) } } /// @dev Returns the log256 of `x`. /// Returns 0 if `x` is zero. function log256(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(shr(3, r), lt(0xff, shr(r, x))) } } /// @dev Returns the log256 of `x`, rounded up. /// Returns 0 if `x` is zero. function log256Up(uint256 x) internal pure returns (uint256 r) { r = log256(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(shl(3, r), 1), x)) } } /// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`. /// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent). function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) { /// @solidity memory-safe-assembly assembly { mantissa := x if mantissa { if iszero(mod(mantissa, 1000000000000000000000000000000000)) { mantissa := div(mantissa, 1000000000000000000000000000000000) exponent := 33 } if iszero(mod(mantissa, 10000000000000000000)) { mantissa := div(mantissa, 10000000000000000000) exponent := add(exponent, 19) } if iszero(mod(mantissa, 1000000000000)) { mantissa := div(mantissa, 1000000000000) exponent := add(exponent, 12) } if iszero(mod(mantissa, 1000000)) { mantissa := div(mantissa, 1000000) exponent := add(exponent, 6) } if iszero(mod(mantissa, 10000)) { mantissa := div(mantissa, 10000) exponent := add(exponent, 4) } if iszero(mod(mantissa, 100)) { mantissa := div(mantissa, 100) exponent := add(exponent, 2) } if iszero(mod(mantissa, 10)) { mantissa := div(mantissa, 10) exponent := add(exponent, 1) } } } } /// @dev Convenience function for packing `x` into a smaller number using `sci`. /// The `mantissa` will be in bits [7..255] (the upper 249 bits). /// The `exponent` will be in bits [0..6] (the lower 7 bits). /// Use `SafeCastLib` to safely ensure that the `packed` number is small /// enough to fit in the desired unsigned integer type: /// ``` /// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether)); /// ``` function packSci(uint256 x) internal pure returns (uint256 packed) { (x, packed) = sci(x); // Reuse for `mantissa` and `exponent`. /// @solidity memory-safe-assembly assembly { if shr(249, x) { mstore(0x00, 0xce30380c) // `MantissaOverflow()`. revert(0x1c, 0x04) } packed := or(shl(7, x), packed) } } /// @dev Convenience function for unpacking a packed number from `packSci`. function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) { unchecked { unpacked = (packed >> 7) * 10 ** (packed & 0x7f); } } /// @dev Returns the average of `x` and `y`. function avg(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = (x & y) + ((x ^ y) >> 1); } } /// @dev Returns the average of `x` and `y`. function avg(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = (x >> 1) + (y >> 1) + (x & y & 1); } } /// @dev Returns the absolute value of `x`. function abs(int256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(sar(255, x), add(sar(255, x), x)) } } /// @dev Returns the absolute distance between `x` and `y`. function dist(int256 x, int256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(mul(xor(sub(y, x), sub(x, y)), sgt(x, y)), sub(y, x)) } } /// @dev Returns the minimum of `x` and `y`. function min(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), lt(y, x))) } } /// @dev Returns the minimum of `x` and `y`. function min(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), slt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), gt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), sgt(y, x))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(uint256 x, uint256 minValue, uint256 maxValue) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), gt(minValue, x))) z := xor(z, mul(xor(z, maxValue), lt(maxValue, z))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), sgt(minValue, x))) z := xor(z, mul(xor(z, maxValue), slt(maxValue, z))) } } /// @dev Returns greatest common divisor of `x` and `y`. function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { for { z := x } y {} { let t := y y := mod(z, y) z := t } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RAW NUMBER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `x + y`, without checking for overflow. function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x + y; } } /// @dev Returns `x + y`, without checking for overflow. function rawAdd(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x + y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x - y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x - y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x * y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x * y; } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(x, y) } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mod(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawSMod(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := smod(x, y) } } /// @dev Returns `(x + y) % d`, return 0 if `d` if zero. function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := addmod(x, y, d) } } /// @dev Returns `(x * y) % d`, return 0 if `d` if zero. function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mulmod(x, y, d) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol) library MerkleProofLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MERKLE PROOF VERIFICATION OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`. function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool isValid) { /// @solidity memory-safe-assembly assembly { if mload(proof) { // Initialize `offset` to the offset of `proof` elements in memory. let offset := add(proof, 0x20) // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(offset, shl(5, mload(proof))) // Iterate over proof elements to compute root hash. for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, mload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), mload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`. function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool isValid) { /// @solidity memory-safe-assembly assembly { if proof.length { // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(proof.offset, shl(5, proof.length)) // Initialize `offset` to the offset of `proof` in the calldata. let offset := proof.offset // Iterate over proof elements to compute root hash. for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, calldataload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), calldataload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`, /// given `proof` and `flags`. /// /// Note: /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length` /// will always return false. /// - The sum of the lengths of `proof` and `leaves` must never overflow. /// - Any non-zero word in the `flags` array is treated as true. /// - The memory offset of `proof` must be non-zero /// (i.e. `proof` is not pointing to the scratch space). function verifyMultiProof( bytes32[] memory proof, bytes32 root, bytes32[] memory leaves, bool[] memory flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leaves` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). /// @solidity memory-safe-assembly assembly { // Cache the lengths of the arrays. let leavesLength := mload(leaves) let proofLength := mload(proof) let flagsLength := mload(flags) // Advance the pointers of the arrays to point to the data. leaves := add(0x20, leaves) proof := add(0x20, proof) flags := add(0x20, flags) // If the number of flags is correct. for {} eq(add(leavesLength, proofLength), add(flagsLength, 1)) {} { // For the case where `proof.length + leaves.length == 1`. if iszero(flagsLength) { // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`. isValid := eq(mload(xor(leaves, mul(xor(proof, leaves), proofLength))), root) break } // The required final proof offset if `flagsLength` is not zero, otherwise zero. let proofEnd := add(proof, shl(5, proofLength)) // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) // Copy the leaves into the hashes. // Sometimes, a little memory expansion costs less than branching. // Should cost less, even with a high free memory offset of 0x7d00. leavesLength := shl(5, leavesLength) for { let i := 0 } iszero(eq(i, leavesLength)) { i := add(i, 0x20) } { mstore(add(hashesFront, i), mload(add(leaves, i))) } // Compute the back of the hashes. let hashesBack := add(hashesFront, leavesLength) // This is the end of the memory for the queue. // We recycle `flagsLength` to save on stack variables (sometimes save gas). flagsLength := add(hashesBack, shl(5, flagsLength)) for {} 1 {} { // Pop from `hashes`. let a := mload(hashesFront) // Pop from `hashes`. let b := mload(add(hashesFront, 0x20)) hashesFront := add(hashesFront, 0x40) // If the flag is false, load the next proof, // else, pops from the queue. if iszero(mload(flags)) { // Loads the next proof. b := mload(proof) proof := add(proof, 0x20) // Unpop from `hashes`. hashesFront := sub(hashesFront, 0x20) } // Advance to the next flag. flags := add(flags, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) if iszero(lt(hashesBack, flagsLength)) { break } } isValid := and( // Checks if the last value in the queue is same as the root. eq(mload(sub(hashesBack, 0x20)), root), // And whether all the proofs are used, if required. eq(proofEnd, proof) ) break } } } /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`, /// given `proof` and `flags`. /// /// Note: /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length` /// will always return false. /// - Any non-zero word in the `flags` array is treated as true. /// - The calldata offset of `proof` must be non-zero /// (i.e. `proof` is from a regular Solidity function with a 4-byte selector). function verifyMultiProofCalldata( bytes32[] calldata proof, bytes32 root, bytes32[] calldata leaves, bool[] calldata flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leaves` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). /// @solidity memory-safe-assembly assembly { // If the number of flags is correct. for {} eq(add(leaves.length, proof.length), add(flags.length, 1)) {} { // For the case where `proof.length + leaves.length == 1`. if iszero(flags.length) { // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`. // forgefmt: disable-next-item isValid := eq( calldataload( xor(leaves.offset, mul(xor(proof.offset, leaves.offset), proof.length)) ), root ) break } // The required final proof offset if `flagsLength` is not zero, otherwise zero. let proofEnd := add(proof.offset, shl(5, proof.length)) // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) // Copy the leaves into the hashes. // Sometimes, a little memory expansion costs less than branching. // Should cost less, even with a high free memory offset of 0x7d00. calldatacopy(hashesFront, leaves.offset, shl(5, leaves.length)) // Compute the back of the hashes. let hashesBack := add(hashesFront, shl(5, leaves.length)) // This is the end of the memory for the queue. // We recycle `flagsLength` to save on stack variables (sometimes save gas). flags.length := add(hashesBack, shl(5, flags.length)) // We don't need to make a copy of `proof.offset` or `flags.offset`, // as they are pass-by-value (this trick may not always save gas). for {} 1 {} { // Pop from `hashes`. let a := mload(hashesFront) // Pop from `hashes`. let b := mload(add(hashesFront, 0x20)) hashesFront := add(hashesFront, 0x40) // If the flag is false, load the next proof, // else, pops from the queue. if iszero(calldataload(flags.offset)) { // Loads the next proof. b := calldataload(proof.offset) proof.offset := add(proof.offset, 0x20) // Unpop from `hashes`. hashesFront := sub(hashesFront, 0x20) } // Advance to the next flag offset. flags.offset := add(flags.offset, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) if iszero(lt(hashesBack, flags.length)) { break } } isValid := and( // Checks if the last value in the queue is same as the root. eq(mload(sub(hashesBack, 0x20)), root), // And whether all the proofs are used, if required. eq(proofEnd, proof.offset) ) break } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EMPTY CALLDATA HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an empty calldata bytes32 array. function emptyProof() internal pure returns (bytes32[] calldata proof) { /// @solidity memory-safe-assembly assembly { proof.length := 0 } } /// @dev Returns an empty calldata bytes32 array. function emptyLeaves() internal pure returns (bytes32[] calldata leaves) { /// @solidity memory-safe-assembly assembly { leaves.length := 0 } } /// @dev Returns an empty calldata bool array. function emptyFlags() internal pure returns (bool[] calldata flags) { /// @solidity memory-safe-assembly assembly { flags.length := 0 } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721.sol) pragma solidity ^0.8.20; import {IERC721} from "../token/ERC721/IERC721.sol";
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC721 implementation with storage hitchhiking. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC721.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC721/ERC721.sol) /// /// @dev Note: /// - The ERC721 standard allows for self-approvals. /// For performance, this implementation WILL NOT revert for such actions. /// Please add any checks with overrides if desired. /// - For performance, methods are made payable where permitted by the ERC721 standard. /// - The `safeTransfer` functions use the identity precompile (0x4) /// to copy memory internally. /// /// If you are overriding: /// - NEVER violate the ERC721 invariant: /// the balance of an owner MUST always be equal to their number of ownership slots. /// The transfer functions do not have an underflow guard for user token balances. /// - Make sure all variables written to storage are properly cleaned // (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood). /// - Check that the overridden function is actually used in the function you want to /// change the behavior of. Much of the code has been manually inlined for performance. abstract contract ERC721 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev An account can hold up to 4294967295 tokens. uint256 internal constant _MAX_ACCOUNT_BALANCE = 0xffffffff; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Only the token owner or an approved account can manage the token. error NotOwnerNorApproved(); /// @dev The token does not exist. error TokenDoesNotExist(); /// @dev The token already exists. error TokenAlreadyExists(); /// @dev Cannot query the balance for the zero address. error BalanceQueryForZeroAddress(); /// @dev Cannot mint or transfer to the zero address. error TransferToZeroAddress(); /// @dev The token must be owned by `from`. error TransferFromIncorrectOwner(); /// @dev The recipient's balance has overflowed. error AccountBalanceOverflow(); /// @dev Cannot safely transfer to a contract that does not implement /// the ERC721Receiver interface. error TransferToNonERC721ReceiverImplementer(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when token `id` is transferred from `from` to `to`. event Transfer(address indexed from, address indexed to, uint256 indexed id); /// @dev Emitted when `owner` enables `account` to manage the `id` token. event Approval(address indexed owner, address indexed account, uint256 indexed id); /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens. event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved); /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`. uint256 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`. uint256 private constant _APPROVAL_EVENT_SIGNATURE = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925; /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`. uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership data slot of `id` is given by: /// ``` /// mstore(0x00, id) /// mstore(0x1c, _ERC721_MASTER_SLOT_SEED) /// let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) /// ``` /// Bits Layout: /// - [0..159] `addr` /// - [160..255] `extraData` /// /// The approved address slot is given by: `add(1, ownershipSlot)`. /// /// See: https://notes.ethereum.org/%40vbuterin/verkle_tree_eip /// /// The balance slot of `owner` is given by: /// ``` /// mstore(0x1c, _ERC721_MASTER_SLOT_SEED) /// mstore(0x00, owner) /// let balanceSlot := keccak256(0x0c, 0x1c) /// ``` /// Bits Layout: /// - [0..31] `balance` /// - [32..255] `aux` /// /// The `operator` approval slot of `owner` is given by: /// ``` /// mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator)) /// mstore(0x00, owner) /// let operatorApprovalSlot := keccak256(0x0c, 0x30) /// ``` uint256 private constant _ERC721_MASTER_SLOT_SEED = 0x7d8825530a5a2e7a << 192; /// @dev Pre-shifted and pre-masked constant. uint256 private constant _ERC721_MASTER_SLOT_SEED_MASKED = 0x0a5a2e7a00000000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC721 METADATA */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the token collection name. function name() public view virtual returns (string memory); /// @dev Returns the token collection symbol. function symbol() public view virtual returns (string memory); /// @dev Returns the Uniform Resource Identifier (URI) for token `id`. function tokenURI(uint256 id) public view virtual returns (string memory); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC721 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of token `id`. /// /// Requirements: /// - Token `id` must exist. function ownerOf(uint256 id) public view virtual returns (address result) { result = _ownerOf(id); /// @solidity memory-safe-assembly assembly { if iszero(result) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } } } /// @dev Returns the number of tokens owned by `owner`. /// /// Requirements: /// - `owner` must not be the zero address. function balanceOf(address owner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Revert if the `owner` is the zero address. if iszero(owner) { mstore(0x00, 0x8f4eb604) // `BalanceQueryForZeroAddress()`. revert(0x1c, 0x04) } mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) result := and(sload(keccak256(0x0c, 0x1c)), _MAX_ACCOUNT_BALANCE) } } /// @dev Returns the account approved to manage token `id`. /// /// Requirements: /// - Token `id` must exist. function getApproved(uint256 id) public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) if iszero(shl(96, sload(ownershipSlot))) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } result := sload(add(1, ownershipSlot)) } } /// @dev Sets `account` as the approved account to manage token `id`. /// /// Requirements: /// - Token `id` must exist. /// - The caller must be the owner of the token, /// or an approved operator for the token owner. /// /// Emits an {Approval} event. function approve(address account, uint256 id) public payable virtual { _approve(msg.sender, account, id); } /// @dev Returns whether `operator` is approved to manage the tokens of `owner`. function isApprovedForAll(address owner, address operator) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x1c, operator) mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x30)) } } /// @dev Sets whether `operator` is approved to manage the tokens of the caller. /// /// Emits an {ApprovalForAll} event. function setApprovalForAll(address operator, bool isApproved) public virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`msg.sender`, `operator`). mstore(0x1c, operator) mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x30), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) // forgefmt: disable-next-item log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator))) } } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function transferFrom(address from, address to, uint256 id) public payable virtual { _beforeTokenTransfer(from, to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) from := and(bitmaskAddress, from) to := and(bitmaskAddress, to) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, caller())) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) let owner := and(bitmaskAddress, ownershipPacked) // Revert if the token does not exist, or if `from` is not the owner. if iszero(mul(owner, eq(owner, from))) { // `TokenDoesNotExist()`, `TransferFromIncorrectOwner()`. mstore(shl(2, iszero(owner)), 0xceea21b6a1148100) revert(0x1c, 0x04) } // Load, check, and update the token approval. { mstore(0x00, from) let approvedAddress := sload(add(1, ownershipSlot)) // Revert if the caller is not the owner, nor approved. if iszero(or(eq(caller(), from), eq(caller(), approvedAddress))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Update with the new owner. sstore(ownershipSlot, xor(ownershipPacked, xor(from, to))) // Decrement the balance of `from`. { let fromBalanceSlot := keccak256(0x0c, 0x1c) sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1)) } // Increment the balance of `to`. { mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x1c) let toBalanceSlotPacked := add(sload(toBalanceSlot), 1) // Revert if `to` is the zero address, or if the account balance overflows. if iszero(mul(to, and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE))) { // `TransferToZeroAddress()`, `AccountBalanceOverflow()`. mstore(shl(2, iszero(to)), 0xea553b3401336cea) revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceSlotPacked) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id) } _afterTokenTransfer(from, to, id); } /// @dev Equivalent to `safeTransferFrom(from, to, id, "")`. function safeTransferFrom(address from, address to, uint256 id) public payable virtual { transferFrom(from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// - 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 id, bytes calldata data) public payable virtual { transferFrom(from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f. result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL QUERY FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns if token `id` exists. function _exists(uint256 id) internal view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := iszero(iszero(shl(96, sload(add(id, add(id, keccak256(0x00, 0x20))))))) } } /// @dev Returns the owner of token `id`. /// Returns the zero address instead of reverting if the token does not exist. function _ownerOf(uint256 id) internal view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := shr(96, shl(96, sload(add(id, add(id, keccak256(0x00, 0x20)))))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL DATA HITCHHIKING FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance, no events are emitted for the hitchhiking setters. // Please emit your own events if required. /// @dev Returns the auxiliary data for `owner`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _getAux(address owner) internal view virtual returns (uint224 result) { /// @solidity memory-safe-assembly assembly { mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) result := shr(32, sload(keccak256(0x0c, 0x1c))) } } /// @dev Set the auxiliary data for `owner` to `value`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _setAux(address owner, uint224 value) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) let balanceSlot := keccak256(0x0c, 0x1c) let packed := sload(balanceSlot) sstore(balanceSlot, xor(packed, shl(32, xor(value, shr(32, packed))))) } } /// @dev Returns the extra data for token `id`. /// Minting, transferring, burning a token will not change the extra data. /// The extra data can be set on a non-existent token. function _getExtraData(uint256 id) internal view virtual returns (uint96 result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := shr(160, sload(add(id, add(id, keccak256(0x00, 0x20))))) } } /// @dev Sets the extra data for token `id` to `value`. /// Minting, transferring, burning a token will not change the extra data. /// The extra data can be set on a non-existent token. function _setExtraData(uint256 id, uint96 value) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let packed := sload(ownershipSlot) sstore(ownershipSlot, xor(packed, shl(160, xor(value, shr(160, packed))))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL MINT FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mints token `id` to `to`. /// /// Requirements: /// /// - Token `id` must not exist. /// - `to` cannot be the zero address. /// /// Emits a {Transfer} event. function _mint(address to, uint256 id) internal virtual { _beforeTokenTransfer(address(0), to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. to := shr(96, shl(96, to)) // Load the ownership data. mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) // Revert if the token already exists. if shl(96, ownershipPacked) { mstore(0x00, 0xc991cbb1) // `TokenAlreadyExists()`. revert(0x1c, 0x04) } // Update with the owner. sstore(ownershipSlot, or(ownershipPacked, to)) // Increment the balance of the owner. { mstore(0x00, to) let balanceSlot := keccak256(0x0c, 0x1c) let balanceSlotPacked := add(sload(balanceSlot), 1) // Revert if `to` is the zero address, or if the account balance overflows. if iszero(mul(to, and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE))) { // `TransferToZeroAddress()`, `AccountBalanceOverflow()`. mstore(shl(2, iszero(to)), 0xea553b3401336cea) revert(0x1c, 0x04) } sstore(balanceSlot, balanceSlotPacked) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id) } _afterTokenTransfer(address(0), to, id); } /// @dev Mints token `id` to `to`, and updates the extra data for token `id` to `value`. /// Does NOT check if token `id` already exists (assumes `id` is auto-incrementing). /// /// Requirements: /// /// - `to` cannot be the zero address. /// /// Emits a {Transfer} event. function _mintAndSetExtraDataUnchecked(address to, uint256 id, uint96 value) internal virtual { _beforeTokenTransfer(address(0), to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. to := shr(96, shl(96, to)) // Update with the owner and extra data. mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) sstore(add(id, add(id, keccak256(0x00, 0x20))), or(shl(160, value), to)) // Increment the balance of the owner. { mstore(0x00, to) let balanceSlot := keccak256(0x0c, 0x1c) let balanceSlotPacked := add(sload(balanceSlot), 1) // Revert if `to` is the zero address, or if the account balance overflows. if iszero(mul(to, and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE))) { // `TransferToZeroAddress()`, `AccountBalanceOverflow()`. mstore(shl(2, iszero(to)), 0xea553b3401336cea) revert(0x1c, 0x04) } sstore(balanceSlot, balanceSlotPacked) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id) } _afterTokenTransfer(address(0), to, id); } /// @dev Equivalent to `_safeMint(to, id, "")`. function _safeMint(address to, uint256 id) internal virtual { _safeMint(to, id, ""); } /// @dev Mints token `id` to `to`. /// /// Requirements: /// /// - Token `id` must not exist. /// - `to` cannot be the zero address. /// - 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 id, bytes memory data) internal virtual { _mint(to, id); if (_hasCode(to)) _checkOnERC721Received(address(0), to, id, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL BURN FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_burn(address(0), id)`. function _burn(uint256 id) internal virtual { _burn(address(0), id); } /// @dev Destroys token `id`, using `by`. /// /// Requirements: /// /// - Token `id` must exist. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function _burn(address by, uint256 id) internal virtual { address owner = ownerOf(id); _beforeTokenTransfer(owner, address(0), id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. by := shr(96, shl(96, by)) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) // Reload the owner in case it is changed in `_beforeTokenTransfer`. owner := shr(96, shl(96, ownershipPacked)) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // Load and check the token approval. { mstore(0x00, owner) let approvedAddress := sload(add(1, ownershipSlot)) // If `by` is not the zero address, do the authorization check. // Revert if the `by` is not the owner, nor approved. if iszero(or(iszero(by), or(eq(by, owner), eq(by, approvedAddress)))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Clear the owner. sstore(ownershipSlot, xor(ownershipPacked, owner)) // Decrement the balance of `owner`. { let balanceSlot := keccak256(0x0c, 0x1c) sstore(balanceSlot, sub(sload(balanceSlot), 1)) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, owner, 0, id) } _afterTokenTransfer(owner, address(0), id); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL APPROVAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `account` is the owner of token `id`, or is approved to manage it. /// /// Requirements: /// - Token `id` must exist. function _isApprovedOrOwner(address account, uint256 id) internal view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 // Clear the upper 96 bits. account := shr(96, shl(96, account)) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, account)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let owner := shr(96, shl(96, sload(ownershipSlot))) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // Check if `account` is the `owner`. if iszero(eq(account, owner)) { mstore(0x00, owner) // Check if `account` is approved to manage the token. if iszero(sload(keccak256(0x0c, 0x30))) { result := eq(account, sload(add(1, ownershipSlot))) } } } } /// @dev Returns the account approved to manage token `id`. /// Returns the zero address instead of reverting if the token does not exist. function _getApproved(uint256 id) internal view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := sload(add(1, add(id, add(id, keccak256(0x00, 0x20))))) } } /// @dev Equivalent to `_approve(address(0), account, id)`. function _approve(address account, uint256 id) internal virtual { _approve(address(0), account, id); } /// @dev Sets `account` as the approved account to manage token `id`, using `by`. /// /// Requirements: /// - Token `id` must exist. /// - If `by` is not the zero address, `by` must be the owner /// or an approved operator for the token owner. /// /// Emits a {Approval} event. function _approve(address by, address account, uint256 id) internal virtual { assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) account := and(bitmaskAddress, account) by := and(bitmaskAddress, by) // Load the owner of the token. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let owner := and(bitmaskAddress, sload(ownershipSlot)) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // If `by` is not the zero address, do the authorization check. // Revert if `by` is not the owner, nor approved. if iszero(or(iszero(by), eq(by, owner))) { mstore(0x00, owner) if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Sets `account` as the approved account to manage `id`. sstore(add(1, ownershipSlot), account) // Emit the {Approval} event. log4(codesize(), 0x00, _APPROVAL_EVENT_SIGNATURE, owner, account, id) } } /// @dev Approve or remove the `operator` as an operator for `by`, /// without authorization checks. /// /// Emits an {ApprovalForAll} event. function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual { /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. by := shr(96, shl(96, by)) operator := shr(96, shl(96, operator)) // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`by`, `operator`). mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator)) mstore(0x00, by) sstore(keccak256(0x0c, 0x30), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, by, operator) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL TRANSFER FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_transfer(address(0), from, to, id)`. function _transfer(address from, address to, uint256 id) internal virtual { _transfer(address(0), from, to, id); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function _transfer(address by, address from, address to, uint256 id) internal virtual { _beforeTokenTransfer(from, to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) from := and(bitmaskAddress, from) to := and(bitmaskAddress, to) by := and(bitmaskAddress, by) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) let owner := and(bitmaskAddress, ownershipPacked) // Revert if the token does not exist, or if `from` is not the owner. if iszero(mul(owner, eq(owner, from))) { // `TokenDoesNotExist()`, `TransferFromIncorrectOwner()`. mstore(shl(2, iszero(owner)), 0xceea21b6a1148100) revert(0x1c, 0x04) } // Load, check, and update the token approval. { mstore(0x00, from) let approvedAddress := sload(add(1, ownershipSlot)) // If `by` is not the zero address, do the authorization check. // Revert if the `by` is not the owner, nor approved. if iszero(or(iszero(by), or(eq(by, from), eq(by, approvedAddress)))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Update with the new owner. sstore(ownershipSlot, xor(ownershipPacked, xor(from, to))) // Decrement the balance of `from`. { let fromBalanceSlot := keccak256(0x0c, 0x1c) sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1)) } // Increment the balance of `to`. { mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x1c) let toBalanceSlotPacked := add(sload(toBalanceSlot), 1) // Revert if `to` is the zero address, or if the account balance overflows. if iszero(mul(to, and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE))) { // `TransferToZeroAddress()`, `AccountBalanceOverflow()`. mstore(shl(2, iszero(to)), 0xea553b3401336cea) revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceSlotPacked) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id) } _afterTokenTransfer(from, to, id); } /// @dev Equivalent to `_safeTransfer(from, to, id, "")`. function _safeTransfer(address from, address to, uint256 id) internal virtual { _safeTransfer(from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// - 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 id, bytes memory data) internal virtual { _transfer(address(0), from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /// @dev Equivalent to `_safeTransfer(by, from, to, id, "")`. function _safeTransfer(address by, address from, address to, uint256 id) internal virtual { _safeTransfer(by, from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// - 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 by, address from, address to, uint256 id, bytes memory data) internal virtual { _transfer(by, from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HOOKS FOR OVERRIDING */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Hook that is called before any token transfers, including minting and burning. function _beforeTokenTransfer(address from, address to, uint256 id) internal virtual {} /// @dev Hook that is called after any token transfers, including minting and burning. function _afterTokenTransfer(address from, address to, uint256 id) internal virtual {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns if `a` has bytecode of non-zero length. function _hasCode(address a) private view returns (bool result) { /// @solidity memory-safe-assembly assembly { result := extcodesize(a) // Can handle dirty upper bits. } } /// @dev Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) let onERC721ReceivedSelector := 0x150b7a02 mstore(m, onERC721ReceivedSelector) mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`. mstore(add(m, 0x40), shr(96, shl(96, from))) mstore(add(m, 0x60), id) mstore(add(m, 0x80), 0x80) let n := mload(data) mstore(add(m, 0xa0), n) if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) } // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } // Load the returndata and compare it. if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) { mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`. revert(0x1c, 0x04) } } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.23; /* * ,_, * (',') * {/"\} * -"-"- */ import {Ownable} from "../lib/solady/src/auth/Ownable.sol"; import {IERC721x} from "./interfaces/IERC721x.sol"; abstract contract LockRegistry is Ownable, IERC721x { mapping(address lockingContract => bool status) public override approvedContract; mapping(uint256 tokenId => uint256 count) public override lockCount; mapping(uint256 tokenId => mapping(uint256 lockIndex => address lockingContract)) public override lockMap; mapping(uint256 tokenId => mapping(address lockingContract => uint256 lockIndex)) public override lockMapIndex; event TokenLocked(uint256 indexed tokenId, address indexed approvedContract); event TokenUnlocked(uint256 indexed tokenId, address indexed approvedContract); function isUnlocked(uint256 tokenId) public view override returns(bool status) { return lockCount[tokenId] == 0; } function updateApprovedContracts(address[] calldata contracts, bool[] calldata values) external onlyOwner { if (contracts.length != values.length) revert IERC721x.ArrayLengthMismatch(); for (uint256 i = 0; i < contracts.length; ++i) { approvedContract[contracts[i]] = values[i]; } } function _lockId(uint256 tokenId) internal { if (!approvedContract[msg.sender]) revert IERC721x.NotApprovedContract(); if (lockMapIndex[tokenId][msg.sender] != 0) revert IERC721x.AlreadyLocked(); unchecked { uint256 count = lockCount[tokenId] + 1; lockMap[tokenId][count] = msg.sender; lockMapIndex[tokenId][msg.sender] = count; lockCount[tokenId] = count; } emit TokenLocked(tokenId, msg.sender); } function _unlockId(uint256 tokenId) internal { if (!approvedContract[msg.sender]) revert IERC721x.NotApprovedContract(); uint256 index = lockMapIndex[tokenId][msg.sender]; if (index == 0) revert IERC721x.NotLocked(); uint256 last = lockCount[tokenId]; if (index != last) { address lastContract = lockMap[tokenId][last]; lockMap[tokenId][index] = lastContract; lockMap[tokenId][last] = address(0); lockMapIndex[tokenId][lastContract] = index; } else { lockMap[tokenId][index] = address(0); } lockMapIndex[tokenId][msg.sender] = 0; unchecked { --lockCount[tokenId]; } emit TokenUnlocked(tokenId, msg.sender); } function _freeId(uint256 tokenId, address lockingContract) internal { if (approvedContract[lockingContract]) revert IERC721x.ApprovedContract(); uint256 index = lockMapIndex[tokenId][lockingContract]; if (index == 0) revert IERC721x.NotLocked(); uint256 last = lockCount[tokenId]; if (index != last) { address lastContract = lockMap[tokenId][last]; lockMap[tokenId][index] = lastContract; lockMap[tokenId][last] = address(0); lockMapIndex[tokenId][lastContract] = index; } else { lockMap[tokenId][index] = address(0); } lockMapIndex[tokenId][lockingContract] = 0; unchecked { --lockCount[tokenId]; } emit TokenUnlocked(tokenId, lockingContract); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.23; /* * ,_, * (',') * {/"\} * -"-"- */ interface IERC721x { /** * @dev Thrown when array parameter lengths do not match. */ error ArrayLengthMismatch(); /** * @dev Thrown when a token locked by an approved contract is freed. */ error ApprovedContract(); /** * @dev Thrown when unapproved contract tries to lock/unlock tokens. */ error NotApprovedContract(); /** * @dev Thrown if a locked token is transferred. */ error Locked(uint256 tokenId); /** * @dev Thrown when caller tries to lock a tokenId they've already locked. */ error AlreadyLocked(); /** * @dev Thrown when caller tries to unlock a tokenId they haven't locked. */ error NotLocked(); /** * @dev Returns if the token is locked (non-transferrable) or not. */ function isUnlocked(uint256 tokenId) external view returns(bool status); /** * @dev Returns the amount of locks on the token. */ function lockCount(uint256 tokenId) external view returns(uint256 count); /** * @dev Returns if a contract is allowed to lock/unlock tokens. */ function approvedContract(address lockingContract) external view returns(bool status); /** * @dev Returns the contract that locked a token at a specific index in the mapping. */ function lockMap(uint256 tokenId, uint256 lockIndex) external view returns(address lockingContract); /** * @dev Returns the mapping index of a contract that locked a token. */ function lockMapIndex(uint256 tokenId, address lockingContract) external view returns(uint256 lockIndex); /** * @dev Locks a token, preventing it from being transferrable */ function lockId(uint256 tokenId) external; /** * @dev Unlocks a token. */ function unlockId(uint256 tokenId) external; /** * @dev Unlocks a token from a given contract if the contract is no longer approved. */ function freeId(uint256 tokenId, address lockingContract) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC-721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC-721 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 ERC-721 * 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 address zero. * * 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 pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /// @dev Cannot double-initialize. error AlreadyInitialized(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. bytes32 internal constant _OWNER_SLOT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return true to make `_initializeOwner` prevent double-initialization. function _guardInitializeOwner() internal pure virtual returns (bool guard) {} /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT if sload(ownerSlot) { mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`. revert(0x1c, 0x04) } // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } else { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(_OWNER_SLOT, newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) } } else { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(_OWNER_SLOT))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(_OWNER_SLOT) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "remappings": [ "@openzeppelin-upgradeable/=lib/AlignmentVault/lib/nftx-protocol-v3/lib/openzeppelin-contracts-upgradeable/", "@openzeppelin/=lib/AlignmentVault/lib/nftx-protocol-v3/lib/openzeppelin-contracts/", "@openzeppelin/contracts/=lib/AlignmentVault/lib/nftx-protocol-v3/lib/openzeppelin-contracts/contracts/", "@mocks/=lib/AlignmentVault/lib/nftx-protocol-v3/src/mocks/", "@openzeppelin/contracts-upgradeable/=lib/ERC721M/lib/ERC721x/lib/openzeppelin-contracts-upgradeable/contracts/", "@permit2/=lib/AlignmentVault/lib/nftx-protocol-v3/lib/permit2/src/", "@src/=lib/AlignmentVault/lib/nftx-protocol-v3/src/", "@test/=lib/AlignmentVault/lib/nftx-protocol-v3/test/", "@uni-core/=lib/AlignmentVault/lib/nftx-protocol-v3/src/uniswap/v3-core/", "@uni-periphery/=lib/AlignmentVault/lib/nftx-protocol-v3/src/uniswap/v3-periphery/", "@uniswap/lib/=lib/AlignmentVault/lib/nftx-protocol-v3/lib/solidity-lib/", "@uniswap/v2-core/=lib/AlignmentVault/lib/nftx-protocol-v3/lib/v2-core/", "@uniswap/v3-core/contracts/=lib/AlignmentVault/lib/nftx-protocol-v3/src/uniswap/v3-core/", "AlignmentVault/=lib/AlignmentVault/", "ERC721A-Upgradeable/=lib/ERC721M/lib/ERC721x/lib/ERC721A-Upgradeable/contracts/", "ERC721A/=lib/ERC721M/lib/ERC721x/lib/ERC721A/contracts/", "ERC721M/=lib/ERC721M/", "ERC721x/=lib/ERC721M/lib/ERC721x/", "base64-sol/=lib/AlignmentVault/lib/nftx-protocol-v3/src/uniswap/v3-periphery/libraries/", "delegate-registry/=lib/AlignmentVault/lib/delegate-registry/", "ds-test/=lib/AlignmentVault/lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-gas-snapshot/=lib/AlignmentVault/lib/nftx-protocol-v3/lib/permit2/lib/forge-gas-snapshot/src/", "forge-std/=lib/forge-std/src/", "murky/=lib/AlignmentVault/lib/delegate-registry/lib/murky/", "nftx-protocol-v3/=lib/AlignmentVault/lib/nftx-protocol-v3/src/", "openzeppelin-contracts-upgradeable/=lib/ERC721M/lib/ERC721x/lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts-v5/=lib/AlignmentVault/lib/openzeppelin-contracts-v5/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin/=lib/AlignmentVault/lib/delegate-registry/lib/openzeppelin-contracts/contracts/", "permit2/=lib/AlignmentVault/lib/nftx-protocol-v3/lib/permit2/", "solady/=lib/solady/src/", "solidity-lib/=lib/AlignmentVault/lib/nftx-protocol-v3/lib/solidity-lib/contracts/", "solmate/=lib/AlignmentVault/lib/solmate/src/", "v2-core/=lib/AlignmentVault/lib/v2-core/contracts/", "v2-periphery/=lib/AlignmentVault/lib/v2-periphery/contracts/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": false, "libraries": {} }
[{"inputs":[],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AlreadyLocked","type":"error"},{"inputs":[],"name":"ApprovedContract","type":"error"},{"inputs":[],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"Blacklisted","type":"error"},{"inputs":[],"name":"ExcessiveClaim","type":"error"},{"inputs":[],"name":"InsufficientPayment","type":"error"},{"inputs":[],"name":"Invalid","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Locked","type":"error"},{"inputs":[],"name":"MintCap","type":"error"},{"inputs":[],"name":"MintClosed","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotAligned","type":"error"},{"inputs":[],"name":"NotApprovedContract","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NotLocked","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"NothingToClaim","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"RoyaltiesDisabled","type":"error"},{"inputs":[],"name":"RoyaltyOverflow","type":"error"},{"inputs":[],"name":"RoyaltyReceiverIsZeroAddress","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URILocked","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"minAllocation","type":"uint16"},{"indexed":true,"internalType":"uint16","name":"maxAllocation","type":"uint16"}],"name":"AlignmentUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address[]","name":"blacklistedAssets","type":"address[]"},{"indexed":true,"internalType":"bool","name":"status","type":"bool"}],"name":"BlacklistUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"uri","type":"string"}],"name":"ContractMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"indexed":true,"internalType":"uint8","name":"listId","type":"uint8"},{"indexed":true,"internalType":"uint40","name":"amount","type":"uint40"}],"name":"CustomMintConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"listId","type":"uint8"}],"name":"CustomMintDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"listId","type":"uint8"}],"name":"CustomMintDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"listId","type":"uint8"},{"indexed":true,"internalType":"uint40","name":"claimable","type":"uint40"}],"name":"CustomMintReenabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"listId","type":"uint8"},{"indexed":true,"internalType":"uint80","name":"price","type":"uint80"}],"name":"CustomMintRepriced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[],"name":"MintOpen","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint80","name":"price","type":"uint80"}],"name":"PriceUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"referral","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ReferralFeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"referralFee","type":"uint16"}],"name":"ReferralFeeUpdate","type":"event"},{"anonymous":false,"inputs":[],"name":"RoyaltyDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"uint96","name":"royaltyFee","type":"uint96"}],"name":"RoyaltyUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint40","name":"supply","type":"uint40"}],"name":"SupplyUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"approvedContract","type":"address"}],"name":"TokenLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"approvedContract","type":"address"}],"name":"TokenUnlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[],"name":"URILock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"alignmentVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"lockingContract","type":"address"}],"name":"approvedContract","outputs":[{"internalType":"bool","name":"status","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint8","name":"listId","type":"uint8"}],"name":"customClaims","outputs":[{"internalType":"uint256","name":"claimed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"uint8","name":"listId","type":"uint8"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint40","name":"amount","type":"uint40"},{"internalType":"address","name":"referral","type":"address"}],"name":"customMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint8","name":"listId","type":"uint8"}],"name":"customMintData","outputs":[{"internalType":"bytes32","name":"root","type":"bytes32"},{"internalType":"uint40","name":"issued","type":"uint40"},{"internalType":"uint40","name":"claimable","type":"uint40"},{"internalType":"uint40","name":"supply","type":"uint40"},{"internalType":"uint80","name":"price","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint40","name":"newMaxSupply","type":"uint40"}],"name":"decreaseSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"listId","type":"uint8"}],"name":"disableCustomMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disableInitializers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disableRoyalties","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"lockingContract","type":"address"}],"name":"freeId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBlacklist","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCustomMintListIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"newMinAllocation","type":"uint16"},{"internalType":"uint16","name":"newMaxAllocation","type":"uint16"}],"name":"increaseAlignment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"string","name":"baseURI_","type":"string"},{"internalType":"uint40","name":"_maxSupply","type":"uint40"},{"internalType":"uint16","name":"_royalty","type":"uint16"},{"internalType":"uint16","name":"_allocation","type":"uint16"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_alignedNft","type":"address"},{"internalType":"uint80","name":"_price","type":"uint80"},{"internalType":"uint96","name":"_vaultId","type":"uint96"},{"internalType":"bytes32","name":"_salt","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isUnlocked","outputs":[{"internalType":"bool","name":"status","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"lockCount","outputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"lockId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"lockIndex","type":"uint256"}],"name":"lockMap","outputs":[{"internalType":"address","name":"lockingContract","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"lockingContract","type":"address"}],"name":"lockMapIndex","outputs":[{"internalType":"uint256","name":"lockIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxAllocation","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minAllocation","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"referral","type":"address"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"referral","type":"address"},{"internalType":"uint16","name":"allocation","type":"uint16"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint16","name":"allocation","type":"uint16"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mintOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"miyaMints","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"listId","type":"uint8"}],"name":"nukeCustomMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"openMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint80","name":"","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"listId","type":"uint8"},{"internalType":"uint40","name":"_claimable","type":"uint40"}],"name":"reenableCustomMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"referralFee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint8","name":"listId","type":"uint8"},{"internalType":"uint80","name":"newPrice","type":"uint80"}],"name":"repriceCustomMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"rescueERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"rescueERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","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":"payable","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":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"isApproved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newBaseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"blacklistedAssets","type":"address[]"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_root","type":"bytes32"},{"internalType":"uint8","name":"listId","type":"uint8"},{"internalType":"uint40","name":"amount","type":"uint40"},{"internalType":"uint40","name":"_claimable","type":"uint40"},{"internalType":"uint80","name":"newPrice","type":"uint80"}],"name":"setCustomMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint80","name":"newPrice","type":"uint80"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newReferralFee","type":"uint16"}],"name":"setReferralFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint96","name":"royaltyFee","type":"uint96"}],"name":"setRoyalties","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint96","name":"royaltyFee","type":"uint96"}],"name":"setRoyaltiesForId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"unlockId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"contracts","type":"address[]"},{"internalType":"bool[]","name":"values","type":"bool[]"}],"name":"updateApprovedContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uriLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040526200000e62000014565b62000078565b63409feecd1980546001811615620000345763f92ee8a96000526004601cfd5b8160c01c808260011c1462000073578060011b8355806020527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602080a15b505050565b61592280620000886000396000f3fe60806040526004361061044b5760003560e01c80636352211e11610234578063a78a04a41161012e578063c87b56dd116100b6578063e9be457f1161007a578063e9be457f14610e16578063ed86997814610e29578063f04e283e14610e49578063f2fde38b14610e5c578063fee81cf414610e6f5761045a565b8063c87b56dd14610d48578063d5abeb0114610d68578063d8a06f7314610da3578063e8a3d48514610dcb578063e985e9c514610de05761045a565b8063bce6d672116100fd578063bce6d67214610cb3578063c107532914610cc8578063c21b471b14610ce8578063c42fe71814610d08578063c7488e7614610d285761045a565b8063a78a04a414610c30578063ac52e64414610c50578063b1a6505f14610c70578063b88d4fde14610ca05761045a565b80638da5cb5b116101bc5780639b3ba79f116101805780639b3ba79f14610b7a578063a035b1fe14610b9c578063a0712d6814610bdb578063a2076b6f14610bee578063a22cb46514610c105761045a565b80638da5cb5b14610a795780638e021c0614610a92578063940fe26314610aa757806394d216d614610b4557806395d89b4114610b655761045a565b806370a082311161020357806370a08231146109ce578063715018a6146109ee57806372abc8b7146109f65780637df325e114610a2457806384ae2bc614610a445761045a565b80636352211e1461094c578063650b00f61461096c57806365252d2e146109995780636c0360eb146109b95761045a565b80632569296211610345578063338d6c30116102cd578063536226ec11610291578063536226ec146108ac57806354d1f13d146108e457806355f804b3146108ec5780635d799f871461090c578063600041a01461092c5761045a565b8063338d6c301461082f57806340a9c8df1461085157806340c10f191461087157806342842e0e146108845780634a355d7f146108975761045a565b80632cba8123116103145780632cba8123146107935780632f6196b7146107d457806330bacb04146107e75780633167611f1461080757806331f449001461081a5761045a565b8063256929621461070c578063269ff7a3146107145780632799cde0146107345780632a55205a146107545761045a565b80630d4d1513116103d357806318160ddd1161039757806318160ddd146106885780631f87f764146106a457806320c5ab6a146106b757806323b872dd146106d857806324bbd049146106eb5761045a565b80630d4d1513146105f45780630e85d1e3146106075780630ec78173146106275780631249c58b14610647578063150b7a021461064f5761045a565b8063090cf73f1161041a578063090cf73f1461053957806309308e5d14610559578063095ea7b31461059f5780630ac27656146105b25780630b8c7e4f146105d25761045a565b806301ffc9a71461048a5780630218d5ef146104bf57806306fdde03146104df578063081812fc146105015761045a565b3661045a57610458610ea2565b005b600b5436806000803760008082600034865af19150508061047f573d6000803e3d6000fd5b503d6000803e3d6000f35b34801561049657600080fd5b506104aa6104a5366004614b3b565b611018565b60405190151581526020015b60405180910390f35b3480156104cb57600080fd5b506104586104da366004614b8d565b611047565b3480156104eb57600080fd5b506104f46110e7565b6040516104b69190614be4565b34801561050d57600080fd5b5061052161051c366004614c17565b611179565b6040516001600160a01b0390911681526020016104b6565b34801561054557600080fd5b50610458610554366004614c45565b6111b8565b34801561056557600080fd5b50610591610574366004614cc3565b600360209081526000928352604080842090915290825290205481565b6040519081526020016104b6565b6104586105ad366004614cf3565b611448565b3480156105be57600080fd5b506104586105cd366004614d31565b611453565b3480156105de57600080fd5b506105e76115b8565b6040516104b69190614d5b565b610458610602366004614d9f565b6115c9565b34801561061357600080fd5b50610458610622366004614e41565b6116f3565b34801561063357600080fd5b50610458610642366004614f05565b6117bd565b61045861183f565b34801561065b57600080fd5b5061066f61066a366004614f20565b6118fe565b6040516001600160e01b031990911681526020016104b6565b34801561069457600080fd5b50600a5464ffffffffff16610591565b6104586106b2366004615046565b611a27565b3480156106c357600080fd5b50600a546104aa90600160d01b900460ff1681565b6104586106e6366004615151565b611d03565b3480156106f757600080fd5b50600a546104aa90600160d81b900460ff1681565b610458611d48565b34801561072057600080fd5b5061045861072f366004615192565b611d98565b34801561074057600080fd5b5061045861074f366004614c17565b611dfb565b34801561076057600080fd5b5061077461076f3660046151ad565b611e2a565b604080516001600160a01b0390931683526020830191909152016104b6565b34801561079f57600080fd5b506105216107ae3660046151ad565b60026020908152600092835260408084209091529082529020546001600160a01b031681565b6104586107e23660046151cf565b611e7f565b3480156107f357600080fd5b50610458610802366004615220565b611f9a565b61045861081536600461525e565b6120a5565b34801561082657600080fd5b50610458612160565b34801561083b57600080fd5b50610844612168565b6040516104b69190615293565b34801561085d57600080fd5b5061045861086c366004614c17565b612174565b61045861087f366004614cf3565b6121a3565b610458610892366004615151565b612268565b3480156108a357600080fd5b506104586122a3565b3480156108b857600080fd5b506105916108c73660046152d4565b600d60209081526000928352604080842090915290825290205481565b61045861231c565b3480156108f857600080fd5b50610458610907366004615300565b612358565b34801561091857600080fd5b5061045861092736600461533d565b6123d9565b34801561093857600080fd5b50600e54610521906001600160a01b031681565b34801561095857600080fd5b50610521610967366004614c17565b61258a565b34801561097857600080fd5b50610591610987366004614c17565b60016020526000908152604090205481565b3480156109a557600080fd5b506104586109b4366004614f05565b6125c8565b3480156109c557600080fd5b506104f46127cf565b3480156109da57600080fd5b506105916109e936600461536b565b6127de565b610458612819565b348015610a0257600080fd5b506104aa610a11366004614c17565b6000908152600160205260409020541590565b348015610a3057600080fd5b50610458610a3f366004615151565b61282b565b348015610a5057600080fd5b50600a54610a6690600160c01b900461ffff1681565b60405161ffff90911681526020016104b6565b348015610a8557600080fd5b50638b78c6d81954610521565b348015610a9e57600080fd5b5061045861296f565b348015610ab357600080fd5b50610b08610ac2366004614f05565b600c602052600090815260409020805460019091015464ffffffffff80821691600160281b8104821691600160501b82041690600160781b90046001600160501b031685565b6040805195865264ffffffffff94851660208701529284169285019290925290911660608301526001600160501b0316608082015260a0016104b6565b348015610b5157600080fd5b50610458610b60366004614cc3565b6129b5565b348015610b7157600080fd5b506104f46129e5565b348015610b8657600080fd5b50600a54610a6690600160b01b900461ffff1681565b348015610ba857600080fd5b50600a54610bc390600160281b90046001600160501b031681565b6040516001600160501b0390911681526020016104b6565b610458610be9366004614c17565b6129f4565b348015610bfa57600080fd5b50600a54610a6690600160a01b900461ffff1681565b348015610c1c57600080fd5b50610458610c2b366004615388565b612ab9565b348015610c3c57600080fd5b50600b54610521906001600160a01b031681565b348015610c5c57600080fd5b50610458610c6b366004615402565b612b0f565b348015610c7c57600080fd5b506104aa610c8b36600461536b565b60006020819052908152604090205460ff1681565b610458610cae366004614f20565b612bc3565b348015610cbf57600080fd5b50610458612c00565b348015610cd457600080fd5b50610458610ce3366004614cf3565b612c46565b348015610cf457600080fd5b50610458610d0336600461546e565b612dd1565b348015610d1457600080fd5b50610458610d2336600461549a565b612e99565b348015610d3457600080fd5b50610458610d433660046154b5565b612f2f565b348015610d5457600080fd5b506104f4610d63366004614c17565b613000565b348015610d7457600080fd5b50600a54610d8d90600160781b900464ffffffffff1681565b60405164ffffffffff90911681526020016104b6565b348015610daf57600080fd5b5061052173e3d5e8e972291bdbda57159481028a77fb8f055a81565b348015610dd757600080fd5b506104f4613084565b348015610dec57600080fd5b506104aa610dfb36600461533d565b601c52670a5a2e7a000000006008526000526030600c205490565b610458610e243660046154df565b61313f565b348015610e3557600080fd5b50610458610e4436600461556a565b6133ef565b610458610e5736600461536b565b613499565b610458610e6a36600461536b565b6134d6565b348015610e7b57600080fd5b50610591610e8a36600461536b565b63389a75e1600c908152600091909152602090205490565b600a54600160d81b900460ff1615610ed957600a54610ed790339061087f90600160281b90046001600160501b0316346155b1565b565b600a54600090610ef790600160a01b900461ffff1634612710613566565b600b546040519192506001600160a01b0316908290600081818185875af1925050503d8060008114610f45576040519150601f19603f3d011682016040523d82523d6000602084013e610f4a565b606091505b5050506000610f5c638b78c6d8195490565b6001600160a01b0316610f6f83346155c5565b604051600081818185875af1925050503d8060008114610fab576040519150601f19603f3d011682016040523d82523d6000602084013e610fb0565b606091505b505090508061101457600b546001600160a01b0316610fcf83346155c5565b604051600081818185875af1925050503d806000811461100b576040519150601f19603f3d011682016040523d82523d6000602084013e611010565b606091505b5050505b5050565b600061102382613594565b806110415750632a55205a60e083901c9081146301ffc9a791909114175b92915050565b61104f6135d6565b61105d600560ff84166135f1565b61107a57604051636dac6a0960e01b815260040160405180910390fd5b60ff82166000818152600c6020526040808220600101805469ffffffffffffffffffff60781b1916600160781b6001600160501b0387169081029190911790915590519092917f4e1d7becfe51ce8dcac99513c8c126636b0f047eddb6b70bab881b0c4f93e1ff91a35050565b6060600680546110f6906155d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611122906155d8565b801561116f5780601f106111445761010080835404028352916020019161116f565b820191906000526020600020905b81548152906001019060200180831161115257829003601f168201915b5050505050905090565b600081600052673ec412a9852d173d60c11b601c52602060002082018201805460601b6111ae5763ceea21b66000526004601cfd5b6001015492915050565b6111c06135d6565b6111ce600560ff86166135f1565b6111e2576111e0600560ff86166135fd565b505b60ff84166000908152600c6020908152604091829020825160a0810184528154815260019091015464ffffffffff808216938301849052600160281b8204811694830194909452600160501b81049093166060820152600160781b9092046001600160501b031660808301521580159061127c57508364ffffffffff16816060015182602001516112739190615612565b64ffffffffff16115b1561129a57604051636dac6a0960e01b815260040160405180910390fd5b6000816020015164ffffffffff166000036112b65750836112f3565b816020015164ffffffffff168564ffffffffff1610156112e257848260200151038260600151036112f0565b816020015185038260600151015b90505b6040518060a001604052808881526020018664ffffffffff1681526020018564ffffffffff1681526020018264ffffffffff168152602001846001600160501b0316815250600c60008860ff1660ff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548164ffffffffff021916908364ffffffffff16021790555060408201518160010160056101000a81548164ffffffffff021916908364ffffffffff160217905550606082015181600101600a6101000a81548164ffffffffff021916908364ffffffffff160217905550608082015181600101600f6101000a8154816001600160501b0302191690836001600160501b031602179055509050508464ffffffffff168660ff16887fbdcecaf53f2dfa3319a5ddf57b4fa9aa4775994b334019cfd8a1ff730e1d23b560405160405180910390a450505050505050565b611014338383613609565b61145b6135d6565b600a5461ffff600160a01b909104811690821681111561148e57604051636dac6a0960e01b815260040160405180910390fd5b600a54612710906114aa90600160c01b900461ffff1684615630565b61ffff1611156114cd57604051636dac6a0960e01b815260040160405180910390fd5b600a546114ea90600290600160781b900464ffffffffff1661564b565b64ffffffffff16611501600a5464ffffffffff1690565b1015611561578061ffff168361ffff16108061152457508161ffff168361ffff16115b1561154257604051636dac6a0960e01b815260040160405180910390fd5b600a805461ffff60a01b1916600160a01b61ffff861602179055611565565b8092505b600a805461ffff60b01b1916600160b01b61ffff85811691820292909217909255604051908516907f651dcfc39d95235af566f8d017566d15d6d368b7df40b5b9f99c0300a5084a8190600090a3505050565b60606115c460056136aa565b905090565b600a548290600160d81b900460ff166115f55760405163589ed34b60e01b815260040160405180910390fd5b600a5464ffffffffff600160781b82048116916116149184911661566f565b111561163357604051635eddbf3560e11b815260040160405180910390fd5b3068929eee149b4bd2126854036116525763ab143c066000526004601cfd5b3068929eee149b4bd2126855336001600160a01b0383160361168757604051636dac6a0960e01b815260040160405180910390fd5b600a546116a5908490600160281b90046001600160501b0316615682565b3410156116c55760405163cd1c886760e01b815260040160405180910390fd5b6116e1848484600a60149054906101000a900461ffff166136bb565b3868929eee149b4bd212685550505050565b6116fb6135d6565b60005b82518110156117775781156117405761173a83828151811061172257611722615699565b602002602001015160046138ec90919063ffffffff16565b5061176f565b61176d83828151811061175557611755615699565b60200260200101516004613a3c90919063ffffffff16565b505b6001016116fe565b508015158260405161178991906156af565b604051908190038120907fee9d89892c5dcf46d5666e29b34f4c774422b5f43f738b564b85938b6ede416490600090a35050565b6117c56135d6565b6117d3600560ff83166135f1565b6117f057604051636dac6a0960e01b815260040160405180910390fd5b60ff81166000818152600c6020526040808220600101805469ffffffffff000000000019169055517fa2981e359ad98af46ff4183dd23efb45ca30069367c61b7cc1bd485f6c62f6ac9190a250565b600a54600190600160d81b900460ff1661186c5760405163589ed34b60e01b815260040160405180910390fd5b600a5464ffffffffff600160781b820481169161188b9184911661566f565b11156118aa57604051635eddbf3560e11b815260040160405180910390fd5b600a54600160281b90046001600160501b03163410156118dd5760405163cd1c886760e01b815260040160405180910390fd5b6118fb3360016000600a60149054906101000a900461ffff166136bb565b50565b600080600b60009054906101000a90046001600160a01b03166001600160a01b031663b13eb2cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611954573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197891906156ee565b90506001600160a01b03811633036119fb57600b54604051632142170760e11b81523060048201526001600160a01b03918216602482015260448101879052908216906342842e0e90606401600060405180830381600087803b1580156119de57600080fd5b505af11580156119f2573d6000803e3d6000fd5b50505050611a14565b604051638fcc34bd60e01b815260040160405180910390fd5b50630a85bd0160e11b9695505050505050565b63409feecd198054600382558015611a5e5760018160011c14303b10611a555763f92ee8a96000526004601cfd5b818160ff1b1b91505b506101f48761ffff161015611a8657604051638fcc34bd60e01b815260040160405180910390fd5b61271061ffff88161180611a9f57506103e861ffff8916115b15611abd57604051636dac6a0960e01b815260040160405180910390fd5b600a805463ffffffff60a01b1916600160a01b61ffff8a811691820261ffff60b01b191692909217600160b01b9190910217909155611b029060009088908b16613b86565b611b10868961ffff16613be0565b611b1986613c2b565b6006611b258d82615753565b506007611b328c82615753565b506008611b3f8b82615753565b50600a805473ffffffffffffffffffffffffffffff00000000001916600160781b64ffffffffff8c16026effffffffffffffffffff0000000000191617600160281b6001600160501b03871602179055600e8054336001600160a01b0319909116811790915560405162bf4f1f60e71b81526001600160a01b03871660048201526001600160601b03851660248201526044810184905260009190635fa78f80906064016020604051808303816000875af1158015611c02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2691906156ee565b600b80546001600160a01b0319166001600160a01b03831617905590503415611cbf576000816001600160a01b03163460405160006040518083038185875af1925050503d8060008114611c96576040519150601f19603f3d011682016040523d82523d6000602084013e611c9b565b606091505b5050905080611cbd576040516312171d8360e31b815260040160405180910390fd5b505b508015611cf5576002815560016020527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602080a15b505050505050505050505050565b60008181526001602052604090205415611d385760405163032bc66b60e01b8152600481018290526024015b60405180910390fd5b611d43838383613c67565b505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b611da06135d6565b600a80546effffffffffffffffffff00000000001916600160281b6001600160501b038416908102919091179091556040517fdaf1ed0e2ffd4362000735d64121408550f2fcee174e71d85d9498c7aa8ada3290600090a250565b611e0481613d67565b611e215760405163677510db60e11b815260040160405180910390fd5b6118fb81613d8b565b600082815268aa4ec00224afccfdb76020526040812054606081901c91906127109083611e5e576020515490508060601c93505b606084901b1884600019829004811182023d3d3e9396930204935090915050565b600a548390600160d81b900460ff16611eab5760405163589ed34b60e01b815260040160405180910390fd5b600a5464ffffffffff600160781b8204811691611eca9184911661566f565b1115611ee957604051635eddbf3560e11b815260040160405180910390fd5b3068929eee149b4bd212685403611f085763ab143c066000526004601cfd5b3068929eee149b4bd2126855336001600160a01b03841603611f3d57604051636dac6a0960e01b815260040160405180910390fd5b600a54611f5b908590600160281b90046001600160501b0316615682565b341015611f7b5760405163cd1c886760e01b815260040160405180910390fd5b611f87858585856136bb565b3868929eee149b4bd21268555050505050565b611fa26135d6565b6103e86001600160601b0382161115611fce57604051636dac6a0960e01b815260040160405180910390fd5b6000611fdb600080611e2a565b5090506001600160a01b0381166120055760405163adc7931960e01b815260040160405180910390fd5b8360000361202657604051636dac6a0960e01b815260040160405180910390fd5b816001600160601b031660000361205357600084815268aa4ec00224afccfdb7602052604081205561205e565b61205e848484613b86565b816001600160601b0316836001600160a01b0316857f5bb0fa5bb0ca1f6fc0bea8341d9bbe9415797f17ca5e32a71c7901649671c24060405160405180910390a450505050565b600a548290600160d81b900460ff166120d15760405163589ed34b60e01b815260040160405180910390fd5b600a5464ffffffffff600160781b82048116916120f09184911661566f565b111561210f57604051635eddbf3560e11b815260040160405180910390fd5b600a5461212d908490600160281b90046001600160501b0316615682565b34101561214d5760405163cd1c886760e01b815260040160405180910390fd5b61215a84846000856136bb565b50505050565b610ed7613e78565b60606115c46004613ed9565b61217d81613d67565b61219a5760405163677510db60e11b815260040160405180910390fd5b6118fb81613fae565b600a548190600160d81b900460ff166121cf5760405163589ed34b60e01b815260040160405180910390fd5b600a5464ffffffffff600160781b82048116916121ee9184911661566f565b111561220d57604051635eddbf3560e11b815260040160405180910390fd5b600a5461222b908390600160281b90046001600160501b0316615682565b34101561224b5760405163cd1c886760e01b815260040160405180910390fd5b611d4383836000600a60149054906101000a900461ffff166136bb565b600081815260016020526040902054156122985760405163032bc66b60e01b815260048101829052602401611d2f565b611d43838383614116565b6122ab6135d6565b6122bd600068aa4ec00224afccfdb755565b600080805268aa4ec00224afccfdb76020527f913817da311d664dd3395c9b93b1f96a4af2b60ec505387b3ac50cc4468f3488556040517f2c57531944d96595a8b3fba36d50130b4cb6f0316fb235c386966db8f2dfbefa90600090a1565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b6123606135d6565b600a54600160d01b900460ff161561238b576040516331d1c0a360e01b815260040160405180910390fd5b60086123978282615753565b50600a54604051600160781b90910464ffffffffff16906000907f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c908290a350565b6123e16135d6565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015612428573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061244c9190615813565b9050600b60009054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124c591906156ee565b6001600160a01b0316836001600160a01b03160361255557600b5460405163a9059cbb60e01b81526001600160a01b039182166004820152602481018390529084169063a9059cbb906044015b6020604051808303816000875af1158015612531573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215a919061582c565b60405163a9059cbb60e01b81526001600160a01b0383811660048301526024820183905284169063a9059cbb90604401612512565b6000818152673ec412a9852d173d60c11b601c526020902081018101546001600160a01b0316806125c35763ceea21b66000526004601cfd5b919050565b6125d06135d6565b60ff81166000908152600c6020908152604091829020825160a0810184528154815260019091015464ffffffffff808216938301849052600160281b8204811694830194909452600160501b810490931660608201819052600160781b9093046001600160501b031660808201529190036126b857612653600560ff84166135f1565b1561266857612666600560ff8416614143565b505b60ff82166000818152600c602052604080822082815560010180546001600160c81b0319169055517f2f72de1149aa0f409dc1831d65c303890971a4f5cd249516c47f8a279d7280a69190a25050565b6040518060a0016040528060008019168152602001826060015183602001516126e19190615612565b64ffffffffff9081168252600060208084018290526040808501839052606094850183905260ff8816808452600c835281842087518155928701516001909301805488840151978901516080909901516001600160501b0316600160781b0269ffffffffffffffffffff60781b19998816600160501b02999099166effffffffffffffffffffffffffffff60501b19988816600160281b0269ffffffffffffffffffff199092169590971694909417939093179590951693909317949094179093555182907fbdcecaf53f2dfa3319a5ddf57b4fa9aa4775994b334019cfd8a1ff730e1d23b5908290a45050565b6060600880546110f6906155d8565b6000816127f357638f4eb6046000526004601cfd5b673ec412a9852d173d60c11b601c528160005263ffffffff601c600c2054169050919050565b6128216135d6565b610ed7600061414f565b6128336135d6565b600b60009054906101000a90046001600160a01b03166001600160a01b031663b13eb2cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612886573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128aa91906156ee565b6001600160a01b0316836001600160a01b03160361293457600b54604051632142170760e11b81523060048201526001600160a01b03918216602482015260448101839052908416906342842e0e906064015b600060405180830381600087803b15801561291757600080fd5b505af115801561292b573d6000803e3d6000fd5b50505050505050565b6040516323b872dd60e01b81523060048201526001600160a01b038381166024830152604482018390528416906323b872dd906064016128fd565b6129776135d6565b600a805460ff60d01b1916600160d01b1790556040517fc8110264427cd578eaa021ca580e278f71edd94d3f61344a5727777cb5e07afc90600090a1565b6129be82613d67565b6129db5760405163677510db60e11b815260040160405180910390fd5b611014828261418d565b6060600780546110f6906155d8565b600a548190600160d81b900460ff16612a205760405163589ed34b60e01b815260040160405180910390fd5b600a5464ffffffffff600160781b8204811691612a3f9184911661566f565b1115612a5e57604051635eddbf3560e11b815260040160405180910390fd5b600a54612a7c908390600160281b90046001600160501b0316615682565b341015612a9c5760405163cd1c886760e01b815260040160405180910390fd5b61101433836000600a60149054906101000a900461ffff166136bb565b801515905081601c52670a5a2e7a0000000060085233600052806030600c2055806000528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a35050565b612b176135d6565b828114612b375760405163512509d360e11b815260040160405180910390fd5b60005b8381101561101057828282818110612b5457612b54615699565b9050602002016020810190612b699190615849565b600080878785818110612b7e57612b7e615699565b9050602002016020810190612b93919061536b565b6001600160a01b031681526020810191909152604001600020805460ff1916911515919091179055600101612b3a565b60008381526001602052604090205415612bf35760405163032bc66b60e01b815260048101849052602401611d2f565b6110108585858585614312565b612c086135d6565b600a805460ff60d81b1916600160d81b1790556040517f8c2245a4c9f0d7f9de9599f098a52451fff46c9be8d4b39e14120ae514b8797f90600090a1565b3068929eee149b4bd212685403612c655763ab143c066000526004601cfd5b3068929eee149b4bd21268556000612c80638b78c6d8195490565b9050476001600160a01b038416612caa57604051636dac6a0960e01b815260040160405180910390fd5b6001600160a01b03821615801590612ccb57506001600160a01b0382163314155b15612ce8576040516282b42960e81b815260040160405180910390fd5b6001600160a01b038216612d0857600b546001600160a01b031693509150815b80831115612d14578092505b6000846001600160a01b03168460405160006040518083038185875af1925050503d8060008114612d61576040519150601f19603f3d011682016040523d82523d6000602084013e612d66565b606091505b5050905080612d88576040516312171d8360e31b815260040160405180910390fd5b60405184906001600160a01b038716907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436490600090a35050503868929eee149b4bd21268555050565b612dd96135d6565b6103e86001600160601b0382161115612e0557604051636dac6a0960e01b815260040160405180910390fd5b6000612e12600080611e2a565b5090506001600160a01b038116612e3c5760405163adc7931960e01b815260040160405180910390fd5b612e4860008484613b86565b612e528383613be0565b816001600160601b0316836001600160a01b031660007f5bb0fa5bb0ca1f6fc0bea8341d9bbe9415797f17ca5e32a71c7901649671c24060405160405180910390a4505050565b612ea16135d6565b600a54612ebb90600160b01b900461ffff16612710615866565b61ffff168161ffff161115612ee357604051636dac6a0960e01b815260040160405180910390fd5b600a805461ffff60c01b1916600160c01b61ffff8416908102919091179091556040517f86d4ccf683b2dc5a92d3b3a8e1c54b8452b39a7aee12580a63a24689d5783d9390600090a250565b612f376135d6565b612f45600560ff84166135f1565b612f6257604051636dac6a0960e01b815260040160405180910390fd5b60ff82166000908152600c602052604081206001015464ffffffffff90811691908316821015612f925781612f94565b825b60ff85166000818152600c6020526040808220600101805469ffffffffff00000000001916600160281b64ffffffffff8716908102919091179091559051939450927f1dac9586e26a9cef0cd6c48d38d5ef12911d811fe74284267653c54c687ef32b9190a350505050565b606061300b82613d67565b6130285760405163677510db60e11b815260040160405180910390fd5b60006130326127cf565b90506000815111613052576040518060200160405280600081525061307d565b8061305c84614366565b60405160200161306d929190615881565b6040516020818303038152906040525b9392505050565b60606115c460088054613096906155d8565b80601f01602080910402602001604051908101604052809291908181526020018280546130c2906155d8565b801561310f5780601f106130e45761010080835404028352916020019161310f565b820191906000526020600020905b8154815290600101906020018083116130f257829003601f168201915b50505050506040518060400160405280600d81526020016c31b7b73a3930b1ba173539b7b760991b8152506143aa565b600a5464ffffffffff831690600160d81b900460ff166131725760405163589ed34b60e01b815260040160405180910390fd5b600a5464ffffffffff600160781b82048116916131919184911661566f565b11156131b057604051635eddbf3560e11b815260040160405180910390fd5b3068929eee149b4bd2126854036131cf5763ab143c066000526004601cfd5b3068929eee149b4bd21268556131e9600560ff87166135f1565b61320657604051636dac6a0960e01b815260040160405180910390fd5b60ff85166000908152600c60205260409020600181015464ffffffffff600160501b9091048116908516111561324f57604051635eddbf3560e11b815260040160405180910390fd5b6001810154336000908152600d6020908152604080832060ff8b16845290915290205464ffffffffff600160281b909204821691613290919087169061566f565b11156132af5760405163fd41fb5360e01b815260040160405180910390fd5b60018101546132d590600160781b90046001600160501b031664ffffffffff86166158b0565b6001600160501b03163410156132fe5760405163cd1c886760e01b815260040160405180910390fd5b6040516bffffffffffffffffffffffff193360601b1660208201526000906034016040516020818303038152906040528051906020012090506133478989846000015484614405565b613364576040516312d37ee560e31b815260040160405180910390fd5b336000908152600d6020908152604080832060ff8b1684529091529020805464ffffffffff87811691820190925560018401805464ffffffffff60501b198116600160501b9182900485168a90039094160292909217909155600a546133d89188918790600160a01b900461ffff166136bb565b50503868929eee149b4bd212685550505050505050565b6133f76135d6565b600a5464ffffffffff600160781b90910481169082161015806134295750600a5464ffffffffff168164ffffffffff16105b1561344757604051636dac6a0960e01b815260040160405180910390fd5b600a805464ffffffffff60781b1916600160781b64ffffffffff8416908102919091179091556040517f7aebd4bde0b5cd06faa86c1ac30854673d54252838e89d9f9d1406fab507334890600090a250565b6134a16135d6565b63389a75e1600c52806000526020600c2080544211156134c957636f5e88186000526004601cfd5b600090556118fb8161414f565b6134de6135d6565b600e546001600160a01b0316635d92051b6134fc638b78c6d8195490565b6040516001600160e01b031960e084901b1681526001600160a01b0391821660048201529084166024820152604401600060405180830381600087803b15801561354557600080fd5b505af1158015613559573d6000803e3d6000fd5b505050506118fb8161443f565b6000613573848484614466565b9050818385091561307d576001018061307d5763ae47f7026000526004601cfd5b60006001600160e01b0319821663706e848960e01b14806110415750611041826301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b638b78c6d819543314610ed7576382b429006000526004601cfd5b600061307d8383614506565b600061307d8383614593565b60001960601c828116925083811693508160005283673ec412a9852d173d60c11b17601c52602060002082018201805482169150816136505763ceea21b66000526004601cfd5b81851485151761367657816000526030600c205461367657634b6e7f186000526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600038a450505050565b60606110416136b8836146ae565b90565b6001600160a01b03841615806136cf575082155b156136ed57604051636dac6a0960e01b815260040160405180910390fd5b6136f73385614769565b600a5461ffff600160a01b909104811690821610806137265750600a5461ffff600160b01b9091048116908216115b1561374457604051636dac6a0960e01b815260040160405180910390fd5b600061375761ffff831634612710613566565b9050341561389057600b546040516001600160a01b03909116908290600081818185875af1925050503d80600081146137ac576040519150601f19603f3d011682016040523d82523d6000602084013e6137b1565b606091505b5050506001600160a01b0383161561389057600a546000906137e190600160c01b900461ffff16346127106148c8565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114613830576040519150601f19603f3d011682016040523d82523d6000602084013e613835565b606091505b5050905080613857576040516312171d8360e31b815260040160405180910390fd5b60405182906001600160a01b038716907f339143a0e6309caafa5c4c55cd7b75d2e49115ce1e88b394e3376814b8507c1590600090a350505b600a5464ffffffffff1660005b858110156138c2576138ba876138b2846158d3565b9350836148f7565b60010161389d565b5050600a805464ffffffffff19811664ffffffffff91821696909601169490941790935550505050565b63978aab926004526000828152602481206001600160a01b03929092169168fbb67fda52d4bfb8be1983016139295763f5a267f16000526004601cfd5b8261393b5768fbb67fda52d4bfb8bf92505b80546001600160601b03811682602052806139fe578160601c80613969578560601b84556001945050613a33565b8581036139765750613a33565b600184015460601c80613997578660601b6001860155600195505050613a33565b8681036139a5575050613a33565b600285015460601c806139c7578760601b600287015560019650505050613a33565b8781036139d657505050613a33565b6000928352604080842060019055918352818320600290558252902060039055506007908117905b8460005260406000208054613a31578160011c91508560601b828501558160010181558260020184556001945050613a33565b505b50505092915050565b63978aab926004526000828152602481206001600160a01b03929092169168fbb67fda52d4bfb8be198301613a795763f5a267f16000526004601cfd5b82613a8b5768fbb67fda52d4bfb8bf92505b80546001600160601b03811680613b095760019350848260601c03613ac457600183018054845560028401805490915560009055613a33565b84600184015460601c03613ae657600283018054600185015560009055613a33565b84600284015460601c03613b005760006002840155613a33565b60009350613a33565b82602052846000526040600020805480613b24575050613a33565b60018360011c039250826001820314613b5c578285015460601c8060601b600183038701556000848701558060005250806040600020555b5083546bffffffffffffffffffffffff1916600192831b1782179093556000909255509392505050565b6001600160601b031661271080821115613ba85763350a88b36000526004601cfd5b8260601b80613bbf5763b4457eaa6000526004601cfd5b8460005268aa4ec00224afccfdb76020528281176040600020555050505050565b6001600160601b031661271080821115613c025763350a88b36000526004601cfd5b8260601b80613c195763b4457eaa6000526004601cfd5b90911768aa4ec00224afccfdb7555050565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6000818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b039485169493841693811691908286148302613cb95767ceea21b6a1148100831560021b526004601cfd5b856000528160010154925082331486331417613ce7576030600c2054613ce757634b6e7f186000526004601cfd5b8215613cf557600082600101555b85851818905550601c600c8181208054600019019055600084905220805460010163ffffffff81168402613d385767ea553b3401336cea841560021b526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600038a4505050565b6000818152673ec412a9852d173d60c11b601c52602090208101015460601b151590565b3360009081526020819052604090205460ff16613dbb5760405163dde218bd60e01b815260040160405180910390fd5b600081815260036020908152604080832033845290915290205415613df3576040516317c3335f60e21b815260040160405180910390fd5b600081815260016020818152604080842080546002845282862090850180875290845282862080546001600160a01b03191633908117909155878752600385528387208188528552838720829055878752949093529190915551909183917f9ecfd70e9ff36df72989324a49559383d39f9290d700b10cf5ac10dcb68d26439190a350565b63409feecd1980546001811615613e975763f92ee8a96000526004601cfd5b8160c01c808260011c14611d43578060011b8355806020527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602080a1505050565b63978aab926004526000818152602481206060915068fbb67fda52d4bfb8bf81548060a01b60a01c6040519450846020018260601c9250838314158302815281613f68578215613f6357600191508185015460601c92508215613f63578284141590920260208301525060028381015460601c918215613f63576003915083831415830260408201525b613f98565b600191821c915b82811015613f96578581015460601c858114158102600583901b8401529350600101613f6f565b505b8186528160051b81016040525050505050919050565b3360009081526020819052604090205460ff16613fde5760405163dde218bd60e01b815260040160405180910390fd5b60008181526003602090815260408083203384529091528120549081900361401957604051631834e26560e01b815260040160405180910390fd5b60008281526001602052604090205481811461408f5760008381526002602090815260408083208484528252808320805486855282852080546001600160a01b03199081166001600160a01b039093169283179091558254169091558684526003835281842090845290915290208290556140b7565b6000838152600260209081526040808320858452909152902080546001600160a01b03191690555b6000838152600360209081526040808320338085529083528184208490558684526001909252808320805460001901905551909185917f0fe7d9801197f79ef3b1595d19379eb58f0fff5f98b0f6d6f34c03cae5306c379190a3505050565b614121838383611d03565b813b15611d4357611d4383838360405180602001604052806000815250614998565b600061307d8383614a24565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b6001600160a01b03811660009081526020819052604090205460ff16156141c7576040516303a179f960e31b815260040160405180910390fd5b60008281526003602090815260408083206001600160a01b03851684529091528120549081900361420b57604051631834e26560e01b815260040160405180910390fd5b6000838152600160205260409020548181146142815760008481526002602090815260408083208484528252808320805486855282852080546001600160a01b03199081166001600160a01b039093169283179091558254169091558784526003835281842090845290915290208290556142a9565b6000848152600260209081526040808320858452909152902080546001600160a01b03191690555b60008481526003602090815260408083206001600160a01b0387168085529083528184208490558784526001909252808320805460001901905551909186917f0fe7d9801197f79ef3b1595d19379eb58f0fff5f98b0f6d6f34c03cae5306c379190a350505050565b61431d858585611d03565b833b156110105761101085858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061499892505050565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a900480614381575050819003601f19909101908152919050565b6040518251601f19906020810182165b85810151848201528201806143ba575083518184018360208301165b86810151828201528401806143d65750506000910183810160208101929092528352603f011660405292915050565b60008315614437578360051b8501855b803580851160051b948552602094851852604060002093018181106144155750505b501492915050565b6144476135d6565b8060601b61445d57637448fbae6000526004601cfd5b6118fb8161414f565b8282026000198385098181108201900380614497578261448e5763ae47f7026000526004601cfd5b5081900461307d565b8083116144ac5763ae47f7026000526004601cfd5b82848609600084810385169485900494848311909303908390038390046001010292030417600260038302811880840282030280840282030280840282030280840282030280840282030280840290910302029392505050565b6318fb586460045260008281526024812068fbb67fda52d4bfb8bf83036145355763f5a267f16000526004601cfd5b826145475768fbb67fda52d4bfb8bf92505b80195461457957805460019250831461458c576001810154831461458c576002810154831461458c576000915061458c565b8060205282600052604060002054151591505b5092915050565b6318fb586460045260008281526024812068fbb67fda52d4bfb8bf83036145c25763f5a267f16000526004601cfd5b826145d45768fbb67fda52d4bfb8bf92505b8019548160205280614679578154806145f45784835560019350506146a6565b84810361460157506146a6565b60018301548061461c578560018501556001945050506146a6565b85810361462a5750506146a6565b60028401548061464657866002860155600195505050506146a6565b868103614655575050506146a6565b60009283526040808420600190559183528183206002905582529020600390555060075b8360005260406000208054613a3357600191821c8381018690558083019182905590821b82178319559092505b505092915050565b6318fb5864600452600081815260249020801954604051919068fbb67fda52d4bfb8bf90602084018161472857835480156147225780841415028152600184810154909250801561472257808414150260208201526002848101549092508015614722576003925083811415810260408301525b50614754565b8160011c915060005b8281101561475257848101548481141502600582901b830152600101614731565b505b8185528160051b810160405250505050919050565b60006147756004613ed9565b9050600060015b82518110156110105782818151811061479757614797615699565b60209081029190910101516040516370a0823160e01b81526001600160a01b038781166004830152909116906370a08231906024016020604051808303816000875af11580156147eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061480f9190615813565b8201915082818151811061482557614825615699565b60209081029190910101516040516370a0823160e01b81526001600160a01b038681166004830152909116906370a08231906024016020604051808303816000875af1158015614879573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061489d9190615813565b9091019081156148c0576040516309550c7760e01b815260040160405180910390fd5b60010161477c565b60008260001904841183021582026148e85763ad251c276000526004601cfd5b50910281810615159190040190565b8160601b60601c915080600052673ec412a9852d173d60c11b601c5260206000208101810180548060601b156149355763c991cbb16000526004601cfd5b831790556000829052601c600c20805460010163ffffffff8116840261496a5767ea553b3401336cea841560021b526004601cfd5b9055808260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8138a45050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a084015280156149df578060c08401826020870160045afa505b60208360a48301601c860160008a5af1614a02573d15614a02573d6000843e3d83fd5b508060e01b825114614a1c5763d1a57ed66000526004601cfd5b505050505050565b6318fb586460045260008281526024812068fbb67fda52d4bfb8bf8303614a535763f5a267f16000526004601cfd5b82614a655768fbb67fda52d4bfb8bf92505b80195480614ad2576001925083825403614a93576001820180548355600283018054909155600090556146a6565b83600183015403614ab2576002820180546001840155600090556146a6565b83600283015403614ac957600060028301556146a6565b600092506146a6565b81602052836000526040600020805480614aed5750506146a6565b60018360011c039250826001820314614b1f578284015480600183038601556000848601558060005250806040600020555b5060018260011b17831955600081555060019250505092915050565b600060208284031215614b4d57600080fd5b81356001600160e01b03198116811461307d57600080fd5b803560ff811681146125c357600080fd5b80356001600160501b03811681146125c357600080fd5b60008060408385031215614ba057600080fd5b614ba983614b65565b9150614bb760208401614b76565b90509250929050565b60005b83811015614bdb578181015183820152602001614bc3565b50506000910152565b6020815260008251806020840152614c03816040850160208701614bc0565b601f01601f19169190910160400192915050565b600060208284031215614c2957600080fd5b5035919050565b803564ffffffffff811681146125c357600080fd5b600080600080600060a08688031215614c5d57600080fd5b85359450614c6d60208701614b65565b9350614c7b60408701614c30565b9250614c8960608701614c30565b9150614c9760808701614b76565b90509295509295909350565b6001600160a01b03811681146118fb57600080fd5b80356125c381614ca3565b60008060408385031215614cd657600080fd5b823591506020830135614ce881614ca3565b809150509250929050565b60008060408385031215614d0657600080fd5b8235614d1181614ca3565b946020939093013593505050565b803561ffff811681146125c357600080fd5b60008060408385031215614d4457600080fd5b614d4d83614d1f565b9150614bb760208401614d1f565b6020808252825182820181905260009190848201906040850190845b81811015614d9357835183529284019291840191600101614d77565b50909695505050505050565b600080600060608486031215614db457600080fd5b8335614dbf81614ca3565b9250602084013591506040840135614dd681614ca3565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614e2057614e20614de1565b604052919050565b80151581146118fb57600080fd5b80356125c381614e28565b60008060408385031215614e5457600080fd5b823567ffffffffffffffff80821115614e6c57600080fd5b818501915085601f830112614e8057600080fd5b8135602082821115614e9457614e94614de1565b8160051b9250614ea5818401614df7565b8281529284018101928181019089851115614ebf57600080fd5b948201945b84861015614ee95785359350614ed984614ca3565b8382529482019490820190614ec4565b9650614ef89050878201614e36565b9450505050509250929050565b600060208284031215614f1757600080fd5b61307d82614b65565b600080600080600060808688031215614f3857600080fd5b8535614f4381614ca3565b94506020860135614f5381614ca3565b935060408601359250606086013567ffffffffffffffff80821115614f7757600080fd5b818801915088601f830112614f8b57600080fd5b813581811115614f9a57600080fd5b896020828501011115614fac57600080fd5b9699959850939650602001949392505050565b600082601f830112614fd057600080fd5b813567ffffffffffffffff811115614fea57614fea614de1565b614ffd601f8201601f1916602001614df7565b81815284602083860101111561501257600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160601b03811681146125c357600080fd5b60008060008060008060008060008060006101608c8e03121561506857600080fd5b67ffffffffffffffff808d35111561507f57600080fd5b61508c8e8e358f01614fbf565b9b508060208e0135111561509f57600080fd5b6150af8e60208f01358f01614fbf565b9a508060408e013511156150c257600080fd5b506150d38d60408e01358e01614fbf565b98506150e160608d01614c30565b97506150ef60808d01614d1f565b96506150fd60a08d01614d1f565b955061510b60c08d01614cb8565b945061511960e08d01614cb8565b93506151286101008d01614b76565b92506151376101208d0161502f565b91506101408c013590509295989b509295989b9093969950565b60008060006060848603121561516657600080fd5b833561517181614ca3565b9250602084013561518181614ca3565b929592945050506040919091013590565b6000602082840312156151a457600080fd5b61307d82614b76565b600080604083850312156151c057600080fd5b50508035926020909101359150565b600080600080608085870312156151e557600080fd5b84356151f081614ca3565b935060208501359250604085013561520781614ca3565b915061521560608601614d1f565b905092959194509250565b60008060006060848603121561523557600080fd5b83359250602084013561524781614ca3565b91506152556040850161502f565b90509250925092565b60008060006060848603121561527357600080fd5b833561527e81614ca3565b92506020840135915061525560408501614d1f565b6020808252825182820181905260009190848201906040850190845b81811015614d935783516001600160a01b0316835292840192918401916001016152af565b600080604083850312156152e757600080fd5b82356152f281614ca3565b9150614bb760208401614b65565b60006020828403121561531257600080fd5b813567ffffffffffffffff81111561532957600080fd5b61533584828501614fbf565b949350505050565b6000806040838503121561535057600080fd5b823561535b81614ca3565b91506020830135614ce881614ca3565b60006020828403121561537d57600080fd5b813561307d81614ca3565b6000806040838503121561539b57600080fd5b82356153a681614ca3565b91506020830135614ce881614e28565b60008083601f8401126153c857600080fd5b50813567ffffffffffffffff8111156153e057600080fd5b6020830191508360208260051b85010111156153fb57600080fd5b9250929050565b6000806000806040858703121561541857600080fd5b843567ffffffffffffffff8082111561543057600080fd5b61543c888389016153b6565b9096509450602087013591508082111561545557600080fd5b50615462878288016153b6565b95989497509550505050565b6000806040838503121561548157600080fd5b823561548c81614ca3565b9150614bb76020840161502f565b6000602082840312156154ac57600080fd5b61307d82614d1f565b600080604083850312156154c857600080fd5b6154d183614b65565b9150614bb760208401614c30565b60008060008060008060a087890312156154f857600080fd5b863567ffffffffffffffff81111561550f57600080fd5b61551b89828a016153b6565b909750955061552e905060208801614b65565b9350604087013561553e81614ca3565b925061554c60608801614c30565b9150608087013561555c81614ca3565b809150509295509295509295565b60006020828403121561557c57600080fd5b61307d82614c30565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000826155c0576155c0615585565b500490565b818103818111156110415761104161559b565b600181811c908216806155ec57607f821691505b60208210810361560c57634e487b7160e01b600052602260045260246000fd5b50919050565b64ffffffffff82811682821603908082111561458c5761458c61559b565b61ffff81811683821601908082111561458c5761458c61559b565b600064ffffffffff8084168061566357615663615585565b92169190910492915050565b808201808211156110415761104161559b565b80820281158282048414176110415761104161559b565b634e487b7160e01b600052603260045260246000fd5b815160009082906020808601845b838110156156e25781516001600160a01b0316855293820193908201906001016156bd565b50929695505050505050565b60006020828403121561570057600080fd5b815161307d81614ca3565b601f821115611d43576000816000526020600020601f850160051c810160208610156157345750805b601f850160051c820191505b81811015614a1c57828155600101615740565b815167ffffffffffffffff81111561576d5761576d614de1565b6157818161577b84546155d8565b8461570b565b602080601f8311600181146157b6576000841561579e5750858301515b600019600386901b1c1916600185901b178555614a1c565b600085815260208120601f198616915b828110156157e5578886015182559484019460019091019084016157c6565b50858210156158035787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020828403121561582557600080fd5b5051919050565b60006020828403121561583e57600080fd5b815161307d81614e28565b60006020828403121561585b57600080fd5b813561307d81614e28565b61ffff82811682821603908082111561458c5761458c61559b565b60008351615893818460208801614bc0565b8351908301906158a7818360208801614bc0565b01949350505050565b6001600160501b038181168382160280821691908281146146a6576146a661559b565b6000600182016158e5576158e561559b565b506001019056fea2646970667358221220d5756ee956a1dc31448fc0c92b9888856adca70cc1945e23016de6def1e7067d64736f6c63430008170033
Deployed Bytecode
0x60806040526004361061044b5760003560e01c80636352211e11610234578063a78a04a41161012e578063c87b56dd116100b6578063e9be457f1161007a578063e9be457f14610e16578063ed86997814610e29578063f04e283e14610e49578063f2fde38b14610e5c578063fee81cf414610e6f5761045a565b8063c87b56dd14610d48578063d5abeb0114610d68578063d8a06f7314610da3578063e8a3d48514610dcb578063e985e9c514610de05761045a565b8063bce6d672116100fd578063bce6d67214610cb3578063c107532914610cc8578063c21b471b14610ce8578063c42fe71814610d08578063c7488e7614610d285761045a565b8063a78a04a414610c30578063ac52e64414610c50578063b1a6505f14610c70578063b88d4fde14610ca05761045a565b80638da5cb5b116101bc5780639b3ba79f116101805780639b3ba79f14610b7a578063a035b1fe14610b9c578063a0712d6814610bdb578063a2076b6f14610bee578063a22cb46514610c105761045a565b80638da5cb5b14610a795780638e021c0614610a92578063940fe26314610aa757806394d216d614610b4557806395d89b4114610b655761045a565b806370a082311161020357806370a08231146109ce578063715018a6146109ee57806372abc8b7146109f65780637df325e114610a2457806384ae2bc614610a445761045a565b80636352211e1461094c578063650b00f61461096c57806365252d2e146109995780636c0360eb146109b95761045a565b80632569296211610345578063338d6c30116102cd578063536226ec11610291578063536226ec146108ac57806354d1f13d146108e457806355f804b3146108ec5780635d799f871461090c578063600041a01461092c5761045a565b8063338d6c301461082f57806340a9c8df1461085157806340c10f191461087157806342842e0e146108845780634a355d7f146108975761045a565b80632cba8123116103145780632cba8123146107935780632f6196b7146107d457806330bacb04146107e75780633167611f1461080757806331f449001461081a5761045a565b8063256929621461070c578063269ff7a3146107145780632799cde0146107345780632a55205a146107545761045a565b80630d4d1513116103d357806318160ddd1161039757806318160ddd146106885780631f87f764146106a457806320c5ab6a146106b757806323b872dd146106d857806324bbd049146106eb5761045a565b80630d4d1513146105f45780630e85d1e3146106075780630ec78173146106275780631249c58b14610647578063150b7a021461064f5761045a565b8063090cf73f1161041a578063090cf73f1461053957806309308e5d14610559578063095ea7b31461059f5780630ac27656146105b25780630b8c7e4f146105d25761045a565b806301ffc9a71461048a5780630218d5ef146104bf57806306fdde03146104df578063081812fc146105015761045a565b3661045a57610458610ea2565b005b600b5436806000803760008082600034865af19150508061047f573d6000803e3d6000fd5b503d6000803e3d6000f35b34801561049657600080fd5b506104aa6104a5366004614b3b565b611018565b60405190151581526020015b60405180910390f35b3480156104cb57600080fd5b506104586104da366004614b8d565b611047565b3480156104eb57600080fd5b506104f46110e7565b6040516104b69190614be4565b34801561050d57600080fd5b5061052161051c366004614c17565b611179565b6040516001600160a01b0390911681526020016104b6565b34801561054557600080fd5b50610458610554366004614c45565b6111b8565b34801561056557600080fd5b50610591610574366004614cc3565b600360209081526000928352604080842090915290825290205481565b6040519081526020016104b6565b6104586105ad366004614cf3565b611448565b3480156105be57600080fd5b506104586105cd366004614d31565b611453565b3480156105de57600080fd5b506105e76115b8565b6040516104b69190614d5b565b610458610602366004614d9f565b6115c9565b34801561061357600080fd5b50610458610622366004614e41565b6116f3565b34801561063357600080fd5b50610458610642366004614f05565b6117bd565b61045861183f565b34801561065b57600080fd5b5061066f61066a366004614f20565b6118fe565b6040516001600160e01b031990911681526020016104b6565b34801561069457600080fd5b50600a5464ffffffffff16610591565b6104586106b2366004615046565b611a27565b3480156106c357600080fd5b50600a546104aa90600160d01b900460ff1681565b6104586106e6366004615151565b611d03565b3480156106f757600080fd5b50600a546104aa90600160d81b900460ff1681565b610458611d48565b34801561072057600080fd5b5061045861072f366004615192565b611d98565b34801561074057600080fd5b5061045861074f366004614c17565b611dfb565b34801561076057600080fd5b5061077461076f3660046151ad565b611e2a565b604080516001600160a01b0390931683526020830191909152016104b6565b34801561079f57600080fd5b506105216107ae3660046151ad565b60026020908152600092835260408084209091529082529020546001600160a01b031681565b6104586107e23660046151cf565b611e7f565b3480156107f357600080fd5b50610458610802366004615220565b611f9a565b61045861081536600461525e565b6120a5565b34801561082657600080fd5b50610458612160565b34801561083b57600080fd5b50610844612168565b6040516104b69190615293565b34801561085d57600080fd5b5061045861086c366004614c17565b612174565b61045861087f366004614cf3565b6121a3565b610458610892366004615151565b612268565b3480156108a357600080fd5b506104586122a3565b3480156108b857600080fd5b506105916108c73660046152d4565b600d60209081526000928352604080842090915290825290205481565b61045861231c565b3480156108f857600080fd5b50610458610907366004615300565b612358565b34801561091857600080fd5b5061045861092736600461533d565b6123d9565b34801561093857600080fd5b50600e54610521906001600160a01b031681565b34801561095857600080fd5b50610521610967366004614c17565b61258a565b34801561097857600080fd5b50610591610987366004614c17565b60016020526000908152604090205481565b3480156109a557600080fd5b506104586109b4366004614f05565b6125c8565b3480156109c557600080fd5b506104f46127cf565b3480156109da57600080fd5b506105916109e936600461536b565b6127de565b610458612819565b348015610a0257600080fd5b506104aa610a11366004614c17565b6000908152600160205260409020541590565b348015610a3057600080fd5b50610458610a3f366004615151565b61282b565b348015610a5057600080fd5b50600a54610a6690600160c01b900461ffff1681565b60405161ffff90911681526020016104b6565b348015610a8557600080fd5b50638b78c6d81954610521565b348015610a9e57600080fd5b5061045861296f565b348015610ab357600080fd5b50610b08610ac2366004614f05565b600c602052600090815260409020805460019091015464ffffffffff80821691600160281b8104821691600160501b82041690600160781b90046001600160501b031685565b6040805195865264ffffffffff94851660208701529284169285019290925290911660608301526001600160501b0316608082015260a0016104b6565b348015610b5157600080fd5b50610458610b60366004614cc3565b6129b5565b348015610b7157600080fd5b506104f46129e5565b348015610b8657600080fd5b50600a54610a6690600160b01b900461ffff1681565b348015610ba857600080fd5b50600a54610bc390600160281b90046001600160501b031681565b6040516001600160501b0390911681526020016104b6565b610458610be9366004614c17565b6129f4565b348015610bfa57600080fd5b50600a54610a6690600160a01b900461ffff1681565b348015610c1c57600080fd5b50610458610c2b366004615388565b612ab9565b348015610c3c57600080fd5b50600b54610521906001600160a01b031681565b348015610c5c57600080fd5b50610458610c6b366004615402565b612b0f565b348015610c7c57600080fd5b506104aa610c8b36600461536b565b60006020819052908152604090205460ff1681565b610458610cae366004614f20565b612bc3565b348015610cbf57600080fd5b50610458612c00565b348015610cd457600080fd5b50610458610ce3366004614cf3565b612c46565b348015610cf457600080fd5b50610458610d0336600461546e565b612dd1565b348015610d1457600080fd5b50610458610d2336600461549a565b612e99565b348015610d3457600080fd5b50610458610d433660046154b5565b612f2f565b348015610d5457600080fd5b506104f4610d63366004614c17565b613000565b348015610d7457600080fd5b50600a54610d8d90600160781b900464ffffffffff1681565b60405164ffffffffff90911681526020016104b6565b348015610daf57600080fd5b5061052173e3d5e8e972291bdbda57159481028a77fb8f055a81565b348015610dd757600080fd5b506104f4613084565b348015610dec57600080fd5b506104aa610dfb36600461533d565b601c52670a5a2e7a000000006008526000526030600c205490565b610458610e243660046154df565b61313f565b348015610e3557600080fd5b50610458610e4436600461556a565b6133ef565b610458610e5736600461536b565b613499565b610458610e6a36600461536b565b6134d6565b348015610e7b57600080fd5b50610591610e8a36600461536b565b63389a75e1600c908152600091909152602090205490565b600a54600160d81b900460ff1615610ed957600a54610ed790339061087f90600160281b90046001600160501b0316346155b1565b565b600a54600090610ef790600160a01b900461ffff1634612710613566565b600b546040519192506001600160a01b0316908290600081818185875af1925050503d8060008114610f45576040519150601f19603f3d011682016040523d82523d6000602084013e610f4a565b606091505b5050506000610f5c638b78c6d8195490565b6001600160a01b0316610f6f83346155c5565b604051600081818185875af1925050503d8060008114610fab576040519150601f19603f3d011682016040523d82523d6000602084013e610fb0565b606091505b505090508061101457600b546001600160a01b0316610fcf83346155c5565b604051600081818185875af1925050503d806000811461100b576040519150601f19603f3d011682016040523d82523d6000602084013e611010565b606091505b5050505b5050565b600061102382613594565b806110415750632a55205a60e083901c9081146301ffc9a791909114175b92915050565b61104f6135d6565b61105d600560ff84166135f1565b61107a57604051636dac6a0960e01b815260040160405180910390fd5b60ff82166000818152600c6020526040808220600101805469ffffffffffffffffffff60781b1916600160781b6001600160501b0387169081029190911790915590519092917f4e1d7becfe51ce8dcac99513c8c126636b0f047eddb6b70bab881b0c4f93e1ff91a35050565b6060600680546110f6906155d8565b80601f0160208091040260200160405190810160405280929190818152602001828054611122906155d8565b801561116f5780601f106111445761010080835404028352916020019161116f565b820191906000526020600020905b81548152906001019060200180831161115257829003601f168201915b5050505050905090565b600081600052673ec412a9852d173d60c11b601c52602060002082018201805460601b6111ae5763ceea21b66000526004601cfd5b6001015492915050565b6111c06135d6565b6111ce600560ff86166135f1565b6111e2576111e0600560ff86166135fd565b505b60ff84166000908152600c6020908152604091829020825160a0810184528154815260019091015464ffffffffff808216938301849052600160281b8204811694830194909452600160501b81049093166060820152600160781b9092046001600160501b031660808301521580159061127c57508364ffffffffff16816060015182602001516112739190615612565b64ffffffffff16115b1561129a57604051636dac6a0960e01b815260040160405180910390fd5b6000816020015164ffffffffff166000036112b65750836112f3565b816020015164ffffffffff168564ffffffffff1610156112e257848260200151038260600151036112f0565b816020015185038260600151015b90505b6040518060a001604052808881526020018664ffffffffff1681526020018564ffffffffff1681526020018264ffffffffff168152602001846001600160501b0316815250600c60008860ff1660ff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548164ffffffffff021916908364ffffffffff16021790555060408201518160010160056101000a81548164ffffffffff021916908364ffffffffff160217905550606082015181600101600a6101000a81548164ffffffffff021916908364ffffffffff160217905550608082015181600101600f6101000a8154816001600160501b0302191690836001600160501b031602179055509050508464ffffffffff168660ff16887fbdcecaf53f2dfa3319a5ddf57b4fa9aa4775994b334019cfd8a1ff730e1d23b560405160405180910390a450505050505050565b611014338383613609565b61145b6135d6565b600a5461ffff600160a01b909104811690821681111561148e57604051636dac6a0960e01b815260040160405180910390fd5b600a54612710906114aa90600160c01b900461ffff1684615630565b61ffff1611156114cd57604051636dac6a0960e01b815260040160405180910390fd5b600a546114ea90600290600160781b900464ffffffffff1661564b565b64ffffffffff16611501600a5464ffffffffff1690565b1015611561578061ffff168361ffff16108061152457508161ffff168361ffff16115b1561154257604051636dac6a0960e01b815260040160405180910390fd5b600a805461ffff60a01b1916600160a01b61ffff861602179055611565565b8092505b600a805461ffff60b01b1916600160b01b61ffff85811691820292909217909255604051908516907f651dcfc39d95235af566f8d017566d15d6d368b7df40b5b9f99c0300a5084a8190600090a3505050565b60606115c460056136aa565b905090565b600a548290600160d81b900460ff166115f55760405163589ed34b60e01b815260040160405180910390fd5b600a5464ffffffffff600160781b82048116916116149184911661566f565b111561163357604051635eddbf3560e11b815260040160405180910390fd5b3068929eee149b4bd2126854036116525763ab143c066000526004601cfd5b3068929eee149b4bd2126855336001600160a01b0383160361168757604051636dac6a0960e01b815260040160405180910390fd5b600a546116a5908490600160281b90046001600160501b0316615682565b3410156116c55760405163cd1c886760e01b815260040160405180910390fd5b6116e1848484600a60149054906101000a900461ffff166136bb565b3868929eee149b4bd212685550505050565b6116fb6135d6565b60005b82518110156117775781156117405761173a83828151811061172257611722615699565b602002602001015160046138ec90919063ffffffff16565b5061176f565b61176d83828151811061175557611755615699565b60200260200101516004613a3c90919063ffffffff16565b505b6001016116fe565b508015158260405161178991906156af565b604051908190038120907fee9d89892c5dcf46d5666e29b34f4c774422b5f43f738b564b85938b6ede416490600090a35050565b6117c56135d6565b6117d3600560ff83166135f1565b6117f057604051636dac6a0960e01b815260040160405180910390fd5b60ff81166000818152600c6020526040808220600101805469ffffffffff000000000019169055517fa2981e359ad98af46ff4183dd23efb45ca30069367c61b7cc1bd485f6c62f6ac9190a250565b600a54600190600160d81b900460ff1661186c5760405163589ed34b60e01b815260040160405180910390fd5b600a5464ffffffffff600160781b820481169161188b9184911661566f565b11156118aa57604051635eddbf3560e11b815260040160405180910390fd5b600a54600160281b90046001600160501b03163410156118dd5760405163cd1c886760e01b815260040160405180910390fd5b6118fb3360016000600a60149054906101000a900461ffff166136bb565b50565b600080600b60009054906101000a90046001600160a01b03166001600160a01b031663b13eb2cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611954573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197891906156ee565b90506001600160a01b03811633036119fb57600b54604051632142170760e11b81523060048201526001600160a01b03918216602482015260448101879052908216906342842e0e90606401600060405180830381600087803b1580156119de57600080fd5b505af11580156119f2573d6000803e3d6000fd5b50505050611a14565b604051638fcc34bd60e01b815260040160405180910390fd5b50630a85bd0160e11b9695505050505050565b63409feecd198054600382558015611a5e5760018160011c14303b10611a555763f92ee8a96000526004601cfd5b818160ff1b1b91505b506101f48761ffff161015611a8657604051638fcc34bd60e01b815260040160405180910390fd5b61271061ffff88161180611a9f57506103e861ffff8916115b15611abd57604051636dac6a0960e01b815260040160405180910390fd5b600a805463ffffffff60a01b1916600160a01b61ffff8a811691820261ffff60b01b191692909217600160b01b9190910217909155611b029060009088908b16613b86565b611b10868961ffff16613be0565b611b1986613c2b565b6006611b258d82615753565b506007611b328c82615753565b506008611b3f8b82615753565b50600a805473ffffffffffffffffffffffffffffff00000000001916600160781b64ffffffffff8c16026effffffffffffffffffff0000000000191617600160281b6001600160501b03871602179055600e8054336001600160a01b0319909116811790915560405162bf4f1f60e71b81526001600160a01b03871660048201526001600160601b03851660248201526044810184905260009190635fa78f80906064016020604051808303816000875af1158015611c02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2691906156ee565b600b80546001600160a01b0319166001600160a01b03831617905590503415611cbf576000816001600160a01b03163460405160006040518083038185875af1925050503d8060008114611c96576040519150601f19603f3d011682016040523d82523d6000602084013e611c9b565b606091505b5050905080611cbd576040516312171d8360e31b815260040160405180910390fd5b505b508015611cf5576002815560016020527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602080a15b505050505050505050505050565b60008181526001602052604090205415611d385760405163032bc66b60e01b8152600481018290526024015b60405180910390fd5b611d43838383613c67565b505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b611da06135d6565b600a80546effffffffffffffffffff00000000001916600160281b6001600160501b038416908102919091179091556040517fdaf1ed0e2ffd4362000735d64121408550f2fcee174e71d85d9498c7aa8ada3290600090a250565b611e0481613d67565b611e215760405163677510db60e11b815260040160405180910390fd5b6118fb81613d8b565b600082815268aa4ec00224afccfdb76020526040812054606081901c91906127109083611e5e576020515490508060601c93505b606084901b1884600019829004811182023d3d3e9396930204935090915050565b600a548390600160d81b900460ff16611eab5760405163589ed34b60e01b815260040160405180910390fd5b600a5464ffffffffff600160781b8204811691611eca9184911661566f565b1115611ee957604051635eddbf3560e11b815260040160405180910390fd5b3068929eee149b4bd212685403611f085763ab143c066000526004601cfd5b3068929eee149b4bd2126855336001600160a01b03841603611f3d57604051636dac6a0960e01b815260040160405180910390fd5b600a54611f5b908590600160281b90046001600160501b0316615682565b341015611f7b5760405163cd1c886760e01b815260040160405180910390fd5b611f87858585856136bb565b3868929eee149b4bd21268555050505050565b611fa26135d6565b6103e86001600160601b0382161115611fce57604051636dac6a0960e01b815260040160405180910390fd5b6000611fdb600080611e2a565b5090506001600160a01b0381166120055760405163adc7931960e01b815260040160405180910390fd5b8360000361202657604051636dac6a0960e01b815260040160405180910390fd5b816001600160601b031660000361205357600084815268aa4ec00224afccfdb7602052604081205561205e565b61205e848484613b86565b816001600160601b0316836001600160a01b0316857f5bb0fa5bb0ca1f6fc0bea8341d9bbe9415797f17ca5e32a71c7901649671c24060405160405180910390a450505050565b600a548290600160d81b900460ff166120d15760405163589ed34b60e01b815260040160405180910390fd5b600a5464ffffffffff600160781b82048116916120f09184911661566f565b111561210f57604051635eddbf3560e11b815260040160405180910390fd5b600a5461212d908490600160281b90046001600160501b0316615682565b34101561214d5760405163cd1c886760e01b815260040160405180910390fd5b61215a84846000856136bb565b50505050565b610ed7613e78565b60606115c46004613ed9565b61217d81613d67565b61219a5760405163677510db60e11b815260040160405180910390fd5b6118fb81613fae565b600a548190600160d81b900460ff166121cf5760405163589ed34b60e01b815260040160405180910390fd5b600a5464ffffffffff600160781b82048116916121ee9184911661566f565b111561220d57604051635eddbf3560e11b815260040160405180910390fd5b600a5461222b908390600160281b90046001600160501b0316615682565b34101561224b5760405163cd1c886760e01b815260040160405180910390fd5b611d4383836000600a60149054906101000a900461ffff166136bb565b600081815260016020526040902054156122985760405163032bc66b60e01b815260048101829052602401611d2f565b611d43838383614116565b6122ab6135d6565b6122bd600068aa4ec00224afccfdb755565b600080805268aa4ec00224afccfdb76020527f913817da311d664dd3395c9b93b1f96a4af2b60ec505387b3ac50cc4468f3488556040517f2c57531944d96595a8b3fba36d50130b4cb6f0316fb235c386966db8f2dfbefa90600090a1565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b6123606135d6565b600a54600160d01b900460ff161561238b576040516331d1c0a360e01b815260040160405180910390fd5b60086123978282615753565b50600a54604051600160781b90910464ffffffffff16906000907f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c908290a350565b6123e16135d6565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015612428573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061244c9190615813565b9050600b60009054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124c591906156ee565b6001600160a01b0316836001600160a01b03160361255557600b5460405163a9059cbb60e01b81526001600160a01b039182166004820152602481018390529084169063a9059cbb906044015b6020604051808303816000875af1158015612531573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215a919061582c565b60405163a9059cbb60e01b81526001600160a01b0383811660048301526024820183905284169063a9059cbb90604401612512565b6000818152673ec412a9852d173d60c11b601c526020902081018101546001600160a01b0316806125c35763ceea21b66000526004601cfd5b919050565b6125d06135d6565b60ff81166000908152600c6020908152604091829020825160a0810184528154815260019091015464ffffffffff808216938301849052600160281b8204811694830194909452600160501b810490931660608201819052600160781b9093046001600160501b031660808201529190036126b857612653600560ff84166135f1565b1561266857612666600560ff8416614143565b505b60ff82166000818152600c602052604080822082815560010180546001600160c81b0319169055517f2f72de1149aa0f409dc1831d65c303890971a4f5cd249516c47f8a279d7280a69190a25050565b6040518060a0016040528060008019168152602001826060015183602001516126e19190615612565b64ffffffffff9081168252600060208084018290526040808501839052606094850183905260ff8816808452600c835281842087518155928701516001909301805488840151978901516080909901516001600160501b0316600160781b0269ffffffffffffffffffff60781b19998816600160501b02999099166effffffffffffffffffffffffffffff60501b19988816600160281b0269ffffffffffffffffffff199092169590971694909417939093179590951693909317949094179093555182907fbdcecaf53f2dfa3319a5ddf57b4fa9aa4775994b334019cfd8a1ff730e1d23b5908290a45050565b6060600880546110f6906155d8565b6000816127f357638f4eb6046000526004601cfd5b673ec412a9852d173d60c11b601c528160005263ffffffff601c600c2054169050919050565b6128216135d6565b610ed7600061414f565b6128336135d6565b600b60009054906101000a90046001600160a01b03166001600160a01b031663b13eb2cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612886573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128aa91906156ee565b6001600160a01b0316836001600160a01b03160361293457600b54604051632142170760e11b81523060048201526001600160a01b03918216602482015260448101839052908416906342842e0e906064015b600060405180830381600087803b15801561291757600080fd5b505af115801561292b573d6000803e3d6000fd5b50505050505050565b6040516323b872dd60e01b81523060048201526001600160a01b038381166024830152604482018390528416906323b872dd906064016128fd565b6129776135d6565b600a805460ff60d01b1916600160d01b1790556040517fc8110264427cd578eaa021ca580e278f71edd94d3f61344a5727777cb5e07afc90600090a1565b6129be82613d67565b6129db5760405163677510db60e11b815260040160405180910390fd5b611014828261418d565b6060600780546110f6906155d8565b600a548190600160d81b900460ff16612a205760405163589ed34b60e01b815260040160405180910390fd5b600a5464ffffffffff600160781b8204811691612a3f9184911661566f565b1115612a5e57604051635eddbf3560e11b815260040160405180910390fd5b600a54612a7c908390600160281b90046001600160501b0316615682565b341015612a9c5760405163cd1c886760e01b815260040160405180910390fd5b61101433836000600a60149054906101000a900461ffff166136bb565b801515905081601c52670a5a2e7a0000000060085233600052806030600c2055806000528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a35050565b612b176135d6565b828114612b375760405163512509d360e11b815260040160405180910390fd5b60005b8381101561101057828282818110612b5457612b54615699565b9050602002016020810190612b699190615849565b600080878785818110612b7e57612b7e615699565b9050602002016020810190612b93919061536b565b6001600160a01b031681526020810191909152604001600020805460ff1916911515919091179055600101612b3a565b60008381526001602052604090205415612bf35760405163032bc66b60e01b815260048101849052602401611d2f565b6110108585858585614312565b612c086135d6565b600a805460ff60d81b1916600160d81b1790556040517f8c2245a4c9f0d7f9de9599f098a52451fff46c9be8d4b39e14120ae514b8797f90600090a1565b3068929eee149b4bd212685403612c655763ab143c066000526004601cfd5b3068929eee149b4bd21268556000612c80638b78c6d8195490565b9050476001600160a01b038416612caa57604051636dac6a0960e01b815260040160405180910390fd5b6001600160a01b03821615801590612ccb57506001600160a01b0382163314155b15612ce8576040516282b42960e81b815260040160405180910390fd5b6001600160a01b038216612d0857600b546001600160a01b031693509150815b80831115612d14578092505b6000846001600160a01b03168460405160006040518083038185875af1925050503d8060008114612d61576040519150601f19603f3d011682016040523d82523d6000602084013e612d66565b606091505b5050905080612d88576040516312171d8360e31b815260040160405180910390fd5b60405184906001600160a01b038716907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436490600090a35050503868929eee149b4bd21268555050565b612dd96135d6565b6103e86001600160601b0382161115612e0557604051636dac6a0960e01b815260040160405180910390fd5b6000612e12600080611e2a565b5090506001600160a01b038116612e3c5760405163adc7931960e01b815260040160405180910390fd5b612e4860008484613b86565b612e528383613be0565b816001600160601b0316836001600160a01b031660007f5bb0fa5bb0ca1f6fc0bea8341d9bbe9415797f17ca5e32a71c7901649671c24060405160405180910390a4505050565b612ea16135d6565b600a54612ebb90600160b01b900461ffff16612710615866565b61ffff168161ffff161115612ee357604051636dac6a0960e01b815260040160405180910390fd5b600a805461ffff60c01b1916600160c01b61ffff8416908102919091179091556040517f86d4ccf683b2dc5a92d3b3a8e1c54b8452b39a7aee12580a63a24689d5783d9390600090a250565b612f376135d6565b612f45600560ff84166135f1565b612f6257604051636dac6a0960e01b815260040160405180910390fd5b60ff82166000908152600c602052604081206001015464ffffffffff90811691908316821015612f925781612f94565b825b60ff85166000818152600c6020526040808220600101805469ffffffffff00000000001916600160281b64ffffffffff8716908102919091179091559051939450927f1dac9586e26a9cef0cd6c48d38d5ef12911d811fe74284267653c54c687ef32b9190a350505050565b606061300b82613d67565b6130285760405163677510db60e11b815260040160405180910390fd5b60006130326127cf565b90506000815111613052576040518060200160405280600081525061307d565b8061305c84614366565b60405160200161306d929190615881565b6040516020818303038152906040525b9392505050565b60606115c460088054613096906155d8565b80601f01602080910402602001604051908101604052809291908181526020018280546130c2906155d8565b801561310f5780601f106130e45761010080835404028352916020019161310f565b820191906000526020600020905b8154815290600101906020018083116130f257829003601f168201915b50505050506040518060400160405280600d81526020016c31b7b73a3930b1ba173539b7b760991b8152506143aa565b600a5464ffffffffff831690600160d81b900460ff166131725760405163589ed34b60e01b815260040160405180910390fd5b600a5464ffffffffff600160781b82048116916131919184911661566f565b11156131b057604051635eddbf3560e11b815260040160405180910390fd5b3068929eee149b4bd2126854036131cf5763ab143c066000526004601cfd5b3068929eee149b4bd21268556131e9600560ff87166135f1565b61320657604051636dac6a0960e01b815260040160405180910390fd5b60ff85166000908152600c60205260409020600181015464ffffffffff600160501b9091048116908516111561324f57604051635eddbf3560e11b815260040160405180910390fd5b6001810154336000908152600d6020908152604080832060ff8b16845290915290205464ffffffffff600160281b909204821691613290919087169061566f565b11156132af5760405163fd41fb5360e01b815260040160405180910390fd5b60018101546132d590600160781b90046001600160501b031664ffffffffff86166158b0565b6001600160501b03163410156132fe5760405163cd1c886760e01b815260040160405180910390fd5b6040516bffffffffffffffffffffffff193360601b1660208201526000906034016040516020818303038152906040528051906020012090506133478989846000015484614405565b613364576040516312d37ee560e31b815260040160405180910390fd5b336000908152600d6020908152604080832060ff8b1684529091529020805464ffffffffff87811691820190925560018401805464ffffffffff60501b198116600160501b9182900485168a90039094160292909217909155600a546133d89188918790600160a01b900461ffff166136bb565b50503868929eee149b4bd212685550505050505050565b6133f76135d6565b600a5464ffffffffff600160781b90910481169082161015806134295750600a5464ffffffffff168164ffffffffff16105b1561344757604051636dac6a0960e01b815260040160405180910390fd5b600a805464ffffffffff60781b1916600160781b64ffffffffff8416908102919091179091556040517f7aebd4bde0b5cd06faa86c1ac30854673d54252838e89d9f9d1406fab507334890600090a250565b6134a16135d6565b63389a75e1600c52806000526020600c2080544211156134c957636f5e88186000526004601cfd5b600090556118fb8161414f565b6134de6135d6565b600e546001600160a01b0316635d92051b6134fc638b78c6d8195490565b6040516001600160e01b031960e084901b1681526001600160a01b0391821660048201529084166024820152604401600060405180830381600087803b15801561354557600080fd5b505af1158015613559573d6000803e3d6000fd5b505050506118fb8161443f565b6000613573848484614466565b9050818385091561307d576001018061307d5763ae47f7026000526004601cfd5b60006001600160e01b0319821663706e848960e01b14806110415750611041826301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b638b78c6d819543314610ed7576382b429006000526004601cfd5b600061307d8383614506565b600061307d8383614593565b60001960601c828116925083811693508160005283673ec412a9852d173d60c11b17601c52602060002082018201805482169150816136505763ceea21b66000526004601cfd5b81851485151761367657816000526030600c205461367657634b6e7f186000526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600038a450505050565b60606110416136b8836146ae565b90565b6001600160a01b03841615806136cf575082155b156136ed57604051636dac6a0960e01b815260040160405180910390fd5b6136f73385614769565b600a5461ffff600160a01b909104811690821610806137265750600a5461ffff600160b01b9091048116908216115b1561374457604051636dac6a0960e01b815260040160405180910390fd5b600061375761ffff831634612710613566565b9050341561389057600b546040516001600160a01b03909116908290600081818185875af1925050503d80600081146137ac576040519150601f19603f3d011682016040523d82523d6000602084013e6137b1565b606091505b5050506001600160a01b0383161561389057600a546000906137e190600160c01b900461ffff16346127106148c8565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114613830576040519150601f19603f3d011682016040523d82523d6000602084013e613835565b606091505b5050905080613857576040516312171d8360e31b815260040160405180910390fd5b60405182906001600160a01b038716907f339143a0e6309caafa5c4c55cd7b75d2e49115ce1e88b394e3376814b8507c1590600090a350505b600a5464ffffffffff1660005b858110156138c2576138ba876138b2846158d3565b9350836148f7565b60010161389d565b5050600a805464ffffffffff19811664ffffffffff91821696909601169490941790935550505050565b63978aab926004526000828152602481206001600160a01b03929092169168fbb67fda52d4bfb8be1983016139295763f5a267f16000526004601cfd5b8261393b5768fbb67fda52d4bfb8bf92505b80546001600160601b03811682602052806139fe578160601c80613969578560601b84556001945050613a33565b8581036139765750613a33565b600184015460601c80613997578660601b6001860155600195505050613a33565b8681036139a5575050613a33565b600285015460601c806139c7578760601b600287015560019650505050613a33565b8781036139d657505050613a33565b6000928352604080842060019055918352818320600290558252902060039055506007908117905b8460005260406000208054613a31578160011c91508560601b828501558160010181558260020184556001945050613a33565b505b50505092915050565b63978aab926004526000828152602481206001600160a01b03929092169168fbb67fda52d4bfb8be198301613a795763f5a267f16000526004601cfd5b82613a8b5768fbb67fda52d4bfb8bf92505b80546001600160601b03811680613b095760019350848260601c03613ac457600183018054845560028401805490915560009055613a33565b84600184015460601c03613ae657600283018054600185015560009055613a33565b84600284015460601c03613b005760006002840155613a33565b60009350613a33565b82602052846000526040600020805480613b24575050613a33565b60018360011c039250826001820314613b5c578285015460601c8060601b600183038701556000848701558060005250806040600020555b5083546bffffffffffffffffffffffff1916600192831b1782179093556000909255509392505050565b6001600160601b031661271080821115613ba85763350a88b36000526004601cfd5b8260601b80613bbf5763b4457eaa6000526004601cfd5b8460005268aa4ec00224afccfdb76020528281176040600020555050505050565b6001600160601b031661271080821115613c025763350a88b36000526004601cfd5b8260601b80613c195763b4457eaa6000526004601cfd5b90911768aa4ec00224afccfdb7555050565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6000818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b039485169493841693811691908286148302613cb95767ceea21b6a1148100831560021b526004601cfd5b856000528160010154925082331486331417613ce7576030600c2054613ce757634b6e7f186000526004601cfd5b8215613cf557600082600101555b85851818905550601c600c8181208054600019019055600084905220805460010163ffffffff81168402613d385767ea553b3401336cea841560021b526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600038a4505050565b6000818152673ec412a9852d173d60c11b601c52602090208101015460601b151590565b3360009081526020819052604090205460ff16613dbb5760405163dde218bd60e01b815260040160405180910390fd5b600081815260036020908152604080832033845290915290205415613df3576040516317c3335f60e21b815260040160405180910390fd5b600081815260016020818152604080842080546002845282862090850180875290845282862080546001600160a01b03191633908117909155878752600385528387208188528552838720829055878752949093529190915551909183917f9ecfd70e9ff36df72989324a49559383d39f9290d700b10cf5ac10dcb68d26439190a350565b63409feecd1980546001811615613e975763f92ee8a96000526004601cfd5b8160c01c808260011c14611d43578060011b8355806020527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602080a1505050565b63978aab926004526000818152602481206060915068fbb67fda52d4bfb8bf81548060a01b60a01c6040519450846020018260601c9250838314158302815281613f68578215613f6357600191508185015460601c92508215613f63578284141590920260208301525060028381015460601c918215613f63576003915083831415830260408201525b613f98565b600191821c915b82811015613f96578581015460601c858114158102600583901b8401529350600101613f6f565b505b8186528160051b81016040525050505050919050565b3360009081526020819052604090205460ff16613fde5760405163dde218bd60e01b815260040160405180910390fd5b60008181526003602090815260408083203384529091528120549081900361401957604051631834e26560e01b815260040160405180910390fd5b60008281526001602052604090205481811461408f5760008381526002602090815260408083208484528252808320805486855282852080546001600160a01b03199081166001600160a01b039093169283179091558254169091558684526003835281842090845290915290208290556140b7565b6000838152600260209081526040808320858452909152902080546001600160a01b03191690555b6000838152600360209081526040808320338085529083528184208490558684526001909252808320805460001901905551909185917f0fe7d9801197f79ef3b1595d19379eb58f0fff5f98b0f6d6f34c03cae5306c379190a3505050565b614121838383611d03565b813b15611d4357611d4383838360405180602001604052806000815250614998565b600061307d8383614a24565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b6001600160a01b03811660009081526020819052604090205460ff16156141c7576040516303a179f960e31b815260040160405180910390fd5b60008281526003602090815260408083206001600160a01b03851684529091528120549081900361420b57604051631834e26560e01b815260040160405180910390fd5b6000838152600160205260409020548181146142815760008481526002602090815260408083208484528252808320805486855282852080546001600160a01b03199081166001600160a01b039093169283179091558254169091558784526003835281842090845290915290208290556142a9565b6000848152600260209081526040808320858452909152902080546001600160a01b03191690555b60008481526003602090815260408083206001600160a01b0387168085529083528184208490558784526001909252808320805460001901905551909186917f0fe7d9801197f79ef3b1595d19379eb58f0fff5f98b0f6d6f34c03cae5306c379190a350505050565b61431d858585611d03565b833b156110105761101085858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061499892505050565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a900480614381575050819003601f19909101908152919050565b6040518251601f19906020810182165b85810151848201528201806143ba575083518184018360208301165b86810151828201528401806143d65750506000910183810160208101929092528352603f011660405292915050565b60008315614437578360051b8501855b803580851160051b948552602094851852604060002093018181106144155750505b501492915050565b6144476135d6565b8060601b61445d57637448fbae6000526004601cfd5b6118fb8161414f565b8282026000198385098181108201900380614497578261448e5763ae47f7026000526004601cfd5b5081900461307d565b8083116144ac5763ae47f7026000526004601cfd5b82848609600084810385169485900494848311909303908390038390046001010292030417600260038302811880840282030280840282030280840282030280840282030280840282030280840290910302029392505050565b6318fb586460045260008281526024812068fbb67fda52d4bfb8bf83036145355763f5a267f16000526004601cfd5b826145475768fbb67fda52d4bfb8bf92505b80195461457957805460019250831461458c576001810154831461458c576002810154831461458c576000915061458c565b8060205282600052604060002054151591505b5092915050565b6318fb586460045260008281526024812068fbb67fda52d4bfb8bf83036145c25763f5a267f16000526004601cfd5b826145d45768fbb67fda52d4bfb8bf92505b8019548160205280614679578154806145f45784835560019350506146a6565b84810361460157506146a6565b60018301548061461c578560018501556001945050506146a6565b85810361462a5750506146a6565b60028401548061464657866002860155600195505050506146a6565b868103614655575050506146a6565b60009283526040808420600190559183528183206002905582529020600390555060075b8360005260406000208054613a3357600191821c8381018690558083019182905590821b82178319559092505b505092915050565b6318fb5864600452600081815260249020801954604051919068fbb67fda52d4bfb8bf90602084018161472857835480156147225780841415028152600184810154909250801561472257808414150260208201526002848101549092508015614722576003925083811415810260408301525b50614754565b8160011c915060005b8281101561475257848101548481141502600582901b830152600101614731565b505b8185528160051b810160405250505050919050565b60006147756004613ed9565b9050600060015b82518110156110105782818151811061479757614797615699565b60209081029190910101516040516370a0823160e01b81526001600160a01b038781166004830152909116906370a08231906024016020604051808303816000875af11580156147eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061480f9190615813565b8201915082818151811061482557614825615699565b60209081029190910101516040516370a0823160e01b81526001600160a01b038681166004830152909116906370a08231906024016020604051808303816000875af1158015614879573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061489d9190615813565b9091019081156148c0576040516309550c7760e01b815260040160405180910390fd5b60010161477c565b60008260001904841183021582026148e85763ad251c276000526004601cfd5b50910281810615159190040190565b8160601b60601c915080600052673ec412a9852d173d60c11b601c5260206000208101810180548060601b156149355763c991cbb16000526004601cfd5b831790556000829052601c600c20805460010163ffffffff8116840261496a5767ea553b3401336cea841560021b526004601cfd5b9055808260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8138a45050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a084015280156149df578060c08401826020870160045afa505b60208360a48301601c860160008a5af1614a02573d15614a02573d6000843e3d83fd5b508060e01b825114614a1c5763d1a57ed66000526004601cfd5b505050505050565b6318fb586460045260008281526024812068fbb67fda52d4bfb8bf8303614a535763f5a267f16000526004601cfd5b82614a655768fbb67fda52d4bfb8bf92505b80195480614ad2576001925083825403614a93576001820180548355600283018054909155600090556146a6565b83600183015403614ab2576002820180546001840155600090556146a6565b83600283015403614ac957600060028301556146a6565b600092506146a6565b81602052836000526040600020805480614aed5750506146a6565b60018360011c039250826001820314614b1f578284015480600183038601556000848601558060005250806040600020555b5060018260011b17831955600081555060019250505092915050565b600060208284031215614b4d57600080fd5b81356001600160e01b03198116811461307d57600080fd5b803560ff811681146125c357600080fd5b80356001600160501b03811681146125c357600080fd5b60008060408385031215614ba057600080fd5b614ba983614b65565b9150614bb760208401614b76565b90509250929050565b60005b83811015614bdb578181015183820152602001614bc3565b50506000910152565b6020815260008251806020840152614c03816040850160208701614bc0565b601f01601f19169190910160400192915050565b600060208284031215614c2957600080fd5b5035919050565b803564ffffffffff811681146125c357600080fd5b600080600080600060a08688031215614c5d57600080fd5b85359450614c6d60208701614b65565b9350614c7b60408701614c30565b9250614c8960608701614c30565b9150614c9760808701614b76565b90509295509295909350565b6001600160a01b03811681146118fb57600080fd5b80356125c381614ca3565b60008060408385031215614cd657600080fd5b823591506020830135614ce881614ca3565b809150509250929050565b60008060408385031215614d0657600080fd5b8235614d1181614ca3565b946020939093013593505050565b803561ffff811681146125c357600080fd5b60008060408385031215614d4457600080fd5b614d4d83614d1f565b9150614bb760208401614d1f565b6020808252825182820181905260009190848201906040850190845b81811015614d9357835183529284019291840191600101614d77565b50909695505050505050565b600080600060608486031215614db457600080fd5b8335614dbf81614ca3565b9250602084013591506040840135614dd681614ca3565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614e2057614e20614de1565b604052919050565b80151581146118fb57600080fd5b80356125c381614e28565b60008060408385031215614e5457600080fd5b823567ffffffffffffffff80821115614e6c57600080fd5b818501915085601f830112614e8057600080fd5b8135602082821115614e9457614e94614de1565b8160051b9250614ea5818401614df7565b8281529284018101928181019089851115614ebf57600080fd5b948201945b84861015614ee95785359350614ed984614ca3565b8382529482019490820190614ec4565b9650614ef89050878201614e36565b9450505050509250929050565b600060208284031215614f1757600080fd5b61307d82614b65565b600080600080600060808688031215614f3857600080fd5b8535614f4381614ca3565b94506020860135614f5381614ca3565b935060408601359250606086013567ffffffffffffffff80821115614f7757600080fd5b818801915088601f830112614f8b57600080fd5b813581811115614f9a57600080fd5b896020828501011115614fac57600080fd5b9699959850939650602001949392505050565b600082601f830112614fd057600080fd5b813567ffffffffffffffff811115614fea57614fea614de1565b614ffd601f8201601f1916602001614df7565b81815284602083860101111561501257600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160601b03811681146125c357600080fd5b60008060008060008060008060008060006101608c8e03121561506857600080fd5b67ffffffffffffffff808d35111561507f57600080fd5b61508c8e8e358f01614fbf565b9b508060208e0135111561509f57600080fd5b6150af8e60208f01358f01614fbf565b9a508060408e013511156150c257600080fd5b506150d38d60408e01358e01614fbf565b98506150e160608d01614c30565b97506150ef60808d01614d1f565b96506150fd60a08d01614d1f565b955061510b60c08d01614cb8565b945061511960e08d01614cb8565b93506151286101008d01614b76565b92506151376101208d0161502f565b91506101408c013590509295989b509295989b9093969950565b60008060006060848603121561516657600080fd5b833561517181614ca3565b9250602084013561518181614ca3565b929592945050506040919091013590565b6000602082840312156151a457600080fd5b61307d82614b76565b600080604083850312156151c057600080fd5b50508035926020909101359150565b600080600080608085870312156151e557600080fd5b84356151f081614ca3565b935060208501359250604085013561520781614ca3565b915061521560608601614d1f565b905092959194509250565b60008060006060848603121561523557600080fd5b83359250602084013561524781614ca3565b91506152556040850161502f565b90509250925092565b60008060006060848603121561527357600080fd5b833561527e81614ca3565b92506020840135915061525560408501614d1f565b6020808252825182820181905260009190848201906040850190845b81811015614d935783516001600160a01b0316835292840192918401916001016152af565b600080604083850312156152e757600080fd5b82356152f281614ca3565b9150614bb760208401614b65565b60006020828403121561531257600080fd5b813567ffffffffffffffff81111561532957600080fd5b61533584828501614fbf565b949350505050565b6000806040838503121561535057600080fd5b823561535b81614ca3565b91506020830135614ce881614ca3565b60006020828403121561537d57600080fd5b813561307d81614ca3565b6000806040838503121561539b57600080fd5b82356153a681614ca3565b91506020830135614ce881614e28565b60008083601f8401126153c857600080fd5b50813567ffffffffffffffff8111156153e057600080fd5b6020830191508360208260051b85010111156153fb57600080fd5b9250929050565b6000806000806040858703121561541857600080fd5b843567ffffffffffffffff8082111561543057600080fd5b61543c888389016153b6565b9096509450602087013591508082111561545557600080fd5b50615462878288016153b6565b95989497509550505050565b6000806040838503121561548157600080fd5b823561548c81614ca3565b9150614bb76020840161502f565b6000602082840312156154ac57600080fd5b61307d82614d1f565b600080604083850312156154c857600080fd5b6154d183614b65565b9150614bb760208401614c30565b60008060008060008060a087890312156154f857600080fd5b863567ffffffffffffffff81111561550f57600080fd5b61551b89828a016153b6565b909750955061552e905060208801614b65565b9350604087013561553e81614ca3565b925061554c60608801614c30565b9150608087013561555c81614ca3565b809150509295509295509295565b60006020828403121561557c57600080fd5b61307d82614c30565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000826155c0576155c0615585565b500490565b818103818111156110415761104161559b565b600181811c908216806155ec57607f821691505b60208210810361560c57634e487b7160e01b600052602260045260246000fd5b50919050565b64ffffffffff82811682821603908082111561458c5761458c61559b565b61ffff81811683821601908082111561458c5761458c61559b565b600064ffffffffff8084168061566357615663615585565b92169190910492915050565b808201808211156110415761104161559b565b80820281158282048414176110415761104161559b565b634e487b7160e01b600052603260045260246000fd5b815160009082906020808601845b838110156156e25781516001600160a01b0316855293820193908201906001016156bd565b50929695505050505050565b60006020828403121561570057600080fd5b815161307d81614ca3565b601f821115611d43576000816000526020600020601f850160051c810160208610156157345750805b601f850160051c820191505b81811015614a1c57828155600101615740565b815167ffffffffffffffff81111561576d5761576d614de1565b6157818161577b84546155d8565b8461570b565b602080601f8311600181146157b6576000841561579e5750858301515b600019600386901b1c1916600185901b178555614a1c565b600085815260208120601f198616915b828110156157e5578886015182559484019460019091019084016157c6565b50858210156158035787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020828403121561582557600080fd5b5051919050565b60006020828403121561583e57600080fd5b815161307d81614e28565b60006020828403121561585b57600080fd5b813561307d81614e28565b61ffff82811682821603908082111561458c5761458c61559b565b60008351615893818460208801614bc0565b8351908301906158a7818360208801614bc0565b01949350505050565b6001600160501b038181168382160280821691908281146146a6576146a661559b565b6000600182016158e5576158e561559b565b506001019056fea2646970667358221220d5756ee956a1dc31448fc0c92b9888856adca70cc1945e23016de6def1e7067d64736f6c63430008170033
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.