Skip to content

Conversation

@gomesalexandre
Copy link
Contributor

@gomesalexandre gomesalexandre commented Nov 12, 2025

Description

tl;dr: gives gas estimates for Near Intents rates, regardless of enough balance

Implements state overrides logic for:

  • ERC-20 balance
  • Native EVM assets balance
  • Allowance grants

Note the last one is here and implemented purely for the sake of confirming this works and is currently used in Relay/Portals only, but is going to actually be reverted.

See more on state overrides here:

https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-eth
https://geth.ethereum.org/docs/interacting-with-geth/rpc/objects

Issue (if applicable)

Risk

High Risk PRs Require 2 approvals

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

Low - isolated to Near Intents
High - touches Portals and Relay gas estimates too. High risk is really paranoia here, as there are failure scenarios for all:

  • Near Intents fees get zero'd out if overrides fail (until we find better heuristics to make it work for more tokens and without having to dig into storage slots and maintain, or unless Near Intents implement their own gas secret sauce, that's the only way)
  • Relay fallbacks to Relay's own estimates (i.e the same as in develop currently)
  • Portals fallbacks to Portal's own estimates (i.e the same as in develop currently)

Testing

  • Able to get Near Intents gas estimates for EVM rates, even when getting rates for sell asset amounts higher than balance
  • Able to get Near Intents gas estimates for EVM rates without a wallet connected
  • For ERC-20s, test at least with USDC and USDT on a few Near Intents supported chains (Eth/Arb/Base Gnosis) + another supported Near Intents token (i.e not that many - DAI is a good one to test with)

Engineering

  • ^
  • Note, state overrides have also been added as a PoC for Relay and Portals, though those two are to be reverted. The reason why those were added was so we could confirm this also works with allowance overrides, so should also test with token sells requiring allowance
  • Also note when testing this, do keep network XHRs open - many tokens simply do not work with Near Intents, so worth checking if 1click XHRs fail, in this case, having no rate is obviously expected

Operations

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

Do a smoke test of Relay/Portals rates, ensuring gas estimates are somehow sane with:

  • Not/enough native balance for native sells
  • Not/enough token balance for token sells
  • Not/enough allowance granted for token sells

These should:

  1. be close/r (compared to develop) to final gas estimates
  2. not get zero'd out

Screenshots (if applicable)

  • No wallet:
Screenshot 2025-11-12 at 19 21 53
  • Not enough native asset:
Screenshot 2025-11-12 at 19 20 50
  • Not enough token:
Screenshot 2025-11-12 at 19 20 40

E2E:

https://jam.dev/c/ce41ff43-33fc-4cdf-844f-aa86b805bd10

Summary by CodeRabbit

  • New Features

    • Simulation-backed gas estimation for EVM swaps (Portals, Relay, Near Intents) for more accurate fees and fewer failed quotes.
    • Affiliate fee handling added to rate requests.
  • Documentation

    • Added comprehensive Tenderly/state-overrides research, implementation guide, storage-slot findings, and testing examples.
  • Bug Fixes

    • Chain-disabled condition now surfaces as trading-halted to improve quote error clarity.
  • Chores

    • Tenderly integration scaffolding, config keys, simulation utilities and safe fallbacks.

gomesalexandre and others added 30 commits November 7, 2025 11:13
Integrate NEAR Intents as a new swapper using deposit-to-address pattern (similar to Chainflip).

## What is NEAR Intents?
- Intent-based cross-chain swap protocol supporting 20+ blockchains
- Users specify WHAT they want, Market Makers compete to provide best execution
- Settlement verified on NEAR blockchain using Chain Signatures (no bridges!)
- $1.8B volume, 3.6M swaps processed

## Implementation
- Uses 1Click API (https://1click.chaindefuser.com/) with TypeScript SDK
- Follows ChainflipSwapper deposit-to-address pattern exactly
- Supports EVM (ETH, Base, Arbitrum, Polygon, BSC, Gnosis), UTXO (BTC, DOGE), and Solana chains
- Status polling via checkTradeStatus (existing infrastructure)

## Current Status
- Core swapper implementation complete ✅
- Feature flag: VITE_FEATURE_NEAR_INTENTS_SWAP (disabled in prod, enabled in dev)
- API key: Pending JWT token from NEAR Intents team (form submitted)
- Affiliate fees: Temporarily disabled (requires NEAR address, not EVM)

## TODOs
- Get JWT token from NEAR Intents (https://docs.google.com/forms/d/e/1FAIpQLSdrSrqSkKOMb_a8XhwF0f7N5xZ0Y5CYgyzxiAuoC2g4a2N68g/viewform)
- Create shapeshift.near account for affiliate fees
- Test with real API key once received
- Add UI integration (icon, feature flag wiring)
- Verify Avalanche/Optimism support via /v0/tokens endpoint

## Files Added
- packages/swapper/src/swappers/NearIntentsSwapper/ (complete swapper implementation)
- src/lib/headers/csps/defi/swappers/NearIntents.ts (CSP headers)
- .claude/skills/swapper-integration/NEAR_INTENTS_RESEARCH.md (comprehensive research doc)

## Files Modified
- .env, .env.development (API key config, feature flags)
- src/config.ts, src/vite-env.d.ts (config validation)
- packages/swapper/src/types.ts (SwapperName enum, metadata types)
- packages/swapper/src/constants.ts (swapper registration, default slippage)
- package.json (SDK dependency)

References: #10991

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

Co-Authored-By: Claude <[email protected]>
Add NEAR Intents to UI swapper selection:
- Add NearIntentsSwap to FeatureFlags type
- Wire up feature flag in preferences initialState
- Add to getEnabledSwappers() helper
- Mark as supporting cross-account trades
- Fix nearIntentsSpecific metadata type (use ?: not | undefined)
- Move CSP file to correct location (headers/csps not src/lib/headers/csps)
- Register CSP in headers/csps/index.ts

Now NEAR Intents will appear in swapper selection when feature flag is enabled!

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

Co-Authored-By: Claude <[email protected]>
Add NearIntents case to SwapperIcon switch (empty icon for now).

TODO: Download icon from https://pages.near.org/about/brand/ and add it.

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

Co-Authored-By: Claude <[email protected]>
- Use 'nearIntentsChain' const name (not 'blockchain')
- Remove over-documentation (format/examples are obvious)
- Move isNativeEvmAsset import to correct location

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

Co-Authored-By: Claude <[email protected]>
- Remove unnecessary docstring comments
- Remove local getDefaultSlippageDecimalPercentageForSwapper helper (use import from constants)
- Remove inline comments that state the obvious
- Fix import order (isNativeEvmAsset before types)

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

Co-Authored-By: Claude <[email protected]>
- Fix isNativeEvmAsset import path (../../../utils not ../../../swappers/utils)
- Add missing getDefaultSlippageDecimalPercentageForSwapper import in getTradeRate
- Fix NEAR_INTENTS_NATIVE_MARKER → NEAR_INTENTS_NATIVE_EVM_MARKER

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

Co-Authored-By: Claude <[email protected]>
- Remove DEFAULT_SWAP_TYPE, DEFAULT_DEPOSIT_TYPE, etc. (just use QuoteRequest enums directly)
- Keep only ONE_CLICK_BASE_URL, DEFAULT_SLIPPAGE_BPS, DEFAULT_QUOTE_DEADLINE_MS
- Clearer to see QuoteRequest.swapType.EXACT_INPUT than DEFAULT_SWAP_TYPE

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

Co-Authored-By: Claude <[email protected]>
QuoteRequest needs to be imported as value (not type) to access enums.

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

Co-Authored-By: Claude <[email protected]>
Change export type to export for QuoteRequest so enums can be accessed.

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

Co-Authored-By: Claude <[email protected]>
More concise and matches the pattern (not everything needs 'Id' suffix).

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

Co-Authored-By: Claude <[email protected]>
- assetToNearIntentsAsset (not assetToNearIntentsId)
- getNearIntentsAsset (not getNearIntentsAssetId)
- nearIntentsChain const name (not blockchain)
- Remove all excessive docstrings

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

Co-Authored-By: Claude <[email protected]>
CRITICAL FIX: Asset format was completely wrong.

Correct format (from /v0/tokens API):
- Native: nep141:eth.omft.near
- ERC20: nep141:eth-0x{address}.omft.near

Previous (wrong): eth.0x{address}

Also fixed test mock missing NearIntentsSwap flag.

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

Co-Authored-By: Claude <[email protected]>
Add clear instructions for:
- Test mocks (src/test/mocks/store.ts) - REQUIRED
- getEnabledSwappers parameter destructuring
- CSP file creation and registration (both steps)
- isCrossAccountTradeSupported

Prevents missing these steps in future integrations.

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

Co-Authored-By: Claude <[email protected]>
Downloaded official NEAR Protocol logo from cryptologos.cc and added to SwapperIcon component.

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

Co-Authored-By: Claude <[email protected]>
Previous PNG download was corrupted (HTML). Using official SVG from near/near-landing repo.

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

Co-Authored-By: Claude <[email protected]>
CRITICAL FIX: Follow Chainflip pattern exactly for ERC20 vs native transfers.

For ERC20 tokens:
- data = evm.getErc20Data(to, value, contractAddress)
- to = contractAddress (token contract)
- value = '0' (no ETH sent)

For native tokens:
- data = '0x'
- to = deposit address
- value = sell amount

Also: Use official NEAR icon SVG from ~/Downloads/Near/SVG/icon.svg

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

Co-Authored-By: Claude <[email protected]>
Both getUnsignedEvmTransaction AND getEvmTransactionFees need the same
ERC20 vs native logic (data, to, value handling).

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

Co-Authored-By: Claude <[email protected]>
Black on black doesn't work - use the PNG icon instead.

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

Co-Authored-By: Claude <[email protected]>
Add missing import for isNativeEvmAsset from ../utils/helpers/helpers.

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

Co-Authored-By: Claude <[email protected]>
SwapperIcon.tsx still had SVG import after file was changed to PNG.

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

Co-Authored-By: Claude <[email protected]>
Use icon_rev.png for better visibility on dark UI.

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

Co-Authored-By: Claude <[email protected]>
Status checks were failing because nearIntentsSpecific wasn't being extracted
from TradeQuoteStep into swap.metadata.

Now depositAddress flows through properly for status polling.

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

Co-Authored-By: Claude <[email protected]>
Explain:
- When metadata is needed (deposit-to-address, order-based swappers)
- Three places to add it (types, quote, swap extraction)
- Complete flow from quote → swap → status check
- Code examples for each step

Prevents missing metadata extraction like we did with NEAR Intents.

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

Co-Authored-By: Claude <[email protected]>
Not all swappers need metadata - only those with async status polling
or deposit-to-address patterns.

Direct transaction swappers (Bebop, 0x, Portals) don't need it.

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

Co-Authored-By: Claude <[email protected]>
Add console.log to see what's in swap.metadata when checkTradeStatus is called.

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

Co-Authored-By: Claude <[email protected]>
Log when nearIntentsSpecific is set in quote to verify data flow.

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

Co-Authored-By: Claude <[email protected]>
Check if firstStep.nearIntentsSpecific exists when swap is created.

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

Co-Authored-By: Claude <[email protected]>
Add logging to:
- selectActiveQuote selector (see what's being returned)
- useTradeButtonProps (check quoteOrRate and all step keys)

Will reveal if we're accidentally using a rate instead of quote.

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

Co-Authored-By: Claude <[email protected]>
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

♻️ Duplicate comments (1)
packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx (1)

189-198: Fallback misses feePercentage parameter.

The fallback call to fetchPortalsTradeEstimate at line 194 passes feePercentage: affiliateBpsPercentage, but the function signature doesn't accept this parameter—it only accepts {inputToken, inputAmount, outputToken, slippageTolerancePercentage, swapperConfig}. This means the affiliate fee is silently ignored in the fallback path.

Apply this diff to remove the unsupported parameter:

       const quoteEstimateResponse = await fetchPortalsTradeEstimate({
         inputToken,
         outputToken,
         inputAmount: sellAmountIncludingProtocolFeesCryptoBaseUnit,
         slippageTolerancePercentage: userSlippageTolerancePercentageDecimalOrDefault,
-        feePercentage: affiliateBpsPercentage,
         swapperConfig,
       })
🧹 Nitpick comments (3)
packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx (1)

184-184: Remove debug logs before merge.

Per your comments, these console.log statements should be removed before merging.

Also applies to: 209-209

packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts (1)

111-111: Remove debug logs before merge.

Per your comments, these console.log statements should be removed before merging.

Also applies to: 125-125

packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts (1)

530-530: Remove debug logs before merge.

Per your comments, these console.log statements should be removed before merging (or before reintroducing this code after the planned revert).

Also applies to: 544-544

📜 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 3826086 and b2575b8.

📒 Files selected for processing (4)
  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts (3 hunks)
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx (5 hunks)
  • packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts (5 hunks)
  • packages/swapper/src/utils/tenderly/simulate.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (30)
📓 Common learnings
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: 10461
File: src/plugins/walletConnectToDapps/hooks/useSimulateEvmTransaction.ts:91-95
Timestamp: 2025-09-12T13:43:50.695Z
Learning: gomesalexandre dismissed gas calculation overflow validation in useSimulateEvmTransaction hook as "stale", preferring to trust Tenderly's simulation data without defensive validation checks, consistent with his established pattern of relying on external service quality over defensive programming in WalletConnect flows.
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: 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: 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/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: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP155TransactionConfirmation.tsx:27-31
Timestamp: 2025-09-11T22:53:19.837Z
Learning: gomesalexandre trusts Tenderly's data quality and doesn't want defensive validation for gas values (transaction?.gasLimit ?? transaction?.gas) in WalletConnect flows, preferring to rely on the external service providing valid hex values.
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-09-12T13:43:50.695Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/hooks/useSimulateEvmTransaction.ts:91-95
Timestamp: 2025-09-12T13:43:50.695Z
Learning: gomesalexandre dismissed gas calculation overflow validation in useSimulateEvmTransaction hook as "stale", preferring to trust Tenderly's simulation data without defensive validation checks, consistent with his established pattern of relying on external service quality over defensive programming in WalletConnect flows.

Applied to files:

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

Applied to files:

  • packages/swapper/src/utils/tenderly/simulate.ts
  • packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
📚 Learning: 2025-09-12T13:43:19.770Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils/EIP155RequestHandlerUtil.ts:94-103
Timestamp: 2025-09-12T13:43:19.770Z
Learning: gomesalexandre has implemented a 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.

Applied to files:

  • packages/swapper/src/utils/tenderly/simulate.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/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/utils/tenderly/simulate.ts
  • packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
📚 Learning: 2025-09-11T22:53:19.837Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP155TransactionConfirmation.tsx:27-31
Timestamp: 2025-09-11T22:53:19.837Z
Learning: gomesalexandre trusts Tenderly's data quality and doesn't want defensive validation for gas values (transaction?.gasLimit ?? transaction?.gas) in WalletConnect flows, preferring to rely on the external service providing valid hex values.

Applied to files:

  • packages/swapper/src/utils/tenderly/simulate.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
📚 Learning: 2025-10-15T15:57:39.956Z
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.

Applied to files:

  • packages/swapper/src/utils/tenderly/simulate.ts
  • packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.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/utils/tenderly/simulate.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 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/utils/tenderly/simulate.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 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/utils/tenderly/simulate.ts
📚 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/RelaySwapper/utils/getTrade.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
📚 Learning: 2025-08-07T11:22:16.983Z
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.

Applied to files:

  • packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts
📚 Learning: 2025-09-12T09:58:57.389Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP155TransactionConfirmation.tsx:0-0
Timestamp: 2025-09-12T09:58:57.389Z
Learning: gomesalexandre prefers letting errors throw and propagate up the call stack in form submit handlers rather than adding local try/catch error handling, consistent with his fail-fast approach in WalletConnect transaction confirmation flows.

Applied to files:

  • packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts
📚 Learning: 2025-08-13T17:06:16.397Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10249
File: src/hooks/useActionCenterSubscribers/useThorchainLpWithdrawActionSubscriber.tsx:76-78
Timestamp: 2025-08-13T17:06:16.397Z
Learning: gomesalexandre prefers to keep error handling simple with console.error rather than implementing structured logging, especially when broader error handling patterns in the codebase (like THOR error handling) need systematic improvement rather than piecemeal fixes.

Applied to files:

  • packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts
📚 Learning: 2025-07-24T10:07:54.919Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10074
File: src/features/defi/providers/fox-farming/components/FoxFarmingManager/Withdraw/components/Confirm.tsx:192-194
Timestamp: 2025-07-24T10:07:54.919Z
Learning: For fox farming withdrawals in the ShapeShift web app, the architectural preference is to either not handle errors with old-style toast notifications or handle broadcast on-chain errors holistically through the action center system. On-chain errors are considered rare and not a major concern worth individual toast handling.

Applied to files:

  • packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts
📚 Learning: 2025-09-13T16:45:17.166Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/StructuredMessage/StructuredMessage.tsx:0-0
Timestamp: 2025-09-13T16:45:17.166Z
Learning: gomesalexandre appreciates safety-focused suggestions for UI rendering in WalletConnect components, specifically defensive programming approaches that prevent null/undefined values from displaying as literal "null"/"undefined" strings in the user interface.

Applied to files:

  • packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts
📚 Learning: 2025-09-12T10:35:51.632Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils/tenderly/index.ts:33-45
Timestamp: 2025-09-12T10:35:51.632Z
Learning: gomesalexandre consistently dismisses CodeRabbit suggestions about replacing console.error/console.warn with structured logging in API integration code, preferring simple console logging for debugging Tenderly transaction simulation APIs in WalletConnect flows.

Applied to files:

  • packages/swapper/src/swappers/RelaySwapper/utils/getTrade.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/RelaySwapper/utils/getTrade.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
📚 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:

  • packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts
📚 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:

  • packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts
📚 Learning: 2025-09-12T10:15:10.389Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP712MessageDisplay.tsx:133-137
Timestamp: 2025-09-12T10:15:10.389Z
Learning: gomesalexandre has identified that EIP-712 domain chainId should be preferred over request context chainId for accuracy in WalletConnect dApps structured signing flows. The domain chainId from the parsed message is more specific and accurate than the general request context, especially for asset resolution and network-specific operations.

Applied to files:

  • packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts
📚 Learning: 2025-07-31T03:51:48.479Z
Learnt from: premiumjibles
Repo: shapeshift/web PR: 10154
File: src/state/apis/swapper/helpers/swapperApiHelpers.ts:57-60
Timestamp: 2025-07-31T03:51:48.479Z
Learning: In src/state/apis/swapper/helpers/swapperApiHelpers.ts, the getState parameter in processQuoteResultWithRatios uses `() => unknown` type instead of `() => ReduxState` to avoid type compatibility issues elsewhere in the codebase.

Applied to files:

  • packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
📚 Learning: 2025-11-03T05:46:24.190Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10985
File: packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx:130-141
Timestamp: 2025-11-03T05:46:24.190Z
Learning: In packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx, gomesalexandre prefers "let it crash" approach when Portals returns zero outputAmount or 100% buffer causing division by zero, rather than adding defensive guards to surface zero quotes. He wants to fail fast with exceptions that bubble up to the try/catch wrapper, surfacing upstream data issues rather than masking them with defensive programming.

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-09-12T10:35:09.443Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils.ts:0-0
Timestamp: 2025-09-12T10:35:09.443Z
Learning: gomesalexandre prefers KISS (Keep It Simple, Stupid) principle for WalletConnect dApp transaction UIs, removing custom EIP-1559 fee configuration in favor of simple speed selection (Fast/Average/Slow) and only exposing gasLimit in advanced parameters. They intentionally removed base/priority fee inputs to simplify the user experience.

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
📚 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:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 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/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
📚 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:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
📚 Learning: 2025-11-12T13:01:06.086Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts:25-38
Timestamp: 2025-11-12T13:01:06.086Z
Learning: In the swapper architecture (packages/swapper), input validation for sell amounts (e.g., checking sellAmount > 0) is handled by the application layer before reaching individual swapper implementations. Swapper methods like getTradeRate and getTradeQuote can assume inputs have already been validated upstream, so defensive guards for basic input validation (amount > 0, valid addresses, etc.) are unnecessary at the swapper layer.

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-08-17T21:53:03.806Z
Learnt from: 0xApotheosis
Repo: shapeshift/web PR: 10290
File: scripts/generateAssetData/color-map.json:41-47
Timestamp: 2025-08-17T21:53:03.806Z
Learning: In the ShapeShift web codebase, native assets (using CAIP-19 slip44 namespace like eip155:1/slip44:60, bip122:.../slip44:..., cosmos:.../slip44:...) are manually hardcoded and not generated via the automated asset generation script. Only ERC20/BEP20 tokens go through the asset generation process. The validation scripts should only validate generated assets, not manually added native assets.

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
📚 Learning: 2025-09-08T15:53:09.362Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10442
File: src/components/TradeAssetSearch/components/GroupedAssetList/GroupedAssetList.tsx:34-35
Timestamp: 2025-09-08T15:53:09.362Z
Learning: In DefaultAssetList.tsx, the GroupedAssetList component already receives the activeChainId prop correctly on line ~58, contrary to automated analysis that may flag it as missing.

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
🧬 Code graph analysis (4)
packages/swapper/src/utils/tenderly/simulate.ts (4)
packages/swapper/src/utils/tenderly/types.ts (4)
  • TenderlySimulationRequest (12-24)
  • TenderlySimulationResponse (26-47)
  • TenderlyErrorResponse (49-55)
  • TenderlyStateOverrides (3-10)
packages/swapper/src/swappers/utils/helpers/helpers.ts (1)
  • isNativeEvmAsset (29-51)
packages/utils/src/index.ts (1)
  • contractAddressOrUndefined (47-48)
packages/swapper/src/utils/tenderly/storageSlots.ts (5)
  • getTokenBalanceSlot (79-80)
  • getBalanceStorageSlot (5-9)
  • getMaxBalanceValue (96-99)
  • getTokenAllowanceSlot (82-93)
  • getAllowanceStorageSlot (12-23)
packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts (4)
packages/swapper/src/utils.ts (1)
  • makeSwapErrorRight (28-44)
packages/chain-adapters/src/evm/EvmBaseAdapter.ts (1)
  • isEvmChainId (83-87)
packages/swapper/src/swappers/RelaySwapper/utils/types.ts (1)
  • isRelayQuoteEvmItemData (148-152)
packages/swapper/src/utils/tenderly/simulate.ts (1)
  • simulateWithStateOverrides (42-112)
packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx (3)
packages/swapper/src/swappers/PortalsSwapper/utils/fetchPortalsTradeOrder.ts (2)
  • fetchPortalsTradeOrder (95-142)
  • fetchPortalsTradeEstimate (144-172)
packages/swapper/src/swappers/utils/helpers/helpers.ts (1)
  • getTreasuryAddressFromChainId (66-74)
packages/swapper/src/utils/tenderly/simulate.ts (1)
  • simulateWithStateOverrides (42-112)
packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts (2)
packages/swapper/src/utils/tenderly/simulate.ts (1)
  • simulateWithStateOverrides (42-112)
packages/swapper/src/swappers/utils/helpers/helpers.ts (1)
  • isNativeEvmAsset (29-51)
⏰ 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/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx (1)

110-117: LGTM!

The affiliate fee calculation correctly converts basis points to percentage for Portals API, and the RATE_DUMMY_ADDRESS approach (using a well-known address for rate quotes without wallet) is well-documented and aligns with industry practice.

packages/swapper/src/utils/tenderly/simulate.ts (2)

42-112: LGTM!

The simulateWithStateOverrides implementation correctly handles address validation, state override construction, Tenderly API communication, and error cases. The gasLimit = gasUsed assignment is appropriate as it represents the actual gas consumed by the simulation.


114-160: LGTM!

The buildStateOverrides implementation correctly handles both native and ERC20 asset cases. The 1B ETH native balance override guarantees sufficient gas on all chains, and the token storage overrides (balance + allowance) use the correct slot calculation helpers to account for different token implementations.

packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts (2)

91-109: LGTM!

The Tenderly simulation correctly handles both ERC20 and native asset cases, with appropriate address fallbacks and a graceful '0' fee return on simulation failure.


117-123: EIP-1559 detection correctly implemented.

The dynamic detection of EIP-1559 support by checking for maxFeePerGas in the average gas data resolves the previous critical issue. This ensures correct fee calculations across both EIP-1559 and legacy chains.

packages/swapper/src/swappers/RelaySwapper/utils/getTrade.ts (2)

228-234: LGTM!

The fallback for unmapped Relay error codes prevents unhandled errors from reaching the view layer. This defensive approach ensures better error surfacing, addressing the issue mentioned in #11114.


506-556: Tenderly simulation implementation is correct.

The EVM-specific Tenderly simulation path correctly handles gas estimation with state overrides, includes proper fallbacks (silent catch + Relay's gas amount), and dynamically detects EIP-1559 support. The implementation aligns with the patterns used in NearIntents and Portals swappers.

Note: Per your comment at line 1, this will be reverted before merge for isolated testing, but the implementation is sound for future reintroduction.

gomesalexandre and others added 3 commits November 17, 2025 18:46
- Add ARB Arbitrum to KNOWN_BALANCE_SLOTS (slot 51)
- Allowance slot 52 auto-inferred from balance slot
- Uses StandardArbERC20 pattern like USDT Arbitrum
- Enables accurate gas estimates for ARB swaps

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

Co-Authored-By: Claude <[email protected]>
- Slot 51/52 is a pattern shared across different L2 implementations
- Not all are StandardArbERC20 (Arbitrum-specific)
- Avalanche uses TransparentProxy, Optimism uses LayerZero OFT
- More accurate labeling of each token's actual implementation

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

Co-Authored-By: Claude <[email protected]>
- Add SWEAT Arbitrum with slot 5/6 pattern
- Wormhole-bridged tokens use different storage layout than StandardArbERC20
- Confirms not all Arbitrum tokens follow slot 51/52 pattern
- Auto-infer allowance slot 6 from balance slot 5

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

Co-Authored-By: Claude <[email protected]>
@gomesalexandre
Copy link
Contributor Author

@premiumjibles bigly rework in 188faf8, see retest below.

Portals and Relay override diff still present to validate all override slots are correct. Feeling fairly confident about it after all the runtime tests, so now closing these two issues #11114 + #11112, but moved to high risk, as the surface area will now be much larger than just Near Intents.

tl;dr of where we're at:

  • ⚠️ This is not changing the params we use at broadcast time in any way - just making us closer to our final estimations, however off they may be from akschual on-chain
  • Gas estimates with approval needed (for Relay, Portals) should be much closer to actual at final quote time (useEvmFees() i.e actual estimates against node), not orders of magnitude off. Note that obviously, for more expensive chains like mainnet, the "discrepancies" may seem high, but they're not introduced by this PR and are a feature, not a bug, i.e if you wait at final quote time while fees refetch in prod, you'll notice the same fees update.
  • Regardless of not/enough gas/balance, the common denominator for testing all scenarios is fees looking somehow sane at rate time for those 3, vs. final quote useEvmFees() time (in other words, Tenderly estimate with overrides being on the same order of magnitude as actual estimate when all conditions are met - will obviously never be the same because of different gas price between blocks)

Not enough allowance (tested with Relay)

USDC

  • Gnosis - unable to test, no routes currently
  • Arb
  • Mainnet
  • BSC
  • Polygon - note this one is a bit weird, as POL fees are so smol you can't see a diff, but it's working! I left a console.log in to validate this, to be removed before merging.
  • Base
  • Optimism
  • Avalanche

USDT

Not enough balance

Misc

  • Random ERC-20 tokens with not enough allowance

https://jam.dev/s/d03029f6-c63c-434c-b729-27da9fb5a642

  • More Near Intents supported ERC-20s (ARB.ARB, SWEAT.ARB, WBTC.ETH) with not enough balance/no allowance granted

https://jam.dev/c/ec4b3d51-f6ef-4fef-8bd6-9cefbea392c0

- Fix list indentation for USDT slots breakdown
- Convert Phase sections to proper heading format (####)
- Addresses CodeRabbit markdown formatting feedback

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

Co-Authored-By: Claude <[email protected]>
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 (1)
packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx (1)

110-198: Excellent Tenderly integration with appropriate fallback.

The implementation correctly:

  • Calculates affiliate fee percentage for Portals API
  • Uses RATE_DUMMY_ADDRESS for simulation without connected wallet
  • Switches to fetchPortalsTradeOrder to obtain transaction data for Tenderly simulation
  • Validates tx data presence before proceeding
  • Invokes simulateWithStateOverrides with proper parameters (chainId, from, to, data, value, sellAsset, spenderAddress)
  • Falls back to fetchPortalsTradeEstimate when simulation fails (graceful degradation)
  • The fallback correctly omits feePercentage (which fetchPortalsTradeEstimate doesn't accept)

The console.log statements (lines 184, 208) are consistent with your debugging approach but could optionally be removed before production.

📜 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 b2575b8 and b6d7698.

📒 Files selected for processing (3)
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx (5 hunks)
  • packages/swapper/src/utils/tenderly/STORAGE_SLOTS_FINDINGS.md (1 hunks)
  • packages/swapper/src/utils/tenderly/storageSlots.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/swapper/src/utils/tenderly/STORAGE_SLOTS_FINDINGS.md
🧰 Additional context used
🧠 Learnings (18)
📓 Common learnings
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: 10461
File: src/plugins/walletConnectToDapps/hooks/useSimulateEvmTransaction.ts:91-95
Timestamp: 2025-09-12T13:43:50.695Z
Learning: gomesalexandre dismissed gas calculation overflow validation in useSimulateEvmTransaction hook as "stale", preferring to trust Tenderly's simulation data without defensive validation checks, consistent with his established pattern of relying on external service quality over defensive programming in WalletConnect flows.
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: 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: 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: 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: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP155TransactionConfirmation.tsx:27-31
Timestamp: 2025-09-11T22:53:19.837Z
Learning: gomesalexandre trusts Tenderly's data quality and doesn't want defensive validation for gas values (transaction?.gasLimit ?? transaction?.gas) in WalletConnect flows, preferring to rely on the external service providing valid hex values.
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-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/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/utils/tenderly/storageSlots.ts
📚 Learning: 2025-11-03T05:46:24.190Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10985
File: packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx:130-141
Timestamp: 2025-11-03T05:46:24.190Z
Learning: In packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx, gomesalexandre prefers "let it crash" approach when Portals returns zero outputAmount or 100% buffer causing division by zero, rather than adding defensive guards to surface zero quotes. He wants to fail fast with exceptions that bubble up to the try/catch wrapper, surfacing upstream data issues rather than masking them with defensive programming.

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.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/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/utils/tenderly/storageSlots.ts
📚 Learning: 2025-10-15T15:57:39.956Z
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.

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/utils/tenderly/storageSlots.ts
📚 Learning: 2025-09-12T13:43:50.695Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/hooks/useSimulateEvmTransaction.ts:91-95
Timestamp: 2025-09-12T13:43:50.695Z
Learning: gomesalexandre dismissed gas calculation overflow validation in useSimulateEvmTransaction hook as "stale", preferring to trust Tenderly's simulation data without defensive validation checks, consistent with his established pattern of relying on external service quality over defensive programming in WalletConnect flows.

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/utils/tenderly/storageSlots.ts
📚 Learning: 2025-09-11T22:53:19.837Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP155TransactionConfirmation.tsx:27-31
Timestamp: 2025-09-11T22:53:19.837Z
Learning: gomesalexandre trusts Tenderly's data quality and doesn't want defensive validation for gas values (transaction?.gasLimit ?? transaction?.gas) in WalletConnect flows, preferring to rely on the external service providing valid hex values.

Applied to files:

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

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/utils/tenderly/storageSlots.ts
📚 Learning: 2025-09-12T13:43:19.770Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils/EIP155RequestHandlerUtil.ts:94-103
Timestamp: 2025-09-12T13:43:19.770Z
Learning: gomesalexandre has implemented a 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.

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
  • packages/swapper/src/utils/tenderly/storageSlots.ts
📚 Learning: 2025-09-12T10:35:09.443Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils.ts:0-0
Timestamp: 2025-09-12T10:35:09.443Z
Learning: gomesalexandre prefers KISS (Keep It Simple, Stupid) principle for WalletConnect dApp transaction UIs, removing custom EIP-1559 fee configuration in favor of simple speed selection (Fast/Average/Slow) and only exposing gasLimit in advanced parameters. They intentionally removed base/priority fee inputs to simplify the user experience.

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.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:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-07-31T03:51:48.479Z
Learnt from: premiumjibles
Repo: shapeshift/web PR: 10154
File: src/state/apis/swapper/helpers/swapperApiHelpers.ts:57-60
Timestamp: 2025-07-31T03:51:48.479Z
Learning: In src/state/apis/swapper/helpers/swapperApiHelpers.ts, the getState parameter in processQuoteResultWithRatios uses `() => unknown` type instead of `() => ReduxState` to avoid type compatibility issues elsewhere in the codebase.

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.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:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 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/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.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:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 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/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 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/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-11-12T13:01:06.086Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts:25-38
Timestamp: 2025-11-12T13:01:06.086Z
Learning: In the swapper architecture (packages/swapper), input validation for sell amounts (e.g., checking sellAmount > 0) is handled by the application layer before reaching individual swapper implementations. Swapper methods like getTradeRate and getTradeQuote can assume inputs have already been validated upstream, so defensive guards for basic input validation (amount > 0, valid addresses, etc.) are unnecessary at the swapper layer.

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
🧬 Code graph analysis (1)
packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx (3)
packages/swapper/src/swappers/PortalsSwapper/utils/fetchPortalsTradeOrder.ts (2)
  • fetchPortalsTradeOrder (95-142)
  • fetchPortalsTradeEstimate (144-172)
packages/swapper/src/swappers/utils/helpers/helpers.ts (1)
  • getTreasuryAddressFromChainId (66-74)
packages/swapper/src/utils/tenderly/simulate.ts (1)
  • simulateWithStateOverrides (42-112)
⏰ 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 (4)
packages/swapper/src/utils/tenderly/storageSlots.ts (1)

1-106: LGTM! Sound implementation of ERC20 storage slot derivations.

The storage slot computation logic correctly implements:

  • Standard ERC20 balance/allowance slot patterns with keccak256-based derivations
  • Special handling for known token variants (USDT/USDC across chains, L2 implementations)
  • Pattern inference for StandardArbERC20 (51→52), Wormhole (5→6), and USDC (9→10)
  • USDC blacklist bit preservation (maxUint256 >> 1 for slot 9)
  • Graceful fallback to conventional slots (0 for balance, 1 for allowance)

The acknowledged limitations (Vyper-compiled tokens, exotic storage layouts) are acceptable given the fallback behavior to upstream estimates when overrides fail.

packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx (3)

137-161: LGTM! Correct amount calculations and buffer derivation.

The implementation properly:

  • Uses context.outputAmount for buyAmountAfterFeesCryptoBaseUnit (not estimate fields)
  • Derives actualBufferDecimal from the difference between outputAmount and minOutputAmount
  • Calculates buyAmountBeforeSlippageCryptoBaseUnit using minOutputAmount / (1 - buffer) approach

This matches the established pattern for rate files to use minOutputAmount-based calculations for conservative estimates.


42-42: LGTM! Proper EIP-1559 support integration.

The supportsEIP1559 parameter is correctly added to the input type and properly used in the network fee calculation with appropriate Boolean casting.

Also applies to: 204-206


177-179: Tenderly configuration is properly set up and verified.

The three Tenderly configuration keys (VITE_TENDERLY_API_KEY, VITE_TENDERLY_ACCOUNT_SLUG, VITE_TENDERLY_PROJECT_SLUG) are:

  • Declared as required environment variables in src/config.ts (lines 200-202)
  • Properly typed in packages/swapper/src/types.ts as part of SwapperConfig
  • Correctly passed to Tenderly simulation in getPortalsTradeRate.tsx (lines 177-179)
  • Protected by error handling that falls back to the estimate endpoint if simulation fails (lines 183-189)

The same pattern is used consistently across all swappers (RelaySwapper, NearIntentsSwapper). No configuration issues found.

Copy link
Collaborator

@premiumjibles premiumjibles left a comment

Choose a reason for hiding this comment

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

@gomesalexandre looks good now 👌 . Tested USDT and can see estimates now

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.

https://jam.dev/c/766064f1-12c3-4657-8c73-aff12963f56b

Couldn't test so much as the overall internet is under fire but looks sane for gas estimations on relay and portals!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx (2)

115-123: Dummy sender for rate-time quotes is fine; could be hoisted to module scope.

Using a well-known address with state overrides for rate-only quotes is reasonable and clearly commented; if this lives long-term, you might optionally move RATE_DUMMY_ADDRESS to module scope to avoid redeclaration and make reuse easier.


165-197: Tenderly simulation + estimate fallback flow is solid; consider skipping Tenderly when config is missing.

Using simulateWithStateOverrides first and falling back to fetchPortalsTradeEstimate on failure gives you override-aware gas limits without regressing to “no rate” on Tenderly errors, and only pulling gasLimit from the estimate keeps amounts sourced from the full quote. One small improvement: if any of VITE_TENDERLY_API_KEY, VITE_TENDERLY_ACCOUNT_SLUG, or VITE_TENDERLY_PROJECT_SLUG are unset, you could short‑circuit directly to the estimate fallback to avoid an extra failing Tenderly call on every rate.

📜 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 b6d7698 and 6d94cf8.

📒 Files selected for processing (2)
  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts (3 hunks)
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx (5 hunks)
🧰 Additional context used
🧠 Learnings (28)
📓 Common learnings
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: 10461
File: src/plugins/walletConnectToDapps/hooks/useSimulateEvmTransaction.ts:91-95
Timestamp: 2025-09-12T13:43:50.695Z
Learning: gomesalexandre dismissed gas calculation overflow validation in useSimulateEvmTransaction hook as "stale", preferring to trust Tenderly's simulation data without defensive validation checks, consistent with his established pattern of relying on external service quality over defensive programming in WalletConnect flows.
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: 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: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP155TransactionConfirmation.tsx:27-31
Timestamp: 2025-09-11T22:53:19.837Z
Learning: gomesalexandre trusts Tenderly's data quality and doesn't want defensive validation for gas values (transaction?.gasLimit ?? transaction?.gas) in WalletConnect flows, preferring to rely on the external service providing valid hex values.
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: 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: 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-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/getTradeRate.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 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/getTradeRate.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-09-12T13:43:50.695Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/hooks/useSimulateEvmTransaction.ts:91-95
Timestamp: 2025-09-12T13:43:50.695Z
Learning: gomesalexandre dismissed gas calculation overflow validation in useSimulateEvmTransaction hook as "stale", preferring to trust Tenderly's simulation data without defensive validation checks, consistent with his established pattern of relying on external service quality over defensive programming in WalletConnect flows.

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-10-15T15:57:39.956Z
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.

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-09-12T10:35:09.443Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils.ts:0-0
Timestamp: 2025-09-12T10:35:09.443Z
Learning: gomesalexandre prefers KISS (Keep It Simple, Stupid) principle for WalletConnect dApp transaction UIs, removing custom EIP-1559 fee configuration in favor of simple speed selection (Fast/Average/Slow) and only exposing gasLimit in advanced parameters. They intentionally removed base/priority fee inputs to simplify the user experience.

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.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:

  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.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:

  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-08-17T21:53:03.806Z
Learnt from: 0xApotheosis
Repo: shapeshift/web PR: 10290
File: scripts/generateAssetData/color-map.json:41-47
Timestamp: 2025-08-17T21:53:03.806Z
Learning: In the ShapeShift web codebase, native assets (using CAIP-19 slip44 namespace like eip155:1/slip44:60, bip122:.../slip44:..., cosmos:.../slip44:...) are manually hardcoded and not generated via the automated asset generation script. Only ERC20/BEP20 tokens go through the asset generation process. The validation scripts should only validate generated assets, not manually added native assets.

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
📚 Learning: 2025-09-08T15:53:09.362Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10442
File: src/components/TradeAssetSearch/components/GroupedAssetList/GroupedAssetList.tsx:34-35
Timestamp: 2025-09-08T15:53:09.362Z
Learning: In DefaultAssetList.tsx, the GroupedAssetList component already receives the activeChainId prop correctly on line ~58, contrary to automated analysis that may flag it as missing.

Applied to files:

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

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-09-11T22:53:19.837Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/components/modals/EIP155TransactionConfirmation.tsx:27-31
Timestamp: 2025-09-11T22:53:19.837Z
Learning: gomesalexandre trusts Tenderly's data quality and doesn't want defensive validation for gas values (transaction?.gasLimit ?? transaction?.gas) in WalletConnect flows, preferring to rely on the external service providing valid hex values.

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-09-12T13:43:19.770Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10461
File: src/plugins/walletConnectToDapps/utils/EIP155RequestHandlerUtil.ts:94-103
Timestamp: 2025-09-12T13:43:19.770Z
Learning: gomesalexandre has implemented a 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.

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-11-18T09:52:51.344Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10334
File: src/lib/user/api.ts:46-105
Timestamp: 2025-11-18T09:52:51.344Z
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/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
📚 Learning: 2025-07-31T03:51:48.479Z
Learnt from: premiumjibles
Repo: shapeshift/web PR: 10154
File: src/state/apis/swapper/helpers/swapperApiHelpers.ts:57-60
Timestamp: 2025-07-31T03:51:48.479Z
Learning: In src/state/apis/swapper/helpers/swapperApiHelpers.ts, the getState parameter in processQuoteResultWithRatios uses `() => unknown` type instead of `() => ReduxState` to avoid type compatibility issues elsewhere in the codebase.

Applied to files:

  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-11-03T05:46:24.190Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 10985
File: packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx:130-141
Timestamp: 2025-11-03T05:46:24.190Z
Learning: In packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx, gomesalexandre prefers "let it crash" approach when Portals returns zero outputAmount or 100% buffer causing division by zero, rather than adding defensive guards to surface zero quotes. He wants to fail fast with exceptions that bubble up to the try/catch wrapper, surfacing upstream data issues rather than masking them with defensive programming.

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.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:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.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:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.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:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-08-08T15:00:22.321Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10231
File: src/components/MultiHopTrade/components/TradeInput/components/HighlightedTokens.tsx:14-14
Timestamp: 2025-08-08T15:00:22.321Z
Learning: In shapeshift/web reviews for NeOMakinG, avoid nitpicks to change deep-relative imports to '@/…' alias paths within feature/non-refactor PRs; defer such style-only changes to a dedicated follow-up refactor unless they fix an issue.

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.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:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.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:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-07-29T10:22:27.037Z
Learnt from: NeOMakinG
Repo: shapeshift/web PR: 10136
File: src/lib/asset-service/service/encodedRelatedAssetIndex.json:1-1
Timestamp: 2025-07-29T10:22:27.037Z
Learning: PRs with titles starting with "feat: regenerate asset data" are routine daily asset updates that don't need detailed code analysis. Users prefer to skip automated reviews for these maintenance PRs using coderabbitai ignore.

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-08-25T23:32:13.876Z
Learnt from: premiumjibles
Repo: shapeshift/web PR: 10361
File: src/pages/Markets/components/CardWithSparkline.tsx:83-92
Timestamp: 2025-08-25T23:32:13.876Z
Learning: In shapeshift/web PR #10361, premiumjibles considered the nested button accessibility issue (ChartErrorFallback retry Button inside Card rendered as Button in CardWithSparkline.tsx) out of scope for the error boundaries feature PR, consistent with deferring minor a11y improvements to follow-up PRs.

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 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/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 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/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
📚 Learning: 2025-11-12T13:01:06.086Z
Learnt from: gomesalexandre
Repo: shapeshift/web PR: 11016
File: packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts:25-38
Timestamp: 2025-11-12T13:01:06.086Z
Learning: In the swapper architecture (packages/swapper), input validation for sell amounts (e.g., checking sellAmount > 0) is handled by the application layer before reaching individual swapper implementations. Swapper methods like getTradeRate and getTradeQuote can assume inputs have already been validated upstream, so defensive guards for basic input validation (amount > 0, valid addresses, etc.) are unnecessary at the swapper layer.

Applied to files:

  • packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx
🧬 Code graph analysis (2)
packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts (2)
packages/swapper/src/utils/tenderly/simulate.ts (1)
  • simulateWithStateOverrides (42-112)
packages/swapper/src/swappers/utils/helpers/helpers.ts (1)
  • isNativeEvmAsset (29-51)
packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx (3)
packages/swapper/src/swappers/PortalsSwapper/utils/fetchPortalsTradeOrder.ts (2)
  • fetchPortalsTradeOrder (95-142)
  • fetchPortalsTradeEstimate (144-172)
packages/swapper/src/swappers/utils/helpers/helpers.ts (1)
  • getTreasuryAddressFromChainId (66-74)
packages/swapper/src/utils/tenderly/simulate.ts (1)
  • simulateWithStateOverrides (42-112)
⏰ 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 (8)
packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts (4)

7-7: LGTM - Required imports for Tenderly integration.

The new imports support the Tenderly simulation workflow for gas estimation with state overrides.

Also applies to: 19-19


100-114: LGTM - Tenderly simulation integration is correct.

The simulation call properly handles both ERC20 and native asset transfers. Using depositAddress as the fallback for from when no wallet is connected (line 103) is unconventional but appropriate here—since state overrides set balances for the from address, the actual address value is effectively a simulation placeholder.


116-118: LGTM - Intentional fallback behavior.

Returning '0' when simulation fails aligns with the PR's goal to rely on state overrides without falling back to upstream estimates. This is consistent with your earlier comment that failures should not use upstream fallbacks.


120-132: LGTM - Fee calculation correctly implements dynamic EIP-1559 detection.

The fee calculation properly addresses the previous review comment by dynamically determining EIP-1559 support (line 124) instead of hardcoding it. Using average gas fee data aligns with useEvmFees() for consistency across quote-time fee polling.

packages/swapper/src/swappers/PortalsSwapper/getPortalsTradeRate/getPortalsTradeRate.tsx (4)

6-27: Imports align with the new Tenderly/Portals flow.

New utilities (convertBasisPointsToDecimalPercentage, simulateWithStateOverrides, treasury/helper imports, and Portals order/estimate helpers plus Address/Hex) are wired in cleanly and keep this swapper consistent with the existing EVM/Tenderly patterns. No issues here.


42-43: Confirm supportsEIP1559 semantics for network fee calculation.

Threading supportsEIP1559 from GetEvmTradeRateInput into calcNetworkFeeCryptoBaseUnit makes sense; just ensure all call sites populate this flag as “chain supports 1559” (not e.g. “wallet UI supports 1559”) so the fee math stays correct across chains.

Also applies to: 203-205


110-113: Affiliate fee scaling to Portals feePercentage looks correct.

Using convertBasisPointsToDecimalPercentage(affiliateBps).times(100) so that, for example, 55 bps → 0.55 before passing it as feePercentage and pairing it with partner: getTreasuryAddressFromChainId(chainId) matches the expected “percentage (not bps)” API shape and centralizes partner handling. Please double‑check this matches the latest Portals docs for feePercentage units.

Also applies to: 127-129


119-121: Order/context usage and slippage reconstruction preserve prior Portals rate behavior.

Switching to fetchPortalsTradeOrder with validate: false to obtain tx while deriving buyAmountAfterFeesCryptoBaseUnit from context.outputAmount and reconstructing buyAmountBeforeSlippageCryptoBaseUnit from minOutputAmount and the implied buffer keeps the existing “minOut/(1-buffer)” semantics and the intentional rate/quote behavior intact. No issues spotted in this section. Based on learnings.

Also applies to: 133-141, 153-161

@gomesalexandre gomesalexandre enabled auto-merge (squash) November 19, 2025 16:50
@gomesalexandre gomesalexandre merged commit 22f2762 into develop Nov 20, 2025
4 checks passed
@gomesalexandre gomesalexandre deleted the feat_near_intents_state_overrides_poc branch November 20, 2025 00:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

4 participants