Skip to content

Comments

feat(deposit): add iUSD extra source list with ethereum mainnet USDC#178

Open
tansawit wants to merge 10 commits intomainfrom
feat/iusd-usdc-source-options
Open

feat(deposit): add iUSD extra source list with ethereum mainnet USDC#178
tansawit wants to merge 10 commits intomainfrom
feat/iusd-usdc-source-options

Conversation

@tansawit
Copy link
Contributor

@tansawit tansawit commented Feb 24, 2026

Note

Medium Risk
Changes core filtering logic for which external assets/chains are shown during deposit/withdraw and adds override behavior, which could impact available options or ordering if assumptions are wrong.

Overview
Improves deposit/withdraw external asset selection by introducing per-asset external source overrides (initially iUSD using USDC as the source symbol, including an explicit Ethereum mainnet USDC option) and making remote option matching robust for EVM ERC-20 address case-insensitivity.

useExternalAssetOptions now returns additional metadata (supportedExternalChains, appchainSourceSymbols, externalSourceSymbol, localSymbol) and refines filtering (supported-chain gating, balance-aware inclusion for deposits, and configurable chain list sourcing). Chain utilities add isInitiaAppchain to help distinguish Initia appchains from Initia itself. The Vite example also adds one more move/... denom to both openDeposit and openWithdraw demo calls.

Written by Cursor Bugbot for commit f357fca. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • New Features
    • Added support for an additional denomination in deposit and withdrawal flows.
    • Enhanced external-asset discovery and selection with richer filtering, balance-aware gating, and external-source overrides.
    • Improved identification and exclusion of specific appchain types from external chain lists.

@coderabbitai
Copy link

coderabbitai bot commented Feb 24, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a denom to example Deposit/Withdraw components, extends deposit hooks with iUSD and richer external-asset resolution/filtering (new helpers, overrides, and a richer return shape), and adds an isInitiaAppchain helper to bridge chain utilities.

Changes

Cohort / File(s) Summary
Example Components
examples/vite/src/Deposit.tsx, examples/vite/src/Withdraw.tsx
Added the denom move/6c69733a9e722f3660afb524f89fce957801fa7e4408b8ef8fe89db9627b570e to the arrays used for deposit and withdraw flows.
Deposit hooks & external asset logic
packages/interwovenkit-react/src/pages/deposit/hooks.ts
Reworked external-asset resolution: introduced iUSD handling (IUSD_SYMBOL), external-source overrides (EXTERNAL_SOURCE_OVERRIDES), helper utilities (matchesAssetOption, getExternalSourceOverride, getChainDisplayName, isSupportedExternalChain), new internal types (ExternalAssetOptionItem, ExternalAssetOptionsResult, EMPTY_EXTERNAL_ASSET_OPTIONS_RESULT), and changed useExternalAssetOptions to return a richer ExternalAssetOptionsResult. Made TransferModeConfig non-exported.
Bridge chain helpers
packages/interwovenkit-react/src/pages/bridge/data/chains.ts
Added exported isInitiaAppchain(chain, getIsInitiaChain) to detect Initia appchains while excluding chains named initia (case-insensitive).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through branches, quick and keen,

added a denom and taught iUSD to preen,
I checked the chains with a curious nose,
nudged hooks to find where external value grows,
— a rabbit's tiny, happy code-hop scene.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: adding iUSD with Ethereum mainnet USDC as an external source option for deposits.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/iusd-usdc-source-options

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

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Feb 24, 2026

Deploying interwovenkit with  Cloudflare Pages  Cloudflare Pages

Latest commit: f357fca
Status: ✅  Deploy successful!
Preview URL: https://0552cb5b.interwovenkit.pages.dev
Branch Preview URL: https://feat-iusd-usdc-source-option.interwovenkit.pages.dev

View logs

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Feb 24, 2026

Deploying interwovenkit-staging with  Cloudflare Pages  Cloudflare Pages

Latest commit: f357fca
Status: ✅  Deploy successful!
Preview URL: https://f92082fd.interwovenkit-staging.pages.dev
Branch Preview URL: https://feat-iusd-usdc-source-option.interwovenkit-staging.pages.dev

View logs

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Feb 24, 2026

Deploying interwovenkit-testnet with  Cloudflare Pages  Cloudflare Pages

Latest commit: f357fca
Status: ✅  Deploy successful!
Preview URL: https://b735d0ce.interwovenkit-testnet.pages.dev
Branch Preview URL: https://feat-iusd-usdc-source-option.interwovenkit-testnet.pages.dev

View logs

@tansawit tansawit marked this pull request as ready for review February 24, 2026 10:26
@tansawit tansawit changed the title feat: add iUSD extra source list with ethereum mainnet USDC feat(deposit): add iUSD extra source list with ethereum mainnet USDC Feb 24, 2026
Copy link

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

🧹 Nitpick comments (2)
packages/interwovenkit-react/src/pages/deposit/hooks.ts (2)

48-50: isSupportedExternalCosmosChain name doesn't reflect its full scope

The function returns true for any non-cosmos chain (EVM, etc.), not just cosmos chains. A caller reading the name would expect it to only apply to Cosmos chains.

♻️ Suggested rename
-function isSupportedExternalCosmosChain(chain: RouterChainJson): boolean {
-  return chain.chain_type !== "cosmos" || chain.bech32_prefix === "init"
-}
+function isSupportedChainType(chain: RouterChainJson): boolean {
+  return chain.chain_type !== "cosmos" || chain.bech32_prefix === "init"
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/interwovenkit-react/src/pages/deposit/hooks.ts` around lines 48 -
50, The function name is misleading because isSupportedExternalCosmosChain
returns true for non-Cosmos chains; rename the function to a name reflecting its
broader scope (e.g., isSupportedExternalChain) and update all usages, exports,
and any tests to use the new identifier; keep the existing logic (return
chain.chain_type !== "cosmos" || chain.bech32_prefix === "init") unchanged so
behavior remains the same while the name accurately describes that it covers
external/non-Cosmos chains as well as the init-prefix case.

262-266: supportedExternalChains (for "supported-assets" path) may include zero-balance chains in deposit mode

supportedExternalChains is built from supportedAssets (pre-balance-gate), while data (what's actually shown to the user) additionally gates on balance.amount > 0 for deposits (Line 250). In deposit mode, the chain selector could surface chains where no asset would appear in data.

This doesn't affect iUSD since it uses "extra-options", but it's worth aligning the chain list with the displayed asset list for future overrides that use the "supported-assets" source.

♻️ Option: derive chains from data for the "supported-assets" branch
   } else {
-    for (const { chain } of supportedAssets) {
+    for (const { chain } of mode === "deposit" ? data : supportedAssets) {
       if (getIsInitiaChain(chain.chain_id)) continue
       supportedExternalChainMap.set(chain.chain_id, chain)
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/interwovenkit-react/src/pages/deposit/hooks.ts` around lines 262 -
266, The chain list for the "supported-assets" path is built from
supportedAssets (via supportedExternalChainMap) before applying the deposit
balance filter, which can surface zero-balance chains; change the logic so that
in the "supported-assets" branch you derive supportedExternalChainMap (or
supportedExternalChains) from the already-filtered data array (the variable
named data) — iterate data, skip getIsInitiaChain(chain.chain_id), and set
supportedExternalChainMap with chain objects from data so the chain selector
matches the assets actually shown to users in deposit mode.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/interwovenkit-react/src/pages/deposit/hooks.ts`:
- Around line 48-50: The function name is misleading because
isSupportedExternalCosmosChain returns true for non-Cosmos chains; rename the
function to a name reflecting its broader scope (e.g., isSupportedExternalChain)
and update all usages, exports, and any tests to use the new identifier; keep
the existing logic (return chain.chain_type !== "cosmos" || chain.bech32_prefix
=== "init") unchanged so behavior remains the same while the name accurately
describes that it covers external/non-Cosmos chains as well as the init-prefix
case.
- Around line 262-266: The chain list for the "supported-assets" path is built
from supportedAssets (via supportedExternalChainMap) before applying the deposit
balance filter, which can surface zero-balance chains; change the logic so that
in the "supported-assets" branch you derive supportedExternalChainMap (or
supportedExternalChains) from the already-filtered data array (the variable
named data) — iterate data, skip getIsInitiaChain(chain.chain_id), and set
supportedExternalChainMap with chain objects from data so the chain selector
matches the assets actually shown to users in deposit mode.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 834d9f4 and f1d1dfd.

📒 Files selected for processing (2)
  • packages/interwovenkit-react/src/pages/bridge/data/chains.ts
  • packages/interwovenkit-react/src/pages/deposit/hooks.ts

Copy link

@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: 1

🧹 Nitpick comments (1)
packages/interwovenkit-react/src/pages/deposit/hooks.ts (1)

48-50: isSupportedExternalCosmosChain is a misleading name — consider renaming.

The function returns true for all non-cosmos chains (e.g., EVM chains) because chain.chain_type !== "cosmos" is unconditionally true for them. The name implies it specifically adjudicates cosmos chains, but it actually acts as a general "is this chain usable as an external source?" predicate. A name like isExternalChainSupported or isSupportedExternalChain would better reflect the full scope.

♻️ Proposed rename
-function isSupportedExternalCosmosChain(chain: RouterChainJson): boolean {
-  return chain.chain_type !== "cosmos" || chain.bech32_prefix === "init"
+function isExternalChainSupported(chain: RouterChainJson): boolean {
+  return chain.chain_type !== "cosmos" || chain.bech32_prefix === "init"
 }

(Update the three call sites accordingly.)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/interwovenkit-react/src/pages/deposit/hooks.ts` around lines 48 -
50, The function name is misleading: isSupportedExternalCosmosChain(chain)
actually returns true for any non-cosmos chain and therefore should be renamed
to reflect its broader purpose (e.g., isExternalChainSupported or
isSupportedExternalChain). Rename the function symbol
(isSupportedExternalCosmosChain) to the chosen name across the file and update
all three call sites that invoke it so signatures and imports (if any) match;
ensure the logic (chain.chain_type !== "cosmos" || chain.bech32_prefix ===
"init") remains unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/interwovenkit-react/src/pages/deposit/hooks.ts`:
- Around line 253-267: The current logic allows supportedAssets to include
assets with isLocalSourceSymbol across all chains even when
externalChainListSource === "extra-options", causing a mismatch with
supportedExternalChainMap (which is limited to extraExternalOptions); update the
supportedAssets filtering so that when externalChainListSource ===
"extra-options" you exclude isLocalSourceSymbol and only include assets whose
chain is in extraExternalOptions or whose symbol is in extraInitiaSourceSymbols
(keep existing getIsInitiaChain/getIsInitiaChain checks), ensuring
supportedAssets and supportedExternalChainMap both respect the override; adjust
references in the code where supportedAssets is built and any related conditions
checking isLocalSourceSymbol, extraExternalOptions, and extraInitiaSourceSymbols
so the override branch is honored consistently.

---

Nitpick comments:
In `@packages/interwovenkit-react/src/pages/deposit/hooks.ts`:
- Around line 48-50: The function name is misleading:
isSupportedExternalCosmosChain(chain) actually returns true for any non-cosmos
chain and therefore should be renamed to reflect its broader purpose (e.g.,
isExternalChainSupported or isSupportedExternalChain). Rename the function
symbol (isSupportedExternalCosmosChain) to the chosen name across the file and
update all three call sites that invoke it so signatures and imports (if any)
match; ensure the logic (chain.chain_type !== "cosmos" || chain.bech32_prefix
=== "init") remains unchanged.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between f1d1dfd and 4f9d362.

📒 Files selected for processing (1)
  • packages/interwovenkit-react/src/pages/deposit/hooks.ts

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Bugbot Autofix is ON. A Cloud Agent has been kicked off to fix the reported issues.

@cursor
Copy link

cursor bot commented Feb 24, 2026

Bugbot Autofix prepared fixes for 3 of the 3 bugs found in the latest run.

  • ✅ Fixed: USDC address comparison may never match
    • Added case-insensitive comparison for ERC-20 addresses to handle different normalizations (checksummed vs lowercase) from Skip API.
  • ✅ Fixed: isInitiaAppchain misclassifies by chain name
    • Changed chain name comparison to case-insensitive by using toLowerCase() to handle registry naming variations.
  • ✅ Fixed: toSorted may break in older runtimes
    • Replaced toSorted() with sort() which mutates the array in-place, avoiding ES2023-only method for broader runtime compatibility.

Create PR

Or push these changes by commenting:

@cursor push f0b362a2d4
Preview (f0b362a2d4)
diff --git a/packages/interwovenkit-react/src/pages/bridge/data/chains.ts b/packages/interwovenkit-react/src/pages/bridge/data/chains.ts
--- a/packages/interwovenkit-react/src/pages/bridge/data/chains.ts
+++ b/packages/interwovenkit-react/src/pages/bridge/data/chains.ts
@@ -26,7 +26,7 @@
   chain: Pick<ChainJson, "chain_id" | "chain_name">,
   getIsInitiaChain: (chainId: string) => boolean,
 ): boolean {
-  return getIsInitiaChain(chain.chain_id) && chain.chain_name !== "initia"
+  return getIsInitiaChain(chain.chain_id) && chain.chain_name.toLowerCase() !== "initia"
 }
 
 export function useFindChainType() {

diff --git a/packages/interwovenkit-react/src/pages/deposit/hooks.ts b/packages/interwovenkit-react/src/pages/deposit/hooks.ts
--- a/packages/interwovenkit-react/src/pages/deposit/hooks.ts
+++ b/packages/interwovenkit-react/src/pages/deposit/hooks.ts
@@ -34,7 +34,13 @@
 }
 
 function matchesAssetOption(option: AssetOption, chainId: string, denom: string): boolean {
-  return option.chainId === chainId && option.denom === denom
+  if (option.chainId !== chainId) return false
+  // ERC-20 addresses are case-insensitive; normalize for comparison
+  const isEvm = option.chainId === "1" || option.chainId.startsWith("eip155:")
+  if (isEvm && option.denom.startsWith("0x") && denom.startsWith("0x")) {
+    return option.denom.toLowerCase() === denom.toLowerCase()
+  }
+  return option.denom === denom
 }
 
 function getExternalSourceOverride(localSymbol: string): ExternalSourceOverride | undefined {
@@ -269,7 +275,7 @@
       supportedExternalChainMap.set(chain.chain_id, chain)
     }
   }
-  const supportedExternalChains = Array.from(supportedExternalChainMap.values()).toSorted((a, b) =>
+  const supportedExternalChains = Array.from(supportedExternalChainMap.values()).sort((a, b) =>
     getChainDisplayName(a).localeCompare(getChainDisplayName(b)),
   )
   const appchainSourceSymbols = [

@tansawit
Copy link
Contributor Author

@cursor push f0b362a

…tibility issues

- Make ERC-20 address comparison case-insensitive in matchesAssetOption to handle different normalizations from Skip API
- Make isInitiaAppchain chain name comparison case-insensitive to handle registry naming variations
- Replace toSorted() with sort() for broader runtime compatibility (ES2023 -> older runtimes)

Applied via @cursor push command
Copy link

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

🧹 Nitpick comments (1)
packages/interwovenkit-react/src/pages/deposit/hooks.ts (1)

36-44: The premise of this review is incorrect—Skip API does not return EVM chain IDs.

Skip's /v2/info/chains endpoint returns only Cosmos-type chains. The isEvm guard correctly recognizes the two formats used in practice: "1" (Ethereum, already in EXTERNAL_SOURCE_OVERRIDES) and "eip155:*" (EIP-155 formatted chains). Since the first check in matchesAssetOption filters by chainId equality, unrecognized EVM chains won't reach the case-insensitivity logic anyway.

However, the suggested refactor—always comparing as lowercase when both denoms start with "0x"—is a reasonable defensive improvement if AssetOptions might contain unknown EVM chains in the future. This would make ERC-20 address matching more robust without relying on chainId format detection.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/interwovenkit-react/src/pages/deposit/hooks.ts` around lines 36 -
44, matchesAssetOption currently gates ERC-20 case-insensitive comparison on an
isEvm check, but to be defensive you should instead compare addresses
case-insensitively whenever both option.denom and denom start with "0x" (while
keeping the initial option.chainId === chainId equality check); update the
function matchesAssetOption to replace the isEvm branch with a simple check "if
(option.denom.startsWith('0x') && denom.startsWith('0x')) return
option.denom.toLowerCase() === denom.toLowerCase()" and otherwise fall back to
the existing strict comparison.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/interwovenkit-react/src/pages/deposit/hooks.ts`:
- Around line 36-44: matchesAssetOption currently gates ERC-20 case-insensitive
comparison on an isEvm check, but to be defensive you should instead compare
addresses case-insensitively whenever both option.denom and denom start with
"0x" (while keeping the initial option.chainId === chainId equality check);
update the function matchesAssetOption to replace the isEvm branch with a simple
check "if (option.denom.startsWith('0x') && denom.startsWith('0x')) return
option.denom.toLowerCase() === denom.toLowerCase()" and otherwise fall back to
the existing strict comparison.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between ee73604 and f357fca.

📒 Files selected for processing (2)
  • packages/interwovenkit-react/src/pages/bridge/data/chains.ts
  • packages/interwovenkit-react/src/pages/deposit/hooks.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/interwovenkit-react/src/pages/bridge/data/chains.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants