fix: better tron estimates - #11274
Conversation
- Add executeTronTransaction method to ThorchainSwapper for transaction execution - Implement proper TRON fee estimation using real-time network prices: * TRC20: triggerConstantContract for energy calculation (~27 TRX) * TRX: actual bandwidth calculation with memo overhead (~0.3-0.5 TRX) - Add VITE_TRON_NODE_URL to SwapperConfig - Set networkFeeCryptoBaseUnit to undefined for rate quotes (calculated at execution time) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Reuse single TronWeb instance for transaction building - Remove manual fee_limit restoration (addUpdateData preserves it) - Clean up transaction flow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…t address extraction - Increase feeLimit to 150 TRX for TRC20 transfers with memo (covers energy + bandwidth) - Use contractAddressOrUndefined utility consistently across tron utils - Research shows feeLimit only covers energy, bandwidth is burned separately Note: TRC20 transfers require ~64k-130k energy + ~345 bandwidth With memo, bandwidth increases. Account needs TRX to burn for bandwidth if free daily bandwidth (600 units) is exhausted. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Critical fix for TRC20 bandwidth error: - Add txLocal: true to addUpdateData() call - This preserves fee_limit field (150 TRX for TRC20 with memo) - Without txLocal, addUpdateData calls wallet/getsignweight API which returns transaction WITHOUT fee_limit, causing "Account resource insufficient" error Root cause: TronWeb's addUpdateData() loses fee_limit when using remote API. Solution: txLocal: true forces local transaction recreation that preserves all fields. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…sues Testing theory: txLocal: true might cause transaction validation issues. Successful Thorchain TRC20 txs on-chain have both fee_limit and memo preserved, suggesting addUpdateData() works correctly without txLocal option. On-chain evidence: - TX 78055EA7: fee_limit 100 TRX, has memo, SUCCESS - TX BD77F95E: fee_limit 15.6 TRX, has memo, SUCCESS If this doesn't work, need to investigate wallet balance or other issues. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
After analyzing SwapKit's TRON implementation and successful Thorchain TRC20 txs: - Standard feeLimit is 100 TRX (not 150) - addUpdateData() without txLocal is correct - Transaction structure matches working implementations Root cause of BANDWIDTH_ERROR confirmed: - Account has 0.25 TRX liquid (frozen TRX cannot pay fees) - Transaction needs ~7-8 TRX liquid for energy + memo fee - Error is misleading - it's insufficient liquid TRX, not bandwidth Code is correct. Issue is account balance. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Created TRON_FEE_ESTIMATION_ISSUES.md documenting critical problems: - getFeeData() returns fixed 0.268 TRX for ALL transactions - TRC20 transfers actually cost 6-15 TRX (24-56x underestimate) - Causes misleading UI fees and on-chain transaction failures - Users lose TRX in partial execution before OUT_OF_ENERGY errors Added TODO comments in TronChainAdapter.getFeeData() with: - Detect TRC20 vs TRX using contractAddress - Use existing estimateTRC20TransferFee() method - Account for memo overhead (1 TRX memo fee + bandwidth) - Build actual transaction for accurate size estimation Evidence includes failed txs and cost analysis. Priority: HIGH - users losing funds on failed transactions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Created THORCHAIN_TRON_INTEGRATION.md covering: - Architecture (UTXO-style pattern, not EVM) - Implementation details for all components - Memo handling via addUpdateData() - Cost breakdown (energy, bandwidth, memo fee) - Successful on-chain transaction examples - Common issues and solutions - Testing checklist - Comparison with SwapKit implementation Documents that implementation is correct and matches working integrations. Main issue is inherited getFeeData() returning wrong fees for TRC20. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Fixed getTronTransactionFees to estimate from user's perspective: - Use args.from instead of vault for triggerConstantContract issuerAddress - Use args.from instead of vault for sendTrx from parameter - Remove unnecessary Number() conversion (TronWeb accepts strings) Why this matters: - triggerConstantContract simulates execution from caller's perspective - Using vault address estimated "vault→vault" cost, not "user→vault" - Energy costs may vary based on sender's account state Credit: coderabbitai review feedback 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
CodeRabbit was incorrect about sendTrx accepting strings. TronWeb's TypeScript definition requires number for amount parameter: sendTrx(to: string, amount?: number, from?: string) While implementation accepts strings internally, the type definition enforces number, causing TS2345 error. Kept the important fix: using args.from instead of vault for sender. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
More consistent with codebase patterns and safer for edge cases. bnOrZero handles invalid inputs gracefully vs raw Number() cast. Note: TronWeb's TypeScript definition requires number type for sendTrx amount, so string is not an option (contrary to CodeRabbit's suggestion). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
CRITICAL: Fixes 24-50x fee underestimation causing OUT_OF_ENERGY failures Previously returned fixed 0.268 TRX for all transactions. Now returns accurate estimates validated against real transactions: - TRC20 transfers: 6.7-13.3 TRX (without memo) - TRC20 with memo: 7.8-14.4 TRX - TRX transfers: 0.198 TRX (without memo) - TRX with memo: 1.231 TRX Validation Results (Real Thorchain USDT swaps + User transaction): - User tx: 6.77 TRX actual, 9.92 TRX estimated (1.46x = conservative ✅) - Thor tx 1: 7.84 TRX actual, 10.92 TRX estimated (1.39x = conservative ✅) - Thor tx 2: 7.82 TRX actual, 10.92 TRX estimated (1.40x = conservative ✅) - Old estimate: 0.268 TRX (0.034x actual = 29x underestimate ❌) - Improvement: 41x more accurate Implementation: - Detects TRC20 vs TRX via contractAddress in chainSpecific - Calls estimateTRC20TransferFee() with actual recipient address - Applies 1.5x safety margin for dynamic energy spikes (max 3.4x) - Builds real transactions to measure bandwidth accurately - Adds 1 TRX memo fee when present (network parameter #68) - Thor/TRON rates now show fees when wallet connected - Send modal now passes contractAddress for TRC20 detection Files Modified: - TronChainAdapter.ts: Rewritten getFeeData() (85 lines) - getL1RateOrQuote.ts: Thor rates with fee calculation (68 lines) - api.ts: Realistic fallback (31→13 TRX) - tron/types.ts: Added GetFeeDataInput type - types.ts: Added TRON to ChainSpecificGetFeeDataInput - Send/utils.ts: Pass contractAddress and memo to getFeeData - NearIntentsSwapper: Added chainSpecific for TRON calls Technical Details: - Uses triggerConstantContract (estimateEnergy not available on TronGrid) - SSTORE cost varies 2x based on recipient balance (20k vs 5k energy) - Dynamic energy can spike up to 3.4x during congestion - Memo fee confirmed via getChainParameters(): 1,000,000 SUN - Energy price: 100 SUN/unit (mainnet), 210 SUN/unit (Shasta) - Validated against NETTS article: 65k/131k energy for USDT Fixes #11270 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
The 19.776 TRX estimate was caused by using fallback (130k energy) because triggerConstantContract didn't have a valid sender address. Changes: - Added 'from' (sender) to TRON GetFeeDataInput type - Send modal now extracts and passes sender address from accountId - estimateTRC20TransferFee uses actual sender for accurate estimation This fixes the recipient balance detection: - Recipient HAS USDT: ~64k energy → 9.6 TRX estimate - Recipient NO USDT: ~130k energy → 19.5 TRX estimate Previously always used fallback 130k energy (19.5 TRX) because sender address was missing. Now estimates accurately based on actual sender calling triggerConstantContract. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Added user-facing documentation explaining TRON fee structure: - Why USDT transfers cost $1-3 (normal and expected) - How energy and bandwidth fees work - Real transaction examples with breakdowns - Dynamic energy model explanation - Fee reduction strategies - Links to TRON docs, explorers, and resources This helps users understand why fees changed from $0.05 to $2 (the old $0.05 was a bug, $1-2 is the real cost). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
📝 WalkthroughWalkthroughRefactors TRON fee estimation to use live chain parameters and transaction-specific inputs. Adds a new GetFeeDataInput type and threads from/contractAddress/memo through callers to compute energy, bandwidth, and memo fees for TRC20 and TRX transfers. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as UI (Send / Swapper)
participant Adapter as TronChainAdapter
participant Web as TronWeb
participant Unchained as Unchained Client
participant Chain as TRON Chain
UI->>Adapter: getFeeData({to, value, chainSpecific:{from?, contractAddress?, memo?}})
Adapter->>Web: instantiate TronWeb & getChainParameters()
Web->>Chain: getChainParameters()
Chain-->>Web: bandwidthPrice, energyPrice
Web-->>Adapter: prices
alt contractAddress present (TRC20)
Adapter->>Unchained: estimateTRC20TransferFee(contractAddress, from?, to?)
Unchained->>Chain: simulate/estimate energyUsed
Chain-->>Unchained: energyUsed
Unchained-->>Adapter: energyUsed
Adapter->>Adapter: energyFee = energyUsed × energyPrice × 1.5
Adapter->>Adapter: bandwidthFee = fixedBytes (≈276) × bandwidthPrice
else TRX transfer (no contractAddress)
Adapter->>Web: build transaction (include memo if present) to estimate size
Web->>Chain: estimate transaction size / bandwidth
Chain-->>Web: totalBytes
Web-->>Adapter: bandwidthFee = totalBytes × bandwidthPrice
Adapter->>Adapter: energyFee = 0
end
alt memo present
Adapter->>Adapter: memoFee = 1 TRX (added to total)
end
Adapter->>Adapter: totalFee = energyFee + bandwidthFee + memoFee
Adapter-->>UI: FeeDataEstimate {fast/average/slow strings, observed bandwidth}
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro Disabled knowledge base sources:
📒 Files selected for processing (4)
🧰 Additional context used📓 Path-based instructions (6)**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/swapper{s,}/**/*.{ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
Files:
**/*.{js,jsx,ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/naming-conventions.mdc)
Files:
packages/swapper/**/*.ts📄 CodeRabbit inference engine (.cursor/rules/swapper.mdc)
Files:
packages/swapper/src/swappers/**/*.ts📄 CodeRabbit inference engine (.cursor/rules/swapper.mdc)
Files:
🧠 Learnings (26)📓 Common learnings📚 Learning: 2025-11-03T22:31:30.786ZApplied to files:
📚 Learning: 2025-11-12T12:49:17.895ZApplied to files:
📚 Learning: 2025-11-24T21:20:57.909ZApplied to files:
📚 Learning: 2025-11-24T21:20:17.804ZApplied to files:
📚 Learning: 2025-11-24T21:20:57.909ZApplied to files:
📚 Learning: 2025-11-24T21:20:57.909ZApplied to files:
📚 Learning: 2025-11-24T21:20:57.909ZApplied to files:
📚 Learning: 2025-12-04T11:05:01.112ZApplied to files:
📚 Learning: 2025-11-24T21:20:57.909ZApplied to files:
📚 Learning: 2025-12-01T22:01:37.982ZApplied to files:
📚 Learning: 2025-11-24T21:20:04.979ZApplied to files:
📚 Learning: 2025-08-05T23:36:13.214ZApplied to files:
📚 Learning: 2025-10-23T14:27:19.073ZApplied to files:
📚 Learning: 2025-09-12T10:21:26.693ZApplied to files:
📚 Learning: 2025-09-12T12:04:59.556ZApplied to files:
📚 Learning: 2025-08-05T16:39:58.598ZApplied to files:
📚 Learning: 2025-09-12T12:04:59.556ZApplied to files:
📚 Learning: 2025-07-24T11:07:20.536ZApplied to files:
📚 Learning: 2025-11-18T09:52:51.368ZApplied to files:
📚 Learning: 2025-11-24T21:20:17.804ZApplied to files:
📚 Learning: 2025-11-24T21:20:57.909ZApplied to files:
📚 Learning: 2025-12-03T23:21:16.985ZApplied to files:
📚 Learning: 2025-11-24T21:20:57.909ZApplied to files:
📚 Learning: 2025-11-12T12:18:00.863ZApplied to files:
📚 Learning: 2025-09-12T12:08:15.823ZApplied to files:
🧬 Code graph analysis (3)packages/swapper/src/swappers/SunioSwapper/utils/getQuoteOrRate.ts (2)
packages/chain-adapters/src/tron/TronChainAdapter.ts (2)
packages/swapper/src/thorchain-utils/getL1RateOrQuote.ts (2)
⏰ 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)
🔇 Additional comments (3)
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
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. Comment |
- Remove documentation files (not needed in codebase) - Remove console.warn from getL1RateOrQuote.ts - Keep only essential code changes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Remove debug console.log with fee estimation info - Remove console.debug in error catch block 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Resolve merge conflicts after PR #11266 was squash merged. The original PR had basic/placeholder Tron fee estimation, while this branch contains the improved fee estimation logic. Kept the improvements from HEAD. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.ts (1)
220-229: Passfromaddress in Tron chainSpecific for consistent and accurate TRC20 fee estimation.The Tron case passes an empty
chainSpecificobject, while the EVM, Solana, and Sui cases all passfrominchainSpecific. The Tron adapter uses thefromaddress to improve TRC20 energy estimation viaestimateTRC20TransferFee—whenfromis not provided, it falls back to using the recipient address. Passfrom: fromin thechainSpecificobject to maintain consistency and enable accurate fee calculation.
🧹 Nitpick comments (5)
packages/swapper/src/thorchain-utils/getL1RateOrQuote.ts (2)
484-489: Consider extracting magic numbers to constants.The fee calculation uses several hardcoded values that would benefit from being defined as named constants for maintainability and clarity.
Extract these values to constants at the file or module level:
const TRON_ENERGY_SAFETY_MARGIN = 1.5 const TRON_TRC20_BANDWIDTH_BYTES = 276 const TRON_BASE_BANDWIDTH_BYTES = 198 const TRON_FALLBACK_FEE_SUN = 13_000_000 // 13 TRX worst caseThen use them in the calculation:
- const energyFee = energyUsed * energyPrice * 1.5 // 1.5x safety margin - const bandwidthFee = 276 * bandwidthPrice // TRC20 bandwidth + const energyFee = energyUsed * energyPrice * TRON_ENERGY_SAFETY_MARGIN + const bandwidthFee = TRON_TRC20_BANDWIDTH_BYTES * bandwidthPrice totalFee = Math.ceil(energyFee + bandwidthFee) } catch { // Fallback: Conservative estimate - totalFee = 13_000_000 // 13 TRX worst case + totalFee = TRON_FALLBACK_FEE_SUN }This improves code clarity and makes it easier to tune these values based on real-world data.
462-462: Optional: Consider reusing TronWeb instance across routes.A new
TronWebinstance is created for each route iteration, which could be optimized by creating a single instance before the map.+ const tronWeb = new TronWeb({ fullHost: deps.config.VITE_TRON_NODE_URL }) + const params = await tronWeb.trx.getChainParameters() + const bandwidthPrice = params.find(p => p.key === 'getTransactionFee')?.value ?? 1000 + const energyPrice = params.find(p => p.key === 'getEnergyFee')?.value ?? 100 + const maybeRoutes = await Promise.allSettled( perRouteValues.map(async (route): Promise<T> => { const memo = getMemo(route) let networkFeeCryptoBaseUnit: string | undefined = undefined if (input.quoteOrRate === 'rate' && input.receiveAddress) { try { - const tronWeb = new TronWeb({ fullHost: deps.config.VITE_TRON_NODE_URL }) - const params = await tronWeb.trx.getChainParameters() - const bandwidthPrice = params.find(p => p.key === 'getTransactionFee')?.value ?? 1000 - const energyPrice = params.find(p => p.key === 'getEnergyFee')?.value ?? 100This reduces redundant initialization and network calls when processing multiple routes.
packages/chain-adapters/src/tron/TronChainAdapter.ts (3)
364-377: getFeeData input handling and chain parameter lookup look good; consider reusing TronWeb instanceThe refactor to use
GetFeeDataInput<KnownChainIds.TronMainnet>and destructurechainSpecificfor{ from, contractAddress, memo }is clear and aligns with the new type surface. ThegetChainParameters()call is also a reasonable way to derivebandwidthPriceandenergyPrice.One optional improvement:
TronWebis instantiated here and also inbuildSendApiTransaction. You could move this to a single adapter-level instance (e.g., a private getter or field initialized in the constructor) so both methods share it and you avoid repeating the setup and potential configuration drift. CachinggetChainParameters()for a short period (e.g., per process or per minute) could also be a future optimization if this path becomes hot.
378-399: ClarifyestimateTRC20TransferFeeunits and consider deriving memo fee from chain parametersThe TRC20 path and memo handling look directionally correct and should eliminate the previous underestimation, but there are a couple of assumptions worth double‑checking:
estimateTRC20TransferFeereturn unitsYou treat
energyEstimateas a fee in SUN (energyFee = Number(energyEstimate)), while the fallback path computes130000 * energyPrice(energy units × price). This is fine ifestimateTRC20TransferFeealready returns a fee (not raw energy units), but it would under‑estimate if it instead returns just energy usage. Please confirm the exact return units ofestimateTRC20TransferFeeand, if it returns energy units, multiply byenergyPricebefore applying the 1.5x margin to keep units consistent with the fallback and withbandwidthFee.Memo fee source
memoFeeis hardcoded to1_000_000SUN with a comment referencing network parameter #68. Since you already haveparamsfromgetChainParameters(), you could optionally readmemoFeedirectly from there (with a sane default) to automatically track future parameter changes:- // Add 1 TRX memo fee when memo present (network parameter #68) - const memoFee = memo ? 1_000_000 : 0 + const memoParam = params.find(p => p.key === 'memoFee')?.value ?? 1_000_000 + const memoFee = memo ? memoParam : 0This keeps the adapter aligned with live chain config without needing manual updates.
Single fee tier across fast/average/slow
Returning the same
txFeeforfast,average, andslowis acceptable on Tron since there’s no gas‑price market, but just confirm this matches the UI expectations for fee tiering.Also applies to: 427-434, 437-447
401-425: Usefrom ?? toas the sender when building TRX estimation transactionIn the TRX branch,
sendTrxis called with the recipient address as bothtoandfrom:const baseTx = await tronWeb.transactionBuilder.sendTrx( to, Number(value), to, // Use recipient as sender for estimation )For pure size estimation this is probably fine, but when
fromis available inchainSpecificyou can make the estimation closer to the real transaction and avoid surprises by using it:- const baseTx = await tronWeb.transactionBuilder.sendTrx( - to, - Number(value), - to, // Use recipient as sender for estimation - ) + const estimationFrom = from ?? to + const baseTx = await tronWeb.transactionBuilder.sendTrx( + to, + Number(value), + estimationFrom, + )This keeps the estimation structurally aligned with the actual transaction while preserving a safe fallback when
fromis not provided.
📜 Review details
Configuration used: CodeRabbit 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.
📒 Files selected for processing (9)
packages/chain-adapters/src/tron/TronChainAdapter.ts(1 hunks)packages/chain-adapters/src/tron/types.ts(1 hunks)packages/chain-adapters/src/types.ts(1 hunks)packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.ts(1 hunks)packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts(1 hunks)packages/swapper/src/thorchain-utils/getL1RateOrQuote.ts(4 hunks)packages/unchained-client/src/tron/api.ts(1 hunks)src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx(2 hunks)src/components/Modals/Send/utils.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{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 runyarn lint --fixandyarn type-checkafter making changes
Avoidletvariable assignments - preferconstwith inline IIFE switch statements or extract to functions for conditional logic
Files:
packages/chain-adapters/src/types.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.tspackages/chain-adapters/src/tron/types.tspackages/chain-adapters/src/tron/TronChainAdapter.tssrc/components/Modals/Send/utils.tssrc/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsxpackages/unchained-client/src/tron/api.tspackages/swapper/src/thorchain-utils/getL1RateOrQuote.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.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 inuseMemoand callbacks inuseCallbackwhere 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 usinguseColorModeValuehook
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()fromreact-polyglot
UseuseFeatureFlag('FlagName')hook to access feature flag values in components
Prefertypeoverinterfacefor type definitions
Use strict typing - avoidany
UseNominaltypes for domain identifiers (e.g.,WalletId,AccountId)
Import types from@shapeshiftoss/caipfor chain/account/asset IDs
UseuseAppSelectorfor Redux state
UseuseAppDispatchfor Redux actions
Memoize expensive computations withuseMemo
Memoize callbacks withuseCallback
**/*.{ts,tsx}: UseResult<T, E>pattern for error handling in swappers and APIs; ALWAYS useOk()andErr()from@sniptt/monads; AVOID throwing within swapper API implementations
ALWAYS use custom error classes from@shapeshiftoss/errorswith meaningful error codes for internationalization and relevant details in error objects
ALWAYS wrap async op...
Files:
packages/chain-adapters/src/types.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.tspackages/chain-adapters/src/tron/types.tspackages/chain-adapters/src/tron/TronChainAdapter.tssrc/components/Modals/Send/utils.tssrc/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsxpackages/unchained-client/src/tron/api.tspackages/swapper/src/thorchain-utils/getL1RateOrQuote.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.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
Usehandleprefix for event handlers with descriptive names in camelCase
Use descriptive boolean variable names withis,has,can,shouldprefixes
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 likedata,item,obj, and single-letter variable names except in loops
Avoid abbreviations in names unless they are widely understood
Avoid generic function names likefn,func, orcallback
Files:
packages/chain-adapters/src/types.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.tspackages/chain-adapters/src/tron/types.tspackages/chain-adapters/src/tron/TronChainAdapter.tssrc/components/Modals/Send/utils.tssrc/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsxpackages/unchained-client/src/tron/api.tspackages/swapper/src/thorchain-utils/getL1RateOrQuote.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
**/swapper{s,}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
ALWAYS use
makeSwapErrorRightfor swapper errors withTradeQuoteErrorenum for error codes and provide detailed error information
Files:
packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.tspackages/swapper/src/thorchain-utils/getL1RateOrQuote.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
packages/swapper/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/swapper.mdc)
packages/swapper/**/*.ts: Use TypeScript with explicit types (e.g., SupportedChainIds) for all code in the Swapper system
Use camelCase for variable and function names in the Swapper system
Use PascalCase for types, interfaces, and enums in the Swapper system
Use kebab-case for filenames in the Swapper system
Files:
packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.tspackages/swapper/src/thorchain-utils/getL1RateOrQuote.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
packages/swapper/src/swappers/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/swapper.mdc)
packages/swapper/src/swappers/**/*.ts: Adhere to the Swapper directory structure: each swapper resides in packages/swapper/src/swappers// with required files (SwapperName.ts, endpoints.ts, types.ts, utils/constants.ts, utils/helpers.ts)
Validate inputs and log errors for debugging in Swapper system implementations
Swapper files must be located in packages/swapper/src/swappers/ directory structure and not placed outside this location
Avoid side effects in swap logic; ensure swap methods are deterministic and stateless
Files:
packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
**/*.{tsx,jsx}: ALWAYS wrap React components in error boundaries and provide user-friendly fallback components with error logging
ALWAYS useuseErrorToasthook for displaying errors with translated error messages and handle different error types appropriatelyUse PascalCase for React component names and match the component name to the file name
Files:
src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)
**/*.{jsx,tsx}: ALWAYS useuseMemofor expensive computations, object/array creations, and filtered data
ALWAYS useuseMemofor derived values and computed properties
ALWAYS useuseMemofor conditional values and simple transformations
ALWAYS useuseCallbackfor event handlers and functions passed as props
ALWAYS useuseCallbackfor any function that could be passed as a prop or dependency
ALWAYS include all dependencies inuseEffect,useMemo,useCallbackdependency arrays
NEVER use// eslint-disable-next-line react-hooks/exhaustive-depsunless absolutely necessary, and ALWAYS explain why dependencies are excluded if using eslint disable
ALWAYS use named exports for components; NEVER use default exports for components
KEEP component files under 200 lines when possible; BREAK DOWN large components into smaller, reusable pieces
EXTRACT complex logic into custom hooks
ALWAYS wrap components in error boundaries for production
ALWAYS handle async errors properly in async operations
ALWAYS provide user-friendly error messages in error handling
ALWAYS use virtualization for lists with 100+ items
ALWAYS implement proper key props for list items
ALWAYS lazy load heavy components using React.lazy for code splitting
ALWAYS use Suspense wrapper for lazy loaded components
USE local state for component-level state; LIFT state up when needed across multiple components; USE Context for avoiding prop drilling; USE Redux only for global state shared across multiple places
Wrap components receiving props withmemofor performance optimization
Files:
src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)
Ensure TypeScript types are explicit and proper; avoid use of
anytype
Files:
src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx
🧠 Learnings (28)
📓 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: 10810
File: src/plugins/walletConnectToDapps/utils/tenderly/index.ts:212-0
Timestamp: 2025-10-15T15:57:39.956Z
Learning: gomesalexandre uses discriminated union patterns (e.g., `isEIP1559 ? { max_fee_per_gas, max_priority_fee_per_gas } : { gas_price }`) in WalletConnect flows without additional validation guards, trusting that the runtime data structure ensures mutual exclusivity between EIP-1559 and legacy gas pricing fields.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11170
File: patches/@shapeshiftoss+bitcoinjs-lib+7.0.0-shapeshift.0.patch:9-19
Timestamp: 2025-11-25T21:43:10.838Z
Learning: In shapeshift/web, gomesalexandre will not expand PR scope to fix latent bugs in unused API surface (like bitcoinjs-lib patch validation methods) when comprehensive testing proves the actual used code paths work correctly, preferring to avoid costly hdwallet/web verdaccio publish cycles and full regression testing for conceptual issues with zero runtime impact.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11261
File: src/lib/utils/tron/getAllowance.ts:14-59
Timestamp: 2025-12-03T23:21:16.985Z
Learning: In src/lib/utils/tron/getAllowance.ts, gomesalexandre is not concerned about adding comprehensive error handling (try-catch blocks, custom error classes) for the getTrc20Allowance utility function, because it is used close to the view layer. He prefers simpler error handling for view-layer utilities, letting errors propagate naturally rather than adding defensive guards.
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.
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 sophisticated gasLimit management system in WalletConnect dApps using Tenderly simulation. The GasSelectionMenu component automatically adjusts gasLimit via setValue when simulation shows higher gas usage than currently set, handling edge cases like dApps that enforce low gas limits (e.g., 21000) when actual usage is higher (e.g., 23322). This makes customTransactionData.gasLimit highly reliable as the primary source.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.ts:109-145
Timestamp: 2025-11-12T12:18:00.863Z
Learning: NEAR Intents swapper: The NEAR 1Click API does not provide gas limit estimation logic like other swappers (e.g., magic gasLimit fields). For ERC20 token swaps in getTradeQuote, accurate fee estimation requires token approval and sufficient balance; without these prerequisites, fees may display as 0 or use inaccurate native transfer estimates. This is a known limitation of the NEAR Intents integration.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/config.ts:127-128
Timestamp: 2025-08-07T11:20:44.614Z
Learning: gomesalexandre prefers required environment variables without default values in the config file (src/config.ts). They want explicit configuration and fail-fast behavior when environment variables are missing, rather than having fallback defaults.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/ContractInteractionBreakdown.tsx:0-0
Timestamp: 2025-09-13T16:45:18.813Z
Learning: gomesalexandre prefers aggressively deleting unused/obsolete code files ("ramboing") rather than fixing technical issues in code that won't be used, demonstrating his preference for keeping codebases clean and PR scope focused.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/types.ts:7-7
Timestamp: 2025-09-10T15:34:29.604Z
Learning: gomesalexandre is comfortable relying on transitive dependencies (like abitype through ethers/viem) rather than explicitly declaring them in package.json, preferring to avoid package.json bloat when the transitive dependency approach works reliably in practice.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10503
File: .env:56-56
Timestamp: 2025-09-16T13:17:02.938Z
Learning: gomesalexandre prefers to enable feature flags globally in the base .env file when the intent is to activate features everywhere, even when there are known issues like crashes, demonstrating his preference for intentional global feature rollouts over cautious per-environment enablement.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10249
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:447-503
Timestamp: 2025-08-13T17:07:10.763Z
Learning: gomesalexandre prefers relying on TypeScript's type system for validation rather than adding defensive runtime null checks when types are properly defined. They favor a TypeScript-first approach over defensive programming with runtime validations.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/hooks/useActionCenterSubscribers/useThorchainLpDepositActionSubscriber.tsx:61-66
Timestamp: 2025-08-14T17:51:47.556Z
Learning: gomesalexandre is not concerned about structured logging and prefers to keep console.error usage as-is rather than implementing structured logging patterns, even when project guidelines suggest otherwise.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10413
File: src/components/Modals/FiatRamps/fiatRampProviders/onramper/utils.ts:29-55
Timestamp: 2025-09-02T14:26:19.028Z
Learning: gomesalexandre prefers to keep preparatory/reference code simple until it's actively consumed, rather than implementing comprehensive error handling, validation, and robustness improvements upfront. They prefer to add these improvements when the code is actually being used in production.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10276
File: src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx:396-402
Timestamp: 2025-08-14T17:55:57.490Z
Learning: gomesalexandre is comfortable with functions/variables that return undefined or true (tri-state) when only the truthy case matters, preferring to rely on JavaScript's truthy/falsy behavior rather than explicitly returning boolean values.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10783
File: src/context/ModalStackProvider/useModalRegistration.ts:30-41
Timestamp: 2025-10-16T11:14:40.657Z
Learning: gomesalexandre prefers to add lint rules (like typescript-eslint/strict-boolean-expressions for truthiness checks on numbers) to catch common issues project-wide rather than relying on code review to catch them.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10206
File: src/lib/moralis.ts:47-85
Timestamp: 2025-08-07T11:22:16.983Z
Learning: gomesalexandre prefers console.error over structured logging for Moralis API integration debugging, as they find it more conventional and prefer to examine XHR requests directly rather than rely on structured logs for troubleshooting.
📚 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/types.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.tspackages/chain-adapters/src/tron/types.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.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/types.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.tssrc/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsxpackages/swapper/src/thorchain-utils/getL1RateOrQuote.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.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/types.tspackages/chain-adapters/src/tron/types.tssrc/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx
📚 Learning: 2025-11-12T12:18:00.863Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.ts:109-145
Timestamp: 2025-11-12T12:18:00.863Z
Learning: NEAR Intents swapper: The NEAR 1Click API does not provide gas limit estimation logic like other swappers (e.g., magic gasLimit fields). For ERC20 token swaps in getTradeQuote, accurate fee estimation requires token approval and sufficient balance; without these prerequisites, fees may display as 0 or use inaccurate native transfer estimates. This is a known limitation of the NEAR Intents integration.
Applied to files:
packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
📚 Learning: 2025-11-03T22:31:30.786Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10985
File: packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeQuote/getPortalsTradeQuote.ts:0-0
Timestamp: 2025-11-03T22:31:30.786Z
Learning: In packages/swapper/src/swappers/PortalsSwapper, the rate and quote files intentionally use different approaches for calculating buyAmountBeforeSlippageCryptoBaseUnit: getPortalsTradeRate.tsx uses minOutputAmount / (1 - buffer) for conservative estimates, while getPortalsTradeQuote.ts uses outputAmount / (1 - buffer) for final quote display. This difference is validated by on-chain simulation testing and is intentional.
Applied to files:
packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.tspackages/swapper/src/thorchain-utils/getL1RateOrQuote.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
📚 Learning: 2025-11-24T21:20:17.804Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-11-24T21:20:17.804Z
Learning: Applies to **/swapper{s,}/**/*.{ts,tsx} : ALWAYS use `makeSwapErrorRight` for swapper errors with `TradeQuoteError` enum for error codes and provide detailed error information
Applied to files:
packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.tspackages/swapper/src/thorchain-utils/getL1RateOrQuote.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.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/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.tssrc/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsxpackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.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/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.tssrc/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx
📚 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 : Avoid side effects in swap logic; ensure swap methods are deterministic and stateless
Applied to files:
packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.tspackages/swapper/src/thorchain-utils/getL1RateOrQuote.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.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 filterAssetIdsBySellable method to filter assets by supported chain IDs in the sell property
Applied to files:
packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.tssrc/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsxpackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
📚 Learning: 2025-12-04T11:05:01.112Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11281
File: packages/swapper/src/swappers/PortalsSwapper/utils/fetchSquidStatus.ts:98-106
Timestamp: 2025-12-04T11:05:01.112Z
Learning: In packages/swapper/src/swappers/PortalsSwapper/utils/fetchSquidStatus.ts, getSquidTrackingLink should return blockchain explorer links (using Asset.explorerTxLink) rather than API endpoints. For non-GMP Squid swaps: return source chain explorer link with sourceTxHash when pending/failed, and destination chain explorer link with destinationTxHash when confirmed.
Applied to files:
packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.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.tssrc/components/Modals/Send/utils.tssrc/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx
📚 Learning: 2025-10-21T17:11:18.087Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10871
File: src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx:426-428
Timestamp: 2025-10-21T17:11:18.087Z
Learning: In src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx, within the handleInputChange function, use .toFixed() without arguments (not .toString()) when converting BigNumber amounts for input field synchronization. This avoids exponential notation in the input while preserving precision for presentational components like <Amount.Crypto /> and <Amount.Fiat /> to format appropriately.
Applied to files:
src/components/Modals/Send/utils.tssrc/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx
📚 Learning: 2025-08-05T22:41:35.473Z
Learnt from: premiumjibles
Repo: shapeshift/web PR: 10187
File: src/pages/Assets/Asset.tsx:1-1
Timestamp: 2025-08-05T22:41:35.473Z
Learning: In the shapeshift/web codebase, component imports use direct file paths like '@/components/ComponentName/ComponentName' rather than barrel exports. The AssetAccountDetails component should be imported as '@/components/AssetAccountDetails/AssetAccountDetails', not from a directory index.
Applied to files:
src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx
📚 Learning: 2025-08-05T23:36:13.214Z
Learnt from: premiumjibles
Repo: shapeshift/web PR: 10187
File: src/state/slices/preferencesSlice/selectors.ts:21-25
Timestamp: 2025-08-05T23:36:13.214Z
Learning: The AssetId type from 'shapeshiftoss/caip' package is a string type alias, so it can be used directly as a return type for cache key resolvers in re-reselect selectors without needing explicit string conversion.
Applied to files:
src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx
📚 Learning: 2025-09-12T13:44:17.019Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/hooks/useSimulateEvmTransaction.ts:0-0
Timestamp: 2025-09-12T13:44:17.019Z
Learning: gomesalexandre prefers letting chain adapter errors throw naturally in useSimulateEvmTransaction rather than adding explicit error handling for missing adapters, consistent with his fail-fast approach and dismissal of defensive validation as "stale" in WalletConnect transaction simulation flows.
Applied to files:
src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx
📚 Learning: 2025-12-03T23:21:16.985Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11261
File: src/lib/utils/tron/getAllowance.ts:14-59
Timestamp: 2025-12-03T23:21:16.985Z
Learning: In src/lib/utils/tron/getAllowance.ts, gomesalexandre is not concerned about adding comprehensive error handling (try-catch blocks, custom error classes) for the getTrc20Allowance utility function, because it is used close to the view layer. He prefers simpler error handling for view-layer utilities, letting errors propagate naturally rather than adding defensive guards.
Applied to files:
packages/unchained-client/src/tron/api.tspackages/swapper/src/thorchain-utils/getL1RateOrQuote.ts
📚 Learning: 2025-09-12T12:04:59.556Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/content/SendTransactionContent.tsx:0-0
Timestamp: 2025-09-12T12:04:59.556Z
Learning: The ShapeShift codebase's fromBaseUnit function correctly handles hex strings (like WalletConnect transaction.value) without manual conversion because bnOrZero -> bn -> new BigNumber() automatically detects and parses hex strings starting with "0x". gomesalexandre confirmed this with concrete evidence showing hex value 0x176d1c49189db correctly converts to 0.000412118294825435 ETH.
Applied to files:
packages/swapper/src/thorchain-utils/getL1RateOrQuote.ts
📚 Learning: 2025-08-05T16:39:58.598Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10191
File: src/pages/Explore/Explore.tsx:56-56
Timestamp: 2025-08-05T16:39:58.598Z
Learning: In the ShapeShift web codebase, the established pattern for handling floating point numbers is to use BigNumber operations (bnOrZero, bn) for calculations and convert to strings using .toString() before passing to UI components like Amount.Fiat, Amount.Crypto, and Amount.Percent. This prevents JavaScript floating point precision issues and maintains consistency across the application.
Applied to files:
packages/swapper/src/thorchain-utils/getL1RateOrQuote.ts
📚 Learning: 2025-09-12T12:04:59.556Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/content/SendTransactionContent.tsx:0-0
Timestamp: 2025-09-12T12:04:59.556Z
Learning: gomesalexandre confirmed that fromBaseUnit in the ShapeShift codebase correctly handles hex strings (like transaction.value from WalletConnect) without requiring manual hex-to-decimal conversion, as bnOrZero handles this automatically via BigNumber.js.
Applied to files:
packages/swapper/src/thorchain-utils/getL1RateOrQuote.ts
📚 Learning: 2025-07-24T11:07:20.536Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10073
File: src/features/defi/providers/fox-farming/components/FoxFarmingManager/Claim/Claim.tsx:77-84
Timestamp: 2025-07-24T11:07:20.536Z
Learning: In fox farming components, the `opportunity?.rewardsCryptoBaseUnit?.amounts` property has a well-defined type signature that is always an array (never undefined), but can be empty: `readonly [] | readonly [string, string, string] | readonly [string, string] | readonly [string]`. Using optional chaining on the `amounts` property itself is unnecessary since it's always defined, though accessing `amounts[0]` on an empty array returns undefined which bnOrZero() handles safely.
Applied to files:
packages/swapper/src/thorchain-utils/getL1RateOrQuote.ts
📚 Learning: 2025-11-18T09:52:51.368Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10334
File: src/lib/user/api.ts:46-105
Timestamp: 2025-11-18T09:52:51.368Z
Learning: In the shapeshift/web repository, monadic error-handling with Result types (Ok/Err from sniptt/monads) is specific to the swapper domain and is not used anywhere else in the codebase. API helpers outside the swapper domain (e.g., user API, notification services) should use traditional throw/catch error handling patterns instead of Result monads.
Applied to files:
packages/swapper/src/thorchain-utils/getL1RateOrQuote.ts
📚 Learning: 2025-11-24T21:20:17.804Z
Learnt from: CR
Repo: shapeshift/web PR: 0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2025-11-24T21:20:17.804Z
Learning: Applies to **/*.{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
Applied to files:
packages/swapper/src/thorchain-utils/getL1RateOrQuote.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/index.ts : Export unique functions and types from packages/swapper/src/index.ts only if needed for external consumption
Applied to files:
packages/swapper/src/thorchain-utils/getL1RateOrQuote.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 : Reuse executeEvmTransaction utility for EVM-based swappers instead of implementing custom transaction execution
Applied to files:
packages/swapper/src/thorchain-utils/getL1RateOrQuote.tspackages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.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/constants.ts : Register new swappers in packages/swapper/src/constants.ts with an entry in the swappers registry mapping SwapperName enum to swapper implementation
Applied to files:
packages/swapper/src/thorchain-utils/getL1RateOrQuote.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/*/endpoints.ts : All swapper API implementations must implement the SwapperApi interface from packages/swapper/src/types.ts
Applied to files:
packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
🧬 Code graph analysis (5)
packages/chain-adapters/src/types.ts (6)
packages/caip/src/adapters/coingecko/generated/index.ts (1)
tron(42-42)packages/utils/src/assetData/baseAssets.ts (1)
tron(339-353)packages/chain-adapters/src/tron/types.ts (1)
GetFeeDataInput(24-28)packages/chain-adapters/src/sui/types.ts (1)
GetFeeDataInput(19-22)packages/chain-adapters/src/evm/types.ts (1)
GetFeeDataInput(82-87)packages/chain-adapters/src/solana/types.ts (1)
GetFeeDataInput(31-36)
packages/chain-adapters/src/tron/types.ts (1)
packages/chain-adapters/src/types.ts (1)
GetFeeDataInput(326-333)
packages/chain-adapters/src/tron/TronChainAdapter.ts (2)
packages/chain-adapters/src/tron/types.ts (1)
GetFeeDataInput(24-28)packages/chain-adapters/src/types.ts (2)
GetFeeDataInput(326-333)FeeDataEstimate(107-111)
src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx (1)
src/components/Modals/Send/utils.ts (1)
estimateFees(58-160)
packages/swapper/src/thorchain-utils/getL1RateOrQuote.ts (3)
packages/utils/src/index.ts (1)
contractAddressOrUndefined(46-47)packages/caip/src/adapters/coingecko/generated/index.ts (1)
tron(42-42)packages/utils/src/assetData/baseAssets.ts (1)
tron(339-353)
⏰ 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/unchained-client/src/tron/api.ts (1)
243-244: LGTM! More realistic TRC20 fallback.The reduced fallback from 31 TRX to 13 TRX (130k energy at 100 sun/energy) provides a more accurate worst-case estimate for TRC20 transfers when dynamic estimation fails. The comment clearly documents the assumption.
src/components/Modals/Send/hooks/useSendDetails/useSendDetails.tsx (1)
111-116: LGTM! Correct derivation of from address.The from address is correctly derived using
fromAccountId(accountId)and passed toestimateFees. The dependency array correctly includesaccountId(the source) rather thanfrom(the derived value), which is the appropriate pattern for stable utility derivations.src/components/Modals/Send/utils.ts (1)
136-140: LGTM! Proper Tron fee data input.The
chainSpecificobject correctly includesfrom,contractAddress, andmemofields for Tron fee estimation. This aligns with the newtron.GetFeeDataInputtype and enables the adapter to differentiate between TRC20 and TRX transfers and handle memo-based fee adjustments.packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts (1)
224-237: LGTM! Appropriate Tron fee data for rate context.The empty
chainSpecificobject is correct for rate estimation without wallet context. Since all fields intron.GetFeeDataInputare optional, the adapter can use default fee estimation logic when specific transaction details aren't available.packages/chain-adapters/src/types.ts (1)
323-323: LGTM! Proper Tron type mapping.The TronMainnet entry correctly maps to
tron.GetFeeDataInputin theChainSpecificGetFeeDataInputtype, following the established pattern for other chains and enabling type-safe Tron fee data requests.packages/chain-adapters/src/tron/types.ts (1)
24-28: LGTM! Well-designed Tron fee input type.The
GetFeeDataInputtype appropriately defines optional fields that enable:
from: Sender address for accurate TRC20 energy estimationcontractAddress: TRC20 vs TRX transfer detectionmemo: Memo-based fee adjustment (1 TRX per memo)The optional design provides flexibility for rate estimation (no wallet) vs quote contexts (wallet connected).
packages/swapper/src/thorchain-utils/getL1RateOrQuote.ts (1)
8-8: LGTM! Necessary imports for Tron integration.The imports properly support Tron fee estimation:
TronWebfor chain queries,contractAddressOrUndefinedfor TRC20 detection, and thetronnamespace for THORChain-specific utilities.Also applies to: 18-18, 46-46
…h calculation After the mergefix, the Tron GetFeeDataInput type now requires chainSpecific parameter with from, contractAddress, and memo fields. Updated all callers: - SunioSwapper: Pass from, contractAddress to estimate swap fees correctly - useApprovalFees: Pass from, contractAddress for approval tx estimation - Fixed memo fee calculation to scale with memo byte length instead of flat 1 TRX Also addressed CodeRabbit feedback: Memo data adds to transaction bandwidth proportionally to byte length, not as a separate flat fee. Removed the redundant 1 TRX memo fee and properly calculate bandwidth based on actual memo size in both chain adapter and swapper code. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Resolved conflicts from squash-merged PR #11274 (Sun.io integration): - TronChainAdapter.ts: kept improved fee estimation with from parameter and account activation - SunioSwapper/getQuoteOrRate.ts: kept detailed TronWeb-based fee estimation (this PR's feature) - NearIntents files: kept proper chainSpecific params with from and contractAddress 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Description
Handles TRC20 gas estimates better, severely underestimated atm and ending up doing at best, bandwidth errors at broadcast time, at worst, reverts and burned gas on-chain.
Issue (if applicable)
closes #11270
Risk
Low
Testing
Engineering
Operations
Screenshots (if applicable)
https://jam.dev/c/9b2bad76-9d58-446b-9b5a-1c27edb9ad0c
https://jam.dev/c/bc1b1178-c43a-43ea-bbe7-d50469a55edc
Summary by CodeRabbit
New Features
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.