/

    Contract Diff Checker

    Contract Name:
    BoringVault

    Contract Source Code:

    // SPDX-License-Identifier: UNLICENSED
    pragma solidity 0.8.21;
    
    import {Address} from "@openzeppelin/contracts/utils/Address.sol";
    import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
    import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
    import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";
    import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
    import {ERC20} from "@solmate/tokens/ERC20.sol";
    import {BeforeTransferHook} from "src/interfaces/BeforeTransferHook.sol";
    import {Auth, Authority} from "@solmate/auth/Auth.sol";
    
    contract BoringVault is ERC20, Auth, ERC721Holder, ERC1155Holder {
        using Address for address;
        using SafeTransferLib for ERC20;
        using FixedPointMathLib for uint256;
    
        // ========================================= STATE =========================================
    
        /**
         * @notice Contract responsbile for implementing `beforeTransfer`.
         */
        BeforeTransferHook public hook;
    
        //============================== EVENTS ===============================
    
        event Enter(address indexed from, address indexed asset, uint256 amount, address indexed to, uint256 shares);
        event Exit(address indexed to, address indexed asset, uint256 amount, address indexed from, uint256 shares);
    
        //============================== CONSTRUCTOR ===============================
    
        constructor(address _owner, string memory _name, string memory _symbol, uint8 _decimals)
            ERC20(_name, _symbol, _decimals)
            Auth(_owner, Authority(address(0)))
        {}
    
        //============================== MANAGE ===============================
    
        /**
         * @notice Allows manager to make an arbitrary function call from this contract.
         * @dev Callable by MANAGER_ROLE.
         */
        function manage(address target, bytes calldata data, uint256 value)
            external
            requiresAuth
            returns (bytes memory result)
        {
            result = target.functionCallWithValue(data, value);
        }
    
        /**
         * @notice Allows manager to make arbitrary function calls from this contract.
         * @dev Callable by MANAGER_ROLE.
         */
        function manage(address[] calldata targets, bytes[] calldata data, uint256[] calldata values)
            external
            requiresAuth
            returns (bytes[] memory results)
        {
            uint256 targetsLength = targets.length;
            results = new bytes[](targetsLength);
            for (uint256 i; i < targetsLength; ++i) {
                results[i] = targets[i].functionCallWithValue(data[i], values[i]);
            }
        }
    
        //============================== ENTER ===============================
    
        /**
         * @notice Allows minter to mint shares, in exchange for assets.
         * @dev If assetAmount is zero, no assets are transferred in.
         * @dev Callable by MINTER_ROLE.
         */
        function enter(address from, ERC20 asset, uint256 assetAmount, address to, uint256 shareAmount)
            external
            requiresAuth
        {
            // Transfer assets in
            if (assetAmount > 0) asset.safeTransferFrom(from, address(this), assetAmount);
    
            // Mint shares.
            _mint(to, shareAmount);
    
            emit Enter(from, address(asset), assetAmount, to, shareAmount);
        }
    
        //============================== EXIT ===============================
    
        /**
         * @notice Allows burner to burn shares, in exchange for assets.
         * @dev If assetAmount is zero, no assets are transferred out.
         * @dev Callable by BURNER_ROLE.
         */
        function exit(address to, ERC20 asset, uint256 assetAmount, address from, uint256 shareAmount)
            external
            requiresAuth
        {
            // Burn shares.
            _burn(from, shareAmount);
    
            // Transfer assets out.
            if (assetAmount > 0) asset.safeTransfer(to, assetAmount);
    
            emit Exit(to, address(asset), assetAmount, from, shareAmount);
        }
    
        //============================== BEFORE TRANSFER HOOK ===============================
        /**
         * @notice Sets the share locker.
         * @notice If set to zero address, the share locker logic is disabled.
         * @dev Callable by OWNER_ROLE.
         */
        function setBeforeTransferHook(address _hook) external requiresAuth {
            hook = BeforeTransferHook(_hook);
        }
    
        /**
         * @notice Call `beforeTransferHook` passing in `from` `to`, and `msg.sender`.
         */
        function _callBeforeTransfer(address from, address to) internal view {
            if (address(hook) != address(0)) hook.beforeTransfer(from, to, msg.sender);
        }
    
        function transfer(address to, uint256 amount) public override returns (bool) {
            _callBeforeTransfer(msg.sender, to);
            return super.transfer(to, amount);
        }
    
        function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
            _callBeforeTransfer(from, to);
            return super.transferFrom(from, to, amount);
        }
    
        //============================== RECEIVE ===============================
    
        receive() external payable {}
    }

    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
    
    pragma solidity ^0.8.20;
    
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev The ETH balance of the account is not enough to perform the operation.
         */
        error AddressInsufficientBalance(address account);
    
        /**
         * @dev There's no code at `target` (it is not a contract).
         */
        error AddressEmptyCode(address target);
    
        /**
         * @dev A call to an address target failed. The target may have reverted.
         */
        error FailedInnerCall();
    
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            if (address(this).balance < amount) {
                revert AddressInsufficientBalance(address(this));
            }
    
            (bool success, ) = recipient.call{value: amount}("");
            if (!success) {
                revert FailedInnerCall();
            }
        }
    
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain `call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason or custom error, it is bubbled
         * up by this function (like regular Solidity function calls). However, if
         * the call reverted with no returned reason, this function reverts with a
         * {FailedInnerCall} error.
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0);
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
            if (address(this).balance < value) {
                revert AddressInsufficientBalance(address(this));
            }
            (bool success, bytes memory returndata) = target.call{value: value}(data);
            return verifyCallResultFromTarget(target, success, returndata);
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a static call.
         */
        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
            (bool success, bytes memory returndata) = target.staticcall(data);
            return verifyCallResultFromTarget(target, success, returndata);
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a delegate call.
         */
        function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
            (bool success, bytes memory returndata) = target.delegatecall(data);
            return verifyCallResultFromTarget(target, success, returndata);
        }
    
        /**
         * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
         * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
         * unsuccessful call.
         */
        function verifyCallResultFromTarget(
            address target,
            bool success,
            bytes memory returndata
        ) internal view returns (bytes memory) {
            if (!success) {
                _revert(returndata);
            } else {
                // only check if target is a contract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                if (returndata.length == 0 && target.code.length == 0) {
                    revert AddressEmptyCode(target);
                }
                return returndata;
            }
        }
    
        /**
         * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
         * revert reason or with a default {FailedInnerCall} error.
         */
        function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
            if (!success) {
                _revert(returndata);
            } else {
                return returndata;
            }
        }
    
        /**
         * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
         */
        function _revert(bytes memory returndata) private pure {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert FailedInnerCall();
            }
        }
    }

    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol)
    
    pragma solidity ^0.8.20;
    
    import {IERC721Receiver} from "../IERC721Receiver.sol";
    
    /**
     * @dev Implementation of the {IERC721Receiver} interface.
     *
     * Accepts all token transfers.
     * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or
     * {IERC721-setApprovalForAll}.
     */
    abstract contract ERC721Holder is IERC721Receiver {
        /**
         * @dev See {IERC721Receiver-onERC721Received}.
         *
         * Always returns `IERC721Receiver.onERC721Received.selector`.
         */
        function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) {
            return this.onERC721Received.selector;
        }
    }

    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/utils/ERC1155Holder.sol)
    
    pragma solidity ^0.8.20;
    
    import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol";
    import {IERC1155Receiver} from "../IERC1155Receiver.sol";
    
    /**
     * @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC1155 tokens.
     *
     * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be
     * stuck.
     */
    abstract contract ERC1155Holder is ERC165, IERC1155Receiver {
        /**
         * @dev See {IERC165-supportsInterface}.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
            return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
        }
    
        function onERC1155Received(
            address,
            address,
            uint256,
            uint256,
            bytes memory
        ) public virtual override returns (bytes4) {
            return this.onERC1155Received.selector;
        }
    
        function onERC1155BatchReceived(
            address,
            address,
            uint256[] memory,
            uint256[] memory,
            bytes memory
        ) public virtual override returns (bytes4) {
            return this.onERC1155BatchReceived.selector;
        }
    }

    // SPDX-License-Identifier: AGPL-3.0-only
    pragma solidity >=0.8.0;
    
    /// @notice Arithmetic library with operations for fixed-point numbers.
    /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
    /// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
    library FixedPointMathLib {
        /*//////////////////////////////////////////////////////////////
                        SIMPLIFIED FIXED POINT OPERATIONS
        //////////////////////////////////////////////////////////////*/
    
        uint256 internal constant MAX_UINT256 = 2**256 - 1;
    
        uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
    
        function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
            return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
        }
    
        function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
            return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
        }
    
        function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
            return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
        }
    
        function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
            return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
        }
    
        /*//////////////////////////////////////////////////////////////
                        LOW LEVEL FIXED POINT OPERATIONS
        //////////////////////////////////////////////////////////////*/
    
        function mulDivDown(
            uint256 x,
            uint256 y,
            uint256 denominator
        ) internal pure returns (uint256 z) {
            /// @solidity memory-safe-assembly
            assembly {
                // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
                if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                    revert(0, 0)
                }
    
                // Divide x * y by the denominator.
                z := div(mul(x, y), denominator)
            }
        }
    
        function mulDivUp(
            uint256 x,
            uint256 y,
            uint256 denominator
        ) internal pure returns (uint256 z) {
            /// @solidity memory-safe-assembly
            assembly {
                // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
                if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                    revert(0, 0)
                }
    
                // If x * y modulo the denominator is strictly greater than 0,
                // 1 is added to round up the division of x * y by the denominator.
                z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
            }
        }
    
        function rpow(
            uint256 x,
            uint256 n,
            uint256 scalar
        ) internal pure returns (uint256 z) {
            /// @solidity memory-safe-assembly
            assembly {
                switch x
                case 0 {
                    switch n
                    case 0 {
                        // 0 ** 0 = 1
                        z := scalar
                    }
                    default {
                        // 0 ** n = 0
                        z := 0
                    }
                }
                default {
                    switch mod(n, 2)
                    case 0 {
                        // If n is even, store scalar in z for now.
                        z := scalar
                    }
                    default {
                        // If n is odd, store x in z for now.
                        z := x
                    }
    
                    // Shifting right by 1 is like dividing by 2.
                    let half := shr(1, scalar)
    
                    for {
                        // Shift n right by 1 before looping to halve it.
                        n := shr(1, n)
                    } n {
                        // Shift n right by 1 each iteration to halve it.
                        n := shr(1, n)
                    } {
                        // Revert immediately if x ** 2 would overflow.
                        // Equivalent to iszero(eq(div(xx, x), x)) here.
                        if shr(128, x) {
                            revert(0, 0)
                        }
    
                        // Store x squared.
                        let xx := mul(x, x)
    
                        // Round to the nearest number.
                        let xxRound := add(xx, half)
    
                        // Revert if xx + half overflowed.
                        if lt(xxRound, xx) {
                            revert(0, 0)
                        }
    
                        // Set x to scaled xxRound.
                        x := div(xxRound, scalar)
    
                        // If n is even:
                        if mod(n, 2) {
                            // Compute z * x.
                            let zx := mul(z, x)
    
                            // If z * x overflowed:
                            if iszero(eq(div(zx, x), z)) {
                                // Revert if x is non-zero.
                                if iszero(iszero(x)) {
                                    revert(0, 0)
                                }
                            }
    
                            // Round to the nearest number.
                            let zxRound := add(zx, half)
    
                            // Revert if zx + half overflowed.
                            if lt(zxRound, zx) {
                                revert(0, 0)
                            }
    
                            // Return properly scaled zxRound.
                            z := div(zxRound, scalar)
                        }
                    }
                }
            }
        }
    
        /*//////////////////////////////////////////////////////////////
                            GENERAL NUMBER UTILITIES
        //////////////////////////////////////////////////////////////*/
    
        function sqrt(uint256 x) internal pure returns (uint256 z) {
            /// @solidity memory-safe-assembly
            assembly {
                let y := x // We start y at x, which will help us make our initial estimate.
    
                z := 181 // The "correct" value is 1, but this saves a multiplication later.
    
                // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
                // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
    
                // We check y >= 2^(k + 8) but shift right by k bits
                // each branch to ensure that if x >= 256, then y >= 256.
                if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                    y := shr(128, y)
                    z := shl(64, z)
                }
                if iszero(lt(y, 0x1000000000000000000)) {
                    y := shr(64, y)
                    z := shl(32, z)
                }
                if iszero(lt(y, 0x10000000000)) {
                    y := shr(32, y)
                    z := shl(16, z)
                }
                if iszero(lt(y, 0x1000000)) {
                    y := shr(16, y)
                    z := shl(8, z)
                }
    
                // Goal was to get z*z*y within a small factor of x. More iterations could
                // get y in a tighter range. Currently, we will have y in [256, 256*2^16).
                // We ensured y >= 256 so that the relative difference between y and y+1 is small.
                // That's not possible if x < 256 but we can just verify those cases exhaustively.
    
                // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
                // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
                // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.
    
                // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
                // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.
    
                // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
                // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.
    
                // There is no overflow risk here since y < 2^136 after the first branch above.
                z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.
    
                // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
                z := shr(1, add(z, div(x, z)))
                z := shr(1, add(z, div(x, z)))
                z := shr(1, add(z, div(x, z)))
                z := shr(1, add(z, div(x, z)))
                z := shr(1, add(z, div(x, z)))
                z := shr(1, add(z, div(x, z)))
                z := shr(1, add(z, div(x, z)))
    
                // If x+1 is a perfect square, the Babylonian method cycles between
                // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
                // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
                // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
                // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
                z := sub(z, lt(div(x, z), z))
            }
        }
    
        function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
            /// @solidity memory-safe-assembly
            assembly {
                // Mod x by y. Note this will return
                // 0 instead of reverting if y is zero.
                z := mod(x, y)
            }
        }
    
        function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
            /// @solidity memory-safe-assembly
            assembly {
                // Divide x by y. Note this will return
                // 0 instead of reverting if y is zero.
                r := div(x, y)
            }
        }
    
        function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
            /// @solidity memory-safe-assembly
            assembly {
                // Add 1 to x * y if x % y > 0. Note this will
                // return 0 instead of reverting if y is zero.
                z := add(gt(mod(x, y), 0), div(x, y))
            }
        }
    }

    // SPDX-License-Identifier: AGPL-3.0-only
    pragma solidity >=0.8.0;
    
    import {ERC20} from "../tokens/ERC20.sol";
    
    /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
    /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
    /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
    /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
    library SafeTransferLib {
        /*//////////////////////////////////////////////////////////////
                                 ETH OPERATIONS
        //////////////////////////////////////////////////////////////*/
    
        function safeTransferETH(address to, uint256 amount) internal {
            bool success;
    
            /// @solidity memory-safe-assembly
            assembly {
                // Transfer the ETH and store if it succeeded or not.
                success := call(gas(), to, amount, 0, 0, 0, 0)
            }
    
            require(success, "ETH_TRANSFER_FAILED");
        }
    
        /*//////////////////////////////////////////////////////////////
                                ERC20 OPERATIONS
        //////////////////////////////////////////////////////////////*/
    
        function safeTransferFrom(
            ERC20 token,
            address from,
            address to,
            uint256 amount
        ) internal {
            bool success;
    
            /// @solidity memory-safe-assembly
            assembly {
                // Get a pointer to some free memory.
                let freeMemoryPointer := mload(0x40)
    
                // Write the abi-encoded calldata into memory, beginning with the function selector.
                mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
                mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
                mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
                mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
    
                success := and(
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                    // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                    // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                    // Counterintuitively, this call must be positioned second to the or() call in the
                    // surrounding and() call or else returndatasize() will be zero during the computation.
                    call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
                )
            }
    
            require(success, "TRANSFER_FROM_FAILED");
        }
    
        function safeTransfer(
            ERC20 token,
            address to,
            uint256 amount
        ) internal {
            bool success;
    
            /// @solidity memory-safe-assembly
            assembly {
                // Get a pointer to some free memory.
                let freeMemoryPointer := mload(0x40)
    
                // Write the abi-encoded calldata into memory, beginning with the function selector.
                mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
                mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
                mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
    
                success := and(
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                    // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                    // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                    // Counterintuitively, this call must be positioned second to the or() call in the
                    // surrounding and() call or else returndatasize() will be zero during the computation.
                    call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
                )
            }
    
            require(success, "TRANSFER_FAILED");
        }
    
        function safeApprove(
            ERC20 token,
            address to,
            uint256 amount
        ) internal {
            bool success;
    
            /// @solidity memory-safe-assembly
            assembly {
                // Get a pointer to some free memory.
                let freeMemoryPointer := mload(0x40)
    
                // Write the abi-encoded calldata into memory, beginning with the function selector.
                mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
                mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
                mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
    
                success := and(
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                    // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                    // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                    // Counterintuitively, this call must be positioned second to the or() call in the
                    // surrounding and() call or else returndatasize() will be zero during the computation.
                    call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
                )
            }
    
            require(success, "APPROVE_FAILED");
        }
    }

    // SPDX-License-Identifier: AGPL-3.0-only
    pragma solidity >=0.8.0;
    
    /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
    /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
    /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
    /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
    abstract contract ERC20 {
        /*//////////////////////////////////////////////////////////////
                                     EVENTS
        //////////////////////////////////////////////////////////////*/
    
        event Transfer(address indexed from, address indexed to, uint256 amount);
    
        event Approval(address indexed owner, address indexed spender, uint256 amount);
    
        /*//////////////////////////////////////////////////////////////
                                METADATA STORAGE
        //////////////////////////////////////////////////////////////*/
    
        string public name;
    
        string public symbol;
    
        uint8 public immutable decimals;
    
        /*//////////////////////////////////////////////////////////////
                                  ERC20 STORAGE
        //////////////////////////////////////////////////////////////*/
    
        uint256 public totalSupply;
    
        mapping(address => uint256) public balanceOf;
    
        mapping(address => mapping(address => uint256)) public allowance;
    
        /*//////////////////////////////////////////////////////////////
                                EIP-2612 STORAGE
        //////////////////////////////////////////////////////////////*/
    
        uint256 internal immutable INITIAL_CHAIN_ID;
    
        bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
    
        mapping(address => uint256) public nonces;
    
        /*//////////////////////////////////////////////////////////////
                                   CONSTRUCTOR
        //////////////////////////////////////////////////////////////*/
    
        constructor(
            string memory _name,
            string memory _symbol,
            uint8 _decimals
        ) {
            name = _name;
            symbol = _symbol;
            decimals = _decimals;
    
            INITIAL_CHAIN_ID = block.chainid;
            INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
        }
    
        /*//////////////////////////////////////////////////////////////
                                   ERC20 LOGIC
        //////////////////////////////////////////////////////////////*/
    
        function approve(address spender, uint256 amount) public virtual returns (bool) {
            allowance[msg.sender][spender] = amount;
    
            emit Approval(msg.sender, spender, amount);
    
            return true;
        }
    
        function transfer(address to, uint256 amount) public virtual returns (bool) {
            balanceOf[msg.sender] -= amount;
    
            // Cannot overflow because the sum of all user
            // balances can't exceed the max uint256 value.
            unchecked {
                balanceOf[to] += amount;
            }
    
            emit Transfer(msg.sender, to, amount);
    
            return true;
        }
    
        function transferFrom(
            address from,
            address to,
            uint256 amount
        ) public virtual returns (bool) {
            uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
    
            if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
    
            balanceOf[from] -= amount;
    
            // Cannot overflow because the sum of all user
            // balances can't exceed the max uint256 value.
            unchecked {
                balanceOf[to] += amount;
            }
    
            emit Transfer(from, to, amount);
    
            return true;
        }
    
        /*//////////////////////////////////////////////////////////////
                                 EIP-2612 LOGIC
        //////////////////////////////////////////////////////////////*/
    
        function permit(
            address owner,
            address spender,
            uint256 value,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) public virtual {
            require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
    
            // Unchecked because the only math done is incrementing
            // the owner's nonce which cannot realistically overflow.
            unchecked {
                address recoveredAddress = ecrecover(
                    keccak256(
                        abi.encodePacked(
                            "\x19\x01",
                            DOMAIN_SEPARATOR(),
                            keccak256(
                                abi.encode(
                                    keccak256(
                                        "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                    ),
                                    owner,
                                    spender,
                                    value,
                                    nonces[owner]++,
                                    deadline
                                )
                            )
                        )
                    ),
                    v,
                    r,
                    s
                );
    
                require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
    
                allowance[recoveredAddress][spender] = value;
            }
    
            emit Approval(owner, spender, value);
        }
    
        function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
            return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
        }
    
        function computeDomainSeparator() internal view virtual returns (bytes32) {
            return
                keccak256(
                    abi.encode(
                        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                        keccak256(bytes(name)),
                        keccak256("1"),
                        block.chainid,
                        address(this)
                    )
                );
        }
    
        /*//////////////////////////////////////////////////////////////
                            INTERNAL MINT/BURN LOGIC
        //////////////////////////////////////////////////////////////*/
    
        function _mint(address to, uint256 amount) internal virtual {
            totalSupply += amount;
    
            // Cannot overflow because the sum of all user
            // balances can't exceed the max uint256 value.
            unchecked {
                balanceOf[to] += amount;
            }
    
            emit Transfer(address(0), to, amount);
        }
    
        function _burn(address from, uint256 amount) internal virtual {
            balanceOf[from] -= amount;
    
            // Cannot underflow because a user's balance
            // will never be larger than the total supply.
            unchecked {
                totalSupply -= amount;
            }
    
            emit Transfer(from, address(0), amount);
        }
    }

    // SPDX-License-Identifier: UNLICENSED
    pragma solidity 0.8.21;
    
    interface BeforeTransferHook {
        function beforeTransfer(address from, address to, address operator) external view;
    }

    // SPDX-License-Identifier: AGPL-3.0-only
    pragma solidity >=0.8.0;
    
    /// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic.
    /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)
    /// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
    abstract contract Auth {
        event OwnershipTransferred(address indexed user, address indexed newOwner);
    
        event AuthorityUpdated(address indexed user, Authority indexed newAuthority);
    
        address public owner;
    
        Authority public authority;
    
        constructor(address _owner, Authority _authority) {
            owner = _owner;
            authority = _authority;
    
            emit OwnershipTransferred(msg.sender, _owner);
            emit AuthorityUpdated(msg.sender, _authority);
        }
    
        modifier requiresAuth() virtual {
            require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED");
    
            _;
        }
    
        function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {
            Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas.
    
            // Checking if the caller is the owner only after calling the authority saves gas in most cases, but be
            // aware that this makes protected functions uncallable even to the owner if the authority is out of order.
            return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner;
        }
    
        function setAuthority(Authority newAuthority) public virtual {
            // We check if the caller is the owner first because we want to ensure they can
            // always swap out the authority even if it's reverting or using up a lot of gas.
            require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig));
    
            authority = newAuthority;
    
            emit AuthorityUpdated(msg.sender, newAuthority);
        }
    
        function transferOwnership(address newOwner) public virtual requiresAuth {
            owner = newOwner;
    
            emit OwnershipTransferred(msg.sender, newOwner);
        }
    }
    
    /// @notice A generic interface for a contract which provides authorization data to an Auth instance.
    /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)
    /// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
    interface Authority {
        function canCall(
            address user,
            address target,
            bytes4 functionSig
        ) external view returns (bool);
    }

    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)
    
    pragma solidity ^0.8.20;
    
    /**
     * @title ERC721 token receiver interface
     * @dev Interface for any contract that wants to support safeTransfers
     * from ERC721 asset contracts.
     */
    interface IERC721Receiver {
        /**
         * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
         * by `operator` from `from`, this function is called.
         *
         * It must return its Solidity selector to confirm the token transfer.
         * If any other value is returned or the interface is not implemented by the recipient, the transfer will be
         * reverted.
         *
         * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
         */
        function onERC721Received(
            address operator,
            address from,
            uint256 tokenId,
            bytes calldata data
        ) external returns (bytes4);
    }

    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
    
    pragma solidity ^0.8.20;
    
    import {IERC165} from "./IERC165.sol";
    
    /**
     * @dev Implementation of the {IERC165} interface.
     *
     * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
     * for the additional interface id that will be supported. For example:
     *
     * ```solidity
     * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
     *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
     * }
     * ```
     */
    abstract contract ERC165 is IERC165 {
        /**
         * @dev See {IERC165-supportsInterface}.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
            return interfaceId == type(IERC165).interfaceId;
        }
    }

    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)
    
    pragma solidity ^0.8.20;
    
    import {IERC165} from "../../utils/introspection/IERC165.sol";
    
    /**
     * @dev Interface that must be implemented by smart contracts in order to receive
     * ERC-1155 token transfers.
     */
    interface IERC1155Receiver is IERC165 {
        /**
         * @dev Handles the receipt of a single ERC1155 token type. This function is
         * called at the end of a `safeTransferFrom` after the balance has been updated.
         *
         * NOTE: To accept the transfer, this must return
         * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
         * (i.e. 0xf23a6e61, or its own function selector).
         *
         * @param operator The address which initiated the transfer (i.e. msg.sender)
         * @param from The address which previously owned the token
         * @param id The ID of the token being transferred
         * @param value The amount of tokens being transferred
         * @param data Additional data with no specified format
         * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
         */
        function onERC1155Received(
            address operator,
            address from,
            uint256 id,
            uint256 value,
            bytes calldata data
        ) external returns (bytes4);
    
        /**
         * @dev Handles the receipt of a multiple ERC1155 token types. This function
         * is called at the end of a `safeBatchTransferFrom` after the balances have
         * been updated.
         *
         * NOTE: To accept the transfer(s), this must return
         * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
         * (i.e. 0xbc197c81, or its own function selector).
         *
         * @param operator The address which initiated the batch transfer (i.e. msg.sender)
         * @param from The address which previously owned the token
         * @param ids An array containing ids of each token being transferred (order and length must match values array)
         * @param values An array containing amounts of each token being transferred (order and length must match ids array)
         * @param data Additional data with no specified format
         * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
         */
        function onERC1155BatchReceived(
            address operator,
            address from,
            uint256[] calldata ids,
            uint256[] calldata values,
            bytes calldata data
        ) external returns (bytes4);
    }

    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
    
    pragma solidity ^0.8.20;
    
    /**
     * @dev Interface of the ERC165 standard, as defined in the
     * https://eips.ethereum.org/EIPS/eip-165[EIP].
     *
     * Implementers can declare support of contract interfaces, which can then be
     * queried by others ({ERC165Checker}).
     *
     * For an implementation, see {ERC165}.
     */
    interface IERC165 {
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }

    Please enter a contract address above to load the contract details and source code.

    Context size (optional):