Omniscia SaucerSwap Audit
TransferHelper Manual Review Findings
TransferHelper Manual Review Findings
THR-01M: Inexistent Cast of Variable
| Type | Severity | Location |
|---|---|---|
| Standard Conformity | ![]() | TransferHelper.sol:L27 |
Description:
The value argument of the IHederaTokenService::transferToken call needs to be of type int64, however, no such casting occurs within the TransferHelper::safeTransferFrom function.
Impact:
As the value is not cast to its signed counterpart, the IHederaTokenService::transferToken call may improperly consume the input value thus causing incorrect transfers to occur.
Example:
25(bool success, bytes memory result) = precompileAddress.call(26 abi.encodeWithSelector(IHederaTokenService.transferToken.selector,27 token, from, to, (value)));Recommendation:
We advise the value variable to be safely cast to the int64 data type, ensuring that the invocation style is compliant with the IHederaTokenService interface.
Alleviation (d8d187efd1fa23b943c82694aaaccb5b9e427096):
The code has been refactored throughout its functions to consistently utilize the IHederaTokenService when performing token actions and in this refactor, all uint256 to int64 conversions are now performed using safe casting.
As such, we consider this exhibit alleviated.
THR-02M: Inexistent Integration of the Hedera Token Service
| Type | Severity | Location |
|---|---|---|
| Logical Fault | ![]() | TransferHelper.sol:L46, L61 |
Description:
The referenced functions indicate points where the IHederaTokenService should be integrated for the contract to function properly, however, they remain as they were in their original implementation.
Impact:
The TransferHelper contract does not appear to be fully compatible with the Hedera Protocol ecosystem, rendering the AMM system impossible to operate there.
Example:
36/// @notice Transfers tokens from msg.sender to a recipient37/// @dev Errors with ST if transfer fails38/// @param token The contract address of the token which will be transferred39/// @param to The recipient of the transfer40/// @param value The value of the transfer41function safeTransfer(42 address token,43 address to,44 uint256 value45) internal {46 (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));47 require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST');48 emit Transfer(address(this), to, value, token);49}50
51/// @notice Approves the stipulated contract to spend the given allowance in the given token52/// @dev Errors with 'SA' if transfer fails53/// @param token The contract address of the token to be approved54/// @param to The target of the approval55/// @param value The amount of the given token the target will be allowed to spend56function safeApprove(57 address token,58 address to,59 uint256 value60) internal {61 (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));62 require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA');63 emit Approval(address(this), to, value, token);64}Recommendation:
We advise them to be updated, properly utilizing the relevant functions of the IHederaTokenService to ensure that the TransferHelper contract is properly compatible with the Hedera Protocol ecosystem.
Alleviation (d8d187efd1fa23b943c82694aaaccb5b9e427096):
After discussions with the SaucerSwap team and inspection of the Hedera Improvement Proposals and specifically HIP-218 and HIP-376, we have concluded that a direct invocation of ERC20::transfer / ERC20::approve is equivalent to an invocation of a transfer / approval via the HederaTokenService.
As such, we consider this exhibit nullified. We would like to note that despite this, the SaucerSwap team has opted to refactor their codebase to consistently utilize the IHederaTokenService when interacting with tokens thus increasing the standardization of their codebase.
