PhiFactory.sol :: createArt() will always revert if a surplus fee is sent, because the contract lacks a receive() or fallback() function to handle the excess ETH.
Audit: 2024-08-phi-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-phi/blob/8c0985f7a10b231f916a51af5d506dd6b0c54120/src/PhiFactory.sol#L196-L213
https://github.com/code-423n4/2024-08-phi/blob/8c0985f7a10b231f916a51af5d506dd6b0c54120/src/PhiFactory.sol#L551-L568
https://github.com/code-423n4/2024-08-phi/blob/8c0985f7a10b231f916a51af5d506dd6b0c54120/src/PhiFactory.sol#L620-L649
https://github.com/code-423n4/2024-08-phi/blob/8c0985f7a10b231f916a51af5d506dd6b0c54120/src/art/PhiNFT1155.sol#L138-L156


# Vulnerability details

## Impact
**`createArt()`** is designed to create artwork, requiring users to send ETH to cover the associated fees. If a user sends more ETH than needed, the function is supposed to refund the surplus. However, the **`PhiFactory.sol`** contract lacks a **`receive()`** or **`fallback()`** function to handle the excess ETH, causing the transaction to revert whenever a surplus is sent.

## Proof of Concept
**`createArt()`** is implemented as follows.
```Solidity
function createArt(
        bytes calldata signedData_,
        bytes calldata signature_,
        CreateConfig memory createConfig_
    )
        external
        payable
        nonReentrant
        whenNotPaused
        returns (address)
    {
        _validateArtCreationSignature(signedData_, signature_);
        (, string memory uri_, bytes memory credData) = abi.decode(signedData_, (uint256, string, bytes));
        ERC1155Data memory erc1155Data = _createERC1155Data(artIdCounter, createConfig_, uri_, credData);
        address artAddress = createERC1155Internal(artIdCounter, erc1155Data);
        artIdCounter++;
        return artAddress;
    }
```
This calls [createERC1155Internal()](https://github.com/code-423n4/2024-08-phi/blob/8c0985f7a10b231f916a51af5d506dd6b0c54120/src/PhiFactory.sol#L562), which, in turn, invokes **`_createNewNFTContract()`** if the credNFT contract does not already exist.
```Solidity
function _createNewNFTContract(
        PhiArt storage art,
        uint256 newArtId,
        ERC1155Data memory createData_,
        uint256 credId,
        uint256 credChainId,
        string memory verificationType
    )
        private
        returns (address)
    {
///...

(bool success_, bytes memory response) =
            newArt.call{ value: msg.value }(abi.encodeWithSignature("createArtFromFactory(uint256)", newArtId));

        if (!success_) revert CreateFailed();

///...
}
```
As you can see, this function calls **`createArtFromFactory()`** in **`PhiNFT1155.sol`**. If the transaction fails, it reverts with the custom error **`CreateFailed()`**.
```Solidity
function createArtFromFactory(uint256 artId_) external payable onlyPhiFactory whenNotPaused returns (uint256) {
        _artIdToTokenId[artId_] = tokenIdCounter;
        _tokenIdToArtId[tokenIdCounter] = artId_;

        uint256 artFee = phiFactoryContract.artCreateFee();

        protocolFeeDestination.safeTransferETH(artFee);
        emit ArtCreated(artId_, tokenIdCounter);
        uint256 createdTokenId =