Skip to content
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

Fix API decimals handling #3378

Merged
merged 5 commits into from
Nov 7, 2024
Merged

Fix API decimals handling #3378

merged 5 commits into from
Nov 7, 2024

Conversation

Defi-Moses
Copy link
Collaborator

@Defi-Moses Defi-Moses commented Nov 7, 2024

Fixing this request:

https://api.synapseprotocol.com/bridge?amount=4.99696492210126891&fromChain=10&toChain=8453&fromToken=0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85&toToken=0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA&originUserAddress=0xa61dcdf0b74a72f676742ee87e31facf4026d5bf

Issue is that decimals arent truncated, so instead mimicked the same logic in the frontend, we return an error like

{"error":{"value":"4.99696492210126891","message":"Amount has too many decimals, maximum allowed is 6","field":"amount","location":"query"}}

Summary by CodeRabbit

  • New Features

    • Enhanced validation for the amount parameter across multiple routes, ensuring it adheres to token-specific decimal requirements.
    • Introduced custom error messages for validation failures, providing clearer feedback to users.
  • Bug Fixes

    • Improved error handling for invalid amount inputs, dynamically reflecting token constraints.
  • Documentation

    • Added new utility functions validateDecimals and tokenAddressToToken to support enhanced validation logic.

@Defi-Moses Defi-Moses requested a review from trajan0x as a code owner November 7, 2024 13:03
Copy link
Contributor

coderabbitai bot commented Nov 7, 2024

Warning

Rate limit exceeded

@Defi-Moses has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 3 minutes and 49 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 48c47b9 and 61bc34e.

Walkthrough

The changes in this pull request enhance the validation logic for the amount query parameter across multiple route files in the REST API. New utility functions validateDecimals and tokenAddressToToken have been introduced to facilitate more robust validation, ensuring that the amount adheres to the specific decimal precision requirements of the token involved. The validation chain for other parameters remains unchanged, maintaining the overall structure while improving error handling and feedback for users.

Changes

File Path Change Summary
packages/rest-api/src/routes/bridgeRoute.ts Enhanced validation for amount query parameter with custom checks for token decimals.
packages/rest-api/src/routes/bridgeTxInfoRoute.ts Updated amount validation to include checks for maximum allowed decimals based on token information.
packages/rest-api/src/routes/swapRoute.ts Improved amount validation logic to ensure compliance with token decimal precision, including dynamic error messages.
packages/rest-api/src/routes/swapTxInfoRoute.ts Enhanced amount validation with custom decimal checks based on token info, improving error messaging.
packages/rest-api/src/validations/validateDecimals.ts Introduced validateDecimals function to check if the amount adheres to the specified decimal precision.
packages/rest-api/src/utils/tokenAddressToToken.ts Added tokenAddressToToken function to retrieve token information based on chain and token address.

Possibly related PRs

Suggested labels

size/m, needs-yarn-install

Suggested reviewers

  • trajan0x
  • abtestingalpha

Poem

In the meadow where tokens play,
Amounts now dance in a safer way.
With decimals checked, no more to fear,
Validation's here, let’s all cheer!
Hops and jumps, the routes align,
A smoother bridge, oh how divine! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

codecov bot commented Nov 7, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 31.65700%. Comparing base (dc1ca02) to head (61bc34e).
Report is 5 commits behind head on master.

Additional details and impacted files
@@                 Coverage Diff                 @@
##              master       #3378         +/-   ##
===================================================
+ Coverage   30.49751%   31.65700%   +1.15949%     
===================================================
  Files            417         397         -20     
  Lines          27658       26367       -1291     
  Branches          82          82                 
===================================================
- Hits            8435        8347         -88     
+ Misses         18437       17237       -1200     
+ Partials         786         783          -3     
Flag Coverage Δ
packages 90.44834% <ø> (ø)
promexporter ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link

cloudflare-workers-and-pages bot commented Nov 7, 2024

Deploying sanguine-fe with  Cloudflare Pages  Cloudflare Pages

Latest commit: 61bc34e
Status: ✅  Deploy successful!
Preview URL: https://c667d993.sanguine-fe.pages.dev
Branch Preview URL: https://feat-api-decimals.sanguine-fe.pages.dev

View logs

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (2)
packages/rest-api/src/utils/formatAmounts.ts (1)

4-25: Consider adding comprehensive error handling and documentation

As this is a critical utility function for amount processing:

  1. Add JSDoc documentation with examples and edge cases
  2. Consider creating custom error types for different validation failures
  3. Add unit tests covering various scenarios:
    • Different decimal places
    • Edge cases (max values, zero, very small numbers)
    • Invalid inputs
    • Overflow scenarios

Would you like me to help create comprehensive unit tests for this utility function?

packages/rest-api/src/controllers/bridgeController.ts (1)

27-30: LGTM! Consider adding specific error handling for amount validation

The replacement of parseUnits with formatAndValidateAmount properly addresses the decimal truncation issue. The implementation correctly handles the conversion by:

  1. Converting amount to string
  2. Using the token's decimal places for proper formatting

Consider adding specific error handling for amount validation failures:

-    const amountInWei = formatAndValidateAmount(
-      amount.toString(),
-      fromTokenInfo.decimals
-    )
+    let amountInWei;
+    try {
+      amountInWei = formatAndValidateAmount(
+        amount.toString(),
+        fromTokenInfo.decimals
+      );
+    } catch (error) {
+      logger.warn(`Invalid amount format`, {
+        amount,
+        decimals: fromTokenInfo.decimals,
+        error: error.message
+      });
+      return res.status(400).json({
+        error: 'Invalid amount format. Please check the decimal places.'
+      });
+    }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c892e69 and df0ae41.

📒 Files selected for processing (3)
  • packages/rest-api/src/controllers/bridgeController.ts (2 hunks)
  • packages/rest-api/src/controllers/bridgeTxInfoController.ts (2 hunks)
  • packages/rest-api/src/utils/formatAmounts.ts (1 hunks)
🔇 Additional comments (3)
packages/rest-api/src/controllers/bridgeTxInfoController.ts (2)

5-5: LGTM: Clean import addition

The new utility import is properly organized with other utility imports.


27-30: Verify decimal truncation behavior

While the change addresses the decimal truncation issue, we should verify the exact behavior of formatAndValidateAmount for edge cases.

Let's check the implementation of the formatting utility:

Consider adding explicit error handling

The formatting function might throw errors for invalid inputs (e.g., scientific notation, extremely large numbers). Consider wrapping this in a try-catch block for better error reporting.

-    const amountInWei = formatAndValidateAmount(
-      amount.toString(),
-      fromTokenInfo.decimals
-    )
+    let amountInWei;
+    try {
+      amountInWei = formatAndValidateAmount(
+        amount.toString(),
+        fromTokenInfo.decimals
+      );
+    } catch (error) {
+      logger.error('Amount formatting failed', {
+        amount,
+        decimals: fromTokenInfo.decimals,
+        error: error.message
+      });
+      return res.status(400).json({
+        error: 'Invalid amount format. Please provide a valid decimal number.'
+      });
+    }
✅ Verification successful

Implementation handles decimal truncation safely

The formatAndValidateAmount implementation properly handles decimal truncation and edge cases:

  • Sanitizes input by removing non-numeric characters except decimal point
  • Handles empty/invalid inputs by returning 0
  • Correctly truncates decimals to token precision
  • Uses parseUnits for final conversion to wei

No explicit error handling is needed as the implementation already:

  • Safely handles invalid inputs
  • Performs proper decimal truncation
  • Returns valid BigNumber in all cases
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the formatAndValidateAmount implementation
# Expected: Should find the implementation showing decimal handling logic

ast-grep --pattern 'export function formatAndValidateAmount($_) {
  $$$
}'

# Also check for any test cases
fd -g "*test*" -x rg -l "formatAndValidateAmount"

Length of output: 126


Script:

#!/bin/bash
# Let's try different approaches to find the implementation

# Search for the function definition with ripgrep
rg -l "formatAndValidateAmount" 

# Search for the function with more context
rg "formatAndValidateAmount" -A 5 -B 5

# Look for files containing "amount" and "validate" in their names
fd -g "*amount*" -g "*validate*"

# Search for any utility files that might contain this function
fd -g "*util*" -x rg -l "formatAndValidateAmount"

Length of output: 4925


Script:

#!/bin/bash
# Let's examine the full implementation of formatAndValidateAmount
cat packages/rest-api/src/utils/formatAmounts.ts

# Also check for any test files specifically for formatAmounts
fd -g "*formatAmounts*test*"

Length of output: 803

packages/rest-api/src/controllers/bridgeController.ts (1)

4-4: Verify the implementation of formatAndValidateAmount utility

The new import aligns with the PR's objective to fix decimal truncation issues. Let's verify the implementation to ensure it handles decimals correctly.

✅ Verification successful

Implementation of formatAndValidateAmount is appropriate for decimal handling

The utility function is well-implemented for handling decimal truncation:

  • Properly imports BigNumber from @ethersproject/bignumber
  • Cleans input by removing non-numeric characters except decimal points
  • Takes decimals parameter to handle token-specific decimal places
  • Returns BigNumber type which is safe for precise numeric operations
  • Used consistently in both bridge controllers for amount processing

The implementation aligns with the PR's objective to fix decimal truncation issues and is being used correctly in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check the implementation of formatAndValidateAmount

# Test: Look for the implementation and any tests
echo "Checking implementation:"
rg -A 10 "export.*formatAndValidateAmount" "packages/rest-api/src/utils/"

echo "\nChecking tests:"
rg -A 5 "formatAndValidateAmount" "packages/rest-api/src/**/*.test.ts"

Length of output: 1114


Script:

#!/bin/bash
# Let's verify how formatAndValidateAmount is used in the codebase
echo "Checking usage of formatAndValidateAmount:"
rg -A 5 "formatAndValidateAmount" "packages/rest-api/src/"

# Let's also check for any test files with .spec.ts extension
echo "\nChecking spec tests:"
rg -A 5 "formatAndValidateAmount" "packages/rest-api/src/**/*.spec.ts"

# Let's examine the BigNumber import and usage
echo "\nChecking BigNumber import:"
rg "import.*BigNumber" "packages/rest-api/src/utils/formatAmounts.ts"

Length of output: 3212

packages/rest-api/src/utils/formatAmounts.ts Outdated Show resolved Hide resolved
packages/rest-api/src/utils/formatAmounts.ts Outdated Show resolved Hide resolved
packages/rest-api/src/utils/formatAmounts.ts Outdated Show resolved Hide resolved
@github-actions github-actions bot added size/s and removed size/xs labels Nov 7, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (3)
packages/rest-api/src/validations/validateDecimals.ts (2)

1-4: Add JSDoc documentation

Add documentation to describe the function's purpose, parameters, return value, and examples of usage.

+/**
+ * Validates if a decimal number string has at most the expected number of decimal places
+ * @param amount - The decimal number as a string (e.g., "123.456")
+ * @param expectedDecimals - The maximum number of decimal places allowed
+ * @returns true if the number has valid decimals, false otherwise
+ * @example
+ * validateDecimals("123.456", 2) // returns false
+ * validateDecimals("123.45", 2) // returns true
+ * validateDecimals("123", 2) // returns true
+ */
 export const validateDecimals = (
   amount: string,
   expectedDecimals: number
 ): boolean => {

1-11: Consider adding unit tests

The function handles critical validation logic and should be thoroughly tested with various edge cases.

Would you like me to generate comprehensive unit tests covering:

  • Valid inputs with different decimal places
  • Invalid inputs (non-numeric, scientific notation)
  • Edge cases (empty strings, multiple decimal points)
  • Boundary conditions for expectedDecimals
packages/rest-api/src/routes/bridgeRoute.ts (1)

231-248: Consider caching the token info to avoid duplicate calls.

The validation logic is correct, but tokenAddressToToken is called twice - once in the validation and once in the error message. Consider storing the result to improve performance:

     check('amount')
       .exists()
       .withMessage('amount is required')
       .isNumeric()
       .custom((value, { req }) => {
-        const fromTokenInfo = tokenAddressToToken(
-          req.query.fromChain,
-          req.query.fromToken
-        )
+        req.tokenInfo = tokenAddressToToken(
+          req.query.fromChain,
+          req.query.fromToken
+        )
-        return validateDecimals(value, fromTokenInfo.decimals)
+        return validateDecimals(value, req.tokenInfo.decimals)
       })
       .withMessage((_value, { req }) => {
-        const fromTokenInfo = tokenAddressToToken(
-          req.query.fromChain,
-          req.query.fromToken
-        )
-        return `Amount has too many decimals, maximum allowed for this token is ${fromTokenInfo.decimals}`
+        return `Amount has too many decimals, maximum allowed for this token is ${req.tokenInfo.decimals}`
       }),
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between df0ae41 and 48c47b9.

📒 Files selected for processing (5)
  • packages/rest-api/src/routes/bridgeRoute.ts (2 hunks)
  • packages/rest-api/src/routes/bridgeTxInfoRoute.ts (2 hunks)
  • packages/rest-api/src/routes/swapRoute.ts (2 hunks)
  • packages/rest-api/src/routes/swapTxInfoRoute.ts (2 hunks)
  • packages/rest-api/src/validations/validateDecimals.ts (1 hunks)
🧰 Additional context used
📓 Learnings (1)
packages/rest-api/src/routes/swapTxInfoRoute.ts (4)
Learnt from: Defi-Moses
PR: synapsecns/sanguine#3133
File: packages/rest-api/src/controllers/swapTxInfoController.ts:14-14
Timestamp: 2024-10-08T15:41:49.333Z
Learning: In this project, request parameter validation is handled in the route files (e.g., `swapTxInfoRoute.ts`) rather than in the controller files.
Learnt from: Defi-Moses
PR: synapsecns/sanguine#3133
File: packages/rest-api/src/controllers/swapTxInfoController.ts:14-14
Timestamp: 2024-10-08T15:41:48.274Z
Learning: In this project, request parameter validation is handled in the route files (e.g., `swapTxInfoRoute.ts`) rather than in the controller files.
Learnt from: Defi-Moses
PR: synapsecns/sanguine#3133
File: packages/rest-api/src/controllers/swapTxInfoController.ts:14-14
Timestamp: 2024-09-17T23:09:44.463Z
Learning: In this project, request parameter validation is handled in the route files (e.g., `swapTxInfoRoute.ts`) rather than in the controller files.
Learnt from: Defi-Moses
PR: synapsecns/sanguine#3133
File: packages/rest-api/src/controllers/swapTxInfoController.ts:14-14
Timestamp: 2024-10-08T15:41:49.333Z
Learning: In this project, request parameter validation is handled in the route files (e.g., `swapTxInfoRoute.ts`) rather than in the controller files.
🔇 Additional comments (7)
packages/rest-api/src/validations/validateDecimals.ts (1)

1-11: Verify integration with token decimals

The function is used to validate amounts against token decimals. Let's verify that the token decimals are correctly passed to this function.

packages/rest-api/src/routes/swapTxInfoRoute.ts (2)

12-13: LGTM! New imports are well-organized.

The new utility imports are properly organized and align with the project's structure.


146-163: Implementation aligns with PR objectives.

The decimal validation logic successfully addresses the API decimals truncation issue by:

  1. Validating the amount against token-specific decimal places
  2. Providing clear error messages with the maximum allowed decimals

Let's verify the token decimal configuration:

✅ Verification successful

Let me verify the token decimal validation implementation by checking the validateDecimals function and tokenAddressToToken implementation.


Decimal validation implementation is correctly configured

The implementation properly validates token decimals by:

  1. Using a robust validateDecimals function that checks if the input amount's decimal places are within the token's specified limit
  2. Retrieving token-specific decimal information through tokenAddressToToken which sources from well-maintained token configuration maps
  3. Providing clear error messages that include the token's correct decimal precision

The token decimal configurations are consistently defined across the codebase with proper handling for:

  • Standard ERC20 tokens (18 decimals)
  • Stablecoins (6 decimals)
  • Special tokens (8 decimals)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify token decimal configuration consistency
# Expected: Find token decimal configurations to ensure they match with the validation

# Search for token decimal configurations
echo "Searching for token decimal configurations..."
rg -l "decimals.*=.*\d+" --type ts

# Search for any hardcoded decimal values
echo "Searching for hardcoded decimal values..."
rg "decimals:.*\d+" --type ts

Length of output: 85704


Script:

#!/bin/bash
# Check validateDecimals implementation
echo "Checking validateDecimals implementation..."
rg -A 10 "validateDecimals.*=.*" --type ts

# Check tokenAddressToToken implementation
echo "Checking tokenAddressToToken implementation..."
rg -A 10 "tokenAddressToToken.*=.*" --type ts

Length of output: 3858

packages/rest-api/src/routes/swapRoute.ts (1)

13-14: LGTM: New imports for decimal validation.

The new utility imports are well-organized and clearly named, supporting the PR's objective of fixing decimal truncation.

packages/rest-api/src/routes/bridgeTxInfoRoute.ts (2)

13-14: LGTM: New imports for decimal validation.

The added imports align with the PR's objective of implementing proper decimal validation.


167-184: Consider optimizing token info lookup and error handling.

The validation logic correctly implements decimal checking, but there are a few points to consider:

  1. The token info lookup is performed twice - once for validation and once for the error message. Consider storing the result to avoid duplicate calls.
  2. Error handling for tokenAddressToToken should be verified.

Consider refactoring to this pattern:

 check('amount')
   .exists()
   .withMessage('amount is required')
   .isNumeric()
   .custom((value, { req }) => {
-    const fromTokenInfo = tokenAddressToToken(
+    const fromTokenInfo = req.fromTokenInfo = tokenAddressToToken(
       req.query.fromChain,
       req.query.fromToken
     )
     return validateDecimals(value, fromTokenInfo.decimals)
   })
   .withMessage((_value, { req }) => {
-    const fromTokenInfo = tokenAddressToToken(
-      req.query.fromChain,
-      req.query.fromToken
-    )
+    const fromTokenInfo = req.fromTokenInfo
     return `Amount has too many decimals, maximum allowed for this token is ${fromTokenInfo.decimals}`
   })

Let's verify the error handling in tokenAddressToToken:

packages/rest-api/src/routes/bridgeRoute.ts (1)

13-14: LGTM: New imports for decimal validation.

The new utility imports are well-organized and follow the codebase conventions.

packages/rest-api/src/routes/swapTxInfoRoute.ts Outdated Show resolved Hide resolved
packages/rest-api/src/routes/swapRoute.ts Outdated Show resolved Hide resolved
packages/rest-api/src/routes/swapRoute.ts Show resolved Hide resolved
packages/rest-api/src/routes/bridgeRoute.ts Show resolved Hide resolved
@Defi-Moses Defi-Moses changed the title Fix API decimals truncation Fix API decimals handling Nov 7, 2024
Copy link
Collaborator

@ChiTimesChi ChiTimesChi left a comment

Choose a reason for hiding this comment

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

LGTM

@abtestingalpha abtestingalpha merged commit 9c294d5 into master Nov 7, 2024
36 checks passed
@abtestingalpha abtestingalpha deleted the feat/api-decimals branch November 7, 2024 19:59
@coderabbitai coderabbitai bot mentioned this pull request Nov 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants