Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@terwey
Copy link
Collaborator

@terwey terwey commented Nov 9, 2025

No description provided.

terwey and others added 21 commits November 9, 2025 14:51
- Add venue-related types from schema to api.ts
- Add custom UI types: VenueFormData, VenueWithAssignments, VenueAssignmentWithBot, BotWithVenue
- Create venue-utils.ts with validation and normalization functions
- Add API_ENDPOINTS constants for mainnet/testnet
- Implement wallet address truncation for UI display
- Create venue-api.ts with complete API client for venue operations
- Implement fetchVenues, upsertVenue, deleteVenue endpoints
- Add venue assignment operations: fetch, assign, unassign
- Add bot venue operations: fetchBotVenues
- All endpoints use buildOpsApiUrl with credentials include
- Add shadcn-style table component with all table primitives
- Create Settings page with tabbed interface for venues and bot assignments
- Integrate VenueManagement and BotAssignmentManager in settings tabs
- Add back navigation support for settings page
- Update VenueManagement to use fetchVenues, upsertVenue, deleteVenue
- Update VenueAssignments to use real assignment API endpoints
- Update BotList to use fetchBotVenues and assignBotToVenue
- Fix sonner import errors in all venue components
- Remove all mockApiCall functions
- Use buildOpsApiUrl with credentials include for all API calls
- Replace single hyperliquid config with venues array
- Integrate VenueManagement component in step 3
- Update SetupData interface to use VaultVenueSecret[] for venues
- Update buildSecretsBundle to use venues array from setup data
- Add venue validation requiring at least one venue before continuing
- Users can now configure multiple wallets during initial setup
- Add Settings button to dashboard header with gear icon
- Add showSettings state to toggle between dashboard and settings
- Lazy load Settings component for code splitting
- Add Settings icon from lucide-react
- Settings page includes back button to return to dashboard
- Maintain Toaster across both views
- Add Execution Venue card to order detail dialog
- Display venue_id and wallet address from order identifiers
- Show truncated wallet address with copy-to-clipboard button
- Display full wallet address for reference
- Add Wallet icon from lucide-react
- Use truncateWalletAddress utility for consistent formatting
- Add type-only imports for all component type definitions to comply with verbatimModuleSyntax
- Fix validation error handling in VenueForm (validation functions return string | null, not objects)
- Add isCustom parameter to validateApiUrl call in VenueForm
- Fix isDuplicateWallet function call with correct parameters (VenueRecord[] instead of string[])
- Rename truncateAddress to truncateWalletAddress in VenueList and VenueDetail
- Update ConfirmationStep to use new SetupData structure with venues array
- Add missing dropdown-menu UI component
- Add null safety check for venue.api_url in ConfirmationStep

All TypeScript errors are now resolved and npx tsc --noEmit passes successfully.
- Remove unused 'loading' parameter from BotAssignmentDialog
- Remove unused imports in BotAssignmentManager (useState, Tabs components)
- Remove unused handleVenuesLoaded function in Settings
- Remove unused error parameter in VenueAssignments catch block
- Remove unused truncateWalletAddress import in VenueDetail
- Change 'let' to 'const' for non-reassigned variables in VenueManagement
- Refactor venue deletion to avoid mutation and properly use const
- Remove unused 'index' parameter in ConfirmationStep map

All ESLint and TypeScript checks now pass successfully.
Add onVenuesLoaded callback to VenueManagement component that is called
after venues are loaded from the API in settings context. Use this callback
in Settings component to populate the venues state, which is then passed to
BotAssignmentManager.

This fixes the issue where the Bot Assignments tab would always show
"no wallets available" even when wallets existed, because the venues
state was never populated.

- Add onVenuesLoaded prop to VenueManagementProps
- Call onVenuesLoaded after fetching and setting venues
- Implement handleVenuesLoaded in Settings to update local state
- Pass onVenuesLoaded callback to VenueManagement component
…upport-for-hyperliquid' into claude/investigate-hyperliquid-multi-wallet-011CUw4TittMwEzSwEkX1xB6
Implement client-side vault update functionality to properly persist
venue credentials (including private keys) when adding, editing, or
deleting wallets in the Settings UI.

## New Files
- `vault-utils.ts`: WebAuthn PRF-based encryption/decryption utilities
  for vault payload operations

## API Updates (venue-api.ts)
- Add `fetchVaultPayload()`: GET /vault/payload
- Add `updateVaultPayload()`: PUT /vault/payload
- Import VaultEncryptedPayload and VaultSecretsBundle types

## VenueManagement Component Updates
- Add `vaultNeedsReseal` state to track when vault needs re-seal
- Add `updateVaultWithModifiedVenues()` helper that:
  - Fetches current encrypted vault payload
  - Decrypts using WebAuthn PRF
  - Applies venue modifications via callback
  - Re-encrypts payload
  - Sends to server for persistence
- Update `handleAddVenue()` in settings context to use vault update
- Update `handleEditVenue()` in settings context to use vault update
- Update `handleDeleteVenue()` in settings context to use vault update
- Add blue info banner when vault needs reseal with instructions

## How It Works (Settings Context)
1. User adds/edits/deletes a wallet in Settings UI
2. Component fetches encrypted vault payload from server
3. Decrypts payload using WebAuthn PRF to get current secrets
4. Modifies the venues array (add/edit/delete)
5. Re-encrypts entire payload with updated venues
6. Sends both encrypted and decrypted payloads to server
7. Server validates decrypted payload before persisting encrypted version
8. Shows banner: "Vault changes saved. Seal and re-unseal to activate."
9. User must seal and re-unseal vault for changes to take effect

## Security Notes
- Private keys are never exposed via public API endpoints
- All venue credentials remain in encrypted vault payload
- WebAuthn PRF ensures only authorized user can decrypt/encrypt
- Server validates payload integrity before persisting

Setup wizard context remains unchanged (uses local state, no vault ops).

All TypeScript and ESLint checks pass.
The previous implementation incorrectly attempted to use WebAuthn PRF
for encryption/decryption, but the actual system uses standard AES-GCM
with a randomly generated key stored in prf_params.key.

Changes:
- Rewrite vault-utils.ts to match Login.tsx and SetupWizard.tsx patterns
- Extract encryption key from payload.prf_params.key (base64url encoded)
- Reuse the same encryption key when updating vault payload
- Add base64url encoding/decoding helpers
- Update encryptVaultPayload signature to accept originalPayload parameter
- Update VenueManagement.tsx to pass original payload to encryptVaultPayload

This fixes the WebAuthn implementation issues identified in code review
by removing the incorrect WebAuthn PRF usage entirely and using the
correct AES-GCM encryption approach that matches the rest of the codebase.
Add fallback support for legacy single-venue vault payloads that use
HYPERLIQUID_WALLET, HYPERLIQUID_PRIVATE_KEY, and HYPERLIQUID_API_URL
fields instead of the modern venues array.

This prevents existing deployments from failing with ErrPrimaryVenueRequired
when unsealing vaults that were created before the multi-venue support.

Changes:
- Add legacy field parsing to wireData struct
- Convert legacy fields to a single venue entry if venues array is empty
- Set converted venue as primary with ID "hyperliquid-legacy"
- Default to https://api.hyperliquid.xyz if API URL not specified

The system does not require active migration - legacy payloads continue
to work as-is. Users can update to the modern format via Settings UI
when convenient.
Allow vault payloads with empty venues array without erroring out.
If venues are present, they are still validated for correctness
(unique IDs, valid wallet/key format, exactly one primary).
…lti-wallet-011CUw4TittMwEzSwEkX1xB6

refactor(hyperliquid): simplify venue handling to single default wallet

| Area              | Change                                                                                                                                                                      |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Vault validation  | `Data.Validate` now requires `secrets.venues` to be present, returning an explicit error when empty.                                                                        |
| Setup wizard      | Replaced multi-venue setup with a single `hyperliquid` config (`apiUrl`, `wallet`, `privateKey`) and map it to one default `hyperliquid:default` venue in `secrets.venues`. |
| Web UI header     | Removed Settings page toggle and button from `App.tsx`, leaving just the main title and logo.                                                                               |
| Venue / bot UI    | Removed venue and bot assignment management components (wallets, assignments, lists, detail views).                                                                         |
| Order detail UI   | Dropped the “Execution Venue” card from `OrderDetailDialog` (no wallet/venue info shown there anymore).                                                                     |
| Types & utilities | Removed venue-related types (`VaultVenueSecret`, `VenueRecord`, etc.) and helpers (`venue-*`, `vault-utils`, `venue-api`).                                                  |
| UI primitives     | Removed local `checkbox`, `dropdown-menu`, `select`, and `table` wrappers that were only used by the deleted venue UI.                                                      |
| Docs              | Trimmed `AGENTS.md` by removing the “Missing elements” / shadcn install note.                                                                                               |
| Dependencies      | Aligned Radix versions: downgraded `@radix-ui/react-checkbox` and `@radix-ui/react-select` to match the used shadcn presets.                                                |
@terwey terwey marked this pull request as ready for review November 9, 2025 20:18
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 74 to 93
const venues = await fetchVenues();

// Load assignment counts for each venue
const venuesWithCounts = await Promise.all(
venues.map(async (venue) => {
try {
const assignments = await fetchVenueAssignments(venue.venue_id);
return {
...venue,
assignmentCount: assignments.length,
};
} catch {
return { ...venue, assignmentCount: 0 };
}
})
);

setVenues(venuesWithCounts);
onVenuesLoaded?.(venuesWithCounts);
} catch (error) {

Choose a reason for hiding this comment

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

P1 Badge Preserve primary wallet flag when populating settings state

The settings view builds its wallet list from fetchVenues() in loadVenuesFromAPI, but the returned records only expose raw flags; the code never derives isPrimary when storing the list (setVenues(venuesWithCounts)). Downstream actions such as edit and delete rely on venue.isPrimary (e.g. promoting a new primary on delete or pre-checking the form), so every venue is treated as non‑primary. Deleting or editing the real primary wallet therefore sends a payload where no venue is marked primary and the backend’s validation (Validate: “invalid payload: no primary venue found”) rejects the request. The UI surfaces “Failed to delete/update wallet” without guidance, leaving the user unable to manage the primary wallet. Consider decoding flags.is_primary (or loading the vault payload) before assigning isPrimary so a single primary is always preserved.

Useful? React with 👍 / 👎.

claude and others added 2 commits November 9, 2025 20:29
The settings view builds its wallet list from fetchVenues() in
loadVenuesFromAPI, but the returned VenueRecord objects store the
primary flag inside venue.flags.is_primary. The code was not extracting
this value when populating the state, so downstream actions (edit, delete)
that rely on venue.isPrimary would fail backend validation when no primary
venue was marked.

This fix decodes flags.is_primary when mapping venues so the isPrimary
property is correctly set on VenueWithAssignments objects, ensuring that
exactly one primary venue is always preserved during updates.

Fixes the "invalid payload: no primary venue found" validation error when
editing or deleting the primary wallet.
…CUxwgEqEVqUuf7yZnBxLd

fix(ui): extract isPrimary flag from venue.flags in settings view
@terwey terwey merged commit ce8fb0b into codex/investigate-multi-wallet-support-for-hyperliquid Nov 9, 2025
2 of 3 checks passed
@terwey terwey deleted the ui/multi-venue branch November 9, 2025 20:39
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.

3 participants