Skip to content

feat: admin rotation cooldown, API key scoping, core SDK bundle, RPC failover - #1503

Merged
joelpeace48-cell merged 4 commits into
FinesseStudioLab:mainfrom
trustosaretin:feat/stellar-wave-1353-1359-1360-1361-v2
Oct 21, 2026
Merged

joelpeace48-cell merged 4 commits into
FinesseStudioLab:mainfrom
trustosaretin:feat/stellar-wave-1353-1359-1360-1361-v2

Conversation

@trustosaretin

Copy link
Copy Markdown
Contributor

Closes #1353, Closes #1359, Closes #1360, Closes #1361

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Refactoring (no functional or behavioral changes)
  • Performance improvement
  • Documentation update
  • Build / CI configuration change
  • Dependency update
  • Other:

Summary

Four focused changes covering contract admin safety, API key scoping, a framework-free SDK entry point, and RPC failover. Each issue is resolved in a single dedicated commit with tests where the surrounding code already had a test harness.

Motivation / Context

Closes #1353, Closes #1359, Closes #1360, Closes #1361


Changes

#1353 — 24-hour admin rotation cooling period (98f23145)

  • propose_admin now records the proposal timestamp in PENDING_ADMIN_AT.
  • accept_admin rejects with Error::AdminCooldownActive (code 128) until ADMIN_ROTATION_COOLDOWN_SECS (86 400) has elapsed.
  • Applied to both contracts/campaign and contracts/rewards.
  • Tests cover the happy path, accept-before-cooldown rejection, and unauthorized callers.

#1361 — read/write API key scoping on operator REST endpoints (dfcd53b0)

  • Authenticated GET routes on operator endpoints now require campaigns:read.
  • Mutating routes require campaigns:write.
  • Removed duplicate unscoped registrations for campaign update/delete/publish/archive that previously bypassed scope checks.

#1359 — @trivela/core lightweight bundle (7e3e5322)

  • New sdk/core/ package with zero UI framework dependencies.
  • Minimal fetch-based REST client (http.ts) that works in Node and the browser.
  • Clean package surface via index.ts and package.json.

#1360 — auto-reconnect fallback RPC node manager (edd38bde)

  • RpcNodeManager tries the primary Soroban RPC node first and fails over to secondaries on HTTP 5xx or transport errors.
  • Unhealthy nodes are retried after a backoff window.
  • Unit tests cover failover, recovery, and error classification (sdk/core/test/rpc.test.ts).

Testing

Area Command / evidence
Contracts cargo test in contracts/campaign and contracts/rewards — new cases test_campaign_accept_admin_before_cooldown_fails, test_campaign_propose_and_accept_admin_happy_path, test_campaign_only_pending_can_accept, test_campaign_propose_without_accept_keeps_old_admin
SDK RPC manager sdk/core/test/rpc.test.ts — failover on 5xx, transport-error fallback, backoff recovery, error classification
Backend scoping Route-level review of backend/src/index.js; scope middleware unchanged, only route registrations updated

Tradeoffs

  • Cooldown is stored per-contract instance (instance() storage) — simplest correct choice for a single-admin rotation slot; no per-key history is kept.
  • proposed_at defaults to 0 when missing, so a legacy pending admin (pre-upgrade) is immediately acceptable rather than locking the contract.
  • RpcNodeManager uses a fixed backoff window rather than exponential — keeps the surface small and testable.

Out of scope

  • No frontend or docs changes.
  • No migration/backfill tooling for existing pending-admin slots (covered by the unwrap_or(0) fallback).
  • No changes to the existing packages/sdk React-coupled bundle; @trivela/core is additive.

Emergency admin rotation now records the proposal timestamp and refuses
accept_admin until ADMIN_ROTATION_COOLDOWN_SECS (86400) has elapsed,
returning Error::AdminCooldownActive if called too early. Covers both
the rewards and campaign contracts.
…dpoints

Operator-facing routes now require campaigns:read for authenticated GETs
and campaigns:write for mutations, so external integrations can be issued
read-only or write-scoped keys. Removes duplicate unscoped registrations
for campaign update/delete/publish/archive that previously bypassed
scope checks.
New vanilla JS/TS SDK entry point with zero UI framework dependencies.
Provides a minimal fetch-based REST client for Node and browser runtimes
and a framework-free package surface for external integrations.
RpcNodeManager tries the primary Soroban RPC node first and fails over to
secondary nodes on HTTP 5xx or transport errors. Unhealthy nodes are
reconnected automatically after a backoff window. Includes unit tests
covering failover, recovery, and error classification.
@drips-wave

drips-wave Bot commented Oct 21, 2026

Copy link
Copy Markdown

@trustosaretin Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Comment thread sdk/core/src/http.ts
throw new Error('fetch is not available in this runtime; pass config.fetchImpl');
}

const baseUrl = config.baseUrl.replace(/\/+$/, '');
@joelpeace48-cell
joelpeace48-cell merged commit d6c91e4 into FinesseStudioLab:main Oct 21, 2026
7 of 29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants