ETH Price: $2,345.21 (+7.60%)

Transaction Decoder

Block:
13357701 at Oct-05-2021 07:28:34 AM +UTC
Transaction Fee:
0.004547184662621304 ETH $10.66
Gas Used:
56,214 Gas / 80.890608436 Gwei

Emitted Events:

160 MagicProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x00000000000000000000000007a1f6fc89223c5ebd4e4ddae89ac97629856a0f, 00000000000000000000000000000000000000000000011393bbfc76723db092 )

Account State Difference:

  Address   Before After State Difference Code
0x07a1f6fc...629856A0f
3.463250370078575906 Eth
Nonce: 1905
3.458703185415954602 Eth
Nonce: 1906
0.004547184662621304
(BeePool)
1,006.936248797381040142 Eth1,006.936333118381040142 Eth0.000084321
0xB0c7a3Ba...91070Ac9A
0xdCf809BB...cF2555418

Execution Trace

ERC721Farm.claimRewards( tokenIds=[6895] )
  • MagicProxy.40c10f19( )
    • MagicMintReentrancyFix.mint( account=0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f, amount=5083499999999999979666 )
      File 1 of 3: ERC721Farm
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import '@openzeppelin/contracts/utils/math/Math.sol';
      import '@solidstate/contracts/token/ERC721/IERC721.sol';
      import '@solidstate/contracts/token/ERC721/IERC721Receiver.sol';
      import '@solidstate/contracts/utils/EnumerableSet.sol';
      import '../token/IMagic.sol';
      contract ERC721Farm is IERC721Receiver {
          using EnumerableSet for EnumerableSet.UintSet;
          address private immutable MAGIC;
          address private immutable ERC721_CONTRACT;
          uint256 public immutable EXPIRATION;
          uint256 private immutable RATE;
          mapping(address => EnumerableSet.UintSet) private _deposits;
          mapping(address => mapping(uint256 => uint256)) public depositBlocks;
          constructor(
              address magic,
              address erc721,
              uint256 rate,
              uint256 expiration
          ) {
              MAGIC = magic;
              ERC721_CONTRACT = erc721;
              RATE = rate;
              EXPIRATION = block.number + expiration;
          }
          function onERC721Received(
              address,
              address,
              uint256,
              bytes calldata
          ) external pure override returns (bytes4) {
              return IERC721Receiver.onERC721Received.selector;
          }
          function depositsOf(address account)
              external
              view
              returns (uint256[] memory)
          {
              EnumerableSet.UintSet storage depositSet = _deposits[account];
              uint256[] memory tokenIds = new uint256[](depositSet.length());
              for (uint256 i; i < depositSet.length(); i++) {
                  tokenIds[i] = depositSet.at(i);
              }
              return tokenIds;
          }
          function calculateRewards(address account, uint256[] memory tokenIds)
              public
              view
              returns (uint256[] memory rewards)
          {
              rewards = new uint256[](tokenIds.length);
              for (uint256 i; i < tokenIds.length; i++) {
                  uint256 tokenId = tokenIds[i];
                  rewards[i] =
                      RATE *
                      (_deposits[account].contains(tokenId) ? 1 : 0) *
                      (Math.min(block.number, EXPIRATION) -
                          depositBlocks[account][tokenId]);
              }
          }
          function claimRewards(uint256[] calldata tokenIds) public {
              uint256 reward;
              uint256 block = Math.min(block.number, EXPIRATION);
              uint256[] memory rewards = calculateRewards(msg.sender, tokenIds);
              for (uint256 i; i < tokenIds.length; i++) {
                  reward += rewards[i];
                  depositBlocks[msg.sender][tokenIds[i]] = block;
              }
              if (reward > 0) {
                  IMagic(MAGIC).mint(msg.sender, reward);
              }
          }
          function deposit(uint256[] calldata tokenIds) external {
              claimRewards(tokenIds);
              for (uint256 i; i < tokenIds.length; i++) {
                  IERC721(ERC721_CONTRACT).safeTransferFrom(
                      msg.sender,
                      address(this),
                      tokenIds[i],
                      ''
                  );
                  _deposits[msg.sender].add(tokenIds[i]);
              }
          }
          function withdraw(uint256[] calldata tokenIds) external {
              claimRewards(tokenIds);
              for (uint256 i; i < tokenIds.length; i++) {
                  require(
                      _deposits[msg.sender].contains(tokenIds[i]),
                      'ERC721Farm: token not deposited'
                  );
                  _deposits[msg.sender].remove(tokenIds[i]);
                  IERC721(ERC721_CONTRACT).safeTransferFrom(
                      address(this),
                      msg.sender,
                      tokenIds[i],
                      ''
                  );
              }
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @dev Standard math utilities missing in the Solidity language.
       */
      library Math {
          /**
           * @dev Returns the largest of two numbers.
           */
          function max(uint256 a, uint256 b) internal pure returns (uint256) {
              return a >= b ? a : b;
          }
          /**
           * @dev Returns the smallest of two numbers.
           */
          function min(uint256 a, uint256 b) internal pure returns (uint256) {
              return a < b ? a : b;
          }
          /**
           * @dev Returns the average of two numbers. The result is rounded towards
           * zero.
           */
          function average(uint256 a, uint256 b) internal pure returns (uint256) {
              // (a + b) / 2 can overflow.
              return (a & b) + (a ^ b) / 2;
          }
          /**
           * @dev Returns the ceiling of the division of two numbers.
           *
           * This differs from standard division with `/` in that it rounds up instead
           * of rounding down.
           */
          function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
              // (a + b - 1) / b can overflow on addition, so we distribute.
              return a / b + (a % b == 0 ? 0 : 1);
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import {IERC165} from '../../introspection/IERC165.sol';
      import {IERC721Internal} from './IERC721Internal.sol';
      /**
       * @notice ERC721 interface
       * @dev see https://eips.ethereum.org/EIPS/eip-721
       */
      interface IERC721 is IERC721Internal, IERC165 {
        /**
         * @notice query the balance of given address
         * @return balance quantity of tokens held
         */
        function balanceOf (
          address account
        ) external view returns (uint256 balance);
        /**
         * @notice query the owner of given token
         * @param tokenId token to query
         * @return owner token owner
         */
        function ownerOf (
          uint256 tokenId
        ) external view returns (address owner);
        /**
         * @notice transfer token between given addresses, checking for ERC721Receiver implementation if applicable
         * @param from sender of token
         * @param to receiver of token
         * @param tokenId token id
         */
        function safeTransferFrom (
          address from,
          address to,
          uint256 tokenId
        ) external payable;
        /**
         * @notice transfer token between given addresses, checking for ERC721Receiver implementation if applicable
         * @param from sender of token
         * @param to receiver of token
         * @param tokenId token id
         * @param data data payload
         */
        function safeTransferFrom (
          address from,
          address to,
          uint256 tokenId,
          bytes calldata data
        ) external payable;
        /**
         * @notice transfer token between given addresses, without checking for ERC721Receiver implementation if applicable
         * @param from sender of token
         * @param to receiver of token
         * @param tokenId token id
         */
        function transferFrom (
          address from,
          address to,
          uint256 tokenId
        ) external payable;
        /**
         * @notice grant approval to given account to spend token
         * @param operator address to be approved
         * @param tokenId token to approve
         */
        function approve (
          address operator,
          uint256 tokenId
        ) external payable;
        /**
         * @notice get approval status for given token
         * @param tokenId token to query
         * @return operator address approved to spend token
         */
        function getApproved (
          uint256 tokenId
        ) external view returns (address operator);
        /**
         * @notice grant approval to or revoke approval from given account to spend all tokens held by sender
         * @param operator address to be approved
         * @param status approval status
         */
        function setApprovalForAll (
          address operator,
          bool status
        ) external;
        /**
         * @notice query approval status of given operator with respect to given address
         * @param account address to query for approval granted
         * @param operator address to query for approval received
         * @return status whether operator is approved to spend tokens held by account
         */
        function isApprovedForAll (
          address account,
          address operator
        ) external view returns (bool status);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      interface IERC721Receiver {
        function onERC721Received (
          address operator,
          address from,
          uint256 tokenId,
          bytes calldata data
        ) external returns (bytes4);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @title Set implementation with enumeration functions
       * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
       */
      library EnumerableSet {
        struct Set {
          bytes32[] _values;
          // 1-indexed to allow 0 to signify nonexistence
          mapping (bytes32 => uint) _indexes;
        }
        struct Bytes32Set {
          Set _inner;
        }
        struct AddressSet {
          Set _inner;
        }
        struct UintSet {
          Set _inner;
        }
        function at (
          Bytes32Set storage set,
          uint index
        ) internal view returns (bytes32) {
          return _at(set._inner, index);
        }
        function at (
          AddressSet storage set,
          uint index
        ) internal view returns (address) {
          return address(uint160(uint(_at(set._inner, index))));
        }
        function at (
          UintSet storage set,
          uint index
        ) internal view returns (uint) {
          return uint(_at(set._inner, index));
        }
        function contains (
          Bytes32Set storage set,
          bytes32 value
        ) internal view returns (bool) {
          return _contains(set._inner, value);
        }
        function contains (
          AddressSet storage set,
          address value
        ) internal view returns (bool) {
          return _contains(set._inner, bytes32(uint(uint160(value))));
        }
        function contains (
          UintSet storage set,
          uint value
        ) internal view returns (bool) {
          return _contains(set._inner, bytes32(value));
        }
        function indexOf (
          Bytes32Set storage set,
          bytes32 value
        ) internal view returns (uint) {
          return _indexOf(set._inner, value);
        }
        function indexOf (
          AddressSet storage set,
          address value
        ) internal view returns (uint) {
          return _indexOf(set._inner, bytes32(uint(uint160(value))));
        }
        function indexOf (
          UintSet storage set,
          uint value
        ) internal view returns (uint) {
          return _indexOf(set._inner, bytes32(value));
        }
        function length (
          Bytes32Set storage set
        ) internal view returns (uint) {
          return _length(set._inner);
        }
        function length (
          AddressSet storage set
        ) internal view returns (uint) {
          return _length(set._inner);
        }
        function length (
          UintSet storage set
        ) internal view returns (uint) {
          return _length(set._inner);
        }
        function add (
          Bytes32Set storage set,
          bytes32 value
        ) internal returns (bool) {
          return _add(set._inner, value);
        }
        function add (
          AddressSet storage set,
          address value
        ) internal returns (bool) {
          return _add(set._inner, bytes32(uint(uint160(value))));
        }
        function add (
          UintSet storage set,
          uint value
        ) internal returns (bool) {
          return _add(set._inner, bytes32(value));
        }
        function remove (
          Bytes32Set storage set,
          bytes32 value
        ) internal returns (bool) {
          return _remove(set._inner, value);
        }
        function remove (
          AddressSet storage set,
          address value
        ) internal returns (bool) {
          return _remove(set._inner, bytes32(uint(uint160(value))));
        }
        function remove (
          UintSet storage set,
          uint value
        ) internal returns (bool) {
          return _remove(set._inner, bytes32(value));
        }
        function _at (
          Set storage set,
          uint index
        ) private view returns (bytes32) {
          require(set._values.length > index, 'EnumerableSet: index out of bounds');
          return set._values[index];
        }
        function _contains (
          Set storage set,
          bytes32 value
        ) private view returns (bool) {
          return set._indexes[value] != 0;
        }
        function _indexOf (
          Set storage set,
          bytes32 value
        ) private view returns (uint) {
          unchecked {
            return set._indexes[value] - 1;
          }
        }
        function _length (
          Set storage set
        ) private view returns (uint) {
          return set._values.length;
        }
        function _add (
          Set storage set,
          bytes32 value
        ) private returns (bool) {
          if (!_contains(set, value)) {
            set._values.push(value);
            set._indexes[value] = set._values.length;
            return true;
          } else {
            return false;
          }
        }
        function _remove (
          Set storage set,
          bytes32 value
        ) private returns (bool) {
          uint valueIndex = set._indexes[value];
          if (valueIndex != 0) {
            uint index = valueIndex - 1;
            bytes32 last = set._values[set._values.length - 1];
            // move last value to now-vacant index
            set._values[index] = last;
            set._indexes[last] = index + 1;
            // clear last index
            set._values.pop();
            delete set._indexes[value];
            return true;
          } else {
            return false;
          }
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import '@solidstate/contracts/token/ERC20/IERC20.sol';
      interface IMagic is IERC20 {
          function mint(address account, uint256 amount) external;
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @title ERC165 interface registration interface
       * @dev see https://eips.ethereum.org/EIPS/eip-165
       */
      interface IERC165 {
        /**
         * @notice query whether contract has registered support for given interface
         * @param interfaceId interface id
         * @return bool whether interface is supported
         */
        function supportsInterface (
          bytes4 interfaceId
        ) external view returns (bool);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @notice Partial ERC721 interface needed by internal functions
       */
      interface IERC721Internal {
        event Transfer (
          address indexed from,
          address indexed to,
          uint256 indexed tokenId
        );
        event Approval (
          address indexed owner,
          address indexed operator,
          uint256 indexed tokenId
        );
        event ApprovalForAll (
          address indexed owner,
          address indexed operator,
          bool approved
        );
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import {IERC20Internal} from './IERC20Internal.sol';
      /**
       * @title ERC20 interface
       * @dev see https://github.com/ethereum/EIPs/issues/20
       */
      interface IERC20 is IERC20Internal {
        /**
         * @notice query the total minted token supply
         * @return token supply
         */
        function totalSupply () external view returns (uint256);
        /**
         * @notice query the token balance of given account
         * @param account address to query
         * @return token balance
         */
        function balanceOf (
          address account
        ) external view returns (uint256);
        /**
         * @notice query the allowance granted from given holder to given spender
         * @param holder approver of allowance
         * @param spender recipient of allowance
         * @return token allowance
         */
        function allowance (
          address holder,
          address spender
        ) external view returns (uint256);
        /**
         * @notice grant approval to spender to spend tokens
         * @dev prefer ERC20Extended functions to avoid transaction-ordering vulnerability (see https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729)
         * @param spender recipient of allowance
         * @param amount quantity of tokens approved for spending
         * @return success status (always true; otherwise function should revert)
         */
        function approve (
          address spender,
          uint256 amount
        ) external returns (bool);
        /**
         * @notice transfer tokens to given recipient
         * @param recipient beneficiary of token transfer
         * @param amount quantity of tokens to transfer
         * @return success status (always true; otherwise function should revert)
         */
        function transfer (
          address recipient,
          uint256 amount
        ) external returns (bool);
        /**
         * @notice transfer tokens to given recipient on behalf of given holder
         * @param holder holder of tokens prior to transfer
         * @param recipient beneficiary of token transfer
         * @param amount quantity of tokens to transfer
         * @return success status (always true; otherwise function should revert)
         */
        function transferFrom (
          address holder,
          address recipient,
          uint256 amount
        ) external returns (bool);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @title Partial ERC20 interface needed by internal functions
       */
      interface IERC20Internal {
        event Transfer(
          address indexed from,
          address indexed to,
          uint256 value
        );
        event Approval(
          address indexed owner,
          address indexed spender,
          uint256 value
        );
      }
      

      File 2 of 3: MagicProxy
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import '@solidstate/contracts/proxy/diamond/Diamond.sol';
      import '@solidstate/contracts/token/ERC20/metadata/ERC20MetadataStorage.sol';
      contract MagicProxy is Diamond {
          constructor() {
              ERC20MetadataStorage.Layout storage l = ERC20MetadataStorage.layout();
              l.name = 'MAGIC';
              l.symbol = 'MAGIC';
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import {SafeOwnable, OwnableStorage, Ownable} from '../../access/SafeOwnable.sol';
      import {IERC173} from '../../access/IERC173.sol';
      import {ERC165, IERC165, ERC165Storage} from '../../introspection/ERC165.sol';
      import {DiamondBase, DiamondBaseStorage} from './DiamondBase.sol';
      import {DiamondCuttable, IDiamondCuttable} from './DiamondCuttable.sol';
      import {DiamondLoupe, IDiamondLoupe} from './DiamondLoupe.sol';
      /**
       * @notice SolidState "Diamond" proxy reference implementation
       */
      abstract contract Diamond is DiamondBase, DiamondCuttable, DiamondLoupe, SafeOwnable, ERC165 {
        using DiamondBaseStorage for DiamondBaseStorage.Layout;
        using ERC165Storage for ERC165Storage.Layout;
        using OwnableStorage for OwnableStorage.Layout;
        constructor () {
          ERC165Storage.Layout storage erc165 = ERC165Storage.layout();
          bytes4[] memory selectors = new bytes4[](12);
          // register DiamondCuttable
          selectors[0] = IDiamondCuttable.diamondCut.selector;
          erc165.setSupportedInterface(type(IDiamondCuttable).interfaceId, true);
          // register DiamondLoupe
          selectors[1] = IDiamondLoupe.facets.selector;
          selectors[2] = IDiamondLoupe.facetFunctionSelectors.selector;
          selectors[3] = IDiamondLoupe.facetAddresses.selector;
          selectors[4] = IDiamondLoupe.facetAddress.selector;
          erc165.setSupportedInterface(type(IDiamondLoupe).interfaceId, true);
          // register ERC165
          selectors[5] = IERC165.supportsInterface.selector;
          erc165.setSupportedInterface(type(IERC165).interfaceId, true);
          // register SafeOwnable
          selectors[6] = Ownable.owner.selector;
          selectors[7] = SafeOwnable.nomineeOwner.selector;
          selectors[8] = SafeOwnable.transferOwnership.selector;
          selectors[9] = SafeOwnable.acceptOwnership.selector;
          erc165.setSupportedInterface(type(IERC173).interfaceId, true);
          // register Diamond
          selectors[10] = Diamond.getFallbackAddress.selector;
          selectors[11] = Diamond.setFallbackAddress.selector;
          // diamond cut
          FacetCut[] memory facetCuts = new FacetCut[](1);
          facetCuts[0] = FacetCut({
            target: address(this),
            action: IDiamondCuttable.FacetCutAction.ADD,
            selectors: selectors
          });
          DiamondBaseStorage.layout().diamondCut(facetCuts, address(0), '');
          // set owner
          OwnableStorage.layout().setOwner(msg.sender);
        }
        receive () external payable {}
        /**
         * @notice get the address of the fallback contract
         * @return fallback address
         */
        function getFallbackAddress () external view returns (address) {
          return DiamondBaseStorage.layout().fallbackAddress;
        }
        /**
         * @notice set the address of the fallback contract
         * @param fallbackAddress fallback address
         */
        function setFallbackAddress (
          address fallbackAddress
        ) external onlyOwner {
          DiamondBaseStorage.layout().fallbackAddress = fallbackAddress;
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      library ERC20MetadataStorage {
        struct Layout {
          string name;
          string symbol;
          uint8 decimals;
        }
        bytes32 internal constant STORAGE_SLOT = keccak256(
          'solidstate.contracts.storage.ERC20Metadata'
        );
        function layout () internal pure returns (Layout storage l) {
          bytes32 slot = STORAGE_SLOT;
          assembly { l.slot := slot }
        }
        function setName (
          Layout storage l,
          string memory name
        ) internal {
          l.name = name;
        }
        function setSymbol (
          Layout storage l,
          string memory symbol
        ) internal {
          l.symbol = symbol;
        }
        function setDecimals (
          Layout storage l,
          uint8 decimals
        ) internal {
          l.decimals = decimals;
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import {Ownable, OwnableStorage} from './Ownable.sol';
      import {SafeOwnableInternal} from './SafeOwnableInternal.sol';
      import {SafeOwnableStorage} from './SafeOwnableStorage.sol';
      /**
       * @title Ownership access control based on ERC173 with ownership transfer safety check
       */
      abstract contract SafeOwnable is Ownable, SafeOwnableInternal {
        using OwnableStorage for OwnableStorage.Layout;
        using SafeOwnableStorage for SafeOwnableStorage.Layout;
        function nomineeOwner () virtual public view returns (address) {
          return SafeOwnableStorage.layout().nomineeOwner;
        }
        /**
         * @inheritdoc Ownable
         * @dev ownership transfer must be accepted by beneficiary before transfer is complete
         */
        function transferOwnership (
          address account
        ) virtual override public onlyOwner {
          SafeOwnableStorage.layout().setNomineeOwner(account);
        }
        /**
         * @notice accept transfer of contract ownership
         */
        function acceptOwnership () virtual public onlyNomineeOwner {
          OwnableStorage.Layout storage l = OwnableStorage.layout();
          emit OwnershipTransferred(l.owner, msg.sender);
          l.setOwner(msg.sender);
          SafeOwnableStorage.layout().setNomineeOwner(address(0));
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @title Contract ownership standard interface
       * @dev see https://eips.ethereum.org/EIPS/eip-173
       */
      interface IERC173 {
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        /**
         * @notice get the ERC173 contract owner
         * @return conract owner
         */
        function owner () external view returns (address);
        /**
         * @notice transfer contract ownership to new account
         * @param account address of new owner
         */
        function transferOwnership (address account) external;
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import {IERC165} from './IERC165.sol';
      import {ERC165Storage} from './ERC165Storage.sol';
      /**
       * @title ERC165 implementation
       */
      abstract contract ERC165 is IERC165 {
        using ERC165Storage for ERC165Storage.Layout;
        /**
         * @inheritdoc IERC165
         */
        function supportsInterface (bytes4 interfaceId) override public view returns (bool) {
          return ERC165Storage.layout().isSupportedInterface(interfaceId);
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import {Proxy} from '../Proxy.sol';
      import {DiamondBaseStorage} from './DiamondBaseStorage.sol';
      import {IDiamondLoupe} from './IDiamondLoupe.sol';
      import {IDiamondCuttable} from './IDiamondCuttable.sol';
      /**
       * @title EIP-2535 "Diamond" proxy base contract
       * @dev see https://eips.ethereum.org/EIPS/eip-2535
       */
      abstract contract DiamondBase is Proxy {
        /**
         * @inheritdoc Proxy
         */
        function _getImplementation () override internal view returns (address) {
          // inline storage layout retrieval uses less gas
          DiamondBaseStorage.Layout storage l;
          bytes32 slot = DiamondBaseStorage.STORAGE_SLOT;
          assembly { l.slot := slot }
          address implementation = address(bytes20(l.facets[msg.sig]));
          if (implementation == address(0)) {
            implementation = l.fallbackAddress;
            require(
              implementation != address(0),
              'DiamondBase: no facet found for function signature'
            );
          }
          return implementation;
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import {OwnableInternal} from '../../access/OwnableInternal.sol';
      import {IDiamondCuttable} from './IDiamondCuttable.sol';
      import {DiamondBaseStorage} from './DiamondBaseStorage.sol';
      /**
       * @title EIP-2535 "Diamond" proxy update contract
       */
      abstract contract DiamondCuttable is IDiamondCuttable, OwnableInternal {
        using DiamondBaseStorage for DiamondBaseStorage.Layout;
        /**
         * @notice update functions callable on Diamond proxy
         * @param facetCuts array of structured Diamond facet update data
         * @param target optional recipient of initialization delegatecall
         * @param data optional initialization call data
         */
        function diamondCut (
          FacetCut[] calldata facetCuts,
          address target,
          bytes calldata data
        ) external override onlyOwner {
          DiamondBaseStorage.layout().diamondCut(facetCuts, target, data);
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import {DiamondBaseStorage} from './DiamondBaseStorage.sol';
      import {IDiamondLoupe} from './IDiamondLoupe.sol';
      /**
       * @title EIP-2535 "Diamond" proxy introspection contract
       * @dev derived from https://github.com/mudgen/diamond-2 (MIT license)
       */
      abstract contract DiamondLoupe is IDiamondLoupe {
        /**
         * @inheritdoc IDiamondLoupe
         */
        function facets () external override view returns (Facet[] memory diamondFacets) {
          DiamondBaseStorage.Layout storage l = DiamondBaseStorage.layout();
          diamondFacets = new Facet[](l.selectorCount);
          uint8[] memory numFacetSelectors = new uint8[](l.selectorCount);
          uint256 numFacets;
          uint256 selectorIndex;
          // loop through function selectors
          for (uint256 slotIndex; selectorIndex < l.selectorCount; slotIndex++) {
            bytes32 slot = l.selectorSlots[slotIndex];
            for (uint256 selectorSlotIndex; selectorSlotIndex < 8; selectorSlotIndex++) {
              selectorIndex++;
              if (selectorIndex > l.selectorCount) {
                break;
              }
              bytes4 selector = bytes4(slot << (selectorSlotIndex << 5));
              address facet = address(bytes20(l.facets[selector]));
              bool continueLoop;
              for (uint256 facetIndex; facetIndex < numFacets; facetIndex++) {
                if (diamondFacets[facetIndex].target == facet) {
                  diamondFacets[facetIndex].selectors[numFacetSelectors[facetIndex]] = selector;
                  // probably will never have more than 256 functions from one facet contract
                  require(numFacetSelectors[facetIndex] < 255);
                  numFacetSelectors[facetIndex]++;
                  continueLoop = true;
                  break;
                }
              }
              if (continueLoop) {
                continue;
              }
              diamondFacets[numFacets].target = facet;
              diamondFacets[numFacets].selectors = new bytes4[](l.selectorCount);
              diamondFacets[numFacets].selectors[0] = selector;
              numFacetSelectors[numFacets] = 1;
              numFacets++;
            }
          }
          for (uint256 facetIndex; facetIndex < numFacets; facetIndex++) {
            uint256 numSelectors = numFacetSelectors[facetIndex];
            bytes4[] memory selectors = diamondFacets[facetIndex].selectors;
            // setting the number of selectors
            assembly { mstore(selectors, numSelectors) }
          }
          // setting the number of facets
          assembly { mstore(diamondFacets, numFacets) }
        }
        /**
         * @inheritdoc IDiamondLoupe
         */
        function facetFunctionSelectors (
          address facet
        ) external override view returns (bytes4[] memory selectors) {
          DiamondBaseStorage.Layout storage l = DiamondBaseStorage.layout();
          selectors = new bytes4[](l.selectorCount);
          uint256 numSelectors;
          uint256 selectorIndex;
          // loop through function selectors
          for (uint256 slotIndex; selectorIndex < l.selectorCount; slotIndex++) {
            bytes32 slot = l.selectorSlots[slotIndex];
            for (uint256 selectorSlotIndex; selectorSlotIndex < 8; selectorSlotIndex++) {
              selectorIndex++;
              if (selectorIndex > l.selectorCount) {
                break;
              }
              bytes4 selector = bytes4(slot << (selectorSlotIndex << 5));
              if (facet == address(bytes20(l.facets[selector]))) {
                selectors[numSelectors] = selector;
                numSelectors++;
              }
            }
          }
          // set the number of selectors in the array
          assembly { mstore(selectors, numSelectors) }
        }
        /**
         * @inheritdoc IDiamondLoupe
         */
        function facetAddresses () external override view returns (address[] memory addresses) {
          DiamondBaseStorage.Layout storage l = DiamondBaseStorage.layout();
          addresses = new address[](l.selectorCount);
          uint256 numFacets;
          uint256 selectorIndex;
          for (uint256 slotIndex; selectorIndex < l.selectorCount; slotIndex++) {
            bytes32 slot = l.selectorSlots[slotIndex];
            for (uint256 selectorSlotIndex; selectorSlotIndex < 8; selectorSlotIndex++) {
              selectorIndex++;
              if (selectorIndex > l.selectorCount) {
                break;
              }
              bytes4 selector = bytes4(slot << (selectorSlotIndex << 5));
              address facet = address(bytes20(l.facets[selector]));
              bool continueLoop;
              for (uint256 facetIndex; facetIndex < numFacets; facetIndex++) {
                if (facet == addresses[facetIndex]) {
                  continueLoop = true;
                  break;
                }
              }
              if (continueLoop) {
                continue;
              }
              addresses[numFacets] = facet;
              numFacets++;
            }
          }
          // set the number of facet addresses in the array
          assembly { mstore(addresses, numFacets) }
        }
        /**
         * @inheritdoc IDiamondLoupe
         */
        function facetAddress (
          bytes4 selector
        ) external override view returns (address facet) {
          facet = address(bytes20(
            DiamondBaseStorage.layout().facets[selector]
          ));
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import {IERC173} from './IERC173.sol';
      import {OwnableInternal} from './OwnableInternal.sol';
      import {OwnableStorage} from './OwnableStorage.sol';
      /**
       * @title Ownership access control based on ERC173
       */
      abstract contract Ownable is IERC173, OwnableInternal {
        using OwnableStorage for OwnableStorage.Layout;
        /**
         * @inheritdoc IERC173
         */
        function owner () virtual override public view returns (address) {
          return OwnableStorage.layout().owner;
        }
        /**
         * @inheritdoc IERC173
         */
        function transferOwnership (
          address account
        ) virtual override public onlyOwner {
          OwnableStorage.layout().setOwner(account);
          emit OwnershipTransferred(msg.sender, account);
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import {SafeOwnableStorage} from './SafeOwnableStorage.sol';
      abstract contract SafeOwnableInternal {
        using SafeOwnableStorage for SafeOwnableStorage.Layout;
        modifier onlyNomineeOwner () {
          require(
            msg.sender == SafeOwnableStorage.layout().nomineeOwner,
            'SafeOwnable: sender must be nominee owner'
          );
          _;
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      library SafeOwnableStorage {
        struct Layout {
          address nomineeOwner;
        }
        bytes32 internal constant STORAGE_SLOT = keccak256(
          'solidstate.contracts.storage.SafeOwnable'
        );
        function layout () internal pure returns (Layout storage l) {
          bytes32 slot = STORAGE_SLOT;
          assembly { l.slot := slot }
        }
        function setNomineeOwner (
          Layout storage l,
          address nomineeOwner
        ) internal {
          l.nomineeOwner = nomineeOwner;
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import {OwnableStorage} from './OwnableStorage.sol';
      abstract contract OwnableInternal {
        using OwnableStorage for OwnableStorage.Layout;
        modifier onlyOwner {
          require(
            msg.sender == OwnableStorage.layout().owner,
            'Ownable: sender must be owner'
          );
          _;
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      library OwnableStorage {
        struct Layout {
          address owner;
        }
        bytes32 internal constant STORAGE_SLOT = keccak256(
          'solidstate.contracts.storage.Ownable'
        );
        function layout () internal pure returns (Layout storage l) {
          bytes32 slot = STORAGE_SLOT;
          assembly { l.slot := slot }
        }
        function setOwner (
          Layout storage l,
          address owner
        ) internal {
          l.owner = owner;
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @title ERC165 interface registration interface
       * @dev see https://eips.ethereum.org/EIPS/eip-165
       */
      interface IERC165 {
        /**
         * @notice query whether contract has registered support for given interface
         * @param interfaceId interface id
         * @return bool whether interface is supported
         */
        function supportsInterface (
          bytes4 interfaceId
        ) external view returns (bool);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      library ERC165Storage {
        struct Layout {
          // TODO: use EnumerableSet to allow post-diamond-cut auditing
          mapping (bytes4 => bool) supportedInterfaces;
        }
        bytes32 internal constant STORAGE_SLOT = keccak256(
          'solidstate.contracts.storage.ERC165'
        );
        function layout () internal pure returns (Layout storage l) {
          bytes32 slot = STORAGE_SLOT;
          assembly { l.slot := slot }
        }
        function isSupportedInterface (
          Layout storage l,
          bytes4 interfaceId
        ) internal view returns (bool) {
          return l.supportedInterfaces[interfaceId];
        }
        function setSupportedInterface (
          Layout storage l,
          bytes4 interfaceId,
          bool status
        ) internal {
          require(interfaceId != 0xffffffff, 'ERC165: invalid interface id');
          l.supportedInterfaces[interfaceId] = status;
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import {AddressUtils} from '../utils/AddressUtils.sol';
      /**
       * @title Base proxy contract
       */
      abstract contract Proxy {
        using AddressUtils for address;
        /**
         * @notice delegate all calls to implementation contract
         * @dev reverts if implementation address contains no code, for compatibility with metamorphic contracts
         * @dev memory location in use by assembly may be unsafe in other contexts
         */
        fallback () virtual external payable {
          address implementation = _getImplementation();
          require(
            implementation.isContract(),
            'Proxy: implementation must be contract'
          );
          assembly {
            calldatacopy(0, 0, calldatasize())
            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
            returndatacopy(0, 0, returndatasize())
            switch result
            case 0 { revert(0, returndatasize()) }
            default { return (0, returndatasize()) }
          }
        }
        /**
         * @notice get logic implementation address
         * @return implementation address
         */
        function _getImplementation () virtual internal returns (address);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import {AddressUtils} from '../../utils/AddressUtils.sol';
      import {IDiamondCuttable} from './IDiamondCuttable.sol';
      /**
       * @dev derived from https://github.com/mudgen/diamond-2 (MIT license)
       */
      library DiamondBaseStorage {
        using AddressUtils for address;
        using DiamondBaseStorage for DiamondBaseStorage.Layout;
        struct Layout {
          // function selector => (facet address, selector slot position)
          mapping (bytes4 => bytes32) facets;
          // total number of selectors registered
          uint16 selectorCount;
          // array of selector slots with 8 selectors per slot
          mapping (uint256 => bytes32) selectorSlots;
          address fallbackAddress;
        }
        bytes32 constant CLEAR_ADDRESS_MASK = bytes32(uint256(0xffffffffffffffffffffffff));
        bytes32 constant CLEAR_SELECTOR_MASK = bytes32(uint256(0xffffffff << 224));
        bytes32 internal constant STORAGE_SLOT = keccak256(
          'solidstate.contracts.storage.DiamondBase'
        );
        event DiamondCut (IDiamondCuttable.FacetCut[] facetCuts, address target, bytes data);
        function layout () internal pure returns (Layout storage l) {
          bytes32 slot = STORAGE_SLOT;
          assembly { l.slot := slot }
        }
        /**
         * @notice update functions callable on Diamond proxy
         * @param l storage layout
         * @param facetCuts array of structured Diamond facet update data
         * @param target optional recipient of initialization delegatecall
         * @param data optional initialization call data
         */
        function diamondCut(
          Layout storage l,
          IDiamondCuttable.FacetCut[] memory facetCuts,
          address target,
          bytes memory data
        ) internal {
          unchecked {
            uint256 originalSelectorCount = l.selectorCount;
            uint256 selectorCount = originalSelectorCount;
            bytes32 selectorSlot;
            // Check if last selector slot is not full
            if (selectorCount & 7 > 0) {
              // get last selectorSlot
              selectorSlot = l.selectorSlots[selectorCount >> 3];
            }
            for (uint256 i; i < facetCuts.length; i++) {
              IDiamondCuttable.FacetCut memory facetCut = facetCuts[i];
              IDiamondCuttable.FacetCutAction action = facetCut.action;
              require(
                facetCut.selectors.length > 0,
                'DiamondBase: no selectors specified'
              );
              if (action == IDiamondCuttable.FacetCutAction.ADD) {
                (selectorCount, selectorSlot) = l.addFacetSelectors(
                  selectorCount,
                  selectorSlot,
                  facetCut
                );
              } else if (action == IDiamondCuttable.FacetCutAction.REMOVE) {
                (selectorCount, selectorSlot) = l.removeFacetSelectors(
                  selectorCount,
                  selectorSlot,
                  facetCut
                );
              } else if (action == IDiamondCuttable.FacetCutAction.REPLACE) {
                l.replaceFacetSelectors(facetCut);
              }
            }
            if (selectorCount != originalSelectorCount) {
              l.selectorCount = uint16(selectorCount);
            }
            // If last selector slot is not full
            if (selectorCount & 7 > 0) {
              l.selectorSlots[selectorCount >> 3] = selectorSlot;
            }
            emit DiamondCut(facetCuts, target, data);
            initialize(target, data);
          }
        }
        function addFacetSelectors (
          Layout storage l,
          uint256 selectorCount,
          bytes32 selectorSlot,
          IDiamondCuttable.FacetCut memory facetCut
        ) internal returns (uint256, bytes32) {
          unchecked {
            require(
              facetCut.target == address(this) || facetCut.target.isContract(),
              'DiamondBase: ADD target has no code'
            );
            for (uint256 i; i < facetCut.selectors.length; i++) {
              bytes4 selector = facetCut.selectors[i];
              bytes32 oldFacet = l.facets[selector];
              require(
                address(bytes20(oldFacet)) == address(0),
                'DiamondBase: selector already added'
              );
              // add facet for selector
              l.facets[selector] = bytes20(facetCut.target) | bytes32(selectorCount);
              uint256 selectorInSlotPosition = (selectorCount & 7) << 5;
              // clear selector position in slot and add selector
              selectorSlot = (
                selectorSlot & ~(CLEAR_SELECTOR_MASK >> selectorInSlotPosition)
              ) | (bytes32(selector) >> selectorInSlotPosition);
              // if slot is full then write it to storage
              if (selectorInSlotPosition == 224) {
                l.selectorSlots[selectorCount >> 3] = selectorSlot;
                selectorSlot = 0;
              }
              selectorCount++;
            }
            return (selectorCount, selectorSlot);
          }
        }
        function removeFacetSelectors (
          Layout storage l,
          uint256 selectorCount,
          bytes32 selectorSlot,
          IDiamondCuttable.FacetCut memory facetCut
        ) internal returns (uint256, bytes32) {
          unchecked {
            require(
              facetCut.target == address(0),
              'DiamondBase: REMOVE target must be zero address'
            );
            uint256 selectorSlotCount = selectorCount >> 3;
            uint256 selectorInSlotIndex = selectorCount & 7;
            for (uint256 i; i < facetCut.selectors.length; i++) {
              bytes4 selector = facetCut.selectors[i];
              bytes32 oldFacet = l.facets[selector];
              require(
                address(bytes20(oldFacet)) != address(0),
                'DiamondBase: selector not found'
              );
              require(
                address(bytes20(oldFacet)) != address(this),
                'DiamondBase: selector is immutable'
              );
              if (selectorSlot == 0) {
                selectorSlotCount--;
                selectorSlot = l.selectorSlots[selectorSlotCount];
                selectorInSlotIndex = 7;
              } else {
                selectorInSlotIndex--;
              }
              bytes4 lastSelector;
              uint256 oldSelectorsSlotCount;
              uint256 oldSelectorInSlotPosition;
              // adding a block here prevents stack too deep error
              {
                // replace selector with last selector in l.facets
                lastSelector = bytes4(selectorSlot << (selectorInSlotIndex << 5));
                if (lastSelector != selector) {
                  // update last selector slot position info
                  l.facets[lastSelector] = (
                    oldFacet & CLEAR_ADDRESS_MASK
                  ) | bytes20(l.facets[lastSelector]);
                }
                delete l.facets[selector];
                uint256 oldSelectorCount = uint16(uint256(oldFacet));
                oldSelectorsSlotCount = oldSelectorCount >> 3;
                oldSelectorInSlotPosition = (oldSelectorCount & 7) << 5;
              }
              if (oldSelectorsSlotCount != selectorSlotCount) {
                bytes32 oldSelectorSlot = l.selectorSlots[oldSelectorsSlotCount];
                // clears the selector we are deleting and puts the last selector in its place.
                oldSelectorSlot = (
                  oldSelectorSlot & ~(CLEAR_SELECTOR_MASK >> oldSelectorInSlotPosition)
                ) | (bytes32(lastSelector) >> oldSelectorInSlotPosition);
                // update storage with the modified slot
                l.selectorSlots[oldSelectorsSlotCount] = oldSelectorSlot;
              } else {
                // clears the selector we are deleting and puts the last selector in its place.
                selectorSlot = (
                  selectorSlot & ~(CLEAR_SELECTOR_MASK >> oldSelectorInSlotPosition)
                ) | (bytes32(lastSelector) >> oldSelectorInSlotPosition);
              }
              if (selectorInSlotIndex == 0) {
                delete l.selectorSlots[selectorSlotCount];
                selectorSlot = 0;
              }
            }
            selectorCount = (selectorSlotCount << 3) | selectorInSlotIndex;
            return (selectorCount, selectorSlot);
          }
        }
        function replaceFacetSelectors (
          Layout storage l,
          IDiamondCuttable.FacetCut memory facetCut
        ) internal {
          unchecked {
            require(
              facetCut.target.isContract(),
              'DiamondBase: REPLACE target has no code'
            );
            for (uint256 i; i < facetCut.selectors.length; i++) {
              bytes4 selector = facetCut.selectors[i];
              bytes32 oldFacet = l.facets[selector];
              address oldFacetAddress = address(bytes20(oldFacet));
              require(
                oldFacetAddress != address(0),
                'DiamondBase: selector not found'
              );
              require(
                oldFacetAddress != address(this),
                'DiamondBase: selector is immutable'
              );
              require(
                oldFacetAddress != facetCut.target,
                'DiamondBase: REPLACE target is identical'
              );
              // replace old facet address
              l.facets[selector] = (oldFacet & CLEAR_ADDRESS_MASK) | bytes20(facetCut.target);
            }
          }
        }
        function initialize (
          address target,
          bytes memory data
        ) private {
          require(
            (target == address(0)) == (data.length == 0),
            'DiamondBase: invalid initialization parameters'
          );
          if (target != address(0)) {
            if (target != address(this)) {
              require(
                target.isContract(),
                'DiamondBase: initialization target has no code'
              );
            }
            (bool success, ) = target.delegatecall(data);
            if (!success) {
              assembly {
                returndatacopy(0, 0, returndatasize())
                revert(0, returndatasize())
              }
            }
          }
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @title Diamond proxy introspection interface
       * @dev see https://eips.ethereum.org/EIPS/eip-2535
       */
      interface IDiamondLoupe {
        struct Facet {
          address target;
          bytes4[] selectors;
        }
        /**
         * @notice get all facets and their selectors
         * @return diamondFacets array of structured facet data
         */
        function facets () external view returns (Facet[] memory diamondFacets);
        /**
         * @notice get all selectors for given facet address
         * @param facet address of facet to query
         * @return selectors array of function selectors
         */
        function facetFunctionSelectors (
          address facet
        ) external view returns (bytes4[] memory selectors);
        /**
         * @notice get addresses of all facets used by diamond
         * @return addresses array of facet addresses
         */
        function facetAddresses () external view returns (address[] memory addresses);
        /**
         * @notice get the address of the facet associated with given selector
         * @param selector function selector to query
         * @return facet facet address (zero address if not found)
         */
        function facetAddress (
          bytes4 selector
        ) external view returns (address facet);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @title Diamond proxy upgrade interface
       * @dev see https://eips.ethereum.org/EIPS/eip-2535
       */
      interface IDiamondCuttable {
        enum FacetCutAction { ADD, REPLACE, REMOVE }
        event DiamondCut (FacetCut[] facetCuts, address target, bytes data);
        struct FacetCut {
          address target;
          FacetCutAction action;
          bytes4[] selectors;
        }
        /**
         * @notice update diamond facets and optionally execute arbitrary initialization function
         * @param facetCuts facet addresses, actions, and function selectors
         * @param target initialization function target
         * @param data initialization function call data
         */
        function diamondCut (
          FacetCut[] calldata facetCuts,
          address target,
          bytes calldata data
        ) external;
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      library AddressUtils {
        function toString (address account) internal pure returns (string memory) {
          bytes32 value = bytes32(uint256(uint160(account)));
          bytes memory alphabet = '0123456789abcdef';
          bytes memory chars = new bytes(42);
          chars[0] = '0';
          chars[1] = 'x';
          for (uint256 i = 0; i < 20; i++) {
            chars[2 + i * 2] = alphabet[uint8(value[i + 12] >> 4)];
            chars[3 + i * 2] = alphabet[uint8(value[i + 12] & 0x0f)];
          }
          return string(chars);
        }
        function isContract (address account) internal view returns (bool) {
          uint size;
          assembly { size := extcodesize(account) }
          return size > 0;
        }
        function sendValue (address payable account, uint amount) internal {
          (bool success, ) = account.call{ value: amount }('');
          require(success, 'AddressUtils: failed to send value');
        }
        function functionCall (address target, bytes memory data) internal returns (bytes memory) {
          return functionCall(target, data, 'AddressUtils: failed low-level call');
        }
        function functionCall (address target, bytes memory data, string memory error) internal returns (bytes memory) {
          return _functionCallWithValue(target, data, 0, error);
        }
        function functionCallWithValue (address target, bytes memory data, uint value) internal returns (bytes memory) {
          return functionCallWithValue(target, data, value, 'AddressUtils: failed low-level call with value');
        }
        function functionCallWithValue (address target, bytes memory data, uint value, string memory error) internal returns (bytes memory) {
          require(address(this).balance >= value, 'AddressUtils: insufficient balance for call');
          return _functionCallWithValue(target, data, value, error);
        }
        function _functionCallWithValue (address target, bytes memory data, uint value, string memory error) private returns (bytes memory) {
          require(isContract(target), 'AddressUtils: function call to non-contract');
          (bool success, bytes memory returnData) = target.call{ value: value }(data);
          if (success) {
            return returnData;
          } else if (returnData.length > 0) {
            assembly {
              let returnData_size := mload(returnData)
              revert(add(32, returnData), returnData_size)
            }
          } else {
            revert(error);
          }
        }
      }
      

      File 3 of 3: MagicMintReentrancyFix
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import '@solidstate/contracts/token/ERC20/base/ERC20BaseInternal.sol';
      import '@solidstate/contracts/utils/ReentrancyGuard.sol';
      import './MagicWhitelistStorage.sol';
      contract MagicMintReentrancyFix is ERC20BaseInternal, ReentrancyGuard {
          function mint(address account, uint256 amount) external nonReentrant {
              require(
                  MagicWhitelistStorage.layout().whitelist[msg.sender],
                  'Magic: sender must be whitelisted'
              );
              _mint(account, amount);
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import {IERC20Internal} from '../IERC20Internal.sol';
      import {ERC20BaseStorage} from './ERC20BaseStorage.sol';
      /**
       * @title Base ERC20 implementation, excluding optional extensions
       */
      abstract contract ERC20BaseInternal is IERC20Internal {
        /**
         * @notice query the total minted token supply
         * @return token supply
         */
        function _totalSupply () virtual internal view returns (uint) {
          return ERC20BaseStorage.layout().totalSupply;
        }
        /**
         * @notice query the token balance of given account
         * @param account address to query
         * @return token balance
         */
        function _balanceOf (
          address account
        ) virtual internal view returns (uint) {
          return ERC20BaseStorage.layout().balances[account];
        }
        /**
         * @notice enable spender to spend tokens on behalf of holder
         * @param holder address on whose behalf tokens may be spent
         * @param spender recipient of allowance
         * @param amount quantity of tokens approved for spending
         */
        function _approve (
          address holder,
          address spender,
          uint amount
        ) virtual internal {
          require(holder != address(0), 'ERC20: approve from the zero address');
          require(spender != address(0), 'ERC20: approve to the zero address');
          ERC20BaseStorage.layout().allowances[holder][spender] = amount;
          emit Approval(holder, spender, amount);
        }
        /**
         * @notice mint tokens for given account
         * @param account recipient of minted tokens
         * @param amount quantity of tokens minted
         */
        function _mint (
          address account,
          uint amount
        ) virtual internal {
          require(account != address(0), 'ERC20: mint to the zero address');
          _beforeTokenTransfer(address(0), account, amount);
          ERC20BaseStorage.Layout storage l = ERC20BaseStorage.layout();
          l.totalSupply += amount;
          l.balances[account] += amount;
          emit Transfer(address(0), account, amount);
        }
        /**
         * @notice burn tokens held by given account
         * @param account holder of burned tokens
         * @param amount quantity of tokens burned
         */
        function _burn (
          address account,
          uint amount
        ) virtual internal {
          require(account != address(0), 'ERC20: burn from the zero address');
          _beforeTokenTransfer(account, address(0), amount);
          ERC20BaseStorage.Layout storage l = ERC20BaseStorage.layout();
          uint256 balance = l.balances[account];
          require(balance >= amount, "ERC20: burn amount exceeds balance");
          unchecked {
            l.balances[account] = balance - amount;
          }
          l.totalSupply -= amount;
          emit Transfer(account, address(0), amount);
        }
        /**
         * @notice transfer tokens from holder to recipient
         * @param holder owner of tokens to be transferred
         * @param recipient beneficiary of transfer
         * @param amount quantity of tokens transferred
         */
        function _transfer (
          address holder,
          address recipient,
          uint amount
        ) virtual internal {
          require(holder != address(0), 'ERC20: transfer from the zero address');
          require(recipient != address(0), 'ERC20: transfer to the zero address');
          _beforeTokenTransfer(holder, recipient, amount);
          ERC20BaseStorage.Layout storage l = ERC20BaseStorage.layout();
          uint256 holderBalance = l.balances[holder];
          require(holderBalance >= amount, 'ERC20: transfer amount exceeds balance');
          unchecked {
            l.balances[holder] = holderBalance - amount;
          }
          l.balances[recipient] += amount;
          emit Transfer(holder, recipient, amount);
        }
        /**
         * @notice ERC20 hook, called before all transfers including mint and burn
         * @dev function should be overridden and new implementation must call super
         * @param from sender of tokens
         * @param to receiver of tokens
         * @param amount quantity of tokens transferred
         */
        function _beforeTokenTransfer (
          address from,
          address to,
          uint amount
        ) virtual internal {}
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      import {ReentrancyGuardStorage} from './ReentrancyGuardStorage.sol';
      /**
       * @title Utility contract for preventing reentrancy attacks
       */
      abstract contract ReentrancyGuard {
        modifier nonReentrant () {
          ReentrancyGuardStorage.Layout storage l = ReentrancyGuardStorage.layout();
          require(l.status != 2, 'ReentrancyGuard: reentrant call');
          l.status = 2;
          _;
          l.status = 1;
        }
      }
      // SPDX-License-Identifier: UNLICENSED
      pragma solidity ^0.8.0;
      library MagicWhitelistStorage {
          struct Layout {
              mapping(address => bool) whitelist;
          }
          bytes32 internal constant STORAGE_SLOT =
              keccak256('treasure.contracts.storage.MagicWhitelist');
          function layout() internal pure returns (Layout storage l) {
              bytes32 slot = STORAGE_SLOT;
              assembly {
                  l.slot := slot
              }
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      /**
       * @title Partial ERC20 interface needed by internal functions
       */
      interface IERC20Internal {
        event Transfer(
          address indexed from,
          address indexed to,
          uint256 value
        );
        event Approval(
          address indexed owner,
          address indexed spender,
          uint256 value
        );
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      library ERC20BaseStorage {
        struct Layout {
          mapping (address => uint) balances;
          mapping (address => mapping (address => uint)) allowances;
          uint totalSupply;
        }
        bytes32 internal constant STORAGE_SLOT = keccak256(
          'solidstate.contracts.storage.ERC20Base'
        );
        function layout () internal pure returns (Layout storage l) {
          bytes32 slot = STORAGE_SLOT;
          assembly { l.slot := slot }
        }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.0;
      library ReentrancyGuardStorage {
        struct Layout {
          uint status;
        }
        bytes32 internal constant STORAGE_SLOT = keccak256(
          'solidstate.contracts.storage.ReentrancyGuard'
        );
        function layout () internal pure returns (Layout storage l) {
          bytes32 slot = STORAGE_SLOT;
          assembly { l.slot := slot }
        }
      }