Skip to content

Conversation

@0xApotheosis
Copy link
Member

Description

Adds a new @shapeshiftoss/public-api package that exposes swap functionality as a REST API for external partners.

Production URL: https://api.shapeshift.com
API Documentation: https://api.shapeshift.com/docs

Endpoints:

  • GET /health - Health check
  • GET /v1/assets - List all supported assets
  • GET /v1/swap/rates - Fetch rates from all enabled swappers (0x, Relay, THORChain, etc.)
  • GET /v1/swap/quote - Get executable quote with full transaction data
  • GET /docs - Interactive Scalar API documentation

Architecture:

  • Imports @shapeshiftoss/swapper directly - zero code duplication
  • Server-side SwapperDeps with minimal EVM adapters fetching gas fees from Unchained
  • esbuild bundling into single CJS file for deployment
  • Multi-stage Docker build with BuildKit cache optimization
  • Scalar-powered interactive API docs with zod-to-openapi

Note: Affiliate fee sharing is not yet implemented. Currently all swaps use the standard DAO affiliate fee (55 bps). Partner attribution, fee tracking, and revenue sharing will be added in Phase 2.

Issue (if applicable)

closes #

Risk

Low-Medium - This is a new standalone package/service that doesn't modify any existing swap flows in the web app.

What protocols, transaction types, wallets or contract interactions might be affected by this PR?

None directly. The public API reads from existing swapper infrastructure but doesn't introduce new on-chain transactions.

Testing

Engineering

# Health check
curl https://api.shapeshift.com/health

# Get rates (ETH -> USDC)
curl "https://api.shapeshift.com/v1/swap/rates?sellAssetId=eip155:1/slip44:60&buyAssetId=eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&sellAmountCryptoBaseUnit=1000000000000000000"

# Interactive docs
open https://api.shapeshift.com/docs

Operations

  • 🏁 My feature is behind a flag and doesn't require operations testing (yet)

This is a new standalone service deployed to Railway. It does not affect the main web application.

Screenshots (if applicable)

N/A - API service, no UI changes.

0xApotheosis and others added 16 commits January 7, 2026 12:16
Implements a public API for swap quotes and rates that reuses the existing
@shapeshiftoss/swapper package without code duplication.

Endpoints:
- GET /v1/swap/rates - Get rates from all swappers
- POST /v1/swap/quote - Get executable quote with tx data
- GET /v1/assets - List supported assets

Features:
- API key authentication middleware
- Minimal EVM chain adapters for gas fee estimation
- esbuild bundling for single-file deployment
- Docker + Railway deployment configuration
- 55 bps affiliate fee (planned 50/50 split with partners)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Replace YARN_ENABLE_SCRIPTS=false with --mode skip-build to properly skip
  all lifecycle scripts including postinstall that requires git
- Add tsconfig files copy for TypeScript compilation
- Add build:docker script to unchained-client to skip Java-based code generation
- Use explicit workspace builds instead of yarn workspaces foreach
- Type JSON response in swapperDeps.ts to fix 'data is of type unknown' error
- Add GetTradeRateInput type assertion in rates.ts for chainId compatibility
- Add GetTradeQuoteInputWithWallet type assertion in quote.ts for chainId compatibility
- Install openjdk17-jre in build stage for OpenAPI generator CLI
- Use full unchained-client build script instead of build:docker
…process.sh

Fixes 'Exec format error' during Docker build.
Fixes runtime module not found errors for external dependencies like @cowprotocol/app-data
…filled examples

- Add Scalar API reference UI at /docs endpoint
- Configure defaultOpenAllTags to auto-expand all sections on page load
- Prefill test API key (test-api-key-123) in authentication section
- Add OpenAPI example values to all request schemas for prefilled forms
- Set up zod-to-openapi for generating OpenAPI spec from Zod schemas

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
zod-to-openapi v8.x requires zod v4 as a peer dependency, causing runtime
errors when used with zod v3.23.8. Downgrade to v7.3.4 which supports zod v3.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
esbuild bundles all dependencies into server.cjs, so copying the entire
node_modules directory to the production image was unnecessary and added
significant time to Railway deployments (~2-4 min) and image size (~500MB+).

The only externals are fsevents (macOS-only, not used in Linux containers)
and @cowprotocol/* (not used by public-api routes).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add comprehensive description explaining how to integrate the swap API:
- Step-by-step integration flow (assets -> rates -> quote -> execute)
- Authentication requirements
- CAIP-19 asset ID format with examples

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add Dockerfile.dockerignore to exclude node_modules (4.5GB), .git (1.4GB),
  and other unnecessary files from build context
- Enable BuildKit with syntax directive for advanced features
- Add cache mount for yarn berry cache to speed up subsequent builds

These optimizations reduce build context transfer time and cache dependencies
between builds, further improving Railway deployment speed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Railway requires cache mounts to have an explicit id parameter.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Railway's cache mount requires a specific prefix format that's not
documented. Reverting to standard yarn install - the .dockerignore
still provides significant build context reduction.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Use Railway's required cache mount ID format: s/<service-id>-<target-path>
This caches yarn's berry cache between builds to speed up dependency installation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 7, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/public-swap-api

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

The @cowprotocol/* packages were externalized in esbuild which caused
them to be missing at runtime in the Docker production image (which only
copies the bundled server.cjs, not node_modules). This caused the entire
swapper module initialization to fail, making the swappers object
undefined and returning empty rates for all requests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@railway-app railway-app bot temporarily deployed to microservices / production January 7, 2026 06:14 Inactive
THORChain doesn't support native ETH -> ERC20 swaps on the same chain.
Update the documentation examples to use 0x which reliably supports
ETH -> USDC swaps and returns valid transaction data.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@railway-app railway-app bot temporarily deployed to microservices / production January 7, 2026 06:35 Inactive
@railway-app railway-app bot temporarily deployed to microservices / production January 7, 2026 06:56 Inactive
The null address (0x000...000) is rejected by swapper APIs like 0x.
Update the OpenAPI examples to use a valid Ethereum address so the
Try It Out feature in the docs actually works.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@railway-app railway-app bot temporarily deployed to microservices / production January 7, 2026 06:59 Inactive
Replace `typeof import()` type annotations with `Awaited<ReturnType<typeof fn>>`
pattern to comply with @typescript-eslint/consistent-type-imports rule.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@railway-app railway-app bot temporarily deployed to microservices / production January 7, 2026 07:17 Inactive
Returns API name, version, description, and available endpoints when
visiting the root URL instead of a 404 error.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@railway-app railway-app bot temporarily deployed to microservices / production January 7, 2026 07:18 Inactive
The early return when asset data file is not found was returning undefined,
which violates the Promise<void> return type.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@railway-app railway-app bot temporarily deployed to microservices / production January 7, 2026 07:43 Inactive
Some swappers return decimal values in buyAmountCryptoBaseUnit which cannot
be converted to BigInt. Strip decimal portion and wrap in try-catch to
prevent the entire rates endpoint from failing.

Also add error handling for swapper module loading failures.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@railway-app railway-app bot temporarily deployed to microservices / production January 7, 2026 08:14 Inactive
0xApotheosis and others added 2 commits January 8, 2026 10:34
The utils package has "type": "module" but was importing from lodash
which doesn't support ESM named exports. This caused runtime errors
when running directly with Node.js ESM (e.g., public-api dev server).

Changed lodash to lodash-es which is the official ESM-compatible version.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Import Transaction from @mysten/sui/transactions directly instead of
reaching into @cetusprotocol/aggregator-sdk's node_modules. Added
@mysten/sui as a direct dependency.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@railway-app railway-app bot temporarily deployed to microservices / production January 7, 2026 23:42 Inactive
Add a non-blocking smoke test suite that can run against the deployed API:

- 6 critical tests: health check, asset endpoints, auth validation
- 2 informative tests: EVM same-chain rates (ETH→USDC), cross-chain rates (ETH→BTC)

Tests are bundled with esbuild and included in the Docker image. They always
exit 0 to avoid blocking deployment - failures are logged but don't prevent
the service from starting.

Run locally: `yarn test:smoke`
Run against prod: `API_URL=https://api.example.com yarn test:smoke`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
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.

2 participants