Skip to content

Feat/deploy config validation router example - #365

Merged
Just-Bamford merged 5 commits into
Sorokit:mainfrom
Joycejay17:feat/deploy-config-validation-router-example
Jul 29, 2026
Merged

Feat/deploy config validation router example#365
Just-Bamford merged 5 commits into
Sorokit:mainfrom
Joycejay17:feat/deploy-config-validation-router-example

Conversation

@Joycejay17

Copy link
Copy Markdown
Contributor

Validate deployment config and add a router frontend example

Summary

Two independent contributor issues, one branch.

#356 — Deployment script validation. Contract deployment failed late and
vaguely: a missing RPC URL surfaced as an opaque fetch error, an empty Horizon
URL as an SDK constructor throw, and a malformed deployer address only failed
once Horizon had already been called. This adds validateDeployConfig, a pure
pre-flight check that inspects every required deployment value in one pass and
reports each problem with the field name, what is wrong, and how to fix it:

Deployment configuration is invalid — 2 problems found:
  1. rpcUrl — rpcUrl is missing. Fix: Set rpcUrl to the Soroban RPC endpoint used to
     simulate the deployment (e.g. "https://soroban-testnet.stellar.org"), or read it
     from NETWORK_DEFAULTS[network].
  2. deployer — deployer is not a valid Stellar public key: "GNOPE". Fix: Stellar
     public keys start with `G` and are 56 characters long.

Issues are also returned as structured { field, reason, hint } data on
error.cause, so a deployment script can render them however it likes instead
of parsing a message. buildContractDeploy runs the check before any network
call; valid configurations follow exactly the same path as before.

#357 — Frontend router example. examples/router-swap is a documented
reference for driving the router from a frontend: quote → swap → transaction
tracking, with wallet signing and router-specific error handling.

Motivation

Closes #356
Closes #357

What changed

#356 — deployment configuration validation

File Change
src/soroban/validateDeployConfig.ts New. validateDeployConfig, collectDeployConfigIssues, formatDeployConfigIssues, DEPLOY_SALT_BYTES
src/soroban/deployContract.ts Pre-flight validation before any network call; guard against an empty WASM buffer
src/soroban/index.ts, src/index.ts Export the new helpers and types
src/tests/deploy-config-validation.test.ts New. 21 tests

Validated: rpcUrl and horizonUrl (present, non-empty, absolute http(s) URL),
networkConfig (present, with networkPassphrase and network), deployer
(present, well-formed G... key), and salt (32 bytes when supplied). All
fields are checked on every call, so a caller sees every problem at once rather
than fixing them one failed deployment at a time.

#357 — router integration example

File Purpose
examples/router-swap/src/routerSwap.ts All swap logic — DOM-free and framework-agnostic
examples/router-swap/src/app.ts Browser wiring: form handling, quote rendering, error display
examples/router-swap/index.html The page it runs in
examples/router-swap/README.md Flow walkthrough, wallet setup, error-code table
examples/router-swap/tsconfig.json Type-checks the example against the SDK source
src/tests/router-example.test.ts New. 26 tests

Two details worth reviewing:

  • The quote and the signed transaction come from the same call.
    buildPathPayment discovers the route on Horizon and prices it; the example
    decodes the built XDR to display it. There is no second price source that can
    disagree with what the user signs.
  • Slippage is applied deliberately. Path discovery sets the on-chain bound to
    the exact quoted amount, which fails as soon as the pool moves a stroop. The
    example rebuilds the transaction over the discovered route with the bound
    widened by the user's tolerance, using integer stroop math so large amounts
    stay exact.

Router failures are mapped through the existing describeRouterSwapFailure, so
the UI can tell ROUTER_INSUFFICIENT_LIQUIDITY apart from
ROUTER_SLIPPAGE_EXCEEDED. A wallet rejection keeps its own
WALLET_SIGN_REJECTED code — the router never saw that swap.

Docs and tooling

  • README.md — contract deployment section under the API reference, plus an
    Examples section
  • CHANGELOG.md — entries under Added and Changed
  • package.jsonnpm run typecheck:examples
  • .gitignore — ignore bundled example output

Testing

  • Added unit tests — 47 new tests (21 for the validation, 26 for the example), all passing
  • npm run lint — clean
  • npm run typecheck:examples — clean
  • npm run typecheck — 11 errors, unchanged from main (all pre-existing, none in the files touched here)
  • npm run test — 924 passing / 13 failing, identical failures to main on the same 6 files (soroban, transaction-submit-status, timeout, router-multi-hop.integration, integration/freighter, integration/lobstr)

The example's tests run the real SDK code with only Horizon faked
(vi.mock("../shared/serverFactory")), so route discovery, quote decoding,
slippage bounds, signing, submission, and status polling all execute the code an
integrator would copy — the example cannot silently drift from the API it
documents.

Checklist

  • Code follows project style (SorokitResult everywhere, no throws, JSDoc on exports)
  • Tests pass locally
  • No breaking changes — the deployment flow is unchanged for valid configurations
  • Branch is rebased on the latest main

Notes for reviewers

  • main currently has pre-existing failures in npm run typecheck, npm run build, and 6 test files (duplicate barrel exports in src/index.ts and
    src/soroban/index.ts, among others). Per the issue notes, none of that was
    touched here; the baseline was recorded before starting and is unchanged after
    these commits.
  • Because the barrels do not currently transform, the example imports the SDK
    modules directly (../../../src/transaction/pathPayment, …) rather than
    through src/index.ts. The README shows the single-import form consumers
    would use once the package is installed from npm. Happy to switch the example
    over to sorokit-core imports in a follow-up once the barrel exports are
    deduplicated.
  • buildContractDeploy validates configuration before the WASM checks, so a
    call with both a bad config and a bad WASM now reports the config first. The
    existing WASM error codes and messages are otherwise unchanged.

Deployment failed late and vaguely: a missing RPC URL surfaced as an opaque
fetch error, an empty Horizon URL as an SDK throw, and a malformed deployer
address only failed once Horizon had already been called.

Add validateDeployConfig, a pure pre-flight check that inspects every required
deployment value in one pass and reports each problem with the field name, what
is wrong, and how to fix it. Issues are returned as structured data so scripts
can render them however they like, and formatted into a numbered message that a
script can print directly.

buildContractDeploy now runs the check before any network call and guards
against an empty WASM buffer. Valid configurations follow exactly the same path
as before.

Closes Sorokit#356
Tests each missing and malformed field, the aggregated multi-problem message,
the structured issue cause, and the buildContractDeploy pre-flight that returns
INVALID_CONFIG before contacting the network.
Developers had no reference for driving the router from a frontend. Add
examples/router-swap: a documented quote → swap → confirmation flow built on
buildPathPayment, the wallet adapters, and the transaction submission APIs.

The swap logic in src/routerSwap.ts is framework-agnostic and DOM-free, so it
drops into React, Vue, or Svelte unchanged; src/app.ts and index.html wire it to
a plain HTML form. Quotes are decoded from the transaction that will be signed,
so the displayed price cannot disagree with what settles, and the slippage bound
is widened by the user's tolerance using integer stroop math.

The example type-checks against the SDK source via npm run typecheck:examples.

Closes Sorokit#357
Runs the real SDK code with only Horizon faked so the example cannot drift from
the API it documents: route discovery, quote decoding, slippage bounds, wallet
rejection, submission failures, and status polling.
Add a contract deployment section to the API reference, an Examples section
linking examples/router-swap, and CHANGELOG entries for both issues.
@drips-wave

drips-wave Bot commented Jul 29, 2026

Copy link
Copy Markdown

@Joycejay17 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

@Just-Bamford
Just-Bamford merged commit 2eb10a2 into Sorokit:main Jul 29, 2026
2 of 5 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

Development

Successfully merging this pull request may close these issues.

Add frontend example for router integration Improve deployment script validation

2 participants