Skip to content

feat: integrate ins - #297

Merged
dadamu merged 1 commit into
mainfrom
feat/impl-ins
Jul 9, 2026
Merged

feat: integrate ins#297
dadamu merged 1 commit into
mainfrom
feat/impl-ins

Conversation

@dadamu

@dadamu dadamu commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Pull Request Checklist

Before Submission


Description


Additional Notes


By submitting this pull request, I confirm that:

  • My contribution is made under the Business Source License
  • I grant Forbole Technology Limited a perpetual, worldwide, non-exclusive license to use my contribution under the
    project's
    license terms
  • I have the authority to make this contribution and license it appropriately

Summary by CodeRabbit

  • New Features

    • Added INS name support across the app, including a new names view and dedicated asset details page.
    • You can now navigate to and view INS records directly from the dashboard.
    • Sending to supported chains now accepts INS domains in addition to wallet addresses.
  • Bug Fixes

    • Improved name resolution and display so resolved addresses and domain details appear inline when available.
    • Enhanced empty/loading states for name lists and send forms for a smoother experience.

Copilot AI review requested due to automatic review settings July 9, 2026 09:07
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Note

.coderabbit.yml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized keys: "labels", "include_paths", "exclude_paths", "filters", "review", "pull_request", "limits", "commands", "messages"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
📝 Walkthrough

Walkthrough

This PR adds INS domain support: a new useIns hooks module for resolving and fetching domain data, an INSItem component and Names dashboard component (replacing KNS), an INSAsset screen with a new router route, an isIgraChain helper, and INS domain resolution wired into EVM send-flow address validation.

Changes

INS Domain Feature

Layer / File(s) Summary
INS API hooks
hooks/ins/useIns.ts
New module with fetchDomainOwner, useInsDomainsByAddress, and useInsResolve hooks backed by SWR, plus extractDomainNames normalization and InsResolveResponse type.
Dashboard INS/KNS unification
components/dashboard/INSItem.tsx, components/dashboard/Names.tsx, components/dashboard/KNS.tsx, components/screens/Dashboard.tsx
Adds INSItem row and Names component combining paginated KNS and INS domain lists with infinite scroll and empty state; removes standalone KNS component; Dashboard tab renamed and rewired to render Names.
INS asset screen and routing
components/screens/INSAsset.tsx, entrypoints/popup/router.tsx
New INSAsset screen displaying resolved domain details, registered at route ins/:name.
INS domain resolution in send flows
lib/layer2.ts, components/send/evm/erc20-send/DetailsStep.tsx, components/send/evm/erc20-send/Erc20Send.tsx, components/send/evm/evm-kas-send/DetailsStep.tsx, components/send/evm/evm-kas-send/EvmKasSend.tsx
Adds isIgraChain helper; extends Erc20Send/EvmKasSend form schemas with optional domain; address validators in both DetailsStep components resolve INS domains to addresses when enabled and updates placeholder/UI text.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant DetailsStep
  participant useIns
  participant InsApi

  User->>DetailsStep: enters address or domain
  DetailsStep->>DetailsStep: addressValidator(input)
  alt input contains dot and insEnabled
    DetailsStep->>useIns: fetchDomainOwner(input)
    useIns->>InsApi: GET /resolve?name=input
    InsApi-->>useIns: exists, address
    useIns-->>DetailsStep: resolved address
    DetailsStep->>DetailsStep: set address and domain fields
  else direct EVM address
    DetailsStep->>DetailsStep: validate address format
  end
Loading
sequenceDiagram
  participant Names
  participant useAssetsByAddress
  participant useInsDomainsByAddress
  participant IntersectionObserver

  Names->>useAssetsByAddress: fetch KNS assets page
  Names->>useInsDomainsByAddress: fetch INS domains
  IntersectionObserver->>Names: sentinel intersecting
  Names->>useAssetsByAddress: setKnsSize(next page)
  useAssetsByAddress-->>Names: additional KNS page data
  Names->>Names: render KNSItem and INSItem lists
Loading

Possibly related PRs

  • forbole/kastle#260: Both PRs modify lib/layer2.ts for IGRA network support, with this PR adding the isIgraChain helper that depends on IGRA chain definitions.
🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change, which adds INS support across navigation, screens, and send flows.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/impl-ins

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (2)
hooks/ins/useIns.ts (2)

31-56: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider using the shared fetcher in fetchDomainOwner.

fetchDomainOwner uses raw fetch while the SWR hooks in this same file use the shared fetcher from @/lib/utils. If fetcher includes common headers, error handling, or retries, this path bypasses them. Additionally, the coding guidelines state hooks should use useSWR for API data fetching. If on-demand resolution outside React render is needed, consider extracting this as a non-hook utility function rather than a useIns hook that doesn't call any React hooks.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@hooks/ins/useIns.ts` around lines 31 - 56, `useIns` currently performs API
access in `fetchDomainOwner` with raw `fetch`, bypassing the shared request
behavior used elsewhere in this module. Update `fetchDomainOwner` to use the
shared `fetcher` from `@/lib/utils` so it benefits from the same headers/error
handling/retry behavior, and if this logic is meant for on-demand use outside
React rendering, move it out of `useIns` into a plain utility instead of keeping
a hook that doesn’t use React hooks.

Source: Coding guidelines


58-62: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

URL-encode address in the SWR key for consistency.

useInsResolve and fetchDomainOwner both use encodeURIComponent for the name parameter, but useInsDomainsByAddress passes address raw into the URL. While EVM addresses are hex and unlikely to contain special characters, this is inconsistent and could break if the function is reused with non-hex inputs.

♻️ Proposed fix
-    address ? `${INS_API_URL}/names/by-owner?address=${address}` : null,
+    address ? `${INS_API_URL}/names/by-owner?address=${encodeURIComponent(address)}` : null,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@hooks/ins/useIns.ts` around lines 58 - 62, The SWR key in
useInsDomainsByAddress currently appends address without encoding, which is
inconsistent with useInsResolve and fetchDomainOwner. Update the URL
construction in useInsDomainsByAddress to URL-encode the address value before
interpolating it into the names/by-owner query string, so the hook matches the
encoding approach used elsewhere.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/dashboard/INSItem.tsx`:
- Line 14: The navigation in INSItem’s onClick handler interpolates name
directly into the route, which can break for domain names containing URL-special
characters. Update the navigate call to encode the dynamic name segment before
building the /ins route so the path is always safe and resolves correctly.

In `@components/screens/INSAsset.tsx`:
- Around line 9-12: The INSAsset screen currently only uses detail from
useInsResolve, so loading and missing-domain cases fall through to an empty
view. Update INSAsset to also destructure isLoading and error from
useInsResolve, then render a loading skeleton or placeholder while loading and a
clear not-found state when error or missing detail is returned. Keep the
existing navigate/useParams flow intact and handle these states before the main
detail render so the screen never appears blank.

In `@components/send/evm/erc20-send/DetailsStep.tsx`:
- Around line 108-119: The async INS validation in DetailsStep can write stale
recipient data after user input changes. Update the validator around the
fetchDomainOwner flow to verify the current input still matches the value being
validated before calling setValue for address or domain, or otherwise
cancel/ignore outdated lookups. Use the existing DetailsStep validation path and
the userInput/value state involved in the INS lookup to ensure only the latest
recipient input can update form state.

In `@components/send/evm/evm-kas-send/DetailsStep.tsx`:
- Around line 86-97: The INS resolution path in DetailsStep’s recipient
validation can apply an outdated async result and overwrite the current
address/domain after the user changes input. Update the fetchDomainOwner branch
to verify the latest recipient value still matches the looked-up value before
calling setValue, or otherwise cancel/ignore stale validations. Use the existing
validation logic around insEnabled, value.includes("."), fetchDomainOwner, and
setValue to keep the current input authoritative.

In `@hooks/ins/useIns.ts`:
- Around line 6-13: The INS response type is currently only a plain interface,
and `useInsResolve` is accepting SWR data without runtime validation. Add a Zod
schema for `InsResolveResponse` and use it to parse the resolved payload before
returning it from `useInsResolve`, so malformed INS API responses are caught at
runtime. Keep the schema colocated with `InsResolveResponse` and update the SWR
response handling to use the parsed result instead of a direct cast.

---

Nitpick comments:
In `@hooks/ins/useIns.ts`:
- Around line 31-56: `useIns` currently performs API access in
`fetchDomainOwner` with raw `fetch`, bypassing the shared request behavior used
elsewhere in this module. Update `fetchDomainOwner` to use the shared `fetcher`
from `@/lib/utils` so it benefits from the same headers/error handling/retry
behavior, and if this logic is meant for on-demand use outside React rendering,
move it out of `useIns` into a plain utility instead of keeping a hook that
doesn’t use React hooks.
- Around line 58-62: The SWR key in useInsDomainsByAddress currently appends
address without encoding, which is inconsistent with useInsResolve and
fetchDomainOwner. Update the URL construction in useInsDomainsByAddress to
URL-encode the address value before interpolating it into the names/by-owner
query string, so the hook matches the encoding approach used elsewhere.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: ee9f35e4-d6d6-4470-99d3-1a139b44d607

📥 Commits

Reviewing files that changed from the base of the PR and between e61f9e0 and b183dca.

📒 Files selected for processing (12)
  • components/dashboard/INSItem.tsx
  • components/dashboard/KNS.tsx
  • components/dashboard/Names.tsx
  • components/screens/Dashboard.tsx
  • components/screens/INSAsset.tsx
  • components/send/evm/erc20-send/DetailsStep.tsx
  • components/send/evm/erc20-send/Erc20Send.tsx
  • components/send/evm/evm-kas-send/DetailsStep.tsx
  • components/send/evm/evm-kas-send/EvmKasSend.tsx
  • entrypoints/popup/router.tsx
  • hooks/ins/useIns.ts
  • lib/layer2.ts
💤 Files with no reviewable changes (1)
  • components/dashboard/KNS.tsx

return (
<div
className="flex cursor-pointer items-center gap-3 rounded-xl border border-daintree-700 bg-daintree-800 p-3 hover:border-white"
onClick={() => navigate(`/ins/${name}`)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Encode name in the navigation URL.

name is interpolated directly into the route path without encodeURIComponent. If a domain name contains URL-special characters (e.g., /, ?, #), the route will break or navigate to the wrong path.

🐛 Proposed fix
-      onClick={() => navigate(`/ins/${name}`)}
+      onClick={() => navigate(`/ins/${encodeURIComponent(name)}`)}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onClick={() => navigate(`/ins/${name}`)}
onClick={() => navigate(`/ins/${encodeURIComponent(name)}`)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/dashboard/INSItem.tsx` at line 14, The navigation in INSItem’s
onClick handler interpolates name directly into the route, which can break for
domain names containing URL-special characters. Update the navigate call to
encode the dynamic name segment before building the /ins route so the path is
always safe and resolves correctly.

Comment on lines +9 to +12
export default function INSAsset() {
const navigate = useNavigate();
const { name } = useParams();
const { detail } = useInsResolve(name);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add loading and not-found states to INSAsset screen.

Only detail is destructured from useInsResolve, ignoring isLoading and error. When the domain is loading or doesn't exist, the user sees a blank screen with only a header. Destructure isLoading and render a loading skeleton or "not found" message accordingly.

💚 Proposed fix
 export default function INSAsset() {
   const navigate = useNavigate();
   const { name } = useParams();
-  const { detail } = useInsResolve(name);
+  const { detail, isLoading } = useInsResolve(name);
 
   return (
     <div className="flex h-full flex-col p-4">
       <Header
         title="INS Asset"
         showClose={false}
         onBack={() => navigate("/dashboard")}
       />
 
+      {isLoading && (
+        <div className="flex flex-1 items-center justify-center">
+          <div className="size-6 animate-spin rounded-full border-[6px] border-current border-t-[`#A2F5FF`] text-icy-blue-600" />
+        </div>
+      )}
+
+      {!isLoading && !detail && (
+        <div className="flex flex-1 items-center justify-center text-sm text-daintree-400">
+          Domain not found
+        </div>
+      )}
+
       {detail && (
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export default function INSAsset() {
const navigate = useNavigate();
const { name } = useParams();
const { detail } = useInsResolve(name);
export default function INSAsset() {
const navigate = useNavigate();
const { name } = useParams();
const { detail, isLoading } = useInsResolve(name);
return (
<div className="flex h-full flex-col p-4">
<Header
title="INS Asset"
showClose={false}
onBack={() => navigate("/dashboard")}
/>
{isLoading && (
<div className="flex flex-1 items-center justify-center">
<div className="size-6 animate-spin rounded-full border-[6px] border-current border-t-[`#A2F5FF`] text-icy-blue-600" />
</div>
)}
{!isLoading && !detail && (
<div className="flex flex-1 items-center justify-center text-sm text-daintree-400">
Domain not found
</div>
)}
{detail && (
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/screens/INSAsset.tsx` around lines 9 - 12, The INSAsset screen
currently only uses detail from useInsResolve, so loading and missing-domain
cases fall through to an empty view. Update INSAsset to also destructure
isLoading and error from useInsResolve, then render a loading skeleton or
placeholder while loading and a clear not-found state when error or missing
detail is returned. Keep the existing navigate/useParams flow intact and handle
these states before the main detail render so the screen never appears blank.

Comment on lines +108 to +119
if (insEnabled && value.includes(".")) {
const resolved = await fetchDomainOwner(value);
if (resolved && isAddress(resolved)) {
setValue("address", resolved);
setValue("domain", value);
return true;
}
}

setValue("address", undefined);
setValue("domain", undefined);
return genericErrorMessage;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the target file, then inspect the relevant region and related symbols.
ast-grep outline components/send/evm/erc20-send/DetailsStep.tsx --view expanded

printf '\n--- file excerpt ---\n'
sed -n '1,220p' components/send/evm/erc20-send/DetailsStep.tsx | cat -n

printf '\n--- fetchDomainOwner references ---\n'
rg -n "fetchDomainOwner|userInput|setValue\\(\" components/send/evm/erc20-send -S

printf '\n--- related form fields and validators ---\n'
rg -n "useFormContext|trigger\\(|validatingFields|address|domain|userInput" components/send/evm/erc20-send -S

Repository: forbole/kastle

Length of output: 8720


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- form definition ---'
ast-grep outline components/send/evm/erc20-send/Erc20Send.tsx --view expanded

printf '\n%s\n' '--- form file excerpt ---'
sed -n '1,260p' components/send/evm/erc20-send/Erc20Send.tsx | cat -n

printf '\n%s\n' '--- userInput / address / domain references in the send flow ---'
rg -n "userInput|address|domain|fetchDomainOwner|trigger\\(|setValue\\(" components/send/evm/erc20-send -S

printf '\n%s\n' '--- react-hook-form config references ---'
rg -n "useForm\\(|mode:|reValidateMode:|resolver:|defaultValues:" components/send/evm/erc20-send -S

Repository: forbole/kastle

Length of output: 11269


Guard the INS lookup against stale recipient input. The async validator can still call setValue("address") / setValue("domain") after userInput has changed, so an older lookup can overwrite or clear the current recipient state. Compare against the latest input, or cancel the in-flight lookup, before writing back.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/send/evm/erc20-send/DetailsStep.tsx` around lines 108 - 119, The
async INS validation in DetailsStep can write stale recipient data after user
input changes. Update the validator around the fetchDomainOwner flow to verify
the current input still matches the value being validated before calling
setValue for address or domain, or otherwise cancel/ignore outdated lookups. Use
the existing DetailsStep validation path and the userInput/value state involved
in the INS lookup to ensure only the latest recipient input can update form
state.

Comment on lines +86 to +97
if (insEnabled && value.includes(".")) {
const resolved = await fetchDomainOwner(value);
if (resolved && isAddress(resolved)) {
setValue("address", resolved);
setValue("domain", value);
return true;
}
}

setValue("address", undefined);
setValue("domain", undefined);
return genericErrorMessage;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the target file and nearby related flows, then inspect the relevant slices.
echo "== target file outline =="
ast-grep outline components/send/evm/evm-kas-send/DetailsStep.tsx --view expanded || true

echo
echo "== search for ERC20 flow and stale-input guards =="
rg -n "getValues\\(|fetchDomainOwner|userInput|domain|address|stale|race|ERC20|erc20" components/send/evm -S

echo
echo "== read the relevant section of target file =="
sed -n '1,220p' components/send/evm/evm-kas-send/DetailsStep.tsx

echo
echo "== locate ERC20-related comparator in repository =="
rg -n "fetchDomainOwner|getValues\\(\"userInput\"\\)|setValue\\(\"address\"|setValue\\(\"domain\"" components -S

Repository: forbole/kastle

Length of output: 23813


Guard INS resolution against stale input.
fetchDomainOwner can resolve after the user has already changed the recipient, and this branch will still overwrite address/domain with the old result. Check the current input before applying the async lookup result, or cancel the in-flight validation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/send/evm/evm-kas-send/DetailsStep.tsx` around lines 86 - 97, The
INS resolution path in DetailsStep’s recipient validation can apply an outdated
async result and overwrite the current address/domain after the user changes
input. Update the fetchDomainOwner branch to verify the latest recipient value
still matches the looked-up value before calling setValue, or otherwise
cancel/ignore stale validations. Use the existing validation logic around
insEnabled, value.includes("."), fetchDomainOwner, and setValue to keep the
current input authoritative.

Comment thread hooks/ins/useIns.ts
Comment on lines +6 to +13
export interface InsResolveResponse {
exists: boolean;
address?: string;
owner?: string;
registry_version?: string;
tenure?: string;
expires_at?: string;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Use Zod schemas for INS API payload validation.

As per coding guidelines, all API payloads should be validated with Zod. InsResolveResponse is a plain interface and the SWR responses are cast without schema validation. Define a Zod schema and parse the response data through it to catch malformed API responses at runtime.

♻️ Proposed Zod schema and validation
+import { z } from "zod";
+
+export const InsResolveResponseSchema = z.object({
+  exists: z.boolean(),
+  address: z.string().optional(),
+  owner: z.string().optional(),
+  registry_version: z.string().optional(),
+  tenure: z.string().optional(),
+  expires_at: z.string().optional(),
+});
+
+export type InsResolveResponse = z.infer<typeof InsResolveResponseSchema>;

Then update useInsResolve to parse through the schema:

 export function useInsResolve(name?: string) {
-  const { data, isLoading, error } = useSWR<InsResolveResponse, Error>(
+  const { data, isLoading, error } = useSWR<InsResolveResponse, Error>(
     name ? `${INS_API_URL}/resolve?name=${encodeURIComponent(name)}` : null,
-    fetcher,
+    async (url: string) => InsResolveResponseSchema.parse(await fetcher(url)),
   );
 
   return { detail: data?.exists ? data : undefined, isLoading, error };
 }

Also applies to: 59-64

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@hooks/ins/useIns.ts` around lines 6 - 13, The INS response type is currently
only a plain interface, and `useInsResolve` is accepting SWR data without
runtime validation. Add a Zod schema for `InsResolveResponse` and use it to
parse the resolved payload before returning it from `useInsResolve`, so
malformed INS API responses are caught at runtime. Keep the schema colocated
with `InsResolveResponse` and update the SWR response handling to use the parsed
result instead of a direct cast.

Source: Coding guidelines

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adds INS (insdomains.org) name support to the Kastle extension popup, including listing INS names on the dashboard, a dedicated INS asset details screen, and the ability to resolve INS domains when sending on IGRA EVM networks.

Changes:

  • Added INS API hooks for resolving names and listing names by owner address.
  • Introduced a unified “Names” dashboard tab combining KNS + INS listings and added an INS asset details route/screen.
  • Enabled INS-domain-to-address resolution in EVM send flows on IGRA chains (and added isIgraChain helper).

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
lib/layer2.ts Adds isIgraChain helper to gate INS features to IGRA networks.
hooks/ins/useIns.ts New INS API hooks for name resolution and listing domains by address.
entrypoints/popup/router.tsx Registers a new ins/:name route for the INS asset page.
components/send/evm/evm-kas-send/EvmKasSend.tsx Extends the EVM KAS send form schema to track resolved domain.
components/send/evm/evm-kas-send/DetailsStep.tsx Adds INS-domain validation/resolution for IGRA EVM KAS sends.
components/send/evm/erc20-send/Erc20Send.tsx Extends the ERC20 send form schema to track resolved domain.
components/send/evm/erc20-send/DetailsStep.tsx Adds INS-domain validation/resolution for IGRA ERC20 sends.
components/screens/INSAsset.tsx New INS asset detail screen using INS resolution hook.
components/screens/Dashboard.tsx Renames KNS tab to “Names” and renders the new consolidated names view.
components/dashboard/Names.tsx New dashboard tab combining KNS + INS listings with pagination for KNS.
components/dashboard/KNS.tsx Removed in favor of the consolidated Names tab.
components/dashboard/INSItem.tsx New dashboard list item for INS names linking into the INS asset route.
Comments suppressed due to low confidence (2)

components/send/evm/evm-kas-send/DetailsStep.tsx:206

  • The loading spinner is keyed off validatingFields.address, but the validated/registered field is userInput. As written, the spinner will never show during async validation/domain resolution.
          <div className="pointer-events-none absolute end-0 top-10 flex h-16 items-center pe-3">
            {validatingFields.address && (
              <img

components/send/evm/erc20-send/DetailsStep.tsx:230

  • The loading spinner is keyed off validatingFields.address, but the validated/registered field is userInput. As written, the spinner will never show during async validation/domain resolution.
          <div className="pointer-events-none absolute end-0 top-10 flex h-16 items-center pe-3">
            {validatingFields.address && (
              <img

Comment thread hooks/ins/useIns.ts
Comment on lines +15 to +29
function extractDomainNames(raw: unknown): string[] {
if (Array.isArray(raw)) {
return raw.map((entry) =>
typeof entry === "string" ? entry : (entry?.name ?? entry?.domain),
);
}

const container = raw as
| { names?: unknown[]; domains?: unknown[]; data?: unknown[] }
| undefined;

return extractDomainNames(
container?.names ?? container?.domains ?? container?.data ?? [],
);
}
Comment thread hooks/ins/useIns.ts
Comment on lines +58 to +65
export function useInsDomainsByAddress(address?: string) {
const { data, isLoading, error, mutate } = useSWR<unknown, Error>(
address ? `${INS_API_URL}/names/by-owner?address=${address}` : null,
fetcher,
);

return { domains: extractDomainNames(data), isLoading, error, mutate };
}
Comment thread hooks/ins/useIns.ts
Comment on lines +67 to +74
export function useInsResolve(name?: string) {
const { data, isLoading, error } = useSWR<InsResolveResponse, Error>(
name ? `${INS_API_URL}/resolve?name=${encodeURIComponent(name)}` : null,
fetcher,
);

return { detail: data?.exists ? data : undefined, isLoading, error };
}
Comment thread hooks/ins/useIns.ts
Comment on lines +32 to +34
const fetchDomainOwner = async (
name: string,
): Promise<string | undefined> => {
Comment on lines +86 to +93
if (insEnabled && value.includes(".")) {
const resolved = await fetchDomainOwner(value);
if (resolved && isAddress(resolved)) {
setValue("address", resolved);
setValue("domain", value);
return true;
}
}
Comment on lines +108 to +115
if (insEnabled && value.includes(".")) {
const resolved = await fetchDomainOwner(value);
if (resolved && isAddress(resolved)) {
setValue("address", resolved);
setValue("domain", value);
return true;
}
}
return (
<div
className="flex cursor-pointer items-center gap-3 rounded-xl border border-daintree-700 bg-daintree-800 p-3 hover:border-white"
onClick={() => navigate(`/ins/${name}`)}
Comment on lines +11 to +12
const { name } = useParams();
const { detail } = useInsResolve(name);
onBack={() => navigate("/dashboard")}
/>

{detail && (
Comment on lines +70 to +79
{detail.expires_at
? new Date(detail.expires_at).toLocaleString("en-GB", {
month: "short",
day: "2-digit",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
timeZoneName: "short",
})
: "-"}
@dadamu
dadamu merged commit 7524a7e into main Jul 9, 2026
3 checks passed
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