Skip to content

feat: index RewardCallerSet reward caller delegation - #253

Merged
rickstaa merged 1 commit into
mainfrom
feat/index-reward-caller-set
Aug 4, 2026
Merged

feat: index RewardCallerSet reward caller delegation#253
rickstaa merged 1 commit into
mainfrom
feat/index-reward-caller-set

Conversation

@rickstaa

@rickstaa rickstaa commented Aug 3, 2026

Copy link
Copy Markdown
Member

Description

livepeer/protocol#648 lets an orchestrator nominate a single address it trusts to call reward() on its behalf, so the main wallet no longer has to stay unlocked every round. It adds one event, RewardCallerSet(address indexed transcoder, address indexed rewardCaller), which the subgraph did not index — so a delegation was invisible to the Explorer and an orchestrator had no way to confirm from indexed data that it took effect.

This adds:

  • Transcoder.rewardCaller: String — nullable, null when unset, alongside serviceURI
  • RewardCallerSetEvent — the standard Event shape, recording the literal 0x0 on unset so
    unset actions stay in history
  • A rewardCallerSet handler, following the serviceURIUpdate / transcoderUpdate pattern

The upgrade is already live on Arbitrum One (target 0xbe197fc…Bd2, artifacts in livepeer/protocol#660), so these events can land today.

The Reward path is deliberately untouched

PR 648 refactored rewardWithHint into a private _rewardWithHint(_transcoder, ...) and switched every emit inside it from msg.sender to _transcoder. The Reward(indexed address,uint256) signature and semantics are unchanged, so both existing handlers — reward in bondingManager.ts and updatePollTallyOnReward on the PollTallyTemplate — stay correct without modification.

One behavioural consequence worth knowing, no code change: once delegation is in use, Transaction.from on a reward tx is the reward caller, not the orchestrator. Per-event attribution via RewardEvent.delegate remains authoritative. No caller field was added to RewardEvent — it would duplicate transaction.from, which is already reachable and is transaction-level rather than per-event.

ABI

The RewardCallerSet entry in abis/BondingManager.json was added by hand, copied from deployments/arbitrumMainnet/BondingManagerTarget.json in the protocol repo and diffed to confirm it matches byte-for-byte. This repo has no ABI sync mechanism, and the change was kept narrow rather than mixing a full resync into a feature PR.

Follow-up tracked in #252, which measures the current drift across all ABIs.

Verification

RewardCallerSet cannot be exercised by the local test suite — the livepeer/geth-with-livepeer-protocol:streamflow image predates setRewardCaller. Two real on-chain events serve as fixtures instead, covering both the set and unset branches on the same transcoder, in order:

Block transcoder rewardCaller
489361725 0x8Ad7BCac720DdCc23cfB0b57fb3c7Da02368E947 0x…dEaD (set)
489361734 0x8Ad7BCac720DdCc23cfB0b57fb3c7Da02368E947 0x0 (unset)

A correct implementation ends with rewardCaller: null and two RewardCallerSetEvent rows.

Checklist

  • Ran yarn prepare and verified yarn codegen and yarn build succeed.
  • (Optional) Validated locally with yarn deploy:local.
  • Confirmed the Subgraph Studio preview link in the PR comment works and the subgraph syncs without errors.

Copilot AI review requested due to automatic review settings August 3, 2026 09:05
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

🚀 Subgraph Studio preview deployed

Item Details
Version label pr-253-0d309f6-30900501743
Query endpoint https://api.studio.thegraph.com/query/31909/livepeer-ci/pr-253-0d309f6-30900501743
curl -H 'Content-Type: application/json' \
  -d '{"query":"{ protocol(id: \"0\") { inflation } }"}' \
  https://api.studio.thegraph.com/query/31909/livepeer-ci/pr-253-0d309f6-30900501743

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Reward caller indexing

Layer / File(s) Summary
Reward caller event contract
abis/BondingManager.json, schema.graphql
Defines the RewardCallerSet ABI event, the nullable Transcoder.rewardCaller field, and the RewardCallerSetEvent entity.
Reward caller event handling
src/mappings/bondingManager.ts
Handles reward-caller updates, clears the field for the zero address, persists transaction data, and creates the event entity.
Data source wiring and release metadata
subgraph.template.yaml, package.json
Registers the event and handler, includes the event entity, and updates the package version to 1.4.0.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant BondingManager
  participant rewardCallerSet
  participant Transcoder
  participant RewardCallerSetEvent
  BondingManager->>rewardCallerSet: Emit RewardCallerSet(transcoder, rewardCaller)
  rewardCallerSet->>Transcoder: Set or clear rewardCaller
  rewardCallerSet->>RewardCallerSetEvent: Store event metadata and caller address
Loading

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies indexing for the RewardCallerSet reward-caller delegation event.
Description check ✅ Passed The description explains the change, motivation, verification, dependencies, and checklist status; the issue field and preview confirmation remain incomplete.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/index-reward-caller-set

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds subgraph indexing support for BondingManager’s RewardCallerSet event so reward-caller delegation is visible in indexed data (including preserving unset actions in history).

Changes:

  • Adds Transcoder.rewardCaller (nullable) and a new RewardCallerSetEvent entity to the GraphQL schema.
  • Wires a rewardCallerSet mapping handler and registers the event/handler in the subgraph manifest template.
  • Extends abis/BondingManager.json with the RewardCallerSet event fragment and bumps package version.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
subgraph.template.yaml Registers RewardCallerSet event + handler and exposes RewardCallerSetEvent in the manifest entities list.
src/mappings/bondingManager.ts Implements rewardCallerSet handler to update Transcoder.rewardCaller and persist RewardCallerSetEvent history rows.
schema.graphql Adds the rewardCaller field to Transcoder and introduces the RewardCallerSetEvent entity type.
package.json Bumps package version to 1.4.0.
abis/BondingManager.json Adds the RewardCallerSet(address,address) event to enable codegen/handler wiring.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread schema.graphql
rickstaa added a commit to livepeer/explorer that referenced this pull request Aug 4, 2026
Account history is keyed on the transaction sender:

    transactions(where: { from: $account })

Since LIP-118 (livepeer/protocol#648) an orchestrator can nominate a
reward caller to submit reward() on its behalf. That transaction is sent
by the caller, so it drops out of the query and every event inside it -
including the RewardEvent - disappears from the orchestrator's history.

The event itself was always attributed correctly: RewardEvent.delegate is
the orchestrator regardless of who signed. The blind spot is purely in how
the Explorer asks for it. It cannot be fixed in place either, because
Transaction.events is typed as the Event interface, whose filter exposes
only id/timestamp/transaction/round - delegate lives on the concrete
RewardEvent type, so events_: { delegate: ... } does not exist.

So query the event entity directly, keyed on the orchestrator. This is the
same shape as winningTicketRedeemedEvents, already a separate role-keyed
query in this file for the same reason: a ticket's recipient is an event
param, so it survives being redeemed by a separate wallet.

Excluding RewardEvent from the transaction-path list is what keeps
self-called rewards, which appear in both queries, from rendering twice -
there is no id-based dedupe in this component.

Also require every list to be exhausted before paging stops. Keying that
on transactions alone cuts off exactly the accounts this fixes: an
orchestrator delegating every reward call has few transactions but one
reward event per round. This equally affects gateways with more tickets
than transactions, which 90ab4a1 fixed for totalLoaded but not reachedEnd.

Delegated calls render with the existing copy. Distinguishing them would
mean comparing transaction.from against the account, which is approximate
- a multisig or relayer shows as the sender. The authoritative answer is
Transcoder.rewardCaller, pending livepeer/subgraph#253.
livepeer/protocol#648 lets an orchestrator nominate an address to call
reward() on its behalf. The subgraph had no visibility into these
delegations.

Adds Transcoder.rewardCaller (null when unset) and RewardCallerSetEvent,
wired to RewardCallerSet(indexed address,indexed address).

The Reward path is unchanged: #648 kept emitting Reward(_transcoder), so
attribution stays on the orchestrator and both existing handlers remain
correct.

The RewardCallerSet ABI entry was added by hand from the protocol
deployment artifact. See #252.
Copilot AI review requested due to automatic review settings August 4, 2026 10:24
@rickstaa
rickstaa force-pushed the feat/index-reward-caller-set branch from f6817ca to 53b6b3a Compare August 4, 2026 10:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

@rickstaa
rickstaa merged commit b13e4f2 into main Aug 4, 2026
3 checks passed
@rickstaa
rickstaa deleted the feat/index-reward-caller-set branch August 4, 2026 10:28
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.

2 participants