Skip to content

Comments

fix(FLOW-15): Return per-token balances in getPendingRequestsByUserUnpacked#36

Open
liobrasil wants to merge 2 commits intomainfrom
fix/FLOW-15-user-pending-balance-per-token
Open

fix(FLOW-15): Return per-token balances in getPendingRequestsByUserUnpacked#36
liobrasil wants to merge 2 commits intomainfrom
fix/FLOW-15-user-pending-balance-per-token

Conversation

@liobrasil
Copy link
Collaborator

@liobrasil liobrasil commented Jan 19, 2026

Summary

Fixes #30

Previously, getPendingRequestsByUserUnpacked only returned native FLOW balances, which made it harder for clients to surface per-token pending/refund balances.

Note: balanceTokens/pendingBalances/claimableRefundsArray currently cover NATIVE_FLOW and (when configured) WFLOW only. Other supported ERC20 balances remain queryable via getUserPendingBalance(user, token) and getClaimableRefund(user, token).

Changes:

  • Solidity: Return balanceTokens[], pendingBalances[], and claimableRefundsArray[] instead of single uint256 values
  • Cadence: Update PendingRequestsInfo struct to use dictionaries pendingBalances: {String: UFix64} and claimableRefunds: {String: UFix64}
  • Update ABI decoding to handle new array types
  • Update all tests to use new return format

Test plan

  • All 70 Solidity tests pass
  • All 4 Cadence test suites pass
  • Verify integration with frontend clients using the new return format

🤖 Generated with Claude Code

liobrasil and others added 2 commits January 19, 2026 14:18
…packed

Previously, `getPendingRequestsByUserUnpacked` only returned native FLOW
balances, ignoring ERC20/WFLOW balances. This made it impossible for
clients to see pending balances for non-native tokens.

Changes:
- Solidity: Return `balanceTokens[]`, `pendingBalances[]`, and
  `claimableRefundsArray[]` instead of single uint256 values
- Cadence: Update `PendingRequestsInfo` struct to use dictionaries
  `pendingBalances: {String: UFix64}` and `claimableRefunds: {String: UFix64}`
- Update ABI decoding to handle new array types
- Update all tests to use new return format

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@claude
Copy link

claude bot commented Feb 12, 2026

Pull Request Review

Overview

This PR successfully addresses issue #30 by enhancing getPendingRequestsByUserUnpacked to return per-token balance arrays instead of single values. The implementation is clean and maintains backward compatibility through proper ABI versioning.


✅ Strengths

1. Clean API Design

  • The new return format with parallel arrays (balanceTokens, pendingBalances, claimableRefundsArray) is intuitive and follows established patterns
  • Dynamic array sizing based on WFLOW configuration is efficient (tokenCount = WFLOW != address(0) ? 2 : 1)
  • Maintains O(1) complexity for user lookups

2. Cross-VM Consistency

  • Solidity and Cadence implementations stay synchronized (solidity/src/FlowYieldVaultsRequests.sol:1425, cadence/contracts/FlowYieldVaultsEVM.cdc:1730)
  • Proper ABI encoding/decoding with correct type specifications
  • Dictionary-based approach in Cadence ({String: UFix64}) is idiomatic and extensible

3. Test Coverage

  • All 70 Solidity tests updated to use new return format
  • Tests cover key scenarios: multiple users, cancellations, processing, edge cases
  • Proper assertions on array indices and balances

4. Documentation

  • Updated FRONTEND_INTEGRATION.md with clear usage examples
  • Inline comments explain the new return values
  • Helpful note about fallback to individual getters for other ERC20s

⚠️ Issues & Recommendations

Critical: Missing Test Coverage

Issue: The ABI artifacts show new error types (YieldVaultTokenMismatch, YieldVaultTokenNotSet) and a new public mapping (yieldVaultTokens) that aren't part of this PR's stated changes.

// From deployments/artifacts/FlowYieldVaultsRequests.json
{
  "type": "function",
  "name": "yieldVaultTokens",
  "inputs": [{"name": "", "type": "uint64"}],
  "outputs": [{"name": "", "type": "address"}]
}

Recommendation:

  • If these changes are from a previous commit that didn't update artifacts, that's fine
  • If this is new functionality in this PR, it needs dedicated tests and should be mentioned in the PR description
  • Run ./scripts/export-artifacts.sh to ensure artifacts match current contract state

Moderate: Array Index Safety

Location: cadence/contracts/FlowYieldVaultsEVM.cdc:1733

while j < balanceTokens.length {
    let tokenAddr = balanceTokens[j].toString()
    pendingBalances[tokenAddr] = FlowEVMBridgeUtils.uint256ToUFix64(value: pendingBalancesRaw[j], decimals: 18)
    // Assumes pendingBalancesRaw and claimableRefundsRaw have same length
    j = j + 1
}

Issue: No validation that pendingBalancesRaw.length == claimableRefundsRaw.length == balanceTokens.length

Recommendation: Add assertions before the loop:

assert(
    balanceTokens.length == pendingBalancesRaw.length && 
    balanceTokens.length == claimableRefundsRaw.length,
    message: "Balance array length mismatch in ABI decode"
)

Minor: Test Assertion Consistency

Location: solidity/test/FlowYieldVaultsRequests.t.sol:919

Some test destructuring statements have trailing commas in the middle of the parameter list:

(uint256[] memory ids, , , , , , , , , , address[] memory balanceTokens, uint256[] memory pendingBalances, ) = ...

Recommendation: While syntactically valid, consider naming intermediate parameters for readability:

(
    uint256[] memory ids,
    , // requestTypes
    , // statuses  
    , // tokenAddresses
    , // amounts
    ...
) = c.getPendingRequestsByUserUnpacked(user);

Minor: Gas Optimization Opportunity

Location: solidity/src/FlowYieldVaultsRequests.sol:1425-1440

uint256 tokenCount = WFLOW != address(0) ? 2 : 1;
balanceTokens = new address[](tokenCount);
pendingBalances = new uint256[](tokenCount);
claimableRefundsArray = new uint256[](tokenCount);

Observation: Conditional logic executed on every call. Since WFLOW is immutable, this could be optimized with early return branches, though current implementation is already quite efficient.

Verdict: Not worth optimizing - code clarity is more valuable here.


🔒 Security Analysis

No Security Issues Found

  • Read-only view function with no state modifications
  • No reentrancy risks
  • Array bounds properly handled by Solidity's automatic checks
  • User-specific data isolation maintained through existing mappings
  • No new privilege escalation vectors

🎯 Recommendations

Before Merge:

  1. Clarify Artifact Changes - Confirm whether yieldVaultTokens, YieldVaultTokenMismatch, and YieldVaultTokenNotSet are from this PR or a previous commit
  2. Add Array Length Validation - Add assertions in Cadence decoder to prevent index out-of-bounds
  3. Update Test Plan Checkbox - "Verify integration with frontend clients" is unchecked - either test or remove

Optional Improvements:

  1. Consider adding a test that explicitly verifies WFLOW balances when WFLOW is configured
  2. Add a test for the edge case where a user has pending balance in WFLOW but not NATIVE_FLOW (or vice versa)

📊 Final Assessment

Code Quality: ⭐⭐⭐⭐½ (4.5/5)
Test Coverage: ⭐⭐⭐⭐ (4/5)
Security: ⭐⭐⭐⭐⭐ (5/5)
Documentation: ⭐⭐⭐⭐ (4/5)

Verdict:Approve with minor fixes

This is a solid implementation that correctly solves the stated problem. The cross-VM synchronization is well-executed, and the API design is extensible. The identified issues are minor and don't block merge, but addressing the array validation would improve robustness.

Great work maintaining consistency across Solidity and Cadence! The frontend integration guide is particularly helpful.


🤖 Review generated by Claude Code

assertEq(pendingBalance, 3 ether, "Pending balance should be sum of amounts");
assertEq(balanceTokens[0], NATIVE_FLOW, "First balance token should be NATIVE_FLOW");
assertEq(pendingBalances[0], 3 ether, "Pending balance should be sum of amounts");
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe also assertEq(balanceTokens.length == 2), and balanceTokens[1] == WFLOW, as well as the pending balance is correct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FLOW-15: User Pending Balance View Is Native-Only

2 participants