Contract Address Details

0xbB3C660AD95306D4B3E6844A89F236a0233D52f2

Contract Name
PostLogic
Creator
0xe01c8d–e085f7 at 0x8e5770–bca55e
Balance
0 CSB
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
85531376
Contract name:
PostLogic




Optimization enabled
true
Compiler version
v0.8.18+commit.87f61d96




Optimization runs
200
Verified at
2023-11-30T01:02:10.232867Z

contracts/libraries/PostLogic.sol

// SPDX-License-Identifier: MIT
// solhint-disable private-vars-leading-underscore
pragma solidity 0.8.18;

import {DataTypes} from "./DataTypes.sol";
import {Events} from "./Events.sol";
import {ILinkModule4Note} from "../interfaces/ILinkModule4Note.sol";
import {IMintModule4Note} from "../interfaces/IMintModule4Note.sol";
import {IMintNFT} from "../interfaces/IMintNFT.sol";
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";

library PostLogic {
    using Strings for uint256;

    function postNoteWithLink(
        DataTypes.PostNoteData calldata vars,
        uint256 noteId,
        bytes32 linkItemType,
        bytes32 linkKey,
        bytes calldata data,
        mapping(uint256 => mapping(uint256 => DataTypes.Note)) storage _noteByIdByCharacter
    ) external {
        uint256 characterId = vars.characterId;
        DataTypes.Note storage note = _noteByIdByCharacter[characterId][noteId];

        // save note
        note.contentUri = vars.contentUri;
        if (linkItemType != bytes32(0)) {
            note.linkItemType = linkItemType;
            note.linkKey = linkKey;
        }

        // init link module
        _setLinkModule4Note(
            characterId,
            noteId,
            vars.linkModule,
            vars.linkModuleInitData,
            _noteByIdByCharacter
        );

        // init mint module
        _setMintModule4Note(
            characterId,
            noteId,
            vars.mintModule,
            vars.mintModuleInitData,
            _noteByIdByCharacter
        );

        emit Events.PostNote(characterId, noteId, linkKey, linkItemType, data);
    }

    function mintNote(
        uint256 characterId,
        uint256 noteId,
        address to,
        bytes calldata mintModuleData,
        address mintNFTImpl,
        mapping(uint256 => mapping(uint256 => DataTypes.Note)) storage _noteByIdByCharacter
    ) external returns (uint256 tokenId) {
        DataTypes.Note storage note = _noteByIdByCharacter[characterId][noteId];
        address mintNFT = note.mintNFT;
        if (mintNFT == address(0)) {
            mintNFT = _deployMintNFT(characterId, noteId, mintNFTImpl);
            note.mintNFT = mintNFT;
        }

        // mint nft
        tokenId = IMintNFT(mintNFT).mint(to);

        address mintModule = note.mintModule;
        if (mintModule != address(0)) {
            IMintModule4Note(mintModule).processMint(to, characterId, noteId, mintModuleData);
        }

        emit Events.MintNote(to, characterId, noteId, mintNFT, tokenId);
    }

    function setNoteUri(
        uint256 characterId,
        uint256 noteId,
        string calldata newUri,
        mapping(uint256 => mapping(uint256 => DataTypes.Note)) storage _noteByIdByCharacter
    ) external {
        _noteByIdByCharacter[characterId][noteId].contentUri = newUri;

        emit Events.SetNoteUri(characterId, noteId, newUri);
    }

    /**
     * @notice  Sets link module for a given note.
     * @param   characterId  The character ID to set link module for.
     * @param   noteId  The note ID to set link module for.
     * @param   linkModule  The link module to set.
     * @param   linkModuleInitData  The data to pass to the link module for initialization, if any.
     */
    function setLinkModule4Note(
        uint256 characterId,
        uint256 noteId,
        address linkModule,
        bytes calldata linkModuleInitData,
        mapping(uint256 => mapping(uint256 => DataTypes.Note)) storage _noteByIdByCharacter
    ) external {
        _setLinkModule4Note(
            characterId,
            noteId,
            linkModule,
            linkModuleInitData,
            _noteByIdByCharacter
        );
    }

    /**
     * @notice  Sets the mint module for a given note.
     * @param   characterId  The character ID of note to set the mint module for.
     * @param   noteId  The note ID of note.
     * @param   mintModule  The mint module to set for note.
     * @param   mintModuleInitData  The data to pass to the mint module.
     */
    function setMintModule4Note(
        uint256 characterId,
        uint256 noteId,
        address mintModule,
        bytes calldata mintModuleInitData,
        mapping(uint256 => mapping(uint256 => DataTypes.Note)) storage _noteByIdByCharacter
    ) external {
        _setMintModule4Note(
            characterId,
            noteId,
            mintModule,
            mintModuleInitData,
            _noteByIdByCharacter
        );
    }

    function _deployMintNFT(
        uint256 characterId,
        uint256 noteId,
        address mintNFTImpl
    ) internal returns (address mintNFT) {
        string memory symbol = string.concat(
            "Note-",
            characterId.toString(),
            "-",
            noteId.toString()
        );

        // deploy nft contract
        mintNFT = Clones.clone(mintNFTImpl);
        // initialize nft
        IMintNFT(mintNFT).initialize(characterId, noteId, address(this), symbol, symbol);
    }

    function _setLinkModule4Note(
        uint256 characterId,
        uint256 noteId,
        address linkModule,
        bytes calldata linkModuleInitData,
        mapping(uint256 => mapping(uint256 => DataTypes.Note)) storage _noteByIdByCharacter
    ) internal {
        if (linkModule != address(0)) {
            _noteByIdByCharacter[characterId][noteId].linkModule = linkModule;

            bytes memory returnData = ILinkModule4Note(linkModule).initializeLinkModule(
                characterId,
                noteId,
                linkModuleInitData
            );

            emit Events.SetLinkModule4Note(
                characterId,
                noteId,
                linkModule,
                linkModuleInitData,
                returnData
            );
        }
    }

    function _setMintModule4Note(
        uint256 characterId,
        uint256 noteId,
        address mintModule,
        bytes calldata mintModuleInitData,
        mapping(uint256 => mapping(uint256 => DataTypes.Note)) storage _noteByIdByCharacter
    ) internal {
        if (mintModule != address(0)) {
            _noteByIdByCharacter[characterId][noteId].mintModule = mintModule;

            bytes memory returnData = IMintModule4Note(mintModule).initializeMintModule(
                characterId,
                noteId,
                mintModuleInitData
            );

            emit Events.SetMintModule4Note(
                characterId,
                noteId,
                mintModule,
                mintModuleInitData,
                returnData
            );
        }
    }
}
        

@openzeppelin/contracts/proxy/Clones.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/Clones.sol)

pragma solidity ^0.8.0;

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 *
 * _Available since v3.4._
 */
library Clones {
    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create(0, 0x09, 0x37)
        }
        require(instance != address(0), "ERC1167: create failed");
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple time will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create2(0, 0x09, 0x37, salt)
        }
        require(instance != address(0), "ERC1167: create2 failed");
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(add(ptr, 0x38), deployer)
            mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
            mstore(add(ptr, 0x14), implementation)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
            mstore(add(ptr, 0x58), salt)
            mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
            predicted := keccak256(add(ptr, 0x43), 0x55)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddress(implementation, salt, address(this));
    }
}
          

@openzeppelin/contracts/utils/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));
    }
}
          

@openzeppelin/contracts/utils/math/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);
        }
    }
}
          

@openzeppelin/contracts/utils/math/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);
        }
    }
}
          

@openzeppelin/contracts/utils/structs/EnumerableSet.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}
          

contracts/interfaces/ILinkModule4Note.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

interface ILinkModule4Note {
    function initializeLinkModule(
        uint256 characterId,
        uint256 noteId,
        bytes calldata data
    ) external returns (bytes memory);

    function processLink(
        address caller,
        uint256 characterId,
        uint256 noteId,
        bytes calldata data
    ) external;
}
          

contracts/interfaces/IMintModule4Note.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;

interface IMintModule4Note {
    /**
     * @notice  Initialize the MintModule for a specific note.
     * @param   characterId  The character ID of the note to initialize.
     * @param   noteId  The note ID to initialize.
     * @param   data  The data passed from the user to be decoded.
     * @return  bytes  The returned data of calling initializeMintModule.
     */
    function initializeMintModule(
        uint256 characterId,
        uint256 noteId,
        bytes calldata data
    ) external returns (bytes memory);

    /**
     * @notice Processes the mint logic. <br>
     * Triggered when the `mintNote` of web3Entry is called, if mint module of note is set.
     * @param   to  The receive address of the NFT.
     * @param   characterId  The character ID of the note owner.
     * @param   noteId  The note ID.
     * @param   data  The data passed from the user to be decoded.
     */
    function processMint(
        address to,
        uint256 characterId,
        uint256 noteId,
        bytes calldata data
    ) external;
}
          

contracts/interfaces/IMintNFT.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

interface IMintNFT {
    /**
     * @notice Initialize the mint nft.
     * @param characterId_  The character ID of the note to initialize.
     * @param noteId_  The note ID to initialize.
     * @param web3Entry_  The address of web3Entry contract.
     * @param name_ The name to set for this NFT.
     * @param symbol_ The symbol to set for this NFT.
     */
    function initialize(
        uint256 characterId_,
        uint256 noteId_,
        address web3Entry_,
        string calldata name_,
        string calldata symbol_
    ) external;

    /**
     * @notice Mints a note NFT to the specified address.
     * This can only be called by web3Entry, and is called upon note.
     * @param to The address to mint the NFT to.
     * @return uint256 The minted token ID.
     */
    function mint(address to) external returns (uint256);

    /**
     * @notice Changes the royalty percentage of specific token ID for secondary sales.
     * Can only be called by character owner of note.
     * @param tokenId The token ID to set.
     * @param recipient The receive address.
     * @param fraction The royalty percentage measured in basis points. Each basis point represents 0.01%.
     */
    function setTokenRoyalty(uint256 tokenId, address recipient, uint96 fraction) external;

    /**
     * @notice Changes the default royalty percentage for secondary sales.
     * Can only be called by character owner of note.
     * @param recipient The receive address.
     * @param fraction The royalty percentage measured in basis points. Each basis point represents 0.01%.
     */
    function setDefaultRoyalty(address recipient, uint96 fraction) external;

    /**
     * @notice Deletes the default royalty percentage.
     * Can only be called by character owner of note.
     */
    function deleteDefaultRoyalty() external;

    /**
     * @notice Returns the original receiver of specified NFT.
     * @return The address of original receiver.
     */
    function originalReceiver(uint256 tokenId) external view returns (address);

    /**
     * @notice Returns the source note pointer mapped to this note NFT.
     * @return characterId The character ID.
     * @return noteId The note ID.
     */
    function getSourceNotePointer() external view returns (uint256 characterId, uint256 noteId);
}
          

contracts/libraries/DataTypes.sol

// SPDX-License-Identifier: MIT
// solhint-disable contract-name-camelcase
pragma solidity 0.8.18;

import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

/**
 * @title DataTypes
 * @notice A standard library of data types.
 */
library DataTypes {
    struct MigrateData {
        address account;
        string handle;
        string uri;
        address[] toAddresses;
        bytes32 linkType;
    }

    struct CreateCharacterData {
        address to;
        string handle;
        string uri;
        address linkModule;
        bytes linkModuleInitData;
    }

    struct createThenLinkCharacterData {
        uint256 fromCharacterId;
        address to;
        bytes32 linkType;
    }

    struct linkNoteData {
        uint256 fromCharacterId;
        uint256 toCharacterId;
        uint256 toNoteId;
        bytes32 linkType;
        bytes data;
    }

    struct unlinkNoteData {
        uint256 fromCharacterId;
        uint256 toCharacterId;
        uint256 toNoteId;
        bytes32 linkType;
    }

    struct linkCharacterData {
        uint256 fromCharacterId;
        uint256 toCharacterId;
        bytes32 linkType;
        bytes data;
    }

    struct unlinkCharacterData {
        uint256 fromCharacterId;
        uint256 toCharacterId;
        bytes32 linkType;
    }

    struct linkERC721Data {
        uint256 fromCharacterId;
        address tokenAddress;
        uint256 tokenId;
        bytes32 linkType;
        bytes data;
    }

    struct unlinkERC721Data {
        uint256 fromCharacterId;
        address tokenAddress;
        uint256 tokenId;
        bytes32 linkType;
    }

    struct linkAddressData {
        uint256 fromCharacterId;
        address ethAddress;
        bytes32 linkType;
        bytes data;
    }

    struct unlinkAddressData {
        uint256 fromCharacterId;
        address ethAddress;
        bytes32 linkType;
    }

    struct linkAnyUriData {
        uint256 fromCharacterId;
        string toUri;
        bytes32 linkType;
        bytes data;
    }

    struct unlinkAnyUriData {
        uint256 fromCharacterId;
        string toUri;
        bytes32 linkType;
    }

    struct linkLinklistData {
        uint256 fromCharacterId;
        uint256 toLinkListId;
        bytes32 linkType;
        bytes data;
    }

    struct unlinkLinklistData {
        uint256 fromCharacterId;
        uint256 toLinkListId;
        bytes32 linkType;
    }

    struct setLinkModule4CharacterData {
        uint256 characterId;
        address linkModule;
        bytes linkModuleInitData;
    }

    struct setLinkModule4NoteData {
        uint256 characterId;
        uint256 noteId;
        address linkModule;
        bytes linkModuleInitData;
    }

    struct setLinkModule4LinklistData {
        uint256 linklistId;
        address linkModule;
        bytes linkModuleInitData;
    }

    struct setLinkModule4ERC721Data {
        address tokenAddress;
        uint256 tokenId;
        address linkModule;
        bytes linkModuleInitData;
    }

    struct setLinkModule4AddressData {
        address account;
        address linkModule;
        bytes linkModuleInitData;
    }

    struct setMintModule4NoteData {
        uint256 characterId;
        uint256 noteId;
        address mintModule;
        bytes mintModuleInitData;
    }

    struct linkCharactersInBatchData {
        uint256 fromCharacterId;
        uint256[] toCharacterIds;
        bytes[] data;
        address[] toAddresses;
        bytes32 linkType;
    }

    struct LinkData {
        uint256 linklistId;
        uint256 linkItemType;
        uint256 linkingCharacterId;
        address linkingAddress;
        uint256 linkingLinklistId;
        bytes32 linkKey;
    }

    struct PostNoteData {
        uint256 characterId;
        string contentUri;
        address linkModule;
        bytes linkModuleInitData;
        address mintModule;
        bytes mintModuleInitData;
        bool locked;
    }

    struct MintNoteData {
        uint256 characterId;
        uint256 noteId;
        address to;
        bytes mintModuleData;
    }

    // character struct
    struct Character {
        uint256 characterId;
        string handle;
        string uri;
        uint256 noteCount;
        address socialToken;
        address linkModule;
    }

    /**
     * @dev A struct containing data associated with each new note.
     * @param linkItemType The link type of this note, if the note is a note with link.
     * @param linkKey If linkKey is not empty, it is a note with link(eg.a comment to a character or a note).
     * @param contentURI The URI associated with this note.
     * @param linkModule The address of the current link module of this note, can be empty.
     * @param mintModule  The address of the current mint module of this note, can be empty.
     * @param mintNFT The address of the mintNFT associated with this note, if any.
     * @param deleted Whether the note is deleted.
     * @param locked Whether the note is locked. If the note is locked, its owner can't set not uri anymore.
     */
    struct Note {
        bytes32 linkItemType;
        bytes32 linkKey;
        string contentUri;
        address linkModule;
        address mintModule;
        address mintNFT;
        bool deleted;
        bool locked;
    }

    struct CharacterLinkStruct {
        uint256 fromCharacterId;
        uint256 toCharacterId;
        bytes32 linkType;
    }

    struct NoteStruct {
        uint256 characterId;
        uint256 noteId;
    }

    struct ERC721Struct {
        address tokenAddress;
        uint256 erc721TokenId;
    }

    /**
     @param blocklist The list of blocklist addresses.
     @param allowlist The list of allowlist addresses.
     */
    struct Operators4Note {
        EnumerableSet.AddressSet blocklist;
        EnumerableSet.AddressSet allowlist;
    }

    /**
     * @dev A struct containing the necessary information to reconstruct an EIP-712 typed data signature.
     * @param v The signature's recovery parameter.
     * @param r The signature's r parameter.
     * @param s The signature's s parameter
     * @param deadline The signature's deadline.
     */
    struct EIP712Signature {
        uint8 v;
        bytes32 r;
        bytes32 s;
        uint256 deadline;
    }
}
          

contracts/libraries/Events.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

library Events {
    event BaseInitialized(string name, string symbol, uint256 timestamp);

    event Web3EntryInitialized(uint256 timestamp);

    event LinklistNFTInitialized(uint256 timestamp);

    event MintNFTInitialized(uint256 characterId, uint256 noteId, uint256 timestamp);

    event CharacterCreated(
        uint256 indexed characterId,
        address indexed creator,
        address indexed to,
        string handle,
        uint256 timestamp
    );

    event SetPrimaryCharacterId(
        address indexed account,
        uint256 indexed characterId,
        uint256 indexed oldCharacterId
    );

    event SetHandle(address indexed account, uint256 indexed characterId, string newHandle);

    event SetSocialToken(
        address indexed account,
        uint256 indexed characterId,
        address indexed tokenAddress
    );

    event GrantOperatorPermissions(
        uint256 indexed characterId,
        address indexed operator,
        uint256 permissionBitMap
    );

    event GrantOperators4Note(
        uint256 indexed characterId,
        uint256 indexed noteId,
        address[] blocklist,
        address[] allowlist
    );

    event SetCharacterUri(uint256 indexed characterId, string newUri);

    event PostNote(
        uint256 indexed characterId,
        uint256 indexed noteId,
        bytes32 indexed linkKey,
        bytes32 linkItemType,
        bytes data
    );

    event SetNoteUri(uint256 indexed characterId, uint256 noteId, string newUri);

    event DeleteNote(uint256 indexed characterId, uint256 noteId);

    event LockNote(uint256 indexed characterId, uint256 noteId);

    event LinkCharacter(
        address indexed account,
        uint256 indexed fromCharacterId,
        uint256 indexed toCharacterId,
        bytes32 linkType,
        uint256 linklistId
    );

    event UnlinkCharacter(
        address indexed account,
        uint256 indexed fromCharacterId,
        uint256 indexed toCharacterId,
        bytes32 linkType
    );

    event LinkNote(
        uint256 indexed fromCharacterId,
        uint256 indexed toCharacterId,
        uint256 indexed toNoteId,
        bytes32 linkType,
        uint256 linklistId
    );

    event UnlinkNote(
        uint256 indexed fromCharacterId,
        uint256 indexed toCharacterId,
        uint256 indexed toNoteId,
        bytes32 linkType,
        uint256 linklistId
    );

    event LinkERC721(
        uint256 indexed fromCharacterId,
        address indexed tokenAddress,
        uint256 indexed toNoteId,
        bytes32 linkType,
        uint256 linklistId
    );

    event LinkAddress(
        uint256 indexed fromCharacterId,
        address indexed ethAddress,
        bytes32 linkType,
        uint256 linklistId
    );

    event UnlinkAddress(
        uint256 indexed fromCharacterId,
        address indexed ethAddress,
        bytes32 linkType
    );

    event LinkAnyUri(
        uint256 indexed fromCharacterId,
        string toUri,
        bytes32 linkType,
        uint256 linklistId
    );

    event UnlinkAnyUri(uint256 indexed fromCharacterId, string toUri, bytes32 linkType);

    event LinkCharacterLink(
        uint256 indexed fromCharacterId,
        bytes32 indexed linkType,
        uint256 clFromCharacterId,
        uint256 clToCharacterId,
        bytes32 clLinkType
    );

    event UnlinkCharacterLink(
        uint256 indexed fromCharacterId,
        bytes32 indexed linkType,
        uint256 clFromCharactereId,
        uint256 clToCharacterId,
        bytes32 clLinkType
    );

    event UnlinkERC721(
        uint256 indexed fromCharacterId,
        address indexed tokenAddress,
        uint256 indexed toNoteId,
        bytes32 linkType,
        uint256 linklistId
    );

    event LinkLinklist(
        uint256 indexed fromCharacterId,
        uint256 indexed toLinklistId,
        bytes32 linkType,
        uint256 indexed linklistId
    );

    event UnlinkLinklist(
        uint256 indexed fromCharacterId,
        uint256 indexed toLinklistId,
        bytes32 linkType,
        uint256 indexed linklistId
    );

    event MintNote(
        address indexed to,
        uint256 indexed characterId,
        uint256 indexed noteId,
        address tokenAddress,
        uint256 tokenId
    );

    event SetLinkModule4Character(
        uint256 indexed characterId,
        address indexed linkModule,
        bytes linkModuleInitData,
        bytes returnData
    );

    event SetLinkModule4Note(
        uint256 indexed characterId,
        uint256 indexed noteId,
        address indexed linkModule,
        bytes linkModuleInitData,
        bytes returnData
    );

    event SetLinkModule4Address(
        address indexed account,
        address indexed linkModule,
        bytes linkModuleInitData,
        bytes returnData
    );

    event SetLinkModule4ERC721(
        address indexed tokenAddress,
        uint256 indexed tokenId,
        address indexed linkModule,
        bytes linkModuleInitData,
        bytes returnData
    );

    event SetLinkModule4Linklist(
        uint256 indexed linklistId,
        address indexed linkModule,
        bytes linkModuleInitData,
        bytes returnData
    );

    event SetMintModule4Note(
        uint256 indexed characterId,
        uint256 indexed noteId,
        address indexed mintModule,
        bytes mintModuleInitData,
        bytes returnData
    );

    event AttachLinklist(
        uint256 indexed linklistId,
        uint256 indexed characterId,
        bytes32 indexed linkType
    );

    event DetachLinklist(
        uint256 indexed linklistId,
        uint256 indexed characterId,
        bytes32 indexed linkType
    );

    event SetApprovedMintAmount4Addresses(
        uint256 indexed characterId,
        uint256 indexed noteId,
        uint256 indexed amount,
        address[] approvedAddresses
    );
}
          

Compiler Settings

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

Contract ABI

[]
              

Contract Creation Code

0x610f8c61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100615760003560e01c80631f2ffb691461006657806320828a021461008857806342a34a53146100a85780639d2e06f0146100c8578063ff97fd41146100fa575b600080fd5b81801561007257600080fd5b50610086610081366004610934565b61011a565b005b81801561009457600080fd5b506100866100a3366004610934565b610130565b8180156100b457600080fd5b506100866100c33660046109a4565b61013e565b8180156100d457600080fd5b506100e86100e3366004610a3c565b61021f565b60405190815260200160405180910390f35b81801561010657600080fd5b50610086610115366004610abe565b6103b7565b610128868686868686610420565b505050505050565b610128868686868686610525565b86356000818152602083815260408083208a8452825290912090610164908a018a610b19565b6002830191610174919083610bfb565b50861561018657868155600181018690555b6101ae828961019b60608d0160408e01610cbc565b6101a860608e018e610b19565b88610420565b6101d682896101c360a08d0160808e01610cbc565b6101d060a08e018e610b19565b88610525565b8588837f6ea6daa2449ded342bb92186e54e576ec7c6a729d4ccbf6f364e1bd1f1a527408a898960405161020c93929190610d07565b60405180910390a4505050505050505050565b600087815260208281526040808320898452909152812060058101546001600160a01b031680610274576102548a8a87610619565b6005830180546001600160a01b0319166001600160a01b03831617905590505b6040516335313c2160e11b81526001600160a01b038981166004830152821690636a627842906024016020604051808303816000875af11580156102bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102e09190610d2a565b60048301549093506001600160a01b0316801561035e57604051637f20dc2160e01b81526001600160a01b03821690637f20dc219061032b908c908f908f908e908e90600401610d43565b600060405180830381600087803b15801561034557600080fd5b505af1158015610359573d6000803e3d6000fd5b505050505b604080516001600160a01b038481168252602082018790528c928e92918d16917f6f1704cf3bc1cfc1bc2284eee0ba541a208bc80989f559ed39cc6567d77cf212910160405180910390a4505050979650505050505050565b60008581526020828152604080832087845290915290206002016103dc838583610bfb565b50847f179143dd0d35a50f482efc003aa5b84a0c3a40d74e9cc2d7ea3053b9e8c3769785858560405161041193929190610d07565b60405180910390a25050505050565b6001600160a01b038416156101285760008681526020828152604080832088845290915280822060030180546001600160a01b0319166001600160a01b038816908117909155905163f033607760e01b815263f03360779061048c908a908a9089908990600401610d7c565b6000604051808303816000875af11580156104ab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104d39190810190610dca565b9050846001600160a01b031686887fdd823eae04016ba1d4def5cad3271f666f3be1645ecfcf019fc4e796df2d634787878660405161051493929190610e98565b60405180910390a450505050505050565b6001600160a01b0384161561012857600086815260208281526040808320888452909152808220600490810180546001600160a01b0319166001600160a01b0389169081179091559151633ee9bd4f60e11b8152637dd37a9e91610591918b918b918a918a9101610d7c565b6000604051808303816000875af11580156105b0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105d89190810190610dca565b9050846001600160a01b031686887f3f256e11ad5e7ccc6f4bd12e4f56b5c63b024aeff884c5426d07ce827434d14c87878660405161051493929190610e98565b600080610625856106ca565b61062e856106ca565b60405160200161063f929190610ebe565b60405160208183030381529060405290506106598361075d565b6040516317eb5c4360e11b81529092506001600160a01b03831690632fd6b886906106909088908890309087908190600401610f0b565b600060405180830381600087803b1580156106aa57600080fd5b505af11580156106be573d6000803e3d6000fd5b50505050509392505050565b606060006106d7836107fb565b600101905060008167ffffffffffffffff8111156106f7576106f7610b60565b6040519080825280601f01601f191660200182016040528015610721576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461072b57509392505050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008260601b60e81c176000526e5af43d82803e903d91602b57fd5bf38260781b17602052603760096000f090506001600160a01b0381166107f65760405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b604482015260640160405180910390fd5b919050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061083a5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310610866576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061088457662386f26fc10000830492506010015b6305f5e100831061089c576305f5e100830492506008015b61271083106108b057612710830492506004015b606483106108c2576064830492506002015b600a83106108ce576001015b92915050565b80356001600160a01b03811681146107f657600080fd5b60008083601f8401126108fd57600080fd5b50813567ffffffffffffffff81111561091557600080fd5b60208301915083602082850101111561092d57600080fd5b9250929050565b60008060008060008060a0878903121561094d57600080fd5b8635955060208701359450610964604088016108d4565b9350606087013567ffffffffffffffff81111561098057600080fd5b61098c89828a016108eb565b979a9699509497949695608090950135949350505050565b600080600080600080600060c0888a0312156109bf57600080fd5b873567ffffffffffffffff808211156109d757600080fd5b9089019060e0828c0312156109eb57600080fd5b90975060208901359650604089013595506060890135945060808901359080821115610a1657600080fd5b50610a238a828b016108eb565b989b979a5095989497959660a090950135949350505050565b600080600080600080600060c0888a031215610a5757600080fd5b8735965060208801359550610a6e604089016108d4565b9450606088013567ffffffffffffffff811115610a8a57600080fd5b610a968a828b016108eb565b9095509350610aa99050608089016108d4565b915060a0880135905092959891949750929550565b600080600080600060808688031215610ad657600080fd5b8535945060208601359350604086013567ffffffffffffffff811115610afb57600080fd5b610b07888289016108eb565b96999598509660600135949350505050565b6000808335601e19843603018112610b3057600080fd5b83018035915067ffffffffffffffff821115610b4b57600080fd5b60200191503681900382131561092d57600080fd5b634e487b7160e01b600052604160045260246000fd5b600181811c90821680610b8a57607f821691505b602082108103610baa57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610bf657600081815260208120601f850160051c81016020861015610bd75750805b601f850160051c820191505b8181101561012857828155600101610be3565b505050565b67ffffffffffffffff831115610c1357610c13610b60565b610c2783610c218354610b76565b83610bb0565b6000601f841160018114610c5b5760008515610c435750838201355b600019600387901b1c1916600186901b178355610cb5565b600083815260209020601f19861690835b82811015610c8c5786850135825560209485019460019092019101610c6c565b5086821015610ca95760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b600060208284031215610cce57600080fd5b610cd7826108d4565b9392505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b838152604060208201526000610d21604083018486610cde565b95945050505050565b600060208284031215610d3c57600080fd5b5051919050565b60018060a01b0386168152846020820152836040820152608060608201526000610d71608083018486610cde565b979650505050505050565b848152836020820152606060408201526000610d9c606083018486610cde565b9695505050505050565b60005b83811015610dc1578181015183820152602001610da9565b50506000910152565b600060208284031215610ddc57600080fd5b815167ffffffffffffffff80821115610df457600080fd5b818401915084601f830112610e0857600080fd5b815181811115610e1a57610e1a610b60565b604051601f8201601f19908116603f01168101908382118183101715610e4257610e42610b60565b81604052828152876020848701011115610e5b57600080fd5b610d71836020830160208801610da6565b60008151808452610e84816020860160208601610da6565b601f01601f19169290920160200192915050565b604081526000610eac604083018587610cde565b8281036020840152610d9c8185610e6c565b644e6f74652d60d81b815260008351610ede816005850160208801610da6565b602d60f81b6005918401918201528351610eff816006840160208801610da6565b01600601949350505050565b85815284602082015260018060a01b038416604082015260a060608201526000610f3860a0830185610e6c565b8281036080840152610f4a8185610e6c565b9897505050505050505056fea26469706673582212205feba857a5614d1b5d6c8100a252d7f08635d796407cdaef139597836958371c64736f6c63430008120033

Deployed ByteCode

0x73bb3c660ad95306d4b3e6844a89f236a0233d52f230146080604052600436106100615760003560e01c80631f2ffb691461006657806320828a021461008857806342a34a53146100a85780639d2e06f0146100c8578063ff97fd41146100fa575b600080fd5b81801561007257600080fd5b50610086610081366004610934565b61011a565b005b81801561009457600080fd5b506100866100a3366004610934565b610130565b8180156100b457600080fd5b506100866100c33660046109a4565b61013e565b8180156100d457600080fd5b506100e86100e3366004610a3c565b61021f565b60405190815260200160405180910390f35b81801561010657600080fd5b50610086610115366004610abe565b6103b7565b610128868686868686610420565b505050505050565b610128868686868686610525565b86356000818152602083815260408083208a8452825290912090610164908a018a610b19565b6002830191610174919083610bfb565b50861561018657868155600181018690555b6101ae828961019b60608d0160408e01610cbc565b6101a860608e018e610b19565b88610420565b6101d682896101c360a08d0160808e01610cbc565b6101d060a08e018e610b19565b88610525565b8588837f6ea6daa2449ded342bb92186e54e576ec7c6a729d4ccbf6f364e1bd1f1a527408a898960405161020c93929190610d07565b60405180910390a4505050505050505050565b600087815260208281526040808320898452909152812060058101546001600160a01b031680610274576102548a8a87610619565b6005830180546001600160a01b0319166001600160a01b03831617905590505b6040516335313c2160e11b81526001600160a01b038981166004830152821690636a627842906024016020604051808303816000875af11580156102bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102e09190610d2a565b60048301549093506001600160a01b0316801561035e57604051637f20dc2160e01b81526001600160a01b03821690637f20dc219061032b908c908f908f908e908e90600401610d43565b600060405180830381600087803b15801561034557600080fd5b505af1158015610359573d6000803e3d6000fd5b505050505b604080516001600160a01b038481168252602082018790528c928e92918d16917f6f1704cf3bc1cfc1bc2284eee0ba541a208bc80989f559ed39cc6567d77cf212910160405180910390a4505050979650505050505050565b60008581526020828152604080832087845290915290206002016103dc838583610bfb565b50847f179143dd0d35a50f482efc003aa5b84a0c3a40d74e9cc2d7ea3053b9e8c3769785858560405161041193929190610d07565b60405180910390a25050505050565b6001600160a01b038416156101285760008681526020828152604080832088845290915280822060030180546001600160a01b0319166001600160a01b038816908117909155905163f033607760e01b815263f03360779061048c908a908a9089908990600401610d7c565b6000604051808303816000875af11580156104ab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104d39190810190610dca565b9050846001600160a01b031686887fdd823eae04016ba1d4def5cad3271f666f3be1645ecfcf019fc4e796df2d634787878660405161051493929190610e98565b60405180910390a450505050505050565b6001600160a01b0384161561012857600086815260208281526040808320888452909152808220600490810180546001600160a01b0319166001600160a01b0389169081179091559151633ee9bd4f60e11b8152637dd37a9e91610591918b918b918a918a9101610d7c565b6000604051808303816000875af11580156105b0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105d89190810190610dca565b9050846001600160a01b031686887f3f256e11ad5e7ccc6f4bd12e4f56b5c63b024aeff884c5426d07ce827434d14c87878660405161051493929190610e98565b600080610625856106ca565b61062e856106ca565b60405160200161063f929190610ebe565b60405160208183030381529060405290506106598361075d565b6040516317eb5c4360e11b81529092506001600160a01b03831690632fd6b886906106909088908890309087908190600401610f0b565b600060405180830381600087803b1580156106aa57600080fd5b505af11580156106be573d6000803e3d6000fd5b50505050509392505050565b606060006106d7836107fb565b600101905060008167ffffffffffffffff8111156106f7576106f7610b60565b6040519080825280601f01601f191660200182016040528015610721576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461072b57509392505050565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008260601b60e81c176000526e5af43d82803e903d91602b57fd5bf38260781b17602052603760096000f090506001600160a01b0381166107f65760405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b604482015260640160405180910390fd5b919050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061083a5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310610866576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061088457662386f26fc10000830492506010015b6305f5e100831061089c576305f5e100830492506008015b61271083106108b057612710830492506004015b606483106108c2576064830492506002015b600a83106108ce576001015b92915050565b80356001600160a01b03811681146107f657600080fd5b60008083601f8401126108fd57600080fd5b50813567ffffffffffffffff81111561091557600080fd5b60208301915083602082850101111561092d57600080fd5b9250929050565b60008060008060008060a0878903121561094d57600080fd5b8635955060208701359450610964604088016108d4565b9350606087013567ffffffffffffffff81111561098057600080fd5b61098c89828a016108eb565b979a9699509497949695608090950135949350505050565b600080600080600080600060c0888a0312156109bf57600080fd5b873567ffffffffffffffff808211156109d757600080fd5b9089019060e0828c0312156109eb57600080fd5b90975060208901359650604089013595506060890135945060808901359080821115610a1657600080fd5b50610a238a828b016108eb565b989b979a5095989497959660a090950135949350505050565b600080600080600080600060c0888a031215610a5757600080fd5b8735965060208801359550610a6e604089016108d4565b9450606088013567ffffffffffffffff811115610a8a57600080fd5b610a968a828b016108eb565b9095509350610aa99050608089016108d4565b915060a0880135905092959891949750929550565b600080600080600060808688031215610ad657600080fd5b8535945060208601359350604086013567ffffffffffffffff811115610afb57600080fd5b610b07888289016108eb565b96999598509660600135949350505050565b6000808335601e19843603018112610b3057600080fd5b83018035915067ffffffffffffffff821115610b4b57600080fd5b60200191503681900382131561092d57600080fd5b634e487b7160e01b600052604160045260246000fd5b600181811c90821680610b8a57607f821691505b602082108103610baa57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610bf657600081815260208120601f850160051c81016020861015610bd75750805b601f850160051c820191505b8181101561012857828155600101610be3565b505050565b67ffffffffffffffff831115610c1357610c13610b60565b610c2783610c218354610b76565b83610bb0565b6000601f841160018114610c5b5760008515610c435750838201355b600019600387901b1c1916600186901b178355610cb5565b600083815260209020601f19861690835b82811015610c8c5786850135825560209485019460019092019101610c6c565b5086821015610ca95760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b600060208284031215610cce57600080fd5b610cd7826108d4565b9392505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b838152604060208201526000610d21604083018486610cde565b95945050505050565b600060208284031215610d3c57600080fd5b5051919050565b60018060a01b0386168152846020820152836040820152608060608201526000610d71608083018486610cde565b979650505050505050565b848152836020820152606060408201526000610d9c606083018486610cde565b9695505050505050565b60005b83811015610dc1578181015183820152602001610da9565b50506000910152565b600060208284031215610ddc57600080fd5b815167ffffffffffffffff80821115610df457600080fd5b818401915084601f830112610e0857600080fd5b815181811115610e1a57610e1a610b60565b604051601f8201601f19908116603f01168101908382118183101715610e4257610e42610b60565b81604052828152876020848701011115610e5b57600080fd5b610d71836020830160208801610da6565b60008151808452610e84816020860160208601610da6565b601f01601f19169290920160200192915050565b604081526000610eac604083018587610cde565b8281036020840152610d9c8185610e6c565b644e6f74652d60d81b815260008351610ede816005850160208801610da6565b602d60f81b6005918401918201528351610eff816006840160208801610da6565b01600601949350505050565b85815284602082015260018060a01b038416604082015260a060608201526000610f3860a0830185610e6c565b8281036080840152610f4a8185610e6c565b9897505050505050505056fea26469706673582212205feba857a5614d1b5d6c8100a252d7f08635d796407cdaef139597836958371c64736f6c63430008120033