Skip to content

Conversation

@gomesalexandre
Copy link
Contributor

@gomesalexandre gomesalexandre commented Dec 2, 2025

Description

Integrates the biggest TRON swapper by TVL/volume:

Screenshot 2025-12-02 at 13 48 21

NOTE: This does not yield the DAO any monies (no affiliate fees), but does expose same-chain TRON routes that otherwise wouldn't exist, so should be a zero-sum game, except for users that do get to have more routes.

Issue (if applicable)

closes N/A, yolo it is the mantra.

Risk

High Risk PRs Require 2 approvals

  • It's a swapper, so classic risk of lost funds if doing things wrong
  • Smol risk of EVM approvals borked

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

Testing

  • Ensure you can see same chain swaps for TRC <-> TRX
  • Ensure you can execute said swaps with native
  • Note, some Txs may fail with out-of-energy, this is unrelated to this PR and already happening in develop currently, related to tron adapter impl. The most important bit here is ensuring you have a well-funded TRX account (>10 TRX at any time)
  • Ensure TRC-20 with approval needed trigger an approval flow, which works

Engineering

  • ☝🏽

Operations

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

Still under flag

Screenshots (if applicable)

Screenshot 2025-12-02 at 17 21 36 Screenshot 2025-12-02 at 17 22 18 Screenshot 2025-12-02 at 17 58 34
  • TRC approvals + erc-20 smoke test

https://jam.dev/c/16796a0c-4e65-4c0c-bac6-067a559dd8c8

Summary by CodeRabbit

  • New Features
    • Sun.io swapper added for TRON with UI icon and feature flag toggle.
  • Improvements
    • Full TRON flows: quote/rate, unsigned transaction construction, fee estimation, approvals, allowance checks, and trade-status polling.
    • Utilities and types to support TRON swap/approval workflows.
  • Documentation
    • Expanded TRON-specific guide with gotchas, examples, and testing notes.
  • Security/Headers
    • Added CSP entry for Sun.io endpoints.
  • Configuration
    • Feature flag added to env and dev configs to enable Sun.io swapper.

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

gomesalexandre and others added 28 commits December 2, 2025 13:43
…ameters

Fetches and displays the current/next nonce for the account in the advanced parameters section instead of showing "Nonce..." placeholder text. Users can now see what nonce will be automatically used if they don't set a custom one.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…and implementation guide

This update transforms the swapper-integration skill from basic guidance into a comprehensive, production-ready integration framework based on analysis of 3 major swapper PRs (Bebop, NEAR Intents, Cetus) and deep understanding of the swapper abstraction.

## Major Enhancements

### Phase 0: Proactive Research (NEW)
- Use WebFetch/WebSearch to research swapper APIs BEFORE asking user
- Automatically find documentation, chain support, existing integrations
- Only ask user for what can't be found online

### Expanded allowed-tools
- Added WebFetch, WebSearch for autonomous research
- Added AskUserQuestion for structured multi-question prompts
- Added gh pr:* for PR research

### Deep Swapper Categorization
- EVM Direct Transaction (Bebop, 0x, Portals)
- Deposit-to-Address (Chainflip, NEAR Intents, THORChain)
- Gasless Order-Based (CowSwap)
- Solana-Only (Jupiter)
- Chain-Specific (Cetus/Sui, Tron, etc.)

### Complete Implementation Guide
- Step-by-step file creation order (10 files)
- Full code templates for each file with actual TypeScript
- Detailed explanations of monadic error handling
- HTTP service factory with caching pattern
- Rate calculation strategies

### Swapper-Specific Metadata Deep Dive
- When to use vs when to skip
- THREE places to wire (types, quote, TWO extraction points)
- Critical: Both useTradeButtonProps AND tradeExecution.ts
- Example flows from NEAR Intents

### Registration Checklist (9 steps)
- SwapperConfig types
- Constants registration
- CSP headers with examples
- Feature flags (3 files)
- UI icon integration
- Environment variables (.env patterns)
- Test mocks

### Proactive Gotcha Prevention
- 10 critical bugs to check BEFORE testing
- Based on real issues from Bebop/NEAR Intents/Cetus PRs
- Slippage format, checksumming, hex conversion, response parsing

### Testing Framework
- Automated checks (type-check, lint, build)
- 11-point manual testing checklist
- 6-point edge case testing
- Rate vs quote delta verification

### Common Errors & Solutions
- 8 common error messages with exact fixes
- Direct mapping from error → solution
- Based on actual PR comments and fixes

## Key Insights from PR Analysis

### From Bebop PR (#11000)
- Dual routing with partial failure handling
- Affiliate fee delta issues (rate vs quote)
- Hex → decimal conversion patterns
- Address checksumming requirements

### From NEAR Intents PR (#11016)
- Deposit-to-address metadata flow
- Status polling with swap metadata
- Cross-chain EVM/UTXO/Solana handling
- OneClick SDK integration patterns

### From Cetus PR (#11240)
- Sui chain-specific adaptations
- Non-EVM transaction metadata
- Chain adapter fee estimation
- Token vs coin namespace handling

## Skill Quality Improvements

- 1500+ lines of comprehensive guidance (3x expansion)
- Code templates with actual imports and types
- File structure with exact locations
- Integration checklist (28 items)
- Three-phase workflow (Research → Implement → Test)

## Technical Depth

- Monadic Result<T, SwapErrorRight> pattern explained
- HTTP service with caching (createCache, makeSwapperAxiosServiceMonadic)
- Chain adapter usage for fee estimation
- Native token marker handling
- TradeQuote vs TradeRate differences
- accountNumber: undefined requirement for rates

## Documentation Template

- Complete INTEGRATION.md structure
- API details section
- Implementation notes with code
- Known gotchas documentation
- Testing strategies

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Adds Sun.io as a new swap aggregator supporting TRC-20 token swaps on the TRON blockchain. Sun.io's smart router aggregates liquidity across SunSwap V1, V2, V3, PSM, and Curve protocols to find optimal swap routes.

## Implementation Details

### API Integration
- **Endpoint**: https://rot.endjgfsv.link/swap/router (official Sun.io backend, verified via frontend XHR inspection)
- **Method**: GET with query parameters (fromToken, toToken, amountIn, typeList)
- **Authentication**: None required
- **Response**: Returns multiple routes sorted by best price with amounts, fees, pool versions

### TRON-Specific Implementation
- Built custom TRON smart contract transaction builder for `swapExactInput` function
- Smart Router Contract: TQAvWQpT9H916GckwWDJNhYZvQMkuRL7PN
- Uses TronWeb to build contract calls with route parameters (path, poolVersion, versionLen, fees)
- Handles TRC-20 token addresses (Base58 format, not EVM checksummed)

### Files Created
- `packages/swapper/src/swappers/SunioSwapper/` - Full swapper implementation
  - `types.ts` - API request/response types
  - `constants.ts` - Supported chains, router contract, DEX types
  - `utils/sunioService.ts` - HTTP client with caching
  - `utils/fetchFromSunio.ts` - API wrapper for quote fetching
  - `utils/helpers/helpers.ts` - Chain validation, token address conversion
  - `utils/buildSwapRouteParameters.ts` - Maps API routes to contract parameters
  - `getSunioTradeQuote/getSunioTradeQuote.ts` - Quote logic with fee estimation
  - `getSunioTradeRate/getSunioTradeRate.ts` - Rate logic (no wallet needed)
  - `endpoints.ts` - SwapperApi implementation with custom TRON tx builder
  - `SunioSwapper.ts` - Swapper interface (executeTronTransaction)
  - `INTEGRATION.md` - Complete integration documentation

### Registration
- Added `SwapperName.Sunio` enum
- Registered in swappers record with default 0.5% slippage
- Exported from main swapper package

### CSP Headers
- Added `headers/csps/defi/swappers/Sunio.ts`
- Whitelisted rot.endjgfsv.link and openapi.sun.io domains

### Feature Flag
- Added `SunioSwap` feature flag to preferences slice
- Wired through state helpers (enabled swappers, cross-account support)
- Updated test mocks
- Environment variables: VITE_FEATURE_SUNIO_SWAP (false in prod, true in dev)

### UI Integration
- Downloaded and converted Sun.io favicon to PNG (128x128)
- Added icon to SwapperIcon component
- Icon displays when Sun.io is selected swapper

## Technical Challenges Solved

### TRON Smart Contract Execution
Unlike deposit-to-address swappers (NEAR Intents, Relay), Sun.io requires building complex smart contract calls. Implemented custom transaction builder using TronWeb's `triggerSmartContract` method.

### Amount Format Conversion
API returns human-readable amounts (e.g., "1.071122") - must convert to base units by multiplying by 10^precision.

### Multi-Hop Route Handling
API can return multi-hop swaps (e.g., USDC→WTRX→USDT). Correctly map intermediate tokens to contract path parameter.

### Slippage Application
API doesn't apply slippage - we calculate `amountOutMin` by applying slippage percentage to protect user from price movement.

## Testing Checklist

Automated:
- ✅ Type-check passes
- ✅ Lint passes
- ✅ Builds successfully

Manual Testing (to be performed):
- [ ] Can fetch quotes for TRON TRC-20 pairs
- [ ] Rates display without wallet connected
- [ ] Can execute swap transaction on TRON
- [ ] Native TRX swaps work
- [ ] Multi-hop routes execute correctly
- [ ] Slippage protection works
- [ ] Feature flag toggles swapper

## Known Limitations

1. **TRON Only**: No cross-chain or multi-chain support
2. **No Affiliate Fees**: API doesn't support affiliate fee parameter
3. **Simple Status Checking**: Returns default status (full TRON tx polling not implemented)
4. **No Cross-Account**: sendAddress must equal receiveAddress

## References

- Sun.io Smart Router: https://docs.sun.io/developers/swap/smart-router
- Smart Exchange Router Contract: https://github.com/sun-protocol/smart-exchange-router
- TronWeb Library: https://tronweb.network/docu/docs/intro/
- Similar Pattern: Jupiter (Solana-only aggregator)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
… to skill

## Code Improvements

**Rate Calculation**:
- Use standard `getInputOutputRate` helper instead of manual calculation
- Ensures consistency with other swappers
- Properly handles precision conversion

**Files Updated**:
- `getSunioTradeQuote.ts` - Use getInputOutputRate
- `getSunioTradeRate.ts` - Use getInputOutputRate

## Swapper Skill Enhancements

Added 4 new TRON-specific gotchas to common-gotchas.md based on Sun.io implementation:

**Gotcha #13: Human-Readable Amounts**
- TRON APIs return amounts like "1.071122" not base units
- Must multiply by 10^precision to convert

**Gotcha #14: Smart Contract Transaction Building**
- Generic tron-utils only handle simple sends
- Need custom TronWeb triggerSmartContract for swaps
- Must handle raw_data_hex type variations (string/Buffer/array)

**Gotcha #15: TRON Address Format**
- TRON uses Base58 (starts with 'T'), not EVM hex
- No checksumming needed - addresses already in correct format
- Native TRX: T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb

**Gotcha #16: RPC URL Access**
- SwapperConfig doesn't include TRON RPC URL
- Must access from chain adapter: `(adapter as any).rpcUrl`
- Protected property requires type assertion

These gotchas will help future TRON swapper integrations avoid the same challenges.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The triggerSmartContract low-level API has issues with address[] parameters
in newer TronWeb versions, causing 'invalid address' errors when trying to
validate Base58 TRON addresses as EVM hex addresses.

Solution: Use the contract interface approach with ABI:
- tronWeb.contract(abi, address).methods.functionName()._build()
- This properly handles TRON Base58 addresses in array parameters
- Matches the pattern from working SunSwap integration examples

Changes:
- Added SUNSWAP_ROUTER_ABI with swapExactInput function definition
- Replaced triggerSmartContract with contract.methods approach
- Fixed transaction building to use _build() method

This fixes the 'invalid address' error when executing Sun.io swaps.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
TronWeb's contract.methods internally mutates the parameter arrays when
converting addresses. If the arrays are frozen/immutable (from API response
or const declarations), this causes 'Cannot assign to read only property' errors.

Solution: Clone arrays with spread operator before passing to TronWeb:
- [...routeParams.path]
- [...routeParams.poolVersion]
- [...routeParams.versionLen]
- [...routeParams.fees]

This allows TronWeb to mutate the cloned arrays without errors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
TronWeb's triggerSmartContract requires addresses in hex format, not Base58.
Use tronWeb.address.toHex() to convert all addresses in parameters:
- path[] addresses (token route)
- recipient address in SwapData tuple

This prevents address validation errors when building transactions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Added practical guidance discovered during Sun.io integration:

**New Gotcha #17: TRON Address Hex Conversion**
- triggerSmartContract requires hex addresses, not Base58
- Use tronWeb.address.toHex() for all address parameters
- Includes node -e test example

**New Gotcha #18: Immutable Array Parameters**
- TronWeb mutates parameter arrays internally
- Clone arrays with spread [...array] before passing
- Prevents 'Cannot assign to read only property' errors

**PROTIP: node -e for Quick Testing**
Added to Phase 2 of main SKILL.md with examples:
- Test address conversions (TronWeb, viem checksumming)
- Verify library behavior before coding
- Parse API response structures
- Test mathematical calculations

Use cases:
- Address transformations
- Checksum validation
- Response structure verification
- Library API exploration

This speeds up development by catching issues before writing full code.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
TronWeb doesn't accept plain 'tuple' type - must specify full type signature.
Struct/tuple values must be passed as ordered array, not object.

Before: { type: 'tuple', value: { amountIn, amountOutMin, to, deadline } }
After: { type: 'tuple(uint256,uint256,address,uint256)', value: [amountIn, amountOutMin, to, deadline] }

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
After testing with working SunSwap example, confirmed that addresses should be
passed as Base58 strings directly (e.g., 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'),
NOT converted to hex.

The working example shows:
  const path = [usdtAddr, usdjAddr];  // Base58 strings
  await router.swapExactInput(path, poolVersion, versionLen, fees, data).send()

Reverted hex conversion - TronWeb handles Base58 natively when using the
contract interface approach with proper ABI.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com)
The ABI was used when attempting contract interface approach, but we reverted
to triggerSmartContract with raw parameters. Removing unused import.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Added console.log statements throughout getUnsignedTronTransaction to debug
the 'invalid address' error with TronWeb's triggerSmartContract.

Logs include:
- Route metadata and amounts
- RPC URL
- Route parameters (path, poolVersion, versionLen, fees, swapData)
- TronWeb parameters array
- Function selector
- Contract and from addresses
- Transaction build result

This will help identify where/why TronWeb is rejecting the Base58 address.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
TronWeb's triggerSmartContract validates the issuerAddress parameter.
Setting the default address on the TronWeb instance may help with validation.

Added: tronWeb.setAddress(from) before calling triggerSmartContract

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com)
…nWeb 6.x

## Problem
TronWeb 6.1.0 uses ethers.js internally for ABI encoding but has a bug where
it only converts TRON Base58 addresses to EVM format (0x-prefixed hex) for
'address' and 'address[]' types, NOT for addresses inside tuple parameters.

This causes ethers.js AbiCoder to throw: 'invalid address' errors when
processing tuples containing TRON addresses.

## Root Cause
In TransactionBuilder._getTriggerSmartContractArgs, the address conversion
logic only matches:
- type === 'address'
- type.match(/^address\[/) === 'address['

It does NOT handle tuple types like 'tuple(uint256,address,uint256)'.

## Solution
Added convertAddressesToEvmFormat() helper that recursively converts TRON
Base58 addresses (TRwyik...) to EVM hex format (0xaf46...) by:
1. Converting to TRON hex: TronWeb.address.toHex() → 41af46...
2. Replacing 41 prefix with 0x: → 0xaf46...

Applied to all tuple values before passing to triggerSmartContract.

## Why EVM Format for TRON?
TronWeb uses ethers.js (Ethereum library) for ABI encoding. The 0x format
is only for parameter encoding - the final TRON transaction still uses
TRON addresses. This is an internal quirk of TronWeb's implementation.

## Files Changed
- endpoints.ts: Added helper, applied to tuple parameters, removed debug logs
- buildSwapTransaction.ts: Added helper, applied to tuple parameters
- common-gotchas.md: Added Gotcha #19 with detailed explanation and tests

## Tested
✅ Verified with node -e testing
✅ All edge cases handled (nested arrays, nulls, non-addresses)
✅ Works with both Base58 and already-converted 0x addresses (idempotent)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…TRX swaps

## Two Critical Fixes

### Fix 1: Wrong Router Contract
We were using TQAvWQpT9H916GckwWDJNhYZvQMkuRL7PN (V3 Router) but sun.io's
frontend uses TCFNp179Lg46D16zKoumd4Poa2WFFdtqYj (Smart Exchange Router).

The Smart Router aggregates liquidity across V1, V2, V3, PSM, and SunCurve,
which is what the API returns in poolVersions.

### Fix 2: Missing call_value for Native TRX
When selling native TRX, TRON requires sending the TRX amount as call_value
in the transaction options. Sun.io sets this to the sell amount for TRX swaps.

Added logic to detect native TRX sales and set call_value accordingly:
- If selling TRX: callValue = sellAmount
- If selling TRC20: callValue = 0

## Changes
- constants.ts: Updated to TCFNp179Lg46D16zKoumd4Poa2WFFdtqYj
- endpoints.ts: Import tronAssetId, check if selling native TRX, set callValue

## Why This Matters
- Correct contract = supports all route types (v1, v2, v3, psm, curve)
- call_value = required for TRON to accept native token transfers

This should resolve the signature/permission errors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…lding

Added console.log statements with JSON.stringify to track:

Quote phase:
- Input parameters (addresses, amounts, accountNumber)
- API response from Sun.io
- Calculated values (buyAmount, fees, rate)
- Final TradeQuote with metadata

Transaction building phase:
- getUnsignedTronTransaction args (from address, stepIndex)
- Step details (sellAsset, buyAsset, amounts, accountNumber)
- Route metadata from quote
- Transaction parameters (contract, callValue, isSellingNativeTrx)
- TronWeb build result
- Final unsigned transaction (addressNList, owner_address)

This will help debug the signature error where wallet signs with
TLaFntgFXpZeTNPpMAL24pNYXoHfAhULG7 instead of expected address.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Added console logs in useTradeExecution.tsx to track:
- Address returned by adapter.getAddress()
- Wallet ID being used
- Transaction details before signing (addressNList, owner_address)
- Signed transaction output

This will reveal if there's a mismatch between the address we think
we're using and what the wallet actually signs with.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The addressNList was using non-hardened values [44, 195, 0, 0, 0] but
TRON wallets expect hardened derivation for purpose/coinType/account:
m/44'/195'/0'/0/0

Fixed by adding 0x80000000 (2^31) to first three values:
- 44 → 2147483692 (44')
- 195 → 2147483843 (195')
- 0 → 2147483648 (0')

This matches how NEAR Intents builds TRON transactions, which work correctly.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Replaced placeholder status check with actual TRON transaction lookup:
- Uses adapter.httpProvider.getTransaction() to fetch tx from TRON network
- Maps contractRet status: SUCCESS → Confirmed, REVERT → Failed, else → Pending
- Falls back to default Unknown status if lookup fails

This enables proper swap status tracking in the UI instead of always
showing Unknown status.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Two type fixes for status polling:
1. Added TronSwapperDeps to CheckTradeStatusInput type so assertGetTronChainAdapter is available
2. Import and use TxStatus enum (TxStatus.Confirmed, etc.) instead of string literals

This resolves build errors in endpoints.ts checkTradeStatus implementation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
TronTx type has a status property that already contains the TxStatus enum.
No need to manually map contractRet values.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
TronTx interface doesn't have a status property. Instead, check if
tx.confirmations > 0 to determine if transaction is confirmed.

Returns:
- Confirmed if tx exists and has confirmations
- Unknown (default) if tx not found or no confirmations yet

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Removed all debug logging added during development:
- Quote input/output logs
- API response logs
- Transaction building logs
- Wallet signing logs

Production code is now clean and ready for use.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com)
…tion

Added assertGetTronChainAdapter to the checkTradeStatus call so TRON
swappers can access the adapter for transaction status lookup.

This fixes 'assertGetTronChainAdapter is not a function' error in
Sun.io status polling.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The unchained-client getTransaction() hardcodes confirmations to 0,
making it useless for status checking.

Instead, call /wallet/gettransactionbyid directly and check ret[0].contractRet:
- SUCCESS → Confirmed
- REVERT → Failed
- Otherwise → Pending

This provides accurate swap status tracking.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com)
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…ation

Replaced manual hardened derivation path construction with the standard
toAddressNList() helper that's used throughout the codebase.

Before (manual):
  const HARDENED = 0x80000000
  addressNList = [purpose + HARDENED, coinType + HARDENED, ...]

After (standard):
  addressNList = toAddressNList(bip44Params)

Benefits:
- DRY: Don't duplicate hardening logic
- Consistent: Same pattern as NEAR/Relay TRON transactions
- Maintainable: One source of truth for BIP44 hardening

This is the correct pattern - toAddressNList already handles converting
m/44'/195'/0'/0/0 notation to [2147483692, 2147483843, 2147483648, 0, 0].

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 2, 2025

📝 Walkthrough

Walkthrough

Adds a Sun.io TRON swapper integration including API client, quote/rate helpers, TRON transaction builders, fees/status handlers, TRON approve/allowance utilities, CSP and feature‑flag wiring, UI icon/state updates, and TRON-specific documentation/gotchas.

Changes

Cohort / File(s) Change Summary
Docs / Gotchas
.claude/skills/swapper-integration/common-gotchas.md
Added TRON-specific gotchas (sections 13–19) covering unit conversion, TronWeb usage, address formats, RPC access, tuple/hex handling, and mutability workarounds with examples.
Env & Config
.env, .env.development, src/config.ts
Added VITE_FEATURE_SUNIO_SWAP env flag (false/.env, true/.env.development) and validator entry in config.
CSP Headers
Sunio CSP
headers/csps/defi/swappers/Sunio.ts, headers/csps/index.ts
New CSP for Sunio with connect-src entries (https://rot.endjgfsv.link, https://openapi.sun.io) and inclusion in exported csps.
Swapper Registry & Exports
packages/swapper/src/constants.ts, packages/swapper/src/index.ts, packages/swapper/src/types.ts
Register SwapperName.Sunio, add default slippage constant and swappers map entry, export SunioSwapper, and extend types (TradeQuoteStep metadata and CheckTradeStatusInput).
SunioSwapper Public API
packages/swapper/src/swappers/SunioSwapper/index.ts, .../endpoints.ts, .../SunioSwapper.ts
New sunioApi (quote/rate/unsigned tron tx/fees/status) and sunioSwapper implementation; barrel exports for types/constants.
Quote/Rate Helpers
packages/swapper/src/swappers/SunioSwapper/getSunioTradeQuote/..., .../getSunioTradeRate/..., .../getQuoteOrRate.ts
Implemented getSunioTradeQuote/getSunioTradeRate delegations and unified getQuoteOrRate with TRON validation, fee/rate computation, error mapping, and Sunio route metadata.
Integration Docs
packages/swapper/src/swappers/SunioSwapper/INTEGRATION.md
Comprehensive Sun.io TRON integration guide (endpoints, mapping, tx construction, testing, known issues, gotchas).
Sunio Utilities & Constants
packages/swapper/src/swappers/SunioSwapper/utils/abi.ts, utils/constants.ts, utils/helpers/helpers.ts
ABI constant for router, Sunio API/contract constants, chain/token helpers and supported-chain checks.
Service & Fetch
packages/swapper/src/swappers/SunioSwapper/utils/sunioService.ts, utils/fetchFromSunio.ts
Axios monadic service factory with short cache and fetchFromSunio that queries SUNIO_API_BASE_URL and returns monadic Result (Ok/Err).
Route → Params / Tx Builder
packages/swapper/src/swappers/SunioSwapper/utils/buildSwapRouteParameters.ts, .../buildSwapTransaction.ts
Build route parameter mapping (path, poolVersion, versionLen, fees, swapData) and build Sunio TRON smart-contract transaction via TronWeb (address conversions, tuple assembly, triggerSmartContract); exports builder and types.
Swapper Types
packages/swapper/src/swappers/SunioSwapper/types.ts
Added Sunio types: SunioRoute, SunioQuoteResponse, supported DEX types, and chain id alias.
Feature Flags & State
src/state/slices/preferencesSlice/preferencesSlice.ts, src/state/helpers.ts, src/test/mocks/store.ts
Added SunioSwap feature flag (config-backed), integrated into getEnabledSwappers gating, added to mock store and cross-account support logic.
UI
src/components/.../SwapperIcon/SwapperIcon.tsx
Added Sunio icon import and mapping for SwapperName.Sunio.
Trade Execution / Status
src/lib/tradeExecution.ts, packages/swapper/src/swappers/SunioSwapper/endpoints.ts
Pass assertGetTronChainAdapter into checkTradeStatus; Sunio endpoints implement checkTradeStatus polling via Tron RPC contractRet mapping.
TRON utils: approve & allowance
src/lib/utils/tron/approve.ts, src/lib/utils/tron/getAllowance.ts, src/lib/utils/tron/types.ts, src/lib/utils/tron/index.ts, src/lib/utils/index.ts
New Tron utilities: approveTron (build/sign/broadcast TRON approve), getTrc20Allowance/getAllowance (triggerConstantContract decode), types and barrel exports; re-exported from utils index.
Approval / Fees / Approval UI flows
src/components/.../useAllowanceApproval.tsx, src/hooks/queries/useApprovalFees.ts, src/react-queries/queries/mutations.ts, src/react-queries/queries/common.ts
TRON-specific flows: approval mutation supports Tron input/wallet, approval UI uses TRON polling for tx confirmation, fee estimation supports TRON via chain adapter, allowance query uses TRON path.
Misc trivial
src/components/MultiHopTrade/hooks/useGetTradeQuotes/useGetTradeQuotes.tsx
Minor whitespace edit; no behavior change.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as Web App
    participant Service as SunioService (cache)
    participant SunioAPI as Sun.io API
    participant TronWeb as TronWeb / Tron Adapter
    participant TRON as TRON Node / Smart Contract

    User->>UI: request trade quote (sell, buy, amount)
    UI->>Service: fetchFromSunio(sell, buy, amount)
    Service->>SunioAPI: GET /swap/router (cached)
    SunioAPI-->>Service: SunioQuoteResponse
    Service-->>UI: Ok(routes)
    UI->>UI: buildSwapRouteParameters(selected route)
    UI->>TronWeb: buildSunioSwapTransaction(params, rpcUrl)
    TronWeb->>TRON: triggerSmartContract (unsigned tx)
    TRON-->>TronWeb: txData.transaction
    UI->>User: present unsigned tx for signing
    User->>UI: signed tx (wallet)
    UI->>TRON: broadcast signed transaction
    loop poll
      UI->>TRON: /wallet/gettransactionbyid(txHash)
      TRON-->>UI: status (contractRet / confirmations)
    end
    UI-->>User: final trade status (confirmed/failed)
Loading
sequenceDiagram
    participant Caller
    participant getQuoteOrRate
    participant fetchFromSunio
    participant SunioService
    participant SunioAPI
    participant TronAdapter
    participant Result

    Caller->>getQuoteOrRate: request
    getQuoteOrRate->>fetchFromSunio: call
    fetchFromSunio->>SunioService: request (cache)
    SunioService->>SunioAPI: HTTP GET
    SunioAPI-->>SunioService: response
    SunioService-->>fetchFromSunio: response
    fetchFromSunio-->>getQuoteOrRate: Ok/Err
    alt Ok
      getQuoteOrRate->>TronAdapter: getFeeData
      getQuoteOrRate->>getQuoteOrRate: compute fees, buyAmount, rate
      getQuoteOrRate-->>Caller: Ok(TradeQuote/Rate with metadata)
    else Err
      getQuoteOrRate-->>Caller: Err(SwapErrorRight)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Pay extra attention to:
    • TRON transaction building and tuple/ABI parameter encoding (buildSwapTransaction.ts, utils/abi.ts).
    • TronWeb interactions and RPC error handling (approveTron, getTrc20Allowance, endpoints.getUnsignedTronTransaction).
    • Consistency of Result/SwapErrorRight propagation across fetchFromSunio → getQuoteOrRate → endpoints.
    • Feature-flag wiring and enabled-swappers mapping (state/helpers, preferencesSlice, .env files).
    • Approval/fee branching for TRON vs EVM in queries/mutations and useApprovalFees.

Possibly related PRs

Suggested labels

high risk

Suggested reviewers

  • NeOMakinG
  • premiumjibles

Poem

🐇
I hopped through code both day and night,
I stitched Base58 to hex with nimble might.
I built routes, deadlines, and a Tron-bound plea,
Contracts triggered, hops danced—then tea for me.
Hooray for Sun.io swaps beneath the sun!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: sun.io swapper' clearly and specifically summarizes the main change: adding sun.io swapper integration to the platform.
✨ 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 feat_swapper_sun_io

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • TRC-20: Entity not found: Issue - Could not find referenced Issue.

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.

gomesalexandre and others added 4 commits December 4, 2025 00:36
Completes TRON approval implementation:

## What Works
- ✅ Allowance checking via getTrc20Allowance
- ✅ Approval transaction building with TronWeb
- ✅ HDWallet signing with supportsTron type guard
- ✅ Transaction broadcast with proper JSON format
- ✅ Quote refresh after approval completes
- ✅ Full end-to-end approval → swap flow

## Key Fixes
1. Broadcast format: Build transaction object with signature array
2. Confirmation polling: Increased timeout to 60s, dual endpoint strategy
3. accountNumber in rates: Extract from input like Relay swapper
4. EVM contract data: Skip generation for TRON chains

## Technical Details
- signedTx.serialized is raw hex, not JSON string
- Must construct: {...transaction, signature: [signedTx.signature]}
- Poll /wallet/gettransactionbyid first (fast), then /walletsolidity (slow but confirmed)
- Don't throw on confirmation timeout (tx may still succeed)

Tested: USDT approval + swap works end-to-end

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@gomesalexandre
Copy link
Contributor Author

Quite happy codewise but impossible to swap from USDC to USDT and the contrary, and swap back my USDC to TRX

Added TRON approvals in 5d52301 and following commits @NeOMakinG !
See test + EVM approvals smoke test https://jam.dev/c/16796a0c-4e65-4c0c-bac6-067a559dd8c8. Note you still need a well-funded TRX balance, and displaying/fees estimation still isn't a thing for now, see #11274

gomesalexandre and others added 2 commits December 4, 2025 01:10
- Replace (adapter as any).rpcUrl with adapter.httpProvider.getRpcUrl()
- Extract hardcoded native TRX address to SUNIO_TRON_NATIVE_ADDRESS constant
- Fix INTEGRATION.md router contract address (was wrong V3 router)

All changes improve type safety and maintainability.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Added CURVE_COMBINATION and WTRX to typeList parameter, enabling
access to additional liquidity pools (oldusdcpool, usdj2pooltusdusdt, etc).

Testing shows ~0.7% better rates with full coverage:
- Before: 1.058133 USDC (v2 pool only)
- After: 1.065580 USDC (oldusdcpool - specialized stable pool)

All DEX types supported by Sun.io Smart Router are now included.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@gomesalexandre
Copy link
Contributor Author

gomesalexandre commented Dec 3, 2025

⚠️ One thing to note: the swap is so fast that the getAccount call is not even updating balances, specially trc20s balances, we need to find an heuristic for that

Basically related to the wrongly implemented getTransaction in unchained-client (they're not as fast at all), asking coderabbit to create an issue

Extracted 95% duplicated code into shared getQuoteOrRate utility,
following Relay and Chainflip swapper patterns.

Changes:
- Created utils/getQuoteOrRate.ts with unified logic (183 lines)
- Reduced getSunioTradeRate from 132 → 11 lines (thin wrapper)
- Reduced getSunioTradeQuote from 170 → 17 lines (thin wrapper)
- Total reduction: 302 lines → 211 lines (30% smaller)

Uses function overloads to maintain type safety:
- getQuoteOrRate(rateInput) → Promise<Result<TradeRate>>
- getQuoteOrRate(quoteInput) → Promise<Result<TradeQuote>>

Behavior unchanged - branches on input.quoteOrRate for:
- Fee fetching (quote only)
- Protocol fees (quote only)
- Transaction metadata (quote only)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@gomesalexandre gomesalexandre marked this pull request as ready for review December 3, 2025 22:59
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: 4

🧹 Nitpick comments (3)
src/lib/utils/tron/approve.ts (1)

30-33: Hardcoded feeLimit may be insufficient or excessive.

The feeLimit: 100_000_000 (100 TRX) is hardcoded. While this is a reasonable default for simple approvals, consider:

  1. Making this configurable if approval gas costs vary significantly
  2. Adding a comment explaining why 100 TRX was chosen

This isn't blocking since approvals are typically low-cost operations, but worth noting for future maintenance.

packages/swapper/src/swappers/SunioSwapper/utils/getQuoteOrRate.ts (1)

128-135: Add validation or comment documenting the expected fee format.

Line 134 calculates protocol fees as bn(bestRoute.fee).times(sellAmountIncludingProtocolFeesCryptoBaseUnit), assuming bestRoute.fee is a decimal ratio (e.g., "0.003000" for 0.3%). While the INTEGRATION.md example response shows this format, consider adding either:

  1. A brief inline comment documenting the expected format: // bestRoute.fee is decimal ratio (e.g., 0.003 for 0.3%)
  2. Runtime validation: Check that bestRoute.fee is numeric and within a reasonable range (0 to 1)

This will prevent silent calculation errors if the Sun.io API changes its fee representation (e.g., percentage like 3 or basis points like 30).

src/hooks/queries/useApprovalFees.ts (1)

96-102: Rename evmFeesResult property to reflect unified fees.

The returned property evmFeesResult (line 101) now contains either TRON or EVM fees depending on chainId, but the name implies EVM-only data. This naming mismatch can mislead consumers of the hook and reduce maintainability.

Consider renaming to better reflect the unified nature:

-  // Return unified interface - TRON or EVM fees
-  const feesResult = chainId === tronChainId ? tronFeesResult : evmFeesResult
+  // Return unified interface - TRON or EVM fees
+  const approvalFeesResult = chainId === tronChainId ? tronFeesResult : evmFeesResult

   return {
     approveContractData,
-    evmFeesResult: feesResult,
+    approvalFeesResult,
   }

Note: This is a breaking change to the hook's public API. Verify consumption sites and update accordingly.

- Fix comment contradiction in TRON tx polling (useAllowanceApproval.tsx:131)
  Comment now correctly states we try /wallet first (recent txs), then /walletsolidity (confirmed txs)

- Fix potential undefined txid in TRON approval broadcast (approve.ts:104)
  Extract txid from transaction.txID as fallback if result.txid is undefined

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
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)
src/lib/utils/tron/approve.ts (2)

47-62: Consider simplifying rawDataHex handling and avoiding Buffer in the browser bundle

transaction.raw_data_hex should already be a hex string from TronWeb, so the Buffer/array branches may be unnecessary. Relying on the global Buffer can also be brittle in browser builds unless it’s explicitly polyfilled.

You could simplify this to a string‑only path (and fail fast otherwise), which also avoids the Buffer dependency:

-  const rawDataHex =
-    typeof transaction.raw_data_hex === 'string'
-      ? transaction.raw_data_hex
-      : Buffer.isBuffer(transaction.raw_data_hex)
-      ? (transaction.raw_data_hex as Buffer).toString('hex')
-      : Array.isArray(transaction.raw_data_hex)
-      ? Buffer.from(transaction.raw_data_hex as number[]).toString('hex')
-      : (() => {
-          throw new Error(`Unexpected raw_data_hex type: ${typeof transaction.raw_data_hex}`)
-        })()
+  if (typeof transaction.raw_data_hex !== 'string') {
+    throw new Error(`Unexpected raw_data_hex type: ${typeof transaction.raw_data_hex}`)
+  }
+
+  const rawDataHex = transaction.raw_data_hex

79-107: Tighten signing validation and enrich broadcast error details

Two small robustness wins here:

  1. You only guard on signedTx.serialized but always use signedTx.signature in broadcastTx. If signature is ever missing, you’ll send an invalid transaction:
-  if (!signedTx?.serialized) {
-    throw new Error('Failed to sign TRON approval transaction')
-  }
+  if (!signedTx?.serialized || !signedTx.signature) {
+    throw new Error('Failed to sign TRON approval transaction')
+  }
  1. On non‑OK HTTP responses, you throw with only statusText, losing the RPC error payload (e.g., out‑of‑energy, contract reverts), which is important for debugging swap failures. Consider reading a short snippet of the body:
-  if (!broadcastResponse.ok) {
-    throw new Error(`Failed to broadcast TRON approval: ${broadcastResponse.statusText}`)
-  }
-
-  const result = await broadcastResponse.json()
+  if (!broadcastResponse.ok) {
+    const errorBody = await broadcastResponse.text().catch(() => '')
+    throw new Error(
+      `Failed to broadcast TRON approval: ${
+        broadcastResponse.statusText || 'HTTP error'
+      } ${errorBody ? `- ${errorBody.slice(0, 200)}` : ''}`,
+    )
+  }
+
+  const result = await broadcastResponse.json()

These changes don’t alter the happy path but give clearer failures when something goes wrong. Based on learnings, feel free to skip if you prefer the current lightweight error surface for this helper.

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 4bd9a36 and 6e835ed.

📒 Files selected for processing (2)
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx (2 hunks)
  • src/lib/utils/tron/approve.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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:

  • src/lib/utils/tron/approve.ts
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
**/*.{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:

  • src/lib/utils/tron/approve.ts
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
**/*.{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:

  • src/lib/utils/tron/approve.ts
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
**/*.{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 use useErrorToast hook for displaying errors with translated error messages and handle different error types appropriately

Use PascalCase for React component names and match the component name to the file name

Files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

**/*.{jsx,tsx}: ALWAYS use useMemo for expensive computations, object/array creations, and filtered data
ALWAYS use useMemo for derived values and computed properties
ALWAYS use useMemo for conditional values and simple transformations
ALWAYS use useCallback for event handlers and functions passed as props
ALWAYS use useCallback for any function that could be passed as a prop or dependency
ALWAYS include all dependencies in useEffect, useMemo, useCallback dependency arrays
NEVER use // eslint-disable-next-line react-hooks/exhaustive-deps unless 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 with memo for performance optimization

Files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react-best-practices.mdc)

Ensure TypeScript types are explicit and proper; avoid use of any type

Files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
🧠 Learnings (38)
📓 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.307Z
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: 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: 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: 10569
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/WalletConnectModalSigningFooter.tsx:121-129
Timestamp: 2025-09-17T22:40:30.149Z
Learning: gomesalexandre maintains strict scope discipline even for style/UI PRs in shapeshift/web, declining functionally correct UX improvements (like keeping Cancel button enabled during gas simulation loading) when they fall outside the PR's stated styling objectives, demonstrating his consistent pattern of deferring valid but tangential improvements to separate efforts.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP712MessageDisplay.tsx:21-24
Timestamp: 2025-09-12T13:16:27.004Z
Learning: gomesalexandre declined to add error boundaries to WalletConnect modals in PR #10461, stating "no error boundaries in this pr ser", consistent with his preference to keep PR scope focused and defer tangential improvements to separate efforts.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10418
File: src/plugins/walletConnectToDapps/components/header/WalletConnectToDappsHeaderButton.tsx:0-0
Timestamp: 2025-09-08T22:00:48.005Z
Learning: gomesalexandre dismissed an aria-label accessibility suggestion with "meh" in PR #10418 for WalletConnectToDappsHeaderButton.tsx, consistent with the team's pattern of deferring minor a11y improvements to follow-up PRs rather than expanding feature PR scope.
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/ButtonWalletPredicate/ButtonWalletPredicate.tsx:7-7
Timestamp: 2025-08-27T09:47:06.275Z
Learning: In shapeshift/web project, NeOMakinG consistently prefers to defer UI/UX improvements and refactoring work (like the Drawer.Close hack fix in ButtonWalletPredicate.tsx) to follow-up PRs rather than expanding the scope of feature PRs, even when the improvements would enhance robustness.
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11171
File: src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx:295-296
Timestamp: 2025-11-28T13:07:32.395Z
Learning: Tron is not supported on GridPlus, Trezor, or Ledger hardware wallets. Therefore, skipDeviceDerivation optimization (which only applies to these wallet types) is not needed in Tron adapter code paths.
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-12-03T23:21:16.968Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11261
File: src/lib/utils/tron/getAllowance.ts:14-59
Timestamp: 2025-12-03T23:21:16.968Z
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:

  • src/lib/utils/tron/approve.ts
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-12-03T23:16:28.307Z
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.307Z
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.

Applied to files:

  • src/lib/utils/tron/approve.ts
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-09-12T10:44:46.723Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/content/SendTransactionContent.tsx:0-0
Timestamp: 2025-09-12T10:44:46.723Z
Learning: gomesalexandre dismissed a clipboard error handling suggestion in PR #10461 for SendTransactionContent.tsx, demonstrating that the current navigator.clipboard.writeText implementation works as expected and preferring to keep it simple without additional try/catch error handling.

Applied to files:

  • src/lib/utils/tron/approve.ts
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-08-22T12:58:26.590Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/Layout/Header/ActionCenter/components/GenericTransactionActionCard.tsx:108-111
Timestamp: 2025-08-22T12:58:26.590Z
Learning: In the RFOX GenericTransactionDisplayType flow in src/components/Layout/Header/ActionCenter/components/GenericTransactionActionCard.tsx, the txHash is always guaranteed to be present according to NeOMakinG, so defensive null checks for txLink are not needed in this context.

Applied to files:

  • src/lib/utils/tron/approve.ts
📚 Learning: 2025-09-12T11:56:19.437Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils/tenderly/index.ts:0-0
Timestamp: 2025-09-12T11:56:19.437Z
Learning: gomesalexandre rejected verbose try/catch error handling for address validation in Tenderly integration (PR #10461), calling the approach "ugly" but still implemented safety measures in commit ad7e424b89, preferring cleaner safety implementations over defensive programming patterns.

Applied to files:

  • src/lib/utils/tron/approve.ts
📚 Learning: 2025-11-19T16:59:50.569Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11012
File: src/context/WalletProvider/Vultisig/components/Connect.tsx:24-59
Timestamp: 2025-11-19T16:59:50.569Z
Learning: In src/context/WalletProvider/*/components/Connect.tsx files across the ShapeShift web codebase, the established pattern for handling null/undefined adapter from getAdapter() is to simply check `if (adapter) { ... }` without an else clause. All wallet Connect components (Coinbase, Keplr, Phantom, Ledger, MetaMask, WalletConnectV2, KeepKey, Vultisig) follow this pattern—they reset loading state after the if block but do not show error messages when adapter is null. This is an intentional design decision and should be maintained for consistency.

Applied to files:

  • src/lib/utils/tron/approve.ts
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-11-28T13:07:32.395Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11171
File: src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx:295-296
Timestamp: 2025-11-28T13:07:32.395Z
Learning: Tron is not supported on GridPlus, Trezor, or Ledger hardware wallets. Therefore, skipDeviceDerivation optimization (which only applies to these wallet types) is not needed in Tron adapter code paths.

Applied to files:

  • src/lib/utils/tron/approve.ts
📚 Learning: 2025-08-08T11:40:55.734Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10234
File: src/components/MultiHopTrade/components/TradeConfirm/TradeConfirm.tsx:41-41
Timestamp: 2025-08-08T11:40:55.734Z
Learning: In MultiHopTrade confirm flow (src/components/MultiHopTrade/components/TradeConfirm/TradeConfirm.tsx and related hooks), there is only one active trade per flow. Because of this, persistent (module/Redux) dedupe for QuotesReceived in useTrackTradeQuotes is not necessary; the existing ref-based dedupe is acceptable.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-07-29T15:04:28.083Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10139
File: src/components/MultiHopTrade/components/TradeConfirm/components/ExpandableStepperSteps.tsx:109-115
Timestamp: 2025-07-29T15:04:28.083Z
Learning: In src/components/MultiHopTrade/components/TradeConfirm/components/ExpandableStepperSteps.tsx, the component is used under an umbrella that 100% of the time contains the quote, making the type assertion `activeTradeQuote?.steps[currentHopIndex] as TradeQuoteStep` safe. Adding conditional returns before hooks would violate React's Rules of Hooks.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-09-12T11:52:39.280Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP155TransactionConfirmation.tsx:18-21
Timestamp: 2025-09-12T11:52:39.280Z
Learning: In WalletConnect dApps integration, gomesalexandre has implemented intentional routing logic where EIP155TransactionConfirmation is typed for EthSignTransactionCallRequest only, while a separate SendTransactionConfirmation component handles EthSendTransactionCallRequest. The WalletConnectModalManager contains conditional logic to route native send transactions to SendTransactionConfirmation and other transaction types to EIP155TransactionConfirmation, creating a clean separation of concerns between signing and sending flows.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-08-08T11:41:36.971Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10234
File: src/components/MultiHopTrade/hooks/useGetTradeQuotes/hooks/useTrackTradeQuotes.ts:88-109
Timestamp: 2025-08-08T11:41:36.971Z
Learning: In MultiHopTrade Confirm flow (src/components/MultiHopTrade/components/TradeConfirm/TradeConfirm.tsx), the Confirm route does not remount; navigating away goes to the swapper input page. Therefore, persistent deduplication across remounts for quote tracking is unnecessary; a ref-based single-mount dedupe is sufficient.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-08-22T15:07:18.021Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 10326
File: src/hooks/useActionCenterSubscribers/useThorchainLpActionSubscriber.tsx:37-41
Timestamp: 2025-08-22T15:07:18.021Z
Learning: In src/hooks/useActionCenterSubscribers/useThorchainLpActionSubscriber.tsx, kaladinlight prefers not to await the upsertBasePortfolio call in the Base chain handling block, indicating intentional fire-and-forget behavior for Base portfolio upserts in the THORChain LP completion flow.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.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 : Implement filterBuyAssetsBySellAssetId method to filter assets by supported chain IDs in the buy property

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-09-04T17:29:59.479Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10380
File: src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx:28-33
Timestamp: 2025-09-04T17:29:59.479Z
Learning: In shapeshift/web, the useGetPopularAssetsQuery function in src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx intentionally uses primaryAssets[assetId] instead of falling back to assets[assetId]. The design distributes primary assets across chains by iterating through their related assets and adding the primary asset to each related asset's chain. This ensures primary assets appear in all chains where they have related assets, supporting the grouped asset system.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-08-22T14:59:04.889Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 10326
File: src/hooks/useActionCenterSubscribers/useGenericTransactionSubscriber.tsx:105-111
Timestamp: 2025-08-22T14:59:04.889Z
Learning: In the ShapeShift web Base chain handling, the await pattern inside forEach in useGenericTransactionSubscriber is intentional to delay the entire action completion flow (not just fetchBasePortfolio) for Base chain transactions. The user kaladinlight wants everything below the Base portfolio refresh - including dispatch, query invalidation, and toast notifications - to also be delayed by ~10 seconds to accommodate Base's degraded node state.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-08-22T13:16:12.721Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/pages/RFOX/hooks/useRfoxRewardDistributionActionSubscriber.tsx:104-105
Timestamp: 2025-08-22T13:16:12.721Z
Learning: In src/pages/RFOX/hooks/useRfoxRewardDistributionActionSubscriber.tsx, the guard `if (!actions[actionId]) return` before upserting completed reward distributions is intentional product behavior. NeOMakinG confirmed that the system should only show completion notifications for reward distributions that were previously seen in a pending state, not for distributions the user missed during the pending phase.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-09-10T15:35:46.223Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10458
File: src/plugins/walletConnectToDapps/components/modals/EIP155SignTypedDataConfirmation.tsx:55-55
Timestamp: 2025-09-10T15:35:46.223Z
Learning: gomesalexandre prefers fail-fast early returns over graceful degradation when critical data is missing in WalletConnect flows (like peer metadata in EIP155SignTypedDataConfirmation.tsx). He favors "safety first, always double-wrap" approach and believes missing peer metadata indicates bigger problems that should be surfaced explicitly rather than masked with partial UI rendering.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-09-08T22:00:48.005Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10418
File: src/plugins/walletConnectToDapps/components/header/WalletConnectToDappsHeaderButton.tsx:0-0
Timestamp: 2025-09-08T22:00:48.005Z
Learning: gomesalexandre dismissed an aria-label accessibility suggestion with "meh" in PR #10418 for WalletConnectToDappsHeaderButton.tsx, consistent with the team's pattern of deferring minor a11y improvements to follow-up PRs rather than expanding feature PR scope.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-08-13T15:52:25.116Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10272
File: src/context/WalletProvider/MobileWallet/mobileMessageHandlers.ts:61-0
Timestamp: 2025-08-13T15:52:25.116Z
Learning: In the ShapeShift web codebase, specifically in src/context/WalletProvider/MobileWallet/mobileMessageHandlers.ts, message variants in the Message union type do not include inline comments documenting their expected return types. The codebase follows a pattern of keeping these type definitions clean without such documentation comments.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-10-01T07:42:40.195Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10596
File: src/components/Layout/Header/NavBar/WalletConnectedMenu.tsx:77-99
Timestamp: 2025-10-01T07:42:40.195Z
Learning: In WalletConnectedMenu.tsx's handleReconnectWallet handler, gomesalexandre prefers throwing an error for unsupported wallet types in the default case rather than gracefully handling with a fallback. His reasoning: "if we have a problem here, we have bigger problems" - only supported wallets (KeepKey, Ledger, MetaMask, Coinbase, Phantom) should reach the reconnect flow when disconnected/locked, so encountering an unsupported type indicates a larger architectural issue that should be surfaced explicitly rather than masked with graceful degradation.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-08-04T16:02:27.360Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10171
File: src/components/MultiHopTrade/components/TradeConfirm/components/ExpandedStepperSteps.tsx:458-458
Timestamp: 2025-08-04T16:02:27.360Z
Learning: In multi-hop swap transactions, last hop sell transactions might not be detected by the swapper (unlike buy transactions which are always known immediately). The conditional stepSource logic for last hop buy transactions (`isLastHopSellTxSeen ? stepSource : undefined`) serves as defensive programming for future multi-hop support with intermediate chains, even though multi-hop functionality is not currently supported in production.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-08-29T07:07:49.332Z
Learnt from: premiumjibles
Repo: shapeshift/web PR: 10386
File: src/components/MultiHopTrade/components/VerifyAddresses/VerifyAddresses.tsx:272-294
Timestamp: 2025-08-29T07:07:49.332Z
Learning: In UTXO sell address verification flow in VerifyAddresses.tsx, the user wants address verification to be marked as "verified/complete" before starting the change address fetch, not after. The verification step and change address fetch should be treated as separate sequential operations in the UI flow.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-08-27T09:47:06.275Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10323
File: src/components/ButtonWalletPredicate/ButtonWalletPredicate.tsx:7-7
Timestamp: 2025-08-27T09:47:06.275Z
Learning: In shapeshift/web project, NeOMakinG consistently prefers to defer UI/UX improvements and refactoring work (like the Drawer.Close hack fix in ButtonWalletPredicate.tsx) to follow-up PRs rather than expanding the scope of feature PRs, even when the improvements would enhance robustness.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-09-17T22:40:30.149Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10569
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/WalletConnectModalSigningFooter.tsx:121-129
Timestamp: 2025-09-17T22:40:30.149Z
Learning: gomesalexandre maintains strict scope discipline even for style/UI PRs in shapeshift/web, declining functionally correct UX improvements (like keeping Cancel button enabled during gas simulation loading) when they fall outside the PR's stated styling objectives, demonstrating his consistent pattern of deferring valid but tangential improvements to separate efforts.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-09-12T13:16:27.004Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP712MessageDisplay.tsx:21-24
Timestamp: 2025-09-12T13:16:27.004Z
Learning: gomesalexandre declined to add error boundaries to WalletConnect modals in PR #10461, stating "no error boundaries in this pr ser", consistent with his preference to keep PR scope focused and defer tangential improvements to separate efforts.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-11-25T21:43:10.838Z
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.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-09-12T12:00:33.924Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/SendTransactionConfirmation.tsx:42-50
Timestamp: 2025-09-12T12:00:33.924Z
Learning: gomesalexandre prefers maintaining consistency with existing code patterns in WalletConnect modals, including side-effects-during-render for error handling (showErrorToast + handleReject), rather than introducing isolated refactors that would make the codebase inconsistent.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-09-12T12:00:33.924Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/SendTransactionConfirmation.tsx:42-50
Timestamp: 2025-09-12T12:00:33.924Z
Learning: gomesalexandre prefers maintaining consistency with existing code patterns across WalletConnect modal components, including side-effects-during-render for error handling (showErrorToast + handleReject calls before return null), rather than introducing isolated refactors that would create inconsistency in the codebase.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-08-08T15:00:49.887Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/AssetSearch/components/AssetList.tsx:2-2
Timestamp: 2025-08-08T15:00:49.887Z
Learning: Project shapeshift/web: NeOMakinG prefers avoiding minor a11y/UI nitpicks (e.g., adding aria-hidden to decorative icons in empty states like src/components/AssetSearch/components/AssetList.tsx) within feature PRs; defer such suggestions to a follow-up instead of blocking the PR.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 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:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.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/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-11-20T12:00:45.005Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11078
File: src/setupVitest.ts:11-15
Timestamp: 2025-11-20T12:00:45.005Z
Learning: In shapeshift/web, src/setupVitest.ts must redirect 'ethers' to 'ethers5' for shapeshiftoss/hdwallet-trezor (and -trezor-connect), same as ledger and shapeshift-multichain. Removing 'trezor' from the regex causes CI/Vitest failures due to ethers v6 vs v5 API differences.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-09-12T10:21:26.693Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP712MessageDisplay.tsx:0-0
Timestamp: 2025-09-12T10:21:26.693Z
Learning: gomesalexandre explained that in WalletConnect V2, the request context chainId comes from params?.chainId following CAIP2 standards, making both the request params chainId and EIP-712 domain chainId equally reliable sources. He considers both approaches trustworthy ("both gucci") for WalletConnect dApps integration.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.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/*/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:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.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/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 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:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
📚 Learning: 2025-08-29T18:09:45.982Z
Learnt from: kaladinlight
Repo: shapeshift/web PR: 10376
File: vite.config.mts:136-137
Timestamp: 2025-08-29T18:09:45.982Z
Learning: In the ShapeShift web repository vite.config.mts, the commonjsOptions.exclude configuration using bare package name strings like ['shapeshiftoss/caip', 'shapeshiftoss/types'] works correctly for excluding specific packages from CommonJS transformation, despite theoretical concerns about module ID matching patterns.

Applied to files:

  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx
🧬 Code graph analysis (2)
src/lib/utils/tron/approve.ts (4)
src/lib/utils/tron/index.ts (1)
  • ApproveTronInputWithWallet (4-4)
src/lib/utils/tron/types.ts (1)
  • ApproveTronInputWithWallet (16-16)
packages/caip/src/assetId/assetId.ts (1)
  • fromAssetId (140-172)
packages/chain-adapters/src/utils/bip44.ts (1)
  • toAddressNList (42-44)
src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx (2)
packages/caip/src/constants.ts (1)
  • tronChainId (80-80)
packages/contracts/src/viemClient.ts (1)
  • assertGetViemClient (124-128)
⏰ 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: Call / Static
🔇 Additional comments (3)
src/components/MultiHopTrade/components/TradeConfirm/hooks/useAllowanceApproval.tsx (2)

1-1: LGTM!

Import of tronChainId is correctly added and used for the TRON chain comparison logic.


117-172: TRON polling implementation looks good.

The polling logic correctly:

  • Tries /wallet/ endpoint first for recent transactions, then falls back to /walletsolidity/ for confirmed ones
  • Handles SUCCESS, REVERT, and OUT_OF_ENERGY contract return statuses appropriately
  • Continues polling on transient errors while rethrowing actual transaction failures
  • Falls back to the existing Viem waitForTransactionReceipt for non-TRON chains

Based on learnings, the optimistic timeout completion approach is acceptable for this integration.

src/lib/utils/tron/approve.ts (1)

9-45: approveTron flow looks solid overall

The end‑to‑end flow (derive token/chain, build TronWeb approve tx, get Bip44 path, sign via tronSignTx, and prepare for broadcast) is cohesive and matches expected TRON approval semantics. I don’t see any blocking correctness issues here.

Copy link
Collaborator

@NeOMakinG NeOMakinG left a comment

Choose a reason for hiding this comment

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

Happy to stamp for the sake of progression:

  • I've been able to swap from USDC to USDT
  • From USDT to USDC
  • From USDC to TRX

I'm running a lot out of energy (obviously because its super expensive)

I also had a failing TX but the real TX was successful, might be fixed by the transaction status check follow up

@NeOMakinG NeOMakinG merged commit 06c2f8a into develop Dec 4, 2025
3 checks passed
@NeOMakinG NeOMakinG deleted the feat_swapper_sun_io branch December 4, 2025 15:42
@coderabbitai coderabbitai bot mentioned this pull request Dec 4, 2025
5 tasks
gomesalexandre added a commit that referenced this pull request Dec 5, 2025
Resolved conflicts from squash-merged PR #11261 (Sun.io integration):
- endpoints.ts: kept improved getTransaction with confirmations check
- getQuoteOrRate.ts: kept improved fee estimation with chainSpecific params
- useApprovalFees.ts: kept improved fee estimation with chainSpecific params

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
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.

3 participants