Appearance
swap-sdk releases
The SDK is distributed as git tags, not an npm package, and consumed by two independent repositories. That combination has one sharp edge, and it has cut production.
The release
bash
cd swap-sdk
# 1. build — catches type errors before consumers do
npm run build
# 2. bump the version in package.json
# (no automation; edit it)
# 3. commit, tag, push
git add -A && git commit -m "v1.13.0: …"
git tag v1.13.0
git push origin main --tagsprepare runs tsc automatically on install, so a git install builds itself — and a broken build breaks consumers at install time. Always run npm run build before tagging.
Bumping the consumers
Two repositories pin independently:
| Repo | File |
|---|---|
bz-backend | package.json → "swap-sdk": "github:blazpay/swap-sdk#v1.13.0" |
defi-dex | Same |
The critical step
Editing package.json alone does nothing
package-lock.json pins swap-sdk by resolved commit hash, and npm install obeys the lock — even after rm -rf node_modules/swap-sdk, which is exactly what the deploy script does.
You must run:
bash
npm install github:blazpay/swap-sdk#v1.13.0 --package-lock-onlyand commit both package.json and package-lock.json.
This trap hit production on 2026-07-26
The deploy installed 1.9.1 despite a v1.12.0 pin. It was only caught because deploy.gcp.sh prints the installed version:
installed swap-sdk: 1.9.1Read that line on every deploy.
Full procedure
bash
# ── swap-sdk ──────────────────────────────────────────────
cd swap-sdk
npm run build # must pass
# edit package.json version
git add -A && git commit -m "v1.13.0: …"
git tag v1.13.0 && git push origin main --tags
# ── bz-backend ────────────────────────────────────────────
cd ../bz-backend
npm install github:blazpay/swap-sdk#v1.13.0 --package-lock-only
git add package.json package-lock.json
git commit -m "bump swap-sdk to v1.13.0"
git push origin bishtNew
./scripts/deploy.gcp.sh deploy bz-backend
# ↑ READ the "installed swap-sdk: X" line
# ── defi-dex ──────────────────────────────────────────────
cd ../defi-dex
npm install github:blazpay/swap-sdk#v1.13.0 --package-lock-only
npm run build:app # verify it compiles
git add package.json package-lock.json
git commit -m "bump swap-sdk to v1.13.0"
git push origin optimized # Netlify auto-buildsVersion drift between consumers
The two pins can differ, and have
At the time of writing the backend is on v1.12.0; the frontend has lagged in the past. A known instance: the frontend stayed on v1.9.0 while the backend ran v1.9.1 — a quote-display precision fix, so low-impact, but the drift was real and unintentional.
Drift matters more than it looks, because the two consumers use different parts of the SDK:
| Consumer | Uses |
|---|---|
bz-backend | TradeManager.getQuotes (server-side fan-out), Quote.getTransactionData |
defi-dex | RelayerFactory via utils/trade.ts — builds and sends the settlement transaction |
So a change to the relayer flow affects the frontend; a change to quoting affects the backend. A change to RELAYER_ADDRESSES or RELAYER_DEPLOYED_CHAINS affects both, and a partial bump means one side thinks a chain is supported and the other does not.
Chain additions must bump both, together
Adding a chain to RELAYER_DEPLOYED_CHAINS in the backend only means the frontend's assertRelayerDeployed still throws. Adding it to the frontend only means the backend will quote a chain it cannot settle on.
When to release
| Change | Release needed |
|---|---|
| A new aggregator | Yes — both consumers |
| Disabling a broken aggregator | Yes — both |
A new chain in RELAYER_ADDRESSES / RELAYER_DEPLOYED_CHAINS | Yes — both, together |
| A relayer ABI change | Yes — the frontend especially |
A quote-shape (IQuote) change | Yes — both |
A status-URL addition to routers | Yes — backend (used by bridgeStatusCron) |
| A fix inside one aggregator's pricing | Yes — backend |
Versioning
Loose semver in practice:
| Bump | For |
|---|---|
| Patch | An aggregator fix, precision, a status URL |
| Minor | A new aggregator, a new chain, an additive type field |
| Major | Never used so far |
Recent history: v1.9.0 → v1.9.1 (precision fix) → … → v1.12.0 (Robinhood Chain, commit 7bc1a8c).
Local development against an unreleased SDK
Option A — link (fast):
bash
cd swap-sdk && npm run build && npm link
cd ../bz-backend && npm link swap-sdkRe-run npm run build after every SDK edit — consumers import from dist/.
Option B — build and copy (closer to reality):
bash
cd swap-sdk && npm run build
rm -rf ../bz-backend/node_modules/swap-sdk/dist
cp -r dist ../bz-backend/node_modules/swap-sdk/npm install in the consumer wipes a link
And reinstalls the pinned tag. Re-link after any install.
Pre-release checklist
There are no SDK tests, so this is manual.
□ npm run build passes (prepare runs it on install — a break blocks consumers)
□ package.json version bumped
□ If an aggregator changed:
□ Quote appears in the SSE stream on the target chain
□ Output amount and units correct vs the provider's own UI
□ usdAmount populated (else the fee display shows $0)
□ allowanceTo is the real spender
□ A real trade completes and output arrives
□ getTxStatus resolves pending → success
□ Killing the provider's API does not break the stream
□ If a chain changed:
□ In RELAYER_ADDRESSES
□ In RELAYER_DEPLOYED_CHAINS
□ ChainName + ChainId + getChainNameById mapping
□ If a type changed: both consumers still compileThere is no test suite
26 aggregators, zero tests. The verification above is all there is. See testing.
Rollback
bash
# in each consumer
npm install github:blazpay/swap-sdk#v1.12.0 --package-lock-only
git add package.json package-lock.json && git commit -m "revert swap-sdk to v1.12.0"
# then deploy / pushTags are immutable, so rolling back is just re-pinning. Do not delete or move a tag — a consumer's lockfile may still reference its commit.
Disabling a broken provider
The established convention — comment the registration out with the reason inline:
ts
// IceCreamSwap: aggregator.icecreamswap.com returns 404 — endpoint
// appears to have been removed. Re-enable when a current URL is published.
// this.aggregatorFactory.register(
// AGGREGATORS.ICECREAM_SWAP,
// new IceCreamAggregator(),
// );Why comment rather than delete
The class, the enum member and the status URL all stay, so re-enabling is a one-line change when the provider comes back. And the inline reason is how the next person understands why 26 files produce 21 live providers.
Then release and bump both consumers, so the dead provider stops being attempted.