Skip to content

feat: 1:1 stablecoin demo toggle (V2-207)#54

Open
reednaa wants to merge 4 commits into
developfrom
feature/v2-207-1to1-stablecoin-demo
Open

feat: 1:1 stablecoin demo toggle (V2-207)#54
reednaa wants to merge 4 commits into
developfrom
feature/v2-207-1to1-stablecoin-demo

Conversation

@reednaa

@reednaa reednaa commented Jun 4, 2026

Copy link
Copy Markdown
Member

Summary

Adds a "1:1 demo" toggle so the 1:1 stablecoin intent flow can be shown to partners/prospects with verifiable on-chain output, powered by LI.FI intents. When enabled, quote requests send the X-Integrator-Key header and force order exclusivity to the LI.FI demo solver (0x94807fE4300D15909C1a4fd39f76c61D68aee11E) so it fills 1:1 via the solver's quick fallback. When off, behavior is unchanged.

This branch is intended as the base for a polished Jumper-style UI built on top of it.

Linear: V2-207

Changes

  • Bump @lifi/intent to 0.1.3 (adds integratorKeyX-Integrator-Key header support in getQuotes)
  • Add use11Demo + integratorKey state and a UI toggle + key field in IssueIntent.svelte
  • GetQuote.svelte sends the header and forced exclusivity in demo mode
  • Extract pure resolveDemoQuoteParams() helper with unit tests
  • Hardcode demo solver as DEMO_EXCLUSIVE_SOLVER in config.ts

Verification

  • bun run check → 0 errors, 0 warnings
  • bun test tests/unit → 28 pass, 0 fail

Out of scope

  • Polished Jumper-style UI (separate effort)
  • Backend fake-quote setup keyed to the integrator key

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added E2E testing environment configuration and intent execution helpers for smart contract interactions.
  • Bug Fixes

    • Updated database schema and migration logic for improved consistency.
  • Refactor

    • Modernized token handling and intent workflow processing.
    • Consolidated order/intent validation dependencies.
  • Tests

    • Updated test workflows with pinned action versions for improved reliability.
  • Chores

    • Updated dependencies and code formatting.
    • Refined GitHub Actions workflows and build configuration.
    • Updated README documentation formatting.

Add a "1:1 demo" toggle that, when enabled, sends the X-Integrator-Key
header on quote requests and forces order exclusivity to the LI.FI demo
solver so it fills 1:1 via the quick fallback. Lets the 1:1 stablecoin
flow be demoed to partners/prospects with verifiable on-chain output.

- Bump @lifi/intent to 0.1.3 (adds integratorKey -> X-Integrator-Key header)
- Add use11Demo + integratorKey state and a UI toggle/key field
- Extract resolveDemoQuoteParams() helper with unit tests

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 55e5c661-4cdd-4984-8990-7a12125d938a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR migrates wallet integration from @web3-onboard to wagmi/LI.FI Intent SDK, consolidates database migrations, refactors configuration to use numeric chain IDs, removes custom intent implementation in favor of external IntentApi, and updates components and factories throughout.

Changes

LI.FI Intent Migration & Config Refactoring

Layer / File(s) Summary
Configuration, Testing Setup, and Tooling
.env.e2e.example, .github/workflows/*.yml, .gitignore, .lintstagedrc.json, .prettierrc, eslint.config.js, package.json, playwright.config.ts, README.md, drizzle.config.ts
E2E environment variables added, GitHub Actions workflows pin third-party action versions by commit SHA, Prettier/ESLint/lint-staged configurations updated for code style standardization, package version bumped to 0.1.0 with wallet/connectivity dependencies replaced (@web3-onboard → wagmi, @lifi/intent, @base-org/account, @coinbase/wallet-sdk, etc.), and Playwright configured for sequential test execution.
Database Schema Consolidation & Migration Restructuring
drizzle/*.sql, drizzle/meta/0000_snapshot.json, drizzle/meta/_journal.json
Four separate migration files consolidated into a single 0000_brief_corsair.sql that recreates all schema at once: fill_transactions (with output_hash unique constraint), intents (with order_id unique constraint), tokens (with new is_manual, is_testnet boolean fields and address+chain_id index), and transaction_receipts. Drizzle metadata updated with expanded table definitions and migration journal entries replaced with single new entry.
Database Initialization Refactoring
src/lib/db.ts
Improved Drizzle instance management: TypeScript suppression changed from @ts-ignore to @ts-expect-error, and initDb now creates a local instance, runs migrations against it, then assigns to module-level db variable.
Core Configuration Refactoring for Chain IDs
src/lib/config.ts
Major refactor transitioning from chain-name-based to numeric chain-ID-based lookups: new chainIdList, chainById, chainNameById, and clientsById exports added; Token type updated from chain: string to chainId: number; balanceQuery keyed by number instead of chain name; getCoin accepts chainId (number/bigint/string); getOracle takes numeric chainId; getChain and getClient use precomputed id-based maps; clients catalog expanded with additional chains and Polygon fix; token inventory updated across mainnet/testnet branches.
Application Type Definitions
src/lib/appTypes.ts
New module exporting AppTokenContext (token + bigint amount) and AppCreateIntentOptions (derived from CreateIntentOptions with AppTokenContext arrays, verifier field, and function-based account) for application-specific intent creation.
Intent Execution Helpers Implementation
src/lib/libraries/intentExecution.ts
New module providing signIntentCompact, depositAndRegisterCompact, openEscrowIntent, and finaliseIntent functions for both standard and multichain intent execution on-chain, replacing previously embedded intent class methods.
Core Intent & Validation Dependencies Wiring
src/lib/libraries/coreDeps.ts
New module exporting intentDeps (with getOracle implementing oracle selection by verifier+chainId) and orderValidationDeps (with allowedInputOracles, allowedOutputOracles, allowedOutputSettlers functions for oracle/settler allowlist validation).
Demo Quote Parameters Resolution
src/lib/libraries/demoQuote.ts
New module with resolveDemoQuoteParams function for computing demo-mode exclusivity overrides and integrator key derivation for quote request calls.
Flow Progress Utilities Refactoring
src/lib/libraries/flowProgress.ts
Updated to use @lifi/intent encoding utilities (getOutputHash, encodeMandateOutput, addressToBytes32, bytes32ToAddress) and containerToIntent conversion instead of local helpers; control flow for fill/validation/finalisation checks remains unchanged.
CompactLib Refactoring for Chain ID Support
src/lib/libraries/compactLib.ts
Updated to use AppTokenContext with chainId, switch to @lifi/intent helpers (toId, addressToBytes32), and route chain/client selection via getChain/getClient by numeric chain ID for deposit, withdraw, and approve flows.
IntentFactory Complete Refactoring
src/lib/libraries/intentFactory.ts
Major refactor replacing OrderServer with IntentApi: now accepts AppCreateIntentOptions, preHook takes numeric chainId, applies same-chain timing and exclusivity overrides, uses new execution helpers (signIntentCompact, depositAndRegisterCompact, openEscrowIntent), and submits orders via intentApi.submitOrder; escrowApprove updated to use AppTokenContext and getClient/getChain by chainId.
Intent List Utilities Refactoring
src/lib/libraries/intentList.ts
Updated to derive orderId via containerToIntent, pass orderValidationDeps to validateOrderContainerWithReason, and introduce safeChainName wrapper for robust chain name lookups in token summaries with fallback formatting.
Removal of Local Intent Implementation
src/lib/libraries/intent.ts (removed)
Complete removal of local Intent, StandardOrderIntent, MultichainOrderIntent classes and related lock/option type definitions—now provided by external @lifi/intent package.
Removal of OrderServer
src/lib/libraries/orderServer.ts (removed)
Complete removal of OrderServer class handling order submission, quote fetching, and WebSocket management—replaced by IntentApi from external package.
Component Type Signature Updates
src/lib/appTypes.ts, src/lib/components/{AwaitButton, BalanceField, InputTokenModal, OutputTokenModal}.svelte, src/lib/components/ui/FlowStepTracker.svelte
AwaitButton props updated to Svelte runes syntax; BalanceField imports toBigIntWithDecimals from @lifi/intent; InputTokenModal and OutputTokenModal prop types changed from TokenContext[] to AppTokenContext[] with chainId-keyed token addressing; FlowStepTracker imports OrderContainer from @lifi/intent.
GetQuote Component Refactoring for IntentApi
src/lib/components/GetQuote.svelte
Complete refactoring to use IntentApi.getQuotes instead of OrderServer: switched from TokenContext to AppTokenContext, added demo/integrator controls (use11Demo, integratorKey, useProductionApi), derive request params via resolveDemoQuoteParams, simplified quote expiry to fixed 30-second duration from quote fetch time.
Token Modal Components Refactoring
src/lib/components/{InputTokenModal, OutputTokenModal}.svelte
Both modals refactored to use AppTokenContext, switch token keying to ${chainId}:${address}, source tokens from store.availableTokens, and render chain options via chainIdList with getChainName lookups.
FlowStepTracker Component Updates
src/lib/components/ui/FlowStepTracker.svelte
OrderContainer type import switched to @lifi/intent; step completion logic reworked to blend flowChecks boolean flags with currentScreenIndex thresholds (assets/issue ≥ 1/2, fetch selected ∨ ≥ 3, fill/prove ≤ 4/5).
UI Layout & Responsive Component Updates
src/lib/components/ui/{FlowProgressList, ScreenFrame}.svelte
FlowProgressList restructured for responsive layout with horizontal/vertical flex orientation across breakpoints and CSS variable-driven connector fill; ScreenFrame made title and description optional props.
Global TypeScript Type Augmentation
src/app.d.ts
Added BigInt interface with toJSON(): string method for proper JSON serialization of bigint values.
Code Formatting & Styling
src/app.html, src/lib/abi/*.ts, src/lib/components/**/*.svelte, src/lib/libraries/assetSelection.ts, src/lib/components/Introduction.svelte
Formatting-only updates: ABI files reformatted with consistent indentation/quoting, component markup normalized for whitespace, AssetSelection code styled for consistency, Introduction component sections reordered and rewording for clarity, and various Svelte components updated to consistent spacing/semicolon style.

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly Related PRs

  • lifinance/lintent#48: Updates to Introduction.svelte component copy and reordering of sections ("Multichain" and other intro content).

Suggested Reviewers

  • Asem-Abdelhady

🐰 A grand refactor hops into sight,
Chain IDs shine where names took flight,
LI.FI intents now lead the way,
Old OrderServer's had its day,
The components dance in types brand new!

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/v2-207-1to1-stablecoin-demo

@reednaa reednaa changed the base branch from main to develop June 4, 2026 10:39
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown

🚀 Preview deployed!

Worker: lintent-pr-54
URL: https://lintent-pr-54.li-fi374.workers.dev

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

🧹 Nitpick comments (7)
.lintstagedrc.json (1)

2-2: ⚡ Quick win

Add ESLint to staged TS/JS/Svelte checks.

This config only formats files; it skips the required lint pass for staged ts/js/svelte changes.

Suggested update
 {
-  "*.{js,ts,svelte,css,md,json,html}": "prettier --write"
+  "*.{js,ts,svelte,css,md,json,html}": "prettier --write",
+  "*.{js,ts,svelte}": "eslint --max-warnings=0"
 }

As per coding guidelines: "**/*.{ts,js,svelte}: Use ESLint with Svelte support for linting; run bun run lint to check lint rules".

🤖 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 @.lintstagedrc.json at line 2, Update the .lintstagedrc.json so staged
TypeScript/JavaScript/Svelte files are linted, not just prettier-formatted: add
or replace the glob "**/*.{ts,js,svelte}" to run the ESLint-based lint command
(per guidelines use "bun run lint") so that staged files matching
"*.{ts,js,svelte}" are checked by ESLint with Svelte support; keep the existing
prettier entry for other globs or chain both commands if you want formatting
plus linting for the same file types.
src/lib/libraries/compactLib.ts (2)

35-58: 💤 Low value

Inconsistent await pattern with writeContract.

In compactDeposit, writeContract is awaited immediately (lines 37, 47), making transactionHash a resolved string. However, in compactWithdraw (line 102) and compactApprove (line 141), writeContract is not awaited, making transactionHash a promise. This inconsistency could confuse future maintainers. Also, on line 57, await transactionHash is redundant since it's already a string.

♻️ Consistent pattern (prefer awaiting immediately)
-      let transactionHash: `0x${string}`;
       if (token.address === ADDRESS_ZERO) {
-        transactionHash = await walletClient.writeContract({
+        const transactionHash = await walletClient.writeContract({
           chain: getChain(token.chainId),
           ...
         });
+        await getClient(token.chainId).waitForTransactionReceipt({ hash: transactionHash });
+        if (postHook) await postHook();
+        return transactionHash;
       } else {
-        transactionHash = await walletClient.writeContract({
+        const transactionHash = await walletClient.writeContract({
           ...
         });
+        await getClient(token.chainId).waitForTransactionReceipt({ hash: transactionHash });
+        if (postHook) await postHook();
+        return transactionHash;
       }
-      await getClient(token.chainId).waitForTransactionReceipt({
-        hash: await transactionHash
-      });
-      if (postHook) await postHook();
-      return transactionHash;
🤖 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 `@src/lib/libraries/compactLib.ts` around lines 35 - 58, The code in
compactDeposit uses await on walletClient.writeContract so transactionHash is a
string, but compactWithdraw and compactApprove leave it as a Promise, and then
caller does await transactionHash later; make the pattern consistent by always
awaiting writeContract immediately in compactDeposit, compactWithdraw, and
compactApprove (i.e., assign transactionHash = await
walletClient.writeContract(...)), and remove redundant await when calling
getClient(...).waitForTransactionReceipt({ hash: transactionHash }); reference
the functions compactDeposit, compactWithdraw, compactApprove, the
transactionHash variable, walletClient.writeContract, and
getClient(...).waitForTransactionReceipt when making the changes.

14-15: ⚡ Quick win

Replace any with proper types for hooks.

ESLint flags any on preHook and postHook return types. Since these hooks are for side effects (UI updates, logging), void or unknown would be more appropriate.

♻️ Proposed fix
   static compactDeposit(
     walletClient: WC,
     opts: {
-      preHook?: (chainId: number) => Promise<any>;
-      postHook?: () => Promise<any>;
+      preHook?: (chainId: number) => Promise<void>;
+      postHook?: () => Promise<void>;
       inputToken: AppTokenContext;
       ...
     }
   )

Apply the same change to compactWithdraw and compactApprove.

Also applies to: 67-68, 121-122

🤖 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 `@src/lib/libraries/compactLib.ts` around lines 14 - 15, Replace the loose any
return types on the hook signatures with a more specific side-effect type:
change preHook?: (chainId: number) => Promise<any> and postHook?: () =>
Promise<any> to use Promise<void> (or Promise<unknown> if you prefer unknown) so
the hooks are clearly for side effects; make the identical change to the same
hook types declared for compactWithdraw and compactApprove (ensure you update
the signatures for preHook and postHook in each of those functions/classes:
preHook, postHook, compactWithdraw, compactApprove).
src/lib/config.ts (1)

383-386: 💤 Low value

Simplify address normalization logic.

The current slicing logic address.length - 42 is confusing and relies on assumptions about input length. For standard hex addresses (42 chars including 0x), consider using a clearer approach.

♻️ Clearer approach
-  const concatedAddress =
-    "0x" + address?.replace("0x", "")?.slice(address.length - 42, address.length);
+  // Normalize to lowercase 0x-prefixed address, taking last 40 hex chars
+  const concatedAddress = address
+    ? (`0x${address.replace("0x", "").slice(-40).toLowerCase()}` as `0x${string}`)
+    : undefined;
🤖 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 `@src/lib/config.ts` around lines 383 - 386, The current address normalization
that builds concatedAddress is brittle; change it to strip any leading "0x" from
address, take the last 40 hex chars (e.g., via slice(-40)), left-pad with zeros
if shorter, and then prefix with "0x" (optionally lowercasing) so
concatedAddress is always a valid 20-byte hex string; update the code that
assigns concatedAddress (the variable named concatedAddress in
src/lib/config.ts) to use this clear sequence instead of address.length - 42
slicing.
src/app.d.ts (1)

11-13: Runtime BigInt.prototype.toJSON implementation is present

  • src/app.d.ts’s BigInt augmentation is backed by a runtime patch: BigInt.prototype.toJSON = function () { return this.toString(); }; in src/routes/+page.svelte (lines 17-19), so JSON.stringify won’t throw for bigint values due to this missing implementation.
  • Prototype mutation is currently done in a page module; move it to a dedicated global/polyfill/entry to avoid unexpected SSR/client side effects.
🤖 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 `@src/app.d.ts` around lines 11 - 13, The runtime patch BigInt.prototype.toJSON
currently implemented inside src/routes/+page.svelte should be moved to a
dedicated global/polyfill entry to avoid unexpected SSR/client side effects;
create a single initialization module (e.g., a polyfills or runtime-init file)
that checks typeof BigInt !== 'undefined' and whether BigInt.prototype.toJSON
already exists before assigning, import that module from a top-level entry
(client and/or server bootstrap such as your app entry or hooks file) so it runs
once for both environments, and keep the TypeScript augmentation in src/app.d.ts
to match the runtime behavior; remove the mutation from src/routes/+page.svelte
to prevent per-page side effects.
src/lib/libraries/intentFactory.ts (1)

124-125: ⚡ Quick win

Replace any types with specific types for hooks.

The linter flags any usage. Consider using void or unknown for hook return types since the return values aren't used.

Proposed fix
-  preHook?: (chainId: number) => Promise<any>;
-  postHook?: () => Promise<any>;
+  preHook?: (chainId: number) => Promise<void>;
+  postHook?: () => Promise<void>;

Apply the same change in the constructor options type and escrowApprove opts.

Also applies to: 133-134, 298-299

🤖 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 `@src/lib/libraries/intentFactory.ts` around lines 124 - 125, The hook
signatures use `any`; change them to more specific types (e.g., replace
`preHook?: (chainId: number) => Promise<any>` with `preHook?: (chainId: number)
=> Promise<void | unknown>` and `postHook?: () => Promise<any>` with `postHook?:
() => Promise<void | unknown>` or simply `Promise<void>` if no return value is
expected) and apply the same replacement in the constructor options type and the
`escrowApprove` opts declarations (update the corresponding types referenced in
intentFactory.ts for the constructor options and escrowApprove opts to use
`Promise<void>` or `Promise<unknown>` instead of `Promise<any>`).
src/lib/libraries/intentExecution.ts (1)

167-192: 💤 Low value

Loop structure with early return only processes first component.

The for loop iterates over components but returns or throws on the first iteration, making subsequent components unreachable. If only the first component should be processed, the loop is misleading; if all components should be processed, the logic needs restructuring.

If only first component is intended, clarify without loop
-  for (const { orderComponent } of components) {
+  const { orderComponent } = components[0];
+  {
     if (intent.inputSettler.toLowerCase() === MULTICHAIN_INPUT_SETTLER_ESCROW.toLowerCase()) {
       return walletClient.writeContract({
         // ...
       });
     }
     if (intent.inputSettler.toLowerCase() === MULTICHAIN_INPUT_SETTLER_COMPACT.toLowerCase()) {
       // ...
       return walletClient.writeContract({
         // ...
       });
     }
     throw new Error(`Could not detect settler type ${intent.inputSettler}`);
   }
-
-  throw new Error(`Failed to finalise multichain order on chain ${actionChain.id}.`);
🤖 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 `@src/lib/libraries/intentExecution.ts` around lines 167 - 192, The for-loop
over components returns or throws on the first iteration, so either remove the
loop and operate on the first element (use components[0] / orderComponent) if
only the first component should be finalised, or process all components by
iterating and collecting the results (e.g., build an array of
walletClient.writeContract promises for each orderComponent, using
intent.inputSettler checks with MULTICHAIN_INPUT_SETTLER_ESCROW and
MULTICHAIN_INPUT_SETTLER_COMPACT, calling combineSignatures(signatures) where
needed) and await Promise.all, and ensure you do not throw inside the loop
(handle per-component errors or aggregate them and throw after the loop with
context including actionChain.id and failed components).
🤖 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 `@drizzle/0000_brief_corsair.sql`:
- Around line 1-8: The baseline migration contains destructive DROP TABLE IF
EXISTS statements for transaction_receipts, tokens, intents, and
fill_transactions which can irreversibly delete persisted user data; remove
those DROP statements from 0000_brief_corsair.sql and make the migration
non-destructive by either replacing them with idempotent CREATE TABLE IF NOT
EXISTS statements (or no-op existence checks) for transaction_receipts, tokens,
intents, and fill_transactions, or move the DROP operations into a clearly
labeled, separate destructive migration that requires explicit opt-in during
upgrades.

In `@drizzle/meta/_journal.json`:
- Around line 4-12: The journal rewrite replaces previous migration history with
a single baseline in _journal.json (the "entries" array with idx 0 and tag
"0000_brief_corsair"), which will cause persistent client DBs like idb://orders
to be replayed and tables dropped; instead preserve existing entries and append
a forward-only migration entry (increment idx and set a new timestamp/tag) or,
if you truly intend a reset, explicitly change the client DB name/version (e.g.,
bump the idb://orders namespace) so consumers know this is a deliberate reset
rather than silently rewriting history.

In `@src/lib/abi/escrow.ts`:
- Around line 1231-1262: Remove the duplicated ABI error object for
FillDeadlineAfterExpiry so only a single error definition remains; locate the
two identical entries named "FillDeadlineAfterExpiry" in the ABI array and
delete one of the objects (the one that repeats the same inputs:
fillDeadline:uint32 and expires:uint32), leaving one canonical definition and
ensuring no other duplicate error entries remain in the same exported ABI
structure (e.g., the escrow ABI list).

In `@src/lib/components/BalanceField.svelte`:
- Line 2: The import toBigIntWithDecimals from "`@lifi/intent`" in
BalanceField.svelte is unused; remove the unused import to clean up the file and
avoid lint warnings by deleting the line that imports toBigIntWithDecimals (the
import statement referencing toBigIntWithDecimals) so the component only imports
and uses props it needs.

In `@src/lib/components/Introduction.svelte`:
- Around line 7-11: The introduction copy in Introduction.svelte contains
grammar and typos; update the text fragments so they read correctly: change
"support" to "supports" in the sentence mentioning "resource lock flow", change
"transaction are" to "transactions are", change "configured different" to
"configured differently", and fix "Learm" to "Learn" wherever these exact
strings appear in the component's markup so the displayed intro text is
grammatically correct.

In `@src/lib/config.ts`:
- Around line 491-497: The polygon public client is mistakenly configured with
chain: base; update the createPublicClient call that constructs polygon to use
chain: polygon instead (replace chain: base with chain: polygon) so the polygon
client uses the correct chain context (chain ID, explorers, etc.); locate the
polygon variable/entry where createPublicClient is invoked and change the chain
argument accordingly.
- Around line 288-293: The native ETH entry in the token list currently sets
decimals: 6 for the object with address: ADDRESS_ZERO, name: "eth", chainId:
arbitrumSepolia.id; update that object's decimals value to 18 so native ETH on
Arbitrum Sepolia uses 18 decimals (fix formatting/calculation errors) and ensure
no other native-token entries for arbitrumSepolia still use 6.

In `@src/lib/libraries/assetSelection.ts`:
- Line 63: The comparator in the values.sort calls currently casts a bigint
difference to Number (values.sort((a, b) => Number(b[0] - a[0]))) which can
overflow and misorder large token amounts; replace the Number(...) conversion
with a bigint-safe comparator that returns -1/0/1 based on comparing the bigint
fields directly (e.g. compare b[0] and a[0] with conditional branches or by
testing b[0] - a[0] > 0 / < 0) so sorting for largest()/smallest() works
correctly; update both occurrences (the comparator at the shown values.sort
lines) to use this bigint-safe comparison.

In `@src/lib/libraries/coreDeps.ts`:
- Around line 31-35: The code inconsistently validates addresses:
POLYMER_ORACLE[key] (variable polymer) is only checked for truthiness while
WORMHOLE_ORACLE[key] uses isNonZeroAddress; change the polymer push to use the
same validation by calling isNonZeroAddress(polymer) before
allowed.push(polymer) so the zero address is rejected; update any related type
assumptions if needed and keep the same allowed: `0x${string}`[] typing.
- Around line 43-47: In allowedOutputOracles, the checks for oracle addresses
are inconsistent: polymer is pushed on a simple truthy check while wormhole uses
isNonZeroAddress; change the polymer check to use isNonZeroAddress as well so
both POLYMER_ORACLE[key] and WORMHOLE_ORACLE[key] are validated the same way
before pushing into the allowed array (refer to allowedOutputOracles,
POLYMER_ORACLE, WORMHOLE_ORACLE, isNonZeroAddress, and the allowed variable).

In `@src/lib/libraries/flowProgress.ts`:
- Around line 157-168: The code can access flattenedInputs[0][0] when
flattenedInputs[0] is an empty array; update the check in the function that uses
flattenedInputs (the block that calls inputChainClient.readContract with COMPACT
and getLockDetails) to ensure the first nested array actually has an element
before using [0][0] — either find the first non-empty entry in flattenedInputs
(e.g., iterate flattenedInputs to pick the first sub-array with length>0) or add
an explicit guard like if (!flattenedInputs[0] || flattenedInputs[0].length ===
0) return false; so you never pass undefined into getLockDetails via
inputChainClient.readContract.

In `@src/lib/libraries/intentExecution.ts`:
- Around line 29-32: The ABI encoding call is inconsistent:
sponsorSignature.payload is defaulted but allocatorSignature.payload is not;
update the encodeAbiParameters call (using encodeAbiParameters and
parseAbiParameters) to provide a safe fallback for allocatorSignature.payload as
well (e.g., allocatorSignature.payload ?? "0x") so both signature payloads are
always a hex string and avoid undefined being passed to encodeAbiParameters.

In `@src/lib/libraries/intentFactory.ts`:
- Around line 231-235: Change transactionHash to a const since it is never
reassigned (assign the result of depositAndRegisterCompact to const
transactionHash) and remove the unused receipt variable created from
getClient(...).waitForTransactionReceipt or, if the receipt is needed, use it;
specifically update the code around the depositAndRegisterCompact call and the
subsequent getClient(...).waitForTransactionReceipt call (which currently
assigns to receipt) so that either the receipt line is deleted or its value is
consumed, keeping symbols transactionHash, depositAndRegisterCompact, account(),
this.walletClient, getClient, and inputTokens intact.
- Around line 63-67: The loop that sets exclusivity currently skips outputs
whose output.context === "0x", so the exclusivity override never applies for the
test-fixture sentinel; change the guard in the block that iterates order.outputs
so that it replaces the sentinel instead of skipping it (i.e., set
output.context = newContext when output.context === "0x", or alternatively
remove the conditional to always assign if intended), targeting the loop that
references order.outputs and the output.context/newContext variables so
exclusivityFor is correctly applied.

---

Nitpick comments:
In @.lintstagedrc.json:
- Line 2: Update the .lintstagedrc.json so staged TypeScript/JavaScript/Svelte
files are linted, not just prettier-formatted: add or replace the glob
"**/*.{ts,js,svelte}" to run the ESLint-based lint command (per guidelines use
"bun run lint") so that staged files matching "*.{ts,js,svelte}" are checked by
ESLint with Svelte support; keep the existing prettier entry for other globs or
chain both commands if you want formatting plus linting for the same file types.

In `@src/app.d.ts`:
- Around line 11-13: The runtime patch BigInt.prototype.toJSON currently
implemented inside src/routes/+page.svelte should be moved to a dedicated
global/polyfill entry to avoid unexpected SSR/client side effects; create a
single initialization module (e.g., a polyfills or runtime-init file) that
checks typeof BigInt !== 'undefined' and whether BigInt.prototype.toJSON already
exists before assigning, import that module from a top-level entry (client
and/or server bootstrap such as your app entry or hooks file) so it runs once
for both environments, and keep the TypeScript augmentation in src/app.d.ts to
match the runtime behavior; remove the mutation from src/routes/+page.svelte to
prevent per-page side effects.

In `@src/lib/config.ts`:
- Around line 383-386: The current address normalization that builds
concatedAddress is brittle; change it to strip any leading "0x" from address,
take the last 40 hex chars (e.g., via slice(-40)), left-pad with zeros if
shorter, and then prefix with "0x" (optionally lowercasing) so concatedAddress
is always a valid 20-byte hex string; update the code that assigns
concatedAddress (the variable named concatedAddress in src/lib/config.ts) to use
this clear sequence instead of address.length - 42 slicing.

In `@src/lib/libraries/compactLib.ts`:
- Around line 35-58: The code in compactDeposit uses await on
walletClient.writeContract so transactionHash is a string, but compactWithdraw
and compactApprove leave it as a Promise, and then caller does await
transactionHash later; make the pattern consistent by always awaiting
writeContract immediately in compactDeposit, compactWithdraw, and compactApprove
(i.e., assign transactionHash = await walletClient.writeContract(...)), and
remove redundant await when calling getClient(...).waitForTransactionReceipt({
hash: transactionHash }); reference the functions compactDeposit,
compactWithdraw, compactApprove, the transactionHash variable,
walletClient.writeContract, and getClient(...).waitForTransactionReceipt when
making the changes.
- Around line 14-15: Replace the loose any return types on the hook signatures
with a more specific side-effect type: change preHook?: (chainId: number) =>
Promise<any> and postHook?: () => Promise<any> to use Promise<void> (or
Promise<unknown> if you prefer unknown) so the hooks are clearly for side
effects; make the identical change to the same hook types declared for
compactWithdraw and compactApprove (ensure you update the signatures for preHook
and postHook in each of those functions/classes: preHook, postHook,
compactWithdraw, compactApprove).

In `@src/lib/libraries/intentExecution.ts`:
- Around line 167-192: The for-loop over components returns or throws on the
first iteration, so either remove the loop and operate on the first element (use
components[0] / orderComponent) if only the first component should be finalised,
or process all components by iterating and collecting the results (e.g., build
an array of walletClient.writeContract promises for each orderComponent, using
intent.inputSettler checks with MULTICHAIN_INPUT_SETTLER_ESCROW and
MULTICHAIN_INPUT_SETTLER_COMPACT, calling combineSignatures(signatures) where
needed) and await Promise.all, and ensure you do not throw inside the loop
(handle per-component errors or aggregate them and throw after the loop with
context including actionChain.id and failed components).

In `@src/lib/libraries/intentFactory.ts`:
- Around line 124-125: The hook signatures use `any`; change them to more
specific types (e.g., replace `preHook?: (chainId: number) => Promise<any>` with
`preHook?: (chainId: number) => Promise<void | unknown>` and `postHook?: () =>
Promise<any>` with `postHook?: () => Promise<void | unknown>` or simply
`Promise<void>` if no return value is expected) and apply the same replacement
in the constructor options type and the `escrowApprove` opts declarations
(update the corresponding types referenced in intentFactory.ts for the
constructor options and escrowApprove opts to use `Promise<void>` or
`Promise<unknown>` instead of `Promise<any>`).
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: e685f060-bab0-42d0-8636-3f83f11b415a

📥 Commits

Reviewing files that changed from the base of the PR and between fd3980c and ebb97af.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (111)
  • .env.e2e.example
  • .github/workflows/deploy.yml
  • .github/workflows/test.yml
  • .gitignore
  • .lintstagedrc.json
  • .prettierrc
  • README.md
  • drizzle.config.ts
  • drizzle/0000_absent_moonstone.sql
  • drizzle/0000_brief_corsair.sql
  • drizzle/0001_nifty_mephisto.sql
  • drizzle/0002_expand_intent_created_at.sql
  • drizzle/0003_unique_intent_order_id.sql
  • drizzle/0004_store_transaction_receipts.sql
  • drizzle/meta/0000_snapshot.json
  • drizzle/meta/0001_snapshot.json
  • drizzle/meta/_journal.json
  • eslint.config.js
  • package.json
  • playwright.config.ts
  • src/app.d.ts
  • src/app.html
  • src/lib/abi/compact.ts
  • src/lib/abi/erc20.ts
  • src/lib/abi/escrow.ts
  • src/lib/abi/multichain_compact.ts
  • src/lib/abi/multichain_escrow.ts
  • src/lib/abi/outputsettler.ts
  • src/lib/abi/polymeroracle.ts
  • src/lib/abi/settlercompact.ts
  • src/lib/abi/wormholeoracle.ts
  • src/lib/appTypes.ts
  • src/lib/components/AwaitButton.svelte
  • src/lib/components/BalanceField.svelte
  • src/lib/components/GetQuote.svelte
  • src/lib/components/InputTokenModal.svelte
  • src/lib/components/IntentListDetailRow.svelte
  • src/lib/components/Introduction.svelte
  • src/lib/components/OutputTokenModal.svelte
  • src/lib/components/ui/ChainActionRow.svelte
  • src/lib/components/ui/FieldRow.svelte
  • src/lib/components/ui/FlowProgressList.svelte
  • src/lib/components/ui/FlowStepTracker.svelte
  • src/lib/components/ui/FormControl.svelte
  • src/lib/components/ui/InlineMetaField.svelte
  • src/lib/components/ui/ScreenFrame.svelte
  • src/lib/components/ui/SectionCard.svelte
  • src/lib/components/ui/SegmentedControl.svelte
  • src/lib/components/ui/TokenAmountChip.svelte
  • src/lib/config.ts
  • src/lib/db.ts
  • src/lib/libraries/assetSelection.ts
  • src/lib/libraries/compactLib.ts
  • src/lib/libraries/coreDeps.ts
  • src/lib/libraries/demoQuote.ts
  • src/lib/libraries/flowProgress.ts
  • src/lib/libraries/intent.ts
  • src/lib/libraries/intentExecution.ts
  • src/lib/libraries/intentFactory.ts
  • src/lib/libraries/intentList.ts
  • src/lib/libraries/orderServer.ts
  • src/lib/libraries/rpcCache.ts
  • src/lib/libraries/solver.ts
  • src/lib/libraries/token.ts
  • src/lib/migrations.json
  • src/lib/schema.ts
  • src/lib/screens/ConnectWallet.svelte
  • src/lib/screens/FillIntent.svelte
  • src/lib/screens/Finalise.svelte
  • src/lib/screens/IntentDescription.svelte
  • src/lib/screens/IntentList.svelte
  • src/lib/screens/IssueIntent.svelte
  • src/lib/screens/ManageDeposit.svelte
  • src/lib/screens/ReceiveMessage.svelte
  • src/lib/state.svelte.ts
  • src/lib/utils/convert.ts
  • src/lib/utils/idLib.ts
  • src/lib/utils/intent.ts
  • src/lib/utils/interopableAddresses.ts
  • src/lib/utils/orderLib.ts
  • src/lib/utils/typedMessage.ts
  • src/lib/utils/wagmi.ts
  • src/lib/utils/walletClient.ts
  • src/lib/utils/walletClientRuntime.ts
  • src/lib/utils/web3-onboard.ts
  • src/routes/+layout.svelte
  • src/routes/+page.svelte
  • src/routes/allocator/+server.ts
  • src/routes/health/+server.ts
  • src/routes/polymer/+server.ts
  • src/routes/polymer/health/+server.ts
  • src/types/index.ts
  • svelte.config.js
  • tests/db.test.ts
  • tests/e2e/escrow-standard-blackbox.spec.ts
  • tests/e2e/escrow-standard-live.spec.ts
  • tests/e2e/helpers/bootstrap.ts
  • tests/e2e/issuance.spec.ts
  • tests/fixtures/mockQuote.ts
  • tests/fixtures/orderFixtures.ts
  • tests/unit/assetSelection.test.ts
  • tests/unit/demoQuote.test.ts
  • tests/unit/intentList.test.ts
  • tests/unit/orderLib.test.ts
  • tests/unit/orderServer.test.ts
  • tests/unit/orderValidationDeps.test.ts
  • tests/unit/recipientField.test.ts
  • tests/unit/walletClientSwitch.test.ts
  • tsconfig.json
  • vite.config.ts
  • wrangler.toml
💤 Files with no reviewable changes (8)
  • drizzle/0000_absent_moonstone.sql
  • src/lib/libraries/intent.ts
  • drizzle/meta/0001_snapshot.json
  • src/lib/libraries/orderServer.ts
  • drizzle/0002_expand_intent_created_at.sql
  • drizzle/0003_unique_intent_order_id.sql
  • drizzle/0004_store_transaction_receipts.sql
  • drizzle/0001_nifty_mephisto.sql

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 14

🧹 Nitpick comments (7)
.lintstagedrc.json (1)

2-2: ⚡ Quick win

Add ESLint to staged TS/JS/Svelte checks.

This config only formats files; it skips the required lint pass for staged ts/js/svelte changes.

Suggested update
 {
-  "*.{js,ts,svelte,css,md,json,html}": "prettier --write"
+  "*.{js,ts,svelte,css,md,json,html}": "prettier --write",
+  "*.{js,ts,svelte}": "eslint --max-warnings=0"
 }

As per coding guidelines: "**/*.{ts,js,svelte}: Use ESLint with Svelte support for linting; run bun run lint to check lint rules".

🤖 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 @.lintstagedrc.json at line 2, Update the .lintstagedrc.json so staged
TypeScript/JavaScript/Svelte files are linted, not just prettier-formatted: add
or replace the glob "**/*.{ts,js,svelte}" to run the ESLint-based lint command
(per guidelines use "bun run lint") so that staged files matching
"*.{ts,js,svelte}" are checked by ESLint with Svelte support; keep the existing
prettier entry for other globs or chain both commands if you want formatting
plus linting for the same file types.
src/lib/libraries/compactLib.ts (2)

35-58: 💤 Low value

Inconsistent await pattern with writeContract.

In compactDeposit, writeContract is awaited immediately (lines 37, 47), making transactionHash a resolved string. However, in compactWithdraw (line 102) and compactApprove (line 141), writeContract is not awaited, making transactionHash a promise. This inconsistency could confuse future maintainers. Also, on line 57, await transactionHash is redundant since it's already a string.

♻️ Consistent pattern (prefer awaiting immediately)
-      let transactionHash: `0x${string}`;
       if (token.address === ADDRESS_ZERO) {
-        transactionHash = await walletClient.writeContract({
+        const transactionHash = await walletClient.writeContract({
           chain: getChain(token.chainId),
           ...
         });
+        await getClient(token.chainId).waitForTransactionReceipt({ hash: transactionHash });
+        if (postHook) await postHook();
+        return transactionHash;
       } else {
-        transactionHash = await walletClient.writeContract({
+        const transactionHash = await walletClient.writeContract({
           ...
         });
+        await getClient(token.chainId).waitForTransactionReceipt({ hash: transactionHash });
+        if (postHook) await postHook();
+        return transactionHash;
       }
-      await getClient(token.chainId).waitForTransactionReceipt({
-        hash: await transactionHash
-      });
-      if (postHook) await postHook();
-      return transactionHash;
🤖 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 `@src/lib/libraries/compactLib.ts` around lines 35 - 58, The code in
compactDeposit uses await on walletClient.writeContract so transactionHash is a
string, but compactWithdraw and compactApprove leave it as a Promise, and then
caller does await transactionHash later; make the pattern consistent by always
awaiting writeContract immediately in compactDeposit, compactWithdraw, and
compactApprove (i.e., assign transactionHash = await
walletClient.writeContract(...)), and remove redundant await when calling
getClient(...).waitForTransactionReceipt({ hash: transactionHash }); reference
the functions compactDeposit, compactWithdraw, compactApprove, the
transactionHash variable, walletClient.writeContract, and
getClient(...).waitForTransactionReceipt when making the changes.

14-15: ⚡ Quick win

Replace any with proper types for hooks.

ESLint flags any on preHook and postHook return types. Since these hooks are for side effects (UI updates, logging), void or unknown would be more appropriate.

♻️ Proposed fix
   static compactDeposit(
     walletClient: WC,
     opts: {
-      preHook?: (chainId: number) => Promise<any>;
-      postHook?: () => Promise<any>;
+      preHook?: (chainId: number) => Promise<void>;
+      postHook?: () => Promise<void>;
       inputToken: AppTokenContext;
       ...
     }
   )

Apply the same change to compactWithdraw and compactApprove.

Also applies to: 67-68, 121-122

🤖 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 `@src/lib/libraries/compactLib.ts` around lines 14 - 15, Replace the loose any
return types on the hook signatures with a more specific side-effect type:
change preHook?: (chainId: number) => Promise<any> and postHook?: () =>
Promise<any> to use Promise<void> (or Promise<unknown> if you prefer unknown) so
the hooks are clearly for side effects; make the identical change to the same
hook types declared for compactWithdraw and compactApprove (ensure you update
the signatures for preHook and postHook in each of those functions/classes:
preHook, postHook, compactWithdraw, compactApprove).
src/lib/config.ts (1)

383-386: 💤 Low value

Simplify address normalization logic.

The current slicing logic address.length - 42 is confusing and relies on assumptions about input length. For standard hex addresses (42 chars including 0x), consider using a clearer approach.

♻️ Clearer approach
-  const concatedAddress =
-    "0x" + address?.replace("0x", "")?.slice(address.length - 42, address.length);
+  // Normalize to lowercase 0x-prefixed address, taking last 40 hex chars
+  const concatedAddress = address
+    ? (`0x${address.replace("0x", "").slice(-40).toLowerCase()}` as `0x${string}`)
+    : undefined;
🤖 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 `@src/lib/config.ts` around lines 383 - 386, The current address normalization
that builds concatedAddress is brittle; change it to strip any leading "0x" from
address, take the last 40 hex chars (e.g., via slice(-40)), left-pad with zeros
if shorter, and then prefix with "0x" (optionally lowercasing) so
concatedAddress is always a valid 20-byte hex string; update the code that
assigns concatedAddress (the variable named concatedAddress in
src/lib/config.ts) to use this clear sequence instead of address.length - 42
slicing.
src/app.d.ts (1)

11-13: Runtime BigInt.prototype.toJSON implementation is present

  • src/app.d.ts’s BigInt augmentation is backed by a runtime patch: BigInt.prototype.toJSON = function () { return this.toString(); }; in src/routes/+page.svelte (lines 17-19), so JSON.stringify won’t throw for bigint values due to this missing implementation.
  • Prototype mutation is currently done in a page module; move it to a dedicated global/polyfill/entry to avoid unexpected SSR/client side effects.
🤖 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 `@src/app.d.ts` around lines 11 - 13, The runtime patch BigInt.prototype.toJSON
currently implemented inside src/routes/+page.svelte should be moved to a
dedicated global/polyfill entry to avoid unexpected SSR/client side effects;
create a single initialization module (e.g., a polyfills or runtime-init file)
that checks typeof BigInt !== 'undefined' and whether BigInt.prototype.toJSON
already exists before assigning, import that module from a top-level entry
(client and/or server bootstrap such as your app entry or hooks file) so it runs
once for both environments, and keep the TypeScript augmentation in src/app.d.ts
to match the runtime behavior; remove the mutation from src/routes/+page.svelte
to prevent per-page side effects.
src/lib/libraries/intentFactory.ts (1)

124-125: ⚡ Quick win

Replace any types with specific types for hooks.

The linter flags any usage. Consider using void or unknown for hook return types since the return values aren't used.

Proposed fix
-  preHook?: (chainId: number) => Promise<any>;
-  postHook?: () => Promise<any>;
+  preHook?: (chainId: number) => Promise<void>;
+  postHook?: () => Promise<void>;

Apply the same change in the constructor options type and escrowApprove opts.

Also applies to: 133-134, 298-299

🤖 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 `@src/lib/libraries/intentFactory.ts` around lines 124 - 125, The hook
signatures use `any`; change them to more specific types (e.g., replace
`preHook?: (chainId: number) => Promise<any>` with `preHook?: (chainId: number)
=> Promise<void | unknown>` and `postHook?: () => Promise<any>` with `postHook?:
() => Promise<void | unknown>` or simply `Promise<void>` if no return value is
expected) and apply the same replacement in the constructor options type and the
`escrowApprove` opts declarations (update the corresponding types referenced in
intentFactory.ts for the constructor options and escrowApprove opts to use
`Promise<void>` or `Promise<unknown>` instead of `Promise<any>`).
src/lib/libraries/intentExecution.ts (1)

167-192: 💤 Low value

Loop structure with early return only processes first component.

The for loop iterates over components but returns or throws on the first iteration, making subsequent components unreachable. If only the first component should be processed, the loop is misleading; if all components should be processed, the logic needs restructuring.

If only first component is intended, clarify without loop
-  for (const { orderComponent } of components) {
+  const { orderComponent } = components[0];
+  {
     if (intent.inputSettler.toLowerCase() === MULTICHAIN_INPUT_SETTLER_ESCROW.toLowerCase()) {
       return walletClient.writeContract({
         // ...
       });
     }
     if (intent.inputSettler.toLowerCase() === MULTICHAIN_INPUT_SETTLER_COMPACT.toLowerCase()) {
       // ...
       return walletClient.writeContract({
         // ...
       });
     }
     throw new Error(`Could not detect settler type ${intent.inputSettler}`);
   }
-
-  throw new Error(`Failed to finalise multichain order on chain ${actionChain.id}.`);
🤖 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 `@src/lib/libraries/intentExecution.ts` around lines 167 - 192, The for-loop
over components returns or throws on the first iteration, so either remove the
loop and operate on the first element (use components[0] / orderComponent) if
only the first component should be finalised, or process all components by
iterating and collecting the results (e.g., build an array of
walletClient.writeContract promises for each orderComponent, using
intent.inputSettler checks with MULTICHAIN_INPUT_SETTLER_ESCROW and
MULTICHAIN_INPUT_SETTLER_COMPACT, calling combineSignatures(signatures) where
needed) and await Promise.all, and ensure you do not throw inside the loop
(handle per-component errors or aggregate them and throw after the loop with
context including actionChain.id and failed components).
🤖 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 `@drizzle/0000_brief_corsair.sql`:
- Around line 1-8: The baseline migration contains destructive DROP TABLE IF
EXISTS statements for transaction_receipts, tokens, intents, and
fill_transactions which can irreversibly delete persisted user data; remove
those DROP statements from 0000_brief_corsair.sql and make the migration
non-destructive by either replacing them with idempotent CREATE TABLE IF NOT
EXISTS statements (or no-op existence checks) for transaction_receipts, tokens,
intents, and fill_transactions, or move the DROP operations into a clearly
labeled, separate destructive migration that requires explicit opt-in during
upgrades.

In `@drizzle/meta/_journal.json`:
- Around line 4-12: The journal rewrite replaces previous migration history with
a single baseline in _journal.json (the "entries" array with idx 0 and tag
"0000_brief_corsair"), which will cause persistent client DBs like idb://orders
to be replayed and tables dropped; instead preserve existing entries and append
a forward-only migration entry (increment idx and set a new timestamp/tag) or,
if you truly intend a reset, explicitly change the client DB name/version (e.g.,
bump the idb://orders namespace) so consumers know this is a deliberate reset
rather than silently rewriting history.

In `@src/lib/abi/escrow.ts`:
- Around line 1231-1262: Remove the duplicated ABI error object for
FillDeadlineAfterExpiry so only a single error definition remains; locate the
two identical entries named "FillDeadlineAfterExpiry" in the ABI array and
delete one of the objects (the one that repeats the same inputs:
fillDeadline:uint32 and expires:uint32), leaving one canonical definition and
ensuring no other duplicate error entries remain in the same exported ABI
structure (e.g., the escrow ABI list).

In `@src/lib/components/BalanceField.svelte`:
- Line 2: The import toBigIntWithDecimals from "`@lifi/intent`" in
BalanceField.svelte is unused; remove the unused import to clean up the file and
avoid lint warnings by deleting the line that imports toBigIntWithDecimals (the
import statement referencing toBigIntWithDecimals) so the component only imports
and uses props it needs.

In `@src/lib/components/Introduction.svelte`:
- Around line 7-11: The introduction copy in Introduction.svelte contains
grammar and typos; update the text fragments so they read correctly: change
"support" to "supports" in the sentence mentioning "resource lock flow", change
"transaction are" to "transactions are", change "configured different" to
"configured differently", and fix "Learm" to "Learn" wherever these exact
strings appear in the component's markup so the displayed intro text is
grammatically correct.

In `@src/lib/config.ts`:
- Around line 491-497: The polygon public client is mistakenly configured with
chain: base; update the createPublicClient call that constructs polygon to use
chain: polygon instead (replace chain: base with chain: polygon) so the polygon
client uses the correct chain context (chain ID, explorers, etc.); locate the
polygon variable/entry where createPublicClient is invoked and change the chain
argument accordingly.
- Around line 288-293: The native ETH entry in the token list currently sets
decimals: 6 for the object with address: ADDRESS_ZERO, name: "eth", chainId:
arbitrumSepolia.id; update that object's decimals value to 18 so native ETH on
Arbitrum Sepolia uses 18 decimals (fix formatting/calculation errors) and ensure
no other native-token entries for arbitrumSepolia still use 6.

In `@src/lib/libraries/assetSelection.ts`:
- Line 63: The comparator in the values.sort calls currently casts a bigint
difference to Number (values.sort((a, b) => Number(b[0] - a[0]))) which can
overflow and misorder large token amounts; replace the Number(...) conversion
with a bigint-safe comparator that returns -1/0/1 based on comparing the bigint
fields directly (e.g. compare b[0] and a[0] with conditional branches or by
testing b[0] - a[0] > 0 / < 0) so sorting for largest()/smallest() works
correctly; update both occurrences (the comparator at the shown values.sort
lines) to use this bigint-safe comparison.

In `@src/lib/libraries/coreDeps.ts`:
- Around line 31-35: The code inconsistently validates addresses:
POLYMER_ORACLE[key] (variable polymer) is only checked for truthiness while
WORMHOLE_ORACLE[key] uses isNonZeroAddress; change the polymer push to use the
same validation by calling isNonZeroAddress(polymer) before
allowed.push(polymer) so the zero address is rejected; update any related type
assumptions if needed and keep the same allowed: `0x${string}`[] typing.
- Around line 43-47: In allowedOutputOracles, the checks for oracle addresses
are inconsistent: polymer is pushed on a simple truthy check while wormhole uses
isNonZeroAddress; change the polymer check to use isNonZeroAddress as well so
both POLYMER_ORACLE[key] and WORMHOLE_ORACLE[key] are validated the same way
before pushing into the allowed array (refer to allowedOutputOracles,
POLYMER_ORACLE, WORMHOLE_ORACLE, isNonZeroAddress, and the allowed variable).

In `@src/lib/libraries/flowProgress.ts`:
- Around line 157-168: The code can access flattenedInputs[0][0] when
flattenedInputs[0] is an empty array; update the check in the function that uses
flattenedInputs (the block that calls inputChainClient.readContract with COMPACT
and getLockDetails) to ensure the first nested array actually has an element
before using [0][0] — either find the first non-empty entry in flattenedInputs
(e.g., iterate flattenedInputs to pick the first sub-array with length>0) or add
an explicit guard like if (!flattenedInputs[0] || flattenedInputs[0].length ===
0) return false; so you never pass undefined into getLockDetails via
inputChainClient.readContract.

In `@src/lib/libraries/intentExecution.ts`:
- Around line 29-32: The ABI encoding call is inconsistent:
sponsorSignature.payload is defaulted but allocatorSignature.payload is not;
update the encodeAbiParameters call (using encodeAbiParameters and
parseAbiParameters) to provide a safe fallback for allocatorSignature.payload as
well (e.g., allocatorSignature.payload ?? "0x") so both signature payloads are
always a hex string and avoid undefined being passed to encodeAbiParameters.

In `@src/lib/libraries/intentFactory.ts`:
- Around line 231-235: Change transactionHash to a const since it is never
reassigned (assign the result of depositAndRegisterCompact to const
transactionHash) and remove the unused receipt variable created from
getClient(...).waitForTransactionReceipt or, if the receipt is needed, use it;
specifically update the code around the depositAndRegisterCompact call and the
subsequent getClient(...).waitForTransactionReceipt call (which currently
assigns to receipt) so that either the receipt line is deleted or its value is
consumed, keeping symbols transactionHash, depositAndRegisterCompact, account(),
this.walletClient, getClient, and inputTokens intact.
- Around line 63-67: The loop that sets exclusivity currently skips outputs
whose output.context === "0x", so the exclusivity override never applies for the
test-fixture sentinel; change the guard in the block that iterates order.outputs
so that it replaces the sentinel instead of skipping it (i.e., set
output.context = newContext when output.context === "0x", or alternatively
remove the conditional to always assign if intended), targeting the loop that
references order.outputs and the output.context/newContext variables so
exclusivityFor is correctly applied.

---

Nitpick comments:
In @.lintstagedrc.json:
- Line 2: Update the .lintstagedrc.json so staged TypeScript/JavaScript/Svelte
files are linted, not just prettier-formatted: add or replace the glob
"**/*.{ts,js,svelte}" to run the ESLint-based lint command (per guidelines use
"bun run lint") so that staged files matching "*.{ts,js,svelte}" are checked by
ESLint with Svelte support; keep the existing prettier entry for other globs or
chain both commands if you want formatting plus linting for the same file types.

In `@src/app.d.ts`:
- Around line 11-13: The runtime patch BigInt.prototype.toJSON currently
implemented inside src/routes/+page.svelte should be moved to a dedicated
global/polyfill entry to avoid unexpected SSR/client side effects; create a
single initialization module (e.g., a polyfills or runtime-init file) that
checks typeof BigInt !== 'undefined' and whether BigInt.prototype.toJSON already
exists before assigning, import that module from a top-level entry (client
and/or server bootstrap such as your app entry or hooks file) so it runs once
for both environments, and keep the TypeScript augmentation in src/app.d.ts to
match the runtime behavior; remove the mutation from src/routes/+page.svelte to
prevent per-page side effects.

In `@src/lib/config.ts`:
- Around line 383-386: The current address normalization that builds
concatedAddress is brittle; change it to strip any leading "0x" from address,
take the last 40 hex chars (e.g., via slice(-40)), left-pad with zeros if
shorter, and then prefix with "0x" (optionally lowercasing) so concatedAddress
is always a valid 20-byte hex string; update the code that assigns
concatedAddress (the variable named concatedAddress in src/lib/config.ts) to use
this clear sequence instead of address.length - 42 slicing.

In `@src/lib/libraries/compactLib.ts`:
- Around line 35-58: The code in compactDeposit uses await on
walletClient.writeContract so transactionHash is a string, but compactWithdraw
and compactApprove leave it as a Promise, and then caller does await
transactionHash later; make the pattern consistent by always awaiting
writeContract immediately in compactDeposit, compactWithdraw, and compactApprove
(i.e., assign transactionHash = await walletClient.writeContract(...)), and
remove redundant await when calling getClient(...).waitForTransactionReceipt({
hash: transactionHash }); reference the functions compactDeposit,
compactWithdraw, compactApprove, the transactionHash variable,
walletClient.writeContract, and getClient(...).waitForTransactionReceipt when
making the changes.
- Around line 14-15: Replace the loose any return types on the hook signatures
with a more specific side-effect type: change preHook?: (chainId: number) =>
Promise<any> and postHook?: () => Promise<any> to use Promise<void> (or
Promise<unknown> if you prefer unknown) so the hooks are clearly for side
effects; make the identical change to the same hook types declared for
compactWithdraw and compactApprove (ensure you update the signatures for preHook
and postHook in each of those functions/classes: preHook, postHook,
compactWithdraw, compactApprove).

In `@src/lib/libraries/intentExecution.ts`:
- Around line 167-192: The for-loop over components returns or throws on the
first iteration, so either remove the loop and operate on the first element (use
components[0] / orderComponent) if only the first component should be finalised,
or process all components by iterating and collecting the results (e.g., build
an array of walletClient.writeContract promises for each orderComponent, using
intent.inputSettler checks with MULTICHAIN_INPUT_SETTLER_ESCROW and
MULTICHAIN_INPUT_SETTLER_COMPACT, calling combineSignatures(signatures) where
needed) and await Promise.all, and ensure you do not throw inside the loop
(handle per-component errors or aggregate them and throw after the loop with
context including actionChain.id and failed components).

In `@src/lib/libraries/intentFactory.ts`:
- Around line 124-125: The hook signatures use `any`; change them to more
specific types (e.g., replace `preHook?: (chainId: number) => Promise<any>` with
`preHook?: (chainId: number) => Promise<void | unknown>` and `postHook?: () =>
Promise<any>` with `postHook?: () => Promise<void | unknown>` or simply
`Promise<void>` if no return value is expected) and apply the same replacement
in the constructor options type and the `escrowApprove` opts declarations
(update the corresponding types referenced in intentFactory.ts for the
constructor options and escrowApprove opts to use `Promise<void>` or
`Promise<unknown>` instead of `Promise<any>`).
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: e685f060-bab0-42d0-8636-3f83f11b415a

📥 Commits

Reviewing files that changed from the base of the PR and between fd3980c and ebb97af.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (111)
  • .env.e2e.example
  • .github/workflows/deploy.yml
  • .github/workflows/test.yml
  • .gitignore
  • .lintstagedrc.json
  • .prettierrc
  • README.md
  • drizzle.config.ts
  • drizzle/0000_absent_moonstone.sql
  • drizzle/0000_brief_corsair.sql
  • drizzle/0001_nifty_mephisto.sql
  • drizzle/0002_expand_intent_created_at.sql
  • drizzle/0003_unique_intent_order_id.sql
  • drizzle/0004_store_transaction_receipts.sql
  • drizzle/meta/0000_snapshot.json
  • drizzle/meta/0001_snapshot.json
  • drizzle/meta/_journal.json
  • eslint.config.js
  • package.json
  • playwright.config.ts
  • src/app.d.ts
  • src/app.html
  • src/lib/abi/compact.ts
  • src/lib/abi/erc20.ts
  • src/lib/abi/escrow.ts
  • src/lib/abi/multichain_compact.ts
  • src/lib/abi/multichain_escrow.ts
  • src/lib/abi/outputsettler.ts
  • src/lib/abi/polymeroracle.ts
  • src/lib/abi/settlercompact.ts
  • src/lib/abi/wormholeoracle.ts
  • src/lib/appTypes.ts
  • src/lib/components/AwaitButton.svelte
  • src/lib/components/BalanceField.svelte
  • src/lib/components/GetQuote.svelte
  • src/lib/components/InputTokenModal.svelte
  • src/lib/components/IntentListDetailRow.svelte
  • src/lib/components/Introduction.svelte
  • src/lib/components/OutputTokenModal.svelte
  • src/lib/components/ui/ChainActionRow.svelte
  • src/lib/components/ui/FieldRow.svelte
  • src/lib/components/ui/FlowProgressList.svelte
  • src/lib/components/ui/FlowStepTracker.svelte
  • src/lib/components/ui/FormControl.svelte
  • src/lib/components/ui/InlineMetaField.svelte
  • src/lib/components/ui/ScreenFrame.svelte
  • src/lib/components/ui/SectionCard.svelte
  • src/lib/components/ui/SegmentedControl.svelte
  • src/lib/components/ui/TokenAmountChip.svelte
  • src/lib/config.ts
  • src/lib/db.ts
  • src/lib/libraries/assetSelection.ts
  • src/lib/libraries/compactLib.ts
  • src/lib/libraries/coreDeps.ts
  • src/lib/libraries/demoQuote.ts
  • src/lib/libraries/flowProgress.ts
  • src/lib/libraries/intent.ts
  • src/lib/libraries/intentExecution.ts
  • src/lib/libraries/intentFactory.ts
  • src/lib/libraries/intentList.ts
  • src/lib/libraries/orderServer.ts
  • src/lib/libraries/rpcCache.ts
  • src/lib/libraries/solver.ts
  • src/lib/libraries/token.ts
  • src/lib/migrations.json
  • src/lib/schema.ts
  • src/lib/screens/ConnectWallet.svelte
  • src/lib/screens/FillIntent.svelte
  • src/lib/screens/Finalise.svelte
  • src/lib/screens/IntentDescription.svelte
  • src/lib/screens/IntentList.svelte
  • src/lib/screens/IssueIntent.svelte
  • src/lib/screens/ManageDeposit.svelte
  • src/lib/screens/ReceiveMessage.svelte
  • src/lib/state.svelte.ts
  • src/lib/utils/convert.ts
  • src/lib/utils/idLib.ts
  • src/lib/utils/intent.ts
  • src/lib/utils/interopableAddresses.ts
  • src/lib/utils/orderLib.ts
  • src/lib/utils/typedMessage.ts
  • src/lib/utils/wagmi.ts
  • src/lib/utils/walletClient.ts
  • src/lib/utils/walletClientRuntime.ts
  • src/lib/utils/web3-onboard.ts
  • src/routes/+layout.svelte
  • src/routes/+page.svelte
  • src/routes/allocator/+server.ts
  • src/routes/health/+server.ts
  • src/routes/polymer/+server.ts
  • src/routes/polymer/health/+server.ts
  • src/types/index.ts
  • svelte.config.js
  • tests/db.test.ts
  • tests/e2e/escrow-standard-blackbox.spec.ts
  • tests/e2e/escrow-standard-live.spec.ts
  • tests/e2e/helpers/bootstrap.ts
  • tests/e2e/issuance.spec.ts
  • tests/fixtures/mockQuote.ts
  • tests/fixtures/orderFixtures.ts
  • tests/unit/assetSelection.test.ts
  • tests/unit/demoQuote.test.ts
  • tests/unit/intentList.test.ts
  • tests/unit/orderLib.test.ts
  • tests/unit/orderServer.test.ts
  • tests/unit/orderValidationDeps.test.ts
  • tests/unit/recipientField.test.ts
  • tests/unit/walletClientSwitch.test.ts
  • tsconfig.json
  • vite.config.ts
  • wrangler.toml
💤 Files with no reviewable changes (8)
  • drizzle/0000_absent_moonstone.sql
  • src/lib/libraries/intent.ts
  • drizzle/meta/0001_snapshot.json
  • src/lib/libraries/orderServer.ts
  • drizzle/0002_expand_intent_created_at.sql
  • drizzle/0003_unique_intent_order_id.sql
  • drizzle/0004_store_transaction_receipts.sql
  • drizzle/0001_nifty_mephisto.sql
🛑 Comments failed to post (14)
drizzle/0000_brief_corsair.sql (1)

1-8: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Remove destructive table drops from the baseline migration.

Line 1-8 can irreversibly wipe persisted user data if this migration is replayed during upgrades. Baseline migrations should be non-destructive.

Suggested non-destructive adjustment
-DROP TABLE IF EXISTS "transaction_receipts";
---> statement-breakpoint
-DROP TABLE IF EXISTS "tokens";
---> statement-breakpoint
-DROP TABLE IF EXISTS "intents";
---> statement-breakpoint
-DROP TABLE IF EXISTS "fill_transactions";
---> statement-breakpoint
-CREATE TABLE "fill_transactions" (
+CREATE TABLE IF NOT EXISTS "fill_transactions" (
@@
-CREATE TABLE "intents" (
+CREATE TABLE IF NOT EXISTS "intents" (
@@
-CREATE TABLE "tokens" (
+CREATE TABLE IF NOT EXISTS "tokens" (
@@
-CREATE TABLE "transaction_receipts" (
+CREATE TABLE IF NOT EXISTS "transaction_receipts" (
🤖 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 `@drizzle/0000_brief_corsair.sql` around lines 1 - 8, The baseline migration
contains destructive DROP TABLE IF EXISTS statements for transaction_receipts,
tokens, intents, and fill_transactions which can irreversibly delete persisted
user data; remove those DROP statements from 0000_brief_corsair.sql and make the
migration non-destructive by either replacing them with idempotent CREATE TABLE
IF NOT EXISTS statements (or no-op existence checks) for transaction_receipts,
tokens, intents, and fill_transactions, or move the DROP operations into a
clearly labeled, separate destructive migration that requires explicit opt-in
during upgrades.
drizzle/meta/_journal.json (1)

4-12: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Do not reset migration history to a new single baseline for persisted client databases.

Line 4-12 rewrites history to one new migration while idb://orders remains persistent. On upgrade paths, this can replay the baseline and, with the current SQL, drop/recreate user tables.

A safer path is to preserve prior journal entries and append a forward-only migration, or explicitly version the client DB name and treat it as a deliberate reset.

🤖 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 `@drizzle/meta/_journal.json` around lines 4 - 12, The journal rewrite replaces
previous migration history with a single baseline in _journal.json (the
"entries" array with idx 0 and tag "0000_brief_corsair"), which will cause
persistent client DBs like idb://orders to be replayed and tables dropped;
instead preserve existing entries and append a forward-only migration entry
(increment idx and set a new timestamp/tag) or, if you truly intend a reset,
explicitly change the client DB name/version (e.g., bump the idb://orders
namespace) so consumers know this is a deliberate reset rather than silently
rewriting history.
src/lib/abi/escrow.ts (1)

1231-1262: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove duplicated FillDeadlineAfterExpiry ABI error entry.

FillDeadlineAfterExpiry is declared twice (Line 1233 and Line 1249) with identical inputs. Keep a single definition to avoid ABI duplication noise and downstream confusion in interface/type generation.

Suggested fix
-  {
-    type: "error",
-    name: "FillDeadlineAfterExpiry",
-    inputs: [
-      {
-        name: "fillDeadline",
-        type: "uint32",
-        internalType: "uint32"
-      },
-      {
-        name: "expires",
-        type: "uint32",
-        internalType: "uint32"
-      }
-    ]
-  },
📝 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.

  {
    type: "error",
    name: "FillDeadlineAfterExpiry",
    inputs: [
      {
        name: "fillDeadline",
        type: "uint32",
        internalType: "uint32"
      },
      {
        name: "expires",
        type: "uint32",
        internalType: "uint32"
      }
    ]
  },
🤖 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 `@src/lib/abi/escrow.ts` around lines 1231 - 1262, Remove the duplicated ABI
error object for FillDeadlineAfterExpiry so only a single error definition
remains; locate the two identical entries named "FillDeadlineAfterExpiry" in the
ABI array and delete one of the objects (the one that repeats the same inputs:
fillDeadline:uint32 and expires:uint32), leaving one canonical definition and
ensuring no other duplicate error entries remain in the same exported ABI
structure (e.g., the escrow ABI list).
src/lib/components/BalanceField.svelte (1)

2-2: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove unused import.

The toBigIntWithDecimals import is not used anywhere in this component. The component only displays the balance value that it receives as a prop.

🧹 Proposed fix
 <script lang="ts">
-  import { toBigIntWithDecimals } from "`@lifi/intent`";
-
   let {
📝 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.

<script lang="ts">
  let {
🧰 Tools
🪛 ESLint

[error] 2-2: 'toBigIntWithDecimals' is defined but never used.

(@typescript-eslint/no-unused-vars)

🤖 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 `@src/lib/components/BalanceField.svelte` at line 2, The import
toBigIntWithDecimals from "`@lifi/intent`" in BalanceField.svelte is unused;
remove the unused import to clean up the file and avoid lint warnings by
deleting the line that imports toBigIntWithDecimals (the import statement
referencing toBigIntWithDecimals) so the component only imports and uses props
it needs.
src/lib/components/Introduction.svelte (1)

7-11: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix user-facing copy typos/grammar in the intro text.

There are visible wording issues on Line 7 (“support” → “supports”), Line 38 (“transaction are” → “transactions are”), Line 76 (“configured different” → “configured differently”), and Line 77 (“Learm” → “Learn”).

Also applies to: 38-39, 75-77

🤖 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 `@src/lib/components/Introduction.svelte` around lines 7 - 11, The introduction
copy in Introduction.svelte contains grammar and typos; update the text
fragments so they read correctly: change "support" to "supports" in the sentence
mentioning "resource lock flow", change "transaction are" to "transactions are",
change "configured different" to "configured differently", and fix "Learm" to
"Learn" wherever these exact strings appear in the component's markup so the
displayed intro text is grammatically correct.
src/lib/config.ts (2)

288-293: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Native ETH has wrong decimals on arbitrumSepolia.

Native ETH should have 18 decimals, not 6. This will cause incorrect amount formatting and calculations for ETH on Arbitrum Sepolia.

🐛 Proposed fix
       {
         address: ADDRESS_ZERO,
         name: "eth",
         chainId: arbitrumSepolia.id,
-        decimals: 6
+        decimals: 18
       },
📝 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.

      {
        address: ADDRESS_ZERO,
        name: "eth",
        chainId: arbitrumSepolia.id,
        decimals: 18
      },
🤖 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 `@src/lib/config.ts` around lines 288 - 293, The native ETH entry in the token
list currently sets decimals: 6 for the object with address: ADDRESS_ZERO, name:
"eth", chainId: arbitrumSepolia.id; update that object's decimals value to 18 so
native ETH on Arbitrum Sepolia uses 18 decimals (fix formatting/calculation
errors) and ensure no other native-token entries for arbitrumSepolia still use
6.

491-497: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Polygon client uses wrong chain configuration.

The polygon client is configured with chain: base instead of chain: polygon. This causes the client to use Base chain's context (chain ID, block explorer, etc.) while connecting to Polygon RPC endpoints, which will lead to incorrect transaction signing and chain ID mismatches.

🐛 Proposed fix
   polygon: createPublicClient({
-    chain: base,
+    chain: polygon,
     transport: fallback([
       http("https://polygon-bor-rpc.publicnode.com"),
       ...polygon.rpcUrls.default.http.map((v) => http(v))
     ])
   }),
📝 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.

  polygon: createPublicClient({
    chain: polygon,
    transport: fallback([
      http("https://polygon-bor-rpc.publicnode.com"),
      ...polygon.rpcUrls.default.http.map((v) => http(v))
    ])
  }),
🤖 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 `@src/lib/config.ts` around lines 491 - 497, The polygon public client is
mistakenly configured with chain: base; update the createPublicClient call that
constructs polygon to use chain: polygon instead (replace chain: base with
chain: polygon) so the polygon client uses the correct chain context (chain ID,
explorers, etc.); locate the polygon variable/entry where createPublicClient is
invoked and change the chain argument accordingly.
src/lib/libraries/assetSelection.ts (1)

63-63: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid Number(...) conversion in bigint sort comparators.

Casting bigint differences to number can lose precision for token-sized values and misorder assets, which breaks largest()/smallest() selection outcomes.

Suggested fix
   largest() {
     const values = AssetSelection.zip(this.values);
-    values.sort((a, b) => Number(b[0] - a[0]));
+    values.sort((a, b) => (b[0] > a[0] ? 1 : b[0] < a[0] ? -1 : 0));

     AssetSelection.takeFromArray(this.goal, values);

     this.sortedValues = AssetSelection.unzip(values);
     return this;
   }

   smallest() {
     const values = AssetSelection.zip(this.values);
-    values.sort((a, b) => Number(a[0] - b[0]));
+    values.sort((a, b) => (a[0] > b[0] ? 1 : a[0] < b[0] ? -1 : 0));

     AssetSelection.takeFromArray(this.goal, values);

     this.sortedValues = AssetSelection.unzip(values);
     return this;
   }

Also applies to: 73-73

🤖 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 `@src/lib/libraries/assetSelection.ts` at line 63, The comparator in the
values.sort calls currently casts a bigint difference to Number (values.sort((a,
b) => Number(b[0] - a[0]))) which can overflow and misorder large token amounts;
replace the Number(...) conversion with a bigint-safe comparator that returns
-1/0/1 based on comparing the bigint fields directly (e.g. compare b[0] and a[0]
with conditional branches or by testing b[0] - a[0] > 0 / < 0) so sorting for
largest()/smallest() works correctly; update both occurrences (the comparator at
the shown values.sort lines) to use this bigint-safe comparison.
src/lib/libraries/coreDeps.ts (2)

31-35: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Inconsistent address validation for polymer vs wormhole.

polymer uses a simple truthy check while wormhole uses isNonZeroAddress. If POLYMER_ORACLE[key] ever returns the zero address string "0x0000...", the truthy check passes and an invalid address gets pushed.

Proposed fix for consistent validation
     const polymer = POLYMER_ORACLE[key];
     const wormhole = WORMHOLE_ORACLE[key];
     const allowed: `0x${string}`[] = [];
-    if (polymer) allowed.push(polymer);
+    if (isNonZeroAddress(polymer)) allowed.push(polymer);
     if (isNonZeroAddress(wormhole)) allowed.push(wormhole);
📝 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.

    const polymer = POLYMER_ORACLE[key];
    const wormhole = WORMHOLE_ORACLE[key];
    const allowed: `0x${string}`[] = [];
    if (isNonZeroAddress(polymer)) allowed.push(polymer);
    if (isNonZeroAddress(wormhole)) allowed.push(wormhole);
🤖 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 `@src/lib/libraries/coreDeps.ts` around lines 31 - 35, The code inconsistently
validates addresses: POLYMER_ORACLE[key] (variable polymer) is only checked for
truthiness while WORMHOLE_ORACLE[key] uses isNonZeroAddress; change the polymer
push to use the same validation by calling isNonZeroAddress(polymer) before
allowed.push(polymer) so the zero address is rejected; update any related type
assumptions if needed and keep the same allowed: `0x${string}`[] typing.

43-47: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Same inconsistency in allowedOutputOracles.

Apply the same fix here for consistency.

Proposed fix
     const polymer = POLYMER_ORACLE[key];
     const wormhole = WORMHOLE_ORACLE[key];
     const allowed: `0x${string}`[] = [];
-    if (polymer) allowed.push(polymer);
+    if (isNonZeroAddress(polymer)) allowed.push(polymer);
     if (isNonZeroAddress(wormhole)) allowed.push(wormhole);
🤖 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 `@src/lib/libraries/coreDeps.ts` around lines 43 - 47, In allowedOutputOracles,
the checks for oracle addresses are inconsistent: polymer is pushed on a simple
truthy check while wormhole uses isNonZeroAddress; change the polymer check to
use isNonZeroAddress as well so both POLYMER_ORACLE[key] and
WORMHOLE_ORACLE[key] are validated the same way before pushing into the allowed
array (refer to allowedOutputOracles, POLYMER_ORACLE, WORMHOLE_ORACLE,
isNonZeroAddress, and the allowed variable).
src/lib/libraries/flowProgress.ts (1)

157-168: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Potential out-of-bounds access on flattenedInputs[0][0].

Line 158 checks flattenedInputs.length === 0 but doesn't verify that flattenedInputs[0] has elements. If flattenedInputs[0] is an empty array, accessing [0][0] at line 167 will return undefined, which may cause unexpected behavior when passed to getLockDetails.

Proposed defensive check
     const flattenedInputs = "originChainId" in order ? order.inputs : order.inputs[0]?.inputs;
-    if (!flattenedInputs || flattenedInputs.length === 0) return false;
+    if (!flattenedInputs || flattenedInputs.length === 0 || !flattenedInputs[0]?.[0]) return false;
🤖 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 `@src/lib/libraries/flowProgress.ts` around lines 157 - 168, The code can
access flattenedInputs[0][0] when flattenedInputs[0] is an empty array; update
the check in the function that uses flattenedInputs (the block that calls
inputChainClient.readContract with COMPACT and getLockDetails) to ensure the
first nested array actually has an element before using [0][0] — either find the
first non-empty entry in flattenedInputs (e.g., iterate flattenedInputs to pick
the first sub-array with length>0) or add an explicit guard like if
(!flattenedInputs[0] || flattenedInputs[0].length === 0) return false; so you
never pass undefined into getLockDetails via inputChainClient.readContract.
src/lib/libraries/intentExecution.ts (1)

29-32: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Inconsistent null-coalescing for signature payloads.

sponsorSignature.payload uses ?? "0x" fallback, but allocatorSignature.payload doesn't. If allocatorSignature.payload is undefined, encodeAbiParameters may fail or produce unexpected results.

Proposed fix
   return encodeAbiParameters(parseAbiParameters(["bytes", "bytes"]), [
     sponsorSignature.payload ?? "0x",
-    allocatorSignature.payload
+    allocatorSignature.payload ?? "0x"
   ]);
📝 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.

  return encodeAbiParameters(parseAbiParameters(["bytes", "bytes"]), [
    sponsorSignature.payload ?? "0x",
    allocatorSignature.payload ?? "0x"
  ]);
🤖 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 `@src/lib/libraries/intentExecution.ts` around lines 29 - 32, The ABI encoding
call is inconsistent: sponsorSignature.payload is defaulted but
allocatorSignature.payload is not; update the encodeAbiParameters call (using
encodeAbiParameters and parseAbiParameters) to provide a safe fallback for
allocatorSignature.payload as well (e.g., allocatorSignature.payload ?? "0x") so
both signature payloads are always a hex string and avoid undefined being passed
to encodeAbiParameters.
src/lib/libraries/intentFactory.ts (2)

63-67: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how output.context is typically initialized and when it would be "0x" vs non-empty
rg -n -B3 -A3 'context.*0x|\.context\s*=' --type=ts

Repository: lifinance/lintent

Length of output: 3820


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show surrounding code where output.context is modified
sed -n '1,120p' src/lib/libraries/intentFactory.ts

# Find where exclusivity override/newContext is computed or used
rg -n "newContext|paddedExclusiveFor|SAME_CHAIN_EXCLUSIVITY_SECONDS|exclusiv" src/lib/libraries/intentFactory.ts src/lib/libraries/intentList.ts

# Inspect context encoding/meaning in intentList
sed -n '120,240p' src/lib/libraries/intentList.ts

Repository: lifinance/lintent

Length of output: 10377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find where order outputs are created/mapped, focusing on context initialization
rg -n "outputs\\b|outputTokens|context\\s*:" src/lib/libraries/intentFactory.ts

# Show the sections around applyExclusivityOverride calls
rg -n "applyExclusivityOverride\\(" -n src/lib/libraries/intentFactory.ts
sed -n '140,320p' src/lib/libraries/intentFactory.ts

# Check how intentFactory inputs map to order outputs (look for context usage)
rg -n "TokenContext|outputTokens|context\\b" src/lib/libraries/intentFactory.ts

# Search across src/lib for common context literals
rg -n "context:\\s*\"0x(00)?\"|context:\\s*\"0x\"" src/lib -S

Repository: lifinance/lintent

Length of output: 7333


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find tests/fixtures referencing exclusivity context bytes or exclusiveFor behavior
rg -n "exclusiveFor|exclusiveUntil|e0|e1|SAME_CHAIN_EXCLUSIVITY_SECONDS|0xe0|0xe1" src tests -S

# Look specifically for context literals used in expected orders
rg -n 'context:\s*"(0x|0x00)"' src tests -S

# Inspect fixtures/orderFixtures and any helper that builds outputs with context
ls -la tests/fixtures || true
sed -n '1,120p' tests/fixtures/orderFixtures.ts

# Find helper makeMandateOutput etc. to see what context they set
rg -n "makeMandateOutput|make.*Output" tests -S

Repository: lifinance/lintent

Length of output: 11170


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for IntentFactory usage in tests
rg -n "new IntentFactory|IntentFactory\\b|applyExclusivityOverride\\b" tests src -S

# Search for "context" assertions in tests related to intents/order outputs
rg -n "output\\.?context|outputs\\s*\\[.*\\].*context|context\\s*:\\s*\"0x\"|context\\s*:\\s*\"0x00\"" tests -S

# If any test targets intentFactory, inspect nearby lines
rg -n "intentFactory\\.ts|intentFactory" tests -S

Repository: lifinance/lintent

Length of output: 1023


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' tests/unit/intentList.test.ts
sed -n '1,160p' tests/unit/orderValidationDeps.test.ts
sed -n '1,120p' tests/fixtures/mockQuote.ts
sed -n '1,120p' tests/unit/demoQuote.test.ts

Repository: lifinance/lintent

Length of output: 8462


Exclusivity override doesn’t apply when output.context is exactly "0x"

In src/lib/libraries/intentFactory.ts (lines 63-67), this guard prevents the exclusivity context from being written for outputs whose context is "0x":

for (const output of order.outputs) {
  if (output.context !== "0x") {
    output.context = newContext;
  }
}

Since this repo’s test/fixture orders use context: "0x" for default (non-exclusive) outputs (tests/fixtures/orderFixtures.ts), this likely makes same-chain exclusiveFor ineffective in the common/default case; the condition is likely inverted (or should be unconditional) depending on the intended sentinel for “unset” context.

🤖 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 `@src/lib/libraries/intentFactory.ts` around lines 63 - 67, The loop that sets
exclusivity currently skips outputs whose output.context === "0x", so the
exclusivity override never applies for the test-fixture sentinel; change the
guard in the block that iterates order.outputs so that it replaces the sentinel
instead of skipping it (i.e., set output.context = newContext when
output.context === "0x", or alternatively remove the conditional to always
assign if intended), targeting the loop that references order.outputs and the
output.context/newContext variables so exclusivityFor is correctly applied.

231-235: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Static analysis: transactionHash should be const and receipt is unused.

The linter correctly flags that transactionHash is never reassigned (should use const) and receipt is assigned but never used.

Proposed fix
-      let transactionHash = await depositAndRegisterCompact(intent, account(), this.walletClient);
+      const transactionHash = await depositAndRegisterCompact(intent, account(), this.walletClient);

-      const receipt = await getClient(inputTokens[0].token.chainId).waitForTransactionReceipt({
+      await getClient(inputTokens[0].token.chainId).waitForTransactionReceipt({
         hash: transactionHash
       });
📝 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.

      const transactionHash = await depositAndRegisterCompact(intent, account(), this.walletClient);

      await getClient(inputTokens[0].token.chainId).waitForTransactionReceipt({
        hash: transactionHash
      });
🧰 Tools
🪛 ESLint

[error] 231-231: 'transactionHash' is never reassigned. Use 'const' instead.

(prefer-const)


[error] 233-233: 'receipt' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)

🤖 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 `@src/lib/libraries/intentFactory.ts` around lines 231 - 235, Change
transactionHash to a const since it is never reassigned (assign the result of
depositAndRegisterCompact to const transactionHash) and remove the unused
receipt variable created from getClient(...).waitForTransactionReceipt or, if
the receipt is needed, use it; specifically update the code around the
depositAndRegisterCompact call and the subsequent
getClient(...).waitForTransactionReceipt call (which currently assigns to
receipt) so that either the receipt line is deleted or its value is consumed,
keeping symbols transactionHash, depositAndRegisterCompact, account(),
this.walletClient, getClient, and inputTokens intact.

In 1:1 demo mode the quote request must not send metadata.exclusiveFor
(the integrator key drives the 1:1 quote), but the on-chain intent must
still be exclusive to the demo solver so it fills 1:1 via quick fallback.

- demoQuote: demo mode returns exclusiveFor undefined (quote omits it)
- IssueIntent: force DEMO_EXCLUSIVE_SOLVER on the order in demo mode
- Update tests/comments accordingly

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown

🚀 Preview deployed!

Worker: lintent-pr-54
URL: https://lintent-pr-54.li-fi374.workers.dev

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

🚀 Preview deployed!

Worker: lintent-pr-54
URL: https://lintent-pr-54.li-fi374.workers.dev

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.

1 participant