Skip to content

Support multiple fee receiver accounts - #100

Open
janezpodhostnik wants to merge 4 commits into
mainfrom
janezp/fee-receivers
Open

Support multiple fee receiver accounts#100
janezpodhostnik wants to merge 4 commits into
mainfrom
janezp/fee-receivers

Conversation

@janezpodhostnik

@janezpodhostnik janezpodhostnik commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Testnet distributes transaction fee deposits across multiple receiver accounts
since the FlowFees concurrent fee collection upgrade (rolled out in tx
be210889dd26a320f530595bd369093e866e26c3941bf7a3d01f861db3eeda81). Rosetta
only recognized deposits to the FlowFees contract account as fees, so deposits
to the child fee accounts were misclassified as ordinary transfers.

Changes

  • Replace the single feeAddr with a set of fee addresses
    (Contracts.FeeAddresses()): the FlowFees account plus a new
    .contracts.fee_receivers config list, documented in the README.
  • Add the three testnet fee receivers to testnet.json, verified against the
    on-chain FlowFees.getFeeReceiverAddresses() getter.
  • Add a startup check (validateFeeReceivers) that fetches the on-chain
    receiver list via a new get-fee-receivers script and exits with a fatal
    error if any on-chain receiver is missing from the config, so future
    receiver additions fail loudly instead of silently misclassifying fees.
    Extra configured addresses are allowed, since they may be needed to
    classify fees in historical blocks.
  • Upgrade flow-go to pull in flow-core-contracts v1.10.4, whose
    getFeeReceiverAddresses() getter the script uses.

Notes

  • Mainnet has no child fee accounts yet, so mainnet.json is unchanged and
    behavior there is identical. Once the upgrade rolls out there, the startup
    check will flag the new receivers and mainnet.json just needs a
    fee_receivers entry.
  • go.mod currently pins the head commit of Upgrade flow-core-contracts to v1.10.4 flow-go#8632, which is not
    yet merged. Do not merge this PR until it lands and the pin is updated to a
    master commit.

Related: onflow/flow-core-contracts#575, onflow/flow-core-contracts#615, onflow/flow-go#8632

Summary by CodeRabbit

  • New Features

    • Added support for configuring multiple transaction fee receiver addresses.
    • Fee deposits and transfer validation now recognize all configured receivers.
    • Added startup validation to confirm configured receivers match on-chain settings.
    • Added testnet configuration with three fee receiver addresses.
  • Documentation

    • Documented the optional fee_receivers setting, address examples, fee behavior, and validation.
  • Bug Fixes

    • Prevented transfers to any configured fee receiver, rather than only the primary fee contract.

@janezpodhostnik
janezpodhostnik requested a review from a team as a code owner July 23, 2026 14:13
@janezpodhostnik janezpodhostnik self-assigned this Jul 23, 2026
@janezpodhostnik janezpodhostnik changed the title support multiple fee receiver accounts Support multiple fee receiver accounts Jul 23, 2026
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Kay-Zee, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 46 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d3bd04ee-1e0e-4c6c-9a99-5799fc79fbbd

📥 Commits

Reviewing files that changed from the base of the PR and between c220b1f and aac270d.

📒 Files selected for processing (1)
  • api/validate.go
📝 Walkthrough

Walkthrough

Changes

Fee receiver configuration and processing

Layer / File(s) Summary
Receiver configuration and script contract
config/config.go, config/config_test.go, script/..., go.mod, testnet.json
Adds configurable fee_receivers, address decoding and deduplication, the get_fee_receivers Cadence script, compilation tests, dependency updates, and testnet receiver settings.
Server initialization and on-chain validation
api/api.go, api/validate.go
Loads multiple fee receiver addresses, compiles the retrieval script, and validates on-chain receivers with retries and response checks.
Multi-address fee processing and documentation
state/..., api/construction_service.go, README.md
Recognizes deposits to all fee receiver addresses, rejects transfers to those addresses, and documents configuration and startup validation.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Server
  participant FlowClient
  participant FlowFees
  participant Logger
  Server->>FlowClient: Retrieve latest block
  Server->>FlowClient: Execute get_fee_receivers
  FlowClient->>FlowFees: Call getFeeReceiverAddresses()
  FlowFees-->>FlowClient: Return receiver addresses
  FlowClient-->>Server: Return Cadence result
  Server->>Logger: Log validation result
Loading

Suggested reviewers: vishalchangrani, tim-barry, kay-zee

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: support for multiple fee receiver accounts.
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.
✨ 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 janezp/fee-receivers

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.

Comment thread go.mod

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are the dependency updates needed or accidentally part of this PR?

Base automatically changed from janezp/localnet-test-fixes to main August 4, 2026 22:04

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@api/api.go`:
- Around line 108-109: Make successful fee-receiver validation a prerequisite
for readiness: update api/api.go lines 108-109 so Run either waits for
validateFeeReceivers before serving or keeps the service unready and rejects
construction requests until it succeeds. In api/validate.go lines 45-56 and 76,
propagate malformed validation results and retry exhaustion to that
startup/readiness gate instead of only logging them. Document the finalized
readiness behavior in README.md lines 377-380.

In `@api/validate.go`:
- Around line 24-26: Move the DataAccessNodes.Client() call from before the
retry loop into the loop around the existing attempt logic, so each retry
selects an access node independently while preserving the five-attempt behavior.

In `@go.mod`:
- Around line 14-16: Update the flow-go dependency pin in go.mod from commit
2799d6025ac3 to a current commit that contains upstream onflow/flow-go#8632,
specifically at or after merge commit b73fea20b2529a55c2bc3c3abb59a2ad891bba15;
alternatively, merge the prerequisite commit before retaining this change.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bc3db4ce-6190-4d11-bef1-0c0fc45a3f3c

📥 Commits

Reviewing files that changed from the base of the PR and between 1524dda and c220b1f.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (13)
  • README.md
  • api/api.go
  • api/construction_service.go
  • api/validate.go
  • config/config.go
  • config/config_test.go
  • go.mod
  • script/cadence/scripts/get-fee-receivers.cdc
  • script/script.go
  • script/script_test.go
  • state/process.go
  • state/state.go
  • testnet.json

Comment thread api/api.go
Comment on lines +108 to +109
s.feeAddrs = s.Chain.Contracts.FeeAddresses()
go s.validateFeeReceivers(ctx)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Make successful fee-receiver validation a readiness requirement.

Run starts validation in a goroutine and then starts the HTTP server. If configuration omits an active receiver, ConstructionPreprocess can accept a construction request for a transfer to that receiver before validation completes. A malformed result or exhausted retries also ends validation with only a log entry, so the service can continue without successful validation.

  • api/api.go#L108-L109: wait for successful validation before serving, or keep the service unready and reject construction requests until validation succeeds.
  • api/validate.go#L45-L56: propagate malformed-result failures to the startup or readiness gate.
  • api/validate.go#L76-L76: propagate retry exhaustion to the startup or readiness gate.
  • README.md#L377-L380: document the finalized readiness behavior.
📍 Affects 3 files
  • api/api.go#L108-L109 (this comment)
  • api/validate.go#L45-L56
  • api/validate.go#L76-L76
  • README.md#L377-L380
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/api.go` around lines 108 - 109, Make successful fee-receiver validation a
prerequisite for readiness: update api/api.go lines 108-109 so Run either waits
for validateFeeReceivers before serving or keeps the service unready and rejects
construction requests until it succeeds. In api/validate.go lines 45-56 and 76,
propagate malformed validation results and retry exhaustion to that
startup/readiness gate instead of only logging them. Document the finalized
readiness behavior in README.md lines 377-380.

Comment thread api/validate.go Outdated
Comment thread go.mod
Comment on lines +14 to +16
github.com/onflow/cadence v1.10.5
github.com/onflow/crypto v0.25.4
github.com/onflow/flow-go v0.48.1-evm-cache-block.0.20260518173711-5b9fa9c8352e
github.com/onflow/flow-go v0.50.1-0.20260731132755-2799d6025ac3

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

pr="$(gh api repos/onflow/flow-go/pulls/8632 --jq '{state, merged_at, merge_commit_sha, head_sha: .head.sha}')"
printf '%s\n' "$pr"

merge_sha="$(printf '%s' "$pr" | jq -r '.merge_commit_sha')"
test "$merge_sha" != "null"

gh api "repos/onflow/flow-go/compare/${merge_sha}...2799d6025ac3" \
  --jq '{status, ahead_by, behind_by}'

Repository: onflow/rosetta

Length of output: 370


Flow commit 2799d6025ac3 does not include upstream onflow/flow-go#8632.

onflow/flow-go#8632 merged at b73fea20b2529a55c2bc3c3abb59a2ad891bba15, but 2799d6025ac3 is 30 commits behind that merge commit. Use a current flow-go pin that contains the required merge, or merge the prerequisite before this change.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@go.mod` around lines 14 - 16, Update the flow-go dependency pin in go.mod
from commit 2799d6025ac3 to a current commit that contains upstream
onflow/flow-go#8632, specifically at or after merge commit
b73fea20b2529a55c2bc3c3abb59a2ad891bba15; alternatively, merge the prerequisite
commit before retaining this change.

@Kay-Zee

Kay-Zee commented Aug 4, 2026

Copy link
Copy Markdown
Member

Notes on the CodeRabbit review threads:

go.mod pin — false positive: 2799d6025ac3 is the head commit of flow-go#8632 and the second parent of its merge commit b73fea20 (compare/2799d6025ac3...b73fea20 → ahead by 30, behind by 0). The bot's compare ran in the opposite direction. The pin already contains the prerequisite.

Dependency updates — intentional: this PR needs flow-go with core-contracts v1.10.4 (the fee-receiver getter); cadence/sdk bumps ride along.

Access node per retry — valid, applied in aac270d. Note the shipped configs run a single access node per spork, so in practice this is a consistency fix (every other call site already picks via Client() per request) rather than a behavior change — but it's the right pattern for multi-node operators.

Readiness gate — not taking this one. The dangerous case (an on-chain receiver missing from config) already ends in log.Fatalf, a stronger guarantee than unready. And on networks whose FlowFees predates getFeeReceiverAddresses, the script can never succeed — gating readiness on it would leave the server permanently unready there.

There is a genuine small gap nearby though: after 5 failed attempts, validation gives up for good with a single log line. A flaky access node at startup plus a stale config would leave the server running with an unvalidated fee set indefinitely. Follow-up idea for @janezpodhostnik (not a blocker): after the quick retries, fall back to a slow poll instead of returning, and/or surface the validation state via /call, matching validateBalances.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@Kay-Zee Thanks for the detailed verification.

I withdraw the flow-go pin concern. The pinned commit already contains the required prerequisite.

The dependency updates are necessary for FlowFees.getFeeReceiverAddresses().

The aac270d change correctly makes each validation retry select an access node through Client().

I also withdraw the readiness-gate concern. Older FlowFees deployments can lack getFeeReceiverAddresses, so validation must not block serving.

The slow-poll or /call validation-state work is a valid non-blocking follow-up. Would you like me to open a GitHub issue for it and assign it to @Kay-Zee?

🐇


✏️ Learnings added
Learnt from: Kay-Zee
URL: https://github.com/onflow/rosetta/pull/100

Timestamp: 2026-08-04T22:42:47.988Z
Learning: In the Flow Rosetta service, fee-receiver validation must remain asynchronous and must not gate readiness. Some supported networks can run an older FlowFees contract that does not provide `FlowFees.getFeeReceiverAddresses()`, so validation cannot succeed on those networks. A missing configured on-chain receiver remains fatal when validation does succeed.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

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.

3 participants