Feat/deploy config validation router example - #365
Merged
Just-Bamford merged 5 commits intoJul 29, 2026
Merged
Conversation
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.
|
@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! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 purepre-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 also returned as structured
{ field, reason, hint }data onerror.cause, so a deployment script can render them however it likes insteadof parsing a message.
buildContractDeployruns the check before any networkcall; valid configurations follow exactly the same path as before.
#357 — Frontend router example.
examples/router-swapis a documentedreference 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
src/soroban/validateDeployConfig.tsvalidateDeployConfig,collectDeployConfigIssues,formatDeployConfigIssues,DEPLOY_SALT_BYTESsrc/soroban/deployContract.tssrc/soroban/index.ts,src/index.tssrc/tests/deploy-config-validation.test.tsValidated:
rpcUrlandhorizonUrl(present, non-empty, absolute http(s) URL),networkConfig(present, withnetworkPassphraseandnetwork),deployer(present, well-formed
G...key), andsalt(32 bytes when supplied). Allfields 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
examples/router-swap/src/routerSwap.tsexamples/router-swap/src/app.tsexamples/router-swap/index.htmlexamples/router-swap/README.mdexamples/router-swap/tsconfig.jsonsrc/tests/router-example.test.tsTwo details worth reviewing:
buildPathPaymentdiscovers the route on Horizon and prices it; the exampledecodes the built XDR to display it. There is no second price source that can
disagree with what the user signs.
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, sothe UI can tell
ROUTER_INSUFFICIENT_LIQUIDITYapart fromROUTER_SLIPPAGE_EXCEEDED. A wallet rejection keeps its ownWALLET_SIGN_REJECTEDcode — the router never saw that swap.Docs and tooling
README.md— contract deployment section under the API reference, plus anExamples section
CHANGELOG.md— entries under Added and Changedpackage.json—npm run typecheck:examples.gitignore— ignore bundled example outputTesting
npm run lint— cleannpm run typecheck:examples— cleannpm run typecheck— 11 errors, unchanged frommain(all pre-existing, none in the files touched here)npm run test— 924 passing / 13 failing, identical failures tomainon 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
SorokitResulteverywhere, no throws, JSDoc on exports)mainNotes for reviewers
maincurrently has pre-existing failures innpm run typecheck,npm run build, and 6 test files (duplicate barrel exports insrc/index.tsandsrc/soroban/index.ts, among others). Per the issue notes, none of that wastouched here; the baseline was recorded before starting and is unchanged after
these commits.
modules directly (
../../../src/transaction/pathPayment, …) rather thanthrough
src/index.ts. The README shows the single-import form consumerswould use once the package is installed from npm. Happy to switch the example
over to
sorokit-coreimports in a follow-up once the barrel exports arededuplicated.
buildContractDeployvalidates configuration before the WASM checks, so acall with both a bad config and a bad WASM now reports the config first. The
existing WASM error codes and messages are otherwise unchanged.