Skip to content

Implement a new pallet services-payment-price-oracle to be able to store TANSSI/STAR token price#1477

Open
evgeny-s wants to merge 21 commits intomasterfrom
evgeny-token-price-oracle
Open

Implement a new pallet services-payment-price-oracle to be able to store TANSSI/STAR token price#1477
evgeny-s wants to merge 21 commits intomasterfrom
evgeny-token-price-oracle

Conversation

@evgeny-s
Copy link
Contributor

@evgeny-s evgeny-s commented Jan 23, 2026

Summary

This PR implements a new pallet that encapsulates the token price storage functionality as well as the price calculation for Tanssi services like block production cost and collator assignment.

Changes

  1. New pallet - pallet-services-payment-price-oracle, that stores the token_price (TokenPriceUsd), that can be updated via the extrinsic with sudo origin. It calculates the service cost based on fixed monthly cost (FixedMonthlyServicesCostUsd), keeping the ratio via configuration ReferenceBlockCost and ReferenceSessionCost.
  2. Added new Proxy type - SudoOraclePrice, which guards all the extrinsics besides the one that updates the token price.
  3. Update the block_cost and collator_assignment_cost function. It calculates the cost based on the token price; it falls back to fixed prices otherwise (old behavior).

Implementation Plan

  • New pallet implementation
  • Add Rust tests for the pallet
  • Add benchmarkings
  • Integrate with Dancelight runtime
  • Integrate with Starlight runtime
  • Add boundaries for the price
  • Typescript tests

Improvements (for future)

  • We might want to store a set of prices instead of just one, and calculate their average. This way, we can avoid large spikes caused by volatility in either direction.
  • Emergency pause functionality
  • Price bounds validation

@coderabbitai
Copy link

coderabbitai bot commented Jan 23, 2026

📝 Walkthrough

Walkthrough

Adds a new Services Payment Price Oracle pallet and runtime-api, integrates it into Dancelight and Starlight runtimes (config, proxy routing, weights, benches, runtime APIs), provides root-gated price-setting and cost-calculation helpers, plus tests, mocks, workspace manifests, and TypeScript API augmentations.

Changes

Cohort / File(s) Summary
Workspace & Manifests
Cargo.toml, pallets/services-payment-price-oracle/Cargo.toml, pallets/services-payment-price-oracle/runtime-api/Cargo.toml, chains/.../runtime/dancelight/Cargo.toml, chains/.../runtime/starlight/Cargo.toml
Added new workspace crates for the pallet and runtime-api; registered them in runtimes, enabled std/runtime-benchmarks/try-runtime features and wired dependencies.
Runtime Integration & Constants
chains/orchestrator-relays/runtime/dancelight/src/lib.rs, chains/orchestrator-relays/runtime/starlight/src/lib.rs, chains/.../constants/src/lib.rs
Added ProxyType::SudoOraclePrice and InstanceFilter routing; registered ServicesPaymentPriceOracle in construct_runtime; added USD constants, parameter types, DECIMALS constant, and replaced fixed cost reads with oracle-driven cost lookups with fixed fallbacks.
Runtime Weights
chains/.../src/weights/mod.rs, .../weights/pallet_services_payment_price_oracle.rs (dancelight & starlight)
Exported new weight modules and added autogenerated weight provider implementing set_token_price() weight (base + DB write).
Pallet Runtime API
pallets/services-payment-price-oracle/runtime-api/src/lib.rs
Added ServicesPaymentPriceOracleApi runtime API with token_price_usd(), block_cost(), and collator_assignment_cost().
Pallet Implementation
pallets/services-payment-price-oracle/src/lib.rs
New FRAME pallet: storage TokenPriceUsd, genesis init, set_token_price extrinsic (root-gated), errors/events, helper methods (scale factor, usd→tokens), and functions to compute block/session costs.
Pallet Weights & Benchmarks
pallets/services-payment-price-oracle/src/weights.rs, pallets/services-payment-price-oracle/src/benchmarking.rs
Added WeightInfo trait and SubstrateWeight impls; added benchmark for set_token_price() and harness.
Tests & Mocks
pallets/services-payment-price-oracle/src/mock.rs, pallets/services-payment-price-oracle/src/tests.rs
Added mock runtime, test utilities, and comprehensive unit tests covering price setting, access control, bounds, calculations, ratio/monthly-cost checks, and events.
TypeScript API Augmentations
typescript-api/src/dancelight/interfaces/*, typescript-api/src/starlight/interfaces/*, typescript-api/src/*/interfaces/registry.ts
Added servicesPaymentPriceOracle consts/errors/events/storage/txs (setTokenPrice), added "SudoOraclePrice" to proxy unions, and registry types for pallet Call/Error/Event.
Integration Tests
test/suites/dev-tanssi-relay/pallet-services-payment-price-oracle/test_pallet_services_payment_price_oracle.ts
New end-to-end tests verifying default price, proxy sudo updates, access control, bounds enforcement, and runtime API cost reflections across chains.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(200,200,255,0.5)
    participant Admin as Admin / Sudo
    participant Runtime as Runtime
    participant Oracle as ServicesPaymentPriceOracle
    participant Storage as TokenPriceStorage
    participant CostProv as CostProvider
    participant API as RuntimeAPI
    end

    Admin->>Runtime: Sudo::call(set_token_price(price))
    Runtime->>Oracle: dispatch set_token_price(price)
    Oracle->>Storage: write TokenPriceUsd
    Oracle-->>Runtime: emit PriceUpdated

    CostProv->>Oracle: calculate_block_production_cost()
    Oracle->>Storage: read TokenPriceUsd
    Oracle->>Oracle: compute scale factor & usd_to_tokens
    Oracle-->>CostProv: return block cost (tokens)

    CostProv->>Oracle: calculate_collator_assignment_cost()
    Oracle->>Storage: read TokenPriceUsd
    Oracle->>Oracle: compute scale factor & usd_to_tokens
    Oracle-->>CostProv: return session cost (tokens)

    API->>Oracle: token_price_usd()
    Oracle->>Storage: read TokenPriceUsd
    Oracle-->>API: return FixedU128 or None
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

R4-starlight, V-1700

Suggested reviewers

  • tmpolaczyk
  • Agusrodri
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main objective of the PR: implementing a new pallet to store TANSSI/STAR token price.
Description check ✅ Passed The description is well-structured, covering the summary, detailed changes, implementation checklist, and future improvements. It clearly relates to the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

@evgeny-s evgeny-s added breaking Needs to be mentioned in breaking changes D9-needsaudit👮 PR contains changes to fund-managing logic that should be properly reviewed and externally audited B7-runtimenoteworthy Changes should be noted in any runtime-upgrade release notes R3-dancelight change affects dancelight runtime V-1800 labels Jan 23, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@pallets/services-payment-price-oracle/runtime-api/src/lib.rs`:
- Around line 32-38: Docs claim the functions may return None but the signatures
for block_cost and collator_assignment_cost currently return Balance; change
their return types to Option<Balance> in the runtime API (update fn block_cost()
-> Option<Balance> and fn collator_assignment_cost() -> Option<Balance>) and
then update all corresponding implementations and callers to handle
Some(balance)/None (or alternatively, if you prefer the fixed-cost fallback
behavior, update the docstrings to describe the fallback instead of "None").
Ensure you update every implementation of block_cost and
collator_assignment_cost and any runtime-to-runtime-api call sites to match the
new Option<Balance> signature.

In `@pallets/services-payment-price-oracle/src/benchmarking.rs`:
- Around line 34-38: The benchmark macro is referencing a nonexistent ExtBuilder
in the mock module; update the impl_benchmark_test_suite invocation to use the
existing test externalities helper instead (replace
crate::mock::ExtBuilder.build() with the crate::mock::new_test_ext() call), or
alternatively add an ExtBuilder type in crate::mock that exposes a build()
method; modify the invocation around impl_benchmark_test_suite, referencing the
symbols impl_benchmark_test_suite, crate::mock::new_test_ext, and ExtBuilder as
appropriate so the suite compiles under runtime-benchmarks.
🧹 Nitpick comments (3)
pallets/services-payment-price-oracle/src/weights.rs (1)

17-17: Resolve the TODO in this generated file.

If the file is already generated, remove the TODO or replace it with regeneration instructions.

chains/orchestrator-relays/runtime/dancelight/src/lib.rs (2)

1013-1019: Address the TODO comment for tests.

The SudoOraclePrice proxy filter implementation looks correct and follows the same pattern as SudoValidatorManagement. Consider tracking the TODO for test coverage.

Do you want me to open a GitHub issue to track adding tests for the SudoOraclePrice proxy type?


1755-1773: Consider accounting for read weight in cost providers.

The cost providers correctly implement fallback behavior when the oracle price is unavailable. However, both return Weight::zero() even though calculate_block_production_cost() and calculate_collator_assignment_cost() perform a storage read of TokenPriceUsd.

♻️ Suggested improvement
 pub struct BlockProductionCost<Runtime>(PhantomData<Runtime>);
 impl ProvideBlockProductionCost<Runtime> for BlockProductionCost<Runtime> {
     fn block_cost(_para_id: &ParaId) -> (u128, Weight) {
         // Try to get cost from oracle, fallback to fixed cost if not available
         let cost = pallet_services_payment_price_oracle::Pallet::<Runtime>::calculate_block_production_cost()
             .unwrap_or(FIXED_BLOCK_PRODUCTION_COST);
-        (cost, Weight::zero())
+        (cost, <Runtime as frame_system::Config>::DbWeight::get().reads(1))
     }
 }

@evgeny-s
Copy link
Contributor Author

@coderabbitai
Could you please review this PR with a focus on potential security issues as well?

@coderabbitai
Copy link

coderabbitai bot commented Jan 23, 2026

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read the main pallet implementation to analyze security aspects
cat pallets/services-payment-price-oracle/src/lib.rs

Length of output: 11954


🏁 Script executed:

#!/bin/bash
# Read the runtime integration to check access control and proxy setup
cat chains/orchestrator-relays/runtime/dancelight/src/lib.rs | head -n 500

Length of output: 18051


🏁 Script executed:

#!/bin/bash
# Continue reading runtime integration focusing on the oracle pallet config and proxy
cat chains/orchestrator-relays/runtime/dancelight/src/lib.rs | sed -n '500,1000p'

Length of output: 18505


🏁 Script executed:

#!/bin/bash
# Read tests to understand expected behavior and edge cases
cat pallets/services-payment-price-oracle/src/tests.rs

Length of output: 7287


🏁 Script executed:

#!/bin/bash
# Check the mock configuration
cat pallets/services-payment-price-oracle/src/mock.rs

Length of output: 3932


🏁 Script executed:

#!/bin/bash
# Continue reading runtime to see oracle pallet configuration and cost provider integration
cat chains/orchestrator-relays/runtime/dancelight/src/lib.rs | sed -n '1000,1500p'

Length of output: 18950


🏁 Script executed:

#!/bin/bash
# Search for the ServicesPaymentPriceOracle pallet configuration in the runtime
rg -A 20 "impl pallet_services_payment_price_oracle::Config" chains/orchestrator-relays/runtime/dancelight/src/lib.rs

Length of output: 993


🏁 Script executed:

#!/bin/bash
# Check how costs are used in the services payment integration
rg -B 5 -A 10 "calculate_block_production_cost\|calculate_collator_assignment_cost" chains/orchestrator-relays/runtime/dancelight/src/lib.rs

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for the complete proxy filtering implementation
rg -B 10 -A 5 "SudoOraclePrice" chains/orchestrator-relays/runtime/dancelight/src/lib.rs

Length of output: 967


🏁 Script executed:

#!/bin/bash
# Check for any TODOs or FIXMEs related to security
rg -i "todo|fixme|hack|unsafe" pallets/services-payment-price-oracle/src/lib.rs

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for CollatorAssignmentCost implementation
rg -B 5 -A 10 "CollatorAssignmentCost" chains/orchestrator-relays/runtime/dancelight/src/lib.rs

Length of output: 4234


🏁 Script executed:

#!/bin/bash
# Check for the constants used in the oracle configuration
rg -B 2 -A 2 "FIXED_MONTHLY_SERVICES_COST_USD|ReferenceBlockCost|ReferenceSessionCost|USD_DECIMALS" chains/orchestrator-relays/runtime/dancelight/src/lib.rs

Length of output: 1075


🏁 Script executed:

#!/bin/bash
# Look for any overflow or bounds checking in arithmetic operations
ast-grep --pattern 'checked_$_($_)'  pallets/services-payment-price-oracle/src/lib.rs

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if there are any other pallets that depend on the price oracle
rg "ServicesPaymentPriceOracle" --type rust -g '!target' -g '!**/weights/**' | head -30

Length of output: 3953


@evgeny-s, I've completed a comprehensive security review of the price oracle pallet. Here are my findings:

🔴 Critical Security Issues

1. No Price Bounds Validation

Location: pallets/services-payment-price-oracle/src/lib.rs - Line 166 in set_token_price()

The pallet only validates that price is non-zero, but doesn't enforce minimum or maximum bounds. This creates significant economic risks:

  • Extremely high price (e.g., $1M/token): Makes services nearly free, potentially draining the treasury or causing economic imbalance
  • Extremely low price (e.g., $0.000001/token): Makes services prohibitively expensive, effectively DoS-ing the network

Recommendation: Add reasonable bounds validation:

pub const MIN_ACCEPTABLE_PRICE: u128 = FixedU128::from_u32(0.001).into_inner(); // $0.001
pub const MAX_ACCEPTABLE_PRICE: u128 = FixedU128::from_u32(1000).into_inner();  // $1000

ensure!(
    price.into_inner() >= MIN_ACCEPTABLE_PRICE && price.into_inner() <= MAX_ACCEPTABLE_PRICE,
    Error::<T>::PriceOutOfBounds
);

🟠 High Security Issues

2. No Rate Limiting or Price Change Caps

Location: pallets/services-payment-price-oracle/src/lib.rs - set_token_price()

Price can be updated multiple times per block with no restrictions on:

  • Frequency of updates
  • Magnitude of price changes

This allows a compromised sudo account to cause economic chaos by rapidly changing prices or making extreme adjustments.

Recommendation: Implement price change constraints:

// Maximum % change per update (e.g., 20%)
const MAX_PRICE_CHANGE_PERCENT: u32 = 20;

// Validate price change if previous price exists
if let Some(old_price) = TokenPriceUsd::<T>::get() {
    let change_ratio = if price > old_price {
        price.saturating_sub(old_price).checked_div(&old_price)
    } else {
        old_price.saturating_sub(price).checked_div(&old_price)
    };
    ensure!(
        change_ratio <= FixedU128::from_u32(MAX_PRICE_CHANGE_PERCENT) / FixedU128::from_u32(100),
        Error::<T>::PriceChangeTooLarge
    );
}

3. Integer Overflow Risk in usd_to_tokens()

Location: Line 301-313

While the function uses checked_mul, the intermediate calculation could overflow before the check:

usd_amount
    .checked_mul(FixedU128::DIV)?
    .checked_div(10u128.pow(USD_DECIMALS))?

The multiplication by FixedU128::DIV (which is 10^18) happens before division, risking overflow with large USD amounts.

Recommendation: Reorder operations or use FixedU128::saturating_from_rational() for safer conversions.

🟡 Medium Security Issues

4. Overly Broad Proxy Filter

Location: chains/orchestrator-relays/runtime/dancelight/src/lib.rs - Lines 1006-1011

The SudoOraclePrice proxy type allows ALL calls to ServicesPaymentPriceOracle, not just set_token_price:

ProxyType::SudoOraclePrice => match c {
    RuntimeCall::Sudo(pallet_sudo::Call::sudo { call: ref x }) => {
        matches!(x.as_ref(), &RuntimeCall::ServicesPaymentPriceOracle(..))  // Too broad!
    }
    _ => false,
},

If future extrinsics are added to the pallet, they would be automatically accessible through this proxy without explicit consideration.

Recommendation: Be specific about allowed calls:

ProxyType::SudoOraclePrice => match c {
    RuntimeCall::Sudo(pallet_sudo::Call::sudo { call: ref x }) => {
        matches!(
            x.as_ref(),
            &RuntimeCall::ServicesPaymentPriceOracle(
                pallet_services_payment_price_oracle::Call::set_token_price { .. }
            )
        )
    }
    _ => false,
},

5. No Time-Delay or Governance Period

The price takes effect immediately upon calling set_token_price(). Consider implementing a time-delay mechanism (similar to OpenZeppelin's TimelockController) for critical parameter changes, allowing the community to react to malicious updates.

6. Arithmetic Corner Cases

Location: Lines 226-228, 241-243

The blocks_per_month() and sessions_per_month() functions return 0 if block time or session duration is 0, which would cause calculate_scale_factor() to return None (division by zero protection). However, this could mask configuration errors.

Recommendation: Add explicit validation at genesis or in Config that these parameters cannot be zero.

🔵 Low/Informational Issues

7. Missing Tests

Line 1005 has a TODO comment: // TODO: Add tests for SudoOraclePrice. The proxy filtering logic should be thoroughly tested.

8. Minimum Cost of 1 Base Unit

Lines 273, 285: The minimum cost of 1 base unit (10^-12 tokens) might be insufficient and could lead to unintended economic behavior. Consider if this threshold is appropriate for your tokenomics.

9. No Price Staleness Check

Consider adding a timestamp-based staleness check. If the price hasn't been updated in X days, the system could fall back to fixed costs or emit a warning event.

10. No Emergency Stop Mechanism

Consider adding an emergency pause mechanism that can temporarily disable oracle-based pricing and revert to fixed costs if an exploit is detected.

✅ Positive Security Features

  1. Access control properly implemented with EnsureRoot
  2. Graceful fallback to fixed costs when price unavailable
  3. Extensive use of checked arithmetic and Option types
  4. Zero price validation prevents accidental misconfiguration
  5. Comprehensive test coverage for core functionality
  6. Event emission for price updates enables monitoring

Recommendations Summary

Immediate Actions:

  1. Add price bounds validation (min/max)
  2. Fix SudoOraclePrice proxy filter to be more specific
  3. Add tests for the proxy filtering logic
  4. Review and fix potential overflow in usd_to_tokens()

Before Mainnet:

  1. Implement price change rate limits
  2. Consider time-delay mechanism for price updates
  3. Add price staleness checks
  4. Implement emergency pause functionality
  5. Add monitoring/alerting for extreme price changes

Nice to Have:

  1. Multi-sig or governance-based price oracle updates
  2. Price history tracking
  3. Automated sanity checks against external price feeds

The implementation is generally solid with good defensive programming practices. The main concerns are around economic attack vectors from price manipulation, which should be addressed before deployment to production.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 23, 2026

WASM runtime size check:

Compared to target branch

dancebox runtime: 1900 KB (no changes) ✅

flashbox runtime: 1124 KB (no changes) ✅

dancelight runtime: 2680 KB (+24 KB) 🚨

starlight runtime: 2584 KB (no changes) 🚨

container chain template simple runtime: 1516 KB (no changes) ✅

container chain template frontier runtime: 1848 KB (no changes) ✅

@evgeny-s
Copy link
Contributor Author

/cmd generate-ts-api

@github-actions
Copy link
Contributor

github-actions bot commented Jan 23, 2026

Coverage Report

(master)

@@                      Coverage Diff                      @@
##           master   evgeny-token-price-oracle      +/-   ##
=============================================================
- Coverage   73.85%                      73.83%   -0.02%     
+ Files         568                         573       +5     
+ Lines       82793                       82938     +145     
=============================================================
+ Hits        61141                       61235      +94     
+ Misses      21652                       21703      +51     
Files Changed Coverage
/chains/orchestrator-relays/runtime/dancelight/src/lib.rs 36.40% (-0.21%)
/chains/orchestrator-relays/runtime/starlight/src/lib.rs 36.18% (-0.20%)

Coverage generated

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@chains/orchestrator-relays/runtime/dancelight/src/lib.rs`:
- Around line 920-921: The SudoOraclePrice proxy filter currently allows any
ServicesPaymentPriceOracle call under sudo; limit it to only the intended
extrinsic by changing the SudoOraclePrice match to allow
ServicesPaymentPriceOracle::set_token_price(_) and deny all other
ServicesPaymentPriceOracle variants (reference the SudoOraclePrice variant and
ServicesPaymentPriceOracle enum and the set_token_price function); update the
proxy/permission check logic where SudoOraclePrice is used to enforce this
specific variant check and add unit tests covering acceptance of set_token_price
and rejection of other ServicesPaymentPriceOracle calls (add tests for the TODO
at the set_token_price location).

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@chains/orchestrator-relays/runtime/starlight/src/lib.rs`:
- Around line 1017-1022: The ProxyType::SudoOraclePrice branch currently allows
any RuntimeCall::ServicesPaymentPriceOracle via the Sudo wrapper; narrow this to
only permit the specific set_token_price extrinsic by changing the inner match
on x to explicitly match RuntimeCall::ServicesPaymentPriceOracle(...) for the
set_token_price variant (the exact variant name used in the pallet), instead of
a wildcard matches!(), so only RuntimeCall::Sudo(pallet_sudo::Call::sudo { call:
ref x }) where x is ServicesPaymentPriceOracle::set_token_price is allowed.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@pallets/services-payment-price-oracle/src/lib.rs`:
- Around line 156-165: The genesis builder for GenesisConfig::build currently
accepts initial_price without bounds checking; change it to enforce configured
min/max bounds by comparing FixedU128::from_inner(price) against the pallet's
configured limits (e.g., T::MinPriceUsd::get() and T::MaxPriceUsd::get() or the
appropriate associated constants/ storage getters) and only call
TokenPriceUsd::<T>::put(fixed_price) if fixed_price is within these bounds; if
out of range, fail fast via an assert/panic or skip setting and document the
behavior so genesis cannot silently install an out‑of‑range price.
- Around line 323-335: The current conversion in usd_to_tokens multiplies
usd_amount by FixedU128::DIV which can overflow; replace that manual scaling
with FixedU128::checked_from_rational to build usd_scaled safely (e.g.,
FixedU128::checked_from_rational(usd_amount, 10u128.pow(USD_DECIMALS))). Then
perform tokens_fixed = usd_scaled.checked_div(&price) as before and convert to
integer tokens using
into_inner().checked_mul(one_token)?.checked_div(FixedU128::DIV) — this avoids
the usd_amount * FixedU128::DIV overflow while preserving the same scaling logic
in the usd_to_tokens flow.
♻️ Duplicate comments (2)
chains/orchestrator-relays/runtime/dancelight/src/lib.rs (1)

1022-1026: Tighten SudoOraclePrice to only allow set_token_price.
Current filter grants all ServicesPaymentPriceOracle calls under sudo, which is overly broad for future extrinsics.

🔒 Suggested restriction
 ProxyType::SudoOraclePrice => match c {
     RuntimeCall::Sudo(pallet_sudo::Call::sudo { call: ref x }) => {
-        matches!(x.as_ref(), &RuntimeCall::ServicesPaymentPriceOracle(..))
+        matches!(
+            x.as_ref(),
+            &RuntimeCall::ServicesPaymentPriceOracle(
+                pallet_services_payment_price_oracle::Call::set_token_price { .. }
+            )
+        )
     }
     _ => false,
 },

Also please cover the TODO with proxy‑filter tests.

chains/orchestrator-relays/runtime/starlight/src/lib.rs (1)

1017-1022: Overly broad proxy filter allows any ServicesPaymentPriceOracle call.

The SudoOraclePrice proxy type matches any call to ServicesPaymentPriceOracle, not just set_token_price. If future extrinsics are added to this pallet, they would automatically be allowed through this proxy without explicit approval.

Restrict the proxy to only the intended set_token_price call:

🔒 Proposed fix to restrict proxy filter
 ProxyType::SudoOraclePrice => match c {
     RuntimeCall::Sudo(pallet_sudo::Call::sudo { call: ref x }) => {
-        matches!(x.as_ref(), &RuntimeCall::ServicesPaymentPriceOracle(..))
+        matches!(
+            x.as_ref(),
+            &RuntimeCall::ServicesPaymentPriceOracle(
+                pallet_services_payment_price_oracle::Call::set_token_price { .. }
+            )
+        )
     }
     _ => false,
 },

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@test/suites/dev-tanssi-relay/pallet-services-payment-price-oracle/test_pallet_services_payment_price_oracle.ts`:
- Around line 149-163: The test computes belowMinPriceValue from minTokenPrice
but when minTokenPrice === 1 the value equals the min (not below), making the
test ineffective; update the logic around belowMinPriceValue in the
test_pallet_services_payment_price_oracle.ts test: if minPriceConst > 1n keep
minPriceConst - 1n and assert PriceOutOfBounds on setTokenPrice, but if
minPriceConst <= 1n set belowMinPriceValue to 0n and either expect the pallet's
zero-price rejection (adjust the expected error from PriceOutOfBounds to the
zero-price error) or assert the appropriate behavior (skip the bound-check
assertion) after calling setTokenPrice; ensure you still construct belowMinPrice
via polkadotJs.createType("FixedU128", belowMinPriceValue) and use the same sudo
dispatch flow and retrieveSudoDispatchErrors to verify the correct error event.

@evgeny-s evgeny-s added the A8-mergeoncegreen Pull request is reviewed well. label Jan 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A8-mergeoncegreen Pull request is reviewed well. B7-runtimenoteworthy Changes should be noted in any runtime-upgrade release notes breaking Needs to be mentioned in breaking changes D9-needsaudit👮 PR contains changes to fund-managing logic that should be properly reviewed and externally audited R3-dancelight change affects dancelight runtime V-1800

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant