Skip to content

Qa - #1291

Merged
MayankMittal1 merged 4 commits into
masterfrom
qa
Jan 19, 2026
Merged

Qa#1291
MayankMittal1 merged 4 commits into
masterfrom
qa

Conversation

@MayankMittal1

Copy link
Copy Markdown
Contributor

No description provided.

@vercel

vercel Bot commented Jan 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
solid-app-staging Ready Ready Preview, Comment Jan 19, 2026 6:47am
1 Skipped Deployment
Project Deployment Review Updated (UTC)
solid-app Ignored Ignored Jan 19, 2026 6:47am

Request Review

@claude

claude Bot commented Jan 19, 2026

Copy link
Copy Markdown

PR Review: Card Borrow Mode Implementation

Overview

This PR implements a borrow-and-repay feature for the card system, allowing users to borrow USDC against their soUSD savings collateral and repay existing borrows. The implementation integrates with Aave V3 on Fuse network.

✅ Strengths

Good Architecture

  • Well-structured separation of concerns with dedicated hooks (useAaveBorrowPosition, useRepayAndWithdrawCollateral, useBorrowAndDepositToCard)
  • Proper state management using Zustand store (useCardRepayStore)
  • Good use of React Query for contract reads
  • Comprehensive error handling with Sentry integration
  • Proper analytics tracking throughout the flow

Security Considerations

  • Proper approval flows before token transfers
  • Health factor calculation to prevent liquidation (1.02x target)
  • Slippage protection on cross-chain bridging (5% tolerance)
  • Input validation with Zod schemas

🔴 Critical Issues

1. Incorrect Debt Calculation in useAaveBorrowPosition.ts (Lines 162-165)

const actualDebt = (scaledVariableDebt * variableBorrowIndex) / BigInt(1e27);

Issue: Aave's variable debt accrues continuously. This calculation is correct at the current block, but by the time a transaction is submitted, the debt may have increased. This could lead to:

  • Underpayment when users try to "repay all"
  • Failed transactions due to insufficient repayment amount

Recommendation: Add a safety buffer (e.g., 0.1%) when calculating repayment amounts, or use type(uint256).max for full repayments.

2. Race Condition Risk in useRepayAndWithdrawCollateral.ts (Lines 92-109)

const rate = await readContract(publicClient(mainnet.id), {
  address: ADDRESSES.ethereum.accountant,
  abi: ACCOUNTANT_ABI,
  functionName: 'getRate',
});

Issue: The exchange rate is fetched at transaction build time but may change before execution. This creates several risks:

  • If the rate decreases, you might withdraw too much collateral and get liquidated
  • If the rate increases, you might withdraw less than optimal

Recommendation: Consider implementing a minimum withdrawal check or validating the rate hasn't changed beyond acceptable bounds.

3. Health Factor Calculation Precision (useRepayAndWithdrawCollateral.ts Lines 97-101)

const requiredCollateralValueWei =
  remainingBorrowWei === 0n
    ? 0n
    : (remainingBorrowWei * TARGET_HEALTH_FACTOR_BPS + (LIQ_THRESHOLD_BPS - 1n)) /
      LIQ_THRESHOLD_BPS;

Issue: This integer division could have rounding errors that leave the position slightly under-collateralized, especially with small borrow amounts.

Recommendation: Add explicit rounding up logic or increase the safety margin slightly (e.g., 1.03x instead of 1.02x).

⚠️ High Priority Issues

4. Missing Balance Validation (CardRepayForm.tsx)

The form validates against balanceAmount and borrowedAmount separately, but doesn't account for:

  • Gas costs (though likely covered by paymaster)
  • Bridge fees when using cross-chain tokens
  • Potential slippage when swapping tokens

5. Incomplete Error Recovery (useRepayAndWithdrawCollateral.ts Lines 224-248)

} catch (error) {
  setRepayAndWithdrawCollateralStatus(Status.ERROR);
  setError(error instanceof Error ? error.message : 'Unknown error');
  throw error;
}

Issue: No rollback mechanism if the repay succeeds but withdraw fails, or if the transaction is partially executed.

Recommendation: Consider implementing idempotency checks or multi-step confirmation.

6. Hardcoded LTV Value (useBorrowAndDepositToCard.ts Line 47)

const soUSDLTV = 79n; // 80% LTV for soUSD (79% to avoid rounding errors)

Issue: LTV is hardcoded and may become outdated if Aave governance changes this parameter.

Recommendation: Fetch LTV dynamically from the protocol configuration or add monitoring/alerts if this changes.

📊 Medium Priority Issues

7. Type Safety Issues

  • CardRepayForm.tsx Line 124: resolver: zodResolver(schema) as any - Avoid type assertions
  • Multiple uses of any type that could be properly typed
  • Missing null checks in several places

8. Performance Concerns

  • BorrowSlider.tsx: Multiple re-renders due to refs and state updates. Consider using useMemo more aggressively or throttling the onValueChange callback
  • useAaveBorrowPosition.ts: Large useMemo dependency array may cause unnecessary recalculations

9. User Experience Issues

  • No loading state between "Repay" button click and modal transition
  • Fee amount is hardcoded to 0 (CardRepayForm.tsx Line 36) - users might expect to see actual bridge fees
  • No confirmation step before submitting large repayments
  • Missing tooltips explaining health factor, APY calculations, etc.

10. Inconsistent Error Messages

Toast.show({
  type: 'error',
  text1: 'Repay failed',
  text2: 'Please try again or check your wallet balance',
});

Generic error messages don't help users understand what went wrong (insufficient balance vs. contract error vs. network issue).

🔵 Low Priority Issues

11. Code Quality

  • Some repeated calculation logic between useBorrowAndDepositToCard and useRepayAndWithdrawCollateral
  • Magic numbers (e.g., 95n / 100n for slippage, 30110 for dstEid) should be constants
  • BorrowSlider.tsx has complex PanResponder logic that could be extracted or use a library

12. Missing Documentation

  • No JSDoc comments explaining the complex financial calculations
  • No README or inline comments explaining the borrow flow
  • Constants like RATE_SCALE, LIQ_THRESHOLD_BPS need explanatory comments

13. Accessibility

  • BorrowSlider.tsx has no accessibility labels for screen readers
  • No keyboard navigation support for the slider component
  • Missing ARIA labels on interactive elements

🧪 Test Coverage

Major Gap: NO TESTS

The PR adds 1,797 lines of complex financial logic with zero test coverage. This is a critical gap for DeFi functionality.

Recommended Tests:

  1. Unit tests for calculation functions:

    • Health factor calculations
    • Debt/collateral conversions
    • Exchange rate applications
    • Edge cases (zero amounts, max uint, very small amounts)
  2. Integration tests for hooks:

    • Mock contract responses
    • Test error scenarios (insufficient balance, rate changes, etc.)
    • Test multi-step transaction flows
  3. E2E tests:

    • Complete borrow-to-repay user flow
    • Error recovery scenarios
    • Cross-chain bridging

Example test structure:

// hooks/__tests__/useAaveBorrowPosition.test.ts
describe('useAaveBorrowPosition', () => {
  it('calculates total borrowed correctly with accrued interest', () => {
    // Test implementation
  });
  
  it('handles zero debt positions', () => {
    // Test implementation
  });
  
  it('calculates net APY correctly', () => {
    // Test implementation
  });
});

🔒 Security Recommendations

  1. Audit Math Operations: All financial calculations should be audited for overflow/underflow and rounding errors
  2. Rate Staleness Check: Add timestamp checks to ensure exchange rates aren't stale
  3. Maximum Slippage Protection: Consider adding configurable maximum slippage for user protection
  4. Transaction Simulation: Consider simulating transactions before execution (Tenderly/Hardhat fork)
  5. Emergency Pause: Consider adding a circuit breaker if health factor calculations seem off

📝 Additional Recommendations

  1. Add TypeScript strict checks: Enable strictNullChecks and fix all violations
  2. Extract constants: Move all magic numbers to a dedicated constants file with documentation
  3. Add logging: More granular logs for debugging production issues
  4. Monitor health factors: Add analytics to track when users get close to liquidation
  5. Rate limiting: Consider rate limiting borrow/repay actions to prevent abuse
  6. Add transaction previews: Show users exactly what will happen before they confirm

Conclusion

This is a substantial feature with solid architecture, but has critical financial calculation risks that need addressing before production deployment. The lack of tests for DeFi functionality is particularly concerning.

Before Merging:

  1. ✅ Fix debt calculation buffer issue (configure project for Android #1)
  2. ✅ Add rate staleness/validation checks (design card screens #2)
  3. ✅ Review and fix health factor precision (Batch transaction #3)
  4. ✅ Add comprehensive test coverage
  5. ⚠️ Consider external audit for financial logic

Post-Merge (Next PR):

  • Improve error messages and UX
  • Add documentation
  • Refactor shared calculation logic
  • Add accessibility improvements

Recommendation: Request Changes - Address critical issues #1-3 and add basic test coverage before merging.

@MayankMittal1
MayankMittal1 merged commit 624b43a into master Jan 19, 2026
8 checks passed
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.

1 participant