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

Adjustments for fee voting #2812

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

Adjustments for fee voting #2812

wants to merge 8 commits into from

Conversation

pdp2121
Copy link
Collaborator

@pdp2121 pdp2121 commented Oct 25, 2024

High Level Overview of Change

Ensure the library works for changes FeeSettings values resulted by Fee Voting:

  • Remove hard-coded reference to 10 drops as the reference transaction cost.
  • Ensure tests passed for all transaction fee scenarios.
  • Modify calculateFeePerTransaction to get accurate tx fee for AMMCreate in case owner_reserve increases.

Context of Change

Fee voting by mainnet UNL validators are approaching 200 drops for base_fee. Both account_reserve and reserve_inc are also getting proposed changes.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (non-breaking change that only restructures code)
  • Tests (You added tests for code that already exists, or your new feature included in this PR)
  • Documentation Updates
  • Release

Did you update HISTORY.md?

  • Yes
  • No, this change does not impact library users

Test Plan

All integration tests passed.

Copy link

coderabbitai bot commented Oct 25, 2024

Walkthrough

The pull request introduces several updates across multiple files, focusing on the configuration and functionality of the XRPL ecosystem. A new [voting] section is added to the configuration file with parameters for fee settings. The HISTORY.md file documents enhancements, including a new utility function for transaction flags and fixes for transaction fee calculations. The autofill.ts file sees a renaming of functions and updates to fee calculation logic. Additionally, tests are modified to incorporate dynamic fee calculations, enhancing accuracy and flexibility.

Changes

File Path Change Summary
.ci-config/rippled.cfg Added new section [voting] with parameters reference_fee, account_reserve, and owner_reserve. Commented out parameters in [server], simplified [node_size], clarified comments in [node_db], and specified ledger_history as 256.
packages/xrpl/HISTORY.md Updated to include new utility function parseTransactionFlags and removed hard-coded reference to transaction cost of 10 drops. Documented breaking changes and new features across multiple releases, including version 4.0.0 modifications.
packages/xrpl/src/sugar/autofill.ts Renamed fetchAccountDeleteFee to fetchOwnerReserveFee. Updated fee calculation logic in calculateFeePerTransactionType. Revised comments for clarity without changing core functionality.
packages/xrpl/test/integration/requests/fee.test.ts Enhanced fee calculation logic by importing xrpToDrops and getFeeXrp. Updated expected response structure to use dynamic calculations based on referenceFee.
packages/xrpl/test/integration/transactions/xchainClaim.test.ts Added import for getFeeXrp to dynamically calculate transaction fees, replacing hardcoded values in balance assertions for improved accuracy.
packages/xrpl/test/integration/utils.ts Introduced fetchAccountReserveFee function to retrieve reserve fee from server state, returning it as a string in base 10. Added import for BigNumber.
CONTRIBUTING.md Updated Docker container version from 2.0.0-b4 to 2.2.0-b3 in setup commands for integration and browser tests. Clarified instructions for updating the Docker container for CI.

Suggested reviewers

  • mvadari

🐇 In the meadow, changes abound,
New fees and functions, all around.
With reserves and votes, we hop with glee,
A brighter future for you and me!
Let's celebrate with a joyful cheer,
For the XRPL, we hold so dear! 🌼✨


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ec590b3 and 309e3c2.

📒 Files selected for processing (2)
  • CONTRIBUTING.md (1 hunks)
  • packages/xrpl/HISTORY.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/xrpl/HISTORY.md
🔇 Additional comments (1)
CONTRIBUTING.md (1)

67-67: LGTM! Consider documenting the version update rationale.

The Docker container version update to 2.2.0-b3 aligns with the PR's fee voting changes. However, consider:

  1. Adding a comment explaining that this version is required for fee voting support
  2. Verifying that all other Docker container version references in the documentation are updated consistently
✅ Verification successful

Docker container versions are consistent across the documentation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any inconsistent Docker container versions in the documentation

# Search for any rippled Docker container version references
rg -i "rippleci/rippled:[0-9]+\.[0-9]+\.[0-9]+.*"

Length of output: 471


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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

Documentation and Community

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

@pdp2121 pdp2121 marked this pull request as draft October 25, 2024 15:18
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 (5)
packages/xrpl/test/integration/requests/fee.test.ts (2)

40-45: LGTM: Robust fee calculations with precision handling.

The dynamic fee calculations are well-implemented with proper precision handling using BigNumber. However, consider adding test cases for edge scenarios:

  • Maximum possible fee values
  • Minimum acceptable fee values
  • Fee calculations with different network load conditions

Example test case structure:

it('handles maximum network load fees', async () => {
  // Test with high current_ledger_size and current_queue_size
})

it('handles minimum acceptable fees', async () => {
  // Test with minimum network conditions
})

Line range hint 1-70: Consider expanding test coverage for fee calculations.

While the current test covers the basic fee calculation scenario, consider adding a comprehensive test suite that validates:

  1. Fee calculations across different transaction types
  2. Fee adjustments based on network load
  3. Integration with the new Fee Voting mechanism
  4. Edge cases around reserve requirements

This would ensure the library remains reliable as the XRPL fee structure evolves.

.ci-config/rippled.cfg (1)

182-183: Consider enhancing the documentation.

While the comment indicates this is for simulating FeeSettings scenarios, it would be helpful to add more context about:

  • The relationship to current mainnet values
  • The purpose of these specific values in CI/testing scenarios
-# # This section can be used to simulate various FeeSettings scenarios for rippled node in standalone mode
+# This section configures FeeSettings for standalone mode to match expected mainnet values
+# These values reflect ongoing fee voting by mainnet UNL validators:
+# - reference_fee: approaching 200 drops on mainnet
+# - reserves: configured to test with realistic mainnet values
packages/xrpl/HISTORY.md (2)

Line range hint 1-24: Consider adding SHA checksums for recent releases.

Recent releases are missing the SHA-256 checksums that were historically included for browser builds. For consistency and security verification, consider adding these checksums back for the latest releases.

Add a section at the end of each recent release with SHA-256 checksums, following the established format:

The SHA-256 checksums for the browser version of this release can be found below.
% shasum -a 256 *
<checksum>  ripple-<version>-debug.js
<checksum>  ripple-<version>-min.js
<checksum>  ripple-<version>.js

Line range hint 1-24: Consider enhancing documentation with more consistent issue/PR linking.

While the changelog is well-documented, consider enhancing it by:

  1. Consistently linking to related GitHub issues/PRs using the format (#<number>)
  2. Adding links to migration guides when breaking changes are introduced
  3. Including references to relevant rippled version requirements

For example, the latest changes could include:

### Fixed
* Remove hard-coded reference to 10 drops as the transaction cost (#2812)
* Fix `calculateFeePerTransaction` for `AMMCreate` operations (#2812)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 0395c14 and d96931b.

📒 Files selected for processing (5)
  • .ci-config/rippled.cfg (1 hunks)
  • packages/xrpl/HISTORY.md (1 hunks)
  • packages/xrpl/src/sugar/autofill.ts (3 hunks)
  • packages/xrpl/test/integration/requests/fee.test.ts (2 hunks)
  • packages/xrpl/test/integration/transactions/xchainClaim.test.ts (3 hunks)
🔇 Additional comments (8)
packages/xrpl/test/integration/requests/fee.test.ts (2)

5-6: LGTM: Appropriate imports for dynamic fee handling.

The addition of xrpToDrops and getFeeXrp imports aligns well with the PR's objective to move away from hard-coded fee values.


31-32: Document and verify the MEDIAN_FEE_MULTIPLIER value.

While the dynamic fee calculation is good, the MEDIAN_FEE_MULTIPLIER value of 500 needs documentation explaining its significance and how it was determined. Given that mainnet UNL validators are approaching 200 drops for base_fee, we should verify if this multiplier aligns with expected fee calculations.

packages/xrpl/test/integration/transactions/xchainClaim.test.ts (2)

12-12: LGTM: Import of dynamic fee calculation utility

The addition of getFeeXrp import aligns with the PR's objective to move away from hardcoded fee values.


43-43: LGTM: Dynamic fee calculation implementation

The implementation correctly retrieves and converts the network fee to drops, replacing the hardcoded value.

Let's verify consistency across other test files:

✅ Verification successful

Let me analyze the specific usage of fees by examining the content of these files.


Based on the analysis of the test files, I can now generate the final response:

Dynamic fee calculation is correctly implemented and consistent

The implementation in xchainClaim.test.ts follows the established pattern in the codebase where:

  • getFeeXrp is used to fetch dynamic network fees
  • The result is converted to drops using xrpToDrops
  • Test files properly handle both normal and high load factor scenarios
  • The fee calculation includes proper cushioning and maximum fee handling
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining hardcoded fee values in test files
# and verify consistent usage of getFeeXrp

# Check for hardcoded fee values in test files
rg -l "(?i)(fee.*?[0-9]+|[0-9]+.*?fee)" "packages/xrpl/test"

# Verify consistent usage of getFeeXrp
rg -l "getFeeXrp" "packages/xrpl/test"

Length of output: 5321


Script:

#!/bin/bash
# Check the content of fee-related test files
rg -A 5 -B 5 "getFeeXrp" packages/xrpl/test/integration/requests/fee.test.ts packages/xrpl/test/client/getFeeXrp.test.ts

# Check for fee handling in integration tests
rg "fee.*=|=.*fee" "packages/xrpl/test/integration/transactions/"

Length of output: 8934

.ci-config/rippled.cfg (1)

182-186: LGTM! Values align with mainnet fee voting trends.

The new [voting] section correctly implements the fee settings to match the expected mainnet values, particularly the reference_fee of 200 drops which aligns with the current UNL validator voting trends.

packages/xrpl/src/sugar/autofill.ts (2)

Line range hint 233-248: LGTM! Function rename improves clarity.

The renaming from fetchAccountDeleteFee to fetchOwnerReserveFee better reflects its purpose of fetching the owner reserve increment from the server state. This aligns well with the PR's objective to accommodate fee voting changes.


Line range hint 270-282: LGTM! Fee calculation logic updated correctly.

The changes correctly implement the fee calculation for special transaction types (AccountDelete and AMMCreate) using the owner reserve fee, which aligns with the PR objectives to handle fee voting changes.

packages/xrpl/HISTORY.md (1)

10-11: Verify that the changelog entry matches the PR objectives.

The changelog entry correctly documents the bug fix for removing the hard-coded reference to 10 drops as the transaction cost. This aligns with the PR objectives to accommodate changes in FeeSettings values from Fee Voting.

However, to better reflect all the changes mentioned in the PR objectives, consider expanding the changelog entry to also mention:

  1. The modifications to calculateFeePerTransaction for AMMCreate operations
  2. The context about mainnet UNL validators' fee voting approaching 200 drops

Comment on lines +108 to +111
initialBalance +
Number(amount) -
Number(signatureReward) -
Number(netFee),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix misleading assertion message

The error message "The destination's balance should not change yet" doesn't match the context of this final balance assertion, which actually verifies the correct balance after all changes.

Apply this change:

        finalBalance,
        initialBalance +
          Number(amount) -
          Number(signatureReward) -
          Number(netFee),
-        "The destination's balance should not change yet",
+        "The destination's final balance should reflect the claim amount minus fees",
📝 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
initialBalance +
Number(amount) -
Number(signatureReward) -
Number(netFee),
finalBalance,
initialBalance +
Number(amount) -
Number(signatureReward) -
Number(netFee),
"The destination's final balance should reflect the claim amount minus fees",

packages/xrpl/src/sugar/autofill.ts Outdated Show resolved Hide resolved
@pdp2121 pdp2121 marked this pull request as ready for review October 25, 2024 16:27
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 (2)
packages/xrpl/test/integration/transactions/payment.test.ts (1)

22-23: Add documentation for DEFAULT_AMOUNT constant.

Consider adding a comment explaining why this specific value was chosen as the default amount and its significance in the context of account reserves and payments.

packages/xrpl/test/integration/utils.ts (1)

449-460: Add JSDoc documentation to improve maintainability.

The function implementation aligns well with the PR objectives for handling dynamic FeeSettings. Consider adding documentation to improve maintainability.

Add JSDoc documentation:

+/**
+ * Fetches the account reserve fee from the server state.
+ * This fee is subject to change through Fee Voting by validators.
+ *
+ * @param client - The XRPL client instance
+ * @returns A promise that resolves to:
+ *          - The reserve fee as a string (rounded up to the nearest integer)
+ *          - null if the fee is not available in the validated ledger
+ * @throws Error if the request fails or if the fee is negative
+ */
 export async function fetchAccountReserveFee(
   client: Client,
 ): Promise<string | null> {
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between d96931b and bb3156d.

📒 Files selected for processing (2)
  • packages/xrpl/test/integration/transactions/payment.test.ts (5 hunks)
  • packages/xrpl/test/integration/utils.ts (2 hunks)
🔇 Additional comments (5)
packages/xrpl/test/integration/transactions/payment.test.ts (4)

10-14: LGTM! Import changes align with dynamic fee calculation requirements.


33-33: LGTM! Successfully implements dynamic amount in payment transaction.


Line range hint 1-112: Verify integration with fee voting changes.

While the changes successfully implement dynamic amounts based on account reserves, we should verify that these tests adequately cover scenarios related to the fee voting changes mentioned in the PR objectives.


71-71: Verify edge cases in amount validation.

While the assertions are correctly updated to use the dynamic amount, consider adding test cases for edge cases such as:

  • Minimum possible amount
  • Maximum possible amount
  • Amount just above/below reserve requirements

Also applies to: 91-91, 109-109

packages/xrpl/test/integration/utils.ts (1)

449-460: Verify the integration with payment tests.

Let's ensure the new function is properly integrated with the payment tests and doesn't have unintended effects on other test utilities.

✅ Verification successful

Let me check the actual usage in payment.test.ts to ensure proper integration.


Integration verified successfully

The fetchAccountReserveFee function is properly integrated:

  • It's correctly exported from utils.ts and imported in payment.test.ts
  • Used appropriately in payment tests to determine minimum reserve requirement
  • No conflicts with other fee-related functions in the test utilities
  • Implementation follows the codebase's patterns for fee handling
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check integration of fetchAccountReserveFee with payment tests and other utilities

# Test 1: Check if the function is used in payment tests
echo "Checking usage in payment tests..."
rg -l "fetchAccountReserveFee" "packages/xrpl/test/integration/transactions/"

# Test 2: Check for potential conflicts with other fee-related functions
echo "Checking for related fee functions..."
rg -l "Fee|fee" "packages/xrpl/test/integration/"

# Test 3: Check if the function is properly exported and imported
echo "Checking exports and imports..."
rg -l "export.*fetchAccountReserveFee|import.*fetchAccountReserveFee" "packages/xrpl/test/"

Length of output: 1296


Script:

#!/bin/bash
# Check the actual usage of fetchAccountReserveFee in payment.test.ts
echo "Checking usage context in payment.test.ts..."
rg -B 2 -A 2 "fetchAccountReserveFee" "packages/xrpl/test/integration/transactions/payment.test.ts"

# Check the implementation of related fee functions in utils.ts
echo -e "\nChecking related fee functions in utils.ts..."
rg "Fee|fee" "packages/xrpl/test/integration/utils.ts"

Length of output: 915

Comment on lines +41 to +43
// Make sure the amount sent satisfies minimum reserve requirement to fund an account.
amount =
(await fetchAccountReserveFee(testContext.client)) ?? DEFAULT_AMOUNT
Copy link

@coderabbitai coderabbitai bot Oct 25, 2024

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding error handling for fetchAccountReserveFee.

While the fallback to DEFAULT_AMOUNT is good, it would be beneficial to add error handling and logging to understand when and why the fetch fails. This helps with test debugging and maintenance.

    // Make sure the amount sent satisfies minimum reserve requirement to fund an account.
-    amount =
-      (await fetchAccountReserveFee(testContext.client)) ?? DEFAULT_AMOUNT
+    try {
+      amount = await fetchAccountReserveFee(testContext.client)
+      if (!amount) {
+        console.warn('Failed to fetch account reserve fee, using default amount')
+        amount = DEFAULT_AMOUNT
+      }
+    } catch (error) {
+      console.warn(`Error fetching account reserve fee: ${error.message}`)
+      amount = DEFAULT_AMOUNT
+    }
📝 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
// Make sure the amount sent satisfies minimum reserve requirement to fund an account.
amount =
(await fetchAccountReserveFee(testContext.client)) ?? DEFAULT_AMOUNT
// Make sure the amount sent satisfies minimum reserve requirement to fund an account.
try {
amount = await fetchAccountReserveFee(testContext.client)
if (!amount) {
console.warn('Failed to fetch account reserve fee, using default amount')
amount = DEFAULT_AMOUNT
}
} catch (error) {
console.warn(`Error fetching account reserve fee: ${error.message}`)
amount = DEFAULT_AMOUNT
}

Copy link

Choose a reason for hiding this comment

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

@ckeshava, you make a valid point. Since the XRPL mainnet can vote for arbitrary fee values, we should not default to any specific amount. Instead, we should throw an error if we're unable to retrieve the fees from the latest validated ledger.

Here's how we can adjust the code:

// Remove the DEFAULT_AMOUNT constant
// const DEFAULT_AMOUNT = '10000000';

// Update the code to throw an error if fetching the amount fails
beforeAll(async () => {
  testContext = await setupClient(serverUrl)
  senderWallet = await generateFundedWallet(testContext.client)
  // Fetch the account reserve fee
  amount = await fetchAccountReserveFee(testContext.client)
  if (!amount) {
    throw new Error('Failed to fetch account reserve fee from the latest validated ledger.')
  }
})

This change ensures that if we are unable to retrieve the fee from the latest validated ledger, the test will fail, making us aware of the issue rather than using a potentially incorrect default amount.

(・_・)


✏️ Learnings added
Learnt from: ckeshava
PR: XRPLF/xrpl.js#2812
File: packages/xrpl/test/integration/transactions/payment.test.ts:41-43
Timestamp: 2024-10-30T01:05:33.417Z
Learning: In tests involving fee calculations for XRPL, avoid using default fee amounts. If unable to retrieve fee values from the latest validated ledger, throw an error instead of defaulting to a specific amount.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment on lines 449 to 460
export async function fetchAccountReserveFee(
client: Client,
): Promise<string | null> {
const response = await client.request({ command: 'server_state' })
const fee = response.result.state.validated_ledger?.reserve_inc

if (fee == null) {
return null
}

return new BigNumber(fee).dp(0, BigNumber.ROUND_CEIL).toString(10)
}
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 error handling and type safety in fetchAccountReserveFee.

While the implementation aligns with the PR objectives to support dynamic fee calculations, consider these improvements:

  1. Add error handling for failed requests
  2. Add type safety for the response structure
  3. Add validation for negative values

Here's a suggested implementation with these improvements:

+interface ServerState {
+  result: {
+    state: {
+      validated_ledger?: {
+        reserve_inc?: string
+      }
+    }
+  }
+}

 export async function fetchAccountReserveFee(
   client: Client,
 ): Promise<string | null> {
-  const response = await client.request({ command: 'server_state' })
-  const fee = response.result.state.validated_ledger?.reserve_inc
+  try {
+    const response = await client.request({ command: 'server_state' }) as ServerState
+    const fee = response.result.state.validated_ledger?.reserve_inc

+    if (fee == null) {
+      return null
+    }

+    const feeBN = new BigNumber(fee)
+    if (feeBN.isNegative()) {
+      throw new Error('Reserve fee cannot be negative')
+    }

+    return feeBN.dp(0, BigNumber.ROUND_CEIL).toString(10)
+  } catch (error) {
+    if (error instanceof Error) {
+      throw new Error(`Failed to fetch reserve fee: ${error.message}`)
+    }
+    throw new Error('Failed to fetch reserve fee')
+  }
-  if (fee == null) {
-    return null
-  }
-
-  return new BigNumber(fee).dp(0, BigNumber.ROUND_CEIL).toString(10)
 }
📝 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 async function fetchAccountReserveFee(
client: Client,
): Promise<string | null> {
const response = await client.request({ command: 'server_state' })
const fee = response.result.state.validated_ledger?.reserve_inc
if (fee == null) {
return null
}
return new BigNumber(fee).dp(0, BigNumber.ROUND_CEIL).toString(10)
}
interface ServerState {
result: {
state: {
validated_ledger?: {
reserve_inc?: string
}
}
}
}
export async function fetchAccountReserveFee(
client: Client,
): Promise<string | null> {
try {
const response = await client.request({ command: 'server_state' }) as ServerState
const fee = response.result.state.validated_ledger?.reserve_inc
if (fee == null) {
return null
}
const feeBN = new BigNumber(fee)
if (feeBN.isNegative()) {
throw new Error('Reserve fee cannot be negative')
}
return feeBN.dp(0, BigNumber.ROUND_CEIL).toString(10)
} catch (error) {
if (error instanceof Error) {
throw new Error(`Failed to fetch reserve fee: ${error.message}`)
}
throw new Error('Failed to fetch reserve fee')
}
}

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: 0

🧹 Outside diff range and nitpick comments (1)
packages/xrpl/test/integration/utils.ts (1)

449-460: Consider moving this utility to the main library.

Given that this function provides essential fee-related functionality aligned with the PR objectives, consider moving it from the test utilities to the main library (e.g., packages/xrpl/src/utils/). This would make it available for production use and maintain consistency with the library's fee calculation capabilities.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between bb3156d and 80a6d1f.

📒 Files selected for processing (1)
  • packages/xrpl/test/integration/utils.ts (2 hunks)
🔇 Additional comments (2)
packages/xrpl/test/integration/utils.ts (2)

449-460: LGTM with suggestions for improvement.

The implementation aligns with the PR objectives to support dynamic fee calculations by fetching the reserve fee from the server state. The previous review comment about enhancing error handling and type safety is still applicable.


449-460: Verify integration with fee-related changes.

Let's verify how this function is integrated with other fee-related changes in the codebase.

✅ Verification successful

Let me gather more context about the payment test integration to understand how the function is being used.


Based on the gathered information, I can now provide the final response:

Function is properly integrated and used in payment tests

The fetchAccountReserveFee function is:

  • Correctly implemented using the server_state command
  • Integrated into payment tests for reserve fee calculations
  • Part of the broader fee-related changes across the codebase (as evidenced by related fee calculation files)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check usage of fetchAccountReserveFee and related fee calculations

# Check for direct usage of fetchAccountReserveFee
echo "Checking direct usage of fetchAccountReserveFee:"
rg "fetchAccountReserveFee"

# Check for related fee calculation changes
echo -e "\nChecking related fee calculation changes:"
rg -l "calculateFeePerTransaction|FeeSettings|base_fee"

# Check for test coverage
echo -e "\nChecking test coverage:"
rg -l "fetchAccountReserveFee.*test"

Length of output: 3744


Script:

#!/bin/bash
# Check the payment test implementation
echo "Checking payment test implementation:"
rg -A 10 "fetchAccountReserveFee" packages/xrpl/test/integration/transactions/payment.test.ts

# Check server_state implementation
echo -e "\nChecking server_state implementation:"
ast-grep --pattern 'command: "server_state"'

Length of output: 914

@mvadari
Copy link
Collaborator

mvadari commented Oct 25, 2024

nit: this PR name should be changed - it has nothing to do with the FeeSettings object.

@pdp2121 pdp2121 changed the title FeeSettings updates Adjustments for fee voting Oct 28, 2024
.ci-config/rippled.cfg Outdated Show resolved Hide resolved
packages/xrpl/src/sugar/autofill.ts Outdated Show resolved Hide resolved
@@ -260,15 +260,14 @@ export async function calculateFeePerTransactionType(
tx: Transaction,
signersCount = 0,
): Promise<void> {
// netFee is usually 0.00001 XRP (10 drops)
const netFeeXRP = await getFeeXrp(client)
const netFeeDrops = xrpToDrops(netFeeXRP)
let baseFee = new BigNumber(netFeeDrops)

// EscrowFinish Transaction with Fulfillment
if (tx.TransactionType === 'EscrowFinish' && tx.Fulfillment != null) {
const fulfillmentBytesSize: number = Math.ceil(tx.Fulfillment.length / 2)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you know why we are dividing the tx.Fulfillment.length by 2 ? I know that you didn't write this code, but I didn't understand it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is from the docs:

The minimum transaction cost to submit an EscrowFinish transaction increases if it contains a fulfillment. If the transaction has no fulfillment, the transaction cost is the standard 10 drops. If the transaction contains a fulfillment, the transaction cost is 330 drops of XRP plus another 10 drops for every 16 bytes in size of the preimage.

The division by 2 is due to the fact that each byte is represented by 2 characters in hex

tx.TransactionType === 'AccountDelete'
? baseFee
: BigNumber.min(baseFee, maxFeeDrops)
const totalFee = ['AccountDelete', 'AMMCreate'].includes(tx.TransactionType)
Copy link
Collaborator

Choose a reason for hiding this comment

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

What is the need for this comparison with maxFeeDrops ( == 2,000,000 drops) ?

the baseFee variable computes the final fees, accounting for the cases where multiple-signers are provided.

Why are performing this arbitrary comparison with 2 XRP ? Moreover, we are not using any cushion value in the getFeeXrp() function call, hence there is no possibility of the library over-estimating the fees.

Copy link
Collaborator Author

@pdp2121 pdp2121 Nov 12, 2024

Choose a reason for hiding this comment

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

This part confuses me a bit as well since baseFee computed the final fee with multi-signers accounted so not sure why we need this comparison.
@khancode could you explain why since you wrote this code a while ago in this PR
Btw, cushion is defaulted to 1.2 if not set.

packages/xrpl/src/sugar/autofill.ts Outdated Show resolved Hide resolved
minimum_fee: '10',
open_ledger_fee: '10',
base_fee: referenceFee,
median_fee: new BigNumber(referenceFee)
Copy link
Collaborator

Choose a reason for hiding this comment

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

We can omit the median_fee field from the deep-equality comparison. Quoting from the docs: An approximation of the median transaction cost among transactions included in the previous validated ledger, represented in drops of XRP.

Since this value depends on the transactions-mix of the previous validated ledger, it is not informative for integration test status. Docs: https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/server-info-methods/fee#response-format

Destination: 'rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy',
}
})

beforeAll(async () => {
testContext = await setupClient(serverUrl)
senderWallet = await generateFundedWallet(testContext.client)
// Make sure the amount sent satisfies minimum reserve requirement to fund an account.
amount =
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hello,
The intention in these tests is not to fund an account into existence. Hence, the Amount field could be any positive value, it does not have to be above the reserve requirement.

It looks like the amount value is always equal to DEFAULT_AMOUNT. So, I don't see a need for another amount variable.

Are changes in this file required? I don't this file is impacted by the fee-change-calculation updates

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It is because the first payment transaction in this test Validate Payment transaction API v2: Payment Transaction: Specify Only Amount field will create the hardcoded account rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy, which does not exist beforehand. So if we increase account_reserve = 20000000 instead of 10XRP then all payment transactions in these tests will fail:
xrpl: Message: xrpl: Destination does not exist. Too little XRP sent to create it.: expected 'tecNO_DST_INSUF_XRP' to equal 'tesSUCCESS'

Hence we either have to make this first payment to be at least the account_reserve or setup a destination account before sending payments

@@ -444,3 +445,16 @@ export async function createAMMPool(client: Client): Promise<{
asset2,
}
}

export async function fetchAccountReserveFee(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of creating a new function, can we re-use the one from packages/xrpl/src/sugar/autofill.ts ? Its titled fetchOwnerReserve

This will improve the test-coverage of the function which is already in the main codebase.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hi Chenna, OwnerReserve and AccountReserve refers to 2 different fees. One would be reserve_inc and the other reserve_base.
Please refer to: https://xrpl.org/docs/references/protocol/ledger-data/ledger-entry-types/feesettings

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 (2)
.ci-config/rippled.cfg (1)

183-186: Consider adding parameter validation ranges

To prevent configuration errors, consider adding comments documenting the valid ranges for each parameter. This would help prevent issues when testing different fee scenarios.

Example:

 [voting]
-reference_fee = 200           # 200 drops
+reference_fee = 200           # 200 drops (valid range: 10-1000)
-account_reserve = 20000000   # 20 XRP
+account_reserve = 20000000   # 20 XRP (valid range: 10-50 XRP)
-owner_reserve = 5000000      # 5 XRP
+owner_reserve = 5000000      # 5 XRP (valid range: 1-10 XRP)
packages/xrpl/src/sugar/autofill.ts (1)

Line range hint 233-248: LGTM! Consider improving error message.

The function renaming and implementation look good. The error handling is appropriate, but the error message could be more descriptive.

Consider updating the error message to be more specific:

-    return Promise.reject(new Error('Could not fetch Owner Reserve.'))
+    return Promise.reject(new Error('Could not fetch Owner Reserve from server state.'))
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 80a6d1f and d907ce5.

📒 Files selected for processing (2)
  • .ci-config/rippled.cfg (1 hunks)
  • packages/xrpl/src/sugar/autofill.ts (2 hunks)
🔇 Additional comments (3)
.ci-config/rippled.cfg (1)

182-186: LGTM! The new [voting] section aligns with fee voting objectives.

The configuration values match the expected changes:

  • reference_fee of 200 drops aligns with mainnet UNL validators' voting
  • Clear documentation of values in both drops and XRP
  • Enables testing of different fee scenarios
packages/xrpl/src/sugar/autofill.ts (2)

278-283: LGTM! Good refactoring.

The introduction of isSpecialTxCost variable eliminates code duplication and improves readability.


295-301: Verify maxFeeDrops comparison necessity and optimize rounding.

The comparison with maxFeeDrops for non-special transactions needs verification. Additionally, the rounding operation could be optimized.

Let's verify the necessity of maxFeeDrops comparison:

Consider optimizing the rounding operation:

-  const totalFee = isSpecialTxCost
-    ? baseFee
-    : BigNumber.min(baseFee, maxFeeDrops)
-  tx.Fee = totalFee.dp(0, BigNumber.ROUND_CEIL).toString(10)
+  tx.Fee = (isSpecialTxCost ? baseFee : BigNumber.min(baseFee, maxFeeDrops))
+    .integerValue(BigNumber.ROUND_CEIL)
+    .toString(10)

Comment on lines 270 to 275
// BaseFee × (33 + (Fulfillment size in bytes / 16))
const product = new BigNumber(
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- expected use of magic numbers
scaleValue(netFeeDrops, 33 + fulfillmentBytesSize / 16),
)
baseFee = product.dp(0, BigNumber.ROUND_CEIL)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix premature rounding and document Fulfillment size calculation.

Two issues need attention:

  1. The rounding operation product.dp(0, BigNumber.ROUND_CEIL) is premature and could lead to precision loss.
  2. The Fulfillment length division needs documentation.
     const fulfillmentBytesSize: number = Math.ceil(tx.Fulfillment.length / 2)
+    // Divide by 2 because Fulfillment is hex-encoded (2 characters per byte)
     // BaseFee × (33 + (Fulfillment size in bytes / 16))
     const product = new BigNumber(
       scaleValue(netFeeDrops, 33 + fulfillmentBytesSize / 16),
     )
-    baseFee = product.dp(0, BigNumber.ROUND_CEIL)
+    baseFee = product

Committable suggestion skipped: line range outside the PR's diff.

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: 0

🧹 Outside diff range and nitpick comments (2)
packages/xrpl/src/sugar/autofill.ts (2)

277-279: Consider a more descriptive variable name.

The variable name isSpecialTxCost could be more specific about what makes these transactions special. Consider requiresOwnerReserveFee or usesReserveAsFee to better reflect its purpose.

-  const isSpecialTxCost = ['AccountDelete', 'AMMCreate'].includes(
+  const requiresOwnerReserveFee = ['AccountDelete', 'AMMCreate'].includes(
     tx.TransactionType,
   )

Line range hint 239-248: Consider validating fee values against voting outcomes.

Given that this PR is related to fee voting changes, consider adding validation to ensure the fetched owner reserve fee aligns with expected voting outcomes. This could help catch unexpected fee values early.

Consider adding validation like:

 async function fetchOwnerReserveFee(client: Client): Promise<BigNumber> {
   const response = await client.request({ command: 'server_state' })
   const fee = response.result.state.validated_ledger?.reserve_inc

   if (fee == null) {
     return Promise.reject(new Error('Could not fetch Owner Reserve.'))
   }

+  // Validate fee against expected range from fee voting
+  const feeValue = new BigNumber(fee)
+  if (feeValue.isLessThan(0)) {
+    return Promise.reject(new Error('Invalid negative owner reserve fee'))
+  }

   return new BigNumber(fee)
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d907ce5 and a36a8f0.

📒 Files selected for processing (1)
  • packages/xrpl/src/sugar/autofill.ts (2 hunks)
🔇 Additional comments (3)
packages/xrpl/src/sugar/autofill.ts (3)

233-239: LGTM! Clear and accurate documentation.

The function renaming from fetchAccountDeleteFee to fetchOwnerReserveFee better reflects its purpose, as it's used for both AccountDelete and AMMCreate transactions.


299-299: LGTM! Appropriate placement of rounding operation.

The rounding operation is correctly placed after all fee calculations are complete, which preserves precision throughout the calculations.


294-296: Verify the necessity of maxFeeDrops comparison.

Based on previous discussions, the comparison with maxFeeDrops might be unnecessary since baseFee already computes the final fee with multi-signers accounted for.

Let's analyze the codebase for the rationale behind this comparison:

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.

4 participants