Contract

0xbADb86BA8A4D0740C1b0DE8a24e92c060131B55c

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

-

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ConcatMowseWearDictionaryImageFacet

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 17 : ConcatMowseWearDictionaryImageFacet.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "hardhat/console.sol";
/*************************************************************************
___  ___                       
|  \/  |                                          ___
| .  . | _____      _____  ___           _  _  .-'   '-.
| |\/| |/ _ \ \ /\ / / __|/ _ \         (.)(.)/         \   
| |  | | (_) \ V  V /\__ \  __/          /@@             ;
\_|  |_/\___/ \_/\_/ |___/\___|         o_\\-mm-......-mm`~~~~~~~~~~~~~~~~` 
															 
/*************************************************************************/

import "@openzeppelin/contracts/utils/Strings.sol";

import {LibDiamond} from "../libraries/LibDiamond.sol";

import {GameStorage, MowseWear, MowseSkillTypes, MowseWearMetadata, SKILL_TYPE_NUM, EQUIPPED_WEARABLE_SLOTS} from "../libraries/LibStorage.sol";

import {AccessControlFacet} from "./AccessControlFacet.sol";

import "./../libraries/LibStorage.sol";

contract ConcatMowseWearDictionaryImageFacet {
    using Strings for uint256;
    using Strings for uint8;
    using Strings for bool;
    GameStorage internal gs;

    error MissingAdminRole(string);
    error InvalidDictionaryIndex(uint256 dictionaryIndex);
    error CannotFindMowseWear(uint8 traitType, uint16 traitIndex);

    modifier onlyAdmin() {
        if (!AccessControlFacet(gs.diamondAddress).hasMowseAdminRole(msg.sender)) revert MissingAdminRole("Must have Admin Role");
        _;
    }

    // Used to concat the image of a MowseWear in the dictionary
    function concatMowseWearDictionaryImage(uint8 traitType, uint16 traitIndex, uint256 dictionaryIndex, string memory image) external onlyAdmin {
        if (bytes(gs.mowseWearDictionary[traitType][traitIndex].traitName).length == 0) revert CannotFindMowseWear(traitType, traitIndex);
        if (dictionaryIndex >= gs.mowseWearDictionaryCount) revert InvalidDictionaryIndex(dictionaryIndex);

        gs.mowseWearDictionary[traitType][traitIndex].baseDimensions.image = string(
          abi.encodePacked(gs.mowseWearDictionary[traitType][traitIndex].baseDimensions.image, image)
        );
        gs.mowseWearDictionaryByDictionaryIndex[dictionaryIndex].baseDimensions.image = string(
          abi.encodePacked(gs.mowseWearDictionaryByDictionaryIndex[dictionaryIndex].baseDimensions.image, image)
        );
    }
}

File 2 of 17 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

File 3 of 17 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

File 4 of 17 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";
import "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toString(int256 value) internal pure returns (string memory) {
        return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

File 5 of 17 : AccessControl.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IAccessControl } from './IAccessControl.sol';
import { AccessControlInternal } from './AccessControlInternal.sol';

/**
 * @title Role-based access control system
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
 */
abstract contract AccessControl is IAccessControl, AccessControlInternal {
    /**
     * @inheritdoc IAccessControl
     */
    function grantRole(
        bytes32 role,
        address account
    ) external onlyRole(_getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @inheritdoc IAccessControl
     */
    function hasRole(
        bytes32 role,
        address account
    ) external view returns (bool) {
        return _hasRole(role, account);
    }

    /**
     * @inheritdoc IAccessControl
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32) {
        return _getRoleAdmin(role);
    }

    /**
     * @inheritdoc IAccessControl
     */
    function revokeRole(
        bytes32 role,
        address account
    ) external onlyRole(_getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @inheritdoc IAccessControl
     */
    function renounceRole(bytes32 role) external {
        _renounceRole(role);
    }
}

File 6 of 17 : AccessControlInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { EnumerableSet } from '../../data/EnumerableSet.sol';
import { AddressUtils } from '../../utils/AddressUtils.sol';
import { UintUtils } from '../../utils/UintUtils.sol';
import { IAccessControlInternal } from './IAccessControlInternal.sol';
import { AccessControlStorage } from './AccessControlStorage.sol';

/**
 * @title Role-based access control system
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
 */
abstract contract AccessControlInternal is IAccessControlInternal {
    using AddressUtils for address;
    using EnumerableSet for EnumerableSet.AddressSet;
    using UintUtils for uint256;

    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /*
     * @notice query whether role is assigned to account
     * @param role role to query
     * @param account account to query
     * @return whether role is assigned to account
     */
    function _hasRole(
        bytes32 role,
        address account
    ) internal view virtual returns (bool) {
        return
            AccessControlStorage.layout().roles[role].members.contains(account);
    }

    /**
     * @notice revert if sender does not have given role
     * @param role role to query
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, msg.sender);
    }

    /**
     * @notice revert if given account does not have given role
     * @param role role to query
     * @param account to query
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!_hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        'AccessControl: account ',
                        account.toString(),
                        ' is missing role ',
                        uint256(role).toHexString(32)
                    )
                )
            );
        }
    }

    /*
     * @notice query admin role for given role
     * @param role role to query
     * @return admin role
     */
    function _getRoleAdmin(
        bytes32 role
    ) internal view virtual returns (bytes32) {
        return AccessControlStorage.layout().roles[role].adminRole;
    }

    /**
     * @notice set role as admin role
     * @param role role to set
     * @param adminRole admin role to set
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = _getRoleAdmin(role);
        AccessControlStorage.layout().roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /*
     * @notice assign role to given account
     * @param role role to assign
     * @param account recipient of role assignment
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        AccessControlStorage.layout().roles[role].members.add(account);
        emit RoleGranted(role, account, msg.sender);
    }

    /*
     * @notice unassign role from given account
     * @param role role to unassign
     * @parm account
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        AccessControlStorage.layout().roles[role].members.remove(account);
        emit RoleRevoked(role, account, msg.sender);
    }

    /**
     * @notice relinquish role
     * @param role role to relinquish
     */
    function _renounceRole(bytes32 role) internal virtual {
        _revokeRole(role, msg.sender);
    }
}

File 7 of 17 : AccessControlStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { EnumerableSet } from '../../data/EnumerableSet.sol';

library AccessControlStorage {
    struct RoleData {
        EnumerableSet.AddressSet members;
        bytes32 adminRole;
    }

    struct Layout {
        mapping(bytes32 => RoleData) roles;
    }

    bytes32 internal constant DEFAULT_ADMIN_ROLE = 0x00;

    bytes32 internal constant STORAGE_SLOT =
        keccak256('solidstate.contracts.storage.AccessControl');

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }
}

File 8 of 17 : IAccessControl.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IAccessControlInternal } from './IAccessControlInternal.sol';

/**
 * @title AccessControl interface
 */
interface IAccessControl is IAccessControlInternal {
    /*
     * @notice query whether role is assigned to account
     * @param role role to query
     * @param account account to query
     * @return whether role is assigned to account
     */
    function hasRole(
        bytes32 role,
        address account
    ) external view returns (bool);

    /*
     * @notice query admin role for given role
     * @param role role to query
     * @return admin role
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /*
     * @notice assign role to given account
     * @param role role to assign
     * @param account recipient of role assignment
     */
    function grantRole(bytes32 role, address account) external;

    /*
     * @notice unassign role from given account
     * @param role role to unassign
     * @parm account
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @notice relinquish role
     * @param role role to relinquish
     */
    function renounceRole(bytes32 role) external;
}

File 9 of 17 : IAccessControlInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title Partial AccessControl interface needed by internal functions
 */
interface IAccessControlInternal {
    event RoleAdminChanged(
        bytes32 indexed role,
        bytes32 indexed previousAdminRole,
        bytes32 indexed newAdminRole
    );

    event RoleGranted(
        bytes32 indexed role,
        address indexed account,
        address indexed sender
    );

    event RoleRevoked(
        bytes32 indexed role,
        address indexed account,
        address indexed sender
    );
}

File 10 of 17 : EnumerableSet.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

/**
 * @title Set implementation with enumeration functions
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
 */
library EnumerableSet {
    error EnumerableSet__IndexOutOfBounds();

    struct Set {
        bytes32[] _values;
        // 1-indexed to allow 0 to signify nonexistence
        mapping(bytes32 => uint256) _indexes;
    }

    struct Bytes32Set {
        Set _inner;
    }

    struct AddressSet {
        Set _inner;
    }

    struct UintSet {
        Set _inner;
    }

    function at(
        Bytes32Set storage set,
        uint256 index
    ) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    function at(
        AddressSet storage set,
        uint256 index
    ) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    function at(
        UintSet storage set,
        uint256 index
    ) internal view returns (uint256) {
        return uint256(_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(uint256(uint160(value))));
    }

    function contains(
        UintSet storage set,
        uint256 value
    ) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    function indexOf(
        Bytes32Set storage set,
        bytes32 value
    ) internal view returns (uint256) {
        return _indexOf(set._inner, value);
    }

    function indexOf(
        AddressSet storage set,
        address value
    ) internal view returns (uint256) {
        return _indexOf(set._inner, bytes32(uint256(uint160(value))));
    }

    function indexOf(
        UintSet storage set,
        uint256 value
    ) internal view returns (uint256) {
        return _indexOf(set._inner, bytes32(value));
    }

    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    function length(UintSet storage set) internal view returns (uint256) {
        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(uint256(uint160(value))));
    }

    function add(UintSet storage set, uint256 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(uint256(uint160(value))));
    }

    function remove(
        UintSet storage set,
        uint256 value
    ) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    function toArray(
        Bytes32Set storage set
    ) internal view returns (bytes32[] memory) {
        return set._inner._values;
    }

    function toArray(
        AddressSet storage set
    ) internal view returns (address[] memory) {
        bytes32[] storage values = set._inner._values;
        address[] storage array;

        assembly {
            array.slot := values.slot
        }

        return array;
    }

    function toArray(
        UintSet storage set
    ) internal view returns (uint256[] memory) {
        bytes32[] storage values = set._inner._values;
        uint256[] storage array;

        assembly {
            array.slot := values.slot
        }

        return array;
    }

    function _at(
        Set storage set,
        uint256 index
    ) private view returns (bytes32) {
        if (index >= set._values.length)
            revert EnumerableSet__IndexOutOfBounds();
        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 (uint256) {
        unchecked {
            return set._indexes[value] - 1;
        }
    }

    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    function _add(
        Set storage set,
        bytes32 value
    ) private returns (bool status) {
        if (!_contains(set, value)) {
            set._values.push(value);
            set._indexes[value] = set._values.length;
            status = true;
        }
    }

    function _remove(
        Set storage set,
        bytes32 value
    ) private returns (bool status) {
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            unchecked {
                bytes32 last = set._values[set._values.length - 1];

                // move last value to now-vacant index

                set._values[valueIndex - 1] = last;
                set._indexes[last] = valueIndex;
            }
            // clear last index

            set._values.pop();
            delete set._indexes[value];

            status = true;
        }
    }
}

File 11 of 17 : AddressUtils.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { UintUtils } from './UintUtils.sol';

library AddressUtils {
    using UintUtils for uint256;

    error AddressUtils__InsufficientBalance();
    error AddressUtils__NotContract();
    error AddressUtils__SendValueFailed();

    function toString(address account) internal pure returns (string memory) {
        return uint256(uint160(account)).toHexString(20);
    }

    function isContract(address account) internal view returns (bool) {
        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

    function sendValue(address payable account, uint256 amount) internal {
        (bool success, ) = account.call{ value: amount }('');
        if (!success) revert AddressUtils__SendValueFailed();
    }

    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,
        uint256 value
    ) internal returns (bytes memory) {
        return
            functionCallWithValue(
                target,
                data,
                value,
                'AddressUtils: failed low-level call with value'
            );
    }

    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory error
    ) internal returns (bytes memory) {
        if (value > address(this).balance)
            revert AddressUtils__InsufficientBalance();
        return _functionCallWithValue(target, data, value, error);
    }

    /**
     * @notice execute arbitrary external call with limited gas usage and amount of copied return data
     * @dev derived from https://github.com/nomad-xyz/ExcessivelySafeCall (MIT License)
     * @param target recipient of call
     * @param gasAmount gas allowance for call
     * @param value native token value to include in call
     * @param maxCopy maximum number of bytes to copy from return data
     * @param data encoded call data
     * @return success whether call is successful
     * @return returnData copied return data
     */
    function excessivelySafeCall(
        address target,
        uint256 gasAmount,
        uint256 value,
        uint16 maxCopy,
        bytes memory data
    ) internal returns (bool success, bytes memory returnData) {
        returnData = new bytes(maxCopy);

        assembly {
            // execute external call via assembly to avoid automatic copying of return data
            success := call(
                gasAmount,
                target,
                value,
                add(data, 0x20),
                mload(data),
                0,
                0
            )

            // determine whether to limit amount of data to copy
            let toCopy := returndatasize()

            if gt(toCopy, maxCopy) {
                toCopy := maxCopy
            }

            // store the length of the copied bytes
            mstore(returnData, toCopy)

            // copy the bytes from returndata[0:toCopy]
            returndatacopy(add(returnData, 0x20), 0, toCopy)
        }
    }

    function _functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory error
    ) private returns (bytes memory) {
        if (!isContract(target)) revert AddressUtils__NotContract();

        (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 12 of 17 : UintUtils.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

/**
 * @title utility functions for uint256 operations
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license)
 */
library UintUtils {
    error UintUtils__InsufficientHexLength();

    bytes16 private constant HEX_SYMBOLS = '0123456789abcdef';

    function add(uint256 a, int256 b) internal pure returns (uint256) {
        return b < 0 ? sub(a, -b) : a + uint256(b);
    }

    function sub(uint256 a, int256 b) internal pure returns (uint256) {
        return b < 0 ? add(a, -b) : a - uint256(b);
    }

    function toString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return '0';
        }

        uint256 temp = value;
        uint256 digits;

        while (temp != 0) {
            digits++;
            temp /= 10;
        }

        bytes memory buffer = new bytes(digits);

        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }

        return string(buffer);
    }

    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return '0x00';
        }

        uint256 length = 0;

        for (uint256 temp = value; temp != 0; temp >>= 8) {
            unchecked {
                length++;
            }
        }

        return toHexString(value, length);
    }

    function toHexString(
        uint256 value,
        uint256 length
    ) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = '0';
        buffer[1] = 'x';

        unchecked {
            for (uint256 i = 2 * length + 1; i > 1; --i) {
                buffer[i] = HEX_SYMBOLS[value & 0xf];
                value >>= 4;
            }
        }

        if (value != 0) revert UintUtils__InsufficientHexLength();

        return string(buffer);
    }
}

File 13 of 17 : AccessControlFacet.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;

/*************************************************************************
___  ___                       
|  \/  |                                          ___
| .  . | _____      _____  ___           _  _  .-'   '-.
| |\/| |/ _ \ \ /\ / / __|/ _ \         (.)(.)/         \   
| |  | | (_) \ V  V /\__ \  __/          /@@             ;
\_|  |_/\___/ \_/\_/ |___/\___|         o_\\-mm-......-mm`~~~~~~~~~~~~~~~~` 
                               
/*************************************************************************/

import "@solidstate/contracts/access/access_control/AccessControl.sol";
import {AccessControlStorage} from "@solidstate/contracts/access/access_control/AccessControlStorage.sol";

import {LibDiamond} from "../libraries/LibDiamond.sol";

import {MOWSE_MINTER_ROLE, MOWSEWEAR_MINTER_ROLE, MOWSE_ADMIN_ROLE, MOWSEWEAR_ADMIN_ROLE, MOWSEGAME_ADMIN_ROLE, MOWSELOOTBOX_MINTER_ROLE, MOWSEJOB_ADMIN_ROLE} from "../libraries/LibStorage.sol";

import "./../libraries/LibStorage.sol";

contract AccessControlFacet is AccessControl {
    GameStorage internal gs;
    error MissingAdminRole(string);

    modifier onlyAdminOrCore() {
        require(
            msg.sender == gs.diamondAddress || msg.sender == LibDiamond.contractOwner(),
            "Only the Core or Admin addresses can perform this action"
        );
        _;
    }
    modifier onlyAccessControlAdmin() {
        if (!_hasRole(AccessControlStorage.DEFAULT_ADMIN_ROLE, msg.sender)) revert MissingAdminRole("Missing Admin role");
        _;
    }

    function hasAdminRole(address account) external view returns (bool) {
        return _hasRole(AccessControlStorage.DEFAULT_ADMIN_ROLE, account);
    }

    // MowseAdminRole is responsible for facet-to-facet communication
    function hasMowseAdminRole(address account) external view returns (bool) {
        return _hasRole(MOWSE_ADMIN_ROLE, account);
    }

    function hasMowseMinterRole(address account) external view returns (bool) {
        return _hasRole(MOWSE_MINTER_ROLE, account);
    }

    function hasMowseWearMinterRole(address account) external view returns (bool) {
        return _hasRole(MOWSEWEAR_MINTER_ROLE, account);
    }

    function hasMowseWearAdminRole(address account) external view returns (bool) {
        return _hasRole(MOWSEWEAR_ADMIN_ROLE, account);
    }

    function hasMowseGameAdminRole(address account) external view returns (bool) {
        return _hasRole(MOWSEGAME_ADMIN_ROLE, account);
    }

    function hasMowseLootboxMinterRole(address account) external view returns (bool) {
        return _hasRole(MOWSELOOTBOX_MINTER_ROLE, account);
    }

    function hasMowseJobAdminRole(address account) external view returns (bool) {
        return _hasRole(MOWSEJOB_ADMIN_ROLE, account);
    }

    // Grant
    function addAccountToAdminRole(address account) external onlyAdminOrCore {
        _grantRole(AccessControlStorage.DEFAULT_ADMIN_ROLE, account);
    }

    function addAccountToMowseAdminRole(address account) external onlyAccessControlAdmin {
        _grantRole(MOWSE_ADMIN_ROLE, account);
    }

    function addAccountToMowseMinterRole(address account) external onlyAccessControlAdmin {
        _grantRole(MOWSE_MINTER_ROLE, account);
    }

    function addAccountToMowseWearMinterRole(address account) external onlyAccessControlAdmin {
        _grantRole(MOWSEWEAR_MINTER_ROLE, account);
    }

    function addAccountToMowseWearAdminRole(address account) external onlyAccessControlAdmin {
        _grantRole(MOWSEWEAR_ADMIN_ROLE, account);
    }

    function addAccountToMowseGameAdminRole(address account) external onlyAccessControlAdmin {
        _grantRole(MOWSEGAME_ADMIN_ROLE, account);
    }

    function addAccountToMowseLootboxMinterRole(address account) external onlyAccessControlAdmin {
        _grantRole(MOWSELOOTBOX_MINTER_ROLE, account);
    }

    function addAccountToMowseJobAdminRole(address account) external onlyAccessControlAdmin {
        _grantRole(MOWSEJOB_ADMIN_ROLE, account);
    }

    // Revoke
    function revokeAccountToMowseAdminRole(address account) external onlyAccessControlAdmin {
        _revokeRole(MOWSE_ADMIN_ROLE, account);
    }

    function revokeAccountToMowseMinterRole(address account) external onlyAccessControlAdmin {
        _revokeRole(MOWSE_MINTER_ROLE, account);
    }

    function revokeAccountToMowseWearMinterRole(address account) external onlyAccessControlAdmin {
        _revokeRole(MOWSEWEAR_MINTER_ROLE, account);
    }

    function revokeAccountToMowseWearAdminRole(address account) external onlyAccessControlAdmin {
        _revokeRole(MOWSEWEAR_ADMIN_ROLE, account);
    }

    function revokeAccountToMowseGameAdminRole(address account) external onlyAccessControlAdmin {
        _revokeRole(MOWSEGAME_ADMIN_ROLE, account);
    }

    function revokeAccountToMowseLootboxMinterRole(address account) external onlyAccessControlAdmin {
        _revokeRole(MOWSELOOTBOX_MINTER_ROLE, account);
    }

    function revokeAccountToMowseJobAdminRole(address account) external onlyAccessControlAdmin {
        _revokeRole(MOWSEJOB_ADMIN_ROLE, account);
    }
}

File 14 of 17 : IDiamondCut.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/

interface IDiamondCut {
    enum FacetCutAction {Add, Replace, Remove}
    // Add=0, Replace=1, Remove=2

    struct FacetCut {
        address facetAddress;
        FacetCutAction action;
        bytes4[] functionSelectors;
    }

    /// @notice Add/replace/remove any number of functions and optionally execute
    ///         a function with delegatecall
    /// @param _diamondCut Contains the facet addresses and function selectors
    /// @param _init The address of the contract or facet to execute _calldata
    /// @param _calldata A function call, including function selector and arguments
    ///                  _calldata is executed with delegatecall on _init
    function diamondCut(
        FacetCut[] calldata _diamondCut,
        address _init,
        bytes calldata _calldata
    ) external;

    event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
}

File 15 of 17 : LibDiamond.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/
import { IDiamondCut } from "../interfaces/IDiamondCut.sol";

// Remember to add the loupe functions from DiamondLoupeFacet to the diamond.
// The loupe functions are required by the EIP2535 Diamonds standard

error InitializationFunctionReverted(address _initializationContractAddress, bytes _calldata);

library LibDiamond {
    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");

    struct FacetAddressAndPosition {
        address facetAddress;
        uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array
    }

    struct FacetFunctionSelectors {
        bytes4[] functionSelectors;
        uint256 facetAddressPosition; // position of facetAddress in facetAddresses array
    }

    struct DiamondStorage {
        // maps function selector to the facet address and
        // the position of the selector in the facetFunctionSelectors.selectors array
        mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;
        // maps facet addresses to function selectors
        mapping(address => FacetFunctionSelectors) facetFunctionSelectors;
        // facet addresses
        address[] facetAddresses;
        // Used to query if a contract implements an interface.
        // Used to implement ERC-165.
        mapping(bytes4 => bool) supportedInterfaces;
        // owner of the contract
        address contractOwner;
    }

    function diamondStorage() internal pure returns (DiamondStorage storage ds) {
        bytes32 position = DIAMOND_STORAGE_POSITION;
        assembly {
            ds.slot := position
        }
    }

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    function setContractOwner(address _newOwner) internal {
        DiamondStorage storage ds = diamondStorage();
        address previousOwner = ds.contractOwner;
        ds.contractOwner = _newOwner;
        emit OwnershipTransferred(previousOwner, _newOwner);
    }

    function contractOwner() internal view returns (address contractOwner_) {
        contractOwner_ = diamondStorage().contractOwner;
    }

    function enforceIsContractOwner() internal view {
        require(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner");
    }

    event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);

    // Internal function version of diamondCut
    function diamondCut(
        IDiamondCut.FacetCut[] memory _diamondCut,
        address _init,
        bytes memory _calldata
    ) internal {
        for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
            IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;
            if (action == IDiamondCut.FacetCutAction.Add) {
                addFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
            } else if (action == IDiamondCut.FacetCutAction.Replace) {
                replaceFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
            } else if (action == IDiamondCut.FacetCutAction.Remove) {
                removeFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
            } else {
                revert("LibDiamondCut: Incorrect FacetCutAction");
            }
        }
        emit DiamondCut(_diamondCut, _init, _calldata);
        initializeDiamondCut(_init, _calldata);
    }

    function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        DiamondStorage storage ds = diamondStorage();        
        require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
        uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
        // add new facet address if it does not exist
        if (selectorPosition == 0) {
            addFacet(ds, _facetAddress);            
        }
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
            require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists");
            addFunction(ds, selector, selectorPosition, _facetAddress);
            selectorPosition++;
        }
    }

    function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        DiamondStorage storage ds = diamondStorage();
        require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
        uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
        // add new facet address if it does not exist
        if (selectorPosition == 0) {
            addFacet(ds, _facetAddress);
        }
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
            require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function");
            removeFunction(ds, oldFacetAddress, selector);
            addFunction(ds, selector, selectorPosition, _facetAddress);
            selectorPosition++;
        }
    }

    function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        DiamondStorage storage ds = diamondStorage();
        // if function does not exist then do nothing and return
        require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
            removeFunction(ds, oldFacetAddress, selector);
        }
    }

    function addFacet(DiamondStorage storage ds, address _facetAddress) internal {
        enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code");
        ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = ds.facetAddresses.length;
        ds.facetAddresses.push(_facetAddress);
    }    


    function addFunction(DiamondStorage storage ds, bytes4 _selector, uint96 _selectorPosition, address _facetAddress) internal {
        ds.selectorToFacetAndPosition[_selector].functionSelectorPosition = _selectorPosition;
        ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(_selector);
        ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress;
    }

    function removeFunction(DiamondStorage storage ds, address _facetAddress, bytes4 _selector) internal {        
        require(_facetAddress != address(0), "LibDiamondCut: Can't remove function that doesn't exist");
        // an immutable function is a function defined directly in a diamond
        require(_facetAddress != address(this), "LibDiamondCut: Can't remove immutable function");
        // replace selector with last selector, then delete last selector
        uint256 selectorPosition = ds.selectorToFacetAndPosition[_selector].functionSelectorPosition;
        uint256 lastSelectorPosition = ds.facetFunctionSelectors[_facetAddress].functionSelectors.length - 1;
        // if not the same then replace _selector with lastSelector
        if (selectorPosition != lastSelectorPosition) {
            bytes4 lastSelector = ds.facetFunctionSelectors[_facetAddress].functionSelectors[lastSelectorPosition];
            ds.facetFunctionSelectors[_facetAddress].functionSelectors[selectorPosition] = lastSelector;
            ds.selectorToFacetAndPosition[lastSelector].functionSelectorPosition = uint96(selectorPosition);
        }
        // delete the last selector
        ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();
        delete ds.selectorToFacetAndPosition[_selector];

        // if no more selectors for facet address then delete the facet address
        if (lastSelectorPosition == 0) {
            // replace facet address with last facet address and delete last facet address
            uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;
            uint256 facetAddressPosition = ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
            if (facetAddressPosition != lastFacetAddressPosition) {
                address lastFacetAddress = ds.facetAddresses[lastFacetAddressPosition];
                ds.facetAddresses[facetAddressPosition] = lastFacetAddress;
                ds.facetFunctionSelectors[lastFacetAddress].facetAddressPosition = facetAddressPosition;
            }
            ds.facetAddresses.pop();
            delete ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
        }
    }

    function initializeDiamondCut(address _init, bytes memory _calldata) internal {
        if (_init == address(0)) {
            return;
        }
        enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");        
        (bool success, bytes memory error) = _init.delegatecall(_calldata);
        if (!success) {
            if (error.length > 0) {
                // bubble up error
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(error)
                    revert(add(32, error), returndata_size)
                }
            } else {
                revert InitializationFunctionReverted(_init, _calldata);
            }
        }
    }

    function enforceHasContractCode(address _contract, string memory _errorMessage) internal view {
        uint256 contractSize;
        assembly {
            contractSize := extcodesize(_contract)
        }
        require(contractSize > 0, _errorMessage);
    }
}

File 16 of 17 : LibStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { LibDiamond } from "./LibDiamond.sol";

uint256 constant SKILL_TYPE_NUM = 7;
uint256 constant STAT_CHARISMA = 0;
uint256 constant STAT_CONSTITUTION = 1;
uint256 constant STAT_DEXTERITY = 2;
uint256 constant STAT_INTELLIGENCE = 3;
uint256 constant STAT_LUCK = 4;
uint256 constant STAT_STRENGTH = 5;
uint256 constant STAT_WISDOM = 6;
uint256 constant EQUIPPED_WEARABLE_SLOTS = 12;
bytes32 constant MOWSE_ADMIN_ROLE = keccak256('MOWSE_ADMIN_ROLE');
bytes32 constant MOWSEWEAR_MINTER_ROLE = keccak256('MOWSEWEAR_MINTER_ROLE');
bytes32 constant MOWSE_MINTER_ROLE = keccak256('MOWSE_MINTER_ROLE');
bytes32 constant MOWSEWEAR_ADMIN_ROLE = keccak256('MOWSEWEAR_ADMIN_ROLE');
bytes32 constant MOWSEGAME_ADMIN_ROLE = keccak256('MOWSEGAME_ADMIN_ROLE');
bytes32 constant MOWSEBANK_CREATE2_SALT = keccak256('MOWSEBANK_CREATE2_SALT');
bytes32 constant MOWSELOOTBOX_MINTER_ROLE = keccak256('MOWSELOOTBOX_MINTER_ROLE');
bytes32 constant MOWSEJOB_ADMIN_ROLE = keccak256('MOWSEJOB_ADMIN_ROLE');

struct GameStorage {
  address diamondAddress;
  address mowseAvatarContractAddress;
  address mowseGoldContractAddress;
  address mowseBankContractAddress;
  address mowseLootboxContractAddress;

  bool paused;
  // Mowse = id > 10,000
  uint256 mowseMintPrice;
  uint256 mowseTokenIdCounter; // Current tokenId of Mowse for minting purposes
  uint256 mowseWearTotalCount;  // Total Count of MowseWear minted
  uint256 mowseWearTokenIdCounter; // Current tokenId of MowseWear for minting purposes
  mapping(address => bool) isMowse; // maps Mowse address to bool if it is a mowse address or not
  mapping(address => uint256) mainMowse; // map address to mowseTokenId
  mapping(uint256 => Mowse) mowses; // map mowseAvatar tokenId to Mowse struct
  mapping(uint256 => MowseWear) mowsewears; // map mowsewear tokenId to MowseWear struct
  // mapping(uint256 => MowseLineage) mowselineages;
  mapping(uint8 => mapping(uint16 => MowseWearMetadata)) mowseWearDictionary; // map equippable wearable slot index to dictionary index to get unique mowsewear
  mapping(uint256 => MowseWearMetadata) mowseWearDictionaryByDictionaryIndex; // map dictionary index to mowsewear (for lootbox)
  uint256 mowseWearDictionaryCount; // Counts how many items are in the mowseWearDictionary (for lootbox)
  uint16[EQUIPPED_WEARABLE_SLOTS] mowseWearDictionaryTraitCount; // count of each trait (11 shirts, 10 eyeWear, etc), used for incrementing next traitIndex
  mapping(uint8 => mapping(uint16 => uint256)) mowseWearCountByTraitIndex;  // Counts how many mowsewear are minted per traitIndex (3 Blue Headbands)
  mapping(uint8 => uint256) mowseWearCountByTraitType;  // Counts how many shirts were minted
  mapping(uint16 => string) possibleTraitTypes; // mapping of all possible traitTypes to strings
  string[] initTraitNames;  // used in DiamondInit

  // MowseWear
  uint256 mowseWearHemPrice;

  // Initial merkel MGOLD aidrop
  // mapping(address => uint256) initialMowseGoldClaimList;  // Used for merkel airdrop

  // MowseLootbox
  // lootbox index is the loot pool index; [0-11] are trait type specific, [12] is general pool, 13+ are any other specific pools (weekly chests or seasonal chests)
  mapping(uint64 => MowseLootboxPool) mowselootboxes;  // map lootbox index (traitType + a few more) to MowseLootbox
  // count of current lootbox index
  uint64 mowseLootboxIndexCount;
  // Current tokenId of MowseLootbox for minting purposes
  uint256 mowseLootboxTokenIdCounter;
  // map tokenId to LootboxIndex to get the lootbox data
  mapping(uint256 => uint64) mowseLootboxIndexByTokenId;
  // large prime used for VDF
  uint256 mowseLootboxPrime;
  // iterations for VDF
  uint256 mowseLootboxIterations;
  // nonce for VDF
  uint256 mowseLootboxNonce;
  // mapping to get seed from tokenId if minted through mowseLootbox
  mapping(uint256 => uint256) mowseLootboxTokenIdToSeed;

  // random seed for pseudo-rng
  uint256 mowsePrngSeed;
  uint256 mowseJobPrngSeed;
  uint256 mowseWearPrngSeed;
  uint256 prngNonce;
  
  // DonationTree
  uint256 totalWishCount;
  uint256 donationTreePrime;
  uint256 donationTreeIterations;
  uint256 donationTreeNonce;
  mapping(uint256 => uint256) donationTreeWishCountToSeed;
  mapping(uint256 => uint256) mowseNextWish;
  mapping(address => uint256) nextWish;
  mapping(address => uint256) wishCount;

  // MowseGame
  mapping(uint256 => MowseGames) mowsegames;
  uint256 mowseGamesCount;
  uint256 activeMowseGamesCount;  // Needed 
  mapping(string => uint256) getMowseGameByName;
  uint8 maxFreeGameSubmits;
  // Normal base token payout
  uint256 baseGamePayout;
  // Pay for users' gas but it ain't free yo. After x number of submits, purchase MowseGold to continue forever
  mapping(address => uint256) freeMowseGameSubmits;
  mapping(address => bool) hasPurchasedMowseGold;
  // For suspicious gaming activity, temporary ban
  mapping(address => bool) mowseGameUserBanned;

  // MowseBank and MowseWallet
  address mowseBankWalletImplementation;
  mapping(address => uint256) mowseBankBalances;
  mapping(address => uint256) mowseBankTokenIdForWallet;

  // Withdrawal
  address payable devRoyaltyAddress;
  address payable teamAddress;
  address payable backendAddress;
  address payable treasuryAddress;
  uint256 devRoyaltyTaxBasisPoints;
  uint256 teamTaxBasisPoints;
  uint256 backendTaxBasisPoints;
  uint256 developerTaxBasisPoints;

  // For testnet purposes and rewarding testers
  uint256 testPatchCount;
  mapping(uint256 => TestPatch) testPatches;  // Maps patchVersion to testPatch  

  // GatherAndGarnishFacet
  uint256 gatherGarnishPrngSeed;
  uint256 gatherGarnishSeasonStart;
  uint256 gatherGarnishSeasonEnd;
  uint256 gatherGarnishSeasonCount;
  // Maps season count -> season reward (mowse wear dictionary index)
  mapping(uint256 => uint256) gatherGarnishSeasonReward;  // MowseWearDictionaryIndex
  // Maps player address -> season count -> stats
  mapping(address => mapping(uint256 => GatherAndGarnishPlayerStats)) gatherGarnishPlayerStats;
  // What day index did the first winner win
  uint256 gatherGarnishDayOfFirstWinner;
  // Maps season count -> first winners count index -> player address for season first winners
  mapping(uint256 => mapping(uint256 => address)) gatherGarnishSeasonFirstWinners;
  uint256 gatherGarnishSeasonFirstWinnersCount;
  // Maps season count -> winners count index -> player address for season winners
  mapping(uint256 => mapping(uint256 => address)) gatherGarnishSeasonWinners;
  uint256 gatherGarnishSeasonWinnersCount;
  // Maps season count -> winners address -> bool if they have won and claimed their rewards
  mapping(uint256 => mapping(address => bool)) gatherGarnishClaimedRewards;
  // Maps season count -> mainMowseId -> bool if the mowseId has received rewards for this season (to prevent transferring main mowse and claiming multiple exp rewards)
  mapping(uint256 => mapping(uint256 => bool)) gatherGarnishMainMowseClaimedRewards;
  // Maps season count -> winners address -> bool if they have won
  mapping(uint256 => mapping(address => bool)) gatherGarnishHasPlayerWon;
  // Maps season count -> day index -> scavenge hunt count
  mapping(uint256 => mapping(uint256 => GatherAndGarnishScavenge)) gatherGarnishScavenge;
  // Maps season count -> day index -> resource type [1-4, wood/rock/gem/food]
  mapping(uint256 => mapping(uint256 => uint256)) gatherGarnishDailyResource;
  // Maps season count -> day index -> investment resource type [1-4]
  mapping(uint256 => mapping(uint256 => uint256)) gatherGarnishInvestmentResource;
  // Maps season count -> pointsStructureCost
  mapping(uint256 => uint256[4]) gatherGarnishFirstPointsStructureCost;
  mapping(uint256 => uint256[4]) gatherGarnishSecondPointsStructureCost;
  mapping(uint256 => uint256[4]) gatherGarnishThirdPointsStructureCost;

  // MowseDungeonFacet
  uint256 statusEffectCount;
  // VDF for initial dungeon hash
  uint256 mowseDungeonPrime;
  uint256 mowseDungeonIterations;
  uint256 mowseDungeonNonce;
  // pRNG for smaller pseudo random actions
  uint256 mowseDungeonPrngSeed;
  // Maps mowseTokenId -> dungeonRunCount -> MowseDungeon
  mapping(uint256 => mapping(uint256 => MowseDungeon)) mowsedungeons;
  // Maps monsterIdCount -> mapping of statusEffects
  mapping(uint256 => mapping(MowseDungeonStatusEffectEnum => uint256)) mowseDungeonMonsterStatusEffects;
  // Count of Monster Ids
  // uint256 mowseDungeonMonsterIdCount;
  // Maps roomId -> MowseDungeonRoom
  // mapping(uint256 => MowseDungeonRoom) mowseDungeonRoom;
  // Count of rooms
  // uint256 mowseDungeonRoomCount;
  // Maps mowseTokenId -> Current Player stats
  mapping(uint256 => MowseDungeonPlayer) mowseDungeonPlayer;
  // Maps mowseTokenId -> AchievementEnum -> threshold
  mapping(uint256 => mapping(MowseDungeonAchievementsEnum => uint256)) mowseDungeonAchievementProgress;
  // Maps mowseTokenId -> Companion Enum -> Companion
  mapping(uint256 => mapping(MowseDungeonCompanionEnum => MowseDungeonCompanion)) mowseDungeonPlayerCompanion;
  // Maps mowseTokenId -> dungeonRunCount -> DungeonRewards
  mapping(uint256 => mapping(uint256 => MowseDungeonDungeonRewards)) mowseDungeonDungeonRewards;
  
  // Maps Monster Enum -> Monster for default values
  mapping(MowseDungeonMonsterEnum => MowseDungeonMonsterAttributes) mowseDungeonMonsterDefaults;
  uint256 mowseDungeonMonsterDefaultsCount;
  // Maps Room Enum -> Room for default values
  mapping(MowseDungeonRoomEnum => MowseDungeonRoom) mowseDungeonRoomDefaults;
  uint256 mowseDungeonRoomDefaultsCount;
  mapping(MowseDungeonTrinketEnum => MowseDungeonTrinket) mowseDungeonTrinketDefaults;
  // Keeps track of number of different trinkets exist
  uint256 mowseDungeonTrinketDefaultsCount;
  
  // Maps mowseTokenId to dungeon run count to vdf seed
  mapping(uint256 => mapping(uint256 => uint256)) mowseDungeonRunCountToSeed;
  // Maps mowseTokenId to dungeon run count
  mapping(uint256 => uint256) mowseDungeonRunCount;

  // RandomFortuneFacet
  mapping(address => uint256) randomFortuneCount;
  // large prime used for VDF
  uint256 randomFortunePrime;
  // iterations for VDF
  uint256 randomFortuneIterations;
  // nonce for VDF
  uint256 randomFortuneNonce;
  // mapping to get seed from timestamp
  mapping(address => mapping(uint256 => uint256)) randomFortuneTimestampToSeed;

  // MowseSpin
  // uint256 mowseSpinPrime;
  // uint256 mowseSpinIterations;
  // uint256 mowseSpinNonce;
  // // Maps mowseTokenId to current mowse spin game
  // mapping(uint256 => MowseSpinStorage) mowseSpinStorage;
  // // Maps mowseTokenId to player stats
  // mapping(uint256 => MowseSpinPlayer) mowseSpinPlayer;
}

// MowseSpin
// struct MowseSpinStorage {
//   uint256 mowseId;
//   uint256 stageCount;
//   uint256 spinCount;
//   uint256 mowseSpinId;
//   uint256 seed;
//   uint256 recountTokens;
//   uint256 trashTokens;
//   uint256 coins;
//   MowseSpinSimplePlayer player;
//   MowseSpinPlayerAchievementsProgress achievementProgress;
//   MowseSpinLog[] spinLog;
//   uint256 spinLogCount;
//   uint256 grid;
// }

// struct MowseSpinPlayer {
//   uint256 mowseId;
//   // Number of times a player has created a game
//   uint256 spinRunCount;
//   // MowseDungeonSimplePlayerAchievementsUnlocked achievements;
//   // // Used for quickly checking if an achievement is unlocked
//   // mapping(MowseDungeonAchievementsEnum => bool) achievementsUnlocked;
//   // mapping(MowseDungeonAchievementsEnum => bool) achievementsClaimed;
//   // MowseDungeonSimplePlayerAchievementsProgress achievementsProgress;
// }

enum MowseDungeonStatusEffectEnum {
  NONE,
  BLIND,      // 1/2 chance of missing attack
  EAGLE_EYE,   // double chance of hitting atttack
  POISON,     // Damage per turn, pre attack
  BURN,       // Damage per turn, post attack
  BLEED,      // Damage per turn, post attack
  CURSE,      // % Damage per turn, pre attack
  STUN,       // Skip damage step
  SILENCE,    // Disable special ability
  FREEZE,     // Skip damage step, +50% damage taken from fire damage
  STRENGTHEN, // Damage Up
  WEAKEN,     // Damage Down
  BULK,       // Defense Up
  FRAIL,      // Defense Down
  THORNS,     // Return damage on hit
  REGEN,      // Heal, pre attack
  SLEEP,      // Skip damage step, +150% damage taken, wakes up after damage taken
  DEATH,      // Kill player after x turns
  INVINCIBLE, // Player does not receive damage 
  LAST_HOPE,   // If player would die, set health to 1
  DODGE,      // Increase dodge chance
  HEAL_BLOCK,  // Disable healing
  CHARM,      // Skip damage step
  COUNTER,    // Basic attack after getting hit by a basic/special attack
  PIERCE,     // Attack through shield
  CLEAVE,     // Every attack hits all monsters
  REVIVE,     // After dying, revive with full health
  UNSTOPPABLE,// Debuffs cannot be applied (existing ones still damage)
  PETRIFY,    // Skip damage step, can't receive damage from enemy attack
  FIRE_RESIST, // Resist application of burn
  POISON_RESIST,
  FREEZE_RESIST,
  STUN_RESIST,
  SLEEP_RESIST,
  CHARGED,    // Used for boss abilities that take wind up time
  DOUBLE_UP,   // Apply double status effects
  RAMPAGE,    // Increase monster damage per turn
  LONE_SURVIVOR,// If all other monsters are dead, increase damage
  ROYAL_DECREE,// Cannot be directly targeted until all other monsters are dead
  WRATHFUL_REPRISAL// Counter attack based off player attack
}
enum MowseDungeonSpecialAbilityEnum {
  DEFEND,         // Apply thorns/counter/shield+5 to self
  POISON_GAS,      // Apply poison to enemy
  BOULDER_TOSS,    // Charge up and deal 3x damage + stun
  RAGE,           // Apply STRENGTHEN to self
  SUMMON_CLUCKO,   // Summon a Clucko in an empty monster slot
  THIN_STICK,      // 80% dodge chance
  BADMOUTH,       // Apply SILENCE, WEAKEN, FRAIL to enemy
  SUMMON_PUNK,     // Summon up to 2 WRAT_PUNK in empty monster slots
  CURSED_SLIME,    // Apply CURSE to enemy
  BLEEDING_SLIME,  // Apply BLEED to enemy
  IRON_GRASP,      // Charge up and double shield. Next turn add shield to damage
  IRON_PRAYER,     // Grant shield to monsters other than self
  JESTER_DANCE,    // Apply CURSE/BLEED/BURN/POISON/STUN/SLEEP/CHARM/freeze to enemy
  KNIGHTS_HONOR,   // Apply STRENGTHEN to self and shield to self
  QUEENS_GRACE,    // Apply REGEN,STRENGTHEN,BULK to all monsters
  KINGS_AUTHORITY, // Apply stun and charge up 2 turns, at end, deal damage equal to players coins
  ROYAL_DECREE,    // Summon up to 2 copper squire, then charge for 2 turns
  HOARDERS_STASH,  // Steal 25% of player's coins, add amount to current & max health
  WRATHFUL_REPRISAL,// Apply WRATHFUL_REPRISAL to self
  DESTRUCTIVE_ENVY,// Charge up 1 turn, copy player's attack
  SEDUCTIVE_GAZE,  // Apply CHARM +2 to player
  INSATIABLE_FEAST,// Charge 1 turn, Consume all debuffs from self and all buffs from player, heal for 10% per debuff
  ANTI_SONIC_SPEED,// Apply SLEEP to all players for 2 turns
  NONE
}
enum MowseDungeonCompanionEnum {
  NONE,
  DIAMOND_BACK,
  DEVILISH,       // Get Copper Squire Achievement
  WONDER_CHILD,     // Get Novice Achievement
  INVALID_COMPANION
}
enum MowseDungeonTrinketEnum {
  DAGGER,         // +10% attack
  SLINGSHOT,      // increase damage when enemy at max health
  PENDANT_OF_LIFE,  // +5 health pre attack
  LEECH,          // +10% lifesteal per stack
  POISON_DAB,      // +1 apply poison stack after attack
  KINDLE,         // +1 burn stack
  BLOOD_LETTER,    // +1 bleed stack
  CURSED_RING,     // +1 curse stack
  STUN_ROD,        // chance to apply +1 stun stack
  SILENCE_BELL,    // chance to apply +1 silence stack
  STRENGTH_BELT,   // +1 strengthen stack (2x damage)
  WEAKENED_CHAIN,  // +1 weaken stack (1/2 damage)
  EMBLEM_OF_INITIATIVE, // +1 action
  GOLD_RING,       // increase coin drop 10% + 10% per stack
  NONE
}
enum MowseDungeonRoomEnum {
  MERCHANT,             // Merchant
  COIN_LOOT_ROOM,
  TRINKET_LOOT_ROOM,
  FOREST_SLIME_1,       // 1 Green Slime
  FOREST_SLIME_2,       // 2 Green Slime
  FOREST_SLIME_3,       // 3 Green Slime
  FOREST_MUSHY,   // 2 Red Mushy
  FOREST_PEBBLE,   // 1 Pebble Golem 1 DUCKY
  FOREST_TOAD,   // 3 Spiny Toad
  FOREST_ROOSTA,         // 1 Roosta 2 Clucko
  FOREST_STICK,         // 3 Stick Bug
  FOREST_WRAT_PUNK,         // 2 WRAT_PUNK
  FOREST_WRAT_GANG_LEADER,           // 1 Wrat Gang Leader
  RAIN_OF_FROGS,          // 3 Spiny Toad
  STICKY_SITUATION,       // 2 Green Slime 1 Stick Bug
  MEDIEVAL_SLIME_INTRO,   // 1 Helmet Slime
  MEDIEVAL_SQUIRE_INTRO,  // 1 Copper Squire
  MEDIEVAL_PRIEST_INTRO,  // 2 Iron Priest
  MEDIEVAL_SLIME,        // 3 Helmet Slime
  MEDIEVAL_SQUIRE,       // 2 Copper Squire
  MEDIEVAL_JESTER,       // 2 Pyrite Jester
  MEDIEVAL_KNIGHT,       // 2 Steel Knight
  MEDIEVAL_KNIGHT_PRIEST, // 1 Steel Knight 1 Iron Priest
  MEDIEVAL_KNIGHT_SQUIRE,       // 1 Steel Knight 1 CopperSquire
  MEDIEVAL_MAIDEN,       // 1 Iron Maiden 2 Iron Priest
  MEDIEVAL_QUEEN,        // 1 Silver Queen 1 SteelKnight
  MEDIEVAL_KING,         // 1 Gold King 1 SteelKnight
  MEDIEVAL_ROYAL,        // 1 Silver Queen 1 Gold King
  BOSS_LIONS_PRIDE,
  BOSS_GOBLINS_GREED,
  BOSS_LICHS_WRATH,
  BOSS_WRATS_ENVY,
  BOSS_LUSTFUL_HEIRESS,
  BOSS_GLUTTONOUS_PIG,
  BOSS_SLOTHFUL_HEDGEHOG
}
enum MowseDungeonMonsterEnum {
  // Forest
  SPINY_TOAD,
  GREEN_SLIME,
  RED_MUSHY,
  PEBBLE_GOLEM,
  CLUCKO,
  ROOSTA,
  STICK_BUG,
  DUCKY,
  WRAT_PUNK,
  WRAT_GANG_LEADER,
  BLUE_SLIME,
  RED_SLIME,
  // Metal Medieval theme
  HELMET_SLIME,
  COPPER_SQUIRE,
  IRON_MAIDEN,
  IRON_PRIEST,
  PYRITE_JESTER,
  STEEL_KNIGHT,
  SILVER_QUEEN,
  GOLD_KING,
  // Bosses
  // 7 Deadly Sins
  LIONS_PRIDE,
  GOBLINS_GREED,
  LICHS_WRATH,
  WRATS_ENVY,
  LUSTFUL_HEIRESS,
  GLUTTONOUS_PIG,
  SLOTHFUL_HEDGEHOG,
  NONE
}
enum MowseDungeonClassEnum {
  // Base Classes
  WARRIOR,  // Basic 100% damage Special ability whirlwind (apply cleave to self)
  MAGE,     // Basic 60% Special ability fireball (2x base attack, apply burn to enemy)
  ARCHER,   // Basic 80% damage, Special ability Hawkshot (apply eagle eye, deal damage x # of times)
  ROGUE,    // Basic 50% x 2 apply poison Special ability backstab (apply dodge 2x)
  // Advanced Classes
  PALADIN,  // Basic 70% damage, Special ability Judgement Of Light (heal 30% max health + 1% per 10 int + 1% per 10 str)
  GUARDIAN,  // Basic 50% damage, gain shield Special ability shieldbash (gain extra shield, damage equal to shield)
  BERSERKER,// Basic 120% Special ability rage (deal basic attack damage, apply strengthen, lastHope, silence to self)
  CLERIC,   // Basic 40% Special ability heal (apply regen to self)
  NECROMANCER,// Basic 55% Special ability life tap (deal basic attack damage, if monster dies, permanently gain 10% attack)
  BARD,     // Basic 60% Special ability charm (apply charm to enemy)
  // T2 Classes
  INVALID_CLASS
}
enum MowseDungeonRoomTypeEnum {
  MONSTER,
  COIN_LOOT,
  TRINKET_LOOT,
  BOSS,
  MERCHANT,
  INVALID_ROOM
}
// Complete Achievements to unlock Companions
enum MowseDungeonAchievementsEnum {
  NOVICE,           // Complete the forest-0 dungeon
  FOREST_MASTER,     // Complete the forest-10 dungeon
  COPPER_SQUIRE,   // Complete the medieval-0 dungeon
  IRON_MAIDEN,   // Complete the medieval-3 dungeon
  STEEL_KNIGHT,    // Complete the medieval-6 dungeon
  GOLD_KING,     // Complete the medieval-9 dungeon
  MASTER_OF_DEADLY_SINS,// Complete the medieval-10 dungeon
  UNTOUCHABLE,      // Defeat a boss without taking damage
  POISON_MASTER,      // Apply 99 stacks of poison in one dungeon
  LOOT_GOBLIN,       // Steal successfully more than 5 times in a single run
  COIN_GOBLIN,       // Have at least 500 coins in inventory
  ONE_MAN_ARMY,       // Deal 1000 damage in a single run
  LEARN_THE_ROPES,  // Complete any dungeon with all 4 base classes
  WARRIOR,          // Complete any dungeon with Warrior
  MAGE,             // Complete any dungeon with Mage
  ARCHER,           // Complete any dungeon with Archer
  ROGUE,            // Complete any dungeon with Rogue
  PALADIN,          // Complete any dungeon with Paladin
  GUARDIAN,         // Complete any dungeon with Guardian
  BERSERKER,        // Complete any dungeon with Berserker
  CLERIC,           // Complete any dungeon with Cleric
  NECROMANCER,      // Complete any dungeon with Necromancer
  BARD,             // Complete any dungeon with Bard
  INVALID_ACHIEVEMENT
}
enum MowseDungeonActionTypeEnum {
  BASIC_ATTACK,
  SPECIAL_ABILITY,
  STEAL,
  DEFEND,
  INVALID_ACTION
}
enum MowseDungeonBattleStatusEnum {
  VICTORY,
  DEFEAT,
  ONGOING
}
enum MowseDungeonDungeonTypeEnum {
  FOREST,
  MEDIEVAL
}
enum MowseDungeonBattleLogTypeEnum {
  INVALID_LOG_TYPE,
  DAMAGE,
  APPLY_STATUS_EFFECT,
  HEAL,
  SUMMON,
  STEAL_SUCCESS,
  STEAL_FAILURE
}
enum MowseDungeonBattleLogSourceEnum {
  PLAYER,
  MONSTER_1,
  MONSTER_2,
  MONSTER_3,
  TARGET_INDEX_MONSTER,  // Target a Monster according to targetIndex
  COMPANION,
  TRINKET_PENDANT_OF_LIFE,
  TRINKET_LEECH,
  STATUS_EFFECT_BLIND,
  STATUS_EFFECT_EAGLE_EYE,
  STATUS_EFFECT_POISON,
  STATUS_EFFECT_BURN,
  STATUS_EFFECT_BLEED,
  STATUS_EFFECT_CURSE,
  STATUS_EFFECT_STUN,
  STATUS_EFFECT_SILENCE,
  STATUS_EFFECT_FREEZE,
  STATUS_EFFECT_STRENGTHEN,
  STATUS_EFFECT_WEAKEN,
  STATUS_EFFECT_BULK,
  STATUS_EFFECT_FRAIL,
  STATUS_EFFECT_THORNS,
  STATUS_EFFECT_REGEN,
  STATUS_EFFECT_SLEEP,
  STATUS_EFFECT_DEATH,
  STATUS_EFFECT_INVINCIBLE,
  STATUS_EFFECT_LAST_HOPE,
  STATUS_EFFECT_DODGE,
  STATUS_EFFECT_HEAL_BLOCK,
  STATUS_EFFECT_CHARM,
  STATUS_EFFECT_COUNTER,
  STATUS_EFFECT_PIERCE,
  STATUS_EFFECT_CLEAVE,
  STATUS_EFFECT_REVIVE,
  STATUS_EFFECT_UNSTOPPABLE,
  STATUS_EFFECT_PETRIFY,
  STATUS_EFFECT_FIRE_RESIST,
  STATUS_EFFECT_POISON_RESIST,
  STATUS_EFFECT_FREEZE_RESIST,
  STATUS_EFFECT_STUN_RESIST,
  STATUS_EFFECT_SLEEP_RESIST,
  STATUS_EFFECT_CHARGED,
  STATUS_EFFECT_DOUBLE_UP,
  STATUS_EFFECT_RAMPAGE,
  STATUS_EFFECT_LONE_SURVIVOR,
  STATUS_EFFECT_ROYAL_DECREE,
  STATUS_EFFECT_WRATHFUL_REPRISAL
}
struct MowseDungeonSimpleTrinkets {
  uint256 dagger;
  uint256 slingshot;
  uint256 pendantOfLife;
  uint256 leech;
  uint256 poisonDab;
  uint256 kindle;
  uint256 bloodLetter;
  uint256 cursedRing;
  uint256 stunRod;
  uint256 silenceBell;
  uint256 strengthBelt;
  uint256 weakenedChain;
  uint256 emblemOfInitiative;
  uint256 goldRing;
}
struct MowseDungeonSimpleStatusEffect {
  uint256 blind;
  uint256 eagleEye;
  uint256 poison;
  uint256 burn;
  uint256 bleed;
  uint256 curse;
  uint256 stun;
  uint256 silence;
  uint256 freeze;
  uint256 strengthen;
  uint256 weaken;
  uint256 bulk;
  uint256 frail;
  uint256 thorns;
  uint256 regen;
  uint256 sleep;
  uint256 death;
  uint256 invincible;
  uint256 lastHope;
  uint256 dodge;
  uint256 healBlock;
  uint256 charm;
  uint256 counter;
  uint256 pierce;
  uint256 cleave;
  uint256 revive;
  uint256 unstoppable;
  uint256 petrify;
  uint256 fireResist;
  uint256 poisonResist;
  uint256 freezeResist;
  uint256 stunResist;
  uint256 sleepResist;
  uint256 charged;
  uint256 doubleUp;
  uint256 rampage;
  uint256 loneSurvivor;
  uint256 royalDecree;
  uint256 wrathfulReprisal;
}
struct MowseDungeonSimplePlayerAchievementsUnlocked {
  bool novice;
  bool forestMaster;
  bool copperSquire;
  bool ironMaiden;
  bool steelKnight;
  bool goldKing;
  bool masterOfDeadlySins;
  bool untouchable;
  bool poisonMaster;
  bool lootGoblin;
  bool coinGoblin;
  bool oneManArmy;
  bool learnTheRopes;
  bool warrior;
  bool mage;
  bool archer;
  bool rogue;
  bool paladin;
  bool guardian;
  bool berserker;
  bool cleric;
  bool necromancer;
  bool bard;
}
struct MowseDungeonSimplePlayerAchievementsProgress {
  uint256 damageDealt;
  uint256 damageTaken;
  uint256 healthHealed;
  uint256 burnDamageDealt;
  uint256 poisonDamageDealt;
  uint256 bleedDamageDealt;
  uint256 curseDamageDealt;
  uint256 trinketsStolen;
}
struct MowseDungeonBattleLog {
  MowseDungeonBattleLogTypeEnum logType;
  MowseDungeonBattleLogSourceEnum source;
  MowseDungeonBattleLogSourceEnum target;
  uint256 amount;
}
struct MowseDungeonBattleSimulation {
  MowseDungeonSimplePlayer player;
  MowseDungeonSimpleMonster monster1;
  MowseDungeonSimpleMonster monster2;
  MowseDungeonSimpleMonster monster3;
  uint256 dungeonId;
  uint256 seed;
  MowseDungeonActionTypeEnum actionType;
  uint8 targetIndex;
  uint256 actionsRun;
  MowseDungeonTrinketEnum[] stolenTrinkets;
  uint256 stolenTrinketCount;
  bool isStealSuccessful;
  MowseDungeonBattleStatusEnum status;
  MowseDungeonSimplePlayerAchievementsProgress achievementProgress;
  uint256 descentLevel;
  MowseDungeonBattleLog[] battleLog;
  uint256 battleLogCount;
}
struct MowseDungeonBattleResults {
  MowseDungeonBattleSimulation simulation;
  MowseDungeonPostBattleResults postBattleResults;
  bytes32 actionsRunHash;
  bytes32 postBattleResultsHash;
}
struct MowseDungeonPostBattleResults {
  uint256 mowseId;
  uint256 coins;
  MowseDungeonMonsterEnum monster1;
  MowseDungeonMonsterEnum monster2;
  MowseDungeonMonsterEnum monster3;
  MowseDungeonTrinketEnum[] stolenTrinkets;
  uint256 stolenTrinketCount;
  MowseDungeonBattleStatusEnum status;
  MowseDungeonSimplePlayerAchievementsProgress achievementProgress;
  uint256 descentLevel;
}
struct MowseDungeonDungeonRewards {
  bool hasRewards;
  uint256 mgoldMintAmount;
  uint256 xpGainedAmount;
  uint256 companionXpGained;
  uint256 completionPercentage;
  uint256 additionalFactor;
}
// Used for _performAction to calculate damage
struct MowseDungeonSimplePlayer {
  uint256 mowseId;
  int32[SKILL_TYPE_NUM] stats;
  uint256 maxHealth;
  uint256 currentHealth;
  uint256 shield;
  uint256 attack;
  bool canHit;
  uint256 accuracy;
  uint256 tempAttack;
  uint256 damageMultiplier;
  uint256 action;
  uint256 numberOfHits;
  MowseDungeonClassEnum class;
  MowseDungeonSimpleStatusEffect statusEffects;
  MowseDungeonSimpleTrinkets trinkets;
  MowseDungeonCompanion companion;
  MowseDungeonDescentLevel descentLevel;
  // MowseDungeonSimplePlayerAchievementsUnlocked achievements;
  uint256 coins;
  uint256 currentDungeonRunCount;
  uint256 currentRoomIndex;
}
struct MowseDungeonPlayer {
  uint256 mowseId;
  int32[SKILL_TYPE_NUM] stats;
  uint256 maxHealth;
  uint256 currentHealth;
  uint256 shield;
  uint256 attack;
  // uint256 maxAction;  // Special Ability points
  uint256 action;
  // Maps StatusEffect to statusEffect value (ex: 1 (poison) => 2 is equal to 2 stacks of poison)
  mapping(MowseDungeonStatusEffectEnum => uint256) statusEffects;
  // Maps trinketIndex to MowseDungeonTrinketEnum
  mapping(MowseDungeonTrinketEnum => MowseDungeonTrinket) trinkets;
  // uint256 trinketCount;
  mapping(MowseDungeonCompanionEnum => MowseDungeonCompanion) companions;
  MowseDungeonCompanion currentCompanion;
  uint256 coins;
  MowseDungeonClassEnum class;
  // Number of times a player has run a dungeon
  uint256 dungeonRunCount;
  MowseDungeonSimplePlayerAchievementsUnlocked achievements;
  // Used for quickly checking if an achievement is unlocked
  mapping(MowseDungeonAchievementsEnum => bool) achievementsUnlocked;
  mapping(MowseDungeonAchievementsEnum => bool) achievementsClaimed;
  MowseDungeonSimplePlayerAchievementsProgress achievementsProgress;
  MowseDungeonDescentLevel descentLevel;
}
struct MowseDungeonPerformAction {
  MowseDungeonActionTypeEnum actionType;
  uint256 targetIndex;
}
// Used for _performAction to calculate damage
struct MowseDungeonSimpleMonster {
  MowseDungeonMonsterEnum monsterType;
  uint256 monsterId;
  uint256 maxHealth;
  uint256 currentHealth;
  uint256 shield;
  uint256 attack;
  bool canHit;
  uint256 accuracy;
  uint256 tempAttack;
  uint256 damageMultiplier;
  MowseDungeonSpecialAbilityEnum specialAbility;
  bool isBoss;
  bool hasBeenStolen;
  bool usedSpecialAbility;
  MowseDungeonSimpleStatusEffect statusEffects;
  string image;
}
// Used for setting default monster values 
struct MowseDungeonMonsterAttributes {
  bool isActive;
  MowseDungeonMonsterEnum monsterType;
  uint256 monsterId;
  uint256 maxHealth;
  uint256 shield;
  uint256 attack;
  MowseDungeonSpecialAbilityEnum specialAbility;
  MowseDungeonSimpleStatusEffect statusEffects;
  bool isBoss;
  uint256 coins;
  string name;
  string image;
}
struct MowseDungeonMonster {
  MowseDungeonMonsterEnum monsterType;
  uint256 monsterId;
  uint256 maxHealth;
  uint256 currentHealth;
  uint256 shield;
  uint256 attack;
  MowseDungeonSpecialAbilityEnum specialAbility;
  mapping(MowseDungeonStatusEffectEnum => uint256) statusEffects;
  // Bosses cannot be stunned, slept, etc.
  bool isBoss;
  // Maps monsterDropIndex to MowseDungeonTrinket
  mapping(uint256 => MowseDungeonTrinket) monsterDrops;
  uint256 monsterDropCount;
  uint256 coins;
  // Players can only use steal once per monster
  bool hasBeenStolen;
  string name;
}
// Trinkets are passive boosts to the player they can select after battle
// Trinkets do not carry over between dungeon run, however, you can enhance trinkets so they are stronger the next run
// Use MowseDungeonTrinketEnum id to conditionally apply statusEffects
struct MowseDungeonTrinket {
  MowseDungeonTrinketEnum trinketId;
  uint256 level;
  // mapping(MowseDungeonStatusEffectEnum => uint256) statusEffects;
  uint256 health;
  uint256 shield;
  uint256 attack;
}
// Should always have 5 items
struct MowseDungeonMerchantRoom {
  MowseDungeonMerchantItem[] items;
}
struct MowseDungeonMerchantItem {
  MowseDungeonTrinketEnum trinketId;
  MowseDungeonTrinket trinket;
  uint256 cost;
  bool hasPurchased;
}
// Unlike Trinkets, Companions carry over between dungeon runs
// Companions can level up before a dungeon run
struct MowseDungeonCompanion {
  MowseDungeonCompanionEnum companionId;
  bool isUnlocked;
  uint256 level;
  uint256 experience;
}
struct MowseDungeonRoom {
  MowseDungeonRoomEnum id;
  MowseDungeonRoomTypeEnum roomType;
  MowseDungeonMonsterEnum[] monsters;
}
struct MowseDungeon {
  uint256 id;   // Should be the VDF hash
  MowseDungeonRoom[] rooms;
  uint256 currentRoomIndex;
  bool active;
  MowseDungeonDungeonTypeEnum dungeonType;
  MowseDungeonMerchantRoom merchantRoom;
  uint256 descentLevel;
}
// 0 - normal
// 1 - +25% hp/shield
// 2 - +25% attack
// 3 - +25% attack, -25% coin
// 4 - +25% attack/hp/shield
// 5 - +25% attack/hp/shield, items cost 10% more
// 6 - +25% attack, +50% hp/shield
// 7 - +25% attack, +50% hp/shield, -25% coins
// 8 - +25% attack, +50% hp/shield, -25% coins, items cost 10% more
// 9 - +100% hp/shield, rampage
// 10 - +100% hp/shield, rampage, -25% coins, items cost 10% more
struct MowseDungeonDescentLevel {
  uint256 forestDungeon;
  uint256 medievalDungeon;
}

// Gather and Garnish
struct GatherAndGarnishScavenge {
  uint256 woodCount;
  uint256 rockCount;
  uint256 gemCount;
  uint256 foodCount;
}
struct GatherAndGarnishPlayerStats {
  // Maps season day index -> action index taken [1 - gather, 2 - predict, 3 - build, 4 - invest]
  mapping(uint256 => uint256) dailyAction;
  uint256 woodStorage;
  uint256 woodStorageLevel;
  uint256 rockStorage;
  uint256 rockStorageLevel;
  uint256 gemStorage;
  uint256 gemStorageLevel;
  uint256 foodStorage;
  uint256 foodStorageLevel;
  uint256 investmentCount;
  // Maps whether the player has built the first/second/third points structure
  mapping(uint256 => bool) hasBuiltPointsStructure;
  // Maps season day index -> resource type prediction [1-4, wood/rock/gem/food]
  mapping(uint256 => uint256) prediction;
  uint256 latestPredictionDay;
  uint256 seasonFirstWinnerIndex;
}

struct TestPatch {
  uint256 testPatchVersion;
  uint256 uniqueInteractionCount; // Unique address interactions
  address[] interactedAddresses;  // Addresses that interacted
  mapping(address => uint256) numberOfInteractions; // maps addresses -> number of times interacted
}

struct Mowse {
  uint256 tokenId; // Mowse asset tokenId counter, also used to check if exists
  address ownerAddress; // Owner Address
  // BaseTraits required on all Mowse
  uint16 generation;
  MowseWearMetadata baseBackgroundColor; // Index 0
  MowseWearMetadata baseSkinColor;       // Index 2
  MowseWearMetadata baseEarType;         // Index 3
  MowseWearMetadata baseBodyType;        // Index 5
  MowseWearMetadata baseMouth;           // Index 6
  MowseWearMetadata baseEyeType;         // Index 8
  // MowseJob
  int32[SKILL_TYPE_NUM] skillLevelBoosts;  // Additional Skill LEVEL modifiers
  int32[SKILL_TYPE_NUM] skillLevel; // Base Skill LEVEL, increases as ExperiencePoints caps [charisma, constitution, dexterity, intelligence, luck, strength, wisdom]
  // uint32[SKILL_TYPE_NUM] skillExperiencePoints; // Skill EXPERIENCE points
  // uint16[SKILL_TYPE_NUM] skillExperiencePointsBoosts; // Additional Skill EXPERIENCE points boosts
  uint8 primarySkillType;  // Primary skill preference from birth (should be 0-6), cannot change
  uint8 secondarySkillType;  // Secondary skill preference from birth (should be 0-6, can be the same as primary skill), cannot change
  uint8 profession; // Career (should be 0-7), can change. 
  // 0 = no profession
  // 1 = Agriculture and Food
  // 2 = Finance and Marketing
  // 3 = Art and Manufacturing
  // 4 = Science and Medicine
  // 5 = Military
  // 6 = Politics (Law and Government)
  // 7 = Nursing and Childcare (Family-focused)
  // MowseLife
  uint16 lifeLevel; // LIFE Experience level
  uint256 lifeExperiencePoints;  // Life Experience points (as life level goes up, skill level can be increased)
  uint256 prngNonce;  // Used in Mowse PRNG (level up to randomly distribute stat points and onMint)

  // MowseWear
  uint256[EQUIPPED_WEARABLE_SLOTS] equippedMowseWearByTokenIds;  // Currently equipped mowsewear tokenIds
  // [backgroundColor, backgroundFeature, skinColor, earType, shirt, bodyType, mouth, eyeBrow, eyeType, eyeWear, headWear, jewelry]

}

// 1 Background Color
// 2 Background Feature
// 3 Skin Color
// 4 Ear Type
// 5 Shirt
// 6 Body Type
// 7 Mouth
// 8 Eye Brow Type
// 9 Eye Type
// 10 Eye Wear
// 11 Head Wear
// 12 Jewelry

struct MowseWear {
  uint256 tokenId;  // MowseWear asset tokenId counter, also used to check if exists
  bool isEquipped;  // Quick way to know if a MowseWear is equipped
  uint256 equippedBy; // track which Mowse tokenId is equipped by
  uint256 durability;  // Durability time after stitching
  uint256 alterCount;  // Number of times a MowseWear has been altered (stitched or hemmed)
  uint256 maxAlterCount;  // Max number of times a MowseWear can be altered (stitched or hemmed)
  MowseWearMetadata metadata;
  MowseWearDimensions dimensions;
  MowseWearBonuses bonuses;
}

struct MowseWearMetadata {
  uint8 traitType;  // Type of MowseWear (backgroundColor, shirt, eyeWear, etc) (should be 0-11)
  string traitName; // MowseWear item name ("Blue Headband")
  uint16 traitIndex;  // MowseWear trait index (12th headband)
  uint256 dictionaryIndex;  // MowseWear dictionary index (12th item in dictionary)
  bool nonTransferrable;  // MowseWear can be traded or not (soulbound)
  string svgFilter; // Any overrides on the svgFilter
  MowseWearDimensions baseDimensions; // Base SVG Dimensions
}

struct MowseWearBonuses {
  uint256 randomness; // Random seed for MowseWear
  uint256 itemRarityIV;  // Item Rarity inherent value (pseudorandom number between 0-4294967294)
  uint8 itemRarity; // Item Rarity (common, uncommon, rare, epic, legendary, unique) (should be 0-5)
  int32[SKILL_TYPE_NUM] baseSkillLevelBoosts; // Base Skill LEVEL modifiers from IV
  int32[SKILL_TYPE_NUM] additionalSkillLevelBoosts;  // Additional Skill LEVEL modifiers from other factors (set bonuses?)
}

struct MowseSkillTypes {
  int32 charisma;
  int32 constitution;
  int32 dexterity;
  int32 intelligence;
  int32 luck;
  int32 strength;
  int32 wisdom;
}

struct MowseWearDimensions {
  uint16 width;
  uint16 height;
  string transform;
  string style;
  string image;
  uint16 weight;
}

struct MowseLootboxPool {
  bool active;  // Is lootbox active and can be minted from?
  uint256 price;  // Price per MowseGold (generic loot pool cheapest -> specific trait type more expensive -> event specific)
  string name;
  uint16 width; // Goes with image to create on-chain SVG
  uint16 height;  // Goes with image to create on-chain SVG
  string image;
  mapping(uint16 => uint256) lootPool;  // TraitTypes & TraitIndexes in the lootPool for minting
  uint16 itemCount; // Number of items in lootpool
  uint256 dateAdded;  // When the lootbox was added; Ex: Earlier lootboxes might have rarer items
  uint256 index;  // Index of the lootbox
}
// This struct is used by MowseLootboxFacet.getMowseLootboxData to return the lootPool mapping as well
struct MowseLootboxPoolData {
  bool active;
  uint256 price;
  string name;
  string image;
  SimpleMowseLootboxPoolItem[] lootPool;
  uint16 itemCount;
  uint256 dateAdded;
  uint64 index;
}
struct SimpleMowseLootboxPoolItem {
  uint16 traitType;
  uint16 traitIndex;
  string traitName;
  string image;
}

struct MowseLineage {
  uint16 generation;
  uint256 parent1;
  uint256 parent2;
  uint256[] children;
}

struct MowseBankStruct {
  address _walletImplementation;
  mapping(address => uint256) balances;
  mapping(address => uint256) getTokenIdForWallet;
}
struct MowseGames {
  string name;
  bool active;  // Game is active or disabled (disable if game updates or something. idk. Bad developer)
  bytes32 gameHash;
  uint256 totalNumberOfSubmits;
  mapping(address => uint256) uniqueSubmitsByAddress;
  address[] uniqueAddressesList;
  uint256 uniqueAddressesCount;
  mapping(address => uint256[3]) dailySubmits;
  // Minimum score to pass to get the max payout MGOLD
  uint256 minScoreForMaxPayout;
  // For granting additional bonuses for special event days
  bool rewardBonus;
  // For paying game developers
  address payable developerAddress;
}


library LibStorage {
  function gameStorage() internal pure returns (GameStorage storage gs) {
    assembly {
      gs.slot := 0
    }
  }
  function skillTypeToString(uint16 x) internal pure returns (string memory skillTypeString) {
    require(x < SKILL_TYPE_NUM, "LibStorage: Invalid Skill Type");

    if (x == 0) return "charisma";
    if (x == 1) return "constitution";
    if (x == 2) return "dexterity";
    if (x == 3) return "intelligence";
    if (x == 4) return "luck";
    if (x == 5) return "strength";
    if (x == 6) return "wisdom";
  }
  function equippableWearableSlotToString(uint8 traitType) internal pure returns (string memory wearableSlotString) {
    require(traitType < EQUIPPED_WEARABLE_SLOTS, "LibStorage: Invalid Trait Type");

    if (traitType == 0) return "backgroundColor"; 
    if (traitType == 1) return "backgroundFeature"; 
    if (traitType == 2) return "skinColor"; 
    if (traitType == 3) return "earType"; 
    if (traitType == 4) return "shirt"; 
    if (traitType == 5) return "bodyType"; 
    if (traitType == 6) return "mouth"; 
    if (traitType == 7) return "eyeBrow"; 
    if (traitType == 8) return "eyeType"; 
    if (traitType == 9) return "eyeWear"; 
    if (traitType == 10) return "headWear"; 
    if (traitType == 11) return "jewelry";
  }
  function itemRarityToString(uint8 itemRarity) internal pure returns (string memory itemRarityString) {
    if (itemRarity == 0) return "common";
    if (itemRarity == 1) return "uncommon";
    if (itemRarity == 2) return "rare";
    if (itemRarity == 3) return "epic";
    if (itemRarity == 4) return "legendary";
    if (itemRarity == 5) return "unique";
  }
}
contract WithStorage {
  function skillTypeToString(uint16 skillType) internal pure returns (string memory) {
    return LibStorage.skillTypeToString(skillType);
  }
  function equippedWearableSlotToString(uint8 traitType) internal pure returns (string memory) {
    return LibStorage.equippableWearableSlotToString(traitType);
  }
  function itemRarityToString(uint8 itemRarity) internal pure returns (string memory) {
    return LibStorage.itemRarityToString(itemRarity);
  }
}

File 17 of 17 : console.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

library console {
    address constant CONSOLE_ADDRESS =
        0x000000000000000000636F6e736F6c652e6c6f67;

    function _sendLogPayloadImplementation(bytes memory payload) internal view {
        address consoleAddress = CONSOLE_ADDRESS;
        /// @solidity memory-safe-assembly
        assembly {
            pop(
                staticcall(
                    gas(),
                    consoleAddress,
                    add(payload, 32),
                    mload(payload),
                    0,
                    0
                )
            )
        }
    }

    function _castToPure(
      function(bytes memory) internal view fnIn
    ) internal pure returns (function(bytes memory) pure fnOut) {
        assembly {
            fnOut := fnIn
        }
    }

    function _sendLogPayload(bytes memory payload) internal pure {
        _castToPure(_sendLogPayloadImplementation)(payload);
    }

    function log() internal pure {
        _sendLogPayload(abi.encodeWithSignature("log()"));
    }
    function logInt(int256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
    }

    function logUint(uint256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
    }

    function logString(string memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function logBool(bool p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function logAddress(address p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function logBytes(bytes memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
    }

    function logBytes1(bytes1 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
    }

    function logBytes2(bytes2 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
    }

    function logBytes3(bytes3 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
    }

    function logBytes4(bytes4 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
    }

    function logBytes5(bytes5 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
    }

    function logBytes6(bytes6 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
    }

    function logBytes7(bytes7 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
    }

    function logBytes8(bytes8 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
    }

    function logBytes9(bytes9 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
    }

    function logBytes10(bytes10 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
    }

    function logBytes11(bytes11 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
    }

    function logBytes12(bytes12 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
    }

    function logBytes13(bytes13 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
    }

    function logBytes14(bytes14 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
    }

    function logBytes15(bytes15 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
    }

    function logBytes16(bytes16 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
    }

    function logBytes17(bytes17 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
    }

    function logBytes18(bytes18 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
    }

    function logBytes19(bytes19 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
    }

    function logBytes20(bytes20 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
    }

    function logBytes21(bytes21 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
    }

    function logBytes22(bytes22 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
    }

    function logBytes23(bytes23 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
    }

    function logBytes24(bytes24 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
    }

    function logBytes25(bytes25 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
    }

    function logBytes26(bytes26 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
    }

    function logBytes27(bytes27 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
    }

    function logBytes28(bytes28 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
    }

    function logBytes29(bytes29 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
    }

    function logBytes30(bytes30 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
    }

    function logBytes31(bytes31 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
    }

    function logBytes32(bytes32 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
    }

    function log(uint256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
    }

    function log(string memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function log(bool p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function log(address p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function log(uint256 p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1));
    }

    function log(uint256 p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1));
    }

    function log(uint256 p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1));
    }

    function log(uint256 p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1));
    }

    function log(string memory p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1));
    }

    function log(string memory p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
    }

    function log(string memory p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
    }

    function log(string memory p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
    }

    function log(bool p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1));
    }

    function log(bool p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
    }

    function log(bool p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
    }

    function log(bool p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
    }

    function log(address p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1));
    }

    function log(address p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
    }

    function log(address p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
    }

    function log(address p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
    }

    function log(uint256 p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
    }

    function log(string memory p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2));
    }

    function log(string memory p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
    }

    function log(string memory p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
    }

    function log(string memory p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
    }

    function log(bool p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2));
    }

    function log(bool p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
    }

    function log(bool p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
    }

    function log(bool p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
    }

    function log(bool p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2));
    }

    function log(bool p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
    }

    function log(bool p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
    }

    function log(bool p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2));
    }

    function log(address p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2));
    }

    function log(address p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
    }

    function log(address p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
    }

    function log(address p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
    }

    function log(address p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2));
    }

    function log(address p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
    }

    function log(address p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
    }

    function log(address p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
    }

    function log(address p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2));
    }

    function log(address p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
    }

    function log(address p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
    }

    function log(address p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
    }

}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint8","name":"traitType","type":"uint8"},{"internalType":"uint16","name":"traitIndex","type":"uint16"}],"name":"CannotFindMowseWear","type":"error"},{"inputs":[{"internalType":"uint256","name":"dictionaryIndex","type":"uint256"}],"name":"InvalidDictionaryIndex","type":"error"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"MissingAdminRole","type":"error"},{"inputs":[{"internalType":"uint8","name":"traitType","type":"uint8"},{"internalType":"uint16","name":"traitIndex","type":"uint16"},{"internalType":"uint256","name":"dictionaryIndex","type":"uint256"},{"internalType":"string","name":"image","type":"string"}],"name":"concatMowseWearDictionaryImage","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b5061058b806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80633bdbd56114610030575b600080fd5b61004361003e366004610259565b610045565b005b600054604051632acd144760e21b81523360048201526001600160a01b039091169063ab34511c90602401602060405180830381865afa15801561008d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100b19190610346565b6100fa5760405163718f3c1960e01b81526020600482015260146024820152734d75737420686176652041646d696e20526f6c6560601b60448201526064015b60405180910390fd5b60ff84166000908152600d6020908152604080832061ffff87168452909152902060010180546101299061036f565b905060000361015a576040516311bb030960e11b815260ff8516600482015261ffff841660248201526044016100f1565b600f54821061017f5760405163a9a933e160e01b8152600481018390526024016100f1565b60ff84166000908152600d6020908152604080832061ffff8716845282529182902091516101b392600901918491016103a9565b60408051601f1981840301815291815260ff86166000908152600d602090815282822061ffff88168352905220600901906101ee9082610495565b506000828152600e6020908152604091829020915161021392600901918491016103a9565b60408051601f198184030181529181526000848152600e602052206009019061023c9082610495565b5050505050565b634e487b7160e01b600052604160045260246000fd5b6000806000806080858703121561026f57600080fd5b843560ff8116811461028057600080fd5b9350602085013561ffff8116811461029757600080fd5b925060408501359150606085013567ffffffffffffffff808211156102bb57600080fd5b818701915087601f8301126102cf57600080fd5b8135818111156102e1576102e1610243565b604051601f8201601f19908116603f0116810190838211818310171561030957610309610243565b816040528281528a602084870101111561032257600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b60006020828403121561035857600080fd5b8151801515811461036857600080fd5b9392505050565b600181811c9082168061038357607f821691505b6020821081036103a357634e487b7160e01b600052602260045260246000fd5b50919050565b60008084546103b78161036f565b600182811680156103cf57600181146103e457610413565b60ff1984168752821515830287019450610413565b8860005260208060002060005b8581101561040a5781548a8201529084019082016103f1565b50505082870194505b50505050835160005b81811015610436576020818701810151848301520161041c565b5060009101908152949350505050565b601f82111561049057600081815260208120601f850160051c8101602086101561046d5750805b601f850160051c820191505b8181101561048c57828155600101610479565b5050505b505050565b815167ffffffffffffffff8111156104af576104af610243565b6104c3816104bd845461036f565b84610446565b602080601f8311600181146104f857600084156104e05750858301515b600019600386901b1c1916600185901b17855561048c565b600085815260208120601f198616915b8281101561052757888601518255948401946001909101908401610508565b50858210156105455787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea2646970667358221220a36977d4f647ff1040250947c8dc180d1a483d56006fed72595d5ba698efaac664736f6c63430008130033

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061002b5760003560e01c80633bdbd56114610030575b600080fd5b61004361003e366004610259565b610045565b005b600054604051632acd144760e21b81523360048201526001600160a01b039091169063ab34511c90602401602060405180830381865afa15801561008d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100b19190610346565b6100fa5760405163718f3c1960e01b81526020600482015260146024820152734d75737420686176652041646d696e20526f6c6560601b60448201526064015b60405180910390fd5b60ff84166000908152600d6020908152604080832061ffff87168452909152902060010180546101299061036f565b905060000361015a576040516311bb030960e11b815260ff8516600482015261ffff841660248201526044016100f1565b600f54821061017f5760405163a9a933e160e01b8152600481018390526024016100f1565b60ff84166000908152600d6020908152604080832061ffff8716845282529182902091516101b392600901918491016103a9565b60408051601f1981840301815291815260ff86166000908152600d602090815282822061ffff88168352905220600901906101ee9082610495565b506000828152600e6020908152604091829020915161021392600901918491016103a9565b60408051601f198184030181529181526000848152600e602052206009019061023c9082610495565b5050505050565b634e487b7160e01b600052604160045260246000fd5b6000806000806080858703121561026f57600080fd5b843560ff8116811461028057600080fd5b9350602085013561ffff8116811461029757600080fd5b925060408501359150606085013567ffffffffffffffff808211156102bb57600080fd5b818701915087601f8301126102cf57600080fd5b8135818111156102e1576102e1610243565b604051601f8201601f19908116603f0116810190838211818310171561030957610309610243565b816040528281528a602084870101111561032257600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b60006020828403121561035857600080fd5b8151801515811461036857600080fd5b9392505050565b600181811c9082168061038357607f821691505b6020821081036103a357634e487b7160e01b600052602260045260246000fd5b50919050565b60008084546103b78161036f565b600182811680156103cf57600181146103e457610413565b60ff1984168752821515830287019450610413565b8860005260208060002060005b8581101561040a5781548a8201529084019082016103f1565b50505082870194505b50505050835160005b81811015610436576020818701810151848301520161041c565b5060009101908152949350505050565b601f82111561049057600081815260208120601f850160051c8101602086101561046d5750805b601f850160051c820191505b8181101561048c57828155600101610479565b5050505b505050565b815167ffffffffffffffff8111156104af576104af610243565b6104c3816104bd845461036f565b84610446565b602080601f8311600181146104f857600084156104e05750858301515b600019600386901b1c1916600185901b17855561048c565b600085815260208120601f198616915b8281101561052757888601518255948401946001909101908401610508565b50858210156105455787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea2646970667358221220a36977d4f647ff1040250947c8dc180d1a483d56006fed72595d5ba698efaac664736f6c63430008130033

Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits

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.