diff --git a/cadence/contracts/FlowYieldVaultsEVM.cdc b/cadence/contracts/FlowYieldVaultsEVM.cdc index 5611b57..958e0fb 100644 --- a/cadence/contracts/FlowYieldVaultsEVM.cdc +++ b/cadence/contracts/FlowYieldVaultsEVM.cdc @@ -25,6 +25,13 @@ import "FlowEVMBridgeConfig" /// 2. Processing: For each PROCESSING request, executes Cadence-side operation /// (create/deposit/withdraw/close YieldVault), then calls completeProcessing() to mark /// as COMPLETED or FAILED (with refund to EVM contract on CREATE/DEPOSIT failure) +/// PRECISION NOTE: +/// EVM uses uint256 with 18 decimals (wei), while Cadence uses UFix64 with 8 decimals. +/// Converting between these formats truncates precision beyond 8 decimal places. +/// For example: 1.123456789012345678 FLOW (EVM) becomes 1.12345678 FLOW (Cadence). +/// This is not exploitable (users receive slightly less, not more) and the 1 FLOW +/// minimum deposit makes any dust loss negligible (~0.0000001% maximum). + access(all) contract FlowYieldVaultsEVM { // ============================================ @@ -1929,9 +1936,11 @@ access(all) contract FlowYieldVaultsEVM { /// @notice Converts a UInt256 amount from EVM to UFix64 for Cadence /// @dev For native FLOW: Uses 18 decimals (attoflow to FLOW conversion) /// For ERC20: Uses FlowEVMBridgeUtils to look up token decimals + /// PRECISION WARNING: UFix64 has only 8 decimal places vs uint256's 18. + /// Precision beyond 8 decimals is truncated (e.g., 1.123456789... → 1.12345678). /// @param value The amount in wei/smallest unit (UInt256) /// @param tokenAddress The token address to determine decimal conversion - /// @return The converted amount in UFix64 format + /// @return The converted amount in UFix64 format (truncated to 8 decimals) access(self) fun ufix64FromUInt256(_ value: UInt256, tokenAddress: EVM.EVMAddress): UFix64 { if tokenAddress.toString() == FlowYieldVaultsEVM.nativeFlowEVMAddress.toString() { return FlowEVMBridgeUtils.uint256ToUFix64(value: value, decimals: 18) diff --git a/solidity/src/FlowYieldVaultsRequests.sol b/solidity/src/FlowYieldVaultsRequests.sol index 7b4bef1..bf0b21f 100644 --- a/solidity/src/FlowYieldVaultsRequests.sol +++ b/solidity/src/FlowYieldVaultsRequests.sol @@ -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. */ contract FlowYieldVaultsRequests is ReentrancyGuard, Ownable2Step { using SafeERC20 for IERC20;