Skip to content

Feat/add support for hyperliquid transactions#1

Open
RyukTheCoder wants to merge 3 commits intonextfrom
feat/add-support-for-hyperliquid-transactions
Open

Feat/add support for hyperliquid transactions#1
RyukTheCoder wants to merge 3 commits intonextfrom
feat/add-support-for-hyperliquid-transactions

Conversation

@RyukTheCoder
Copy link
Copy Markdown
Owner

@RyukTheCoder RyukTheCoder commented Apr 19, 2026

This pull request introduces comprehensive support for Hyperliquid transactions within the Rango client.

Key changes include:

  • Hyperliquid Transaction Execution: New actions and utilities are added to handle the execution of Hyperliquid-specific transactions (e.g., withdrawals, USD sends). This involves using an EVM signer to sign typed data, splitting the signature, and submitting the transaction to the Hyperliquid exchange API.
  • Hyperliquid Transaction Status Checking: A new action is implemented to check the status of Hyperliquid transactions by polling the Hyperliquid explorer API using the wallet address and transaction nonce to retrieve the transaction hash.
  • Integration with Queue Manager: Hyperliquid transaction execution and status checking are integrated into the existing Rango queue management system, ensuring proper scheduling and state transitions for these transactions.
  • EVM Signer Enhancement: The EVM signer is updated to support signTypedData, which is essential for signing Hyperliquid transactions.
  • Wallet Compatibility: Multiple EVM-compatible wallet providers (e.g., Bitget, Brave, Coinbase, MetaMask, TrustWallet) are updated to recognize and support Hyperliquid, allowing them to connect and sign Hyperliquid transactions.
  • Account Management: The wallet store now automatically adds Hyperliquid accounts for EVM wallets that support the designated Hyperliquid signing network (Arbitrum).

These changes enable users to seamlessly perform and track Hyperliquid transactions through the Rango client.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 19, 2026

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'Feat/add support for hyperliquid transactions' directly and clearly summarizes the main change: adding Hyperliquid transaction support across the codebase.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/add-support-for-hyperliquid-transactions

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
queue-manager/rango-preset/src/actions/scheduleNextStep.ts (1)

43-53: ⚠️ Potential issue | 🟠 Major

Route resumed Hyperliquid steps to Hyperliquid status checker.

When currentStep.executedTransactionId exists, Line 52 always schedules CHECK_TRANSACTION_STATUS. For Hyperliquid, this should schedule CHECK_HYPERLIQUID_TRANSACTION_STATUS; otherwise resumed swaps can poll the wrong action path.

Suggested fix
-    if (currentStep?.executedTransactionId) {
-      schedule(SwapActionTypes.CHECK_TRANSACTION_STATUS);
+    if (currentStep?.executedTransactionId) {
+      if (currentStep.fromBlockchain === TransactionType.HYPERLIQUID) {
+        schedule(SwapActionTypes.CHECK_HYPERLIQUID_TRANSACTION_STATUS);
+      } else {
+        schedule(SwapActionTypes.CHECK_TRANSACTION_STATUS);
+      }
       return next();
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@queue-manager/rango-preset/src/actions/scheduleNextStep.ts` around lines 43 -
53, When resuming a step that already has currentStep.executedTransactionId we
always schedule SwapActionTypes.CHECK_TRANSACTION_STATUS but must route
Hyperliquid transactions to the Hyperliquid status checker; update the branch
that handles currentStep.executedTransactionId to check
currentStep.fromBlockchain (compare to TransactionType.HYPERLIQUID) and call
schedule(SwapActionTypes.CHECK_HYPERLIQUID_TRANSACTION_STATUS) for Hyperliquid,
otherwise schedule(SwapActionTypes.CHECK_TRANSACTION_STATUS) so resumed
Hyperliquid swaps poll the correct action.
🧹 Nitpick comments (6)
wallets/shared/src/rango.ts (1)

176-176: Add a short rationale comment for this mapping.

Line 176 is easy to misinterpret. A one-line note explaining why Hyperliquid signing is intentionally mapped to Networks.ARBITRUM would reduce future regressions.

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

In `@wallets/shared/src/rango.ts` at line 176, Add a one-line rationale comment
above the HYPERLIQUID_SIGN_NETWORK constant explaining why Hyperliquid signing
maps to Networks.ARBITRUM (e.g., that Hyperliquid uses Arbitrum-compatible
signing or that the Hyperliquid chain is signed using Arbitrum keys) so future
readers understand this intentional mapping; update the comment near the
HYPERLIQUID_SIGN_NETWORK export to mention the compatibility/intent and any
relevant reference (Hyperliquid signing behavior) to prevent accidental change.
queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/types.ts (1)

1-5: Tighten typed-data typing to prevent invalid EIP-712 payloads.

The current type uses unknown and loose Record<string, unknown> patterns, which removes compile-time checks for signing inputs. The proposed refactor below is incomplete—it should use TypedDataDomain for the domain field (not Record<string, unknown>) and Record<string, any> for value, matching ethers v6's actual requirements.

Corrected type-tightening
+import type { TypedDataDomain, TypedDataField } from 'ethers';
+
+type TypedDataField = {
+  name: string;
+  type: string;
+};
+
 export type EthersV6CompatibleTypedData = {
-  domain: unknown;
-  types: Record<string, unknown>;
-  value: Record<string, unknown>;
+  domain: TypedDataDomain;
+  types: Record<string, Array<TypedDataField>>;
+  value: Record<string, any>;
 };

Alternatively, consider reusing the existing TypedData type from signers/signer-evm/src/types.ts, which already has the correct shape.

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

In
`@queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/types.ts`
around lines 1 - 5, Update the EthersV6CompatibleTypedData type to tighten
EIP-712 typing: replace the loose domain and value shapes by using
TypedDataDomain for the domain field and use Record<string, any> for value (or
simply reuse the existing TypedData type if available), keeping types as the
appropriate record; modify the EthersV6CompatibleTypedData declaration to import
and reference TypedDataDomain (or TypedData) and change value to Record<string,
any> so signing inputs align with ethers v6 requirements.
queue-manager/rango-preset/src/helpers.ts (1)

791-791: Prefer network-based wallet lookup over transaction-type lookup.

Using step.hyperliquidTransaction?.type as the wallet-map key is brittle. For consistency with other branches, key this via the step network (fromBlockchain) when Hyperliquid tx exists.

Refactor sketch
-    swap.wallets[step.hyperliquidTransaction?.type || ''] ||
+    (step.hyperliquidTransaction
+      ? swap.wallets[step.fromBlockchain]
+      : null) ||
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@queue-manager/rango-preset/src/helpers.ts` at line 791, The lookup currently
uses swap.wallets[step.hyperliquidTransaction?.type || ''] which is brittle;
change the key to use the network field when a Hyperliquid transaction exists
(e.g. step.hyperliquidTransaction?.fromBlockchain) and fall back to the normal
step.fromBlockchain or existing fallback used elsewhere; update the expression
that references swap.wallets to use step.hyperliquidTransaction?.fromBlockchain
|| step.fromBlockchain (or the same fallback string used in other branches) so
the wallet lookup is network-based instead of transaction-type-based.
queue-manager/rango-preset/src/queueDef.ts (1)

35-38: Please add a queue-definition test for the two new action registrations.

These keys are orchestration-critical; a focused assertion around swapQueueDef.actions helps prevent silent regressions.

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

In `@queue-manager/rango-preset/src/queueDef.ts` around lines 35 - 38, Add a unit
test that asserts the queue definition registers the two new actions: verify
swapQueueDef.actions has keys SwapActionTypes.EXECUTE_HYPERLIQUID_TRANSACTION
and SwapActionTypes.CHECK_HYPERLIQUID_TRANSACTION_STATUS and that their values
are the expected handlers (executeHyperliquidTransaction and
checkHyperliquidTransactionStatus respectively); import swapQueueDef,
SwapActionTypes, executeHyperliquidTransaction, and
checkHyperliquidTransactionStatus from the module under test and use focused
assertions (e.g., hasOwnProperty/has/key and strict equality against the handler
functions) so this test will fail if those registrations are removed or renamed.
wallets/provider-safepal/src/constants.ts (1)

34-37: Consider centralizing EVM+Hyperliquid chain composition.

This merge logic is now repeated across multiple provider constants. A shared helper would reduce drift risk if chain-grouping rules change later.

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

In `@wallets/provider-safepal/src/constants.ts` around lines 34 - 37, Multiple
provider constants duplicate the same merge logic for EVM + Hyperliquid chains;
extract that logic into a single helper (e.g., composeEvmAndHyperliquid or
getEvmHyperliquidChains) and replace occurrences of the inline array in
getSupportedChains with a call to that helper. The helper should accept the same
parameter (allBlockchains: BlockchainMeta[]) and internally call
evmBlockchains(allBlockchains) and hyperliquidBlockchain(allBlockchains) to
return the combined array; update every provider constant that currently uses
getSupportedChains: (allBlockchains) => [...evmBlockchains(allBlockchains),
...hyperliquidBlockchain(allBlockchains)] to instead call the new helper.
queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/checkHyperliquidTransactionStatus.ts (1)

83-85: Consider bounded retry/backoff for long-lived transaction polling

Current fixed-interval retry is okay for happy path, but adding a cap/backoff here improves resilience under explorer incidents.

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

In
`@queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/checkHyperliquidTransactionStatus.ts`
around lines 83 - 85, The current fixed-interval retry in
checkHyperliquidTransactionStatus (using
delay(INTERVAL_FOR_CHECK_HYPERLIQUID_TRANSACTION_STATUS); retry(); return;)
should be replaced with a bounded backoff: add a retry counter (e.g., attempts
or retryCount) and a MAX_RETRIES constant, compute an increasing delay
(exponential backoff with optional jitter using
INTERVAL_FOR_CHECK_HYPERLIQUID_TRANSACTION_STATUS as the base) and call retry()
only while attempts < MAX_RETRIES; when max is reached, stop polling and
surface/return a failure (or emit a timeout/error) so the caller can handle it.
Ensure the new logic updates the retry counter on each loop and uses
INTERVAL_FOR_CHECK_HYPERLIQUID_TRANSACTION_STATUS as the backoff base.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/checkHyperliquidTransactionStatus.ts`:
- Around line 74-79: The warning call in checkHyperliquidTransactionStatus is
logging the full swap object (pendingSwap: swap) which may contain PII; instead,
modify the warn(...) tags to avoid including the entire swap payload—replace
pendingSwap: swap with a minimal identifier such as pendingSwapId: swap.id (or
pendingSwapNonce: swap.nonce) and remove or redact any direct user identifiers
(e.g., walletAddress) in the tags; update the warn(...) invocation so it only
emits non-sensitive fields and keep the same tag keys for traceability.

In
`@queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/utils.ts`:
- Around line 39-43: The find predicate that computes currentUserDetailsItem
assumes every entry in userDetailsJson.txs has an action and directly accesses
item.action.type/time, which can throw; update the predicate in the function
that uses currentUserDetailsItem to first guard that item and item.action are
present (e.g., check item && item.action or use optional chaining) before
comparing action.type and action.time against 'withdraw3'|'usdSend' and nonce,
and if missing return a typed error/result instead of letting polling crash so
callers can handle malformed explorer items.
- Around line 17-23: The fetch call that assigns userDetailsResponse should use
a timeout via an AbortController (or equivalent) and must check the HTTP status
before parsing: wrap the POST to HYPERLIQUID_EXPLORER_API_URL in a request that
aborts after a configured timeout, call response.ok (or check status) and
throw/return a clear error for non-2xx responses instead of assuming parse
errors, and ensure the calling code (e.g., whichever function in utils.ts that
awaits userDetailsResponse) handles abort/timeouts and non-2xx errors distinctly
so polling won't hang or misclassify failures.

In
`@queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/executeHyperliquidTransaction.ts`:
- Around line 153-165: The code calls handleErr when
initiateWithdrawalResponse.val.status !== 'ok' but then continues to call
onSuccessfulFinish(), advancing the queue on failure; modify the control flow in
executeHyperliquidTransaction so that after creating and invoking handleErr for
the failed initiation (reference initiateWithdrawalResponse and handleErr) the
function returns or otherwise stops execution (do not call onSuccessfulFinish)
to prevent advancing the queue on error; ensure any necessary cleanup or error
propagation still occurs before the early return.

In
`@queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/utils.ts`:
- Around line 89-107: The API call in initiateWithdrawalResponse (to
HYPERLIQUID_EXCHANGE_API_URL) needs a timeout and proper HTTP-status/error
handling: wrap the fetch with an AbortController to enforce a short timeout
(e.g., 3–10s) and abort if exceeded, check initiateWithdrawalResponse.ok after
fetch and if false read the error body (or use status/statusText) and return an
Err result instead of Ok, and wrap the JSON parsing of
initiateWithdrawalResponseJson in a try/catch to handle invalid/non-JSON
responses and return an Err with useful context (including HTTP status or abort
error) — ensure callers still get Ok(...) only for successful 2xx responses.

In `@queue-manager/rango-preset/src/shared.ts`:
- Line 256: The wallet lookup is using the transaction type
(step.hyperliquidTransaction?.type) which is wrong and causes WalletMissing;
change the key to the Hyperliquid network identifier on the transaction (e.g.,
step.hyperliquidTransaction?.network or the appropriate network/chain field on
hyperliquidTransaction) when indexing swap.wallets so swap.wallets[networkKey ||
''] is used instead of swap.wallets[step.hyperliquidTransaction?.type || ''];
update any null/undefined fallback handling to preserve previous behavior and
ensure WalletMissing no longer occurs for valid Hyperliquid steps.

---

Outside diff comments:
In `@queue-manager/rango-preset/src/actions/scheduleNextStep.ts`:
- Around line 43-53: When resuming a step that already has
currentStep.executedTransactionId we always schedule
SwapActionTypes.CHECK_TRANSACTION_STATUS but must route Hyperliquid transactions
to the Hyperliquid status checker; update the branch that handles
currentStep.executedTransactionId to check currentStep.fromBlockchain (compare
to TransactionType.HYPERLIQUID) and call
schedule(SwapActionTypes.CHECK_HYPERLIQUID_TRANSACTION_STATUS) for Hyperliquid,
otherwise schedule(SwapActionTypes.CHECK_TRANSACTION_STATUS) so resumed
Hyperliquid swaps poll the correct action.

---

Nitpick comments:
In
`@queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/checkHyperliquidTransactionStatus.ts`:
- Around line 83-85: The current fixed-interval retry in
checkHyperliquidTransactionStatus (using
delay(INTERVAL_FOR_CHECK_HYPERLIQUID_TRANSACTION_STATUS); retry(); return;)
should be replaced with a bounded backoff: add a retry counter (e.g., attempts
or retryCount) and a MAX_RETRIES constant, compute an increasing delay
(exponential backoff with optional jitter using
INTERVAL_FOR_CHECK_HYPERLIQUID_TRANSACTION_STATUS as the base) and call retry()
only while attempts < MAX_RETRIES; when max is reached, stop polling and
surface/return a failure (or emit a timeout/error) so the caller can handle it.
Ensure the new logic updates the retry counter on each loop and uses
INTERVAL_FOR_CHECK_HYPERLIQUID_TRANSACTION_STATUS as the backoff base.

In
`@queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/types.ts`:
- Around line 1-5: Update the EthersV6CompatibleTypedData type to tighten
EIP-712 typing: replace the loose domain and value shapes by using
TypedDataDomain for the domain field and use Record<string, any> for value (or
simply reuse the existing TypedData type if available), keeping types as the
appropriate record; modify the EthersV6CompatibleTypedData declaration to import
and reference TypedDataDomain (or TypedData) and change value to Record<string,
any> so signing inputs align with ethers v6 requirements.

In `@queue-manager/rango-preset/src/helpers.ts`:
- Line 791: The lookup currently uses
swap.wallets[step.hyperliquidTransaction?.type || ''] which is brittle; change
the key to use the network field when a Hyperliquid transaction exists (e.g.
step.hyperliquidTransaction?.fromBlockchain) and fall back to the normal
step.fromBlockchain or existing fallback used elsewhere; update the expression
that references swap.wallets to use step.hyperliquidTransaction?.fromBlockchain
|| step.fromBlockchain (or the same fallback string used in other branches) so
the wallet lookup is network-based instead of transaction-type-based.

In `@queue-manager/rango-preset/src/queueDef.ts`:
- Around line 35-38: Add a unit test that asserts the queue definition registers
the two new actions: verify swapQueueDef.actions has keys
SwapActionTypes.EXECUTE_HYPERLIQUID_TRANSACTION and
SwapActionTypes.CHECK_HYPERLIQUID_TRANSACTION_STATUS and that their values are
the expected handlers (executeHyperliquidTransaction and
checkHyperliquidTransactionStatus respectively); import swapQueueDef,
SwapActionTypes, executeHyperliquidTransaction, and
checkHyperliquidTransactionStatus from the module under test and use focused
assertions (e.g., hasOwnProperty/has/key and strict equality against the handler
functions) so this test will fail if those registrations are removed or renamed.

In `@wallets/provider-safepal/src/constants.ts`:
- Around line 34-37: Multiple provider constants duplicate the same merge logic
for EVM + Hyperliquid chains; extract that logic into a single helper (e.g.,
composeEvmAndHyperliquid or getEvmHyperliquidChains) and replace occurrences of
the inline array in getSupportedChains with a call to that helper. The helper
should accept the same parameter (allBlockchains: BlockchainMeta[]) and
internally call evmBlockchains(allBlockchains) and
hyperliquidBlockchain(allBlockchains) to return the combined array; update every
provider constant that currently uses getSupportedChains: (allBlockchains) =>
[...evmBlockchains(allBlockchains), ...hyperliquidBlockchain(allBlockchains)] to
instead call the new helper.

In `@wallets/shared/src/rango.ts`:
- Line 176: Add a one-line rationale comment above the HYPERLIQUID_SIGN_NETWORK
constant explaining why Hyperliquid signing maps to Networks.ARBITRUM (e.g.,
that Hyperliquid uses Arbitrum-compatible signing or that the Hyperliquid chain
is signed using Arbitrum keys) so future readers understand this intentional
mapping; update the comment near the HYPERLIQUID_SIGN_NETWORK export to mention
the compatibility/intent and any relevant reference (Hyperliquid signing
behavior) to prevent accidental change.
🪄 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 Plus

Run ID: aafe4bc7-5e95-48e3-868f-0c6af53530c8

📥 Commits

Reviewing files that changed from the base of the PR and between d6622c2 and 81b17a3.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (82)
  • queue-manager/queue-manager-demo/package.json
  • queue-manager/rango-preset/package.json
  • queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/checkHyperliquidTransactionStatus.ts
  • queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/constants.ts
  • queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/index.ts
  • queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/types.ts
  • queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/utils.ts
  • queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/constants.ts
  • queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/executeHyperliquidTransaction.ts
  • queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/index.ts
  • queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/types.ts
  • queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/utils.ts
  • queue-manager/rango-preset/src/actions/scheduleNextStep.ts
  • queue-manager/rango-preset/src/helpers.ts
  • queue-manager/rango-preset/src/queueDef.ts
  • queue-manager/rango-preset/src/shared.ts
  • queue-manager/rango-preset/src/types.ts
  • signers/signer-cosmos/package.json
  • signers/signer-evm/package.json
  • signers/signer-evm/src/signer.ts
  • signers/signer-evm/src/types.ts
  • signers/signer-solana/package.json
  • signers/signer-starknet/package.json
  • signers/signer-sui/package.json
  • signers/signer-ton/package.json
  • signers/signer-tron/package.json
  • wallets/core/package.json
  • wallets/core/src/legacy/types.ts
  • wallets/provider-binance/package.json
  • wallets/provider-bitget/package.json
  • wallets/provider-bitget/src/constants.ts
  • wallets/provider-braavos/package.json
  • wallets/provider-brave/package.json
  • wallets/provider-brave/src/constants.ts
  • wallets/provider-coin98/package.json
  • wallets/provider-coin98/src/constants.ts
  • wallets/provider-coinbase/package.json
  • wallets/provider-coinbase/src/constants.ts
  • wallets/provider-cosmostation/package.json
  • wallets/provider-cosmostation/src/constants.ts
  • wallets/provider-default/package.json
  • wallets/provider-enkrypt/package.json
  • wallets/provider-enkrypt/src/constants.ts
  • wallets/provider-exodus/package.json
  • wallets/provider-keplr/package.json
  • wallets/provider-leap-cosmos/package.json
  • wallets/provider-ledger/package.json
  • wallets/provider-math-wallet/package.json
  • wallets/provider-math-wallet/src/constants.ts
  • wallets/provider-metamask/package.json
  • wallets/provider-metamask/src/constants.ts
  • wallets/provider-okx/package.json
  • wallets/provider-phantom/package.json
  • wallets/provider-rabby/package.json
  • wallets/provider-rabby/src/constants.ts
  • wallets/provider-ready/package.json
  • wallets/provider-safe/package.json
  • wallets/provider-safepal/package.json
  • wallets/provider-safepal/src/constants.ts
  • wallets/provider-slush/package.json
  • wallets/provider-solflare/package.json
  • wallets/provider-taho/package.json
  • wallets/provider-tokenpocket/package.json
  • wallets/provider-tokenpocket/src/constants.ts
  • wallets/provider-tomo/package.json
  • wallets/provider-tomo/src/constants.ts
  • wallets/provider-tonconnect/package.json
  • wallets/provider-trezor/package.json
  • wallets/provider-tron-link/package.json
  • wallets/provider-trustwallet/package.json
  • wallets/provider-trustwallet/src/constants.ts
  • wallets/provider-unisat/package.json
  • wallets/provider-walletconnect-2/package.json
  • wallets/provider-xdefi/package.json
  • wallets/provider-xverse/package.json
  • wallets/react/package.json
  • wallets/shared/package.json
  • wallets/shared/src/rango.ts
  • widget/embedded/package.json
  • widget/embedded/src/utils/wallets.ts
  • widget/playground/package.json
  • widget/ui/package.json

Comment on lines +74 to +79
warn(new Error('check Hyperliquid transaction status Error'), {
tags: {
type: 'request-error',
requestBody: { type: 'userDetails', user: walletAddress, nonce },
pendingSwap: swap,
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid logging full swap payload in warning tags

Line 78 logs pendingSwap: swap, which can expose user identifiers and transaction metadata in logs.

Proposed fix
       warn(new Error('check Hyperliquid transaction status Error'), {
         tags: {
           type: 'request-error',
-          requestBody: { type: 'userDetails', user: walletAddress, nonce },
-          pendingSwap: swap,
+          requestType: 'userDetails',
+          nonce,
+          walletAddressSuffix: walletAddress.slice(-6),
         },
       });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/checkHyperliquidTransactionStatus.ts`
around lines 74 - 79, The warning call in checkHyperliquidTransactionStatus is
logging the full swap object (pendingSwap: swap) which may contain PII; instead,
modify the warn(...) tags to avoid including the entire swap payload—replace
pendingSwap: swap with a minimal identifier such as pendingSwapId: swap.id (or
pendingSwapNonce: swap.nonce) and remove or redact any direct user identifiers
(e.g., walletAddress) in the tags; update the warn(...) invocation so it only
emits non-sensitive fields and keep the same tag keys for traceability.

Comment on lines +17 to +23
userDetailsResponse = await fetch(HYPERLIQUID_EXPLORER_API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ type: 'userDetails', user: walletAddress }),
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add timeout and HTTP status handling to explorer request

Line 17 awaits fetch without timeout, and non-2xx responses are treated like parse issues. This can hang polling or blur failure classification.

Proposed fix
   let userDetailsResponse: Response;
+  const controller = new AbortController();
+  const timeoutId = setTimeout(() => controller.abort(), 10_000);
   try {
     userDetailsResponse = await fetch(HYPERLIQUID_EXPLORER_API_URL, {
       method: 'POST',
+      signal: controller.signal,
       headers: {
         'Content-Type': 'application/json',
       },
       body: JSON.stringify({ type: 'userDetails', user: walletAddress }),
     });
+    if (!userDetailsResponse.ok) {
+      return new Err(GetHyperliquidTransactionHashError.FETCH_ERROR);
+    }
   } catch {
     return new Err(GetHyperliquidTransactionHashError.FETCH_ERROR);
+  } finally {
+    clearTimeout(timeoutId);
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/utils.ts`
around lines 17 - 23, The fetch call that assigns userDetailsResponse should use
a timeout via an AbortController (or equivalent) and must check the HTTP status
before parsing: wrap the POST to HYPERLIQUID_EXPLORER_API_URL in a request that
aborts after a configured timeout, call response.ok (or check status) and
throw/return a clear error for non-2xx responses instead of assuming parse
errors, and ensure the calling code (e.g., whichever function in utils.ts that
awaits userDetailsResponse) handles abort/timeouts and non-2xx errors distinctly
so polling won't hang or misclassify failures.

Comment on lines +39 to +43
const currentUserDetailsItem = userDetailsJson.txs.find(
(item) =>
(item.action.type === 'withdraw3' || item.action.type === 'usdSend') &&
item.action.time === nonce
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Guard malformed explorer items before nested property access

Line 41/42 can throw at runtime if any txs entry is missing action. This crashes polling instead of returning a typed error.

Proposed fix
-  const currentUserDetailsItem = userDetailsJson.txs.find(
-    (item) =>
-      (item.action.type === 'withdraw3' || item.action.type === 'usdSend') &&
-      item.action.time === nonce
-  );
+  const currentUserDetailsItem = userDetailsJson.txs.find((item) => {
+    const action = item?.action;
+    return (
+      (action?.type === 'withdraw3' || action?.type === 'usdSend') &&
+      action?.time === nonce &&
+      typeof item?.hash === 'string'
+    );
+  });
📝 Committable suggestion

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

Suggested change
const currentUserDetailsItem = userDetailsJson.txs.find(
(item) =>
(item.action.type === 'withdraw3' || item.action.type === 'usdSend') &&
item.action.time === nonce
);
const currentUserDetailsItem = userDetailsJson.txs.find((item) => {
const action = item?.action;
return (
(action?.type === 'withdraw3' || action?.type === 'usdSend') &&
action?.time === nonce &&
typeof item?.hash === 'string'
);
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/utils.ts`
around lines 39 - 43, The find predicate that computes currentUserDetailsItem
assumes every entry in userDetailsJson.txs has an action and directly accesses
item.action.type/time, which can throw; update the predicate in the function
that uses currentUserDetailsItem to first guard that item and item.action are
present (e.g., check item && item.action or use optional chaining) before
comparing action.type and action.time against 'withdraw3'|'usdSend' and nonce,
and if missing return a typed error/result instead of letting polling crash so
callers can handle malformed explorer items.

Comment on lines +153 to +165
if (initiateWithdrawalResponse.val.status !== 'ok') {
handleErr(
new Err({
nextStatus: 'failed',
nextStepStatus: 'failed',
message: 'Unexpected Error: Failed to initiate withdrawal.',
details: undefined,
errorCode: 'CLIENT_UNEXPECTED_BEHAVIOUR',
})
);
}

onSuccessfulFinish();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Stop flow after failed withdrawal initiation status

Line 153-163 marks an error, but execution still reaches Line 165 (onSuccessfulFinish()), advancing the queue on failure.

Proposed fix
   if (initiateWithdrawalResponse.val.status !== 'ok') {
     handleErr(
       new Err({
         nextStatus: 'failed',
         nextStepStatus: 'failed',
         message: 'Unexpected Error: Failed to initiate withdrawal.',
         details: undefined,
         errorCode: 'CLIENT_UNEXPECTED_BEHAVIOUR',
       })
     );
+    return;
   }
 
   onSuccessfulFinish();
📝 Committable suggestion

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

Suggested change
if (initiateWithdrawalResponse.val.status !== 'ok') {
handleErr(
new Err({
nextStatus: 'failed',
nextStepStatus: 'failed',
message: 'Unexpected Error: Failed to initiate withdrawal.',
details: undefined,
errorCode: 'CLIENT_UNEXPECTED_BEHAVIOUR',
})
);
}
onSuccessfulFinish();
if (initiateWithdrawalResponse.val.status !== 'ok') {
handleErr(
new Err({
nextStatus: 'failed',
nextStepStatus: 'failed',
message: 'Unexpected Error: Failed to initiate withdrawal.',
details: undefined,
errorCode: 'CLIENT_UNEXPECTED_BEHAVIOUR',
})
);
return;
}
onSuccessfulFinish();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/executeHyperliquidTransaction.ts`
around lines 153 - 165, The code calls handleErr when
initiateWithdrawalResponse.val.status !== 'ok' but then continues to call
onSuccessfulFinish(), advancing the queue on failure; modify the control flow in
executeHyperliquidTransaction so that after creating and invoking handleErr for
the failed initiation (reference initiateWithdrawalResponse and handleErr) the
function returns or otherwise stops execution (do not call onSuccessfulFinish)
to prevent advancing the queue on error; ensure any necessary cleanup or error
propagation still occurs before the early return.

Comment on lines +89 to +107
const initiateWithdrawalResponse = await fetch(
HYPERLIQUID_EXCHANGE_API_URL,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action,
signature,
nonce,
}),
}
);

const initiateWithdrawalResponseJson =
await initiateWithdrawalResponse.json();

return Ok(initiateWithdrawalResponseJson);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Harden withdrawal API call with timeout and HTTP status check

Line 89 call has no timeout and treats any parseable JSON as success. This weakens failure handling for exchange API outages/error responses.

Proposed fix
 export async function initiateWithdrawalRequest(
   action: HyperliquidTransaction['action'],
   signature: Signature,
   nonce: HyperliquidTransaction['nonce']
 ): Promise<Result<{ status: string }, NextTransactionStateError>> {
+  const controller = new AbortController();
+  const timeoutId = setTimeout(() => controller.abort(), 10_000);
   try {
     const initiateWithdrawalResponse = await fetch(
       HYPERLIQUID_EXCHANGE_API_URL,
       {
         method: 'POST',
+        signal: controller.signal,
         headers: {
           'Content-Type': 'application/json',
         },
         body: JSON.stringify({
           action,
           signature,
           nonce,
         }),
       }
     );
+    if (!initiateWithdrawalResponse.ok) {
+      return new Err({
+        nextStatus: 'failed',
+        nextStepStatus: 'failed',
+        message: 'Unexpected Error: Failed to initiate withdrawal.',
+        details: undefined,
+        errorCode: 'CLIENT_UNEXPECTED_BEHAVIOUR',
+      });
+    }
 
     const initiateWithdrawalResponseJson =
       await initiateWithdrawalResponse.json();
 
     return Ok(initiateWithdrawalResponseJson);
   } catch {
     return new Err({
       nextStatus: 'failed',
       nextStepStatus: 'failed',
       message: 'Unexpected Error: Failed to initiate withdrawal.',
       details: undefined,
       errorCode: 'CLIENT_UNEXPECTED_BEHAVIOUR',
     });
+  } finally {
+    clearTimeout(timeoutId);
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/utils.ts`
around lines 89 - 107, The API call in initiateWithdrawalResponse (to
HYPERLIQUID_EXCHANGE_API_URL) needs a timeout and proper HTTP-status/error
handling: wrap the fetch with an AbortController to enforce a short timeout
(e.g., 3–10s) and abort if exceeded, check initiateWithdrawalResponse.ok after
fetch and if false read the error body (or use status/statusText) and return an
Err result instead of Ok, and wrap the JSON parsing of
initiateWithdrawalResponseJson in a try/catch to handle invalid/non-JSON
responses and return an Err with useful context (including HTTP status or abort
error) — ensure callers still get Ok(...) only for successful 2xx responses.

swap.wallets[step.suiTransaction?.blockChain || ''] ||
swap.wallets[step.xrplTransaction?.blockChain || ''] ||
swap.wallets[step.stellarTransaction?.blockChain || ''] ||
swap.wallets[step.hyperliquidTransaction?.type || ''] ||
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Use Hyperliquid network key (not tx type) for wallet lookup.

On Line 256, wallet resolution uses step.hyperliquidTransaction?.type as the key into swap.wallets. That key is transaction type metadata, not the blockchain/network key, so valid Hyperliquid steps can fail with WalletMissing.

💡 Proposed fix
-    swap.wallets[step.hyperliquidTransaction?.type || ''] ||
+    (step.hyperliquidTransaction
+      ? swap.wallets[HYPERLIQUID_SIGN_NETWORK]
+      : null) ||
📝 Committable suggestion

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

Suggested change
swap.wallets[step.hyperliquidTransaction?.type || ''] ||
(step.hyperliquidTransaction
? swap.wallets[HYPERLIQUID_SIGN_NETWORK]
: null) ||
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@queue-manager/rango-preset/src/shared.ts` at line 256, The wallet lookup is
using the transaction type (step.hyperliquidTransaction?.type) which is wrong
and causes WalletMissing; change the key to the Hyperliquid network identifier
on the transaction (e.g., step.hyperliquidTransaction?.network or the
appropriate network/chain field on hyperliquidTransaction) when indexing
swap.wallets so swap.wallets[networkKey || ''] is used instead of
swap.wallets[step.hyperliquidTransaction?.type || '']; update any null/undefined
fallback handling to preserve previous behavior and ensure WalletMissing no
longer occurs for valid Hyperliquid steps.

@kody-ai
Copy link
Copy Markdown

kody-ai Bot commented Apr 19, 2026

@kody start-review

@kody-ai
Copy link
Copy Markdown

kody-ai Bot commented Apr 19, 2026

Code Review Completed! 🔥

The code review was successfully completed based on your current configurations.

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the @kody start-review command at the root of your PR.

  • Validate Business Logic: Ask Kody to validate your code against business rules by adding a comment with the @kody -v business-logic command.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug
Performance
Security
Cross File
Business Logic

Access your configuration settings here.

swap.wallets[step.tonTransaction?.blockChain || ''] ||
swap.wallets[step.suiTransaction?.blockChain || ''] ||
swap.wallets[step.xrplTransaction?.blockChain || ''] ||
swap.wallets[step.hyperliquidTransaction?.type || ''] ||
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Bug high

Incorrect property used for Hyperliquid wallet lookup in multiple files. The code incorrectly uses hyperliquidTransaction.type instead of hyperliquidTransaction.blockChain to look up wallets in swap.wallets. Since the wallets map is keyed by blockchain names, this causes wallet lookups to fail for Hyperliquid transactions.

This issue appears in multiple locations:

  • queue-manager/rango-preset/src/helpers.ts: Lines 791-791
  • queue-manager/rango-preset/src/shared.ts: Lines 256-256
    Replace all instances of hyperliquidTransaction?.type with hyperliquidTransaction?.blockChain for wallet lookups to ensure consistent behavior with other transaction types.
    swap.wallets[step.hyperliquidTransaction?.blockChain || ''] ||
Prompt for LLM

File queue-manager/rango-preset/src/helpers.ts:

Line 791:

In the file `queue-manager/rango-preset/src/helpers.ts`, I've identified a bug in the `isTxAlreadyCreated` function. When checking for a wallet for a `hyperliquidTransaction`, the code uses `step.hyperliquidTransaction.type` as the key for the `swap.wallets` map. This is incorrect because the `wallets` map is keyed by blockchain names (like 'ARBITRUM'), whereas `.type` refers to the transaction's type (like 'HYPERLIQUID'). All other transaction types in this function correctly use the `.blockChain` property for this lookup. This will cause the wallet lookup to fail for Hyperliquid transactions. Please provide a fix that uses the correct property, `blockChain`, for the lookup, consistent with the other transaction types.

Suggested Code:

    swap.wallets[step.hyperliquidTransaction?.blockChain || ''] ||

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

Comment on lines +28 to +37
let userDetailsJson: UserDetailsResponse;
try {
userDetailsJson = await userDetailsResponse.json();

if (!Array.isArray(userDetailsJson.txs)) {
return new Err(GetHyperliquidTransactionHashError.RESPONSE_PARSING_ERROR);
}
} catch {
return new Err(GetHyperliquidTransactionHashError.RESPONSE_PARSING_ERROR);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Kody Rules high

Avoid unsafe any assignment by validating the API response structure before casting to UserDetailsResponse.

This issue appears in multiple locations:

  • queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/utils.ts: Lines 28-37
  • queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/utils.ts: Lines 63-70
  • signers/signer-evm/src/signer.ts: Lines 163-164
    Please fix this Kody Rule violation in all listed locations.
  let userDetailsJson: UserDetailsResponse;
  try {
    const data: unknown = await userDetailsResponse.json();

    if (
      !data ||
      typeof data !== 'object' ||
      !('txs' in data) ||
      !Array.isArray((data as { txs: unknown }).txs)
    ) {
      return new Err(GetHyperliquidTransactionHashError.RESPONSE_PARSING_ERROR);
    }

    userDetailsJson = data as UserDetailsResponse;
  } catch {
    return new Err(GetHyperliquidTransactionHashError.RESPONSE_PARSING_ERROR);
  }
Prompt for LLM

File queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/utils.ts:

Line 28 to 37:

I have a piece of TypeScript code that fetches data from an API. It currently assigns the result of `response.json()`, which is of type `any`, directly to a variable that has a specific interface type. This approach is not type-safe and could lead to runtime errors if the API response structure changes.

My project follows a strict rule that disallows the use of the `any` type to maintain type safety. All external data, such as API responses, must be properly validated before being used with a specific type.

Please refactor the code to handle this safely. The solution should first treat the JSON response as `unknown`, then perform runtime checks to validate its structure (e.g., ensure it's an object and contains the expected `txs` array). Only after successful validation should the data be cast to the `UserDetailsResponse` type.

Suggested Code:

  let userDetailsJson: UserDetailsResponse;
  try {
    const data: unknown = await userDetailsResponse.json();

    if (
      !data ||
      typeof data !== 'object' ||
      !('txs' in data) ||
      !Array.isArray((data as { txs: unknown }).txs)
    ) {
      return new Err(GetHyperliquidTransactionHashError.RESPONSE_PARSING_ERROR);
    }

    userDetailsJson = data as UserDetailsResponse;
  } catch {
    return new Err(GetHyperliquidTransactionHashError.RESPONSE_PARSING_ERROR);
  }

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

Comment on lines +153 to +165
if (initiateWithdrawalResponse.val.status !== 'ok') {
handleErr(
new Err({
nextStatus: 'failed',
nextStepStatus: 'failed',
message: 'Unexpected Error: Failed to initiate withdrawal.',
details: undefined,
errorCode: 'CLIENT_UNEXPECTED_BEHAVIOUR',
})
);
}

onSuccessfulFinish();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Bug high

Logic error causes inconsistent state on failed withdrawal. When initiateWithdrawalRequest returns a non-'ok' status, the code calls handleErr to mark the transaction as failed but then proceeds to call onSuccessfulFinish. This incorrectly advances the queue to the next step for a failed transaction, leading to state corruption. A return statement is missing after handling the error.

  if (initiateWithdrawalResponse.val.status !== 'ok') {
    handleErr(
      new Err({
        nextStatus: 'failed',
        nextStepStatus: 'failed',
        message: 'Unexpected Error: Failed to initiate withdrawal.',
        details: undefined,
        errorCode: 'CLIENT_UNEXPECTED_BEHAVIOUR',
      })
    );
    return;
  }

  onSuccessfulFinish();
Prompt for LLM

File queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/executeHyperliquidTransaction.ts:

Line 153 to 165:

I have a TypeScript function that handles Hyperliquid transactions within a queue manager. There's a logic error in the error handling. When a withdrawal initiation request succeeds but returns a non-'ok' status, the code correctly calls an error handler (`handleErr`). However, it fails to stop execution and proceeds to call the success handler (`onSuccessfulFinish`). This results in the transaction being marked as failed while also advancing the queue to the next step, causing an inconsistent state. Explain why this is a problem and how to fix it by adding a `return` statement.

Suggested Code:

  if (initiateWithdrawalResponse.val.status !== 'ok') {
    handleErr(
      new Err({
        nextStatus: 'failed',
        nextStepStatus: 'failed',
        message: 'Unexpected Error: Failed to initiate withdrawal.',
        details: undefined,
        errorCode: 'CLIENT_UNEXPECTED_BEHAVIOUR',
      })
    );
    return;
  }

  onSuccessfulFinish();

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

Comment on lines +104 to +107
const initiateWithdrawalResponseJson =
await initiateWithdrawalResponse.json();

return Ok(initiateWithdrawalResponseJson);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Bug high

The initiateWithdrawalRequest function does not handle non-successful HTTP responses from the fetch call. If the API returns an error status code (e.g., 4xx or 5xx), the code incorrectly treats the failed request as a success. Additionally, the response JSON is implicitly typed as any, which violates the strict typing rule. The improved code adds proper error handling for failed requests and explicitly types both the error details (unknown) and the successful response to ensure type safety.

    if (!initiateWithdrawalResponse.ok) {
      let errorDetails: unknown;
      try {
        errorDetails = await initiateWithdrawalResponse.json();
      } catch (e) {
        errorDetails = initiateWithdrawalResponse.statusText;
      }
      return new Err({
        nextStatus: 'failed',
        nextStepStatus: 'failed',
        message: `Failed to initiate withdrawal: ${initiateWithdrawalResponse.status}`,
        details: errorDetails,
        errorCode: 'CLIENT_UNEXPECTED_BEHAVIOUR',
      });
    }

    const initiateWithdrawalResponseJson = await initiateWithdrawalResponse.json() as { status: string };

    return Ok(initiateWithdrawalResponseJson);
Prompt for LLM

File queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/utils.ts:

Line 104 to 107:

I have a function `initiateWithdrawalRequest` in my TypeScript code that makes a `fetch` call. It has two issues. First, it doesn't handle non-successful HTTP responses (like 4xx or 5xx errors) and treats them as successes. Second, it violates our strict typing rules by implicitly using the `any` type for the JSON response. Our rules state that the `any` type must not be used to ensure type safety.

Please modify the function to:
1. Check the `ok` property of the response. If it's not ok, return an `Err` result with error details.
2. For the error details, use the `unknown` type instead of an implicit `any`.
3. For the successful response, ensure the parsed JSON is explicitly typed as `{ status: string }` to match the function's return signature and avoid the `any` type.

Suggested Code:

    if (!initiateWithdrawalResponse.ok) {
      let errorDetails: unknown;
      try {
        errorDetails = await initiateWithdrawalResponse.json();
      } catch (e) {
        errorDetails = initiateWithdrawalResponse.statusText;
      }
      return new Err({
        nextStatus: 'failed',
        nextStepStatus: 'failed',
        message: `Failed to initiate withdrawal: ${initiateWithdrawalResponse.status}`,
        details: errorDetails,
        errorCode: 'CLIENT_UNEXPECTED_BEHAVIOUR',
      });
    }

    const initiateWithdrawalResponseJson = await initiateWithdrawalResponse.json() as { status: string };

    return Ok(initiateWithdrawalResponseJson);

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

Comment on lines +101 to +114
async signTypedData(typedData: TypedData): Promise<string> {
try {
const signer = await this.provider.getSigner();
const signature = await signer.signTypedData(
typedData.domain,
typedData.types,
typedData.value
);

return signature;
} catch (error) {
throw new SignerError(SignerErrorCode.SIGN_TX_ERROR, undefined, error);
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Bug high

Missing signer validation in the signTypedData method. The method's signature is inconsistent with its usage, which passes the wallet address and chain ID as additional arguments. These arguments are ignored, and unlike signAndSendTx in the same class, the method fails to validate that the active signer's address and chain ID match the required ones. This omission can lead to generating invalid signatures if the user's wallet is on the wrong network or has the wrong account selected. The proposed fix adds this validation and also improves type safety in the catch block by explicitly typing the error as unknown to avoid using an implicit any type.

  async signTypedData(
    typedData: TypedData,
    address: string,
    chainId: string | null
  ): Promise<string> {
    try {
      const signer = await this.provider.getSigner();

      const signerChainId = (await this.provider.getNetwork()).chainId;
      const signerAddress = await signer.getAddress();

      if (
        !!chainId &&
        !!signerChainId &&
        signerChainId.toString() !== Number(chainId).toString()
      ) {
        throw new SignerError(
          SignerErrorCode.UNEXPECTED_BEHAVIOUR,
          undefined,
          `Signer chainId: '${signerChainId}' doesn't match with required chainId: '${chainId}' for tx.`
        );
      }

      if (address.toLowerCase() !== signerAddress.toLowerCase()) {
        throw new SignerError(
          SignerErrorCode.UNEXPECTED_BEHAVIOUR,
          undefined,
          `Signer address: '${signerAddress.toLowerCase()}' doesn't match with required address: '${address.toLowerCase()}' for tx.`
        );
      }

      const signature = await signer.signTypedData(
        typedData.domain,
        typedData.types,
        typedData.value
      );

      return signature;
    } catch (error: unknown) {
      if (error instanceof SignerError) {
        throw error;
      }
      throw new SignerError(SignerErrorCode.SIGN_TX_ERROR, undefined, error);
    }
  }
Prompt for LLM

File signers/signer-evm/src/signer.ts:

Line 101 to 114:

The provided code introduces a new `signTypedData` method to an EVM signer class. However, its signature and implementation are incorrect. A consumer of this method calls it with three arguments: the typed data object, the expected signer address, and the expected chain ID. The new method only accepts the first argument, ignoring the address and chain ID. Furthermore, another method in the same class, `signAndSendTx`, correctly uses the address and chain ID to validate the signer's state before performing an action. The new `signTypedData` method omits this critical validation.

Refactor the `signTypedData` method to accept all three arguments and include the validation logic for the address and chain ID, mirroring the pattern in `signAndSendTx`, to prevent signing with an incorrect wallet configuration.

Additionally, please ensure the implementation adheres to our strict typing rules. Specifically, the use of the `any` type is disallowed. This means that any error handling, such as in a `try...catch` block, must explicitly type the error as `unknown` (e.g., `catch (error: unknown)`), not leave it as an implicit `any`.

Suggested Code:

  async signTypedData(
    typedData: TypedData,
    address: string,
    chainId: string | null
  ): Promise<string> {
    try {
      const signer = await this.provider.getSigner();

      const signerChainId = (await this.provider.getNetwork()).chainId;
      const signerAddress = await signer.getAddress();

      if (
        !!chainId &&
        !!signerChainId &&
        signerChainId.toString() !== Number(chainId).toString()
      ) {
        throw new SignerError(
          SignerErrorCode.UNEXPECTED_BEHAVIOUR,
          undefined,
          `Signer chainId: '${signerChainId}' doesn't match with required chainId: '${chainId}' for tx.`
        );
      }

      if (address.toLowerCase() !== signerAddress.toLowerCase()) {
        throw new SignerError(
          SignerErrorCode.UNEXPECTED_BEHAVIOUR,
          undefined,
          `Signer address: '${signerAddress.toLowerCase()}' doesn't match with required address: '${address.toLowerCase()}' for tx.`
        );
      }

      const signature = await signer.signTypedData(
        typedData.domain,
        typedData.types,
        typedData.value
      );

      return signature;
    } catch (error: unknown) {
      if (error instanceof SignerError) {
        throw error;
      }
      throw new SignerError(SignerErrorCode.SIGN_TX_ERROR, undefined, error);
    }
  }

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

Comment on lines +34 to +37
getSupportedChains: (allBlockchains: BlockchainMeta[]) => [
...evmBlockchains(allBlockchains),
...hyperliquidBlockchain(allBlockchains),
],
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Bug high

Duplicate blockchain entry. The function concatenates the results of evmBlockchains and hyperliquidBlockchain. As Hyperliquid is an EVM-compatible chain, it is likely included in the list returned by evmBlockchains. This implementation will create a duplicate Hyperliquid entry in the supported chains list, which can cause downstream logic failures or UI bugs.

            getSupportedChains: (allBlockchains: BlockchainMeta[]) => {
              const chains = [
                ...evmBlockchains(allBlockchains),
                ...hyperliquidBlockchain(allBlockchains),
              ];
              // Assuming `chain.name` is the unique identifier for a blockchain.
              return [
                ...new Map(chains.map((chain) => [chain.name, chain])).values(),
              ];
            },
Prompt for LLM

File wallets/provider-rabby/src/constants.ts:

Line 34 to 37:

I have this TypeScript code that is supposed to return a list of supported blockchain networks for a crypto wallet. It combines a list of all EVM chains with the Hyperliquid chain. The problem is that Hyperliquid is an EVM-compatible chain, so it's likely already included in the list from `evmBlockchains()`. The current code just concatenates the two lists using the spread operator, which will result in a duplicate Hyperliquid entry in the final array. This can cause bugs in the UI or other parts of the application. How can I modify this code to combine the two lists while ensuring the final list contains only unique blockchains? Assume each blockchain object in the array has a unique `name` property that can be used for deduplication.

Suggested Code:

            getSupportedChains: (allBlockchains: BlockchainMeta[]) => {
              const chains = [
                ...evmBlockchains(allBlockchains),
                ...hyperliquidBlockchain(allBlockchains),
              ];
              // Assuming `chain.name` is the unique identifier for a blockchain.
              return [
                ...new Map(chains.map((chain) => [chain.name, chain])).values(),
              ];
            },

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

type of hyperliquid chain in meta is "Hyperliquid" so it will not be returned in the evmBlockchains so I need to do the concatenatrion @kody

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Add comprehensive Hyperliquid transaction support to Rango client

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add Hyperliquid transaction execution and status checking actions
• Integrate Hyperliquid support into queue manager workflow
• Enable EVM signer to support typed data signing for Hyperliquid
• Add Hyperliquid blockchain support across multiple wallet providers
• Automatically provision Hyperliquid accounts for EVM wallets
Diagram
flowchart LR
  A["Hyperliquid Transaction"] --> B["Execute Hyperliquid Transaction"]
  B --> C["Sign Typed Data"]
  C --> D["Submit to Exchange API"]
  D --> E["Check Transaction Status"]
  E --> F["Poll Explorer API"]
  F --> G["Transaction Hash"]
  H["EVM Wallets"] --> I["Support Hyperliquid"]
  I --> J["Auto-provision Accounts"]
Loading

Grey Divider

File Changes

1. queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/executeHyperliquidTransaction.ts ✨ Enhancement +166/-0

Execute Hyperliquid transactions with typed data signing

queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/executeHyperliquidTransaction.ts


2. queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/utils.ts ✨ Enhancement +155/-0

Utilities for Hyperliquid transaction validation and signing

queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/utils.ts


3. queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/types.ts ✨ Enhancement +5/-0

Type definitions for Ethers v6 compatible typed data

queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/types.ts


View more (79)
4. queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/constants.ts ⚙️ Configuration changes +2/-0

Hyperliquid exchange API endpoint configuration

queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/constants.ts


5. queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/checkHyperliquidTransactionStatus.ts ✨ Enhancement +94/-0

Check Hyperliquid transaction status via explorer API

queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/checkHyperliquidTransactionStatus.ts


6. queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/utils.ts ✨ Enhancement +50/-0

Fetch transaction hash from Hyperliquid explorer

queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/utils.ts


7. queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/types.ts ✨ Enhancement +20/-0

Type definitions for Hyperliquid explorer API responses

queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/types.ts


8. queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/constants.ts ⚙️ Configuration changes +10/-0

Hyperliquid explorer API and polling interval configuration

queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/constants.ts


9. queue-manager/rango-preset/src/queueDef.ts ✨ Enhancement +6/-0

Register Hyperliquid transaction actions in queue manager

queue-manager/rango-preset/src/queueDef.ts


10. queue-manager/rango-preset/src/actions/scheduleNextStep.ts ✨ Enhancement +2/-0

Route Hyperliquid transactions to execution action

queue-manager/rango-preset/src/actions/scheduleNextStep.ts


11. queue-manager/rango-preset/src/types.ts ✨ Enhancement +2/-0

Add Hyperliquid action types to swap action enum

queue-manager/rango-preset/src/types.ts


12. queue-manager/rango-preset/src/helpers.ts ✨ Enhancement +8/-1

Support Hyperliquid transaction in transaction helpers

queue-manager/rango-preset/src/helpers.ts


13. queue-manager/rango-preset/src/shared.ts ✨ Enhancement +10/-1

Add Hyperliquid namespace and account provisioning logic

queue-manager/rango-preset/src/shared.ts


14. signers/signer-evm/src/signer.ts ✨ Enhancement +17/-0

Implement signTypedData method for EVM signer

signers/signer-evm/src/signer.ts


15. signers/signer-evm/src/types.ts ✨ Enhancement +7/-0

Define TypedData type for EVM signer

signers/signer-evm/src/types.ts


16. wallets/core/src/legacy/types.ts ✨ Enhancement +1/-0

Add Hyperliquid to supported networks enum

wallets/core/src/legacy/types.ts


17. wallets/shared/src/rango.ts ⚙️ Configuration changes +1/-0

Define Hyperliquid signing network constant

wallets/shared/src/rango.ts


18. widget/embedded/src/utils/wallets.ts ✨ Enhancement +9/-0

Auto-add Hyperliquid accounts for EVM wallets

widget/embedded/src/utils/wallets.ts


19. wallets/provider-bitget/src/constants.ts ✨ Enhancement +5/-2

Enable Hyperliquid support in Bitget wallet

wallets/provider-bitget/src/constants.ts


20. wallets/provider-brave/src/constants.ts ✨ Enhancement +5/-2

Enable Hyperliquid support in Brave wallet

wallets/provider-brave/src/constants.ts


21. wallets/provider-coin98/src/constants.ts ✨ Enhancement +5/-2

Enable Hyperliquid support in Coin98 wallet

wallets/provider-coin98/src/constants.ts


22. wallets/provider-coinbase/src/constants.ts ✨ Enhancement +5/-2

Enable Hyperliquid support in Coinbase wallet

wallets/provider-coinbase/src/constants.ts


23. wallets/provider-cosmostation/src/constants.ts ✨ Enhancement +5/-2

Enable Hyperliquid support in Cosmostation wallet

wallets/provider-cosmostation/src/constants.ts


24. wallets/provider-enkrypt/src/constants.ts ✨ Enhancement +9/-3

Enable Hyperliquid support in Enkrypt wallet

wallets/provider-enkrypt/src/constants.ts


25. wallets/provider-math-wallet/src/constants.ts ✨ Enhancement +5/-2

Enable Hyperliquid support in Math Wallet

wallets/provider-math-wallet/src/constants.ts


26. wallets/provider-metamask/src/constants.ts ✨ Enhancement +5/-2

Enable Hyperliquid support in MetaMask wallet

wallets/provider-metamask/src/constants.ts


27. wallets/provider-rabby/src/constants.ts ✨ Enhancement +9/-3

Enable Hyperliquid support in Rabby wallet

wallets/provider-rabby/src/constants.ts


28. wallets/provider-safepal/src/constants.ts ✨ Enhancement +9/-3

Enable Hyperliquid support in SafePal wallet

wallets/provider-safepal/src/constants.ts


29. wallets/provider-tokenpocket/src/constants.ts ✨ Enhancement +9/-3

Enable Hyperliquid support in TokenPocket wallet

wallets/provider-tokenpocket/src/constants.ts


30. wallets/provider-tomo/src/constants.ts ✨ Enhancement +9/-3

Enable Hyperliquid support in Tomo wallet

wallets/provider-tomo/src/constants.ts


31. wallets/provider-trustwallet/src/constants.ts ✨ Enhancement +5/-2

Enable Hyperliquid support in TrustWallet

wallets/provider-trustwallet/src/constants.ts


32. queue-manager/rango-preset/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

queue-manager/rango-preset/package.json


33. signers/signer-evm/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

signers/signer-evm/package.json


34. signers/signer-cosmos/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

signers/signer-cosmos/package.json


35. signers/signer-solana/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

signers/signer-solana/package.json


36. signers/signer-starknet/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

signers/signer-starknet/package.json


37. signers/signer-sui/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

signers/signer-sui/package.json


38. signers/signer-ton/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

signers/signer-ton/package.json


39. signers/signer-tron/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

signers/signer-tron/package.json


40. wallets/core/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/core/package.json


41. wallets/provider-binance/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-binance/package.json


42. wallets/provider-bitget/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-bitget/package.json


43. wallets/provider-braavos/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-braavos/package.json


44. wallets/provider-brave/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-brave/package.json


45. wallets/provider-coin98/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-coin98/package.json


46. wallets/provider-coinbase/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-coinbase/package.json


47. wallets/provider-cosmostation/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-cosmostation/package.json


48. wallets/provider-default/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-default/package.json


49. wallets/provider-enkrypt/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-enkrypt/package.json


50. wallets/provider-exodus/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-exodus/package.json


51. wallets/provider-keplr/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-keplr/package.json


52. wallets/provider-leap-cosmos/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-leap-cosmos/package.json


53. wallets/provider-ledger/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-ledger/package.json


54. wallets/provider-math-wallet/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-math-wallet/package.json


55. wallets/provider-metamask/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-metamask/package.json


56. wallets/provider-okx/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-okx/package.json


57. wallets/provider-phantom/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-phantom/package.json


58. wallets/provider-rabby/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-rabby/package.json


59. wallets/provider-ready/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-ready/package.json


60. wallets/provider-safe/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-safe/package.json


61. wallets/provider-safepal/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-safepal/package.json


62. wallets/provider-slush/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-slush/package.json


63. wallets/provider-solflare/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-solflare/package.json


64. wallets/provider-taho/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-taho/package.json


65. wallets/provider-tokenpocket/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-tokenpocket/package.json


66. wallets/provider-tomo/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-tomo/package.json


67. wallets/provider-tonconnect/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-tonconnect/package.json


68. wallets/provider-trezor/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-trezor/package.json


69. wallets/provider-tron-link/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-tron-link/package.json


70. wallets/provider-trustwallet/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-trustwallet/package.json


71. wallets/provider-unisat/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-unisat/package.json


72. wallets/provider-walletconnect-2/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-walletconnect-2/package.json


73. wallets/provider-xdefi/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-xdefi/package.json


74. wallets/provider-xverse/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/provider-xverse/package.json


75. wallets/react/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/react/package.json


76. wallets/shared/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

wallets/shared/package.json


77. widget/embedded/package.json Dependencies +2/-2

Upgrade rango-sdk and rango-types dependencies

widget/embedded/package.json


78. widget/playground/package.json Dependencies +1/-1

Upgrade rango-sdk dependency

widget/playground/package.json


79. widget/ui/package.json Dependencies +1/-1

Upgrade rango-types to 0.1.97

widget/ui/package.json


80. queue-manager/queue-manager-demo/package.json Dependencies +3/-3

Upgrade rango-sdk and rango-types dependencies

queue-manager/queue-manager-demo/package.json


81. queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/index.ts Additional files +1/-0

...

queue-manager/rango-preset/src/actions/checkHyperliquidTransactionStatus/index.ts


82. queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/index.ts Additional files +2/-0

...

queue-manager/rango-preset/src/actions/executeHyperliquidTransaction/index.ts


Grey Divider

Qodo Logo

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