Owner unable to collect fulfillment fee from certain users due to revert error
Certain users might not be able to call the `claimOrder` function under certain conditions, resulting in the owner being unable to collect fulfillment fees from the users.\\n```\\nFile: LimitOrderRegistry.sol\\n    function claimOrder(uint128 batchId, address user) external payable returns (ERC20, uint256) {\\n        Claim storage userClaim = claim[batchId];\\n        if (!userClaim.isReadyForClaim) revert LimitOrderRegistry__OrderNotReadyToClaim(batchId);\\n        uint256 depositAmount = batchIdToUserDepositAmount[batchId][user];\\n        if (depositAmount == 0) revert LimitOrderRegistry__UserNotFound(user, batchId);\\n\\n        // Zero out user balance.\\n        delete batchIdToUserDepositAmount[batchId][user];\\n\\n        // Calculate owed amount.\\n        uint256 totalTokenDeposited;\\n        uint256 totalTokenOut;\\n        ERC20 tokenOut;\\n\\n        // again, remembering that direction == true means that the input token is token0.\\n        if (userClaim.direction) {\\n            totalTokenDeposited = userClaim.token0Amount;\\n            totalTokenOut = userClaim.token1Amount;\\n            tokenOut = poolToData[userClaim.pool].token1;\\n        } else {\\n            totalTokenDeposited = userClaim.token1Amount;\\n            totalTokenOut = userClaim.token0Amount;\\n            tokenOut = poolToData[userClaim.pool].token0;\\n        }\\n\\n        uint256 owed = (totalTokenOut * depositAmount) / totalTokenDeposited;\\n\\n        // Transfer tokens owed to user.\\n        tokenOut.safeTransfer(user, owed);\\n```\\n\\nAssume the following:\\nSHIB has 18 decimals of precision, while USDC has 6.\\nAlice (Small Trader) deposited 10 SHIB while Bob (Big Whale) deposited 100000000 SHIB.\\nThe batch order was fulfilled, and it claimed 9 USDC (totalTokenOut)\\nThe following formula and code compute the number of swapped/claimed USDC tokens a user is entitled to.\\n```\\nowed = (totalTokenOut * depositAmount) / totalTokenDeposited\\nowed = (9 USDC * 10 SHIB) / 100000000 SHIB\\nowed = (9 * 10^6 * 10 * 10^18) / (100000000 * 10^18)\\nowed = (9 * 10^6 * 10) / (100000000)\\nowed = 90000000 / 100000000\\nowed = 0 USDC (Round down)\\n```\\n\\nBased on the above assumptions and computation, Alice will receive zero tokens in return due to a rounding error in Solidity.\\nThe issue will be aggravated under the following conditions:\\nIf the difference in the precision between `token0` and `token1` in the pool is larger\\nThe token is a stablecoin, which will attract a lot of liquidity within a small price range (e.g. $0.95 ~ $1.05)\\nThe rounding down to zero is unavoidable in this scenario due to how values are represented. It is not possible to send Alice 0.9 WEI of USDC. The smallest possible amount is 1 WEI.\\nIn this case, it will attempt to transfer a zero amount of `tokenOut,` which might result in a revert as some tokens disallow the transfer of zero value. As a result, when users call the `claimOrder` function, it will revert, and the owner will not be able to collect the fulfillment fee from the users.\\n```\\n        // Transfer tokens owed to user.\\n        tokenOut.safeTransfer(user, owed);\\n```\\n
Consider only transferring the assets if the amount is more than zero.\\n```\\nuint256 owed = (totalTokenOut * depositAmount) / totalTokenDeposited;\\n\\n// Transfer tokens owed to user.\\n// Remove the line below\\n tokenOut.safeTransfer(user, owed);\\n// Add the line below\\n if (owed > 0) tokenOut.safeTransfer(user, owed);\\n```\\n
When a user cannot call the `claimOrder` function due to the revert error, the owner will not be able to collect the fulfillment fee from the user, resulting in a loss of fee for the owner.
```\\nFile: LimitOrderRegistry.sol\\n    function claimOrder(uint128 batchId, address user) external payable returns (ERC20, uint256) {\\n        Claim storage userClaim = claim[batchId];\\n        if (!userClaim.isReadyForClaim) revert LimitOrderRegistry__OrderNotReadyToClaim(batchId);\\n        uint256 depositAmount = batchIdToUserDepositAmount[batchId][user];\\n        if (depositAmount == 0) revert LimitOrderRegistry__UserNotFound(user, batchId);\\n\\n        // Zero out user balance.\\n        delete batchIdToUserDepositAmount[batchId][user];\\n\\n        // Calculate owed amount.\\n        uint256 totalTokenDeposited;\\n        uint256 totalTokenOut;\\n        ERC20 tokenOut;\\n\\n        // again, remembering that direction == true means that the input token is token0.\\n        if (userClaim.direction) {\\n            totalTokenDeposited = userClaim.token0Amount;\\n            totalTokenOut = userClaim.token1Amount;\\n            tokenOut = poolToData[userClaim.pool].token1;\\n        } else {\\n            totalTokenDeposited = userClaim.token1Amount;\\n            totalTokenOut = userClaim.token0Amount;\\n            tokenOut = poolToData[userClaim.pool].token0;\\n        }\\n\\n        uint256 owed = (totalTokenOut * depositAmount) / totalTokenDeposited;\\n\\n        // Transfer tokens owed to user.\\n        tokenOut.safeTransfer(user, owed);\\n```\\n