APE Price: $0.67 (-4.68%)
    /

    Contract Diff Checker

    Contract Name:
    FallbackHandler

    Contract Source Code:

    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)
    
    pragma solidity ^0.8.0;
    
    import "../../utils/introspection/IERC165.sol";
    
    /**
     * @dev _Available since v3.1._
     */
    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 v4.6.0) (token/ERC721/IERC721Receiver.sol)
    
    pragma solidity ^0.8.0;
    
    /**
     * @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 v4.4.1 (utils/introspection/IERC165.sol)
    
    pragma solidity ^0.8.0;
    
    /**
     * @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);
    }

    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.19;
    
    import { RoleManagerStorage } from "./managers/RoleManager.sol";
    import { ModuleManagerStorage } from "./managers/ModuleManager.sol";
    
    /// @title Cyan Wallet Core Storage - A Cyan wallet's core storage.
    /// @dev This contract only needed if the Module wants to access main storage of the wallet.
    ///     Must be the very first parent of the Module contract.
    /// @author Bulgantamir Gankhuyag - <bulgaa@usecyan.com>
    /// @author Naranbayar Uuganbayar - <naba@usecyan.com>
    abstract contract CoreStorage is RoleManagerStorage, ModuleManagerStorage {
    
    }

    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.19;
    
    import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
    import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
    
    import "../helpers/Utils.sol";
    import "./CoreStorage.sol";
    import "./Lockers.sol" as Lockers;
    
    /// @title Cyan Wallet Fallback Handler - A Cyan wallet's fallback handler.
    /// @author Bulgantamir Gankhuyag - <bulgaa@usecyan.com>
    /// @author Naranbayar Uuganbayar - <naba@usecyan.com>
    contract FallbackHandler is CoreStorage, IERC721Receiver, IERC1155Receiver {
        // bytes4(keccak256("isValidSignature(bytes32,bytes)"));
        bytes4 internal constant ERC1271_MAGIC_VALUE = 0x1626ba7e;
    
        // bytes4(keccak256("supportsInterface(bytes4)"))
        bytes4 private constant ERC165_INTERFACE = 0x01ffc9a7;
    
        // bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"));
        bytes4 private constant ERC1155_RECEIVED = 0xf23a6e61;
    
        // bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"));
        bytes4 private constant ERC1155_BATCH_RECEIVED = 0xbc197c81;
    
        // bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
        bytes4 private constant ERC721_RECEIVED = 0x150b7a02;
    
        event EthTransferred(address indexed receiver, uint256 value);
    
        /// @notice Allows the wallet to receive an ERC721 tokens.
        function onERC721Received(
            address,
            address,
            uint256,
            bytes calldata
        ) external pure returns (bytes4) {
            return ERC721_RECEIVED;
        }
    
        /// @notice Allows the wallet to receive an ERC1155 token.
        function onERC1155Received(
            address,
            address,
            uint256,
            uint256,
            bytes calldata
        ) external pure returns (bytes4) {
            return ERC1155_RECEIVED;
        }
    
        /// @notice Allows the wallet to receive an ERC1155 tokens.
        function onERC1155BatchReceived(
            address,
            address,
            uint256[] calldata,
            uint256[] calldata,
            bytes calldata
        ) external pure returns (bytes4) {
            return ERC1155_BATCH_RECEIVED;
        }
    
        function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) {
            return
                interfaceId == type(IERC1155Receiver).interfaceId ||
                interfaceId == type(IERC721Receiver).interfaceId ||
                interfaceId == type(IERC165).interfaceId;
        }
    
        /// @notice Return whether the signature provided is valid for the provided data.
        /// @param data Data signed on the behalf of the wallet.
        /// @param signature Signature byte array associated with the data.
        /// @return magicValue Returns a magic value (0x1626ba7e) if the given signature is correct.
        function isValidSignature(bytes32 data, bytes calldata signature) external view returns (bytes4 magicValue) {
            require(signature.length == 65, "Invalid signature length.");
            address signer = Utils.recoverSigner(data, signature);
            require(signer == _owner, "Invalid signer.");
            return ERC1271_MAGIC_VALUE;
        }
    
        function isLockedERC721(address collection, uint256 tokenId) external view returns (bool) {
            return Lockers.isLockedERC721(collection, tokenId);
        }
    
        function isLockedByCyanPlanERC721(address collection, uint256 tokenId) external view returns (bool) {
            return Lockers.isLockedByCyanPlanERC721(collection, tokenId);
        }
    
        function isLockedByApePlan(address collection, uint256 tokenId) external view returns (bool) {
            return Lockers.isLockedByApePlan(collection, tokenId);
        }
    
        function getLockedERC1155Amount(address collection, uint256 tokenId) external view returns (uint256) {
            return Lockers.getLockedERC1155Amount(collection, tokenId);
        }
    
        function getApeLockState(address collection, uint256 tokenId) external view returns (uint8) {
            return Lockers.getApeLockState(collection, tokenId);
        }
    }

    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.19;
    
    // keccak256("wallet.YugaModule.lockedApe")
    bytes32 constant APE_PLAN_LOCKER_SLOT = 0x010881fa8a1edce184936a8e4e08060bba49cb5145c9b396e6e80c0c6b0e1269;
    
    // keccak256("wallet.ERC721Module.lockedERC721")
    bytes32 constant CYAN_PLAN_LOCKER_SLOT_ERC721 = 0x25888debd3e1e584ccaebe1162c7763ec457a94078c5d0d9a1d32a926ff9973c;
    
    // keccak256("wallet.ERC1155Module.lockedERC1155")
    bytes32 constant CYAN_PLAN_LOCKER_SLOT_ERC1155 = 0xdcc609ac7fc3b6a216ce1445788736c9dbe88a58b25a13af71623e6da931efa0;
    
    // keccak256("wallet.CryptoPunksModule.lockedCryptoPunks")
    bytes32 constant CRYPTO_PUNKS_PLAN_LOCKER_SLOT = 0x67ae504a494a1bd5120fdcd8b3565de046d61ac7bb95311090f1976ec179a99a;
    
    struct ApePlanLocker {
        /// @notice Map of the locked tokens.
        ///     Note: Collection Address => Token ID => Lock state
        mapping(address => mapping(uint256 => uint8)) tokens;
    }
    
    struct CyanPlanLockerERC721 {
        /// @notice Locked tokens count of the collection.
        ///     Note: Collection Address => Number of locked tokens
        mapping(address => uint256) count;
        /// @notice Map of the locked tokens.
        ///     Note: Collection Address => Token ID => isLocked
        mapping(address => mapping(uint256 => bool)) tokens;
    }
    
    struct CyanPlanLockerCryptoPunks {
        /// @notice Locked tokens count of the CryptoPunks.
        ///     Note: Number of locked tokens
        uint256 count;
        /// @notice Map of the locked tokens.
        ///     Note: CryptoPunk index => isLocked
        mapping(uint256 => bool) tokens;
    }
    
    struct CyanPlanLockerERC1155 {
        /// @notice Map of the locked ERC1155 tokens.
        ///     Note: Collection Address => Token ID => amount
        mapping(address => mapping(uint256 => uint256)) tokens;
    }
    
    /// @notice Checks whether the NFT is locked or not. This method checks both ERC721 lock and ApePlan lock.
    /// @param collection Collection address.
    /// @param tokenId Token ID.
    /// @return isLocked Whether the token is locked or not.
    function isLockedERC721(address collection, uint256 tokenId) view returns (bool) {
        return isLockedByCyanPlanERC721(collection, tokenId) || isLockedByApePlan(collection, tokenId);
    }
    
    /// @notice Checks whether the ERC721 token is locked or not.
    /// @param collection Collection address.
    /// @param tokenId Token ID.
    /// @return isLocked Whether the token is locked or not.
    function isLockedByCyanPlanERC721(address collection, uint256 tokenId) view returns (bool) {
        return getCyanPlanLockerERC721().tokens[collection][tokenId];
    }
    
    /// @notice Checks whether the CryptoPunks token is locked or not.
    /// @param tokenId Token ID.
    /// @return isLocked Whether the token is locked or not.
    function isLockedByCryptoPunkPlan(uint256 tokenId) view returns (bool) {
        return getCyanPlanLockerCryptoPunks().tokens[tokenId];
    }
    
    /// @notice Checks whether the BAYC, MAYC or BAKC token is locked or not.
    /// @param collection Ape collection address.
    /// @param tokenId Token ID.
    /// @return isLocked Whether the token is ape locked or not.
    function isLockedByApePlan(address collection, uint256 tokenId) view returns (bool) {
        return getApePlanLocker().tokens[collection][tokenId] != 0;
    }
    
    /// @notice Returns amount of locked ERC1155Token items.
    /// @param collection Collection address.
    /// @param tokenId Token ID.
    /// @return isLocked Whether the token is locked or not.
    function getLockedERC1155Amount(address collection, uint256 tokenId) view returns (uint256) {
        return getCyanPlanLockerERC1155().tokens[collection][tokenId];
    }
    
    /// @notice Returns ape lock state.
    /// @param collection Ape collection address.
    /// @param tokenId Token ID.
    /// @return Ape locks state.
    function getApeLockState(address collection, uint256 tokenId) view returns (uint8) {
        return getApePlanLocker().tokens[collection][tokenId];
    }
    
    /// @dev Returns the map of the locked ERC721 tokens.
    /// @return result CyanPlanLockerERC721 struct of the locked tokens.
    ///     Note: Collection Address => Token ID => isLocked
    function getCyanPlanLockerERC721() pure returns (CyanPlanLockerERC721 storage result) {
        assembly {
            result.slot := CYAN_PLAN_LOCKER_SLOT_ERC721
        }
    }
    
    /// @dev Returns the map of the locked ERC1155 tokens.
    /// @return result CyanPlanERC1155Locker struct of the locked tokens.
    ///     Note: Collection Address => Token ID => locked amount
    function getCyanPlanLockerERC1155() pure returns (CyanPlanLockerERC1155 storage result) {
        assembly {
            result.slot := CYAN_PLAN_LOCKER_SLOT_ERC1155
        }
    }
    
    /// @dev Returns the map of the locked Crypto Punks.
    /// @return result CryptoPunksPlanLocker struct of the locked tokens.
    ///     Note: CryptoPunk index => isLocked
    function getCyanPlanLockerCryptoPunks() pure returns (CyanPlanLockerCryptoPunks storage result) {
        assembly {
            result.slot := CRYPTO_PUNKS_PLAN_LOCKER_SLOT
        }
    }
    
    /// @dev Returns the map of the locked tokens.
    /// @return result ApePlanLocker struct of the locked tokens.
    ///     Note: Collection Address => Token ID => Lock state
    function getApePlanLocker() pure returns (ApePlanLocker storage result) {
        assembly {
            result.slot := APE_PLAN_LOCKER_SLOT
        }
    }

    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.19;
    
    /// @title Cyan Wallet Module Manager Storage - A Cyan wallet's module manager's storage.
    /// @author Bulgantamir Gankhuyag - <bulgaa@usecyan.com>
    /// @author Naranbayar Uuganbayar - <naba@usecyan.com>
    abstract contract ModuleManagerStorage {
        /// @notice Storing allowed contract methods.
        ///     Note: Target Contract Address => Sighash of method => Module address
        mapping(address => mapping(bytes4 => address)) internal _modules;
    
        /// @notice Storing internally allowed module methods.
        ///     Note: Sighash of module method => Module address
        mapping(bytes4 => address) internal _internalModules;
    }
    
    /// @title Cyan Wallet Module Manager - A Cyan wallet's module manager's functionalities.
    /// @author Bulgantamir Gankhuyag - <bulgaa@usecyan.com>
    /// @author Naranbayar Uuganbayar - <naba@usecyan.com>
    abstract contract IModuleManager is ModuleManagerStorage {
        event SetModule(address target, bytes4 funcHash, address oldModule, address newModule);
        event SetInternalModule(bytes4 funcHash, address oldModule, address newModule);
    
        /// @notice Sets the handler module of the target's function.
        /// @param target Address of the target contract.
        /// @param funcHash Sighash of the target contract's method.
        /// @param module Address of the handler module.
        function setModule(
            address target,
            bytes4 funcHash,
            address module
        ) external virtual;
    
        /// @notice Returns a handling module of the target function.
        /// @param target Address of the target contract.
        /// @param funcHash Sighash of the target contract's method.
        /// @return module Handler module.
        function getModule(address target, bytes4 funcHash) external view returns (address) {
            return _modules[target][funcHash];
        }
    
        /// @notice Sets the internal handler module of the function.
        /// @param funcHash Sighash of the module method.
        /// @param module Address of the handler module.
        function setInternalModule(bytes4 funcHash, address module) external virtual;
    
        /// @notice Returns an internal handling module of the given function.
        /// @param funcHash Sighash of the module's method.
        /// @return module Handler module.
        function getInternalModule(bytes4 funcHash) external view returns (address) {
            return _internalModules[funcHash];
        }
    
        /// @notice Used to call module functions on the wallet.
        ///     Usually used to call locking function of the module on the wallet.
        /// @param data Data payload of the transaction.
        /// @return Result of the execution.
        function executeModule(bytes memory data) external virtual returns (bytes memory);
    }

    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.19;
    
    /// @title Cyan Wallet Role Manager - A Cyan wallet's role manager's storage.
    /// @author Bulgantamir Gankhuyag - <bulgaa@usecyan.com>
    /// @author Naranbayar Uuganbayar - <naba@usecyan.com>
    abstract contract RoleManagerStorage {
        address[3] internal _deprecatedOperators; // Deprecated
        address internal _admin;
        address internal _owner;
        mapping(address => bool) internal _operators;
    }
    
    /// @title Cyan Wallet Role Manager - A Cyan wallet's role manager's functionalities.
    /// @author Bulgantamir Gankhuyag - <bulgaa@usecyan.com>
    /// @author Naranbayar Uuganbayar - <naba@usecyan.com>
    abstract contract IRoleManager is RoleManagerStorage {
        event SetOwner(address owner);
        event SetAdmin(address admin);
        event SetOperator(address operator, bool isActive);
    
        modifier onlyOperator() {
            _checkOnlyOperator();
            _;
        }
    
        modifier onlyAdmin() {
            _checkOnlyAdmin();
            _;
        }
    
        modifier onlyOwner() {
            _checkOnlyOwner();
            _;
        }
    
        constructor(address admin) {
            require(admin != address(0x0), "Invalid admin address.");
            _admin = admin;
        }
    
        /// @notice Returns current owner of the wallet.
        /// @return Address of the current owner.
        function getOwner() external view virtual returns (address);
    
        /// @notice Changes the current admin.
        /// @param admin New admin address.
        function setAdmin(address admin) external virtual;
    
        /// @notice Returns current admin of the core contract.
        /// @return Address of the current admin.
        function getAdmin() external view virtual returns (address);
    
        /// @notice Sets the operator status.
        /// @param operator Operator address.
        /// @param isActive Is active or not.
        function setOperator(address operator, bool isActive) external virtual;
    
        /// @notice Checks whether the given address is an operator.
        /// @param operator Address that will be checked.
        /// @return result Boolean result.
        function isOperator(address operator) external view virtual returns (bool result);
    
        /// @notice Checks whether the message sender is an operator.
        function _checkOnlyOperator() internal view virtual;
    
        /// @notice Checks whether the message sender is an admin.
        function _checkOnlyAdmin() internal view virtual;
    
        /// @notice Checks whether the message sender is an owner.
        function _checkOnlyOwner() internal view virtual;
    }

    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.19;
    
    library Utils {
        /// @notice Executes a transaction to the given address.
        /// @param to Target address.
        /// @param value Native token value to be sent to the address.
        /// @param data Data to be sent to the address.
        /// @return result Result of the transaciton.
        function _execute(
            address to,
            uint256 value,
            bytes memory data
        ) internal returns (bytes memory result) {
            assembly {
                let success := call(gas(), to, value, add(data, 0x20), mload(data), 0, 0)
    
                mstore(result, returndatasize())
                returndatacopy(add(result, 0x20), 0, returndatasize())
    
                if eq(success, 0) {
                    revert(add(result, 0x20), returndatasize())
                }
            }
        }
    
        /// @notice Recover signer address from signature.
        /// @param signedHash Arbitrary length data signed on the behalf of the wallet.
        /// @param signature Signature byte array associated with signedHash.
        /// @return Recovered signer address.
        function recoverSigner(bytes32 signedHash, bytes memory signature) internal pure returns (address) {
            uint8 v;
            bytes32 r;
            bytes32 s;
            // we jump 32 (0x20) as the first slot of bytes contains the length
            // we jump 65 (0x41) per signature
            // for v we load 32 bytes ending with v (the first 31 come from s) then apply a mask
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            require(v == 27 || v == 28, "Bad v value in signature.");
    
            address recoveredAddress = ecrecover(signedHash, v, r, s);
            require(recoveredAddress != address(0), "ecrecover returned 0.");
            return recoveredAddress;
        }
    
        /// @notice Helper method to parse the function selector from data.
        /// @param data Any data to be parsed, mostly calldata of transaction.
        /// @return result Parsed function sighash.
        function parseFunctionSelector(bytes memory data) internal pure returns (bytes4 result) {
            require(data.length >= 4, "Invalid data.");
            assembly {
                result := mload(add(data, 0x20))
            }
        }
    
        /// @notice Parse uint256 from given data.
        /// @param data Any data to be parsed, mostly calldata of transaction.
        /// @param position Position in the data.
        /// @return result Uint256 parsed from given data.
        function getUint256At(bytes memory data, uint8 position) internal pure returns (uint256 result) {
            assembly {
                result := mload(add(data, add(position, 0x20)))
            }
        }
    }

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

    Context size (optional):