Skip to content

On-chain writes prep: signing-key config, slashing flow, cutover runbook, architecture doc - #145

Open
spotkorner-dot wants to merge 8 commits into
stellar-vortex-protocol:mainfrom
spotkorner-dot:feature/onchain-writes-batch
Open

On-chain writes prep: signing-key config, slashing flow, cutover runbook, architecture doc#145
spotkorner-dot wants to merge 8 commits into
stellar-vortex-protocol:mainfrom
spotkorner-dot:feature/onchain-writes-batch

Conversation

@spotkorner-dot

@spotkorner-dot spotkorner-dot commented Jul 25, 2026

Copy link
Copy Markdown

closes #33
closes #34
closes #37
closes #38

Summary

Combined PR covering four related Stellar Wave issues that all sit under
the same "prepare for on-chain writes" umbrella:

#34 — Signing-key config (src/config/env.validation.ts, configuration.ts, .env.example, README)

SOROBAN_SIGNING_KEY is added with strkey-format validation, required in
production
(NODE_ENV=production) and format-checked whenever it's set.
No default anywhere in the schema — unset means empty, not a placeholder.
README documents generating a throwaway testnet-only key for local dev.

#33 — Solver slashing (intents-sweeper.service.ts, new solver-registry.service.ts)

IntentsSweeperService now detects accepted intents whose fill deadline
passed, transitions them to slashed (previously defined in IntentState
but never set anywhere), bumps the solver's fillsFailed counter, and
calls the new SolverRegistryService.

That service builds and simulates (via Soroban RPC simulateTransaction,
which never mutates ledger state) a slash contract call — it does not
submit a live transaction. Two reasons: there's no deployed solver-registry
contract or confirmed function signature to submit against yet (issue #23,
still open, and the vortex-contract repo doesn't exist yet either), and
there's no dry-run/live-mode gate for staged rollout yet (issue #35, also
open). It fails closed to a pure no-op whenever the contract ID or signing
key isn't configured — the default in every environment today. Wiring real
submission is flagged as follow-up work once those two land; see the
docstring in solver-registry.service.ts and the cutover runbook below.

#38 — Cutover runbook (docs/runbooks/onchain-cutover.md)

Pre-checks, staged rollout via the (upcoming) dry-run flag, and a rollback
procedure that reconstructs in-memory state from the chain + audit trail
so no in-flight intent's history is lost. Explicitly notes this procedure
isn't actionable yet — it documents the dependency graph (issues #21, #22,
#23, #24, #35, #62) that has to land first, same spirit as the slashing
scaffold above.

#37 — Architecture doc (docs/architecture/onchain-settlement.md, README)

On-chain writes have not shipped in this repo — intent create/accept/fill
are still fully in-memory (IntentsService), and SorobanService is
read-only. So this doc is written and clearly labeled as the target
architecture (HTTP request → Soroban tx → event ingestion → state
reconciliation, with a sequence diagram and an IntentState→contract-call
mapping table), not a description of shipped behavior. The README roadmap
checkbox for "On-chain writes" is left unchecked and instead links to
this doc — flipping it would misrepresent the current state of the system.
It references the ADR (issue #19, docs/adr/0001-onchain-settlement.md,
not yet written) as the place the custody-model call gets formally ratified.

Why one PR for four issues

All four are prerequisites for the same eventual on-chain-writes cutover,
share the same signing-key/contract-ID config surface, and #33 directly
depends on #34's config addition to compile. Bundled at the requester's
preference rather than opened as four separate PRs.

Test plan

$ npm run lint
> eslint src test scripts --ext .ts
(clean)

$ npm run typecheck
> tsc --noEmit
(clean)

$ npm test
Test Suites: 6 passed, 6 total
Tests:       32 passed, 32 total

$ npm run test:e2e
Test Suites: 5 passed, 5 total
Tests:       23 passed, 23 total

New tests added:

  • src/config/env.validation.spec.ts — production-required + format
    validation for SOROBAN_SIGNING_KEY, including rejecting a placeholder
    like "changeme".
  • src/intents/intents-sweeper.service.spec.ts — slash-on-missed-deadline,
    existing expiry behavior preserved, solver fillsFailed bump, and a
    defensive no-solver-on-record case.
  • src/soroban/solver-registry.service.spec.ts — fails closed to a no-op
    when unconfigured (today's default in every environment).

🤖 Generated with Claude Code

Adds SOROBAN_SIGNING_KEY: required and strkey-format-validated in
production, optional (empty by default) elsewhere, with no placeholder
default anywhere in the schema. Documents throwaway testnet key
generation for local dev in README and .env.example.
Documents pre-checks, staged rollout via the (upcoming) dry-run flag,
and a rollback path back to in-memory state with no data loss for
in-flight intents, coordinated with the audit trail work in stellar-vortex-protocol#62.
Adds docs/architecture/onchain-settlement.md covering the planned
HTTP request -> Soroban tx -> event ingestion -> state reconciliation
flow, the IntentState-to-contract-call mapping, and the open custody
question for the ADR (issue stellar-vortex-protocol#19) to ratify. Links it from the README
roadmap without checking off "On-chain writes" -- that item ships
when the linked design is actually implemented, not with this doc.
Adds SOROBAN_SIGNING_KEY: required and strkey-format-validated in
production, optional (empty by default) elsewhere, with no placeholder
default anywhere in the schema. Documents throwaway testnet key
generation for local dev in README and .env.example.
IntentsSweeperService now detects "accepted" intents whose fill
deadline has passed, transitions them to "slashed" (previously unset
anywhere in the codebase), bumps the solver's fillsFailed counter,
and calls the new SolverRegistryService to invoke the solver-registry
contract's penalty path.

SolverRegistryService builds and simulates the on-chain "slash" call
via the Soroban RPC signed with SOROBAN_SIGNING_KEY. It never submits
a transaction yet: there's no deployed solver-registry contract or
confirmed function signature to submit against (issue stellar-vortex-protocol#23 is still
open), and there's no dry-run/live-mode gate for staged rollout yet
(issue stellar-vortex-protocol#35). It fails closed to a pure no-op whenever the contract ID
or signing key isn't configured, which is the default everywhere
today. Wiring real submission is left for once both of those land.

Includes the signing-key config from stellar-vortex-protocol#34 (feature/signing-key-config)
since this depends on it directly.
@drips-wave

drips-wave Bot commented Jul 25, 2026

Copy link
Copy Markdown

@spotkorner-dot 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

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

Labels

None yet

Projects

None yet

1 participant