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.

- 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.
@terwey terwey marked this pull request as ready for review November 9, 2025 14:50
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".

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
@terwey
Copy link
Collaborator Author

terwey commented Nov 9, 2025

@codex review

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 133 to 138
await upsertVenue(venueId, {
type: 'hyperliquid',
display_name: formData.display_name,
wallet: formData.wallet,
flags: { api_url: formData.api_url },
});

Choose a reason for hiding this comment

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

P1 Badge 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 👍 / 👎.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@codex review if the most recent commit (8e5573a) fixes this problem you flagged!

claude and others added 12 commits November 9, 2025 17:36
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]>
…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.
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 17 to 33
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

Choose a reason for hiding this comment

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

P1 Badge 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.
@terwey
Copy link
Collaborator Author

terwey commented Nov 9, 2025

@codex review

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

d.THREECOMMASAPIKEY = payload.ThreeCommasAPIKey
d.THREECOMMASPRIVATEKEY = payload.ThreeCommasPrivate
d.Venues = venues
return nil

Choose a reason for hiding this comment

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

P0 Badge 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.
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).
@terwey
Copy link
Collaborator Author

terwey commented Nov 9, 2025

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. 👍

ℹ️ 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".

@terwey terwey merged commit f5df199 into ui/multi-venue Nov 9, 2025
3 checks passed
@terwey terwey deleted the claude/investigate-hyperliquid-multi-wallet-011CUw4TittMwEzSwEkX1xB6 branch November 9, 2025 20:14
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.

4 participants