Skip to content

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 --tags

prepare 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:

RepoFile
bz-backendpackage.json"swap-sdk": "github:blazpay/swap-sdk#v1.13.0"
defi-dexSame

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-only

and 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.1

Read 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-builds

Version 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:

ConsumerUses
bz-backendTradeManager.getQuotes (server-side fan-out), Quote.getTransactionData
defi-dexRelayerFactory 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

ChangeRelease needed
A new aggregatorYes — both consumers
Disabling a broken aggregatorYes — both
A new chain in RELAYER_ADDRESSES / RELAYER_DEPLOYED_CHAINSYes — both, together
A relayer ABI changeYes — the frontend especially
A quote-shape (IQuote) changeYes — both
A status-URL addition to routersYes — backend (used by bridgeStatusCron)
A fix inside one aggregator's pricingYes — backend

Versioning

Loose semver in practice:

BumpFor
PatchAn aggregator fix, precision, a status URL
MinorA new aggregator, a new chain, an additive type field
MajorNever used so far

Recent history: v1.9.0v1.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-sdk

Re-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 compile

There 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 / push

Tags 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.

Internal + developer documentation. Usage figures are point-in-time snapshots — re-verify before publishing them.