Skip to content

fix: add throttler to tron chain adapter#11544

Merged
gomesalexandre merged 6 commits intodevelopfrom
tron-throttle
Dec 29, 2025
Merged

fix: add throttler to tron chain adapter#11544
gomesalexandre merged 6 commits intodevelopfrom
tron-throttle

Conversation

@NeOMakinG
Copy link
Collaborator

@NeOMakinG NeOMakinG commented Dec 29, 2025

Description

Adding a throttle to tron chain adapter so we are not limited anymore when estimating fees when doing sends or other actions

Issue (if applicable)

closes #11543

Risk

Low

High Risk PRs Require 2 approvals

What protocols, transaction types, wallets or contract interactions might be affected by this PR?

Testing

  • Try to send some TRX to a sub account, notice you are not rate limited anymore (or at least check networks requests)

Engineering

Operations

  • 🏁 My feature is behind a flag and doesn't require operations testing (yet)

Screenshots (if applicable)

image

Summary by CodeRabbit

  • Refactor
    • Implemented serialized request queue to improve stability and throttling of network operations on TRON chain.

✏️ Tip: You can customize this high-level summary in your review settings.

@NeOMakinG NeOMakinG requested a review from a team as a code owner December 29, 2025 15:33
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 29, 2025

📝 Walkthrough

Walkthrough

Added a PQueue-based request throttling mechanism to TronChainAdapter. Wrapped multiple async operations (triggerSmartContract, createTransaction, addUpdateData, getChainParameters, sendTrx, fetch calls, getAccount) through a serialized request queue with configurable concurrency and rate limiting to prevent rate-limit issues.

Changes

Cohort / File(s) Summary
TronChainAdapter request throttling
packages/chain-adapters/src/tron/TronChainAdapter.ts
Added requestQueue: PQueue private member to ChainAdapter class. Wrapped TronWeb and HTTP requests through queue with concurrency of 1 and interval-based rate limiting. Updated TRC20/TRX transaction building, account queries, and fee-estimation calls to use queued variants. Normalized raw_data_hex handling via temporary value. Maintained existing error paths.

Sequence Diagram

sequenceDiagram
    participant Client
    participant ChainAdapter
    participant RequestQueue as PQueue<br/>(requestQueue)
    participant TronWeb
    participant HTTP

    Client->>ChainAdapter: buildTransaction()
    
    rect rgb(200, 220, 240)
    Note over ChainAdapter,RequestQueue: Queued Request Flow
    ChainAdapter->>RequestQueue: queue.add(triggerSmartContract)
    activate RequestQueue
    RequestQueue->>RequestQueue: Wait for slot<br/>(concurrency: 1)
    RequestQueue->>TronWeb: triggerSmartContract()
    TronWeb-->>RequestQueue: response
    deactivate RequestQueue
    RequestQueue-->>ChainAdapter: result
    end
    
    rect rgb(200, 220, 240)
    Note over ChainAdapter,RequestQueue: Serial Fee Estimation
    ChainAdapter->>RequestQueue: queue.add(getChainParameters)
    activate RequestQueue
    RequestQueue->>HTTP: fetch chain params
    HTTP-->>RequestQueue: data
    deactivate RequestQueue
    RequestQueue-->>ChainAdapter: parameters
    end
    
    rect rgb(200, 220, 240)
    Note over ChainAdapter,RequestQueue: Account Query
    ChainAdapter->>RequestQueue: queue.add(getAccount)
    activate RequestQueue
    RequestQueue->>TronWeb: getAccount()
    TronWeb-->>RequestQueue: account data
    deactivate RequestQueue
    RequestQueue-->>ChainAdapter: account info
    end
    
    ChainAdapter-->>Client: signedTx ready
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • gomesalexandre
  • premiumjibles

Poem

🐰 A queue, a queue! The requests now wait,
No rushing through at a frantic rate!
One by one, they hop in line,
With throttled grace—oh, how divine!
The Tron adapter breathes with ease,
Rate limits tamed, the rabbit sees. 🚀

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding a throttler to the Tron chain adapter to prevent rate limiting.
Linked Issues check ✅ Passed The PR implements request throttling using PQueue with configurable concurrency in the TronChainAdapter, directly addressing the requirements in issue #11543.
Out of Scope Changes check ✅ Passed All changes are scoped to TronChainAdapter.ts and implement only the throttling mechanism requested in issue #11543 without extraneous modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch tron-throttle

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/chain-adapters/src/tron/TronChainAdapter.ts (2)

255-257: Consider removing as any cast.

The intermediate as any cast could be replaced with as unknown for better type safety, or the typing could be improved by checking TronWeb's return type signature.

🔎 Suggested type-safe alternative
-        txData = (await this.requestQueue.add(() =>
-          tronWeb.transactionBuilder.addUpdateData(txData as any, memo, 'utf8'),
-        )) as TronUnsignedTx
+        txData = (await this.requestQueue.add(() =>
+          tronWeb.transactionBuilder.addUpdateData(txData as unknown, memo, 'utf8'),
+        )) as TronUnsignedTx

Apply the same change at lines 431-433.

Also applies to: 431-433


264-274: Consider using unknown instead of any for type safety.

The rawDataHexValue variable uses any type. Per coding guidelines, prefer unknown when the type is truly unknown, as it enforces type guards before usage.

🔎 Suggested improvement
-      const rawDataHexValue: any = txData.raw_data_hex
+      const rawDataHexValue: unknown = txData.raw_data_hex
       const rawDataHex =
         typeof rawDataHexValue === 'string'
           ? rawDataHexValue
           : Buffer.isBuffer(rawDataHexValue)
           ? rawDataHexValue.toString('hex')
           : Array.isArray(rawDataHexValue)
           ? Buffer.from(rawDataHexValue).toString('hex')
           : (() => {
               throw new Error(`Unexpected raw_data_hex type: ${typeof rawDataHexValue}`)
             })()
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e5e371b and a733f15.

📒 Files selected for processing (1)
  • packages/chain-adapters/src/tron/TronChainAdapter.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Never assume a library is available - always check imports/package.json first
Prefer composition over inheritance
Write self-documenting code with clear variable and function names
Keep functions small and focused on a single responsibility
Avoid deep nesting - use early returns instead
Prefer procedural and easy to understand code
Never expose, log, or commit secrets, API keys, or credentials
Validate all inputs, especially user inputs
Handle errors gracefully with meaningful messages
Don't silently catch and ignore exceptions
Log errors appropriately for debugging
Provide fallback behavior when possible
Use appropriate data structures for the task
Never add code comments unless explicitly requested
When modifying code, do not add comments that reference previous implementations or explain what changed. Comments should only describe the current logic and functionality.
Use meaningful names for branches, variables, and functions
Always run yarn lint --fix and yarn type-check after making changes
Avoid let variable assignments - prefer const with inline IIFE switch statements or extract to functions for conditional logic

Files:

  • packages/chain-adapters/src/tron/TronChainAdapter.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid useEffect where practical - use it only when necessary and following best practices
Avoid 'any' types - use specific type annotations instead
For default values with user overrides, use computed values (useMemo) instead of useEffect - pattern: userSelected ?? smartDefault ?? fallback
When function parameters are unused due to interface requirements, refactor the interface or implementation to remove them rather than prefixing with underscore
Sanitize data before displaying to prevent XSS
Memoize aggressively - wrap component variables in useMemo and callbacks in useCallback where possible
For static JSX icon elements (e.g., <TbCopy />) that don't depend on state/props, define them as constants outside the component to avoid re-renders instead of using useMemo
Account for light/dark mode using useColorModeValue hook
Account for responsive mobile designs in all UI components
When applying styles, use the existing standards and conventions of the codebase
Use Chakra UI components and conventions
All copy/text must use translation keys - never hardcode strings
Use the translation hook: useTranslate() from react-polyglot
Use useFeatureFlag('FlagName') hook to access feature flag values in components
Prefer type over interface for type definitions
Use strict typing - avoid any
Use Nominal types for domain identifiers (e.g., WalletId, AccountId)
Import types from @shapeshiftoss/caip for chain/account/asset IDs
Use useAppSelector for Redux state
Use useAppDispatch for Redux actions
Memoize expensive computations with useMemo
Memoize callbacks with useCallback

**/*.{ts,tsx}: Use Result<T, E> pattern for error handling in swappers and APIs; ALWAYS use Ok() and Err() from @sniptt/monads; AVOID throwing within swapper API implementations
ALWAYS use custom error classes from @shapeshiftoss/errors with meaningful error codes for internationalization and relevant details in error objects
ALWAYS wrap async op...

Files:

  • packages/chain-adapters/src/tron/TronChainAdapter.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)

**/*.{js,jsx,ts,tsx}: Use camelCase for variables, functions, and methods with descriptive names that explain the purpose
Use verb prefixes for functions that perform actions (e.g., fetch, validate, execute, update, calculate)
Use UPPER_SNAKE_CASE for constants and configuration values with descriptive names
Use handle prefix for event handlers with descriptive names in camelCase
Use descriptive boolean variable names with is, has, can, should prefixes
Use named exports for components, functions, and utilities instead of default exports
Use descriptive import names and avoid renaming imports unless necessary
Avoid non-descriptive variable names like data, item, obj, and single-letter variable names except in loops
Avoid abbreviations in names unless they are widely understood
Avoid generic function names like fn, func, or callback

Files:

  • packages/chain-adapters/src/tron/TronChainAdapter.ts
🧠 Learnings (10)
📓 Common learnings
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11261
File: src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx:117-172
Timestamp: 2025-12-03T23:16:28.342Z
Learning: In TRON transaction confirmation polling (e.g., approval flows in useAllowanceApproval.tsx), gomesalexandre is comfortable with optimistic completion when polling times out after the configured duration (e.g., 60 seconds). He considers the timeout a "paranoia" safety net for unlikely scenarios, expecting normal transactions to complete much faster. He prefers to defer more sophisticated timeout/failure handling as a separate follow-up concern rather than expanding PR scope.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11449
File: packages/chain-adapters/src/tron/TronChainAdapter.ts:570-596
Timestamp: 2025-12-17T14:50:01.629Z
Learning: In packages/chain-adapters/src/tron/TronChainAdapter.ts, the parseTx method uses `unknown` type for the txHashOrTx parameter intentionally. TRON is a "second-class chain" that works differently from other chains - it accepts either a string hash (to fetch TronTx via unchained client) or a TronTx object directly. The base chain-adapter interface is strongly typed and doesn't accommodate this flexible signature, so `unknown` is used as an appropriate escape hatch rather than a type safety issue.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/pages/RFOX/components/Stake/components/StakeSummary.tsx:112-114
Timestamp: 2025-08-22T13:00:44.879Z
Learning: NeOMakinG prefers to keep PR changes minimal and focused on the core objectives, avoiding cosmetic or defensive code improvements that aren't directly related to the PR scope, even when they would improve robustness.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10128
File: .cursor/rules/error-handling.mdc:266-274
Timestamp: 2025-07-29T10:35:22.059Z
Learning: NeOMakinG prefers less nitpicky suggestions on documentation and best practices files, finding overly detailed suggestions on minor implementation details (like console.error vs logger.error) too granular for cursor rules documentation.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/pages/Dashboard/components/AccountList/AccountTable.tsx:60-0
Timestamp: 2025-09-02T08:34:08.157Z
Learning: NeOMakinG prefers code review comments to focus only on actual PR changes, not pre-existing code issues, unless there are critical security or correctness concerns directly related to the new functionality.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10234
File: src/components/MultiHopTrade/hooks/useGetTradeQuotes/hooks/useTrackTradeQuotes.ts:42-86
Timestamp: 2025-08-08T11:41:22.794Z
Learning: NeOMakinG prefers not to include refactors in move-only PRs; such suggestions should be deferred to follow-up issues instead of being applied within the same PR.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/components/Table/Table.theme.ts:177-180
Timestamp: 2025-09-02T12:38:46.940Z
Learning: NeOMakinG prefers to defer technical debt and CSS correctness issues (like improper hover selectors) to follow-up PRs when the current PR is already large and focused on major feature implementation, even when the issues are valid from a usability/technical perspective.
📚 Learning: 2025-12-17T14:50:01.629Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11449
File: packages/chain-adapters/src/tron/TronChainAdapter.ts:570-596
Timestamp: 2025-12-17T14:50:01.629Z
Learning: In packages/chain-adapters/src/tron/TronChainAdapter.ts, the parseTx method uses `unknown` type for the txHashOrTx parameter intentionally. TRON is a "second-class chain" that works differently from other chains - it accepts either a string hash (to fetch TronTx via unchained client) or a TronTx object directly. The base chain-adapter interface is strongly typed and doesn't accommodate this flexible signature, so `unknown` is used as an appropriate escape hatch rather than a type safety issue.

Applied to files:

  • packages/chain-adapters/src/tron/TronChainAdapter.ts
📚 Learning: 2025-12-04T22:57:50.850Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 11290
File: packages/chain-adapters/src/utxo/zcash/ZcashChainAdapter.ts:48-51
Timestamp: 2025-12-04T22:57:50.850Z
Learning: In packages/chain-adapters/src/**/*ChainAdapter.ts files, the getName() method uses the pattern `const enumIndex = Object.values(ChainAdapterDisplayName).indexOf(ChainAdapterDisplayName.XXX); return Object.keys(ChainAdapterDisplayName)[enumIndex]` to reverse-lookup the enum key from its value. This is the established pattern used consistently across almost all chain adapters (Bitcoin, Ethereum, Litecoin, Dogecoin, Polygon, Arbitrum, Cosmos, etc.) and should be preserved for consistency when adding new chain adapters.

Applied to files:

  • packages/chain-adapters/src/tron/TronChainAdapter.ts
📚 Learning: 2025-11-24T21:20:57.909Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/**/*.ts : Use TypeScript with explicit types (e.g., SupportedChainIds) for all code in the Swapper system

Applied to files:

  • packages/chain-adapters/src/tron/TronChainAdapter.ts
📚 Learning: 2025-11-24T21:20:57.909Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/utils/constants.ts : Define supported chain IDs for each swapper in utils/constants.ts with both 'sell' and 'buy' properties following the pattern: SupportedChainIds type

Applied to files:

  • packages/chain-adapters/src/tron/TronChainAdapter.ts
📚 Learning: 2025-11-24T21:20:04.979Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:20:04.979Z
Learning: Applies to **/*.{ts,tsx} : Import types from `shapeshiftoss/caip` for chain/account/asset IDs

Applied to files:

  • packages/chain-adapters/src/tron/TronChainAdapter.ts
📚 Learning: 2025-11-24T21:20:57.909Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/swapper.mdc:0-0
Timestamp: 2025-11-24T21:20:57.909Z
Learning: Applies to packages/swapper/src/swappers/*/*.ts : Implement filterBuyAssetsBySellAssetId method to filter assets by supported chain IDs in the buy property

Applied to files:

  • packages/chain-adapters/src/tron/TronChainAdapter.ts
📚 Learning: 2025-10-23T14:27:19.073Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10857
File: src/plugins/walletConnectToDapps/eventsManager/useWalletConnectEventsHandler.ts:101-104
Timestamp: 2025-10-23T14:27:19.073Z
Learning: In WalletConnect wallet_switchEthereumChain and wallet_addEthereumChain requests, the chainId parameter is always present as per the protocol spec. Type guards checking for missing chainId in these handlers (like `if (!evmNetworkIdHex) return`) are solely for TypeScript compiler satisfaction, not real runtime edge cases.

Applied to files:

  • packages/chain-adapters/src/tron/TronChainAdapter.ts
📚 Learning: 2025-11-12T12:49:17.895Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.ts:109-125
Timestamp: 2025-11-12T12:49:17.895Z
Learning: In packages/chain-adapters/src/evm/utils.ts, the getErc20Data function already includes a guard that returns an empty string when contractAddress is undefined (line 8: `if (!contractAddress) return ''`). This built-in handling means callers don't need to conditionally invoke getErc20Data—it safely handles both ERC20 tokens and native assets.

Applied to files:

  • packages/chain-adapters/src/tron/TronChainAdapter.ts
📚 Learning: 2025-09-12T13:43:19.770Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils/EIP155RequestHandlerUtil.ts:94-103
Timestamp: 2025-09-12T13:43:19.770Z
Learning: gomesalexandre has implemented a reliable gasLimit flow in WalletConnect dApps where Tenderly simulation provides gas estimates that get written to the form via setValue in GasSelectionMenu.tsx, making customTransactionData.gasLimit the primary reliable source. The sendTransaction.gasLimit fallback is kept as "paranoia" but may rarely be hit in practice due to this simulation-based architecture.

Applied to files:

  • packages/chain-adapters/src/tron/TronChainAdapter.ts
🧬 Code graph analysis (1)
packages/chain-adapters/src/tron/TronChainAdapter.ts (1)
packages/chain-adapters/src/tron/types.ts (1)
  • TronUnsignedTx (30-50)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Install and Cache
🔇 Additional comments (7)
packages/chain-adapters/src/tron/TronChainAdapter.ts (7)

9-9: LGTM! Throttling setup is sound.

The PQueue initialization with conservative rate limiting (2.5 req/sec) effectively addresses the rate-limiting issue. The private field and hardcoded configuration are appropriate for this initial implementation.

Also applies to: 60-60, 65-69


213-221: LGTM! TRC20 transaction building properly throttled.

The triggerSmartContract call is correctly wrapped with the request queue, maintaining existing error handling and result validation.


236-242: LGTM! TRX transaction creation properly throttled.

The fetch call to /wallet/createtransaction is correctly serialized through the queue, preventing concurrent requests.


391-391: LGTM! Fee estimation parameter fetch properly throttled.

The getChainParameters call is correctly serialized, ensuring reliable fee estimation without triggering rate limits.


425-427: LGTM! TRX transfer estimation properly throttled.

The sendTrx call is correctly wrapped to prevent rate limiting during fee estimation for native TRX transfers.


454-463: LGTM! Account existence check properly throttled.

The fetch call to /wallet/getaccount is correctly serialized, preventing rate limiting during recipient activation checks for fee estimation.


65-69: Verify that throttling doesn't materially degrade UX.

The conservative rate limiting (1 request per 400ms) means operations like buildSendApiTransaction could take 1.6-2 seconds when multiple queued calls execute sequentially. Please verify through testing that this doesn't create a noticeable delay in transaction flows.

Additionally, the PR objectives mention making throttle limits configurable—consider exposing these as constructor parameters in a follow-up if testing reveals the need for adjustment.

Based on PR objectives mentioning configurable limits.

Copy link
Contributor

@gomesalexandre gomesalexandre left a comment

Choose a reason for hiding this comment

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

Still seeing two 429s here though super intermittent and invisible as a user since it work again right after
https://jam.dev/c/53f97093-5d1d-473a-bb40-c8cc9990b659

@gomesalexandre gomesalexandre merged commit df64246 into develop Dec 29, 2025
4 checks passed
@gomesalexandre gomesalexandre deleted the tron-throttle branch December 29, 2025 16:06
@coderabbitai coderabbitai bot mentioned this pull request Jan 27, 2026
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add throttle to TronChainAdapter

2 participants