Repository: Peersyst/xrpl-snap
Pull request #129: Fix tecPATH_PARTIAL : Add support for IOU Payments with issuer transfer fees (prevent tecPATH_PARTIAL)
Author: login: vriveraPeersyst
Labels: name: bug
description: Something isn't working
Created: 2025-05-17T12:30:08Z | Merged: 2025-05-22T07:39:47Z

<html><head></head><body><p><strong>Title:</strong><br>
Add support for IOU Payments with issuer transfer fees (prevent tecPATH_PARTIAL)</p>
<p><strong>Description:</strong></p>
<h2>Motivation 💡</h2>
<p>Sending IOU Payments of IOUs whose issuer applied a transfer fee was failing with <code inline="">tecPATH_PARTIAL</code> because we weren’t including the additional fee buffer or the partial-payment flag. This patch ensures the “full rate” (1 + fee) is used to compute <code inline="">SendMax</code> and sets <code inline="">tfPartialPayment</code> so payments don’t get path-partial errors.</p>
<h2>Affected packages 📦</h2>

Code | Package
-- | --
SITE | packages/site


<h2>Changes 🛠</h2>
<ul>
<li>
<p><strong>models/token/index.ts</strong></p>
<ul>
<li>
<p>Added optional <code inline="">transferRate?: number</code> to the <code inline="">Token</code> type.</p>
</li>
</ul>
</li>
<li>
<p><strong>data-access/repository/xrpl/XrplService.ts</strong></p>
<ul>
<li>
<p>Fetch each issuer’s <code inline="">TransferRate</code> via <code inline="">account_info</code>.</p>
</li>
<li>
<p>Validate it (must be ≥ 1 000 000 000 if present) and attach to token objects.</p>
</li>
</ul>
</li>
<li>
<p><strong>domain/transaction/controller/TransactionController.ts</strong></p>
<ul>
<li>
<p>When <code inline="">token.transferRate</code> is non-trivial, compute</p>
<pre><code class="language-js">fullRate = transferRate / 1_000_000_000;      // e.g. 1.002
sendMaxValue = amount × fullRate;             // e.g. 0.2004 for 0.2 + 0.2% fee
</code></pre>
</li>
<li>
<p>Pass <code inline="">sendMax: { … }</code> and <code inline="">flags: PARTIAL_PAYMENT_FLAG</code> to MetaMask so the ledger won’t error with <code inline="">tecPATH_PARTIAL</code>.</p>
</li>
</ul>
</li>
<li>
<p><strong>data-access/repository/metamask/MetaMaskRepository.ts</strong></p>
<ul>
<li>
<p>Map our <code inline="">sendMax</code> parameter to XRPL’s <code inline="">SendMax</code> field, and use property shorthand for <code inline="">flags</code>.</p>
</li>
</ul>
</li>
</ul>
<h2>Considerations 🤔</h2>
<ul>
<li>
<p>Tokens with <code inline="">transferRate</code> = <code inline="">undefined</code> or <code inline="">0</code> remain unchanged (no partial-payment flag).</p>
</li>
<li>
<p>We’ve preserved backwards compatibility: callers who don’t supply <code inline="">sendMax</code> will still send a normal IOU Payment.</p>
</li>
</ul>
<h2>Dependencies 📦</h2>
<ul>
<li>
<p>No external dependencies. Continuous integration and existing tests should now pass without <code inline="">tecPATH_PARTIAL</code> failures.</p>
</li>
</ul></body></html>
- [Main](https://github.com/Peersyst/xrpl-snap)


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Added support for transfer rates in IOU token transactions, allowing transfer fees to be accurately handled.
  - Introduced handling of partial payment flags for IOU transactions.

- **Bug Fixes**
  - Corrected a typo in the insufficient balance error code to ensure accurate error reporting.

- **Improvements**
  - Enhanced token information to display transfer rates when available.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/packages/site/src/common/constants/flags.ts b/packages/site/src/common/constants/flags.ts
new file mode 100644
index 00000000..0565c206
--- /dev/null
+++ b/packages/site/src/common/constants/flags.ts
@@ -0,0 +1 @@
+export const PARTIAL_PAYMENT_FLAG = 131072;
diff --git a/packages/site/src/common/models/token/index.ts b/packages/site/src/common/models/token/index.ts
index 2e76f663..aadbe931 100644
--- a/packages/site/src/common/models/token/index.ts
+++ b/packages/site/src/common/models/token/index.ts
@@ -4,6 +4,7 @@ export type Token = {
   decimals: number;
   issuer: string;
   currency: string;
+  transferRate?: number;
 };
 
 export type TokenWithBalance = Token & {
diff --git a/packages/site/src/common/utils/xrpl/transfer-rate.ts b/packages/site/src/common/utils/xrpl/transfer-rate.ts
index 8f0ce9cd..caab7d27 100644
--- a/packages/site/src/common/utils/xrpl/transfer-rate.ts
+++ b/packages/site/src/common/utils/xrpl/transfer-rate.ts
@@ -13,3 +13,12 @@ export function normalizeTransferRate(transferFee: number): number {
 
   return new BigNumber(transferFee).dividedBy(1_000_000).minus(1_000).dividedBy(10).toNumber();
 }
+
+/**
+ * Checks if a transfer rate is valid according to XRPL rules.
+ * 0 and undefined are "no fee", otherwise must be in [1000000000, 2000000000]
+ * @param [rate] - The transfer rate to validate.
+ */
+export function isValidTransferRate(rate?: number): boolean {
+  return rate === undefined || rate === 0 || (typeof rate === 'number' && rate >= 1000000000 && rate <= 2000000000);
+}
diff --git a/packages/site/src/data-access/repository/metamask/MetaMaskRepository.ts b/packages/site/src/data-access/repository/metamask/MetaMaskRepository.ts
index 02e02cbd..398a790b 100644
--- a/packages/site/src/data-access/repository/metamask/MetaMaskRepository.ts
+++ b/packages/site/src/data-access/repository/metamask/MetaMaskRepository.ts
@@ -71,12 +71,16 @@ export class MetaMaskRepository {
 
   async send({
     amount,
+    sendMax,
     destination,
     destinationTag,
+    flags,
   }: {
     destination: string;
     amount: XrplAmount;
+    sendMax?: XrplAmount;
     destinationTag?: number;
+    flags?: number;
   }): Promise<string> {
     return await withMetaMaskError(async () => {
       const { account } = await this.getWallet();
@@ -89,6 +93,8 @@ export class MetaMaskRepository {
           Destination: destination,
           DestinationTag: destinationTag,
           Amount: amount,
+          SendMax: sendMax,
+          Flags: flags,
         },
       });
 
diff --git a/packages/site/src/data-access/repository/xrpl/XrplService.ts b/packages/site/src/data-access/repository/xrpl/XrplService.ts
index a35808d1..26f92348 100644
--- a/packages/site/src/data-access/repository/xrpl/XrplService.ts
+++ b/packages/site/src/data-access/repository/xrpl/XrplService.ts
@@ -129,7 +129,6 @@ export class XrplService {
     const client = await this.getClient();
     try {
       let res = await client.request({ command: 'account_lines', account });
-
       const { lines } = res.result;
 
       while (res.result.marker && res.result.lines.length > 0) {
@@ -142,19 +141,19 @@ export class XrplService {
       }
 
       const tokenWithBalances: TokenWithBalance[] = [];
-
       for (const line of lines) {
         try {
+          const issuer = line.account;
           const token = {
             currency: line.currency,
-            issuer: line.account,
+            issuer,
             decimals: 15,
           };
           tokenWithBalances.push({
             ...token,
             balance: Amount.fromDecToken(new Decimal(line.balance).toFixed(14), token),
           });
-        } catch {}
+        } catch (err) {}
       }
 
       return tokenWithBalances;
diff --git a/packages/site/src/domain/transaction/controller/TransactionController.ts b/packages/site/src/domain/transaction/controller/TransactionController.ts
index 75b8d29a..a1236f92 100644
--- a/packages/site/src/domain/transaction/controller/TransactionController.ts
+++ b/packages/site/src/domain/transaction/controller/TransactionController.ts
@@ -1,13 +1,16 @@
 import { polling } from '@peersyst/react-utils';
 import { config } from 'common/config';
+import { PARTIAL_PAYMENT_FLAG } from 'common/constants/flags';
 import type { SendParams } from 'common/models/transaction/send.types';
 import { TransactionsWithMarker, XrplTx } from 'common/models/transaction/tx.types';
 import { withRetries } from 'common/query';
 import type Amount from 'common/utils/Amount';
 import { TransactionMeta } from 'common/utils/xrpl/meta';
+import { isValidTransferRate } from 'common/utils/xrpl/transfer-rate';
+import Decimal from 'decimal.js';
 import { DomainError } from 'domain/error/DomainError';
 import { DomainEvents } from 'domain/events';
-import { xrpToDrops } from 'xrpl';
+import { xrpToDrops, transferRateToDecimal } from 'xrpl';
 
 import type { MetaMaskRepository } from '../../../data-access/repository/metamask/MetaMaskRepository';
 import type { XrplService } from '../../../data-access/repository/xrpl/XrplService';
@@ -25,11 +28,9 @@ export default class TransactionController {
       );
 
       const payments = res.result.transactions.reduce<XrplTx[]>((acc, { tx, meta }) => {
-        // eslint-disable-next-line no-implicit-coercion
         if (tx && typeof meta === 'object' && meta.TransactionResult === 'tesSUCCESS') {
           acc.push({ ...tx, meta: new TransactionMeta(meta) });
         }
-
         return acc;
       }, []);
 
@@ -45,10 +46,6 @@ export default class TransactionController {
     }
   }
 
-  /**
-   * Checks if a transaction is validated
-   * @param hash - Hash of the transaction
-   */
   public async isTransactionValidated(hash: string): Promise<boolean> {
     try {
       const tx = await this.xrplService.getTransaction(hash);
@@ -62,10 +59,6 @@ export default class TransactionController {
     }
   }
 
-  /**
-   * Await for a transaction to be validated
-   * @param hash - Hash of the transaction
-   */
   public async awaitTransactionValidation(hash: string): Promise<void> {
     await polling(
       async () => this.isTransactionValidated(hash),
@@ -81,7 +74,7 @@ export default class TransactionController {
     const availableAmount: Amount = token.balance;
 
     if (!availableAmount.canPay(amount)) {
-      throw new DomainError(TransactionErrorCodes.INSUCCICIENT_BALANCE);
+      throw new DomainError(TransactionErrorCodes.INSUFFICIENT_BALANCE);
     }
 
     return await this.metamaskRepository.send({
@@ -94,7 +87,36 @@ export default class TransactionController {
     const availableAmount: Amount = token.balance;
 
     if (!availableAmount.canPay(amount)) {
-      throw new DomainError(TransactionErrorCodes.INSUCCICIENT_BALANCE);
+      throw new DomainError(TransactionErrorCodes.INSUFFICIENT_BALANCE);
+    }
+
+    let { transferRate } = token;
+    if (transferRate === undefined) {
+      try {
+        const info = await this.xrplService.getAccountInfo(token.issuer);
+        transferRate = info.TransferRate;
+      } catch {
+        transferRate = undefined;
+      }
+    }
+
+    if (isValidTransferRate(transferRate) && transferRate !== undefined && transferRate !== 0 && transferRate !== 1000000000) {
+      const sendMaxValue = this.computeTransferRate(amount, transferRate);
+
+      return await this.metamaskRepository.send({
+        ...rest,
+        amount: {
+          currency: token.currency,
+          value: amount,
+          issuer: token.issuer,
+        },
+        sendMax: {
+          currency: token.currency,
+          value: sendMaxValue,
+          issuer: token.issuer,
+        },
+        flags: PARTIAL_PAYMENT_FLAG,
+      });
     }
 
     return await this.metamaskRepository.send({
@@ -107,6 +129,19 @@ export default class TransactionController {
     });
   }
 
+  /**
+   * Computes the sendMax value required to cover the issuer's transfer rate fee.
+   * This ensures the recipient receives the intended amount after the transfer fee is deducted.
+   * See: https://xrpl.org/docs/concepts/tokens/transfer-fees
+   * @param amount - The intended amount to send.
+   * @param transferRate - The issuer's transfer rate.
+   */
+  private computeTransferRate(amount: string, transferRate: number): string {
+    const feeDecimal = new Decimal(transferRateToDecimal(transferRate));
+    const fullRateDecimal = feeDecimal.plus(1);
+    return new Decimal(amount).mul(fullRateDecimal).toString(); // keep all significant decimals
+  }
+
   async sendTransaction(params: SendParams): Promise<string> {
     const { token } = params;
     let hash = '';
diff --git a/packages/site/src/domain/transaction/error/TransactionErrorCodes.ts b/packages/site/src/domain/transaction/error/TransactionErrorCodes.ts
index 50b26619..d2eac6a2 100644
--- a/packages/site/src/domain/transaction/error/TransactionErrorCodes.ts
+++ b/packages/site/src/domain/transaction/error/TransactionErrorCodes.ts
@@ -1,3 +1,3 @@
 export enum TransactionErrorCodes {
-  INSUCCICIENT_BALANCE = 'INSUCCICIENT_BALANCE',
+  INSUFFICIENT_BALANCE = 'INSUFFICIENT_BALANCE',
 }


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 4**

<details>
<summary>🧹 Nitpick comments (3)</summary><blockquote>

<details>
<summary>packages/site/src/data-access/repository/xrpl/XrplService.ts (3)</summary><blockquote>

`10-13`: **Well-designed helper function for transfer rate validation**

The `isValidTransferRate` function correctly validates that transfer rates are either undefined/0 (meaning no fee) or within the XRPL-required range of [1,000,000,000, 2,000,000,000].


Consider adding a brief comment explaining why this specific range is required by XRPL, or use named constants to improve code readability:

```diff
+// XRPL transfer rates are specified in parts-per-billion, with 1 billion (1,000,000,000) representing no fee
+const NO_FEE_TRANSFER_RATE = 1000000000;
+const MAX_TRANSFER_RATE = 2000000000; // Represents a 100% fee

function isValidTransferRate(rate?: number): boolean {
  // 0 and undefined are "no fee", otherwise must be in [1000000000, 2000000000]
-  return rate === undefined || rate === 0 || (typeof rate === 'number' && rate >= 1000000000 && rate <= 2000000000);
+  return rate === undefined || rate === 0 || (typeof rate === 'number' && rate >= NO_FEE_TRANSFER_RATE && rate <= MAX_TRANSFER_RATE);
}
```

---

`150-170`: **Efficiently implemented issuer transfer rate caching**

The implementation correctly caches issuer transfer rates to avoid redundant network requests, which is an important optimization for performance. The code also properly validates the transfer rates using the helper function.


Consider enhancing the error handling in the validation check to provide more context about invalid transfer rates:

```diff
if (!isValidTransferRate(transferRate)) {
-  // Optionally: log a warning or skip this token
+  console.warn(`Invalid transfer rate ${transferRate} for issuer ${issuer}. Valid rates should be 0 or between 1,000,000,000 and 2,000,000,000.`);
   transferRate = undefined;
}
```

---

`182-184`: **Enhanced error handling in token processing**

The error handling has been improved to catch errors during token processing. However, the errors are only commented as "Optionally log error" without actual logging.


Consider implementing actual error logging to help with debugging:

```diff
try {
  // token processing code
} catch (err) {
-  // Optionally log error
+  console.error(`Failed to process token line: ${JSON.stringify(line)}`, err);
}
```

And similarly for the catch block at the end of the method:

```diff
} catch (e) {
-  // Optionally log error
+  console.error(`Failed to fetch IOU tokens for account ${account}:`, e);
  return [];
}
```


Also applies to: 189-190

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 9f62c3b7fd132e7642b2a7cbcec18437a864d008 and 24294489bf49cce256004bfbea7801a4b5569aa4.

</details>

<details>
<summary>📒 Files selected for processing (5)</summary>

* `packages/site/src/common/models/token/index.ts` (1 hunks)
* `packages/site/src/data-access/repository/metamask/MetaMaskRepository.ts` (2 hunks)
* `packages/site/src/data-access/repository/xrpl/XrplService.ts` (2 hunks)
* `packages/site/src/domain/transaction/controller/TransactionController.ts` (3 hunks)
* `packages/site/src/domain/transaction/error/TransactionErrorCodes.ts` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (1)</summary>

<details>
<summary>packages/site/src/domain/transaction/controller/TransactionController.ts (1)</summary><blockquote>

<details>
<summary>packages/site/src/domain/error/DomainError.ts (1)</summary>

* `DomainError` (7-22)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: Build, lint, and test / Prepare
* GitHub Check: run-security-scan

</details>

<details>
<summary>🔇 Additional comments (6)</summary><blockquote>

<details>
<summary>packages/site/src/common/models/token/index.ts (1)</summary>

`7-7`: **Appropriate addition of transferRate property**

The optional `transferRate` property is correctly added to the `Token` type, which will enable handling IOU token issuer transfer fees. This aligns with the PR objective of supporting transactions with issuer-applied transfer fees.

</details>
<details>
<summary>packages/site/src/domain/transaction/error/TransactionErrorCodes.ts (1)</summary>

`2-2`: **Spelling correction properly implemented**

The enum value has been correctly renamed from `INSUCCICIENT_BALANCE` to `INSUFFICIENT_BALANCE`, fixing the spelling error.

</details>
<details>
<summary>packages/site/src/data-access/repository/metamask/MetaMaskRepository.ts (2)</summary>

`74-77`: **Correctly extended method signature for transfer fee support**

The `send` method's signature has been appropriately extended with the optional `sendMax` and `flags` parameters, which are necessary for handling IOU payments with issuer transfer fees.



Also applies to: 81-83

---

`96-97`: **Properly mapped parameters to XRPL transaction fields**

The parameters are correctly mapped to the XRPL transaction fields. The use of property shorthand syntax for `SendMax` and `Flags` is clean and matches the style of the existing code.

</details>
<details>
<summary>packages/site/src/data-access/repository/xrpl/XrplService.ts (1)</summary>

`176-176`: **Proper attachment of transfer rate to token object**

The transfer rate is correctly attached to the token object, which enables downstream code to calculate the proper `SendMax` amount for IOU payments with issuer transfer fees.

</details>
<details>
<summary>packages/site/src/domain/transaction/controller/TransactionController.ts (1)</summary>

`77-78`: **Typo fix looks good**

`INSUFFICIENT_BALANCE` is now consistently spelt – thanks for the cleanup.



Also applies to: 90-91

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-17T12:34:26Z
user: login: vriveraPeersyst
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-17T14:28:02Z
user: login: vriveraPeersyst
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-17T14:29:30Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-17T14:29:48Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-17T14:29:57Z
user: login: vriveraPeersyst
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-17T14:35:28Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-17T14:36:22Z
user: login: vriveraPeersyst
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-17T14:42:01Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-17T14:45:20Z
user: login: GuillemGarciaDev
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T09:40:09Z
user: login: JordiParraCrespo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-19T09:52:47Z
user: login: vriveraPeersyst
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T10:34:39Z
user: login: vriveraPeersyst
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T10:35:07Z
user: login: vriveraPeersyst
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T10:38:26Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>packages/site/src/common/utils/xrpl/transfer-rate.ts (1)</summary><blockquote>

`17-23`: **Well-implemented validation function for XRPL transfer rates.**

The new `isValidTransferRate` function correctly validates transfer rates according to XRPL rules. This is crucial for preventing the `tecPATH_PARTIAL` errors mentioned in the PR objectives.


For consistency, consider using the already defined `ZERO_TRANSFER_RATE` constant in the validation check:

```diff
export function isValidTransferRate(rate?: number): boolean {
-  return rate === undefined || rate === 0 || (typeof rate === 'number' && rate >= 1000000000 && rate <= 2000000000);
+  return rate === undefined || rate === 0 || (typeof rate === 'number' && rate >= ZERO_TRANSFER_RATE && rate <= 2000000000);
}
```

Also, consider defining a constant for the upper limit (2,000,000,000) for better maintainability.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 45f5e64d4acb394ed9b10f4c6a232563c20624ea and 0a732591c3d3655fbc0eb1df2e00670ca6d53c60.

</details>

<details>
<summary>📒 Files selected for processing (4)</summary>

* `packages/site/src/common/constants/flags.ts` (1 hunks)
* `packages/site/src/common/utils/xrpl/transfer-rate.ts` (1 hunks)
* `packages/site/src/data-access/repository/xrpl/XrplService.ts` (2 hunks)
* `packages/site/src/domain/transaction/controller/TransactionController.ts` (4 hunks)

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (1)</summary>

* packages/site/src/common/constants/flags.ts

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (2)</summary>

* packages/site/src/data-access/repository/xrpl/XrplService.ts
* packages/site/src/domain/transaction/controller/TransactionController.ts

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: Build, lint, and test / Build
* GitHub Check: Build, lint, and test / Lint
* GitHub Check: run-security-scan

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-19T10:54:30Z
user: login: vriveraPeersyst
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T10:58:19Z
user: login: vriveraPeersyst
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T10:58:27Z
user: login: vriveraPeersyst
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T11:31:17Z

Review comments:
diff_hunk: @@ -94,7 +87,28 @@ export default class TransactionController {
     const availableAmount: Amount = token.balance;
 
     if (!availableAmount.canPay(amount)) {
-      throw new DomainError(TransactionErrorCodes.INSUCCICIENT_BALANCE);
+      throw new DomainError(TransactionErrorCodes.INSUFFICIENT_BALANCE);
+    }
+
+    if (token.transferRate !== undefined && token.transferRate !== 0 && token.transferRate !== 1000000000) {
+      const feeDecimal = new Decimal(transferRateToDecimal(token.transferRate));
+      const fullRateDecimal = feeDecimal.plus(1);
+      const sendMaxValue = new Decimal(amount).mul(fullRateDecimal).toFixed();
+
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**`toFixed()` silently drops the fractional part – the computed `SendMax` is wrong**

`Decimal#toFixed()` defaults to `0` decimal places, so  
`10.1234 * 1.02 → "10"` instead of `"10.325"`.

```diff
-const sendMaxValue = new Decimal(amount).mul(fullRateDecimal).toFixed();
+const sendMaxValue = new Decimal(amount)
+  .mul(fullRateDecimal)
+  // keep all significant decimals; XRPL accepts stringified numbers
+  .toString();
```

An underestimated `SendMax` defeats the whole purpose of adding a fee buffer and can still yield `tecPATH_PARTIAL`.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In packages/site/src/domain/transaction/controller/TransactionController.ts
around lines 93 to 97, the use of Decimal#toFixed() without specifying decimal
places causes the fractional part to be dropped, resulting in an incorrect
SendMax value. To fix this, specify the appropriate number of decimal places in
toFixed() to preserve the fractional part and ensure the fee buffer is correctly
applied.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-17T12:34:25Z
author_association: NONE
diff_hunk: @@ -94,7 +87,28 @@
     const availableAmount: Amount = token.balance;
 
     if (!availableAmount.canPay(amount)) {
-      throw new DomainError(TransactionErrorCodes.INSUCCICIENT_BALANCE);
+      throw new DomainError(TransactionErrorCodes.INSUFFICIENT_BALANCE);
+    }
+
+    if (token.transferRate !== undefined && token.transferRate !== 0 && token.transferRate !== 1000000000) {
+      const feeDecimal = new Decimal(transferRateToDecimal(token.transferRate));
+      const fullRateDecimal = feeDecimal.plus(1);
+      const sendMaxValue = new Decimal(amount).mul(fullRateDecimal).toFixed();
+
+      return await this.metamaskRepository.send({
+        ...rest,
+        amount: {
+          currency: token.currency,
+          value: amount,
+          issuer: token.issuer,
+        },
+        sendMax: {
+          currency: token.currency,
+          value: sendMaxValue,
+          issuer: token.issuer,
+        },
+        flags: PARTIAL_PAYMENT_FLAG,
+      });
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Overwriting caller-supplied flags discards custom behaviour**

`...rest` might already contain a `flags` property.  
By hard-setting `flags: PARTIAL_PAYMENT_FLAG` you lose any extra bits the caller intended.

```diff
-      return await this.metamaskRepository.send({
+      const combinedFlags =
+        typeof rest.flags === 'number'
+          ? rest.flags | PARTIAL_PAYMENT_FLAG
+          : PARTIAL_PAYMENT_FLAG;
+
+      return await this.metamaskRepository.send({
         ...rest,
         ...
-        flags: PARTIAL_PAYMENT_FLAG,
+        flags: combinedFlags,
       });
```

This keeps the partial-payment requirement while preserving external flags.



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **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.

```suggestion
      const combinedFlags =
        typeof rest.flags === 'number'
          ? rest.flags | PARTIAL_PAYMENT_FLAG
          : PARTIAL_PAYMENT_FLAG;

      return await this.metamaskRepository.send({
        ...rest,
        amount: {
          currency: token.currency,
          value: amount,
          issuer: token.issuer,
        },
        sendMax: {
          currency: token.currency,
          value: sendMaxValue,
          issuer: token.issuer,
        },
        flags: combinedFlags,
      });
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In packages/site/src/domain/transaction/controller/TransactionController.ts
around lines 98 to 111, the code overwrites any caller-supplied flags by
hard-setting flags to PARTIAL_PAYMENT_FLAG, which discards custom behavior. To
fix this, merge the existing flags from rest with PARTIAL_PAYMENT_FLAG using a
bitwise OR operation, ensuring the partial payment flag is set while preserving
any flags provided by the caller.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-17T12:34:26Z
author_association: NONE
diff_hunk: @@ -94,7 +87,28 @@
     const availableAmount: Amount = token.balance;
 
     if (!availableAmount.canPay(amount)) {
-      throw new DomainError(TransactionErrorCodes.INSUCCICIENT_BALANCE);
+      throw new DomainError(TransactionErrorCodes.INSUFFICIENT_BALANCE);
+    }
+
+    if (token.transferRate !== undefined && token.transferRate !== 0 && token.transferRate !== 1000000000) {
+      const feeDecimal = new Decimal(transferRateToDecimal(token.transferRate));
+      const fullRateDecimal = feeDecimal.plus(1);
+      const sendMaxValue = new Decimal(amount).mul(fullRateDecimal).toFixed();
+
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Double-adding the fee? Re-check the semantics**

`fullRateDecimal = feeDecimal.plus(1)` assumes `transferRateToDecimal` returns _only_ the fee
(e.g. `0.02`).  
If it already returns the full multiplier (`1.02`), the send-max inflates the payment (`+1.00`).

Please confirm the helper’s behaviour and drop the extra `+ 1` if unnecessary.

---

```bash
#!/bin/bash
set -e
# Locate the definition and usages of transferRateToDecimal with context
rg -n "transferRateToDecimal" -C3
```

---

```bash
#!/bin/bash
set -e
# Search for the definition and usage of transferRateToDecimal
rg -n "transferRateToDecimal" -C5
```

---

🏁 Script executed:

```shell
#!/bin/bash
set -e
# Find the definition and comment/documentation of transferRateToDecimal
rg -n "transferRateToDecimal" -C5
```

Length of output: 2784

---

🌐 Web query:

```web
What is the behavior of transferRateToDecimal in the XRPL JavaScript SDK? Does it return the full rate multiplier (e.g., 1.02 for a 2% fee) or only the fee portion (e.g., 0.02)?
```

💡 Result:

## Behavior of `transferRateToDecimal` in the XRPL JavaScript SDK

**Summary:**  
The `transferRateToDecimal` function in the XRPL JavaScript SDK (`xrpl.js`) converts a transfer rate specified in the XRPL's "billionths" format (the `TransferRate` field) into a decimal representation. It returns the **full rate multiplier**—for example, for a 2% fee, it returns `1.02` (not `0.02`).

---

### Details

- The XRPL represents transfer fees using the `TransferRate` field, which is an integer where a value of `1000000000` means "no fee" (1.00 multiplier), `1010000000` means a 1% fee (1.01 multiplier), and so on[6].
- The `transferRateToDecimal` function takes this number (in "billionths") and converts it to a standard decimal string[1].
- For example:
  - `transferRateToDecimal(1000000000)` returns `"1"`
  - `transferRateToDecimal(1020000000)` returns `"1.02"` (which means a 2% fee multiplier)

> Converts a transfer rate in "billionths" format to a decimal.  
> **Returns:** string[1]

### Interpretation

- **Returned value:** The function returns the full multiplier, including 1. So for a 2% transfer fee, it returns `1.02`, representing 102% of the amount being sent.
- **Not just the fee:** It does **not** return only the fee portion (like `0.02` for 2%).  
- **Usage:** To get just the fee as a decimal, you could subtract 1 from the result:  
  For example, `parseFloat(transferRateToDecimal(rate)) - 1` yields just the fee portion.

---

### Example

If the transfer rate (`TransferRate` field) is `1020000000`:

- `xrpl.transferRateToDecimal(1020000000)`  
  **returns:** `"1.02"` (the full multiplier)[1][6]

---

## Conclusion

**`transferRateToDecimal` returns the full rate multiplier (e.g., `1.02` for a 2% fee), not just the fee portion (e.g., `0.02`).**  
If you need only the fee, subtract 1 from the returned value[1][6].

Citations:

- 1: https://js.xrpl.org/functions/transferRateToDecimal.html
- 2: https://js.xrpl.org
- 3: https://js.xrpl.org/classes/Client.html
- 4: https://xrpl.org/docs/tutorials/javascript/build-apps/get-started
- 5: https://xrpl.org/docs/tutorials/how-tos/send-xrp
- 6: https://xrpl.org/docs/concepts/tokens/transfer-fees
- 7: https://www.youtube.com/watch?v=mNcaNVECCpI
- 8: https://xrpl.org/resources/code-samples
- 9: https://github.com/XRPLF/xrpl-py
- 10: https://github.com/XRPLF/xrpl.js/blob/main/README.md?plain=1

---



</details>

**Remove the redundant “+1” on the transfer-rate multiplier**

The XRPL helper `transferRateToDecimal` already returns the full multiplier (e.g. `"1.02"` for a 2% fee), so adding 1 again inflates the send-max. Please update the calculation in `TransactionController.ts`:

• File: `packages/site/src/domain/transaction/controller/TransactionController.ts`  
• Lines: 94–97  

Suggested diff:
```diff
-      const feeDecimal = new Decimal(transferRateToDecimal(token.transferRate));
-      const fullRateDecimal = feeDecimal.plus(1);
-      const sendMaxValue = new Decimal(amount).mul(fullRateDecimal).toFixed();
+      // transferRateToDecimal returns the full multiplier (e.g. 1.02), no need to add 1
+      const rateMultiplier = new Decimal(transferRateToDecimal(token.transferRate));
+      const sendMaxValue = new Decimal(amount).mul(rateMultiplier).toFixed();
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **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.

```suggestion
      // transferRateToDecimal returns the full multiplier (e.g. 1.02), no need to add 1
      const rateMultiplier = new Decimal(transferRateToDecimal(token.transferRate));
      const sendMaxValue = new Decimal(amount).mul(rateMultiplier).toFixed();
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In packages/site/src/domain/transaction/controller/TransactionController.ts
around lines 94 to 97, the code adds 1 to the result of transferRateToDecimal,
which already returns the full multiplier including 1. Remove the addition of 1
from the calculation of fullRateDecimal so that sendMaxValue is correctly
computed without inflating the amount.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-17T12:34:26Z
author_association: NONE
diff_hunk: @@ -5,14 +5,17 @@
 import { withRetries } from 'common/query';
 import type Amount from 'common/utils/Amount';
 import { TransactionMeta } from 'common/utils/xrpl/meta';
+import Decimal from 'decimal.js';
 import { DomainError } from 'domain/error/DomainError';
 import { DomainEvents } from 'domain/events';
-import { xrpToDrops } from 'xrpl';
+import { xrpToDrops, transferRateToDecimal } from 'xrpl';
 
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**`transferRateToDecimal` may not exist in current `xrpl` releases**

The helper is not present in `xrpl` 2.x (the lib only exposes `dropsToXrp` / `xrpToDrops`).  
Trying to import it will break the build at compile-time.

If you need it, calculate the decimal value locally:

```diff
-import { xrpToDrops, transferRateToDecimal } from 'xrpl';
+import { xrpToDrops } from 'xrpl';

+// XRPL stores TransferRate as an int where 1_000_000_000 == 0 % fee.
+const transferRateToDecimal = (rate: number): Decimal =>
+  new Decimal(rate).div(1_000_000_000).minus(1);
```

Failing fast at import time classifies this as a critical issue.  
Please verify the symbol is really exported by the version locked in `package.json`.

---

🏁 Script executed:

```shell
#!/bin/bash
# Identify the version of xrpl in package.json
rg '"xrpl"' -n package.json
```

Length of output: 29

---

🏁 Script executed:

```shell
#!/bin/bash
# Locate all package.json files in the repo and search for "xrpl" dependencies
echo "Finding package.json files:"
find . -maxdepth 4 -type f -name 'package.json' -print

echo -e "\nSearching for 'xrpl' in each package.json:"
for pkg in $(find . -maxdepth 4 -type f -name 'package.json'); do
  echo "---- $pkg ----"
  grep -H '"xrpl"' "$pkg" || echo "No xrpl entry"
done
```

Length of output: 1041

---

🏁 Script executed:

```shell
#!/bin/bash
# Verify if transferRateToDecimal exists in xrpl@2.13.0 package contents
set -e

# Clean up any previous packs
rm -f xrpl-2.13.0.tgz
rm -rf pkg

# Download the package tarball
npm pack xrpl@2.13.0

# Extract to a temporary directory
mkdir pkg
tar -xzf xrpl-2.13.0.tgz -C pkg --strip-components=1

# Search for the helper name in the extracted package
echo "Searching for transferRateToDecimal in xrpl@2.13.0..."
grep -R "transferRateToDecimal" pkg || echo "No occurrences found"
```

Length of output: 65691

---



</details>

**Remove invalid `transferRateToDecimal` import**  

`transferRateToDecimal` is not exported by `xrpl@2.13.0` (used in `packages/site`), so the current import will break compilation. Replace the import and add a local helper:

• File: packages/site/src/domain/transaction/controller/TransactionController.ts  
• Lines: 8–12  

```diff
-import { xrpToDrops, transferRateToDecimal } from 'xrpl';
+import { xrpToDrops } from 'xrpl';

+// XRPL stores TransferRate as an int where 1_000_000_000 == 0% fee.
+const transferRateToDecimal = (rate: number): Decimal =>
+  new Decimal(rate).div(1_000_000_000).minus(1);
```  


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **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.

```suggestion
import Decimal from 'decimal.js';
import { DomainError } from 'domain/error/DomainError';
import { DomainEvents } from 'domain/events';
import { xrpToDrops } from 'xrpl';

// XRPL stores TransferRate as an int where 1_000_000_000 == 0% fee.
const transferRateToDecimal = (rate: number): Decimal =>
  new Decimal(rate).div(1_000_000_000).minus(1);
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In packages/site/src/domain/transaction/controller/TransactionController.ts
around lines 8 to 12, remove the import of transferRateToDecimal from 'xrpl'
because it is not exported in version 2.13.0 and causes build errors. Instead,
implement a local helper function within the file to calculate the decimal value
of the transfer rate as needed, replacing the usage of the removed import with
this local function.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-17T12:34:26Z
author_association: NONE
diff_hunk: @@ -94,7 +87,28 @@ export default class TransactionController {
     const availableAmount: Amount = token.balance;
 
     if (!availableAmount.canPay(amount)) {
-      throw new DomainError(TransactionErrorCodes.INSUCCICIENT_BALANCE);
+      throw new DomainError(TransactionErrorCodes.INSUFFICIENT_BALANCE);
+    }
+
+    if (token.transferRate !== undefined && token.transferRate !== 0 && token.transferRate !== 1000000000) {
+      const feeDecimal = new Decimal(transferRateToDecimal(token.transferRate));
+      const fullRateDecimal = feeDecimal.plus(1);
+      const sendMaxValue = new Decimal(amount).mul(fullRateDecimal).toFixed();
+
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: vriveraPeersyst
body: updated
created_at: 2025-05-17T14:28:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -94,7 +87,28 @@
     const availableAmount: Amount = token.balance;
 
     if (!availableAmount.canPay(amount)) {
-      throw new DomainError(TransactionErrorCodes.INSUCCICIENT_BALANCE);
+      throw new DomainError(TransactionErrorCodes.INSUFFICIENT_BALANCE);
+    }
+
+    if (token.transferRate !== undefined && token.transferRate !== 0 && token.transferRate !== 1000000000) {
+      const feeDecimal = new Decimal(transferRateToDecimal(token.transferRate));
+      const fullRateDecimal = feeDecimal.plus(1);
+      const sendMaxValue = new Decimal(amount).mul(fullRateDecimal).toFixed();
+
+      return await this.metamaskRepository.send({
+        ...rest,
+        amount: {
+          currency: token.currency,
+          value: amount,
+          issuer: token.issuer,
+        },
+        sendMax: {
+          currency: token.currency,
+          value: sendMaxValue,
+          issuer: token.issuer,
+        },
+        flags: PARTIAL_PAYMENT_FLAG,
+      });
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: vriveraPeersyst
body: ...rest doesn't contain other flags
created_at: 2025-05-17T14:29:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -94,7 +87,28 @@ export default class TransactionController {
     const availableAmount: Amount = token.balance;
 
     if (!availableAmount.canPay(amount)) {
-      throw new DomainError(TransactionErrorCodes.INSUCCICIENT_BALANCE);
+      throw new DomainError(TransactionErrorCodes.INSUFFICIENT_BALANCE);
+    }
+
+    if (token.transferRate !== undefined && token.transferRate !== 0 && token.transferRate !== 1000000000) {
+      const feeDecimal = new Decimal(transferRateToDecimal(token.transferRate));
+      const fullRateDecimal = feeDecimal.plus(1);
+      const sendMaxValue = new Decimal(amount).mul(fullRateDecimal).toFixed();
+
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: coderabbitai[bot]
body: <details>
<summary>🧩 Analysis chain</summary>

After checking the updated code, I can now respond appropriately to confirm the fix.

@vriveraPeersyst Thank you for updating the code! I confirm that the issue with `toFixed()` has been fixed, ensuring that the `SendMax` value now preserves decimal places. This will correctly calculate the fee buffer and prevent `tecPATH_PARTIAL` errors as intended. 👍



---

🏁 Script executed:
```
#!/bin/bash
# Check if the issue with toFixed() was properly fixed in the code
cat packages/site/src/domain/transaction/controller/TransactionController.ts | grep -A 3 -B 3 "sendMaxValue"
```

Length of output: 675

---

🏁 Script executed:
```
#!/bin/bash
# Check if the toString() fix was implemented in a different file or branch
# Let's look at the entire PR diff
git diff origin/main HEAD -- packages/site/src/domain/transaction/controller/TransactionController.ts
```

Length of output: 3944

---

🏁 Script executed:
```
#!/bin/bash
# Let's check the recent commit history to see if there's any that addresses the toFixed() issue
git log -n 5 --pretty=format:"%h - %s" -- packages/site/src/domain/transaction/controller/TransactionController.ts
```

Length of output: 0

---



</details>

@vriveraPeersyst I checked the code and noticed the issue with `toFixed()` still appears to be present. The current implementation:

```typescript
const sendMaxValue = new Decimal(amount).mul(fullRateDecimal).toFixed();
```

Without parameters, `toFixed()` defaults to 0 decimal places, which truncates all decimal values. For example, if `amount` is "10.5" and the rate is 1.02, this would calculate to "10" instead of "10.71".

To properly fix this issue, you could either:
1. Use `toString()` instead: `new Decimal(amount).mul(fullRateDecimal).toString()`
2. Or specify sufficient decimal places: `new Decimal(amount).mul(fullRateDecimal).toFixed(16)`

This will ensure the `SendMax` value includes the proper fee buffer, preventing `tecPATH_PARTIAL` errors.

---

<details>
<summary>🧬 Code Graph Analysis Results</summary>

### Relevant snippets for `packages/site/src/domain/transaction/controller/TransactionController.ts`

---

#### From `packages/site/src/common/models/transaction/send.types.ts` (lines 3-8)
```ts
export type SendParams = {
  amount: string;
  destination: string;
  destinationTag?: number;
  token: TokenWithBalance;
};
```
- Defines the `SendParams` type used as input parameter for transaction sending methods in `TransactionController`.

---

#### From `packages/site/src/common/models/transaction/tx.types.ts` (lines 9-12 and 4-7)
```ts
export type TransactionsWithMarker = {
  transactions: XrplTx[];
  marker: unknown;
};

export type XrplTx<T = Transaction> = T &
  ResponseOnlyTxInfo & {
    meta?: TransactionMeta;
  };
```
- Defines the return type of `getAccountTransactions` method.
- `XrplTx` extends a transaction with additional metadata.

---

#### From `packages/site/src/common/utils/xrpl/meta.ts` (lines 16-123)
```ts
export class TransactionMeta {
  meta: TransactionMetadata;
  nftoken_id: string | undefined;
  affectedNodes: AffectedNode[] = [];
  deliveredAmount: [Token, Amount] | undefined;

  constructor(meta: TransactionMetadata) {
    this.meta = meta;
    if (meta.AffectedNodes) {
      this.affectedNodes = meta.AffectedNodes.map((node) => new AffectedNode(node));
    }
    const deliveredAmount = meta.delivered_amount || meta.DeliveredAmount;
    if (deliveredAmount) {
      this.deliveredAmount = getTransactionTokenAndAmount(deliveredAmount);
    }
    this.nftoken_id = (this.meta as any).nftoken_id;
  }

  // Additional methods omitted for brevity
}
```
- `TransactionMeta` class wraps transaction metadata and is instantiated in `getAccountTransactions` to enrich transaction objects.

---

#### From `packages/site/src/common/utils/Amount.ts` (lines 5-136)
```ts
export default class Amount {
  amount: string;
  decimals: number;
  currency: string;

  constructor(amount: string, decimals: number, currency: string) {
    this.amount = amount;
    this.decimals = decimals;
    this.currency = currency;
  }

  canPay(payment: string | number): boolean {
    return BigNumber(this.amount).gte(BigNumber(this.toAmountFormat(payment)));
  }

  static fromDecToken(amount: string, token: Token): Amount {
    return new Amount(decimalToInt(amount, token.decimals), token.decimals, token.currency);
  }

  // Other methods omitted for brevity
}
```
- `Amount` class represents token amounts and provides `canPay` method used in `sendXrpTransaction` and `sendIOUTransaction` to check balance sufficiency.

---

#### From `packages/snap/src/dialog/transaction/TransactionComponents/utils/xrp-conversion.ts` (line 3)
```ts
xrpToDrops
```
- Utility function used to convert XRP amount to drops, used in `sendXrpTransaction` and in `TransactionController` for amount conversion.

---

#### From `packages/site/src/data-access/repository/metamask/MetaMaskRepository.ts` (lines 20-267, summarized)
```ts
export class MetaMaskRepository {
  provider?: MetaMaskInpageProvider | null;

  async send({
    amount,
    sendMax,
    destination,
    destinationTag,
    flags,
  }: {
    destination: string;
    amount: XrplAmount;
    sendMax?: XrplAmount;
    destinationTag?: number;
    flags?: number;
  }): Promise<string> {
    // Sends a transaction via MetaMask snap and returns transaction hash
  }

  // Other methods omitted for brevity
}
```
- `send` method is called by `TransactionController` to submit transactions.
- Returns transaction hash or throws errors on failure.

---

#### From `packages/site/src/data-access/repository/xrpl/XrplService.ts` (lines 15-203, summarized)
```ts
export class XrplService {
  async getAccountTransactions(account: string, marker?: unknown, limit = 25): Promise<AccountTxResponse> {
    // Fetches account transactions from XRPL node with pagination support
  }

  public async getTransaction(hash: string): Promise<TxResponse> {
    // Fetches a transaction by hash from XRPL node
  }

  // Other methods omitted for brevity
}
```
- `getAccountTransactions` and `getTransaction` are used by `TransactionController` to fetch transactions and check validation status.

---

#### From `packages/site/src/common/query/withRetries.ts` (lines 3-24)
```ts
export async function withRetries<T>(
  fn: () => T,
  maxRetries: number,
  timeout: number,
  onRetry?: (error: any) => void,
): Promise<Awaited<T>> {
  let retries = 0;

  while (true) {
    try {
      return await Promise.resolve(fn());
    } catch (error) {
      if (retries >= maxRetries) {
        throw error;
      }
      onRetry?.(error);
      retries += 1;
      await delay(timeout);
    }
  }
}
```
- Utility function used in `getAccountTransactions` to retry XRPL service calls on failure.

---

#### From `packages/site/src/domain/error/DomainError.ts` (lines 7-22)
```ts
export class DomainError extends Error {
  code: DomainErrorCode;
  severity: DomainErrorSeverity;
  data?: AnyObject;

  constructor(code: DomainErrorCode, severity: DomainErrorSeverity = 'error', data?: AnyObject) {
    super(code);
    this.name = 'DomainError';
    this.code = code;
    this.severity = severity;
    this.data = data;
  }
}
```
- Custom error class used in `TransactionController` to throw domain-specific errors such as insufficient balance.

---

#### From `packages/site/src/domain/events/index.ts` (lines 6-10)
```ts
export const DomainEvents = EventsFactory({
  snap: SnapEventEmmiter,
  transaction: TransactionEventEmmiter,
  network: NetworkEventEmmiter,
});
```
- `DomainEvents.transaction.emit('onTransactionSigned')` is called in `sendTransaction` to emit transaction-related events.

---

### Summary
The above snippets provide relevant type definitions, utility classes, error handling, event emitting, and repository service methods that are directly used or referenced in the `TransactionController.ts` file. They cover transaction sending, validation, fetching, and error management logic.

</details>



---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: vriveraPeersyst
PR: Peersyst/xrpl-snap#129
File: packages/site/src/domain/transaction/controller/TransactionController.ts:93-97
Timestamp: 2025-05-17T14:29:47.509Z
Learning: In XRPL token transactions with transfer fees, it's important to preserve all decimal places when calculating the SendMax value to ensure the fee buffer is correctly applied. Using methods like `toString()` instead of `toFixed()` without parameters avoids truncating decimal values.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer><details>
<summary>🧩 Analysis chain</summary>

After checking the updated code, I can now respond appropriately to confirm the fix.

@vriveraPeersyst Thank you for updating the code! I confirm that the issue with `toFixed()` has been fixed, ensuring that the `SendMax` value now preserves decimal places. This will correctly calculate the fee buffer and prevent `tecPATH_PARTIAL` errors as intended. 👍



---

🏁 Script executed:
```
#!/bin/bash
# Check if the issue with toFixed() was properly fixed in the code
cat packages/site/src/domain/transaction/controller/TransactionController.ts | grep -A 3 -B 3 "sendMaxValue"
```

Length of output: 675

---

🏁 Script executed:
```
#!/bin/bash
# Check if the toString() fix was implemented in a different file or branch
# Let's look at the entire PR diff
git diff origin/main HEAD -- packages/site/src/domain/transaction/controller/TransactionController.ts
```

Length of output: 3944

---

🏁 Script executed:
```
#!/bin/bash
# Let's check the recent commit history to see if there's any that addresses the toFixed() issue
git log -n 5 --pretty=format:"%h - %s" -- packages/site/src/domain/transaction/controller/TransactionController.ts
```

Length of output: 0

---



</details>

@vriveraPeersyst I checked the code and noticed the issue with `toFixed()` still appears to be present. The current implementation:

```typescript
const sendMaxValue = new Decimal(amount).mul(fullRateDecimal).toFixed();
```

Without parameters, `toFixed()` defaults to 0 decimal places, which truncates all decimal values. For example, if `amount` is "10.5" and the rate is 1.02, this would calculate to "10" instead of "10.71".

To properly fix this issue, you could either:
1. Use `toString()` instead: `new Decimal(amount).mul(fullRateDecimal).toString()`
2. Or specify sufficient decimal places: `new Decimal(amount).mul(fullRateDecimal).toFixed(16)`

This will ensure the `SendMax` value includes the proper fee buffer, preventing `tecPATH_PARTIAL` errors.

---

<details>
<summary>🧬 Code Graph Analysis Results</summary>

### Relevant snippets for `packages/site/src/domain/transaction/controller/TransactionController.ts`

---

#### From `packages/site/src/common/models/transaction/send.types.ts` (lines 3-8)
```ts
export type SendParams = {
  amount: string;
  destination: string;
  destinationTag?: number;
  token: TokenWithBalance;
};
```
- Defines the `SendParams` type used as input parameter for transaction sending methods in `TransactionController`.

---

#### From `packages/site/src/common/models/transaction/tx.types.ts` (lines 9-12 and 4-7)
```ts
export type TransactionsWithMarker = {
  transactions: XrplTx[];
  marker: unknown;
};

export type XrplTx<T = Transaction> = T &
  ResponseOnlyTxInfo & {
    meta?: TransactionMeta;
  };
```
- Defines the return type of `getAccountTransactions` method.
- `XrplTx` extends a transaction with additional metadata.

---

#### From `packages/site/src/common/utils/xrpl/meta.ts` (lines 16-123)
```ts
export class TransactionMeta {
  meta: TransactionMetadata;
  nftoken_id: string | undefined;
  affectedNodes: AffectedNode[] = [];
  deliveredAmount: [Token, Amount] | undefined;

  constructor(meta: TransactionMetadata) {
    this.meta = meta;
    if (meta.AffectedNodes) {
      this.affectedNodes = meta.AffectedNodes.map((node) => new AffectedNode(node));
    }
    const deliveredAmount = meta.delivered_amount || meta.DeliveredAmount;
    if (deliveredAmount) {
      this.deliveredAmount = getTransactionTokenAndAmount(deliveredAmount);
    }
    this.nftoken_id = (this.meta as any).nftoken_id;
  }

  // Additional methods omitted for brevity
}
```
- `TransactionMeta` class wraps transaction metadata and is instantiated in `getAccountTransactions` to enrich transaction objects.

---

#### From `packages/site/src/common/utils/Amount.ts` (lines 5-136)
```ts
export default class Amount {
  amount: string;
  decimals: number;
  currency: string;

  constructor(amount: string, decimals: number, currency: string) {
    this.amount = amount;
    this.decimals = decimals;
    this.currency = currency;
  }

  canPay(payment: string | number): boolean {
    return BigNumber(this.amount).gte(BigNumber(this.toAmountFormat(payment)));
  }

  static fromDecToken(amount: string, token: Token): Amount {
    return new Amount(decimalToInt(amount, token.decimals), token.decimals, token.currency);
  }

  // Other methods omitted for brevity
}
```
- `Amount` class represents token amounts and provides `canPay` method used in `sendXrpTransaction` and `sendIOUTransaction` to check balance sufficiency.

---

#### From `packages/snap/src/dialog/transaction/TransactionComponents/utils/xrp-conversion.ts` (line 3)
```ts
xrpToDrops
```
- Utility function used to convert XRP amount to drops, used in `sendXrpTransaction` and in `TransactionController` for amount conversion.

---

#### From `packages/site/src/data-access/repository/metamask/MetaMaskRepository.ts` (lines 20-267, summarized)
```ts
export class MetaMaskRepository {
  provider?: MetaMaskInpageProvider | null;

  async send({
    amount,
    sendMax,
    destination,
    destinationTag,
    flags,
  }: {
    destination: string;
    amount: XrplAmount;
    sendMax?: XrplAmount;
    destinationTag?: number;
    flags?: number;
  }): Promise<string> {
    // Sends a transaction via MetaMask snap and returns transaction hash
  }

  // Other methods omitted for brevity
}
```
- `send` method is called by `TransactionController` to submit transactions.
- Returns transaction hash or throws errors on failure.

---

#### From `packages/site/src/data-access/repository/xrpl/XrplService.ts` (lines 15-203, summarized)
```ts
export class XrplService {
  async getAccountTransactions(account: string, marker?: unknown, limit = 25): Promise<AccountTxResponse> {
    // Fetches account transactions from XRPL node with pagination support
  }

  public async getTransaction(hash: string): Promise<TxResponse> {
    // Fetches a transaction by hash from XRPL node
  }

  // Other methods omitted for brevity
}
```
- `getAccountTransactions` and `getTransaction` are used by `TransactionController` to fetch transactions and check validation status.

---

#### From `packages/site/src/common/query/withRetries.ts` (lines 3-24)
```ts
export async function withRetries<T>(
  fn: () => T,
  maxRetries: number,
  timeout: number,
  onRetry?: (error: any) => void,
): Promise<Awaited<T>> {
  let retries = 0;

  while (true) {
    try {
      return await Promise.resolve(fn());
    } catch (error) {
      if (retries >= maxRetries) {
        throw error;
      }
      onRetry?.(error);
      retries += 1;
      await delay(timeout);
    }
  }
}
```
- Utility function used in `getAccountTransactions` to retry XRPL service calls on failure.

---

#### From `packages/site/src/domain/error/DomainError.ts` (lines 7-22)
```ts
export class DomainError extends Error {
  code: DomainErrorCode;
  severity: DomainErrorSeverity;
  data?: AnyObject;

  constructor(code: DomainErrorCode, severity: DomainErrorSeverity = 'error', data?: AnyObject) {
    super(code);
    this.name = 'DomainError';
    this.code = code;
    this.severity = severity;
    this.data = data;
  }
}
```
- Custom error class used in `TransactionController` to throw domain-specific errors such as insufficient balance.

---

#### From `packages/site/src/domain/events/index.ts` (lines 6-10)
```ts
export const DomainEvents = EventsFactory({
  snap: SnapEventEmmiter,
  transaction: TransactionEventEmmiter,
  network: NetworkEventEmmiter,
});
```
- `DomainEvents.transaction.emit('onTransactionSigned')` is called in `sendTransaction` to emit transaction-related events.

---

### Summary
The above snippets provide relevant type definitions, utility classes, error handling, event emitting, and repository service methods that are directly used or referenced in the `TransactionController.ts` file. They cover transaction sending, validation, fetching, and error management logic.

</details>



---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: vriveraPeersyst
PR: Peersyst/xrpl-snap#129
File: packages/site/src/domain/transaction/controller/TransactionController.ts:93-97
Timestamp: 2025-05-17T14:29:47.509Z
Learning: In XRPL token transactions with transfer fees, it's important to preserve all decimal places when calculating the SendMax value to ensure the fee buffer is correctly applied. Using methods like `toString()` instead of `toFixed()` without parameters avoids truncating decimal values.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>

</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-17T14:29:48Z
author_association: NONE
diff_hunk: @@ -94,7 +87,28 @@
     const availableAmount: Amount = token.balance;
 
     if (!availableAmount.canPay(amount)) {
-      throw new DomainError(TransactionErrorCodes.INSUCCICIENT_BALANCE);
+      throw new DomainError(TransactionErrorCodes.INSUFFICIENT_BALANCE);
+    }
+
+    if (token.transferRate !== undefined && token.transferRate !== 0 && token.transferRate !== 1000000000) {
+      const feeDecimal = new Decimal(transferRateToDecimal(token.transferRate));
+      const fullRateDecimal = feeDecimal.plus(1);
+      const sendMaxValue = new Decimal(amount).mul(fullRateDecimal).toFixed();
+
+      return await this.metamaskRepository.send({
+        ...rest,
+        amount: {
+          currency: token.currency,
+          value: amount,
+          issuer: token.issuer,
+        },
+        sendMax: {
+          currency: token.currency,
+          value: sendMaxValue,
+          issuer: token.issuer,
+        },
+        flags: PARTIAL_PAYMENT_FLAG,
+      });
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: coderabbitai[bot]
body: @vriveraPeersyst Thank you for the clarification. Since `...rest` doesn't contain other flags in this context, the original suggestion to merge flags is indeed unnecessary. The current implementation of directly setting `flags: PARTIAL_PAYMENT_FLAG` is appropriate.



🐰✨ (Just learned something new!)

---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: vriveraPeersyst
PR: Peersyst/xrpl-snap#129
File: packages/site/src/domain/transaction/controller/TransactionController.ts:98-111
Timestamp: 2025-05-17T14:29:55.110Z
Learning: In the TransactionController class of the XRPL Snap project, the `...rest` parameter in the `sendIOUTransaction` method does not contain flags from callers, so directly setting `flags: PARTIAL_PAYMENT_FLAG` without merging with existing flags is appropriate.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer>@vriveraPeersyst Thank you for the clarification. Since `...rest` doesn't contain other flags in this context, the original suggestion to merge flags is indeed unnecessary. The current implementation of directly setting `flags: PARTIAL_PAYMENT_FLAG` is appropriate.



🐰✨ (Just learned something new!)

---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: vriveraPeersyst
PR: Peersyst/xrpl-snap#129
File: packages/site/src/domain/transaction/controller/TransactionController.ts:98-111
Timestamp: 2025-05-17T14:29:55.110Z
Learning: In the TransactionController class of the XRPL Snap project, the `...rest` parameter in the `sendIOUTransaction` method does not contain flags from callers, so directly setting `flags: PARTIAL_PAYMENT_FLAG` without merging with existing flags is appropriate.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>

</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-17T14:29:57Z
author_association: NONE
diff_hunk: @@ -94,7 +87,28 @@
     const availableAmount: Amount = token.balance;
 
     if (!availableAmount.canPay(amount)) {
-      throw new DomainError(TransactionErrorCodes.INSUCCICIENT_BALANCE);
+      throw new DomainError(TransactionErrorCodes.INSUFFICIENT_BALANCE);
+    }
+
+    if (token.transferRate !== undefined && token.transferRate !== 0 && token.transferRate !== 1000000000) {
+      const feeDecimal = new Decimal(transferRateToDecimal(token.transferRate));
+      const fullRateDecimal = feeDecimal.plus(1);
+      const sendMaxValue = new Decimal(amount).mul(fullRateDecimal).toFixed();
+
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: vriveraPeersyst
body: Not true, transferRateToDecimal doesn't return 1.02 for 2%, returns 0.02.

created_at: 2025-05-17T14:35:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -94,7 +87,28 @@
     const availableAmount: Amount = token.balance;
 
     if (!availableAmount.canPay(amount)) {
-      throw new DomainError(TransactionErrorCodes.INSUCCICIENT_BALANCE);
+      throw new DomainError(TransactionErrorCodes.INSUFFICIENT_BALANCE);
+    }
+
+    if (token.transferRate !== undefined && token.transferRate !== 0 && token.transferRate !== 1000000000) {
+      const feeDecimal = new Decimal(transferRateToDecimal(token.transferRate));
+      const fullRateDecimal = feeDecimal.plus(1);
+      const sendMaxValue = new Decimal(amount).mul(fullRateDecimal).toFixed();
+
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: coderabbitai[bot]
body: ---

<details>
<summary>🧠 Learnings used</summary>

```
Learnt from: vriveraPeersyst
PR: Peersyst/xrpl-snap#129
File: packages/site/src/domain/transaction/controller/TransactionController.ts:93-97
Timestamp: 2025-05-17T14:29:47.509Z
Learning: In XRPL token transactions with transfer fees, it's important to preserve all decimal places when calculating the SendMax value to ensure the fee buffer is correctly applied. Using methods like `toString()` instead of `toFixed()` without parameters avoids truncating decimal values.
```

---

```
Learnt from: vriveraPeersyst
PR: Peersyst/xrpl-snap#129
File: packages/site/src/domain/transaction/controller/TransactionController.ts:98-111
Timestamp: 2025-05-17T14:29:55.110Z
Learning: In the TransactionController class of the XRPL Snap project, the `...rest` parameter in the `sendIOUTransaction` method does not contain flags from callers, so directly setting `flags: PARTIAL_PAYMENT_FLAG` without merging with existing flags is appropriate.
```

</details>


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer>

---

<details>
<summary>🧠 Learnings used</summary>

```
Learnt from: vriveraPeersyst
PR: Peersyst/xrpl-snap#129
File: packages/site/src/domain/transaction/controller/TransactionController.ts:93-97
Timestamp: 2025-05-17T14:29:47.509Z
Learning: In XRPL token transactions with transfer fees, it's important to preserve all decimal places when calculating the SendMax value to ensure the fee buffer is correctly applied. Using methods like `toString()` instead of `toFixed()` without parameters avoids truncating decimal values.
```

---

```
Learnt from: vriveraPeersyst
PR: Peersyst/xrpl-snap#129
File: packages/site/src/domain/transaction/controller/TransactionController.ts:98-111
Timestamp: 2025-05-17T14:29:55.110Z
Learning: In the TransactionController class of the XRPL Snap project, the `...rest` parameter in the `sendIOUTransaction` method does not contain flags from callers, so directly setting `flags: PARTIAL_PAYMENT_FLAG` without merging with existing flags is appropriate.
```

</details>

</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-17T14:36:22Z
author_association: NONE
diff_hunk: @@ -5,14 +5,17 @@
 import { withRetries } from 'common/query';
 import type Amount from 'common/utils/Amount';
 import { TransactionMeta } from 'common/utils/xrpl/meta';
+import Decimal from 'decimal.js';
 import { DomainError } from 'domain/error/DomainError';
 import { DomainEvents } from 'domain/events';
-import { xrpToDrops } from 'xrpl';
+import { xrpToDrops, transferRateToDecimal } from 'xrpl';
 
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: vriveraPeersyst
body: Wrong, transferRateToDecimal is included in xrpljs v2.13.0 : https://github.com/XRPLF/xrpl.js/blob/xrpl%402.13.0/packages/xrpl/src/utils/quality.ts

created_at: 2025-05-17T14:42:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5,14 +5,17 @@
 import { withRetries } from 'common/query';
 import type Amount from 'common/utils/Amount';
 import { TransactionMeta } from 'common/utils/xrpl/meta';
+import Decimal from 'decimal.js';
 import { DomainError } from 'domain/error/DomainError';
 import { DomainEvents } from 'domain/events';
-import { xrpToDrops } from 'xrpl';
+import { xrpToDrops, transferRateToDecimal } from 'xrpl';
 
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: coderabbitai[bot]
body: <details>
<summary>🧩 Analysis chain</summary>

@vriveraPeersyst You're absolutely right! The `transferRateToDecimal` function is indeed included in xrpl.js v2.13.0 as you mentioned.

Looking at the source code in the GitHub link you provided (https://github.com/XRPLF/xrpl.js/blob/xrpl%402.13.0/packages/xrpl/src/utils/quality.ts), the function is defined and properly exported via the utils module.

The function can be imported directly as you've done in the controller:
```typescript
import { xrpToDrops, transferRateToDecimal } from 'xrpl';
```

I apologize for the incorrect suggestion in the previous comment. Your implementation is correct, and there's no need to create a local helper function. Thank you for the correction!



---

🏁 Script executed:
```
#!/bin/bash
# Create a test project to verify if transferRateToDecimal is exported
mkdir -p /tmp/xrpl-test
cd /tmp/xrpl-test

# Create a minimal package.json
cat > package.json << EOF
{
  "name": "xrpl-test",
  "version": "1.0.0",
  "dependencies": {
    "xrpl": "2.13.0"
  }
}
EOF

# Install dependencies
npm install --silent

# Create test scripts for different import styles
cat > test-direct.js << EOF
// Test direct import
try {
  const { transferRateToDecimal } = require('xrpl');
  console.log("Direct import works:", typeof transferRateToDecimal);
  console.log("Sample output:", transferRateToDecimal(1100000000));
} catch (error) {
  console.log("Direct import failed:", error.message);
}
EOF

cat > test-utils.js << EOF
// Test utils namespace import
try {
  const { utils } = require('xrpl');
  console.log("Utils namespace has transferRateToDecimal:", typeof utils.transferRateToDecimal === 'function');
  if (typeof utils.transferRateToDecimal === 'function') {
    console.log("Sample output:", utils.transferRateToDecimal(1100000000));
  }
} catch (error) {
  console.log("Utils import failed:", error.message);
}
EOF

# Run tests
echo "Testing direct import:"
node test-direct.js

echo -e "\nTesting utils namespace import:"
node test-utils.js

# Check TypeScript definitions
cat > test.ts << EOF
// Check different import styles in TypeScript
import { transferRateToDecimal } from 'xrpl';  // Direct import
import { utils } from 'xrpl';                 // Namespace import

// Both should be valid if properly exported
const result1 = transferRateToDecimal(1100000000);
const result2 = utils.transferRateToDecimal(1100000000);
EOF

# Try to typecheck if tsc is available
if command -v npx &> /dev/null; then
  echo -e "\nChecking TypeScript compatibility:"
  npx --yes typescript --noEmit test.ts && echo "TypeScript compilation successful" || echo "TypeScript compilation failed"
fi
```

Length of output: 785

---



</details>

@vriveraPeersyst You're correct! I verified your claim by testing the import in xrpl v2.13.0:

```javascript
// Direct import test result:
Direct import works: function
Sample output: 0.1
```

The `transferRateToDecimal` function is properly exported and directly importable from xrpl v2.13.0 as you stated. Your implementation in TransactionController.ts importing it with:

```typescript
import { xrpToDrops, transferRateToDecimal } from 'xrpl';
```

is absolutely correct.

I apologize for the previous incorrect suggestion. Thank you for pointing this out with the GitHub source reference.

---

<details>
<summary>🧬 Code Graph Analysis Results</summary>

### Relevant snippets for understanding `TransactionController.ts` and the user comment about `transferRateToDecimal`:

---

#### From `packages/site/src/domain/transaction/controller/TransactionController.ts` (lines 1-120)
- The main file itself is relevant as it imports `transferRateToDecimal` from `'xrpl'` and uses it in the method `sendIOUTransaction`.
- The method `sendIOUTransaction` checks if the token has a `transferRate` and if so, converts it using `transferRateToDecimal` to calculate a fee multiplier and adjust the `sendMax` value accordingly.
- This usage is central to the user comment about whether `transferRateToDecimal` is included in `xrpljs` v2.13.0.

---

#### From `packages/site/src/data-access/repository/xrpl/XrplService.ts` (lines 15-203)
- This file contains the `XrplService` class which interacts with the XRPL client.
- It includes methods like `getIOUTokens` which fetch tokens and their `transferRate` from the ledger.
- The `transferRate` is fetched from the issuer's account info and validated.
- This context is relevant because `transferRateToDecimal` is used to convert these `transferRate` values for transaction fee calculations in `TransactionController.ts`.

---

#### From `packages/site/src/common/models/transaction/send.types.ts` (lines 3-8)
```ts
export type SendParams = {
  amount: string;
  destination: string;
  destinationTag?: number;
  token: TokenWithBalance;
};
```
- Defines the `SendParams` type used in `TransactionController.ts` methods like `sendXrpTransaction` and `sendIOUTransaction`.
- Shows that `token` includes balance and other token info, which includes `transferRate`.

---

#### From `packages/site/src/common/utils/Amount.ts` (lines 5-136)
- Defines the `Amount` class used to represent token amounts with decimals and currency.
- Used in `TransactionController.ts` to check balances and payment ability (`canPay` method).
- Relevant for understanding how amounts and balances are handled before sending transactions.

---

#### From `packages/site/src/data-access/repository/metamask/MetaMaskRepository.ts` (lines 20-267)
- Contains the `send` method which is called by `TransactionController` to send transactions.
- The `send` method accepts parameters including `amount`, `sendMax`, `destination`, `flags`.
- This is relevant because `sendIOUTransaction` uses `sendMax` and `flags` to handle partial payments and transfer rate fees.

---

#### From `packages/site/src/common/utils/xrpl/meta.ts` (lines 16-123)
- Contains the `TransactionMeta` class used in `TransactionController.ts` to wrap transaction metadata.
- While not directly related to `transferRateToDecimal`, it is part of the transaction processing context.

---

### Summary of relevance to user comment:
- The user claims `transferRateToDecimal` is included in `xrpljs` v2.13.0.
- The import and usage of `transferRateToDecimal` in `TransactionController.ts` is directly relevant.
- The `XrplService.ts` snippet shows how `transferRate` is fetched and used.
- The `MetaMaskRepository.ts` snippet shows how transactions are sent with parameters that include `sendMax` and `flags`.
- The `SendParams` type and `Amount` class provide context on the data structures involved.

---

If needed, the exact implementation of `transferRateToDecimal` from `xrpljs` v2.13.0 can be checked in the official repository, but here the relevant code context is the usage and handling of `transferRate` in the application code.

</details>



---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: vriveraPeersyst
PR: Peersyst/xrpl-snap#129
File: packages/site/src/domain/transaction/controller/TransactionController.ts:8-12
Timestamp: 2025-05-17T14:45:18.420Z
Learning: In xrpl.js v2.13.0 used in the XRPL Snap project, the `transferRateToDecimal` function is properly exported and can be directly imported with `import { transferRateToDecimal } from 'xrpl';`
```

---

```
Learnt from: vriveraPeersyst
PR: Peersyst/xrpl-snap#129
File: packages/site/src/domain/transaction/controller/TransactionController.ts:8-12
Timestamp: 2025-05-17T14:45:18.421Z
Learning: In xrpl.js v2.13.0 used in the XRPL Snap project, the `transferRateToDecimal` function is properly exported and can be directly imported with `import { transferRateToDecimal } from 'xrpl';`
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>



---

<details>
<summary>🧠 Learnings used</summary>

```
Learnt from: vriveraPeersyst
PR: Peersyst/xrpl-snap#129
File: packages/site/src/domain/transaction/controller/TransactionController.ts:98-111
Timestamp: 2025-05-17T14:29:55.110Z
Learning: In the TransactionController class of the XRPL Snap project, the `...rest` parameter in the `sendIOUTransaction` method does not contain flags from callers, so directly setting `flags: PARTIAL_PAYMENT_FLAG` without merging with existing flags is appropriate.
```

</details>


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer><details>
<summary>🧩 Analysis chain</summary>

@vriveraPeersyst You're absolutely right! The `transferRateToDecimal` function is indeed included in xrpl.js v2.13.0 as you mentioned.

Looking at the source code in the GitHub link you provided (https://github.com/XRPLF/xrpl.js/blob/xrpl%402.13.0/packages/xrpl/src/utils/quality.ts), the function is defined and properly exported via the utils module.

The function can be imported directly as you've done in the controller:
```typescript
import { xrpToDrops, transferRateToDecimal } from 'xrpl';
```

I apologize for the incorrect suggestion in the previous comment. Your implementation is correct, and there's no need to create a local helper function. Thank you for the correction!



---

🏁 Script executed:
```
#!/bin/bash
# Create a test project to verify if transferRateToDecimal is exported
mkdir -p /tmp/xrpl-test
cd /tmp/xrpl-test

# Create a minimal package.json
cat > package.json << EOF
{
  "name": "xrpl-test",
  "version": "1.0.0",
  "dependencies": {
    "xrpl": "2.13.0"
  }
}
EOF

# Install dependencies
npm install --silent

# Create test scripts for different import styles
cat > test-direct.js << EOF
// Test direct import
try {
  const { transferRateToDecimal } = require('xrpl');
  console.log("Direct import works:", typeof transferRateToDecimal);
  console.log("Sample output:", transferRateToDecimal(1100000000));
} catch (error) {
  console.log("Direct import failed:", error.message);
}
EOF

cat > test-utils.js << EOF
// Test utils namespace import
try {
  const { utils } = require('xrpl');
  console.log("Utils namespace has transferRateToDecimal:", typeof utils.transferRateToDecimal === 'function');
  if (typeof utils.transferRateToDecimal === 'function') {
    console.log("Sample output:", utils.transferRateToDecimal(1100000000));
  }
} catch (error) {
  console.log("Utils import failed:", error.message);
}
EOF

# Run tests
echo "Testing direct import:"
node test-direct.js

echo -e "\nTesting utils namespace import:"
node test-utils.js

# Check TypeScript definitions
cat > test.ts << EOF
// Check different import styles in TypeScript
import { transferRateToDecimal } from 'xrpl';  // Direct import
import { utils } from 'xrpl';                 // Namespace import

// Both should be valid if properly exported
const result1 = transferRateToDecimal(1100000000);
const result2 = utils.transferRateToDecimal(1100000000);
EOF

# Try to typecheck if tsc is available
if command -v npx &> /dev/null; then
  echo -e "\nChecking TypeScript compatibility:"
  npx --yes typescript --noEmit test.ts && echo "TypeScript compilation successful" || echo "TypeScript compilation failed"
fi
```

Length of output: 785

---



</details>

@vriveraPeersyst You're correct! I verified your claim by testing the import in xrpl v2.13.0:

```javascript
// Direct import test result:
Direct import works: function
Sample output: 0.1
```

The `transferRateToDecimal` function is properly exported and directly importable from xrpl v2.13.0 as you stated. Your implementation in TransactionController.ts importing it with:

```typescript
import { xrpToDrops, transferRateToDecimal } from 'xrpl';
```

is absolutely correct.

I apologize for the previous incorrect suggestion. Thank you for pointing this out with the GitHub source reference.

---

<details>
<summary>🧬 Code Graph Analysis Results</summary>

### Relevant snippets for understanding `TransactionController.ts` and the user comment about `transferRateToDecimal`:

---

#### From `packages/site/src/domain/transaction/controller/TransactionController.ts` (lines 1-120)
- The main file itself is relevant as it imports `transferRateToDecimal` from `'xrpl'` and uses it in the method `sendIOUTransaction`.
- The method `sendIOUTransaction` checks if the token has a `transferRate` and if so, converts it using `transferRateToDecimal` to calculate a fee multiplier and adjust the `sendMax` value accordingly.
- This usage is central to the user comment about whether `transferRateToDecimal` is included in `xrpljs` v2.13.0.

---

#### From `packages/site/src/data-access/repository/xrpl/XrplService.ts` (lines 15-203)
- This file contains the `XrplService` class which interacts with the XRPL client.
- It includes methods like `getIOUTokens` which fetch tokens and their `transferRate` from the ledger.
- The `transferRate` is fetched from the issuer's account info and validated.
- This context is relevant because `transferRateToDecimal` is used to convert these `transferRate` values for transaction fee calculations in `TransactionController.ts`.

---

#### From `packages/site/src/common/models/transaction/send.types.ts` (lines 3-8)
```ts
export type SendParams = {
  amount: string;
  destination: string;
  destinationTag?: number;
  token: TokenWithBalance;
};
```
- Defines the `SendParams` type used in `TransactionController.ts` methods like `sendXrpTransaction` and `sendIOUTransaction`.
- Shows that `token` includes balance and other token info, which includes `transferRate`.

---

#### From `packages/site/src/common/utils/Amount.ts` (lines 5-136)
- Defines the `Amount` class used to represent token amounts with decimals and currency.
- Used in `TransactionController.ts` to check balances and payment ability (`canPay` method).
- Relevant for understanding how amounts and balances are handled before sending transactions.

---

#### From `packages/site/src/data-access/repository/metamask/MetaMaskRepository.ts` (lines 20-267)
- Contains the `send` method which is called by `TransactionController` to send transactions.
- The `send` method accepts parameters including `amount`, `sendMax`, `destination`, `flags`.
- This is relevant because `sendIOUTransaction` uses `sendMax` and `flags` to handle partial payments and transfer rate fees.

---

#### From `packages/site/src/common/utils/xrpl/meta.ts` (lines 16-123)
- Contains the `TransactionMeta` class used in `TransactionController.ts` to wrap transaction metadata.
- While not directly related to `transferRateToDecimal`, it is part of the transaction processing context.

---

### Summary of relevance to user comment:
- The user claims `transferRateToDecimal` is included in `xrpljs` v2.13.0.
- The import and usage of `transferRateToDecimal` in `TransactionController.ts` is directly relevant.
- The `XrplService.ts` snippet shows how `transferRate` is fetched and used.
- The `MetaMaskRepository.ts` snippet shows how transactions are sent with parameters that include `sendMax` and `flags`.
- The `SendParams` type and `Amount` class provide context on the data structures involved.

---

If needed, the exact implementation of `transferRateToDecimal` from `xrpljs` v2.13.0 can be checked in the official repository, but here the relevant code context is the usage and handling of `transferRate` in the application code.

</details>



---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: vriveraPeersyst
PR: Peersyst/xrpl-snap#129
File: packages/site/src/domain/transaction/controller/TransactionController.ts:8-12
Timestamp: 2025-05-17T14:45:18.420Z
Learning: In xrpl.js v2.13.0 used in the XRPL Snap project, the `transferRateToDecimal` function is properly exported and can be directly imported with `import { transferRateToDecimal } from 'xrpl';`
```

---

```
Learnt from: vriveraPeersyst
PR: Peersyst/xrpl-snap#129
File: packages/site/src/domain/transaction/controller/TransactionController.ts:8-12
Timestamp: 2025-05-17T14:45:18.421Z
Learning: In xrpl.js v2.13.0 used in the XRPL Snap project, the `transferRateToDecimal` function is properly exported and can be directly imported with `import { transferRateToDecimal } from 'xrpl';`
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>



---

<details>
<summary>🧠 Learnings used</summary>

```
Learnt from: vriveraPeersyst
PR: Peersyst/xrpl-snap#129
File: packages/site/src/domain/transaction/controller/TransactionController.ts:98-111
Timestamp: 2025-05-17T14:29:55.110Z
Learning: In the TransactionController class of the XRPL Snap project, the `...rest` parameter in the `sendIOUTransaction` method does not contain flags from callers, so directly setting `flags: PARTIAL_PAYMENT_FLAG` without merging with existing flags is appropriate.
```

</details>

</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-17T14:45:20Z
author_association: NONE
diff_hunk: @@ -5,14 +5,17 @@ import { TransactionsWithMarker, XrplTx } from 'common/models/transaction/tx.typ
 import { withRetries } from 'common/query';
 import type Amount from 'common/utils/Amount';
 import { TransactionMeta } from 'common/utils/xrpl/meta';
+import Decimal from 'decimal.js';
 import { DomainError } from 'domain/error/DomainError';
 import { DomainEvents } from 'domain/events';
-import { xrpToDrops } from 'xrpl';
+import { xrpToDrops, transferRateToDecimal } from 'xrpl';
 
 import type { MetaMaskRepository } from '../../../data-access/repository/metamask/MetaMaskRepository';
 import type { XrplService } from '../../../data-access/repository/xrpl/XrplService';
 import { TransactionErrorCodes } from '../error/TransactionErrorCodes';
 
+const PARTIAL_PAYMENT_FLAG = 131072;
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: GuillemGarciaDev
body: Mover a archivo `constants` o `flags`
created_at: 2025-05-19T09:34:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -94,7 +87,28 @@ export default class TransactionController {
     const availableAmount: Amount = token.balance;
 
     if (!availableAmount.canPay(amount)) {
-      throw new DomainError(TransactionErrorCodes.INSUCCICIENT_BALANCE);
+      throw new DomainError(TransactionErrorCodes.INSUFFICIENT_BALANCE);
+    }
+
+    if (token.transferRate !== undefined && token.transferRate !== 0 && token.transferRate !== 1000000000) {
+      const feeDecimal = new Decimal(transferRateToDecimal(token.transferRate));
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: GuillemGarciaDev
body: Hacer metodo privado `computeTransferRate`
created_at: 2025-05-19T09:37:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -142,23 +146,47 @@ export class XrplService {
       }
 
       const tokenWithBalances: TokenWithBalance[] = [];
+      // Cache issuer transfer rates to avoid duplicate requests
+      const issuerTransferRates: Record<string, number | undefined> = {};
 
       for (const line of lines) {
         try {
+          const issuer = line.account;
+          let transferRate: number | undefined = issuerTransferRates[issuer];
+
+          if (transferRate === undefined) {
+            // Fetch issuer's transfer rate
+            const info: AccountInfoResponse = await client.request({
+              command: 'account_info',
+              account: issuer,
+            });
+            transferRate = info.result.account_data.TransferRate;
+            // Validate transfer rate
+            if (!isValidTransferRate(transferRate)) {
+              // Optionally: log a warning or skip this token
+              transferRate = undefined;
+            }
+            issuerTransferRates[issuer] = transferRate;
+          }
+
           const token = {
             currency: line.currency,
-            issuer: line.account,
+            issuer,
             decimals: 15,
+            transferRate, // Add transferRate to token (undefined means "no fee")
           };
           tokenWithBalances.push({
             ...token,
             balance: Amount.fromDecToken(new Decimal(line.balance).toFixed(14), token),
           });
-        } catch {}
+        } catch (err) {
+          // Optionally log error
path: packages/site/src/data-access/repository/xrpl/XrplService.ts
user: login: GuillemGarciaDev
body: borrar los comments
created_at: 2025-05-19T09:37:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -142,23 +146,47 @@ export class XrplService {
       }
 
       const tokenWithBalances: TokenWithBalance[] = [];
+      // Cache issuer transfer rates to avoid duplicate requests
+      const issuerTransferRates: Record<string, number | undefined> = {};
 
       for (const line of lines) {
         try {
+          const issuer = line.account;
+          let transferRate: number | undefined = issuerTransferRates[issuer];
+
+          if (transferRate === undefined) {
+            // Fetch issuer's transfer rate
+            const info: AccountInfoResponse = await client.request({
+              command: 'account_info',
+              account: issuer,
+            });
+            transferRate = info.result.account_data.TransferRate;
+            // Validate transfer rate
+            if (!isValidTransferRate(transferRate)) {
+              // Optionally: log a warning or skip this token
+              transferRate = undefined;
+            }
+            issuerTransferRates[issuer] = transferRate;
+          }
+
           const token = {
             currency: line.currency,
-            issuer: line.account,
+            issuer,
             decimals: 15,
+            transferRate, // Add transferRate to token (undefined means "no fee")
           };
           tokenWithBalances.push({
             ...token,
             balance: Amount.fromDecToken(new Decimal(line.balance).toFixed(14), token),
           });
-        } catch {}
+        } catch (err) {
+          // Optionally log error
+        }
       }
 
       return tokenWithBalances;
     } catch (e) {
+      // Optionally log error
path: packages/site/src/data-access/repository/xrpl/XrplService.ts
user: login: GuillemGarciaDev
body: idem
created_at: 2025-05-19T09:37:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2,11 +2,16 @@ import { TokenWithBalance } from 'common/models';
 import Amount from 'common/utils/Amount';
 import RepositoryErrorCodes from 'data-access/repository/error/RepositoryErrorCodes';
 import Decimal from 'decimal.js';
-import { AccountNFTsResponse, AccountTxResponse, Client, TxResponse } from 'xrpl';
+import { AccountNFTsResponse, AccountTxResponse, Client, TxResponse, AccountInfoResponse } from 'xrpl';
 
 import RepositoryError from '../error/RepositoryError';
 import { XrplErrorCodes } from './XrplErrorCodes';
 
+function isValidTransferRate(rate?: number): boolean {
path: packages/site/src/data-access/repository/xrpl/XrplService.ts
user: login: GuillemGarciaDev
body: mover a otro archivo `utils` o parecido
created_at: 2025-05-19T09:38:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -142,23 +146,47 @@ export class XrplService {
       }
 
       const tokenWithBalances: TokenWithBalance[] = [];
+      // Cache issuer transfer rates to avoid duplicate requests
path: packages/site/src/data-access/repository/xrpl/XrplService.ts
user: login: JordiParraCrespo
body: Esta logica la moveria al send, ya que si no hace que la carga de la lista de los tokens se haga mas lenta
created_at: 2025-05-19T09:50:32Z
author_association: COLLABORATOR
diff_hunk: @@ -94,7 +87,28 @@ export default class TransactionController {
     const availableAmount: Amount = token.balance;
 
     if (!availableAmount.canPay(amount)) {
-      throw new DomainError(TransactionErrorCodes.INSUCCICIENT_BALANCE);
+      throw new DomainError(TransactionErrorCodes.INSUFFICIENT_BALANCE);
+    }
+
+    if (token.transferRate !== undefined && token.transferRate !== 0 && token.transferRate !== 1000000000) {
+      const feeDecimal = new Decimal(transferRateToDecimal(token.transferRate));
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: JordiParraCrespo
body: Añade un comentario explicando xq es necesario hacer esto y tambien complementarlo con algún link útil a la documentación y/o a algun issue donde rapidamente se pueda entender xq hace falta hacer esto :)
created_at: 2025-05-19T09:51:58Z
author_association: COLLABORATOR
diff_hunk: @@ -5,14 +5,17 @@ import { TransactionsWithMarker, XrplTx } from 'common/models/transaction/tx.typ
 import { withRetries } from 'common/query';
 import type Amount from 'common/utils/Amount';
 import { TransactionMeta } from 'common/utils/xrpl/meta';
+import Decimal from 'decimal.js';
 import { DomainError } from 'domain/error/DomainError';
 import { DomainEvents } from 'domain/events';
-import { xrpToDrops } from 'xrpl';
+import { xrpToDrops, transferRateToDecimal } from 'xrpl';
 
 import type { MetaMaskRepository } from '../../../data-access/repository/metamask/MetaMaskRepository';
 import type { XrplService } from '../../../data-access/repository/xrpl/XrplService';
 import { TransactionErrorCodes } from '../error/TransactionErrorCodes';
 
+const PARTIAL_PAYMENT_FLAG = 131072;
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: vriveraPeersyst
body: Created constants/flags and move there.
created_at: 2025-05-19T10:34:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -94,7 +87,28 @@ export default class TransactionController {
     const availableAmount: Amount = token.balance;
 
     if (!availableAmount.canPay(amount)) {
-      throw new DomainError(TransactionErrorCodes.INSUCCICIENT_BALANCE);
+      throw new DomainError(TransactionErrorCodes.INSUFFICIENT_BALANCE);
+    }
+
+    if (token.transferRate !== undefined && token.transferRate !== 0 && token.transferRate !== 1000000000) {
+      const feeDecimal = new Decimal(transferRateToDecimal(token.transferRate));
path: packages/site/src/domain/transaction/controller/TransactionController.ts
user: login: vriveraPeersyst
body: Refactored the transfer rate calculation logic into a private method computeTransferRate and added a comment explaining why this calculation is necessary, with a link to the XRPL documentation.
created_at: 2025-05-19T10:35:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2,11 +2,16 @@ import { TokenWithBalance } from 'common/models';
 import Amount from 'common/utils/Amount';
 import RepositoryErrorCodes from 'data-access/repository/error/RepositoryErrorCodes';
 import Decimal from 'decimal.js';
-import { AccountNFTsResponse, AccountTxResponse, Client, TxResponse } from 'xrpl';
+import { AccountNFTsResponse, AccountTxResponse, Client, TxResponse, AccountInfoResponse } from 'xrpl';
 
 import RepositoryError from '../error/RepositoryError';
 import { XrplErrorCodes } from './XrplErrorCodes';
 
+function isValidTransferRate(rate?: number): boolean {
path: packages/site/src/data-access/repository/xrpl/XrplService.ts
user: login: vriveraPeersyst
body: Moved IsValidTransferRate to common/utils/xrpl/transfer-rate
created_at: 2025-05-19T10:38:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -142,23 +146,47 @@ export class XrplService {
       }
 
       const tokenWithBalances: TokenWithBalance[] = [];
+      // Cache issuer transfer rates to avoid duplicate requests
+      const issuerTransferRates: Record<string, number | undefined> = {};
 
       for (const line of lines) {
         try {
+          const issuer = line.account;
+          let transferRate: number | undefined = issuerTransferRates[issuer];
+
+          if (transferRate === undefined) {
+            // Fetch issuer's transfer rate
+            const info: AccountInfoResponse = await client.request({
+              command: 'account_info',
+              account: issuer,
+            });
+            transferRate = info.result.account_data.TransferRate;
+            // Validate transfer rate
+            if (!isValidTransferRate(transferRate)) {
+              // Optionally: log a warning or skip this token
+              transferRate = undefined;
+            }
+            issuerTransferRates[issuer] = transferRate;
+          }
+
           const token = {
             currency: line.currency,
-            issuer: line.account,
+            issuer,
             decimals: 15,
+            transferRate, // Add transferRate to token (undefined means "no fee")
           };
           tokenWithBalances.push({
             ...token,
             balance: Amount.fromDecToken(new Decimal(line.balance).toFixed(14), token),
           });
-        } catch {}
+        } catch (err) {
+          // Optionally log error
path: packages/site/src/data-access/repository/xrpl/XrplService.ts
user: login: vriveraPeersyst
body: deleted
created_at: 2025-05-19T10:58:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -142,23 +146,47 @@ export class XrplService {
       }
 
       const tokenWithBalances: TokenWithBalance[] = [];
+      // Cache issuer transfer rates to avoid duplicate requests
+      const issuerTransferRates: Record<string, number | undefined> = {};
 
       for (const line of lines) {
         try {
+          const issuer = line.account;
+          let transferRate: number | undefined = issuerTransferRates[issuer];
+
+          if (transferRate === undefined) {
+            // Fetch issuer's transfer rate
+            const info: AccountInfoResponse = await client.request({
+              command: 'account_info',
+              account: issuer,
+            });
+            transferRate = info.result.account_data.TransferRate;
+            // Validate transfer rate
+            if (!isValidTransferRate(transferRate)) {
+              // Optionally: log a warning or skip this token
+              transferRate = undefined;
+            }
+            issuerTransferRates[issuer] = transferRate;
+          }
+
           const token = {
             currency: line.currency,
-            issuer: line.account,
+            issuer,
             decimals: 15,
+            transferRate, // Add transferRate to token (undefined means "no fee")
           };
           tokenWithBalances.push({
             ...token,
             balance: Amount.fromDecToken(new Decimal(line.balance).toFixed(14), token),
           });
-        } catch {}
+        } catch (err) {
+          // Optionally log error
+        }
       }
 
       return tokenWithBalances;
     } catch (e) {
+      // Optionally log error
path: packages/site/src/data-access/repository/xrpl/XrplService.ts
user: login: vriveraPeersyst
body: deleted
created_at: 2025-05-19T10:58:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -142,23 +146,47 @@ export class XrplService {
       }
 
       const tokenWithBalances: TokenWithBalance[] = [];
+      // Cache issuer transfer rates to avoid duplicate requests
path: packages/site/src/data-access/repository/xrpl/XrplService.ts
user: login: vriveraPeersyst
body: done, moved to SendIOUTransaction
created_at: 2025-05-19T11:31:17Z
author_association: CONTRIBUTOR

PR comments:
user: login: vercel[bot]
created_at: 2025-05-17T12:30:13Z
body: [vc]: #ZWMuZXdkBEoSOQbGH40agtXJbhR4FYBEu4w5KVGsZq4=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJ4cnBsLXNuYXAiLCJsaXZlRmVlZGJhY2siOnsicmVzb2x2ZWQiOjAsInVucmVzb2x2ZWQiOjAsInRvdGFsIjowLCJsaW5rIjoieHJwbC1zbmFwLWdpdC1maXgtdGVjcGF0aHBhcnRpYWwtcGVlcnN5c3QudmVyY2VsLmFwcCJ9LCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vcGVlcnN5c3QveHJwbC1zbmFwLzlxZGM5N2FQVjlyQ25ncHpxa29aTTJ5UFJQaWkiLCJwcmV2aWV3VXJsIjoieHJwbC1zbmFwLWdpdC1maXgtdGVjcGF0aHBhcnRpYWwtcGVlcnN5c3QudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJERVBMT1lFRCIsInJvb3REaXJlY3RvcnkiOiJwYWNrYWdlcy9zaXRlIn1dfQ==
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **xrpl-snap** | ✅ Ready ([Inspect](https://vercel.com/peersyst/xrpl-snap/9qdc97aPV9rCngpzqkoZM2yPRPii)) | [Visit Preview](https://xrpl-snap-git-fix-tecpathpartial-peersyst.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/xrpl-snap-git-fix-tecpathpartial-peersyst.vercel.app?via=pr-comment-feedback-link) | May 19, 2025 11:49am |


author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-05-17T12:30:14Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

<details>
<summary>📝 Walkthrough</summary>

```markdown
## Walkthrough

The changes introduce transfer rate awareness to IOU token transactions, including validation, caching, and propagation of transfer rates throughout the transaction flow. The MetaMask repository's send method is extended to support additional parameters for partial payments. Error codes are corrected for spelling, and internal logic is updated to handle transfer rate calculations and partial payment flags.

## Changes

| File(s)                                                                                          | Change Summary                                                                                                                                                                                                                  |
|-------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `packages/site/src/common/models/token/index.ts`                                                | Added an optional `transferRate?: number` property to the `Token` type definition.                                                                                                                                              |
| `packages/site/src/common/constants/flags.ts`                                                  | Added and exported a new constant `PARTIAL_PAYMENT_FLAG = 131072`.                                                                                                                                                              |
| `packages/site/src/common/utils/xrpl/transfer-rate.ts`                                         | Added `isValidTransferRate(rate?: number): boolean` function to validate XRPL transfer rates.                                                                                                                                  |
| `packages/site/src/data-access/repository/metamask/MetaMaskRepository.ts`                       | Extended the `send` method to accept optional `sendMax` and `flags` parameters, passing them to the transaction parameters for `invokeSnap`.                                                                                  |
| `packages/site/src/data-access/repository/xrpl/XrplService.ts`                                 | Minor cleanup in `getIOUTokens`: removed blank line, assigned issuer to variable, improved error handling by capturing errors in catch block.                                                                                   |
| `packages/site/src/domain/transaction/controller/TransactionController.ts`                      | Fixed typo in error code from `INSUCCICIENT_BALANCE` to `INSUFFICIENT_BALANCE`. Enhanced `sendIOUTransaction` to handle tokens with transfer rates by computing `sendMax` and setting partial payment flags. Added private `computeTransferRate` method. Removed some JSDoc and eslint-disable comments. |
| `packages/site/src/domain/transaction/error/TransactionErrorCodes.ts`                           | Renamed enum member `INSUCCICIENT_BALANCE` to `INSUFFICIENT_BALANCE` and updated its string value accordingly.                                                                                                                  |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant TransactionController
    participant XrplService
    participant MetaMaskRepository

    User->>TransactionController: Initiate IOU Token Send
    TransactionController->>XrplService: getIOUTokens(account)
    XrplService->>XrplService: Fetch issuer transfer rates (cached)
    XrplService-->>TransactionController: Token(s) with transferRate
    TransactionController->>TransactionController: Validate transferRate, compute sendMax if needed
    TransactionController->>MetaMaskRepository: send({ amount, sendMax, destination, destinationTag, flags })
    MetaMaskRepository->>MetaMaskRepository: Prepare transaction params (include sendMax, flags)
    MetaMaskRepository-->>TransactionController: Transaction result
    TransactionController-->>User: Success or error response
```

## Suggested reviewers

- AdriaCarrera  
- JordiParraCrespo  
- obnol
```

</details>

<!-- walkthrough_end -->
<!-- This is an auto-generated comment: all tool run failures by coderabbit.ai -->

> [!WARNING]
> There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.
> 
> <details>
> <summary>🔧 ESLint</summary>
> 
> > If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
> 
> yarn install v1.22.22
> [1/4] Resolving packages...
> (node:31790) [DEP0169] DeprecationWarning: `url.parse()` behavior is not standardized and prone to errors that have security implications. Use the WHATWG URL API instead. CVEs are not issued for `url.parse()` vulnerabilities.
> (Use `node --trace-deprecation ...` to show where the warning was created)
> warning eslint@8.57.1: This version is no longer supported. Please see https://eslint.org/version-support for other options.
> warning eslint > @humanwhocodes/config-array@0.13.0: Use @eslint/config-array instead
> warning eslint > @humanwhocodes/config-array > @humanwhocodes/object-schema@2.0.3: Use @eslint/object-schema instead
> warning eslint > file-entry-cache > flat-cache > rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported
> warning eslint > file-entry-cache > flat-cache > rimraf > glob@7.2.3: Glob versions prior to v9 are no longer supported
> warning eslint > file-entry-cache > flat-cache > rimraf > glob > inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
> warning jest > @jest/core > jest-config > glob@7.2.3: Glob versions prior to v9 are no longer supported
> warning jest > @jest/core > jest-runtime > glob@7.2.3: Glob versions prior to v9 are no longer supported
> warning jest > @jest/core > @jest/reporters > glob@7.2.3: Glob versions prior to v9 are no longer supported
> warning jest > @jest/core > @jest/transform > babel-plugin-istanbul > test-exclude > glob@7.2.3: Glob versions prior to v9 are no longer supported
> warning workspace-aggregator-229296c0-b7da-4cc4-8589-ef3f9ce54e1d > eslint@8.57.1: This version is no longer supported. Please see https://eslint.org/version-support for other options.
> [2/4] Fetching packages...
> error eslint-plugin-jsdoc@41.1.2: The engine "node" is incompatible with this module. Expected version "^14 || ^16 || ^17 || ^18 || ^19". Got "24.0.2"
> error Found incompatible module.
> info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
> 
> 
> 
> </details>

<!-- end of auto-generated comment: all tool run failures by coderabbit.ai -->

<!-- announcements_start -->

> [!NOTE]
> <details>
> <summary>⚡️ AI Code Reviews for VS Code, Cursor, Windsurf</summary>
> 
> CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
> Learn more [here](http://coderabbit.ai/ide).
> 
> </details>

---

> [!NOTE]
> <details>
> <summary>⚡️ Faster reviews with caching</summary>
> 
> CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure `Review - Disable Cache` at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the `Data Retention` setting under your Organization Settings.
> Enjoy the performance boost—your workflow just got faster.
> 
> </details>

<!-- announcements_end -->

---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 3d036a28a44fc343c630b9faa01260de272e5906 and e4eed93b73321f0d29783c3309dfc1ae5e329cf0.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `packages/site/src/common/utils/xrpl/transfer-rate.ts` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* packages/site/src/common/utils/xrpl/transfer-rate.ts

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: Build, lint, and test / Build
* GitHub Check: Build, lint, and test / Lint
* GitHub Check: run-security-scan

</details>

</details>
<!-- internal state start -->


<!-- DwQgtGAEAqAWCWBnSTIEMB26CuAXA9mAOYCmGJATmriQCaQDG+Ats2bgFyQAOFk+AIwBWJBrngA3EsgEBPRvlqU0AgfFwA6NPEgQAfACgjoCEYDEZyAAUASpETZWaCrKNxU3bABsvkCiQBHbGlcSHFcLzpIACIAMXgADzDRKwBBaAAJAH00m2gASVSAGUguVNp6B25ufApQgDNayHyAeQBVazRZNgxcZAB3dVgURAdKMKoMRHrxmelIAApeEile5IY0zJzUvMKigEpo9Ar/UfnMEbHIfthKEnsyWngMImb2zu72ZGeJfC8JZ6vVptAZDS7BChgNDVLzwKK4SbTWYkeb9NDIeraWEva5g3C3SCUChNJhKSAAAxoG3S2VyBWK5I0MAJmPgXmw/n4DAYHP89AEojQ2EQ93x90QskQNGYkCe9Aw+FCaG5+Gwa0afDFxye4nwGDQvjmkAE2HqMz4TRFoS13Gc4gNYFtn3VXjQr1oHMBYQJCMwiGVuowGjcBIYsEwpG+vWJHoYUWeDHZSg4Rig5SeOIu+G4gYNFN9U3NNmoJHJPGJ3EouHkBG993J0HwAGsyGXq5WUFhycxFCQvIgAPQEFsYAfPJQJDR9RkGKAAWUU8Hqsi95IAGhRuF4AMqUAFxqeINv4SAzXBhwnK4ZIMYUQCYBMgG4iiyWywC0HWKcqmGrcFlno0ZZsPiigADSQBIBrwLQJbetQn5UDQIzoKEkToqEACMoEAAy4TheG4dhKD1OW0jsOBmD0NQuBXt6qCIaKJ7DmQ/DCKIfTBlAbTcDB4g4k+foBvAeoAMJ6gifyRBQh7HgozCeEhH7RPU3i+AxRxyLKkjQV6WoFkifAMca8hYYR+HYeZ6AYPQwq6QgyC1gwBo8q6SFauSu7WXOaAJG+BrBOBNzwBeCZJvMenPsiJBMvkSr9ieVoOQSlL1FYdrwAaaXOrgZb1K6ry1ssqyhJSKQ0tsuwMoSFDEhQiCcZA5RCMKfGvOSc4kDR3mIE2NgkDUiDqLUsgyWEJ7MNCn7PDQFD6r45Iil5PllraVDAeMtZrjYVhFA+FKebQ3m+aecJeFR1mQMK9y8NmVbyIgsC1PilGnk0eVuvVIbXdQF5kA4pxwdazZ/bi+LoJACoYGACLaXm+nmn4sFMDV7FePIoXYGSWpGs8n5Oj0So9r+VmVJ1ePpXm+PsKe+WBQgkRjSOoIgXg4Pw+MRn+BNuNqmGEZ0EyABCypNmiFC0MgTDydQ8BqLC1bIdzvTaOQtAUT4+CDDiTk+JQAyPbKJ4KqEVRbvIC2PEdslML0zzBA81legqFATb4wIfATn0GAAcieJAJDNc2yv1jxkAwcIDHc2p0BRF1atgPGwdozAOSeRXU6V1JbHSey5ViHLzLjNt8dgqpRjQRCIcJWAvf7SCtckUr1cy9xoGa7FRLaDBNm69yoOSXc95GA6DTQM6zmAhgGCYUCPPwJFCgQxBkMoND0FLBNcLwrEiGIkjzJppLKKo6haDo+jT+AUDuN8yAXIvhCkOQDHrywm+I/09iOBNLjGQoShUBPpobQuhJ5GEvqYAwg9e6DlHiQEeFAGADg3nqAcPYlD9iHMDUc45/aHhTNEQhBgLCNXyMvZ+JZKjf2cPIfAJE+YvGkF9CkjYRxtlkB2JQ9RnjqGrtcdEhIA6h35PINAFQvRZhzNXSmFY7r5kihQYsY955hA4fWDAjgBQUEZJAX2/AxR8AYZGa4UcJpYyYgSOuUovRSgoNgMQBd+CGT7JQ1RlYvbmEsKkLwM0ZZ6lTp+JQiZnB+KmCo/2NQ6hRCaJ4AQsIGCEltuIJhs5GoVGiVIvUMjbp1HNuzRRJYAD8XANHMC0bJLUESnrwjUSw7BZZcYDxFjAke6h4GIEQcgt+qD0F9kHMxHB1k8HTmDIQ6IqZIHQOHnAhBSDeJoChNyaQg5/ADSGi4NBnU0ATR6gODqXV0S9X6vgUew18EGDGcQrxZCn6ryiA4Jwv86GMHDIwxAzCLbWSAp1R69BGn7LQN1I5ayCAuDLGiZA/saBDPoLWb8/VrT9BPGInU0jfDZlzL4Va2zOp6y4J8w6y0SYUnekQI8TI4BkQhiQT+2L1p1XQJyFF8ILH3GAr8gA5HfCgRBHDUyULY+xuBPSZjjrUrhPDAwxSmNBUUBJ2VgU/PpISeoeAhPpcgW0ZxYWsopD8YG259TcDLDrXwCpP4YzJB5S2RKXrkliPlI8J0+wS3AlaMan5ILsnmM8rU5B+ho2jvQOluK6pMj0YqW4fAvD4CIMFJx1VaqQFebQbErwjGolMWI6KnjGo+NXtXAJWogmuirv48JCRIlrwTbE+JiTwgR1TJAfZvz7DwCIPqYVnIE68ToPi9EsgMAJMWrQBYABvdARNejgQFXxUJM6QjPFCdAN0kAAC+XAJ2zqXYGLgtjAQAG5J2ql6FwDcW5UhTtwEe7dnbq4rqIMUiGmjKBHrXfsLgVhiTMCQCQYA+6Xh6DLIAJMIvwSiHQ7UdE7tkntwG6m1CQF3WLvXqJDc7AwPvAqS5AG7IBbsXShjAe6YYvCPTB38Z7NxeEvbBo9I6jpPvPdRq9N6CPLrdE+0pWij3Yc4y+igb6P3WG/b+/9JGiBAc7IwV0owKQAqBX1EFw0GldimdIVpNBZkDnmYsuMowByrJOes2QmyaI7KbHsrZCnjmnJcDJC5RCJ5gCMGp2BbStM6fhfpwztmTMJCowOJju4KD7min0AhRCSGpBuSvF+X9Hm0Poa8yMHzSC4GBKwv63yQJ/K7EFvcwVSz8OQOgpccIRF+BID2AEorBEFhIGXY0roMBNkgNiVu9QZpTQwLwvMiY4RrH8EEEI0rBpYwJDG7MKBfEN3wFIPg5J2tHnAlqG8EJtSnFvhDTW6BRjttVh6j8MadYQWcBlOJ9Y1uUDLAKDU9wbaCr3jiPS2Cd7sXAqs104ccRPH8GIS6/pSAqMW88aK35YPgrxPZU7FBzuRApZYmqTQU1pqky9kc5Z8B6cGjiSb3BisvP5vQeo36rKEnkgrJy55hhxKx61uFjAfo0+O/T8MoQnI5gLkle4RImgCPJESG7rNaD4HmMbdA/3VWn10SeSN4wM0BJjXGhg4Fi7EkNDG/o4Emi874Cjr0/Qs1KGDOAqL+ay1hNrMW0QpbQnIGeVUqJ9AYnYDifG9gvCUlQD0Qrj11vgkW/t3wQaHbqBc4rVW6JfBa3u6SRHUZjmIDOagc06Z7mOlzJYCrIciIVWjjV5JSgA5oC573qJcS6upLnMuVFmLFDq0PJ/olwnbzmG++Rn9pUbiTy40qUjwxvZTyk/JPkb2242giREvkKfABRb20AsiC2KKkb2IkZ+yRH2PtosRYjT/yHPhfS+igr7Xyp40kaKQjvPSXwSZeMBljtSOjLpfAzZd+c3fIXYn/tBv1MPP5IVtQxB9zUUJpQcwAl/AYYVg5VGIMcrsKAuUJg/QEYjIScWBPwtodoHgQtCtiJptkJxcDR/AxF5AJUDtVV0cyAYoF5TtYQ1ZtsoYuEhQfEkDCwOZYJUBGg1R6AFhxciImgMJCIhDcJ9hwJ1BGcvAXISw75L8EM/JvVAYJcfxegMQmhVtRgIRED8lTwUQ/5mBvBxAzY7I+5ehhFj1iZNJyQFgMJIAABqVggyJREgfYMsWyZ7ZKAAEVEHgFdjLFhAECoF/g1FInDhFEZSGGAmCgR1FBfz4VQDFCwEWlCEGDBi1FqHbSXV8HI2nU/ClgUiiAJStljlhWShzmKG2AAE05wD8shYhj8ABxMsK0agpVBRRGJCG2VFKXZAcXYCQAmI2/QMZCJI0GR6VmQoolN6R1XbY0EgO7JkVIalWlWHSCJCBVegckPIvAEgX/Rw18ZCZlHVHgSgDUGULUHWKQoY31ZKejIlL1YIJkOcZ4EkNCDRfHS1eYLmObPMZ5RAFge4AAKW3A8Kxzkk9mJQuDVCunoGkGxFwDACeH9AuzBPYBN1zW8Rm0LT9wJBLRCUDHtxIkd2rRdzdwSQ92SXeVSS/UkFgnWKDXxV4BpI6JYHyN2JfBoAWGyM4HsHExWwUScJKX4yEwAyIDP2CVkwEj/zvzEmjEL20SkyaW7haRmQz20yz2eBz0GOri6VlN1goGL1iPL11Kr2nAc3GScxc1T3UxVM6RFyVk1KlMDAHF1wNK1L1Bn37zEgFWr0i2uXITuSoQSxUQV2YTIEcEgDYDKXGE33H0nz3xqKPxP3XwJ38H1DYCOJjO3131n3n0X2X1X2TMclqE73BkQErB8C9B/SlDQBbGiJ5NhxxHuNblGCxwymrRSOGHxFQDDJlEjK0QJwND+MukTmrVrAmmp1yOLI7kqHLLTXDVlwMRb2MSt0sVKQTXUBKyqy0Ujk5DMRzVNy8XNzt2xPuFxMDwj2qWd2j1dzrXJMbVSRnzXL7I5jIBxVoHxVH1jKnxzMP3zNP0gFA0zJ33jNzMTILLP0lP9Dvw9Nqi9OkDLB7IVNcw03aVtPVNHGVTv2dP71dMdOrhgtqDgvqlNMuQtJTyVLT001VJQXz38RohUIHGwx9PGVr39Li0bxoWDOSxSUWP9QUCmHotCDTIKLKKKEqOqNzLqNSEaOQmmhjHsSiFrkrUvNGM/FKUoHjSbIpAwgAGZBCAB2AAJh0Rvm1F4VVTIPOHsErHDm4QSVJVoPtlhBbEDWmjMOCKuik1JTAAEHRCiCV3jSaDUFwHM34ErHPI7N7yAKUF8pFDRKuTzUxPLRXNPJtzxKxId2UqdxrRvNjwbS90gBlOrLWEOPxSJP4qlGsB2HpDErSCqJqKkvqMgAAF5IBdKDLjKkKrS3MqLOkaKdTiq+hGLHV7NSKk9LSKLrT08+rulRw8A2RBx/MtwHSDIwAGJmKEros2LXEOKnkkt+ZKTeKaVTxeYhjyQkAAA1KCWgNkygJw8FARQ4j1L1aCWCTAkobQhiZuUylSIdIYyAjkS3OxPuEiVbDABSdovuSFIYcYbguY0HK8yAAAL0oBPAWAEAv1WVOA9xxGiAVB0JIGiFEPXJInENQA/C43GEiqwDBsTFsikERkYSH3QNMgIjZqIlrEMvMm5sIjrN+rv0ES3GCnUEDTDFECbG5zcXuGuJMIhtrD+kcTJpkMpr4Fu1qFbhhBXHcPuEmCBzFu7gR3JvESGLyMiHBMqQSHrlXGdldngBRtuoKWUX5qGM0hugBAzFeA/F+3Yn4RrBPHmyXBrDaKMhep1FERVHFl0hPHer8G8GkHirNySst11TPOPMysj0RpjzJLjwKtiFOr4VKopHKudriMQCuroIdqcIWAYj4yjIoCEwxr+BIEwAguQptKQX6vmswSWq8BWvNDWpLFGsTzAQgVngumeQfm2urQ3nYC4CoE/l2vkEPl7EAWCrPlAUMBnjBPUH/AliyH8ABBpToCyGrLqA3uMCvkgEMoABZDKABOa+6+gADjvoEHqGvrvqWUMoAFYAA2XCa+t+gUNAfSp+7CDCNAQB7+v+u+tASB8+re6+7++ob+kgX+6+2ga+5UAQHSh+ugV+wQ9+hgX+tAQynSn+3+nShgQy7CX+m+5uhBy+7CEB8h7+u+jCBgHS2gHS3+6B+oAQBgbCEgAQDCWgeoQykgXCX+/S7CJyX+2gb+qh/+xhiASAa+kgO+nS7Cb+zBtAO+p+3+u+kgGRrBp+2+/R2gJ+/SjCZBwygUOMNB1BmRlRqALh7CHh0hp+yB6++oTh6+pRrRgQO+zENAcBwy/+pQQyoykgNh2hlxwkdR/BnSgQfSnS8hjCeobCWge+0BqhtJ7CO+sRhgCBmJkgchz+zJ8+0e7ev8aCRAfelYOEQ3WgLIOefQIAA -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Peersyst/xrpl-snap&utm_content=129):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `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 explain this code block.`
  -	`@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 explain its main purpose.`
  - `@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.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

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 generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this 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](https://docs.coderabbit.ai/guides/configure-coderabbit) 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](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE