Using the transfer() function of address payable is discouraged
transfer() only forwards 2300 gas. If the initiator is a multisig or payment splitter that needs more, the call fails. Use call{value: ...} for native transfers instead.
Description
The transfer() function only allows the recipient to use 2300 gas. If the recipient uses more than that, transfers will fail. This could, for example, be the case if initiator is the address of a Multisig or payment splitter that is supposed to execute additional logic after the withdrawal. Furthermore, gas costs might change in the future, increasing the likelihood of that happening. Also, notice that once the initiator address is set to a specific subscription, it could be changed via the modifySubscription() function.
Consider the following scenario:
- During the creation of a subscription, the executor is not aware of this "
transfer()issue" and sets theinitiatorto a contract address (e.g., a payment splitter) that consumes more than 2300 gas. - The user calls
processPayment()function for a native subscription payment but the execution reverts because theinitiatorconsumes more than 2300 gas when receiving the funds.
/// @notice Processes a native payment for the subscriptionfunction _processNativePayment(SubStorage storage sub) internal {require(address(this).balance >= sub.amount, "Insufficient Ether balance");payable(sub.initiator).transfer(sub.amount);}
/// @notice Withdraws all Ether held by the contract to the owner's address/// @dev This function can only be called by the contract ownerfunction withdrawETH() public onlyOwner {payable(owner()).transfer(address(this).balance);}
Impact
Native payments to multisig recipients or payment splitters fail silently when the recipient's logic exceeds the 2300-gas limit, blocking valid subscription payments.
Recommendation
Use call() instead of transfer() in _processNativePayment() and withdrawETH() functions:
- payable(sub.initiator).transfer(sub.amount);+ (bool success, ) = sub.initiator.call{value: sub.amount}("");+ require(success, "ProcessNativePayment failed.");- payable(owner()).transfer(address(this).balance);+ (bool success, ) = owner().call{value: address(this).balance}("");+ require(success, "WithdrawETH failed.");
Resolution
Team Response: Acknowledged and fixed as suggested.

