Skip to content

feat: enumerate OffchainQuotedLinearFee standing quotes#8904

Open
xeno097 wants to merge 1 commit into
audit-q3-2026from
xeno/offchain-fee-enumeration
Open

feat: enumerate OffchainQuotedLinearFee standing quotes#8904
xeno097 wants to merge 1 commit into
audit-q3-2026from
xeno/offchain-fee-enumeration

Conversation

@xeno097

@xeno097 xeno097 commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Description

Exposes OffchainQuotedLinearFee's standing-quote mapping for offchain enumeration.

The quotes mapping (destination => recipient => StoredQuote) is write-only from the chain's perspective — there was no way to enumerate which standing quotes exist. This adds enumerable key-tracking and two views:

  • quoteDomains() — returns the domain ids that have at least one standing quote.
  • getQuotesForDomain(domainId) — returns every quote stored under that exact domain key as QuoteEntry[] (recipient key + StoredQuote).

Implementation:

  • Added a new QuoteEntry { bytes32 recipient; StoredQuote quote; } struct.
  • Added an EnumerableSet.UintSet of domain ids and a per-domain EnumerableSet.Bytes32Set of recipients. Keys are tracked (idempotently) whenever a standing quote is stored; the quote data itself stays in the existing quotes mapping.
  • Entries are never removed: standing quotes expire logically but are never deleted, so enumeration includes logically-expired quotes and the wildcard recipient. Callers filter by quote.expiry.
  • Recipient-only quotes are stored under the WILDCARD_DEST (type(uint32).max) key and apply to every destination, so callers computing effective fees must also query getQuotesForDomain(WILDCARD_DEST). This is documented on the view and covered by a dedicated test.
  • Transient quotes never touch the mapping and are therefore not enumerated.

Drive-by changes

None.

Related issues

None.

Backward compatibility

Yes. Additive only — two new view functions, a new struct, and two private storage sets appended after existing storage. No changes to existing function signatures, the quotes mapping, or fee resolution behavior.

Testing

Unit Tests (Forge). Added a "Quote Enumeration" suite to OffchainQuotedLinearFee.t.sol covering:

  • empty state (no standing quotes)
  • stored entries returned per domain (order-independent, asserted by recipient)
  • separation across domains
  • in-place overwrite does not duplicate keys
  • transient quotes excluded
  • wildcard recipient included
  • wildcard destination enumerated under its own WILDCARD_DEST key, not under specific destinations

@xeno097 xeno097 requested a review from nambrot as a code owner June 16, 2026 15:36
@github-project-automation github-project-automation Bot moved this to In Review in Hyperlane Tasks Jun 16, 2026
@xeno097 xeno097 marked this pull request as draft June 16, 2026 15:36
@xeno097 xeno097 marked this pull request as ready for review June 16, 2026 15:36
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b0cf17e5-cdc0-4309-8338-ff476d731827

📥 Commits

Reviewing files that changed from the base of the PR and between d3bbedf and 30b115e.

📒 Files selected for processing (3)
  • .changeset/offchain-quoted-linear-fee-enumeration.md
  • solidity/contracts/token/fees/OffchainQuotedLinearFee.sol
  • solidity/test/token/OffchainQuotedLinearFee.t.sol

📝 Walkthrough

Walkthrough

OffchainQuotedLinearFee gains on-chain enumeration support for standing quotes. OpenZeppelin EnumerableSet is used to track stored domain IDs and per-domain recipient keys. Two new view functions, quoteDomains() and getQuotesForDomain(domainId), expose this index. A changeset and tests covering all edge cases are included.

Changes

Standing-quote enumeration in OffchainQuotedLinearFee

Layer / File(s) Summary
QuoteEntry struct and enumerable storage indices
solidity/contracts/token/fees/OffchainQuotedLinearFee.sol
Imports EnumerableSet, adds using directives, defines the QuoteEntry return struct, and declares _domainIds (UintSet) and _recipients (mapping of Bytes32Set) as the enumeration index alongside the existing quotes mapping.
_storeStanding index population and new view functions
solidity/contracts/token/fees/OffchainQuotedLinearFee.sol
_storeStanding now calls add on both enumerable sets when persisting a standing quote. quoteDomains() iterates _domainIds and getQuotesForDomain(domainId) iterates _recipients[domainId], hydrating raw QuoteEntry data from the existing quotes mapping.
Enumeration tests and changeset
solidity/test/token/OffchainQuotedLinearFee.t.sol, .changeset/offchain-quoted-linear-fee-enumeration.md
Seven new test cases cover empty state, multi-recipient aggregation, domain separation, overwrite deduplication, transient quote exclusion, wildcard recipient inclusion, and wildcard destination key scoping. Internal helpers _findQuote and _containsDomain support order-tolerant assertions. The changeset documents the public API additions.

Sequence Diagram(s)

sequenceDiagram
  participant Offchain as Offchain Caller
  participant Contract as OffchainQuotedLinearFee
  participant Sets as EnumerableSet Indices
  participant QuoteStore as quotes mapping

  rect rgba(34, 139, 34, 0.5)
    note over Offchain,QuoteStore: Write path (standing quote)
    Offchain->>Contract: storeStandingQuote(dest, recipient, quote)
    Contract->>Sets: _domainIds.add(dest)
    Contract->>Sets: _recipients[dest].add(recipient)
    Contract->>QuoteStore: quotes[dest][recipient] = StoredQuote
  end

  rect rgba(70, 130, 180, 0.5)
    note over Offchain,QuoteStore: Read path (enumeration)
    Offchain->>Contract: quoteDomains()
    Contract->>Sets: _domainIds.values()
    Sets-->>Contract: uint32[] domainIds
    Contract-->>Offchain: uint32[] memory

    Offchain->>Contract: getQuotesForDomain(domainId)
    Contract->>Sets: _recipients[domainId].values()
    Sets-->>Contract: bytes32[] recipientKeys
    Contract->>QuoteStore: quotes[domainId][key] for each key
    QuoteStore-->>Contract: StoredQuote entries
    Contract-->>Offchain: QuoteEntry[] memory
  end
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding enumeration support for standing quotes in OffchainQuotedLinearFee contract.
Description check ✅ Passed The description is comprehensive and well-structured, covering all template sections with clear explanations of implementation details, backward compatibility assurance, and thorough test coverage documentation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

@codecov

codecov Bot commented Jun 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.42%. Comparing base (d3bbedf) to head (30b115e).

Additional details and impacted files
@@                Coverage Diff                @@
##           audit-q3-2026    #8904      +/-   ##
=================================================
+ Coverage          79.33%   79.42%   +0.08%     
=================================================
  Files                143      143              
  Lines               4278     4296      +18     
  Branches             436      437       +1     
=================================================
+ Hits                3394     3412      +18     
  Misses               855      855              
  Partials              29       29              
Flag Coverage Δ
solidity 80.68% <100.00%> (+0.09%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
core 87.80% <ø> (ø)
hooks 78.11% <ø> (ø)
isms 81.46% <ø> (ø)
token 88.12% <100.00%> (+0.12%) ⬆️
middlewares 87.90% <ø> (+0.14%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Review

Development

Successfully merging this pull request may close these issues.

1 participant