# StreamUserFills - Stream User Fills

`StreamUserFills` sends live fills whose own account equals the requested `user`. It does not match a counterparty, builder, or liquidated account unless that address is also the fill owner.

## Request and live-only behavior

`user` is a required 0x-prefixed address and matches case-insensitively. The zero address is accepted but has no special meaning. Empty `coins` means every coin; supplied coin identifiers match exactly, and unknown values simply never match.

The stream has no opening snapshot or backfill. Filtering can produce an empty `fills` list, but the frame remains present to preserve `sequence` continuity.

## Request Parameters

- `user` (`string, required`): Required 0x-prefixed fill-owner address, matched case-insensitively.
- `coins` (`repeated string, optional`): Optional exact coin scope; empty means all coins, and unknown coins simply never match.

## Request Example

```go
package main

import (
    "context"
    "crypto/tls"
    "log"
    "os"

    pb "example.com/hyperliquid-v3-client/gen/v3"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"
)

func main() {
    endpoint, apiKey := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT"), os.Getenv("DWELLIR_API_KEY")
    if endpoint == "" || apiKey == "" {
        log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
    }
    conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})))
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()
    ctx := metadata.AppendToOutgoingContext(context.Background(), "x-api-key", apiKey)
    stream, err := pb.NewMarketStreamingClient(conn).StreamUserFills(ctx, &pb.UserFillsRequest{
        User: "0x1111111111111111111111111111111111111111",
        Coins: []string{"BTC", "ETH"},
    })
    if err != nil {
        log.Fatal(err)
    }
    var last uint64
    for {
        update, err := stream.Recv()
        if err != nil {
            log.Fatal(err)
        }
        if update.GetSequence() != last+1 {
            log.Fatalf("sequence gap: got=%d expected=%d", update.GetSequence(), last+1)
        }
        last = update.GetSequence()
        log.Printf("block=%d sequence=%d fills=%d", update.GetBlockNumber(), update.GetSequence(), len(update.GetFills()))
    }
}
```

## Response Fields

- `time` (`int64, required`): Source block time in Unix milliseconds.
- `block_number` (`int64, required`): Sequential Hyperliquid block number.
- `sequence` (`uint64, required`): Per-subscription monotonic counter beginning at 1 on the first live frame.
- `fills` (`repeated Fill, required`): Fills whose own account matches user; may be empty after coin filtering.
- `fills.user` (`string, required`): Account this fill belongs to.
- `fills.coin` (`string, required`): Native coin identifier.
- `fills.px` (`string, required`): Execution price as a decimal string.
- `fills.sz` (`string, required`): Executed size as a decimal string.
- `fills.side` (`string, required`): Native side B or A.
- `fills.time` (`int64, required`): Execution time in Unix milliseconds.
- `fills.hash` (`string, required`): Transaction hash.
- `fills.tid` (`uint64, required`): Within one block, use (coin, tid). Across blocks, include the frame's block_number. Retain account and order identity for individual fills.
- `fills.crossed` (`bool, required`): True when this account was the taker.
- `fills.dir` (`string, required`): Human-readable position direction.
- `fills.start_position` (`string, required`): Signed position immediately before this fill.
- `fills.oid` (`uint64, required`): Filled order identifier.
- `fills.closed_pnl` (`string, required`): Closed profit and loss as a decimal string.
- `fills.fee` (`string, required`): Trading fee as a decimal string.
- `fills.fee_token` (`string, required`): Fee denomination.
- `fills.builder` (`FillBuilder, optional`): Builder attribution, unset for fills without a builder.
- `fills.builder.address` (`string, required`): Builder address.
- `fills.builder.fee` (`string, required`): Builder fee charged on this fill.
- `fills.cloid` (`optional string, optional`): Client order identifier when present.
- `fills.twap_id` (`optional uint64, optional`): TWAP identifier when the fill came from a TWAP order.
- `fills.liquidation` (`FillLiquidation, optional`): Liquidation metadata, unset for non-liquidation fills.
- `fills.liquidation.liquidated_user` (`string, required`): Liquidated account address.
- `fills.liquidation.mark_px` (`string, required`): Liquidation mark price.
- `fills.liquidation.method` (`string, required`): Native liquidation method.

## Successful Response

```protobuf
time: 1785736814057
block_number: 1058646974
sequence: 1
fills: {
  user: "0x1111111111111111111111111111111111111111"
  coin: "BTC"
  px: "114250.0"
  sz: "0.25"
  side: "B"
  time: 1785736814057
  hash: "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
  tid: 99887766
  crossed: true
  dir: "Open Long"
  start_position: "0.0"
  oid: 123456789
  closed_pnl: "0.0"
  fee: "0.285625"
  fee_token: "USDC"
  builder: { address: "0x2222222222222222222222222222222222222222" fee: "0.01" }
  cloid: "0x00112233445566778899aabbccddeeff"
  twap_id: 778899
  liquidation: { liquidated_user: "0x3333333333333333333333333333333333333333" mark_px: "114200.0" method: "market" }
}
```

## Error Responses

### Invalid filter

- Code: `INVALID_ARGUMENT`
- Description: The required user or a coin entry is malformed.

### Feature unavailable

- Code: `FAILED_PRECONDITION`
- Description: This stream is unavailable on the selected endpoint.

### View unavailable

- Code: `UNAVAILABLE`
- Description: Live fills are not currently available.

### Lost live fills

- Code: `ABORTED`
- Description: Frame loss or a stream state reset ended this live-only stream.

### Slow consumer

- Code: `DEADLINE_EXCEEDED`
- Description: The consumer was too slow; reconnect.

### Unauthenticated

- Code: `UNAUTHENTICATED`
- Description: Usable x-api-key metadata was not supplied.

### Permission denied

- Code: `PERMISSION_DENIED`
- Description: The supplied credential cannot call this service.

## Sequencing and recovery

Require contiguous `sequence` values. On a gap or `ABORTED`, reconnect for new activity and recover missed blocks from [StreamFills](https://www.dwellir.com/docs/hyperliquid/stream_fills) or durable [historical data](https://www.dwellir.com/docs/hyperliquid/historical-data). Common live-stream errors are listed on the [gRPC overview](https://www.dwellir.com/docs/hyperliquid/grpc#v3-market-streaming-service).

Related references: [StreamAllFills](https://www.dwellir.com/docs/hyperliquid/stream_all_fills) and [StreamTrades](https://www.dwellir.com/docs/hyperliquid/stream_trades).
