-
Notifications
You must be signed in to change notification settings - Fork 0
Claude/investigate hyperliquid multi wallet 011 c uw4 titt mw ez sw ek x1x b6 #95
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Claude/investigate hyperliquid multi wallet 011 c uw4 titt mw ez sw ek x1x b6 #95
Conversation
- 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.
There was a problem hiding this 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".
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
|
@codex review |
There was a problem hiding this 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".
| await upsertVenue(venueId, { | ||
| type: 'hyperliquid', | ||
| display_name: formData.display_name, | ||
| wallet: formData.wallet, | ||
| flags: { api_url: formData.api_url }, | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Persist wallet secrets when adding or editing venues
The settings flow collects a private key in VenueForm and validates it, but when a user saves a wallet the payload sent to /api/venues/{id} only includes type, display_name, wallet, and flags. The private key is never transmitted, so any wallet created or edited after initial setup will be missing the secret material required to submit orders. That means newly added wallets cannot sign Hyperliquid transactions, and edits cannot rotate a compromised key. The same omission exists in the edit path a few lines below. Consider extending the upsert request to include the private key so the vault can persist it along with the public metadata.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove legacy venue parsing code from vault types as per multi-venue spec. This includes: - Legacy wireData fields (LegacyWallet, LegacyPrivateKey, etc.) - legacyVenue and legacyVenueWithID structs - decodeLegacyVenues() function - Legacy parsing logic in decodeVenues() The vault now only supports the modern multi-venue payload format. Co-authored-by: Claude <[email protected]>
Add new endpoint to allow users to update the encrypted vault payload after initial setup. This enables adding, editing, and removing venue credentials without requiring a full vault re-initialization. Changes: - Add PUT /vault/payload to OpenAPI spec - Implement UpdateVaultPayload handler with server-side validation - Require both encrypted and decrypted payloads for validation - Validate vault must be unsealed and session must be active - Validate decrypted payload structure and venue configuration - Use existing UpsertVaultPayload storage method (atomic transaction) - Sync venue metadata to storage after successful update The endpoint validates: - Session authentication and vault unsealed state - Encrypted payload structure (version, ciphertext, nonce) - Decrypted payload contents using vault.Data.Validate() - At least one primary venue exists - No duplicate venue IDs - Valid wallet addresses (40 hex chars) - Valid private keys (64 hex chars) After update, the vault remains unsealed but new configuration is not active until seal/re-unseal cycle. Co-authored-by: Claude <[email protected]>
The generated UpdateVaultPayload200JSONResponse has Message as *string, but the handler was passing a string literal. Fixed to use a pointer. Also add comprehensive test coverage for UpdateVaultPayload endpoint covering all scenarios from the spec: - Success case with valid payload - Missing/invalid session (401) - Vault sealed (403) - No primary venue (400) - Multiple primary venues (400) - Duplicate venue IDs (400) - Invalid wallet address (400) - Invalid private key (400) - Database errors (500) Co-authored-by: Claude <[email protected]>
Fix test failures: - Use VenueId field instead of ID in VenueRecord - Pass vault.StateSealed to NewController (signature changed) Co-authored-by: Claude <[email protected]>
Fix all UpdateVaultPayload tests to properly inject HTTP request into context. The requireSession() function needs the HTTP request in the context to work properly, even in debug mode. Changes: - Add net/http and net/http/httptest imports - Create httptest.NewRequest for each test - Add request to context using httpRequestContextKey - Pass context with request to handler Co-authored-by: Claude <[email protected]>
Co-authored-by: Your Name <[email protected]>
…hanging-functionality test: fix vault payload update tests
…int-011CUxiES5RUW3tL4bb1Awsm Claude/vault payload update endpoint 011 c uxi es5 ruw3t l4bb1 awsm
…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.
There was a problem hiding this 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".
webui/app/src/lib/vault-utils.ts
Outdated
| const credentialRequestOptions: CredentialRequestOptions = { | ||
| publicKey: { | ||
| challenge: new Uint8Array(32), // Server should provide this | ||
| rpId: window.location.hostname, | ||
| userVerification: 'required', | ||
| extensions: { | ||
| prf: { | ||
| eval: { | ||
| first: new TextEncoder().encode('vault-decrypt'), | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| const credential = (await navigator.credentials.get( | ||
| credentialRequestOptions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use actual WebAuthn challenge and credential when deriving PRF key
Both decryptVaultPayload and encryptVaultPayload call navigator.credentials.get with a zeroed challenge and without allowCredentials/prf_params from the server. In a real browser, passkeys are scoped to a server‑issued challenge and credential ID; omitting them typically yields a NotAllowedError or derives a PRF output for an arbitrary credential. As a result the client cannot reliably decrypt the stored vault payload nor re‑encrypt an update, so the Settings UI will fail as soon as more than one credential exists. The PRF parameters returned by /vault/payload (credential ID, salt) and a fresh challenge from the backend should be supplied here before this code will work.
Useful? React with 👍 / 👎.
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.
|
@codex review |
There was a problem hiding this 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".
| d.THREECOMMASAPIKEY = payload.ThreeCommasAPIKey | ||
| d.THREECOMMASPRIVATEKEY = payload.ThreeCommasPrivate | ||
| d.Venues = venues | ||
| return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dropping legacy vault payload conversion breaks existing secrets
The new Data.UnmarshalJSON only populates venues from the venues property and removes the previous decodeLegacyVenues fallback. Vault payloads saved by earlier versions stored Hyperliquid credentials in the legacy HYPERLIQUID_* fields without a venues array, so after this change they unmarshal with an empty Venues slice. When the controller subsequently calls ensurePrimaryVenuePresent during unseal it fails with ErrPrimaryVenueRequired, leaving existing deployments unable to unseal until the payload is manually rebuilt. A migration or compatibility path is needed before removing the legacy conversion.
Useful? React with 👍 / 👎.
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.
This reverts commit b306d71.
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).
|
@codex review |
|
Codex Review: Didn't find any major issues. 👍 ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
No description provided.