-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add venue-aware order identifiers #55
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
feat: add venue-aware order identifiers #55
Conversation
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".
| idents, err := h.store.ListSubmissionIdentifiersForOrder(ctx, *oid) | ||
| if err != nil { | ||
| if h.logger != nil { | ||
| h.logger.Error("CancelOrderByOrderId load submission failed", slog.String("orderid", oid.Hex()), slog.String("error", err.Error())) | ||
| h.logger.Warn("CancelOrderByOrderId list identifiers failed", slog.String("orderid", oid.Hex()), slog.String("error", err.Error())) | ||
| } | ||
| return CancelOrderByOrderId500Response{}, nil | ||
| } | ||
| if !found || (action.Create == nil && action.Modify == nil) { | ||
| if len(idents) == 0 { | ||
| if h.logger != nil { | ||
| h.logger.Info("CancelOrderByOrderId submission not found", slog.String("orderid", oid.Hex())) | ||
| } | ||
| return CancelOrderByOrderId404Response{}, 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.
Return 500 when identifier lookup fails
The cancel endpoint now calls ListSubmissionIdentifiersForOrder and logs any error, but it falls through and returns a 404 when the slice is empty. A storage failure (e.g. database unavailable) will therefore be reported to clients as “not found” instead of a server error, which makes retry logic and alerting unreliable. The previous implementation returned a 500 on the same failure path. Consider propagating the error after logging so transient storage issues aren’t silently treated as missing orders.
Useful? React with 👍 / 👎.
storage/storage.go
Outdated
| // ListVenuesForBot returns the configured venue assignments for the given bot. | ||
| // If no explicit assignments exist, the default Hyperliquid venue is returned. | ||
| func (s *Storage) ListVenuesForBot(ctx context.Context, botID uint32) ([]VenueAssignment, error) { | ||
| s.mu.Lock() | ||
| defer s.mu.Unlock() | ||
|
|
||
| assignments, err := s.queries.ListBotVenueAssignments(ctx, int64(botID)) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| if len(assignments) == 0 { | ||
| return []VenueAssignment{{ | ||
| VenueID: defaultHyperliquidVenueID, | ||
| Wallet: defaultHyperliquidWallet, | ||
| IsPrimary: true, | ||
| }}, 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.
Default venue uses placeholder wallet causing mismatched identifiers
When no venue assignments exist for a bot, ListVenuesForBot returns an assignment with Wallet: default (the defaultHyperliquidWallet constant). The engine uses this value when emitting order work, so submissions and fill‑tracker entries are keyed by VenueID=hyperliquid:default and wallet default. However the websocket client is constructed with the actual Hyperliquid wallet from secrets and records status updates using that real wallet string (hl/ws/ws.go around the New constructor). The same order therefore appears under two different OrderIdentifiers (one with wallet default, one with the real wallet) and reloadDeal iterates over both, creating duplicate order state with missing status data. This corrupts snapshots and downstream reconciliation. The default path should use the runtime wallet or persist the secret to the venues table so identifiers match across subsystems.
Useful? React with 👍 / 👎.
|
@codex review 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.
💡 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".
| hasLocalOrder := len(storedIdents) > 0 | ||
|
|
||
| action, latestEvent, shouldEmit, err := e.reduceOrderEvents(ctx, currency, oid, hasLocalOrder, orderLogger) | ||
| if err != 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.
Skip fan-out when one venue already has a submission
The loop treats hasLocalOrder := len(storedIdents) > 0 as a global flag for the order and immediately bails out when reduceOrderEvents returns shouldEmit=false. When a bot is assigned to multiple venues and one venue already recorded a submission, hasLocalOrder is true even for venues that never saw a create. With no new 3Commas snapshot, reduceOrderEvents returns ActionNone, the loop continues, and resolveOrderTargets is never called, so missing venues never receive their initial create. A transient failure during fan-out therefore leaves additional venues permanently unsynchronized until a new bot event happens. Consider evaluating hasLocalOrder per target or emitting create work for assignments that still lack a submission.
Useful? React with 👍 / 👎.
guard generated code
guard generated code
…ue' into codex/extend-orderwork-with-identifier-and-refactor-queue-ehfv2o
…ifier-and-refactor-queue-ehfv2o fix: replay missing venue submissions
|
@codex please fix the following 💡 Codex Review recomma/storage/storage.go L125-L133 P1 Badge Update default wallet without migrating existing submissions |
|
You have reached your Codex usage limits. You can see your limits in the Codex usage dashboard. |
|
@codex please fix the following recomma/storage/storage.go L125-L133 Update default wallet without migrating existing submissions |
|
Summary
Testing
|
…ue-aware-order-identifiers fix: migrate default wallet using generated queries
|
@codex review 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.
💡 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".
| } | ||
|
|
||
| work := recomma.OrderWork{ | ||
| OrderId: oid, | ||
| Identifier: ident, | ||
| OrderId: oid, | ||
| Action: recomma.Action{ | ||
| Type: recomma.ActionCancel, | ||
| Cancel: &cancel, |
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.
ReconcileTakeProfits ignores venue-specific emitters
The fill tracker still accepts a single recomma.Emitter and cmd/recomma/main.go wires it up with the default HyperLiquidEmitter. When ReconcileTakeProfits emits cancellations or recreate orders it calls that emitter directly, even though each OrderWork now carries a venue-scoped identifier. For take profits that belong to a non‑default venue, those emissions will be executed with the default wallet/client and recorded under the foreign venue, so the wrong account is modified and the intended venue never receives the cancel/create. The multi‑venue spec expects take‑profit reconciliation to dispatch per venue; this path should go through the venue dispatcher or resolve the correct emitter before emitting.
Useful? React with 👍 / 👎.
…tifier-and-refactor-queue' into codex/expand-openapi.yaml-for-venue-management - Fix storage with duplicate UpsertVenue
…ue-management feat: add venue management APIs and venue-aware identifiers
… into codex/extend-orderwork-with-identifier-and-refactor-queue
c5393b1
into
codex/investigate-multi-wallet-support-for-hyperliquid
Summary
Reviewing
Read
specs/multi_venue_emission.adocbefore reviewinghttps://chatgpt.com/codex/tasks/task_e_6907f529e9788326a5b7d93ea277ce5a