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

Feat/zapper 2 #333

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open

Feat/zapper 2 #333

wants to merge 24 commits into from

Conversation

vuonghuuhung
Copy link
Member

@vuonghuuhung vuonghuuhung commented Sep 19, 2024

Summary by CodeRabbit

  • New Features

    • Updated version number of the @oraichain/oraiswap-v3 package to "0.1.20-beta.2."
    • Updated version number of the @oraichain/oraidex-common package to "1.1.21."
    • Updated version number of the @oraichain/oraidex-contracts-sdk package to "1.0.53-beta.2."
    • Enhanced liquidity provisioning functionality with flexible handling of token amounts for single-sided and dual-sided liquidity.
    • Improved testing capabilities for various components, including the Incentives Fund Manager and token interactions.
  • Bug Fixes

    • Corrected minor issues in the test setup and formatting for better clarity and functionality.

Copy link

coderabbitai bot commented Sep 19, 2024

Walkthrough

The pull request introduces updates to the @oraichain/oraiswap-v3 package, including a version increment from 0.1.8 to 0.1.20-beta.2, and updates to dependencies on @oraichain/oraidex-common from ^1.1.6 to ^1.1.21, and @oraichain/oraidex-contracts-sdk from ^1.0.52 to 1.0.53-beta.2. New types and functions for handling liquidity provisioning have been added, enhancing the flexibility of token management within the contract. The test files have also been updated to reflect these changes.

Changes

File Path Change Summary
packages/oraiswap-v3/package.json Updated package version from 0.1.8 to 0.1.20-beta.2; dependency on @oraichain/oraidex-common updated from ^1.1.6 to ^1.1.21; dependency on @oraichain/oraidex-contracts-sdk updated from ^1.0.52 to 1.0.53-beta.2.
packages/oraiswap-v3/src/helpers.ts Added new type buildZapInMessageOptions; modified populateMessageZapIn and calculateMinimumLiquidity functions to utilize this new type.
packages/oraiswap-v3/src/main.ts Removed poolList; updated tokenIn determination; replaced processZapInPositionLiquidity with processZapOutPositionLiquidity; modified tick range for liquidity processing.
packages/oraiswap-v3/tests/handler.spec.ts Reformatted imports; added fundManager variable; updated instantiation of OraiswapV3Client to include incentives_fund_manager.
packages/oraiswap-v3/tests/test-common.ts Expanded imports from @oraichain/oraidex-contracts-sdk; added new deployment functions and constants for managing incentives and contracts.
packages/oraiswap-v3/tests/zap-consumer.spec.ts Expanded imports; reorganized test structure to include new test suites for connect function and zap function, enhancing testing capabilities.

Possibly related PRs

  • Feat/oraiswap v3 #285: Updates to the package.json for @oraichain/oraiswap-v3, relevant to the main PR's changes.
  • Feat/update amm v3 sdk #307: Updates the @oraichain/oraiswap-v3 package, reflecting changes in the version number and enhancements that align with the updates made in the main PR.
  • Feat/update v3 sdk #315: Similar to the main PR, this PR updates the version number for @oraichain/oraiswap-v3 and includes dependency updates that are relevant to the changes made in the main PR.
  • Feat/update v3 sdk #319: Continues the version updates for @oraichain/oraiswap-v3, indicating ongoing enhancements that relate to the changes in the main PR.
  • Feat/add params smart route #325: Updates in this PR for @oraichain/oraidex-common are relevant as they may impact the functionality of the @oraichain/oraiswap-v3 package.
  • bump: fix version #341: Updates the version of @oraichain/oraidex-universal-swap, which is relevant to the overall ecosystem that the main PR is part of, indicating a broader context of updates.

Suggested reviewers

  • trung2891
  • quangdz1704
  • haunv3

🐇 In the fields where tokens play,
New routes and constants come to stay.
With BSC and ETH in the mix,
Oraiswap hops with clever tricks!
A version bump, oh what a cheer,
Let’s celebrate with carrots near! 🥕


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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

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

github-actions bot commented Sep 19, 2024

badge

Code Coverage Summary

Filename                                                                      Stmts    Miss  Cover    Missing
--------------------------------------------------------------------------  -------  ------  -------  ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
docs/assets/main.js                                                              58      58  0.00%    1-58
docs/assets/search.js                                                             1       1  0.00%    1
packages/ibc-routing/hardhat.config.ts                                           59      59  0.00%    1-75
packages/ibc-routing/src/db.ts                                                  158     158  0.00%    1-263
packages/ibc-routing/src/event.ts                                                85      85  0.00%    1-122
packages/ibc-routing/src/index.ts                                                31      31  0.00%    1-56
packages/ibc-routing/src/machine.ts                                              30      30  0.00%    1-34
packages/ibc-routing/test/mock-eth-ws.ts                                         52      52  0.00%    1-55
packages/ibc-routing/test/mock-tendermint-ws.spec.ts                             25      17  32.00%   7-24
packages/oraidex-common/src/alpha-network.ts                                     61       0  100.00%
packages/oraidex-common/src/axios-request.ts                                     11      11  0.00%    1-20
packages/oraidex-common/src/bigdecimal.ts                                       139      50  64.02%   23-24, 30-33, 40-41, 45-54, 63-65, 71-73, 120-124, 127-146, 149-150, 153-154, 180-181, 184-185
packages/oraidex-common/src/constant.ts                                         169       0  100.00%
packages/oraidex-common/src/helper.ts                                           466     142  69.52%   141-142, 145-156, 159-169, 267-269, 286-293, 296-309, 319-325, 335-350, 353-360, 363-393, 396-404, 407-409, 412-414, 418-427, 436-450, 456-458, 543-544, 569-572
packages/oraidex-common/src/ibc-info.ts                                         183     183  0.00%    1-215
packages/oraidex-common/src/index.ts                                             13      13  0.00%    1-13
packages/oraidex-common/src/network.ts                                         1022       0  100.00%
packages/oraidex-common/src/pairs.ts                                            154       4  97.40%   151-152, 157-158
packages/oraidex-common/src/token.ts                                             71       0  100.00%
packages/oraidex-common/src/wallet.ts                                           146     146  0.00%    1-236
packages/oraidex-common/src/config/chainInfosWithIcon.ts                        208     208  0.00%    1-222
packages/oraidex-common/src/interface/index.ts                                    1       1  0.00%    1
packages/oraidex-common/src/interface/wallet.ts                                  19      19  0.00%    1-20
packages/oraidex-common/tests/bigdecimal.spec.ts                                220       0  100.00%
packages/oraidex-common/tests/helper.spec.ts                                    560       8  98.57%   97-98, 337-338, 628-629, 659-660
packages/oraidex-common/tests/pairs.spec.ts                                      24       0  100.00%
packages/oraiswap-v3/src/const.ts                                                11       0  100.00%
packages/oraiswap-v3/src/error.ts                                                15       6  60.00%   3-4, 9-10, 15-16
packages/oraiswap-v3/src/handler.ts                                             292      28  90.41%   63-64, 100-101, 216-217, 341-355, 358-366
packages/oraiswap-v3/src/helpers.ts                                             467     257  44.96%   122-123, 133-134, 159-160, 188-189, 199-200, 283-287, 290-297, 300-356, 359-364, 367-376, 380-436, 439-447, 450-481, 484-497, 505-545, 548-554, 557-581
packages/oraiswap-v3/src/index.ts                                                 7       0  100.00%
packages/oraiswap-v3/src/main.ts                                                 36      36  0.00%    1-59
packages/oraiswap-v3/src/types.ts                                                 9       0  100.00%
packages/oraiswap-v3/src/zap-consumer.ts                                        394     370  6.09%    80-127, 135-137, 147-174, 184-197, 215-286, 302-522, 534-581
packages/oraiswap-v3/src/wasm/oraiswap_v3_wasm.d.ts                              32      32  0.00%    469-500
packages/oraiswap-v3/src/wasm/oraiswap_v3_wasm.js                              1543     369  76.08%   32-34, 92-94, 100-101, 103-108, 113-120, 136-145, 160-223, 249-250, 278-279, 307-308, 336-337, 365-366, 394-395, 423-424, 463-464, 496-497, 525-526, 543-544, 565-579, 723-724, 748-749, 770-771, 783-786, 801-802, 832-833, 863-864, 884-885, 910-911, 929-953, 958-961, 966-969, 976-979, 984-987, 992-995, 1002-1005, 1010-1013, 1028-1031, 1036-1039, 1044-1047, 1062-1065, 1080-1083, 1088-1091, 1096-1099, 1106-1109, 1114-1117, 1122-1125, 1132-1135, 1149-1150, 1161-1164, 1170-1173, 1188-1191, 1196-1199, 1204-1207, 1214-1217, 1219-1225, 1300-1301, 1329-1330, 1333-1335, 1356-1361, 1364-1365, 1368-1372, 1386-1387, 1390-1391, 1394-1395, 1398-1399, 1402-1403, 1406-1407, 1410-1413, 1416-1417, 1420-1421, 1424-1425, 1428-1431, 1434-1437, 1444, 1447-1448, 1451-1458, 1465-1466, 1469-1470, 1473-1474, 1477, 1480-1481, 1484-1491, 1500-1504, 1507, 1510-1511
packages/oraiswap-v3/tests/handler.spec.ts                                      280       0  100.00%
packages/oraiswap-v3/tests/helpers.spec.ts                                      577       0  100.00%
packages/oraiswap-v3/tests/test-common.ts                                        97       0  100.00%
packages/oraiswap-v3/tests/wasm-bindgen.spec.ts                                 368       3  99.18%   450-452
packages/oraiswap-v3/tests/zap-consumer.spec.ts                                 209       0  100.00%
packages/universal-swap/src/handler.ts                                         1228     662  46.09%   79-80, 101-102, 117-119, 125-128, 150-155, 176-198, 278-308, 365-370, 421-441, 492-497, 544-555, 579, 581-585, 598-609, 616-631, 634-692, 703-713, 716-726, 733-740, 754-831, 835-866, 870-889, 892-909, 913-970, 975-1059, 1065-1150, 1160-1167, 1196-1197, 1199-1200, 1206, 1220-1244, 1274-1277, 1310-1313, 1320-1330, 1335-1355, 1396-1397, 1410-1453, 1516-1517
packages/universal-swap/src/helper.ts                                           948     326  65.61%   87-89, 225-226, 272-277, 305-306, 340-352, 366-420, 461-463, 488-494, 520-522, 526-528, 535-562, 624-625, 658-665, 672-713, 725-779, 818-819, 834, 862, 869-892, 894-895, 937-938, 942-945, 955-997, 1005-1021, 1080-1090, 1101-1106, 1125, 1151-1163, 1281-1292
packages/universal-swap/src/index.ts                                              6       6  0.00%    1-6
packages/universal-swap/src/swap-filter.ts                                       40       0  100.00%
packages/universal-swap/src/types.ts                                             10       0  100.00%
packages/universal-swap/src/wrapper.ts                                           79      79  0.00%    1-117
packages/universal-swap/src/proto/index.ts                                        1       1  0.00%    1
packages/universal-swap/src/proto/universal-swap-memo-proto-handler.ts           66      60  9.09%    21-46, 50-91
packages/universal-swap/src/proto/universal_swap_memo.ts                        911     818  10.20%   110-112, 116-132, 135-183, 186-193, 196-213, 216-217, 219-230, 233-235, 239-243, 246-266, 269-274, 277-282, 285-286, 288-291, 294-296, 300-304, 307-327, 330-333, 336-341, 344-345, 347-350, 353-355, 359-366, 369-396, 399-405, 408-416, 419-420, 422-426, 429-431, 435-445, 448-482, 485-490, 493-504, 507-508, 510-515, 518-520, 524-534, 537-571, 574-583, 586-597, 600-601, 603-613, 616-618, 622-635, 638-679, 682-690, 693-707, 710-711, 713-727, 730-732, 736-752, 755-803, 806-813, 816-833, 836-837, 839-846, 849-851, 855-871, 874-922, 925-932, 935-952, 955-956, 958-965, 968-970, 974-981, 984-1011, 1014-1018, 1021-1029, 1032-1033, 1035-1039, 1042-1044, 1048-1052, 1055-1075, 1078-1079, 1082-1087, 1090-1091, 1093-1096, 1111-1119, 1122-1128
packages/universal-swap/src/universal-demos/alpha-smart-router.ts               114     114  0.00%    1-589
packages/universal-swap/src/universal-demos/evm-to-evm.ts                        52      52  0.00%    1-68
packages/universal-swap/src/universal-demos/from-cosmos-to-evm.ts                41      41  0.00%    1-53
packages/universal-swap/src/universal-demos/from-oraichain-to-evm.ts             42      42  0.00%    1-62
packages/universal-swap/src/universal-demos/from-oraichain-to-oraichain.ts       49      49  0.00%    1-66
packages/universal-swap/src/universal-demos/handle-simulate-swap.ts              32      32  0.00%    1-36
packages/universal-swap/src/universal-demos/ibc-hooks-demo.ts                    40      40  0.00%    1-55
packages/universal-swap/src/universal-demos/neutaro-ibc-demo.ts                  40      40  0.00%    1-47
packages/universal-swap/src/universal-demos/noble-ibc-demo.ts                    41      41  0.00%    1-45
packages/universal-swap/src/universal-demos/offline-wallet.ts                    19      19  0.00%    1-21
packages/universal-swap/tests/helper.spec.ts                                    697      24  96.55%   378, 947-969
packages/universal-swap/tests/index.spec.ts                                    1743      32  98.16%   240-243, 271-272, 283-284, 289-290, 292-293, 295-296, 1138-1157
packages/universal-swap/tests/smart-router-common.ts                            864       0  100.00%
packages/universal-swap/tests/test-common.ts                                     56       0  100.00%
TOTAL                                                                         15422    4855  68.51%

Diff against main

Filename                                             Stmts    Miss  Cover
-------------------------------------------------  -------  ------  --------
packages/oraiswap-v3/src/error.ts                      +10      +4  +100.00%
packages/oraiswap-v3/src/helpers.ts                    +23     +23  -2.33%
packages/oraiswap-v3/src/main.ts                        -1      -1  +100.00%
packages/oraiswap-v3/src/types.ts                       -4       0  +100.00%
packages/oraiswap-v3/src/zap-consumer.ts              -102    -108  +2.47%
packages/oraiswap-v3/src/wasm/oraiswap_v3_wasm.js        0    -341  +22.10%
packages/oraiswap-v3/tests/handler.spec.ts              +4       0  +100.00%
packages/oraiswap-v3/tests/test-common.ts              +65       0  +100.00%
packages/oraiswap-v3/tests/wasm-bindgen.spec.ts       +368      +3  +99.18%
packages/oraiswap-v3/tests/zap-consumer.spec.ts       +159       0  +100.00%
TOTAL                                                 +522    -420  +3.92%

Results for commit: dfa75cf

Minimum allowed coverage is 0%

♻️ This comment has been updated with latest results

Copy link

@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: 9

Outside diff range and nitpick comments (5)
packages/oraiswap-v3/src/types.ts (1)

275-284: Enhance readability of ZapInResult enum descriptions

Consider rephrasing the descriptions in the ZapInResult enum for better clarity and conciseness.

You might revise the descriptions as follows:

 export enum ZapInResult {
   // In range
-  InRangeNoRouteThroughSelf = "This zap operation has no swap through this pool and the position is in range so the accuracy is good",
+  InRangeNoRouteThroughSelf = "No swap through this pool; position in range; accuracy is good",
-  InRangeHasRouteThroughSelf = "This zap operation has swap through this pool and the position is in range so the accuracy is good",
+  InRangeHasRouteThroughSelf = "Swap through this pool; position in range; accuracy is good",
-  InRangeHasRouteThroughSelfMayBecomeOutRange = "This zap operation has swap through this pool and the position is in range but the next tick is out of range so the accuracy is low",
+  InRangeHasRouteThroughSelfMayBecomeOutRange = "Swap through this pool; position in range but next tick out of range; accuracy is low",

   // Out of range
-  OutRangeNoRouteThroughSelf = "This zap operation has no swap through this pool and the position is out of range so the accuracy is good",
+  OutRangeNoRouteThroughSelf = "No swap through this pool; position out of range; accuracy is good",
-  OutRangeHasRouteThroughSelf = "This zap operation has swap through this pool and the position is out of range but the next tick is not in range so the accuracy is good",
+  OutRangeHasRouteThroughSelf = "Swap through this pool; position out of range and next tick also out of range; accuracy is good",
-  OutRangeHasRouteThroughSelfMayBecomeInRange = "This zap operation has swap through this pool and the position is out of range but the next tick is in range so the accuracy is low"
+  OutRangeHasRouteThroughSelfMayBecomeInRange = "Swap through this pool; position out of range but next tick in range; accuracy is low"
 }

This enhances readability and makes the descriptions more straightforward.

packages/oraiswap-v3/src/helpers.ts (1)

513-514: Ensure consistent use of optional parameters in function signature

In the populateMessageZapIn function, the optional parameter buildZapInMessageOptions is added without a space before the colon, which is inconsistent with the rest of the parameters and could affect readability.

Apply this diff to maintain consistent formatting:

 export const populateMessageZapIn = (
   message: ZapInLiquidityResponse,
   actualAmountXReceived: SmartRouteResponse,
   actualAmountYReceived: SmartRouteResponse,
   sqrtPrice: bigint,
   poolKey: PoolKey,
   lowerTick: number,
   upperTick: number,
   slippage: number,
-  buildZapInMessageOptions?:buildZapInMessageOptions
+  buildZapInMessageOptions?: buildZapInMessageOptions
 ) => {
packages/oraiswap-v3/src/zap-consumer.ts (3)

489-496: Enhance Documentation for processZapOutPositionLiquidity Parameters

The JSDoc comments for the processZapOutPositionLiquidity method (lines 489-496) lack detailed descriptions for the parameters.

Improve the documentation to enhance readability and maintainability:

/**
 * Processes the zap-out operation for a liquidity position.
 * @param tokenId - The unique identifier of the position token.
 * @param owner - The address of the position owner.
 * @param tokenOut - The token to receive after removing liquidity.
 * @param zapFee - The fee percentage applied during the zap-out process.
 * @param slippage - (Optional) The acceptable slippage percentage (default is 1%).
 * @returns Result of the zap-out operation.
 */

Providing clear documentation helps other developers understand the purpose and usage of the method.


Line range hint 280-481: Refactor Long Method for processZapInPositionLiquidity

The processZapInPositionLiquidity method spans over 200 lines (lines 280-481), which makes it lengthy and potentially difficult to maintain.

Consider refactoring the method into smaller, reusable private methods that handle specific tasks. For example:

  • Extract the calculation logic into a separate method.
  • Separate the route finding logic.
  • Isolate the simulation steps.

This refactoring will improve the readability and maintainability of your code.


35-53: Remove Redundant Comments

The extensive comments between lines 35-53 explain the flow and methods of the ZapConsumer class. While documentation is valuable, these comments duplicate information that should be in documentation rather than inline comments.

Consider removing or reducing these comments and instead rely on clear method names and external documentation. This will declutter the code and make it more readable.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 87032d5 and fd9093f.

Files selected for processing (7)
  • .github/workflows/publish_oraiswap_v3.yml (1 hunks)
  • packages/oraiswap-v3/package.json (1 hunks)
  • packages/oraiswap-v3/src/error.ts (1 hunks)
  • packages/oraiswap-v3/src/helpers.ts (2 hunks)
  • packages/oraiswap-v3/src/main.ts (2 hunks)
  • packages/oraiswap-v3/src/types.ts (2 hunks)
  • packages/oraiswap-v3/src/zap-consumer.ts (9 hunks)
Files skipped from review due to trivial changes (1)
  • packages/oraiswap-v3/package.json
Additional context used
actionlint
.github/workflows/publish_oraiswap_v3.yml

24-24: the runner of "actions/checkout@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


26-26: the runner of "actions/setup-node@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


31-31: workflow command "set-output" was deprecated. use echo "{name}={value}" >> $GITHUB_OUTPUT instead: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions

(deprecated-commands)

Biome
packages/oraiswap-v3/src/zap-consumer.ts

[error] 143-143: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)

Additional comments not posted (11)
packages/oraiswap-v3/src/error.ts (2)

7-11: LGTM!

The RouteNoLiquidity error class is implemented correctly:

  • It extends the base Error class.
  • The constructor sets a specific error message, which is a good practice for custom error classes.
  • The error class name is descriptive and conveys the purpose of the error.

This new error class enhances error handling by allowing developers to catch and respond to scenarios where a route is valid but lacks the necessary liquidity for transactions. It improves the robustness and clarity of the codebase, allowing for more precise error handling and debugging.


13-16: LGTM!

The SpamTooManyRequestsError error class is implemented correctly:

  • It extends the base Error class.
  • The constructor sets a specific error message, which is a good practice for custom error classes.
  • The error class name is descriptive and conveys the purpose of the error.

This new error class could be useful for rate limiting and managing user interactions with the system. It improves the robustness and clarity of the codebase, allowing for more precise error handling and debugging.

packages/oraiswap-v3/src/main.ts (7)

3-3: LGTM!

The import statement for KWT_CONTRACT is syntactically correct.

Ensure that KWT_CONTRACT is used appropriately in the rest of the file.


8-8: LGTM!

The import statement for USDT_CONTRACT is syntactically correct.


12-12: LGTM!

The import statement for extractAddress and parsePoolKey is syntactically correct.


28-28: LGTM!

The change to directly find the token by its name enhances clarity and reduces complexity.


29-31: LGTM!

The changes to directly construct the pool string and fetch the pool information immediately after deriving the pool key improve the flow of data retrieval and simplify the pool selection process.


32-33: LGTM!

The assignments of tickSpacing and currentTick are syntactically correct.


35-46: LGTM!

The changes to use the fetched pool information, dynamically calculate the amount of input tokens based on the token's decimals, and modify the logging of results enhance flexibility and readability.

packages/oraiswap-v3/src/zap-consumer.ts (2)

443-445: Safeguard Against Division by Zero

At lines 443-445, the calculation involves division operations that could potentially result in a division by zero if yPerX or xPriceByY are zero.

Add checks to ensure that yPerX and xPriceByY are not zero before performing the division:

if (diffX > this._deviation || diffY > this._deviation) {
+ if (yPerX.isZero() || xPriceByY.isZero()) {
+   throw new Error("yPerX or xPriceByY is zero, cannot proceed with division.");
+ }
  const deltaX = yAmount.sub(yPerX.mul(xAmount)).div(yPerX.add(xPriceByY));
  ...
}

This prevents runtime errors and ensures the reliability of your calculations.

Likely invalid or redundant comment.


184-187: Review Pool State Update Logic

At lines 184-187, after simulating the swap, you're updating the pool's sqrt_price and current_tick_index by averaging:

pool.sqrt_price = ((BigInt(pool.sqrt_price) + BigInt(swapResult.target_sqrt_price)) / 2n).toString();
const tick = getTickAtSqrtPrice(BigInt(pool.sqrt_price), poolKey.fee_tier.tick_spacing);
pool.current_tick_index = (pool.current_tick_index + tick) / 2;

This averaging may not accurately reflect the pool's state after the swap simulation.

Consider verifying whether the averaging correctly represents the new state of the pool. It might be more appropriate to use the target_sqrt_price and corresponding tick directly.

Run the following script to compare the calculated tick index:

Ensure that the pool state update logic aligns with the domain requirements.

packages/oraiswap-v3/src/types.ts Outdated Show resolved Hide resolved
packages/oraiswap-v3/src/helpers.ts Outdated Show resolved Hide resolved
packages/oraiswap-v3/src/helpers.ts Show resolved Hide resolved
packages/oraiswap-v3/src/helpers.ts Outdated Show resolved Hide resolved
packages/oraiswap-v3/src/zap-consumer.ts Outdated Show resolved Hide resolved
packages/oraiswap-v3/src/zap-consumer.ts Show resolved Hide resolved
packages/oraiswap-v3/src/zap-consumer.ts Show resolved Hide resolved
packages/oraiswap-v3/src/zap-consumer.ts Outdated Show resolved Hide resolved
packages/oraiswap-v3/src/zap-consumer.ts Outdated Show resolved Hide resolved
Copy link

@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: 10

Outside diff range and nitpick comments (6)
packages/universal-swap/src/universal-demos/from-oraichain-to-evm.ts (2)

20-26: Remove Commented-Out Code for Clarity

The commented-out code between lines 20 and 26 can clutter the codebase and cause confusion. If this code is no longer needed, consider removing it. If it's meant for future use or reference, add a comment explaining its purpose.


59-61: Simplify Function Invocation Without IIFE

Wrapping oraichainToEvm() inside an Immediately Invoked Function Expression (IIFE) is unnecessary here. You can call the async function directly and handle any top-level promises appropriately.

Apply this diff to simplify the function call:

-(() => {
-  return oraichainToEvm();
-})();
+
+oraichainToEvm();
packages/oraidex-common/src/network.ts (3)

327-334: Include the "type" Property for the "PEPE" Token

For consistency with other CW20 tokens, consider adding the "type": "cw20" property to the "PEPE" token definition if applicable.

Apply this diff to add the "type" property:

{
  coinDenom: "PEPE",
  coinGeckoId: "pepe",
  coinMinimalDenom: PEPE_ORAICHAIN_DENOM,
+ type: "cw20",
  bridgeTo: ["0x38", "0x01"],
  coinDecimals: 18,
  coinImageUrl: "https://assets.coingecko.com/coins/images/29850/standard/pepe-token.jpeg?1696528776"
},

335-342: Include the "type" Property for the "CAT" Token

Similarly, consider adding the "type": "cw20" property to the "CAT" token definition for consistency if it is a CW20 token.

Apply this diff:

{
  coinDenom: "CAT",
  coinMinimalDenom: CAT_ORAICHAIN_DENOM,
  coinDecimals: 18,
+ type: "cw20",
  bridgeTo: ["0x38"],
  coinGeckoId: "simon-s-cat",
  coinImageUrl: "https://assets.coingecko.com/coins/images/39765/standard/Simon's_Cat_Logo.png?1724017505"
},

987-996: Add "CAT" Token to the Ethereum Network if Intended

Currently, only the "PEPE" token is added to the Ethereum network. If the "CAT" token is also available on Ethereum, consider adding its definition to ensure users can interact with it on this network.

packages/universal-swap/src/handler.ts (1)

1015-1017: Consider removing commented-out code for cleanliness

The lines related to network switching for EVM wallets are commented out. If these are no longer needed, it's better to remove them to maintain code clarity and reduce clutter.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 3233dcf and ea92c38.

Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
Files selected for processing (8)
  • packages/oraidex-common/package.json (1 hunks)
  • packages/oraidex-common/src/constant.ts (3 hunks)
  • packages/oraidex-common/src/helper.ts (1 hunks)
  • packages/oraidex-common/src/network.ts (6 hunks)
  • packages/universal-swap/package.json (1 hunks)
  • packages/universal-swap/src/handler.ts (8 hunks)
  • packages/universal-swap/src/types.ts (1 hunks)
  • packages/universal-swap/src/universal-demos/from-oraichain-to-evm.ts (1 hunks)
Files skipped from review due to trivial changes (1)
  • packages/oraidex-common/package.json
Additional comments not posted (16)
packages/universal-swap/package.json (1)

3-3: Version updated to a beta release.

The version change from 1.1.5 to 1.1.5-beta.3 indicates a transition to a beta release. This suggests that the package may include features that are still in testing or not yet finalized.

Please consider the following when using this beta version:

  • Thoroughly test the beta version before using it in production environments.
  • Inform dependent projects or packages about the beta release and the potential for instability or breaking changes.
  • Document any known issues or limitations of the beta release.
packages/universal-swap/src/types.ts (1)

92-92: LGTM! Remember to handle the new property in the consuming code.

The addition of the isCheckBalanceIbc property to the SwapOptions interface is a valid change that expands the configuration options for swap operations. It allows for more granular control over the balance check behavior in the context of Inter-Blockchain Communication (IBC).

Please ensure that the code consuming the SwapOptions interface is updated to handle this new optional property appropriately. If the property is set to true, the corresponding balance check logic should be triggered during the swap process.

Run the following script to verify the usage of the new property:

Verification successful

shell
#!/bin/bash

Description: Verify the usage of the isCheckBalanceIbc property in the codebase.

Test: Search for the property usage in TypeScript files.

rg 'isCheckBalanceIbc' -g '.ts' -g '.tsx' -A 5



---

<!-- [monologue]
[task level_1/1 level_2/1]
Analyze the results from the latest shell script execution to verify the usage of the `isCheckBalanceIbc` property.

[observations]
- The `isCheckBalanceIbc` property is used in `handler.ts` and `from-oraichain-to-evm.ts`.
- In `handler.ts`, the property is checked within conditional statements to control balance checks.
- In `from-oraichain-to-evm.ts`, the property is set to `true` within the `SwapOptions` configuration.
- The property is defined in `types.ts` as an optional boolean in the `SwapOptions` interface.

[analysis]
- The property `isCheckBalanceIbc` has been consistently added and utilized across relevant files.
- Its usage in conditional statements indicates that the property is actively controlling logic based on its value.
- Setting the property in `from-oraichain-to-evm.ts` ensures that it is being used where `SwapOptions` are configured.
- No instances suggest that the property is defined but unused or improperly handled.

[actions]
- Conclude that the `isCheckBalanceIbc` property is appropriately integrated and handled in the codebase.
- Approve the review comment as the verification confirms that the property is being utilized correctly.
-->
**Verified: `isCheckBalanceIbc` is appropriately handled in the codebase.**

The `isCheckBalanceIbc` property is correctly integrated and utilized within the relevant parts of the codebase, ensuring that balance checks in the context of IBC are effectively controlled based on this configuration.


</details>


<details>
<summary>Scripts executed</summary>

The following scripts were executed for the analysis:

Script:

```shell
#!/bin/bash
# Description: Verify the usage of the `isCheckBalanceIbc` property in the codebase.

# Test: Search for the property usage. Expect: Occurrences in the code that consumes SwapOptions.
rg --type typescript -A 5 $'isCheckBalanceIbc'

Length of output: 80


Script:

Length of output: 98


Script:

Length of output: 0


Script:

#!/bin/bash
# Description: Verify the usage of the `isCheckBalanceIbc` property in the codebase.

# Test: Search for the property usage in TypeScript files.
rg 'isCheckBalanceIbc' -g '*.ts' -g '*.tsx' -A 5

Length of output: 2416

packages/oraidex-common/src/constant.ts (5)

56-56: LGTM!

The constant is properly declared and follows the existing naming convention. The value is a valid BSC contract address format.


57-57: LGTM!

The constant is properly declared and follows the existing naming convention. The value is a valid BSC contract address format.


72-72: LGTM!

The constant is properly declared and follows the existing naming convention. The value is a valid Ethereum contract address format.


100-100: LGTM!

The constant is properly declared and follows the existing naming convention. The value follows the format of other Oraichain denominators.


101-101: LGTM!

The constant is properly declared and follows the existing naming convention. The value follows the format of other Oraichain denominators.

packages/oraidex-common/src/helper.ts (1)

255-268: Verify the function usage in the codebase.

The changes to the getTokenOnOraichain function look good. The function now handles cases where multiple tokens are found for a given coingeckoId and uses the isNative flag to distinguish between native and non-native tokens.

Please ensure that all calls to this function have been updated to provide the isNative argument where necessary.

Run the following script to verify the function usage:

Verification successful

Function usage verified

All calls to getTokenOnOraichain include the isNative argument as required.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `getTokenOnOraichain` provide the `isNative` argument where necessary.

# Test: Search for the function usage. Expect: Occurrences with the `isNative` argument.
ast-grep --lang typescript --pattern $'getTokenOnOraichain($_, $_)'

Length of output: 182

packages/oraidex-common/src/network.ts (3)

121-123: Confirm Accuracy of CoinGecko IDs

Ensure that the CoinGeckoId values "pepe" and "simon-s-cat" correctly correspond to the intended tokens on CoinGecko to avoid mismatches in token data.


57-62: Verify the Existence and Correctness of Newly Added Constants

Please ensure that the constants PEPE_ORAICHAIN_DENOM, CAT_ORAICHAIN_DENOM, PEPE_ETH_CONTRACT, PEPE_BSC_CONTRACT, and CAT_BSC_CONTRACT are correctly defined and exported in "./constant".

Run the following script to verify the definitions:

#!/bin/bash
# Description: Verify that the new constants are defined in "./constant.ts"

# Test: Search for the constant definitions. Expect: Definitions found for all constants.
rg 'export const (PEPE_ORAICHAIN_DENOM|CAT_ORAICHAIN_DENOM|PEPE_ETH_CONTRACT|PEPE_BSC_CONTRACT|CAT_BSC_CONTRACT)' ./packages/oraidex-common/src/constant.ts

663-681: Verify "prefixToken" and "bridgeNetworkIdentifier" Properties

Ensure that the "prefixToken" and "bridgeNetworkIdentifier" properties for the "PEPE" and "CAT" tokens are correctly set to maintain consistency and proper bridging functionality.

Run the following script to check the properties:

packages/universal-swap/src/handler.ts (5)

140-140: Verify the use of 'true' for 'isNative' parameter

In the condition where isSpecialChain && isSpecialCoingecko, getTokenOnOraichain is called with isNative set to true. Please verify that this is the intended behavior and that it does not affect other tokens.


280-280: Confirm the necessity of 'isNative' set to 'true'

When handling specific tokens, getTokenOnOraichain is invoked with isNative as true. Ensure this is required for the tokens in question and won't introduce unexpected behavior.


1258-1258: Verify if 'isNative' parameter is required in this context

The method getTokenOnOraichain is called without the isNative parameter. Ensure that omitting this parameter is appropriate here and that the default behavior aligns with the expected outcome.


1287-1287: Confirm correctness of 'getTokenOnOraichain' usage without 'isNative'

Another instance where getTokenOnOraichain is called without specifying isNative. Please confirm that this is intentional and does not affect token retrieval.


74-75: Ensure all calls to 'getTokenOnOraichain' are updated with the new parameter

The method signature of getTokenOnOraichain has changed to accept isNative?: boolean. Verify that all calls to this method have been updated accordingly.

Verification successful

Verification Successful: All calls to getTokenOnOraichain in handler.ts include the new isNative parameter

All instances within packages/universal-swap/src/handler.ts have been correctly updated to include the isNative parameter.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all calls to 'getTokenOnOraichain' without the 'isNative' parameter.

# Search for function calls to 'getTokenOnOraichain' with only one argument.
ast-grep --lang typescript --pattern 'getTokenOnOraichain($_)'

Length of output: 2298

packages/oraidex-common/src/network.ts Outdated Show resolved Hide resolved
packages/oraidex-common/src/network.ts Outdated Show resolved Hide resolved
packages/universal-swap/src/handler.ts Outdated Show resolved Hide resolved
packages/universal-swap/src/handler.ts Outdated Show resolved Hide resolved
packages/universal-swap/src/handler.ts Outdated Show resolved Hide resolved
Copy link

@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: 4

🧹 Outside diff range and nitpick comments (3)
packages/oraiswap-v3/tests/wasm-bindgen.spec.ts (3)

340-340: Remove unnecessary console.log statement

The console.log(res); statement in the positionToTick test may clutter the test output. It's generally best to remove such statements unless they're needed for debugging purposes.

Apply this diff to remove the console log:

-          console.log(res);

443-449: Remove redundant empty test for 'checkTickToSqrtPriceRelationship'

The test for checkTickToSqrtPriceRelationship has an empty array of test cases, resulting in no executed tests. Since there is another test for this function with actual test cases, consider removing this redundant empty test to keep the test suite clean.

Apply this diff to remove the empty test:

-      it.each<[number, number, bigint, boolean]>([])(
-        "checkTickToSqrtPriceRelationship",
-        (tick, tickSpacing, sqrtPrice, expected) => {
-          const res = checkTickToSqrtPriceRelationship(tick, tickSpacing, sqrtPrice);
-          expect(res).toEqual(expected);
-        }
-      );

537-543: Consolidate 'checkTickToSqrtPriceRelationship' tests

There are two separate tests for checkTickToSqrtPriceRelationship. To improve maintainability, consider consolidating them into a single test block with all relevant test cases.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 6a8e432 and 54a7cbc.

⛔ Files ignored due to path filters (6)
  • packages/oraiswap-v3/tests/data/incentives-fund-manager.wasm is excluded by !**/*.wasm
  • packages/oraiswap-v3/tests/data/oraiswap-factory.wasm is excluded by !**/*.wasm
  • packages/oraiswap-v3/tests/data/oraiswap-mixed-router.wasm is excluded by !**/*.wasm
  • packages/oraiswap-v3/tests/data/oraiswap-oracle.wasm is excluded by !**/*.wasm
  • packages/oraiswap-v3/tests/data/oraiswap-pair.wasm is excluded by !**/*.wasm
  • packages/oraiswap-v3/tests/data/zapper.wasm is excluded by !**/*.wasm
📒 Files selected for processing (2)
  • packages/oraiswap-v3/package.json (2 hunks)
  • packages/oraiswap-v3/tests/wasm-bindgen.spec.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/oraiswap-v3/package.json

packages/oraiswap-v3/tests/wasm-bindgen.spec.ts Outdated Show resolved Hide resolved
packages/oraiswap-v3/tests/wasm-bindgen.spec.ts Outdated Show resolved Hide resolved
Copy link

@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: 2

🧹 Outside diff range and nitpick comments (3)
packages/oraiswap-v3/src/zap-consumer.ts (3)

Line range hint 195-281: Consider refactoring processZapInWithSingleSide for improved readability

The processZapInWithSingleSide method effectively handles zap-in with a single token. However, its complexity and multiple conditional branches make it challenging to understand at a glance.

Consider refactoring this method to improve readability:

  1. Extract the token need determination logic into a separate method:
private determineTokenNeed(pool: Pool, upperTick: number, tokenX: TokenItemType, tokenY: TokenItemType): { tokenNeed: TokenItemType, isTokenX: boolean } {
  const isTokenX = upperTick >= pool.current_tick_index;
  return {
    tokenNeed: isTokenX ? tokenX : tokenY,
    isTokenX
  };
}
  1. Extract the route finding and simulation logic into a separate method:
private async findAndSimulateRoute(tokenIn: TokenItemType, tokenNeed: TokenItemType, amountIn: string, poolKey: PoolKey, pool: Pool): Promise<{ actualReceive: SmartRouteResponse, updatedPool: Pool }> {
  const actualReceive = await this.findRoute({
    sourceAsset: tokenIn,
    destAsset: tokenNeed,
    amount: BigInt(amountIn)
  });

  const routes: ActionRoute[] = extractOraidexV3Actions(actualReceive.routes);
  const updatedPool = await this.simulateSwapOffChainForRoute(routes, poolKey, { ...pool });

  return { actualReceive, updatedPool };
}
  1. Use these extracted methods in the main processZapInWithSingleSide method to simplify its structure.

These refactorings will make the method easier to understand and maintain.


Line range hint 284-488: Refactor processZapInPositionLiquidity for improved maintainability

The processZapInPositionLiquidity method is comprehensive and handles multiple scenarios for zap-in operations. However, its length and complexity make it challenging to understand and maintain.

Consider breaking down this method into smaller, more focused methods:

  1. Extract the out-of-range handling:
private async handleOutOfRangeZapIn(params: ZapInParams): Promise<ZapInLiquidityResponse> {
  // Logic for handling out-of-range zap-in
}
  1. Extract the price and liquidity calculations:
private calculatePricesAndLiquidity(pool: Pool, tokenX: TokenItemType, tokenY: TokenItemType, tokenIn: TokenItemType, amountIn: string): CalculationResult {
  // Price and liquidity calculation logic
}
  1. Extract the route finding and simulation:
private async findAndSimulateRoutes(tokenIn: TokenItemType, tokenX: TokenItemType, tokenY: TokenItemType, amountInToX: bigint, amountInToY: bigint): RouteSimulationResult {
  // Route finding and simulation logic
}
  1. Use these extracted methods in the main processZapInPositionLiquidity method:
public async processZapInPositionLiquidity(params: ZapInParams): Promise<ZapInLiquidityResponse> {
  // Handle out-of-range case
  if (params.lowerTick >= params.pool.pool.current_tick_index || params.upperTick < params.pool.pool.current_tick_index) {
    return this.handleOutOfRangeZapIn(params);
  }

  // Calculate prices and liquidity
  const calculationResult = this.calculatePricesAndLiquidity(params.pool.pool, params.tokenX, params.tokenY, params.tokenIn, params.amountIn);

  // Find and simulate routes
  const routeSimulationResult = await this.findAndSimulateRoutes(params.tokenIn, params.tokenX, params.tokenY, calculationResult.amountInToX, calculationResult.amountInToY);

  // Process results and return response
  // ...
}

This refactoring will improve the method's readability and maintainability by breaking it down into more manageable pieces.


Line range hint 492-542: Improve robustness of token finding in processZapOutPositionLiquidity

The processZapOutPositionLiquidity method is well-structured and effectively uses helper functions. However, there's a potential issue with finding tokens by address on lines 526 and 531:

sourceAsset: oraichainTokens.find((t) => extractAddress(t) === pool.pool_key.token_x) as TokenItemType,

This approach assumes that the token will always be found, which may not always be the case.

Consider adding a null check and error handling for cases where the token is not found:

private findTokenByAddress(address: string): TokenItemType {
  const token = oraichainTokens.find((t) => extractAddress(t) === address);
  if (!token) {
    throw new Error(`Token not found for address: ${address}`);
  }
  return token;
}

// In processZapOutPositionLiquidity:
const [xRouteInfo, yRouteInfo] = await this.findZapRoutes([
  {
    sourceAsset: this.findTokenByAddress(pool.pool_key.token_x),
    destAsset: tokenOut,
    amount: amountX
  },
  {
    sourceAsset: this.findTokenByAddress(pool.pool_key.token_y),
    destAsset: tokenOut,
    amount: amountY
  }
]);

This change will make the code more robust by explicitly handling cases where a token might not be found, preventing potential runtime errors.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 54a7cbc and 1b08c7e.

📒 Files selected for processing (2)
  • packages/oraiswap-v3/package.json (2 hunks)
  • packages/oraiswap-v3/src/zap-consumer.ts (9 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/oraiswap-v3/package.json
🧰 Additional context used
🪛 Biome
packages/oraiswap-v3/src/zap-consumer.ts

[error] 147-147: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)

🔇 Additional comments (4)
packages/oraiswap-v3/src/zap-consumer.ts (4)

35-53: Great addition of comprehensive class documentation!

The detailed documentation for the ZapConsumer class and its methods significantly improves code readability and maintainability. It provides a clear overview of the class's purpose and the functionality of each method, which will be helpful for developers working with this code in the future.


129-136: Efficient implementation of findZapRoutes

The findZapRoutes method is well-implemented, using Promise.all for efficient parallel execution of route finding. This approach optimizes performance when finding multiple routes simultaneously.


Line range hint 139-173: Improved precision and simulation accuracy in simulateSwapOffChain

The updates to the simulateSwapOffChain method are commendable:

  1. The use of BigInt for calculations improves precision, which is crucial for financial operations.
  2. The new logic for handling liquidity changes enhances the simulation accuracy.

These improvements will lead to more reliable swap simulations.

🧰 Tools
🪛 Biome

[error] 147-147: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


Line range hint 1-542: Overall assessment of ZapConsumer class updates

The changes to the ZapConsumer class significantly enhance its functionality, particularly in handling zap operations and route finding. The additions of methods like findRoute, findZapRoutes, and simulateSwapOffChainForRoute provide more granular control over the zap process.

Key improvements:

  1. Better error handling and more precise calculations using BigInt.
  2. Comprehensive documentation added to the class and its methods.
  3. New methods for handling various zap scenarios.

Areas for further improvement:

  1. Some methods, particularly processZapInPositionLiquidity, are quite complex and could benefit from further refactoring.
  2. Consider adding more robust error handling, especially when dealing with token lookups.
  3. Be cautious of potential stack overflow in recursive calls within findRoute.

Overall, these changes represent a significant improvement to the ZapConsumer class, enhancing its capabilities and making it more versatile for handling various zap operations.

packages/oraiswap-v3/src/zap-consumer.ts Outdated Show resolved Hide resolved
packages/oraiswap-v3/src/zap-consumer.ts Outdated Show resolved Hide resolved
Copy link

@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: 14

🧹 Outside diff range and nitpick comments (4)
packages/oraiswap-v3/tests/wasm-bindgen.spec.ts (3)

345-348: Add clarifying comment to getGlobalMaxSqrtPrice test

The test for getGlobalMaxSqrtPrice correctly checks its equality with getMaxSqrtPrice(1). However, it would be helpful to add a comment explaining the relationship between these two functions and why they are expected to be equal. This will make the test more self-documenting and easier for other developers to understand.

Example:

it("getGlobalMaxSqrtPrice", () => {
  // getGlobalMaxSqrtPrice should return the maximum sqrt price
  // which is equivalent to getMaxSqrtPrice with a tick spacing of 1
  const res = getGlobalMaxSqrtPrice();
  expect(res).toEqual(getMaxSqrtPrice(1));
});

350-373: Add explanatory comments to constant value tests

The tests for getTickSearchRange, getMaxChunk, getMaxTickCross, getMaxPoolKeysReturned, and getMaxPoolPairsReturned correctly check for specific constant values. To improve the readability and maintainability of these tests, consider adding brief comments explaining the significance of each constant value.

Example:

it("getTickSearchRange", () => {
  // The tick search range is expected to be 256 ticks
  // This value determines the range of ticks to search when finding the next initialized tick
  const res = getTickSearchRange();
  expect(res).toEqual(256);
});

it.each<[number]>([[1]])("getMaxChunk", (tickSpacing) => {
  // The maximum chunk value is 6931 for a tick spacing of 1
  // This represents the maximum number of chunks in the bitmap for the given tick spacing
  const res = getMaxChunk(tickSpacing);
  expect(res).toEqual(6931);
});

// Add similar comments for the other constant value tests

These comments will help other developers understand the purpose and importance of these constants in the context of the protocol.


435-445: Add explanatory comment to isTokenX test

The test for isTokenX includes multiple scenarios with different token address formats, which is good. To improve the clarity of this test, consider adding a comment explaining the different token address formats and their significance in determining the token order.

Example:

it.each<[string, string, boolean]>([
  // Test cases with explanatory comments
  // Case 1: Standard address vs. native token symbol
  ["orai1zyvk3n9r8sax4xvqph97pxuhduqqsqwq6dwzj2", "orai", false],
  // Case 2: Standard address vs. factory token address
  ["orai1zyvk3n9r8sax4xvqph97pxuhduqqsqwq6dwzj2", "factory/abc/ton", false],
  // Case 3: Native token symbol vs. standard address
  ["orai", "orai1zyvk3n9r8sax4xvqph97pxuhduqqsqwq6dwzj2", true]
])(
  "isTokenX",
  (tokenX, tokenY, expected) => {
    // isTokenX determines if tokenX comes before tokenY in the canonical ordering
    // This ordering is crucial for consistent pool creation and interaction
    const res = isTokenX(tokenX, tokenY);
    expect(res).toEqual(expected);
  }
);

This additional context will help other developers understand the purpose of the isTokenX function and the significance of different token address formats in the protocol.

packages/oraiswap-v3/src/main.ts (1)

45-55: Remove timing code around commented-out function

The console.time("processZapInPositionLiquidity"); and console.timeEnd("processZapInPositionLiquidity"); calls are surrounding a function that is currently commented out. This results in timing an empty block of code, which may be misleading.

Consider commenting out or removing the timing calls, or uncommenting the function if you plan to use it.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 646d1f6 and 47ab38b.

📒 Files selected for processing (6)
  • packages/oraiswap-v3/package.json (2 hunks)
  • packages/oraiswap-v3/src/helpers.ts (2 hunks)
  • packages/oraiswap-v3/src/main.ts (2 hunks)
  • packages/oraiswap-v3/src/types.ts (2 hunks)
  • packages/oraiswap-v3/src/zap-consumer.ts (9 hunks)
  • packages/oraiswap-v3/tests/wasm-bindgen.spec.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/oraiswap-v3/package.json
  • packages/oraiswap-v3/src/helpers.ts
  • packages/oraiswap-v3/src/types.ts
  • packages/oraiswap-v3/src/zap-consumer.ts
🔇 Additional comments (2)
packages/oraiswap-v3/tests/wasm-bindgen.spec.ts (1)

533-548: Improve test coverage for getTickAtSqrtPrice and checkTickToSqrtPriceRelationship

Both the getTickAtSqrtPrice and checkTickToSqrtPriceRelationship tests have two scenarios each, which is a good start. However, to ensure these functions work correctly across a wider range of inputs, consider adding more test cases:

For getTickAtSqrtPrice:

  1. Add cases with different tick spacings
  2. Include edge cases (minimum and maximum sqrt prices)
  3. Test with sqrt prices that correspond to tick boundaries
it.each<[bigint, number,

</blockquote></details>
<details>
<summary>packages/oraiswap-v3/src/main.ts (1)</summary><blockquote>

`31-33`: **Initialization of 'tokenIn', 'pool', and 'poolKey' is correct**

The variables `tokenIn`, `pool`, and `poolKey` are correctly initialized, setting up the necessary components for further processing.

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment on lines +32 to +109
describe("wasm bind gen tests", () => {
it.each<
[
{
currentSqrtPrice: bigint;
targetSqrtPrice: bigint;
liquidity: bigint;
amount: bigint;
byAmountIn: boolean;
fee: bigint;
},
{
next_sqrt_price: bigint;
amount_in: bigint;
amount_out: bigint;
fee_amount: bigint;
}
]
>([
[
{
currentSqrtPrice: 10n ** 24n,
targetSqrtPrice: 1004987562112089027021926n,
liquidity: 2000n * 10n ** 6n,
amount: 1n,
byAmountIn: true,
fee: 6n * 10n ** 4n
},
{
next_sqrt_price: 10n ** 24n,
amount_in: 0n,
amount_out: 0n,
fee_amount: 1n
}
],
[
{
currentSqrtPrice: 10n ** 24n,
targetSqrtPrice: 1004987562112089027021926n,
liquidity: 2000n * 10n ** 6n,
amount: 20n,
byAmountIn: true,
fee: 6n * 10n ** 4n
},
{
next_sqrt_price: 1004987562112089027021926n,
amount_in: 10n,
amount_out: 9n,
fee_amount: 1n
}
],
[
{
currentSqrtPrice: 10n ** 24n,
targetSqrtPrice: 1004987562112089027021926n,
liquidity: 2000n * 10n ** 6n,
amount: 20n,
byAmountIn: false,
fee: 6n * 10n ** 4n
},
{
next_sqrt_price: 1004987562112089027021926n,
amount_in: 10n,
amount_out: 9n,
fee_amount: 1n
}
]
])("compute swap step", (input, output) => {
const res = computeSwapStep(
input.currentSqrtPrice,
input.targetSqrtPrice,
input.liquidity,
input.amount,
input.byAmountIn,
input.fee
);
expect(res).toMatchObject(output);
});
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding more test cases for edge scenarios

The current test cases for computeSwapStep provide a good starting point. However, to ensure robust testing, consider adding more test cases that cover edge scenarios such as:

  1. Extreme liquidity values (very low or very high)
  2. Cases where the target price is equal to the current price
  3. Scenarios with zero amounts or fees

This will help ensure the function behaves correctly under a wider range of conditions.

Comment on lines +111 to +177
it.each<
[
{
sqrtPriceA: bigint;
sqrtPriceB: bigint;
liquidity: bigint;
roundUp: boolean;
},
bigint
]
>([
[
{
sqrtPriceA: 10n ** 24n,
sqrtPriceB: 10n ** 24n,
liquidity: 0n,
roundUp: false
},
0n
],
[
{
sqrtPriceA: 10n ** 24n,
sqrtPriceB: 2n * 10n ** 24n,
liquidity: 2n * 10n ** 6n,
roundUp: false
},
1n
]
])("get delta x", (input, output) => {
const res = getDeltaX(input.sqrtPriceA, input.sqrtPriceB, input.liquidity, input.roundUp);
expect(res).toEqual(output);
});

it.each<
[
{
sqrtPriceA: bigint;
sqrtPriceB: bigint;
liquidity: bigint;
roundUp: boolean;
},
bigint
]
>([
[
{
sqrtPriceA: 10n ** 24n,
sqrtPriceB: 10n ** 24n,
liquidity: 0n,
roundUp: false
},
0n
],
[
{
sqrtPriceA: 10n ** 24n,
sqrtPriceB: 2n * 10n ** 24n,
liquidity: 2n * 10n ** 6n,
roundUp: false
},
2n
]
])("get delta y", (input, output) => {
const res = getDeltaY(input.sqrtPriceA, input.sqrtPriceB, input.liquidity, input.roundUp);
expect(res).toEqual(output);
});
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance test coverage for getDeltaX and getDeltaY functions

The current test cases for getDeltaX and getDeltaY cover basic scenarios. To improve the robustness of these tests, consider adding more test cases that include:

  1. Extreme price differences
  2. Very large liquidity values
  3. Cases where sqrtPriceA > sqrtPriceB and vice versa
  4. Edge cases where the result might be close to overflowing

This will help ensure these functions behave correctly across a wider range of inputs.

Comment on lines +179 to +227
it.each<
[
{
sqrtPrice: bigint;
liquidity: bigint;
amount: bigint;
xToY: boolean;
},
bigint
]
>([
[
{
sqrtPrice: 10n ** 24n,
liquidity: 10n ** 6n,
amount: 1n,
xToY: true
},
5n * 10n ** 23n
]
])("get next sqrt price from input", (input, output) => {
const res = getNextSqrtPriceFromInput(input.sqrtPrice, input.liquidity, input.amount, input.xToY);
expect(res).toEqual(output);
});

it.each<
[
{
sqrtPrice: bigint;
liquidity: bigint;
amount: bigint;
xToY: boolean;
},
bigint
]
>([
[
{
sqrtPrice: 10n ** 24n,
liquidity: 2n * 10n ** 6n,
amount: 1n,
xToY: true
},
5n * 10n ** 23n
]
])("get next sqrt price from output", (input, output) => {
const res = getNextSqrtPriceFromOutput(input.sqrtPrice, input.liquidity, input.amount, input.xToY);
expect(res).toEqual(output);
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Significantly increase test coverage for price calculation functions

The current test cases for getNextSqrtPriceFromInput and getNextSqrtPriceFromOutput only include one scenario each. This is insufficient for functions that likely have complex behavior. Please add more test cases that cover:

  1. Both x-to-y and y-to-x directions
  2. Various liquidity levels (low, medium, high)
  3. Edge cases with very small or very large amounts
  4. Scenarios where the price doesn't change
  5. Cases that might approach the limits of BigInt

Comprehensive testing of these functions is crucial as they are likely core to the swap mechanism.

Comment on lines +229 to +277
it.each<
[
{
sqrtPrice: bigint;
liquidity: bigint;
amount: bigint;
xToY: boolean;
},
bigint
]
>([
[
{
sqrtPrice: 10n ** 24n,
liquidity: 10n ** 6n,
amount: 1n,
xToY: true
},
5n * 10n ** 23n
]
])("getNextSqrtPriceXUp", (input, output) => {
const res = getNextSqrtPriceXUp(input.sqrtPrice, input.liquidity, input.amount, input.xToY);
expect(res).toEqual(output);
});

it.each<
[
{
sqrtPrice: bigint;
liquidity: bigint;
amount: bigint;
xToY: boolean;
},
bigint
]
>([
[
{
sqrtPrice: 10n ** 24n,
liquidity: 10n ** 6n,
amount: 1n,
xToY: true
},
2n * 10n ** 24n
]
])("getNextSqrtPriceYDown", (input, output) => {
const res = getNextSqrtPriceYDown(input.sqrtPrice, input.liquidity, input.amount, input.xToY);
expect(res).toEqual(output);
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Expand test coverage for getNextSqrtPriceXUp and getNextSqrtPriceYDown

The current test cases for getNextSqrtPriceXUp and getNextSqrtPriceYDown only include one scenario each. To ensure these functions work correctly across various situations, please add more test cases that cover:

  1. Both x-to-y and y-to-x directions
  2. Different liquidity levels
  3. Edge cases with minimal price changes
  4. Scenarios with large price changes
  5. Cases where the amount is very small or very large

Thorough testing of these functions is important as they likely play a crucial role in price calculations during swaps.

Comment on lines +279 to +313
it.each<
[
{
amount: bigint;
startSqrtPrice: bigint;
liquidity: bigint;
fee: bigint;
byAmountIn: boolean;
xToY: boolean;
},
boolean
]
>([
[
{
amount: 340282366920938463463374607431768211455n,
startSqrtPrice: 65535383934512647000000000000n,
liquidity: 0n,
fee: 1000000000000n,
byAmountIn: false,
xToY: false
},
true
]
])("isEnoughAmountToChangePrice", (input, output) => {
const res = isEnoughAmountToChangePrice(
input.amount,
input.startSqrtPrice,
input.liquidity,
input.fee,
input.byAmountIn,
input.xToY
);
expect(res).toEqual(output);
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Improve test coverage for isEnoughAmountToChangePrice

The current test case for isEnoughAmountToChangePrice only covers one scenario with the maximum BigInt value. While testing with extreme values is good, it's important to have a more comprehensive set of test cases. Consider adding tests that cover:

  1. Both true and false outcomes
  2. Various combinations of amount, liquidity, and fee values
  3. Edge cases where the amount is just enough or not quite enough to change the price
  4. Scenarios for both byAmountIn true and false
  5. Cases for both xToY true and false

This will ensure the function behaves correctly across different scenarios.

Comment on lines +375 to +433
it.each<
[
{
lower_tick_index: number;
lower_tick_fee_growth_outside_x: bigint;
lower_tick_fee_growth_outside_y: bigint;
upper_tick_index: number;
upper_tick_fee_growth_outside_x: bigint;
upper_tick_fee_growth_outside_y: bigint;
pool_current_tick_index: number;
pool_fee_growth_global_x: bigint;
pool_fee_growth_global_y: bigint;
position_fee_growth_inside_x: bigint;
position_fee_growth_inside_y: bigint;
position_liquidity: bigint;
},
{
x: bigint;
y: bigint;
}
]
>([
[
{
lower_tick_index: -24300,
lower_tick_fee_growth_outside_x: 30566305483401951213259107n,
lower_tick_fee_growth_outside_y: 3090193022255581920240205n,
upper_tick_index: -23900,
upper_tick_fee_growth_outside_x: 0n,
upper_tick_fee_growth_outside_y: 0n,
pool_current_tick_index: -24200,
pool_fee_growth_global_x: 34015516218039756676745948n,
pool_fee_growth_global_y: 3360651078360214052633596n,
position_fee_growth_inside_x: 1856777541687032563592895n,
position_fee_growth_inside_y: 164732622916975273061067n,
position_liquidity: 7823906503624803n
},
{
x: 1245904n,
y: 82718n
}
]
])("calculateFee", (input, output) => {
const res = calculateFee(
input.lower_tick_index,
input.lower_tick_fee_growth_outside_x,
input.lower_tick_fee_growth_outside_y,
input.upper_tick_index,
input.upper_tick_fee_growth_outside_x,
input.upper_tick_fee_growth_outside_y,
input.pool_current_tick_index,
input.pool_fee_growth_global_x,
input.pool_fee_growth_global_y,
input.position_fee_growth_inside_x,
input.position_fee_growth_inside_y,
input.position_liquidity
);
expect(res).toMatchObject(output);
});
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance test coverage for calculateFee function

The current test for calculateFee includes a single, complex scenario. While this is a good start, for a function with this many parameters and potential edge cases, it would be beneficial to include more test cases. Consider adding tests that cover:

  1. Different combinations of tick indices (lower, upper, and current)
  2. Various fee growth values, including edge cases (very small and very large values)
  3. Different liquidity amounts
  4. Scenarios where the current tick is outside the range (below lower and above upper)
  5. Cases where fee growth values are zero

Example:

it.each<
  [
    {
      lower_tick_index: number;
      lower_tick_fee_growth_outside_x: bigint;
      lower_tick_fee_growth_outside_y: bigint;
      upper_tick_index: number;
      upper_tick_fee_growth_outside_x: bigint;
      upper_tick_fee_growth_outside_y: bigint;
      pool_current_tick_index: number;
      pool_fee_growth_global_x: bigint;
      pool_fee_growth_global_y: bigint;
      position_fee_growth_inside_x: bigint;
      position_fee_growth_inside_y: bigint;
      position_liquidity: bigint;
    },
    {
      x: bigint;
      y: bigint;
    }
  ]
>([
  // Existing test case
  [
    {
      lower_tick_index: -24300,
      lower_tick_fee_growth_outside_x: 30566305483401951213259107n,
      lower_tick_fee_growth_outside_y: 3090193022255581920240205n,
      upper_tick_index: -23900,
      upper_tick_fee_growth_outside_x: 0n,
      upper_tick_fee_growth_outside_y: 0n,
      pool_current_tick_index: -24200,
      pool_fee_growth_global_x: 34015516218039756676745948n,
      pool_fee_growth_global_y: 3360651078360214052633596n,
      position_fee_growth_inside_x: 1856777541687032563592895n,
      position_fee_growth_inside_y: 164732622916975273061067n,
      position_liquidity: 7823906503624803n
    },
    {
      x: 1245904n,
      y: 82718n
    }
  ],
  // Add more test cases here, covering different scenarios
])("calculateFee", (input, output) => {
  const res = calculateFee(
    input.lower_tick_index,
    input.lower_tick_fee_growth_outside_x,
    input.lower_tick_fee_growth_outside_y,
    input.upper_tick_index,
    input.upper_tick_fee_growth_outside_x,
    input.upper_tick_fee_growth_outside_y,
    input.pool_current_tick_index,
    input.pool_fee_growth_global_x,
    input.pool_fee_growth_global_y,
    input.position_fee_growth_inside_x,
    input.position_fee_growth_inside_y,
    input.position_liquidity
  );
  expect(res).toMatchObject(output);
});

This will provide more comprehensive testing for the calculateFee function and help ensure it behaves correctly across a wide range of inputs.

Comment on lines +447 to +453
it.each<[number, number, bigint, boolean]>([])(
"checkTickToSqrtPriceRelationship",
(tick, tickSpacing, sqrtPrice, expected) => {
const res = checkTickToSqrtPriceRelationship(tick, tickSpacing, sqrtPrice);
expect(res).toEqual(expected);
}
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Implement test cases for checkTickToSqrtPriceRelationship

The current test for checkTickToSqrtPriceRelationship is set up correctly, but it lacks any actual test cases. This means the function is not being tested at all. To properly test this function:

  1. Add multiple test cases to cover various scenarios.
  2. Include cases for both true and false outcomes.
  3. Test with different tick spacings.
  4. Include edge cases if applicable.

Example:

it.each<[number, number, bigint, boolean]>([
  // tick, tickSpacing, sqrtPrice, expected
  [0, 1, 1000000000000000000000000n, true],
  [1, 1, 1000050000000000000000000n, true],
  [-1, 1, 999950000000000000000000n, true],
  [0, 2, 1000000000000000000000000n, true],
  [1, 2, 1000100000000000000000000n, false],
  // Add more test cases to cover different scenarios
])("checkTickToSqrtPriceRelationship", (tick, tickSpacing, sqrtPrice, expected) => {
  const res = checkTickToSqrtPriceRelationship(tick, tickSpacing, sqrtPrice);
  expect(res).toEqual(expected);
});

Implementing these test cases will ensure that the checkTickToSqrtPriceRelationship function is properly tested and behaves as expected across different inputs.

Comment on lines +455 to +492
it.each<
[
{
x: bigint;
lower_tick: number;
upper_tick: number;
current_sqrt_price: bigint;
rounding_up: boolean;
},
{
amount: bigint;
l: bigint;
}
]
>([
[
{
x: 1000000n,
lower_tick: -10,
upper_tick: 10,
current_sqrt_price: 10n ** 24n,
rounding_up: true
},
{
amount: 1000000n,
l: 2000600039999999n
}
]
])("getLiquidityByX", (input, output) => {
const res = getLiquidityByX(
input.x,
input.lower_tick,
input.upper_tick,
input.current_sqrt_price,
input.rounding_up
);
expect(res).toMatchObject(output);
});
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Expand test coverage for getLiquidityByX function

The current test for getLiquidityByX includes a single scenario, which is a good start but may not be sufficient for a function with multiple parameters and potential edge cases. To improve the test coverage:

  1. Add more test cases with different combinations of input parameters.
  2. Include edge cases such as:
    • Minimum and maximum possible tick values
    • Very small and very large x values
    • Cases where lower_tick == upper_tick
    • Different current_sqrt_price values (below range, within range, above range)
  3. Test both rounding_up true and false scenarios

Example:

it.each<
  [
    {
      x: bigint;
      lower_tick: number;
      upper_tick: number;
      current_sqrt_price: bigint;
      rounding_up: boolean;
    },
    {
      amount: bigint;
      l: bigint;
    }
  ]
>([
  // Existing test case
  [
    {
      x: 1000000n,
      lower_tick: -10,
      upper_tick: 10,
      current_sqrt_price: 10n ** 24n,
      rounding_up: true
    },
    {
      amount: 1000000n,
      l: 2000600039999999n
    }
  ],
  // Additional test cases
  [
    {
      x: 1n,
      lower_tick: -100,
      upper_tick: 100,
      current_sqrt_price: 10n ** 24n,
      rounding_up: false
    },
    {
      amount: 1n,
      l: /* expected liquidity */
    }
  ],
  // Add more test cases here
])("getLiquidityByX", (input, output) => {
  const res = getLiquidityByX(
    input.x,
    input.lower_tick,
    input.upper_tick,
    input.current_sqrt_price,
    input.rounding_up
  );
  expect(res).toMatchObject(output);
});

By adding these additional test cases, you'll ensure that getLiquidityByX functions correctly across a wide range of inputs and edge cases.

Comment on lines +494 to +531
it.each<
[
{
y: bigint;
lower_tick: number;
upper_tick: number;
current_sqrt_price: bigint;
rounding_up: boolean;
},
{
amount: bigint;
l: bigint;
}
]
>([
[
{
y: 1000000n,
lower_tick: -10,
upper_tick: 10,
current_sqrt_price: 10n ** 24n,
rounding_up: true
},
{
amount: 1000000n,
l: 2000600039969988n
}
]
])("getLiquidityByY", (input, output) => {
const res = getLiquidityByY(
input.y,
input.lower_tick,
input.upper_tick,
input.current_sqrt_price,
input.rounding_up
);
expect(res).toMatchObject(output);
});
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance test coverage for getLiquidityByY function

The current test for getLiquidityByY includes only one scenario, which is insufficient for a function with multiple parameters and potential edge cases. To improve the test coverage:

  1. Add more test cases with different combinations of input parameters.
  2. Include edge cases such as:
    • Minimum and maximum possible tick values
    • Very small and very large y values
    • Cases where lower_tick == upper_tick
    • Different current_sqrt_price values (below range, within range, above range)
  3. Test both rounding_up true and false scenarios

Example:

it.each<
  [
    {
      y: bigint;
      lower_tick: number;
      upper_tick: number;
      current_sqrt_price: bigint;
      rounding_up: boolean;
    },
    {
      amount: bigint;
      l: bigint;
    }
  ]
>([
  // Existing test case
  [
    {
      y: 1000000n,
      lower_tick: -10,
      upper_tick: 10,
      current_sqrt_price: 10n ** 24n,
      rounding_up: true
    },
    {
      amount: 1000000n,
      l: 2000600039969988n
    }
  ],
  // Additional test cases
  [
    {
      y: 1n,
      lower_tick: -100,
      upper_tick: 100,
      current_sqrt_price: 10n ** 24n,
      rounding_up: false
    },
    {
      amount: 1n,
      l: /* expected liquidity */
    }
  ],
  // Add more test cases here
])("getLiquidityByY", (input, output) => {
  const res = getLiquidityByY(
    input.y,
    input.lower_tick,
    input.upper_tick,
    input.current_sqrt_price,
    input.rounding_up
  );
  expect(res).toMatchObject(output);
});

By adding these additional test cases, you'll ensure that getLiquidityByY functions correctly across a wide range of inputs and edge cases.

Comment on lines 46 to 54
// const res = await zapper.processZapInPositionLiquidity({
// pool: poolInfo,
// tokenIn: tokenIn as TokenItemType,
// amountIn: (10 ** tokenIn.decimals).toString(),
// lowerTick: currentTick - tickSpacing * 3,
// upperTick: currentTick + tickSpacing * 3,
// tokenX: oraichainTokens.find((t) => extractAddress(t) === poolKey.token_x) as TokenItemType,
// tokenY: oraichainTokens.find((t) => extractAddress(t) === poolKey.token_y) as TokenItemType,
// });
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure 'poolInfo' is defined before use in 'processZapInPositionLiquidity'

The function call to zapper.processZapInPositionLiquidity uses poolInfo, but poolInfo is not defined in the current scope. This will cause a reference error when the code is executed.

Apply this diff to define poolInfo before using it:

+  const poolInfo = await zapper.handler.getPool(poolKey);
   const res = await zapper.processZapInPositionLiquidity({
     pool: poolInfo,

Committable suggestion was skipped due to low confidence.

Copy link

@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: 8

🧹 Outside diff range and nitpick comments (3)
packages/contracts-sdk/package.json (1)

3-3: Version bump approved.

The package version has been correctly updated from 1.0.52 to 1.0.53-beta.1, indicating a new beta release. This change follows semantic versioning practices.

Remember to update the CHANGELOG.md file (if one exists) to document the changes introduced in this beta version. This helps users understand what new features or fixes they can expect in this release.

packages/contracts-sdk/src/index.ts (1)

35-36: LGTM! Consider grouping related exports.

The new export statements for IncentivesFundManager are consistent with the existing pattern in the file and expand the SDK's functionality. Good job!

For improved readability and maintainability, consider grouping related exports together. You could move these new exports next to other similar modules or create a new section for fund management related exports if there are more to come in the future.

packages/contracts-sdk/src/IncentivesFundManager.client.ts (1)

14-29: Enhance Documentation with JSDoc Comments

To improve maintainability and provide better context for other developers, consider adding JSDoc comments to your classes and methods. Documenting parameter types, return types, and method purposes can greatly aid in understanding and using the code effectively.

Also applies to: 48-90

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between f524f05 and 835a928.

📒 Files selected for processing (4)
  • packages/contracts-sdk/package.json (1 hunks)
  • packages/contracts-sdk/src/IncentivesFundManager.client.ts (1 hunks)
  • packages/contracts-sdk/src/IncentivesFundManager.types.ts (1 hunks)
  • packages/contracts-sdk/src/index.ts (1 hunks)
🧰 Additional context used
🪛 Biome
packages/contracts-sdk/src/IncentivesFundManager.types.ts

[error] 34-34: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)


[error] 32-32: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

🔇 Additional comments (8)
packages/contracts-sdk/src/IncentivesFundManager.types.ts (7)

1-1: LGTM: Clear and concise type alias for addresses.

The Addr type alias is well-defined and follows good practices for improving code readability and maintainability.


2-5: LGTM: Well-structured instantiation message interface.

The InstantiateMsg interface is properly defined with clear property types. The optional owner property is correctly typed as Addr | null.


6-16: LGTM: Well-structured execute message type.

The ExecuteMsg type is properly defined as a union type, representing different possible message structures. The use of optional properties with Addr | null type in the update_config variant is correct and follows best practices.


17-17: LGTM: Appropriate type alias for large integers.

The Uint128 type alias as a string is a good practice for representing large integers in blockchain contexts, improving code clarity and type safety.


18-26: LGTM: Well-structured asset information type.

The AssetInfo type is properly defined as a union type, representing different asset types (token and native token). This structure allows for clear distinction between asset types and follows good practices for type definitions in TypeScript.


27-30: LGTM: Clear and concise asset interface.

The Asset interface is well-defined, combining the amount (of type Uint128) with the info (of type AssetInfo). This structure provides a complete representation of an asset.


35-38: LGTM: Well-defined configuration response interface.

The ConfigResponse interface is properly structured, clearly defining the expected properties of a configuration response. The use of the Addr type for both properties ensures type consistency.

packages/contracts-sdk/src/IncentivesFundManager.client.ts (1)

1-5: Note on Auto-Generated File

This file is auto-generated by @oraichain/[email protected]. Please refrain from manually modifying it. If changes are necessary, update the source JSONSchema file and regenerate this file to ensure consistency and maintainability.

Comment on lines +31 to +33
export type QueryMsg = {
config: {};
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider refining the QueryMsg type definition.

The current definition of QueryMsg uses an empty object {} as a type, which is discouraged. Consider refining this type to be more explicit about its structure.

Here's a suggested improvement:

export type QueryMsg = {
  config: Record<string, never>;
};

This change maintains the same functionality while addressing the static analysis warning about using {} as a type.

🧰 Tools
🪛 Biome

[error] 32-32: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

export type QueryMsg = {
config: {};
};
export interface MigrateMsg {}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refine the MigrateMsg definition.

The MigrateMsg is currently defined as an empty interface, which is equivalent to {}. This has been flagged by the static analysis tool.

Consider changing it to a type alias if no properties are needed:

export type MigrateMsg = Record<string, never>;

This change maintains the same functionality while addressing the static analysis warning about empty interfaces.

🧰 Tools
🪛 Biome

[error] 34-34: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

Comment on lines +21 to +22
this.config = this.config.bind(this);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid Unnecessary Binding of Methods

Since you're using arrow functions for your methods, explicit binding in the constructor is unnecessary. Arrow functions lexically bind this, so you can safely remove these bindings to simplify the constructor.

Apply this diff to remove the unnecessary bindings:

- this.config = this.config.bind(this);
- this.updateConfig = this.updateConfig.bind(this);
- this.sendFund = this.sendFund.bind(this);

Also applies to: 58-59

Comment on lines +24 to +28
config = async (): Promise<ConfigResponse> => {
return this.client.queryContractSmart(this.contractAddress, {
config: {}
});
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add Error Handling in the config Method

The config method performs a smart contract query but lacks error handling. To enhance robustness, consider wrapping the query in a try-catch block to handle potential exceptions, such as network issues or unexpected responses.

Apply this diff to implement error handling:

config = async (): Promise<ConfigResponse> => {
+  try {
    return this.client.queryContractSmart(this.contractAddress, {
      config: {}
    });
+  } catch (error) {
+    // Handle the error appropriately
+    throw new Error(`Failed to fetch config: ${error.message}`);
+  }
};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
config = async (): Promise<ConfigResponse> => {
return this.client.queryContractSmart(this.contractAddress, {
config: {}
});
};
config = async (): Promise<ConfigResponse> => {
try {
return this.client.queryContractSmart(this.contractAddress, {
config: {}
});
} catch (error) {
// Handle the error appropriately
throw new Error(`Failed to fetch config: ${error.message}`);
}
};

Comment on lines +49 to +51
client: SigningCosmWasmClient;
sender: string;
contractAddress: string;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove Redundant Assignment of contractAddress

In the IncentivesFundManagerClient constructor, this.contractAddress is assigned twice—once in the superclass and again in the subclass. This redundancy is unnecessary and can be removed to streamline the code.

Apply this diff to eliminate the redundant assignment:

constructor(client: SigningCosmWasmClient, sender: string, contractAddress: string) {
  super(client, contractAddress);
  this.client = client;
  this.sender = sender;
- this.contractAddress = contractAddress;
  this.updateConfig = this.updateConfig.bind(this);
  this.sendFund = this.sendFund.bind(this);
}

Committable suggestion was skipped due to low confidence.

Comment on lines +83 to +89
return await this.client.execute(this.sender, this.contractAddress, {
send_fund: {
asset,
receiver
}
}, _fee, _memo, _funds);
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle Execution Errors in sendFund Method

Similar to updateConfig, the sendFund method should include error handling to manage potential execution errors. This ensures that any issues during the transaction are properly caught and communicated.

Apply this diff to add error handling:

sendFund = async ({
  asset,
  receiver
}: {
  asset: Asset;
  receiver: Addr;
}, _fee: number | StdFee | "auto" = "auto", _memo?: string, _funds?: Coin[]): Promise<ExecuteResult> => {
+  try {
    return await this.client.execute(this.sender, this.contractAddress, {
      send_fund: {
        asset,
        receiver
      }
    }, _fee, _memo, _funds);
+  } catch (error) {
+    // Handle the error appropriately
+    throw new Error(`Failed to execute sendFund: ${error.message}`);
+  }
};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return await this.client.execute(this.sender, this.contractAddress, {
send_fund: {
asset,
receiver
}
}, _fee, _memo, _funds);
};
sendFund = async ({
asset,
receiver
}: {
asset: Asset;
receiver: Addr;
}, _fee: number | StdFee | "auto" = "auto", _memo?: string, _funds?: Coin[]): Promise<ExecuteResult> => {
try {
return await this.client.execute(this.sender, this.contractAddress, {
send_fund: {
asset,
receiver
}
}, _fee, _memo, _funds);
} catch (error) {
// Handle the error appropriately
throw new Error(`Failed to execute sendFund: ${error.message}`);
}
};

Comment on lines +69 to +75
return await this.client.execute(this.sender, this.contractAddress, {
update_config: {
oraiswap_v3: oraiswapV3,
owner
}
}, _fee, _memo, _funds);
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle Execution Errors in updateConfig Method

The updateConfig method may encounter execution failures, such as insufficient funds or unauthorized access. Implement error handling to catch and manage these exceptions, providing informative feedback to the user or calling function.

Apply this diff to add error handling:

updateConfig = async ({
  oraiswapV3,
  owner
}: {
  oraiswapV3?: Addr;
  owner?: Addr;
}, _fee: number | StdFee | "auto" = "auto", _memo?: string, _funds?: Coin[]): Promise<ExecuteResult> => {
+  try {
    return await this.client.execute(this.sender, this.contractAddress, {
      update_config: {
        oraiswap_v3: oraiswapV3,
        owner
      }
    }, _fee, _memo, _funds);
+  } catch (error) {
+    // Handle the error appropriately
+    throw new Error(`Failed to execute updateConfig: ${error.message}`);
+  }
};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return await this.client.execute(this.sender, this.contractAddress, {
update_config: {
oraiswap_v3: oraiswapV3,
owner
}
}, _fee, _memo, _funds);
};
updateConfig = async ({
oraiswapV3,
owner
}: {
oraiswapV3?: Addr;
owner?: Addr;
}, _fee: number | StdFee | "auto" = "auto", _memo?: string, _funds?: Coin[]): Promise<ExecuteResult> => {
try {
return await this.client.execute(this.sender, this.contractAddress, {
update_config: {
oraiswap_v3: oraiswapV3,
owner
}
}, _fee, _memo, _funds);
} catch (error) {
// Handle the error appropriately
throw new Error(`Failed to execute updateConfig: ${error.message}`);
}
};

Comment on lines +30 to +39
export interface IncentivesFundManagerInterface extends IncentivesFundManagerReadOnlyInterface {
contractAddress: string;
sender: string;
updateConfig: ({
oraiswapV3,
owner
}: {
oraiswapV3?: Addr;
owner?: Addr;
}, _fee?: number | StdFee | "auto", _memo?: string, _funds?: Coin[]) => Promise<ExecuteResult>;
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Inconsistent Usage of oraiswapV3 Parameter Names

The parameter oraiswapV3 is inconsistently used as oraiswap_v3 in the following files:

  • packages/contracts-sdk/src/IncentivesFundManager.client.ts
  • packages/contracts-sdk/src/OraiswapMixedRouter.client.ts

Please update these instances to oraiswapV3 to maintain consistent naming conventions across interfaces and implementations.

🔗 Analysis chain

Verify Consistency of Parameter Naming

Ensure that parameter names are consistent across your interfaces and methods. For example, check that oraiswapV3 and owner are used uniformly throughout the codebase, adhering to naming conventions.

Run the following script to check for parameter naming consistency:

Also applies to: 62-68, 76-82

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistent usage of parameter names 'oraiswapV3' and 'owner'.

# Search for 'oraiswapV3' occurrences
rg --type ts 'oraiswapV3[^A-Za-z0-9_]'

# Search for 'owner' occurrences
rg --type ts 'owner[^A-Za-z0-9_]'

# Ensure that the parameter names match across interfaces and implementations.

Length of output: 29938

Copy link

@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: 1

🧹 Outside diff range and nitpick comments (4)
packages/contracts-sdk/src/OraiswapV3.types.ts (2)

1-1: LGTM. Consider adding a comment for clarity.

The addition of incentives_fund_manager to the InstantiateMsg interface is a good enhancement for managing incentives.

Consider adding a brief comment explaining the purpose of the incentives_fund_manager:

export interface InstantiateMsg {
  // Address of the manager responsible for handling incentives funds
  incentives_fund_manager: Addr;
  protocol_fee: Percentage;
}

Also applies to: 4-4


Line range hint 1-185: Consider adding documentation for the new incentives fund manager feature.

The additions related to the incentives fund manager are good enhancements to the contract's functionality. However, to improve maintainability and ease of use for other developers, consider adding more documentation.

Suggestions:

  1. Add a comment at the top of the file explaining the purpose of the incentives fund manager.
  2. If there's a README or documentation file for this contract, update it to include information about this new feature and how it should be used.

Example comment for the top of the file:

/**
 * @file OraiswapV3.types.ts
 * This file contains type definitions for the OraiswapV3 contract.
 * It includes support for an incentives fund manager, which is responsible for...
 * [Add a brief explanation of the incentives fund manager's role and how it's used]
 */
packages/contracts-sdk/src/OraiswapV3.client.ts (2)

248-252: Implementation of the new method

The incentivesFundManager method is correctly implemented in the OraiswapV3QueryClient class. It follows the established pattern for querying the smart contract.

However, to improve code consistency and maintainability, consider adding a JSDoc comment to describe the method's purpose and return type. For example:

/**
 * Queries the contract for the address of the incentives fund manager.
 * @returns {Promise<Addr>} The address of the incentives fund manager.
 */
incentivesFundManager = async (): Promise<Addr> => {
  // ... existing implementation ...
};

Line range hint 1-1024: Overall structure and impact

The addition of the incentivesFundManager method is well-integrated into the existing codebase. It follows the established patterns and conventions used throughout the file. The change appears to be part of expanding the functionality to interact with an incentives fund manager in the OraiswapV3 contract.

To ensure the change is fully integrated, consider the following:

  1. Update any relevant documentation or comments that describe the OraiswapV3ReadOnlyInterface to include this new method.
  2. If there are any test files associated with this client, make sure to add tests for the new incentivesFundManager method.
  3. Check if any other parts of the codebase need to be updated to use this new method where appropriate.
🧰 Tools
🪛 Biome

[error] 9-9: Do not shadow the global "Boolean" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 835a928 and fca1e4f.

📒 Files selected for processing (3)
  • packages/contracts-sdk/package.json (1 hunks)
  • packages/contracts-sdk/src/OraiswapV3.client.ts (3 hunks)
  • packages/contracts-sdk/src/OraiswapV3.types.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/contracts-sdk/package.json
🧰 Additional context used
🪛 Biome
packages/contracts-sdk/src/OraiswapV3.client.ts

[error] 9-9: Do not shadow the global "Boolean" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

packages/contracts-sdk/src/OraiswapV3.types.ts

[error] 185-185: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

🔇 Additional comments (3)
packages/contracts-sdk/src/OraiswapV3.client.ts (3)

14-14: New method added to the interface

The incentivesFundManager method has been added to the OraiswapV3ReadOnlyInterface. This addition is consistent with the interface's structure and naming conventions.


209-209: Method binding in the constructor

The new incentivesFundManager method is correctly bound to the class instance in the constructor, maintaining consistency with other methods.


9-9: Potential naming conflict with global Boolean

The static analysis tool flagged a potential issue with shadowing the global Boolean property. However, this is a false positive in this context. The Boolean type is correctly imported from the local types file and is not shadowing the global Boolean.

🧰 Tools
🪛 Biome

[error] 9-9: Do not shadow the global "Boolean" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

Comment on lines +184 to +185
} | {
incentives_fund_manager: {};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Approve the new query, but refine the type definition.

The addition of the incentives_fund_manager query is a good complement to the new instantiation parameter. However, the use of {} as a type is not recommended.

Replace {} with a more specific type or void to improve type safety:

export type QueryMsg = {
  // ... other queries ...
} | {
  incentives_fund_manager: void;
} | {
  // ... remaining queries ...
};

This change addresses the static analysis warning and makes the type definition more explicit.

🧰 Tools
🪛 Biome

[error] 185-185: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

Copy link

@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: 9

🧹 Outside diff range and nitpick comments (2)
packages/oraiswap-v3/tests/handler.spec.ts (1)

9-9: LGTM. Consider updating documentation.

The addition of deployIncentivesFundManager to the imports is appropriate given the new functionality.

Consider updating the documentation to reflect this new functionality if not already done.

packages/oraiswap-v3/src/helpers.ts (1)

570-571: Consider using precise decimal calculations for slippageMultiplier

The calculation of slippageMultiplier involves multiplying and dividing by large numbers to adjust for slippage:

const slippageMultiplier = BigInt(Math.floor((100 - slippage) * 1000));
message.minimumLiquidity = res.l ? (BigInt(res.l) * slippageMultiplier) / 100_000n : 0n;

This approach can lead to precision loss and might not accurately reflect the intended slippage adjustment. Consider using a precise decimal or big number library to handle decimal calculations more accurately.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between fca1e4f and dfa75cf.

⛔ Files ignored due to path filters (2)
  • packages/oraiswap-v3/tests/data/oraiswap-v3.wasm is excluded by !**/*.wasm
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (5)
  • packages/oraiswap-v3/package.json (2 hunks)
  • packages/oraiswap-v3/src/helpers.ts (3 hunks)
  • packages/oraiswap-v3/tests/handler.spec.ts (4 hunks)
  • packages/oraiswap-v3/tests/test-common.ts (2 hunks)
  • packages/oraiswap-v3/tests/zap-consumer.spec.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/oraiswap-v3/package.json
🔇 Additional comments (9)
packages/oraiswap-v3/tests/handler.spec.ts (4)

190-192: LGTM. Improved formatting.

The formatting adjustment in the createIncentive method call improves code readability without changing functionality.


Line range hint 1-368: Overall LGTM. New component added to test setup.

The changes in this file primarily involve the addition of an incentives fund manager component to the test setup and a minor update to the approve function call. While these changes don't alter the core functionality of the tests, they introduce a new element that could potentially affect test behavior.

To ensure the integrity of the test suite:

  1. Run the entire test suite and verify that all tests pass with the new setup.
  2. Review the coverage report to ensure that the new component is adequately tested.
  3. Consider adding specific tests for the new incentives fund manager functionality if not already present.

307-308: LGTM. Verify contract interface update.

The addition of the tokenId parameter to the approve method call is appropriate.

Please verify that this change is consistent with any updates to the contract's approve function signature. Run the following script to check the contract interface:

#!/bin/bash
# Description: Check the contract interface for the approve function

# Test: Search for the approve function definition
rg --type rust -A 5 'fn approve'

# Note: Adjust the search pattern if necessary based on your contract structure

46-49: LGTM. Verify impact on existing tests.

The addition of fundManager and its integration into the OraiswapV3Client instantiation is appropriate. This change introduces a new component to the test setup.

Please verify that this change doesn't unintentionally affect the behavior of existing tests. Run the following script to check for any failing tests:

Also applies to: 58-58

packages/oraiswap-v3/tests/test-common.ts (2)

81-84: Verify that the multicall contract requires no initialization parameters

In deployMultiCall, an empty object {} is passed as the initialization message to deployContract. Ensure that the multicall contract does not require any specific initialization parameters and will function correctly when instantiated with an empty message.

If necessary, update the initialization message to include required parameters based on the contract's specification.


86-114: Consistent typing for msg parameters in deployment functions

The deployment functions (deployIncentivesFundManager, deployDexV3, deployOracle, deployFactory, deployMixedRouter, deployZapper) accept msg parameters with specific types, which is good for type safety. Ensure that these types align with the expected initialization messages for each contract.

Consider applying similar type safety improvements to deployContract as previously suggested.

packages/oraiswap-v3/tests/zap-consumer.spec.ts (2)

74-85: Test assertions are properly validating token transfers

The test case for the connect function correctly checks the balances before and after the transfer, ensuring that the connect method assigns the signer properly and that the transfer functionality works as expected.


170-175: Verify initial sqrt prices and tick values

The initialization of pools with initSqrtPrice and initTick should be carefully verified to ensure they correspond to the intended starting prices and tick positions.

Would you like to confirm that the initSqrtPrice and initTick values match the expected initial prices for the pools?

You can run the following script to calculate and compare the sqrt prices and ticks:

Also applies to: 181-186, 192-197

packages/oraiswap-v3/src/helpers.ts (1)

499-502: Unused property isSingleSide remains in buildZapInMessageOptions

The isSingleSide property is still declared but not used anywhere in the code. Keeping unused properties can lead to confusion and increase maintenance overhead.


export const senderAddress = "orai1g4h64yjt0fvzv5v2j8tyfnpe5kmnetejvfgs7g";
export const bobAddress = "orai1602dkqjvh4s7ryajnz2uwhr8vetrwr8nekpxv5";

export const deployer = "orai1swus8mwu8xjulawqxdwh8hvg4gknh2c64tuc0k";
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider using configuration or environment variables for the deployer address

Hardcoding the deployer address reduces flexibility and may cause issues if the address changes. Consider using a configuration file or environment variables to manage addresses, which will make the code more maintainable and adaptable to different environments.

Comment on lines +43 to +59
export const deployContract = async (name: string, initMsg: any) => {
const { codeId } = await client.upload(
deployer,
fs.readFileSync(path.resolve(__dirname, "data", `${name}.wasm`)),
"auto"
);

const { contractAddress } = await client.instantiate(
deployer,
codeId,
initMsg,
name,
"auto"
);

return contractAddress;
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid using the any type for initMsg parameter

Using any for the initMsg parameter in deployContract bypasses TypeScript's type checking, potentially leading to runtime errors. Define a generic type parameter or a specific interface to enhance type safety and code reliability.

Apply this change to improve type safety:

-export const deployContract = async (name: string, initMsg: any) => {
+export const deployContract = async <T>(name: string, initMsg: T) => {

This introduces a generic type T for the initMsg parameter, allowing for better type inference and validation.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const deployContract = async (name: string, initMsg: any) => {
const { codeId } = await client.upload(
deployer,
fs.readFileSync(path.resolve(__dirname, "data", `${name}.wasm`)),
"auto"
);
const { contractAddress } = await client.instantiate(
deployer,
codeId,
initMsg,
name,
"auto"
);
return contractAddress;
};
export const deployContract = async <T>(name: string, initMsg: T) => {
const { codeId } = await client.upload(
deployer,
fs.readFileSync(path.resolve(__dirname, "data", `${name}.wasm`)),
"auto"
);
const { contractAddress } = await client.instantiate(
deployer,
codeId,
initMsg,
name,
"auto"
);
return contractAddress;
};

⚠️ Potential issue

Add error handling to deployContract function

If an error occurs during the client.upload or client.instantiate calls, it will currently go unhandled, which might make debugging difficult. Wrap these calls in a try-catch block to handle exceptions gracefully and provide informative error messages.

Apply this change to incorporate error handling:

 export const deployContract = async <T>(name: string, initMsg: T) => {
+  try {
     const { codeId } = await client.upload(
       deployer,
       fs.readFileSync(path.resolve(__dirname, "data", `${name}.wasm`)),
       "auto"
     );
 
     const { contractAddress } = await client.instantiate(
       deployer,
       codeId,
       initMsg,
       name,
       "auto"
     );
 
     return contractAddress;
+  } catch (error) {
+    console.error(`Failed to deploy contract ${name}:`, error);
+    throw error;
+  }
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const deployContract = async (name: string, initMsg: any) => {
const { codeId } = await client.upload(
deployer,
fs.readFileSync(path.resolve(__dirname, "data", `${name}.wasm`)),
"auto"
);
const { contractAddress } = await client.instantiate(
deployer,
codeId,
initMsg,
name,
"auto"
);
return contractAddress;
};
export const deployContract = async <T>(name: string, initMsg: T) => {
try {
const { codeId } = await client.upload(
deployer,
fs.readFileSync(path.resolve(__dirname, "data", `${name}.wasm`)),
"auto"
);
const { contractAddress } = await client.instantiate(
deployer,
codeId,
initMsg,
name,
"auto"
);
return contractAddress;
} catch (error) {
console.error(`Failed to deploy contract ${name}:`, error);
throw error;
}
};

Comment on lines +38 to +47
// move signer to dynamic signing of an object
declare module "@oraichain/oraidex-contracts-sdk" {
interface OraiswapTokenClient {
connect(signer: string): OraiswapTokenClient;
}
}
OraiswapTokenClient.prototype.connect = function (signer: string): OraiswapTokenClient {
this.sender = signer;
return this;
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid modifying the prototypes of external modules

Modifying the prototype of OraiswapTokenClient can lead to unintended side effects throughout the codebase, especially if other parts of the application rely on the original behavior of the client. This practice can make the code harder to maintain and debug.

Consider extending the class or using a wrapper function to add the connect method without altering the original prototype.

Refactor Suggestion:

Create a subclass to extend OraiswapTokenClient:

class ExtendedOraiswapTokenClient extends OraiswapTokenClient {
  connect(signer: string): OraiswapTokenClient {
    this.sender = signer;
    return this;
  }
}

Use the extended class in your tests:

tokenTest = new ExtendedOraiswapTokenClient(client, tokenAddress);

Comment on lines +49 to +57
declare module "@oraichain/oraidex-contracts-sdk" {
interface OraiswapV3Client {
connect(signer: string): OraiswapV3Client;
}
}
OraiswapV3Client.prototype.connect = function (signer: string): OraiswapV3Client {
this.sender = signer;
return this;
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid modifying the prototypes of external modules

Similarly, modifying the prototype of OraiswapV3Client can introduce unexpected behavior and complicate maintenance. It's better to extend the class or create a wrapper to add new functionalities like the connect method.

Refactor Suggestion:

Create a subclass to extend OraiswapV3Client:

class ExtendedOraiswapV3Client extends OraiswapV3Client {
  connect(signer: string): OraiswapV3Client {
    this.sender = signer;
    return this;
  }
}

Use the extended class where needed:

oraiswapV3 = new ExtendedOraiswapV3Client(client, contractAddress);

Comment on lines +121 to +123
protocol_fee: 0.25 * 10 ** 12,
incentives_fund_manager: incentivesFundManager.contractAddress
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use integer arithmetic to prevent floating-point precision errors

Using floating-point numbers in calculations like 0.25 * 10 ** 12 can lead to precision issues due to how floating-point arithmetic works in JavaScript/TypeScript. Instead, use integer arithmetic to maintain precision, especially when dealing with financial values.

Apply this diff to use integer values:

- protocol_fee: 0.25 * 10 ** 12,
+ protocol_fee: 250_000_000_000, // Equivalent to 0.25 * 10^12

...

- fee: 0.003 * 10 ** 12,
+ fee: 3_000_000_000, // Equivalent to 0.003 * 10^12

...

- fee: 0.0005 * 10 ** 12,
+ fee: 500_000_000, // Equivalent to 0.0005 * 10^12

Also applies to: 151-157, 173-175, 184-185, 195-196

Comment on lines +216 to +285
it("InRangeNoRouteThroughSelf", async () => {
// zap to pool usdt usdc, use oraix
const pools = await handler.getPools();

await oraix.connect(deployer).mint({
recipient: alice,
amount: (1000n * 10n ** 6n).toString()
});
await usdc.connect(deployer).mint({
recipient: alice,
amount: (1000n * 10n ** 6n).toString()
});
await usdt.connect(deployer).mint({
recipient: alice,
amount: (1000n * 10n ** 6n).toString()
});

await oraix.connect(alice).increaseAllowance({
spender: oraiswapV3.contractAddress,
amount: (1000n * 10n ** 6n).toString()
});
await usdc.connect(alice).increaseAllowance({
spender: oraiswapV3.contractAddress,
amount: (1000n * 10n ** 6n).toString()
});
await usdt.connect(alice).increaseAllowance({
spender: oraiswapV3.contractAddress,
amount: (1000n * 10n ** 6n).toString()
});

const oraixUsdtPK = newPoolKey(oraix.contractAddress, usdt.contractAddress, feeTier1); // oraix < usdt
const usdcOraixPK = newPoolKey(oraix.contractAddress, usdc.contractAddress, feeTier1); // usdc < oraix
const usdcUsdtPK = newPoolKey(usdt.contractAddress, usdc.contractAddress, feeTier2); // usdc < usdt

await oraiswapV3.connect(alice).createPosition({
poolKey: oraixUsdtPK,
lowerTick: 13700,
upperTick: 13900,
liquidityDelta: (10000n * 10n ** 6n).toString(),
slippageLimitLower: getGlobalMinSqrtPrice().toString(),
slippageLimitUpper: getGlobalMaxSqrtPrice().toString()
});
await oraiswapV3.connect(alice).createPosition({
poolKey: usdcOraixPK,
lowerTick: -14000,
upperTick: -13800,
liquidityDelta: (10000n * 10n ** 6n).toString(),
slippageLimitLower: getGlobalMinSqrtPrice().toString(),
slippageLimitUpper: getGlobalMaxSqrtPrice().toString()
});
await oraiswapV3.connect(alice).createPosition({
poolKey: usdcUsdtPK,
lowerTick: -10,
upperTick: 10,
liquidityDelta: (10000n * 10n ** 6n).toString(),
slippageLimitLower: getGlobalMinSqrtPrice().toString(),
slippageLimitUpper: getGlobalMaxSqrtPrice().toString()
});

const oraixUsdt = await handler.getPool(oraixUsdtPK);
const usdcOraix = await handler.getPool(usdcOraixPK);
const usdcUsdt = await handler.getPool(usdcUsdtPK);

// console.log({ oraixUsdt, usdcOraix, usdcUsdt });

const positions = await handler.allPositions();
const liquidityOraixUsdt = await handler.getPairLiquidityValues(oraixUsdt, positions);
const liquidityUsdcOraix = await handler.getPairLiquidityValues(usdcOraix, positions);
const liquidityUsdcUsdt = await handler.getPairLiquidityValues(usdcUsdt, positions);
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Unused variables and commented-out code

Within the InRangeNoRouteThroughSelf test case, there are variables assigned that are not utilized, and there's a commented-out console.log statement. Unused variables can clutter the code and make it harder to read.

Consider removing or utilizing the unused variables:

- const pools = await handler.getPools();
- // console.log({ oraixUsdt, usdcOraix, usdcUsdt });

- const positions = await handler.allPositions();
- const liquidityOraixUsdt = await handler.getPairLiquidityValues(oraixUsdt, positions);
- const liquidityUsdcOraix = await handler.getPairLiquidityValues(usdcOraix, positions);
- const liquidityUsdcUsdt = await handler.getPairLiquidityValues(usdcUsdt, positions);

If these variables are intended for future use or for assertion purposes, ensure they are integrated into the test case accordingly.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it("InRangeNoRouteThroughSelf", async () => {
// zap to pool usdt usdc, use oraix
const pools = await handler.getPools();
await oraix.connect(deployer).mint({
recipient: alice,
amount: (1000n * 10n ** 6n).toString()
});
await usdc.connect(deployer).mint({
recipient: alice,
amount: (1000n * 10n ** 6n).toString()
});
await usdt.connect(deployer).mint({
recipient: alice,
amount: (1000n * 10n ** 6n).toString()
});
await oraix.connect(alice).increaseAllowance({
spender: oraiswapV3.contractAddress,
amount: (1000n * 10n ** 6n).toString()
});
await usdc.connect(alice).increaseAllowance({
spender: oraiswapV3.contractAddress,
amount: (1000n * 10n ** 6n).toString()
});
await usdt.connect(alice).increaseAllowance({
spender: oraiswapV3.contractAddress,
amount: (1000n * 10n ** 6n).toString()
});
const oraixUsdtPK = newPoolKey(oraix.contractAddress, usdt.contractAddress, feeTier1); // oraix < usdt
const usdcOraixPK = newPoolKey(oraix.contractAddress, usdc.contractAddress, feeTier1); // usdc < oraix
const usdcUsdtPK = newPoolKey(usdt.contractAddress, usdc.contractAddress, feeTier2); // usdc < usdt
await oraiswapV3.connect(alice).createPosition({
poolKey: oraixUsdtPK,
lowerTick: 13700,
upperTick: 13900,
liquidityDelta: (10000n * 10n ** 6n).toString(),
slippageLimitLower: getGlobalMinSqrtPrice().toString(),
slippageLimitUpper: getGlobalMaxSqrtPrice().toString()
});
await oraiswapV3.connect(alice).createPosition({
poolKey: usdcOraixPK,
lowerTick: -14000,
upperTick: -13800,
liquidityDelta: (10000n * 10n ** 6n).toString(),
slippageLimitLower: getGlobalMinSqrtPrice().toString(),
slippageLimitUpper: getGlobalMaxSqrtPrice().toString()
});
await oraiswapV3.connect(alice).createPosition({
poolKey: usdcUsdtPK,
lowerTick: -10,
upperTick: 10,
liquidityDelta: (10000n * 10n ** 6n).toString(),
slippageLimitLower: getGlobalMinSqrtPrice().toString(),
slippageLimitUpper: getGlobalMaxSqrtPrice().toString()
});
const oraixUsdt = await handler.getPool(oraixUsdtPK);
const usdcOraix = await handler.getPool(usdcOraixPK);
const usdcUsdt = await handler.getPool(usdcUsdtPK);
// console.log({ oraixUsdt, usdcOraix, usdcUsdt });
const positions = await handler.allPositions();
const liquidityOraixUsdt = await handler.getPairLiquidityValues(oraixUsdt, positions);
const liquidityUsdcOraix = await handler.getPairLiquidityValues(usdcOraix, positions);
const liquidityUsdcUsdt = await handler.getPairLiquidityValues(usdcUsdt, positions);
});
it("InRangeNoRouteThroughSelf", async () => {
// zap to pool usdt usdc, use oraix
await oraix.connect(deployer).mint({
recipient: alice,
amount: (1000n * 10n ** 6n).toString()
});
await usdc.connect(deployer).mint({
recipient: alice,
amount: (1000n * 10n ** 6n).toString()
});
await usdt.connect(deployer).mint({
recipient: alice,
amount: (1000n * 10n ** 6n).toString()
});
await oraix.connect(alice).increaseAllowance({
spender: oraiswapV3.contractAddress,
amount: (1000n * 10n ** 6n).toString()
});
await usdc.connect(alice).increaseAllowance({
spender: oraiswapV3.contractAddress,
amount: (1000n * 10n ** 6n).toString()
});
await usdt.connect(alice).increaseAllowance({
spender: oraiswapV3.contractAddress,
amount: (1000n * 10n ** 6n).toString()
});
const oraixUsdtPK = newPoolKey(oraix.contractAddress, usdt.contractAddress, feeTier1); // oraix < usdt
const usdcOraixPK = newPoolKey(oraix.contractAddress, usdc.contractAddress, feeTier1); // usdc < oraix
const usdcUsdtPK = newPoolKey(usdt.contractAddress, usdc.contractAddress, feeTier2); // usdc < usdt
await oraiswapV3.connect(alice).createPosition({
poolKey: oraixUsdtPK,
lowerTick: 13700,
upperTick: 13900,
liquidityDelta: (10000n * 10n ** 6n).toString(),
slippageLimitLower: getGlobalMinSqrtPrice().toString(),
slippageLimitUpper: getGlobalMaxSqrtPrice().toString()
});
await oraiswapV3.connect(alice).createPosition({
poolKey: usdcOraixPK,
lowerTick: -14000,
upperTick: -13800,
liquidityDelta: (10000n * 10n ** 6n).toString(),
slippageLimitLower: getGlobalMinSqrtPrice().toString(),
slippageLimitUpper: getGlobalMaxSqrtPrice().toString()
});
await oraiswapV3.connect(alice).createPosition({
poolKey: usdcUsdtPK,
lowerTick: -10,
upperTick: 10,
liquidityDelta: (10000n * 10n ** 6n).toString(),
slippageLimitLower: getGlobalMinSqrtPrice().toString(),
slippageLimitUpper: getGlobalMaxSqrtPrice().toString()
});
const oraixUsdt = await handler.getPool(oraixUsdtPK);
const usdcOraix = await handler.getPool(usdcOraixPK);
const usdcUsdt = await handler.getPool(usdcUsdtPK);
});

Comment on lines +522 to +529
if (buildZapInMessageOptions) {
if (buildZapInMessageOptions.isTokenX) {
message.amountY = "0";
} else {
message.amountX = "0";
}
message.routes = generateMessageSwapOperation([actualAmountXReceived], slippage);
} else {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure isTokenX is always defined when using buildZapInMessageOptions

In the populateMessageZapIn function, when buildZapInMessageOptions is provided, isTokenX is accessed without verifying its existence. This could lead to runtime errors if isTokenX is undefined.

Consider adding a type check to ensure isTokenX is defined:

if (buildZapInMessageOptions) {
+  if (typeof buildZapInMessageOptions.isTokenX !== 'boolean') {
+    throw new Error('buildZapInMessageOptions.isTokenX must be a boolean');
+  }
  if (buildZapInMessageOptions.isTokenX) {
    message.amountY = "0";
  } else {
    message.amountX = "0";
  }
  message.routes = generateMessageSwapOperation([actualAmountXReceived], slippage);
} else {
  message.routes = generateMessageSwapOperation([actualAmountXReceived, actualAmountYReceived], slippage);
}

This ensures robustness by validating the expected type of isTokenX.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (buildZapInMessageOptions) {
if (buildZapInMessageOptions.isTokenX) {
message.amountY = "0";
} else {
message.amountX = "0";
}
message.routes = generateMessageSwapOperation([actualAmountXReceived], slippage);
} else {
if (buildZapInMessageOptions) {
if (typeof buildZapInMessageOptions.isTokenX !== 'boolean') {
throw new Error('buildZapInMessageOptions.isTokenX must be a boolean');
}
if (buildZapInMessageOptions.isTokenX) {
message.amountY = "0";
} else {
message.amountX = "0";
}
message.routes = generateMessageSwapOperation([actualAmountXReceived], slippage);
} else {

Comment on lines +566 to +574
if (buildZapInMessageOptions) {
const res = buildZapInMessageOptions.isTokenX
? getLiquidityByX(BigInt(actualAmountXReceived.returnAmount), lowerTick, upperTick, sqrtPrice, true)
: getLiquidityByY(BigInt(actualAmountYReceived.returnAmount), lowerTick, upperTick, sqrtPrice, true);
const slippageMultiplier = BigInt(Math.floor((100 - slippage) * 1000));
message.minimumLiquidity = res.l ? (BigInt(res.l) * slippageMultiplier) / 100_000n : 0n;
return;
}

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add type check for isTokenX in calculateMinimumLiquidity

In the calculateMinimumLiquidity function, when buildZapInMessageOptions is provided, isTokenX is accessed without verification. To prevent potential runtime errors, ensure that isTokenX is defined:

if (buildZapInMessageOptions) {
+  if (typeof buildZapInMessageOptions.isTokenX !== 'boolean') {
+    throw new Error('buildZapInMessageOptions.isTokenX must be a boolean');
+  }
  const res = buildZapInMessageOptions.isTokenX
    ? getLiquidityByX(BigInt(actualAmountXReceived.returnAmount), lowerTick, upperTick, sqrtPrice, true)
    : getLiquidityByY(BigInt(actualAmountYReceived.returnAmount), lowerTick, upperTick, sqrtPrice, true);

Adding this check ensures that isTokenX has the expected type before use.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (buildZapInMessageOptions) {
const res = buildZapInMessageOptions.isTokenX
? getLiquidityByX(BigInt(actualAmountXReceived.returnAmount), lowerTick, upperTick, sqrtPrice, true)
: getLiquidityByY(BigInt(actualAmountYReceived.returnAmount), lowerTick, upperTick, sqrtPrice, true);
const slippageMultiplier = BigInt(Math.floor((100 - slippage) * 1000));
message.minimumLiquidity = res.l ? (BigInt(res.l) * slippageMultiplier) / 100_000n : 0n;
return;
}
if (buildZapInMessageOptions) {
if (typeof buildZapInMessageOptions.isTokenX !== 'boolean') {
throw new Error('buildZapInMessageOptions.isTokenX must be a boolean');
}
const res = buildZapInMessageOptions.isTokenX
? getLiquidityByX(BigInt(actualAmountXReceived.returnAmount), lowerTick, upperTick, sqrtPrice, true)
: getLiquidityByY(BigInt(actualAmountYReceived.returnAmount), lowerTick, upperTick, sqrtPrice, true);
const slippageMultiplier = BigInt(Math.floor((100 - slippage) * 1000));
message.minimumLiquidity = res.l ? (BigInt(res.l) * slippageMultiplier) / 100_000n : 0n;
return;
}

Copy link

@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/oraiswap-v3/src/main.ts (1)

32-32: Simplify the Fee Tier Calculation in Pool String

Consider simplifying the calculation (0.3 / 100) * 10 ** 12 to 3e9 for improved readability and to avoid unnecessary computations at runtime.

Apply this diff to simplify the calculation:

-  const pool = `${OSMOSIS_ORAICHAIN_DENOM}-orai-${(0.3 / 100) * 10 ** 12}-100`;
+  const pool = `${OSMOSIS_ORAICHAIN_DENOM}-orai-${3e9}-100`;
packages/oraiswap-v3/src/helpers.ts (1)

Line range hint 499-573: Add unit tests for the new buildZapInMessageOptions functionality

The introduction of buildZapInMessageOptions adds conditional logic paths that should be tested to ensure correctness and prevent future regressions. Consider adding unit tests that cover scenarios with and without buildZapInMessageOptions, and with different values of isTokenX.

Would you like assistance in creating unit tests for these new code paths or opening a GitHub issue to track this task?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between dfa75cf and dd2abc4.

📒 Files selected for processing (3)
  • packages/oraiswap-v3/package.json (2 hunks)
  • packages/oraiswap-v3/src/helpers.ts (2 hunks)
  • packages/oraiswap-v3/src/main.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/oraiswap-v3/package.json
🔇 Additional comments (7)
packages/oraiswap-v3/src/main.ts (6)

3-3: Addition of 'KWT_CONTRACT' Import

The import of KWT_CONTRACT is appropriate and correctly added to the import statement.


7-8: Importing 'OSMO' and 'OSMOSIS_ORAICHAIN_DENOM'

The additions of OSMO and OSMOSIS_ORAICHAIN_DENOM to the imports are correct and necessary for the code.


14-15: Importing Helper Functions and Modules

The imports of extractAddress, parsePoolKey, and getTickAtSqrtPrice are appropriately added. These functions are essential for parsing pool keys and handling price calculations.


26-26: Setting 'protocols' to ['OraidexV3']

The protocols configuration in smartRouteConfig.swapOptions is set to ["OraidexV3"], which specifies the use of the Oraidex V3 protocol. This is correctly implemented.


31-31: Finding 'tokenIn' by Name

Using oraichainTokens.find((t) => t.name === "USDT") to locate the tokenIn by its name enhances code readability and clarity.


40-41: Retrieving Tick Spacing and Current Tick Index

The retrieval of tickSpacing and currentTick from poolKey and the pool data is correctly implemented, ensuring accurate tick calculations for liquidity operations.

packages/oraiswap-v3/src/helpers.ts (1)

499-502: Remove unused property isSingleSide from buildZapInMessageOptions

The isSingleSide property is declared but not used anywhere in the code. Keeping unused properties can lead to confusion and increase maintenance overhead.

Comment on lines +57 to +61
const res = await zapper.processZapOutPositionLiquidity({
owner: "orai1hvr9d72r5um9lvt0rpkd4r75vrsqtw6yujhqs2",
tokenId: 4275,
tokenOut: tokenIn,
zapFee: 0,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid Hardcoding 'owner' Address and 'tokenId'

Hardcoding the owner address and tokenId may lead to security risks and reduce code flexibility. It's advisable to parameterize these values or retrieve them from a secure configuration or user input.

Consider modifying the code as follows to pass these values dynamically:

 const res = await zapper.processZapOutPositionLiquidity({
-    owner: "orai1hvr9d72r5um9lvt0rpkd4r75vrsqtw6yujhqs2",
-    tokenId: 4275,
+    owner: OWNER_ADDRESS, // Replace with dynamic value
+    tokenId: TOKEN_ID,    // Replace with dynamic value
     tokenOut: tokenIn,
     zapFee: 0,
 });

This change enhances maintainability and security by avoiding hardcoded sensitive information.

Committable suggestion was skipped due to low confidence.

Comment on lines +566 to +573
if (buildZapInMessageOptions) {
const res = buildZapInMessageOptions.isTokenX
? getLiquidityByX(BigInt(actualAmountXReceived.returnAmount), lowerTick, upperTick, sqrtPrice, true)
: getLiquidityByY(BigInt(actualAmountYReceived.returnAmount), lowerTick, upperTick, sqrtPrice, true);
const slippageMultiplier = BigInt(Math.floor((100 - slippage) * 1000));
message.minimumLiquidity = res.l ? (BigInt(res.l) * slippageMultiplier) / 100_000n : 0n;
return;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Handle slippage calculations with precise decimal arithmetic

The current implementation multiplies the slippage by 1000 and uses integer arithmetic to calculate slippageMultiplier. This may lead to precision loss for small slippage values. Consider using a decimal library like BigNumber.js to handle precise decimal computations, ensuring accurate minimum liquidity calculations.

Apply this refactor to improve precision:

-const slippageMultiplier = BigInt(Math.floor((100 - slippage) * 1000));
-message.minimumLiquidity = res.l ? (BigInt(res.l) * slippageMultiplier) / 100_000n : 0n;
+const slippageDecimal = new BigDecimal(100 - slippage).div(100);
+message.minimumLiquidity = res.l ? BigInt(new BigDecimal(res.l.toString()).mul(slippageDecimal).toFixed(0)) : 0n;

This change ensures that the slippage is accurately applied without losing precision due to integer division.

Committable suggestion was skipped due to low confidence.

Comment on lines +513 to +544
buildZapInMessageOptions?: buildZapInMessageOptions
) => {
message.assetIn = parseAsset(tokenIn, amountIn);
message.amountToX = amountInToX.toString();
message.amountToY = amountInToY.toString();
message.amountX = actualAmountXReceived.returnAmount;
message.amountY = actualAmountYReceived.returnAmount;
message.poolKey = poolKey;
message.sqrtPrice = BigInt(pool.sqrt_price);
message.tickLowerIndex = lowerTick;
message.tickUpperIndex = upperTick;
message.routes = generateMessageSwapOperation([actualAmountXReceived, actualAmountYReceived], slippage);
message.currentSqrtPrice = sqrtPrice;

if (buildZapInMessageOptions) {
if (buildZapInMessageOptions.isTokenX) {
message.amountY = "0";
} else {
message.amountX = "0";
}
message.routes = generateMessageSwapOperation([actualAmountXReceived], slippage);
} else {
message.routes = generateMessageSwapOperation([actualAmountXReceived, actualAmountYReceived], slippage);
}

calculateSwapFee(message);

calculateMinimumLiquidity(
message,
actualAmountXReceived,
actualAmountYReceived,
lowerTick,
upperTick,
sqrtPrice,
slippage,
buildZapInMessageOptions
);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider refactoring populateMessageZapIn to improve readability

The populateMessageZapIn function now has a large number of parameters, which can make it harder to read and maintain. Consider refactoring the function to accept an options object or to group related parameters into objects.

Apply this refactor to simplify the function signature:

-export const populateMessageZapIn = (
-  message: ZapInLiquidityResponse,
-  actualAmountXReceived: SmartRouteResponse,
-  actualAmountYReceived: SmartRouteResponse,
-  sqrtPrice: bigint,
-  poolKey: PoolKey,
-  lowerTick: number,
-  upperTick: number,
-  slippage: number,
-  buildZapInMessageOptions?: buildZapInMessageOptions
-) => {
+interface PopulateMessageZapInOptions {
+  message: ZapInLiquidityResponse;
+  actualAmountXReceived: SmartRouteResponse;
+  actualAmountYReceived: SmartRouteResponse;
+  sqrtPrice: bigint;
+  poolKey: PoolKey;
+  lowerTick: number;
+  upperTick: number;
+  slippage: number;
+  buildZapInMessageOptions?: buildZapInMessageOptions;
+}
+
+export const populateMessageZapIn = (options: PopulateMessageZapInOptions) => {
+  const {
+    message,
+    actualAmountXReceived,
+    actualAmountYReceived,
+    sqrtPrice,
+    poolKey,
+    lowerTick,
+    upperTick,
+    slippage,
+    buildZapInMessageOptions
+  } = options;

This refactor enhances readability and makes it easier to manage parameters.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
buildZapInMessageOptions?: buildZapInMessageOptions
) => {
message.assetIn = parseAsset(tokenIn, amountIn);
message.amountToX = amountInToX.toString();
message.amountToY = amountInToY.toString();
message.amountX = actualAmountXReceived.returnAmount;
message.amountY = actualAmountYReceived.returnAmount;
message.poolKey = poolKey;
message.sqrtPrice = BigInt(pool.sqrt_price);
message.tickLowerIndex = lowerTick;
message.tickUpperIndex = upperTick;
message.routes = generateMessageSwapOperation([actualAmountXReceived, actualAmountYReceived], slippage);
message.currentSqrtPrice = sqrtPrice;
if (buildZapInMessageOptions) {
if (buildZapInMessageOptions.isTokenX) {
message.amountY = "0";
} else {
message.amountX = "0";
}
message.routes = generateMessageSwapOperation([actualAmountXReceived], slippage);
} else {
message.routes = generateMessageSwapOperation([actualAmountXReceived, actualAmountYReceived], slippage);
}
calculateSwapFee(message);
calculateMinimumLiquidity(
message,
actualAmountXReceived,
actualAmountYReceived,
lowerTick,
upperTick,
sqrtPrice,
slippage,
buildZapInMessageOptions
);
interface PopulateMessageZapInOptions {
message: ZapInLiquidityResponse;
actualAmountXReceived: SmartRouteResponse;
actualAmountYReceived: SmartRouteResponse;
sqrtPrice: bigint;
poolKey: PoolKey;
lowerTick: number;
upperTick: number;
slippage: number;
buildZapInMessageOptions?: buildZapInMessageOptions;
}
export const populateMessageZapIn = (options: PopulateMessageZapInOptions) => {
const {
message,
actualAmountXReceived,
actualAmountYReceived,
sqrtPrice,
poolKey,
lowerTick,
upperTick,
slippage,
buildZapInMessageOptions
} = options;
message.amountX = actualAmountXReceived.returnAmount;
message.amountY = actualAmountYReceived.returnAmount;
message.poolKey = poolKey;
message.tickLowerIndex = lowerTick;
message.tickUpperIndex = upperTick;
message.currentSqrtPrice = sqrtPrice;
if (buildZapInMessageOptions) {
if (buildZapInMessageOptions.isTokenX) {
message.amountY = "0";
} else {
message.amountX = "0";
}
message.routes = generateMessageSwapOperation([actualAmountXReceived], slippage);
} else {
message.routes = generateMessageSwapOperation([actualAmountXReceived, actualAmountYReceived], slippage);
}
calculateSwapFee(message);
calculateMinimumLiquidity(
message,
actualAmountXReceived,
actualAmountYReceived,
lowerTick,
upperTick,
sqrtPrice,
slippage,
buildZapInMessageOptions
);

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.

2 participants