Subgraph misaccounts redemptions when a ticket is partially covered by the reserve
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 5
- Forks
- 7
- Avg merge
- 4h 1m
- Merged PRs (30d)
- 6
Description
When a winning ticket's `faceValue` exceeds the sender's deposit, the shortfall is claimed from the reserve and `claimFromReserve` caps the claim at the recipient's per-orchestrator allocation. The actual amount paid out (`WinningTicketTransfer.amount` = deposit + capped reserve claim) can therefore be less than `faceValue`. The subgraph gets several things wrong in this case:
### 1. Actual redeemed amount is not indexed
`WinningTicketTransfer` is not handled at all, and `WinningTicketRedeemedEvent` only stores `faceValue`. Consumers (e.g. the explorer history view) display `faceValue` as the paid amount, which overstates the payout whenever the reserve claim is capped.
### 2. Reserve is deducted twice, and by the wrong amount
For a single redemption tx:
- `reserveClaimed` correctly subtracts the actual claimed amount from `broadcaster.reserve` (`src/mappings/ticketBroker.ts:218`)
- `winningTicketRedeemed` then subtracts from the reserve again (`src/mappings/ticketBroker.ts:63-75`), and due to an ordering bug the deducted amount is the full `faceValue`: `broadcaster.deposit` is zeroed before `difference = faceValue.minus(broadcaster.deposit)` is computed
**Example:** a ticket with `faceValue = X` where only `Y < X` is actually claimable from the reserve drains the indexed reserve by `X + Y` while on-chain it only drops by `Y`. Repeated redemptions collapse the indexed reserve to (near) zero while the on-chain reserve is still funded, so the explorer shows a far lower reserve balance than the contract holds.
### 3. Volume stats use faceValue instead of the actual payout
`broadcaster/transcoder/protocol.totalVolumeETH/USD` and the day entities are incremented by `faceValue` (`src/mappings/ticketBroker.ts:80-109`), inflating fee volume whenever the reserve claim is capped.
### Proposed fix
- Index `WinningTicketTransfer` and store the actual `amount` on `WinningTicketRedeemedEvent` (same tx, emitted immediately before `WinningTicketRedeemed`).
- In `winningTicketRedeemed`, only deduct `min(faceValue, deposit)` from `deposit` and stop touching `reserve`; `reserveClaimed` already owns that deduction.
- Use the actual transfer amount for the volume aggregates.
- Requires a redeploy + full resync to rebuild balances and backfill.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/mappings/ticketBroker.ts, reviewing the WinningTicketTransfer and WinningTicketRedeemed handlers, especially lines 63-109 and 218. Trace the emitted transfer amount and existing reserveClaimed flow, then verify after a full resync that redeemed amounts, reserve balances, and volume aggregates match the actual payout rather than faceValue.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- data
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100