-
Notifications
You must be signed in to change notification settings - Fork 1
docs(FLOW-16): Document precision loss in cross-VM amount conversions #37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,6 +30,11 @@ import { | |
| * Processing uses atomic two-phase commit: | ||
| * - startProcessingBatch(): Marks requests as PROCESSING, deducts user balances | ||
| * - completeProcessing(): Marks as COMPLETED/FAILED, credits claimable refunds on failure | ||
| * | ||
| * PRECISION NOTE: EVM uses uint256 with 18 decimals, while Cadence uses UFix64 with 8 decimals. | ||
| * Amounts are truncated beyond 8 decimal places during cross-VM conversion. | ||
| * Example: 1.123456789012345678 FLOW → 1.12345678 FLOW (loss of ~9e-9 FLOW). | ||
| * This is not exploitable (truncation favors the protocol) and the minimum deposit mitigates dust. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The "not exploitable" claim is incomplete — see the refund path The forward direction (deposit → Cadence) is indeed safe: users put in more than they get, so the protocol is not at risk. But When a native FLOW request fails, the Cadence worker reconstructs the refund amount via UFix64, losing the same sub-8-decimal precision. The resulting Fix: Change line 1001 to |
||
| */ | ||
| contract FlowYieldVaultsRequests is ReentrancyGuard, Ownable2Step { | ||
| using SafeERC20 for IERC20; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incomplete analysis — precision truncation IS a liveness bug in the refund path
The note correctly describes forward-direction truncation (deposit → Cadence), but misses the critical reverse case: when a native FLOW CREATE/DEPOSIT request fails,
completeProcessing(lines 1056–1060) convertsrefundAmount(UInt256, 18 dec) → UFix64 (8 dec, truncated) →EVM.BalanceviasetFLOW. The resultingmsg.valueis smaller than the originalrequest.amount.Solidity then reverts with
MsgValueMustEqualAmount(msg.value != request.amount, exact match). This causescompleteProcessingto returnfalse→processRequestpanics → the WorkerHandler transaction reverts. Because the PROCESSING status was committed in a priorstartProcessingBatchtransaction, it is not reverted. When the SchedulerHandler detects the panic and callsmarkRequestAsFailed, it hits the same truncation, the same Solidity revert, and the samefalsereturn — after which it removes the request fromscheduledRequestswith no retry (line 674 of WorkerOps, comment: "errors are not considered transient"). The request is permanently stuck in PROCESSING with user funds in the COA.The statement "users receive slightly less, not more" is true for withdrawals/close, but for the refund-on-failure path the protocol currently cannot return even the truncated amount because Solidity demands the exact original amount.
Affected amounts: any wei value where
amount % 10^10 != 0(e.g. any amount with non-zero attoflow below 10 gwei). Amounts that are exact multiples of 10^10 wei (1 FLOW, 1.5 FLOW, etc.) are unaffected.