feat: index RewardCallerSet reward caller delegation - #253
Merged
Conversation
|
🚀 Subgraph Studio preview deployed
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 |
📝 WalkthroughWalkthroughChangesReward caller indexing
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
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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 newRewardCallerSetEvententity to the GraphQL schema. - Wires a
rewardCallerSetmapping handler and registers the event/handler in the subgraph manifest template. - Extends
abis/BondingManager.jsonwith theRewardCallerSetevent 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.
This was referenced Aug 3, 2026
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.
rickstaa
force-pushed
the
feat/index-reward-caller-set
branch
from
August 4, 2026 10:24
f6817ca to
53b6b3a
Compare
This was referenced Aug 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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,nullwhen unset, alongsideserviceURIRewardCallerSetEvent— the standardEventshape, recording the literal0x0on unset sounset actions stay in history
rewardCallerSethandler, following theserviceURIUpdate/transcoderUpdatepatternThe upgrade is already live on Arbitrum One (target
0xbe197fc…Bd2, artifacts in livepeer/protocol#660), so these events can land today.The
Rewardpath is deliberately untouchedPR 648 refactored
rewardWithHintinto a private_rewardWithHint(_transcoder, ...)and switched every emit inside it frommsg.senderto_transcoder. TheReward(indexed address,uint256)signature and semantics are unchanged, so both existing handlers —rewardinbondingManager.tsandupdatePollTallyOnRewardon thePollTallyTemplate— stay correct without modification.One behavioural consequence worth knowing, no code change: once delegation is in use,
Transaction.fromon a reward tx is the reward caller, not the orchestrator. Per-event attribution viaRewardEvent.delegateremains authoritative. Nocallerfield was added toRewardEvent— it would duplicatetransaction.from, which is already reachable and is transaction-level rather than per-event.ABI
The
RewardCallerSetentry inabis/BondingManager.jsonwas added by hand, copied fromdeployments/arbitrumMainnet/BondingManagerTarget.jsonin 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
RewardCallerSetcannot be exercised by the local test suite — thelivepeer/geth-with-livepeer-protocol:streamflowimage predatessetRewardCaller. Two real on-chain events serve as fixtures instead, covering both the set and unset branches on the same transcoder, in order:0x8Ad7BCac720DdCc23cfB0b57fb3c7Da02368E9470x…dEaD(set)0x8Ad7BCac720DdCc23cfB0b57fb3c7Da02368E9470x0(unset)A correct implementation ends with
rewardCaller: nulland twoRewardCallerSetEventrows.Checklist
yarn prepareand verifiedyarn codegenandyarn buildsucceed.yarn deploy:local.