One SDK. Every DEX. Zero MEV.
Stop integrating Uniswap, 1inch, and Paraswap separately. Write 4 lines of code and let SwapKit find the best route, simulate MEV risk, and execute safely.
Getting Started • How It Works • API Reference • CLI • Architecture
- The Problem
- Our Solution
- Getting Started
- How It Works (Step by Step)
- API Reference
- CLI Usage
- Architecture Deep Dive
- API Keys Guide
- Developer Documentation
- Changelog
- Security
- FAQ
Building a token swap feature in a Web3 app is an engineering nightmare. In 2024–2026, liquidity is fragmented across completely different execution architectures:
┌─────────────────────────────────────────────────────────────────────────┐
│ THE FRAGMENTED DeFi LANDSCAPE │
├──────────────────┬──────────────────────┬───────────────────────────────┤
│ Uniswap V4 │ 1inch Fusion+ │ Paraswap │
│ (On-Chain) │ (Off-Chain Intent) │ (On-Chain Aggregator) │
├──────────────────┼──────────────────────┼───────────────────────────────┤
│ • Singleton │ • No on-chain TX │ • Traditional API │
│ PoolManager │ • EIP-712 signatures │ • Routes across 30+ DEXs │
│ • Custom Hooks │ • HTLC secrets for │ • Returns standard │
│ • UniversalRouter│ cross-chain │ calldata │
│ binary encoding│ • Resolver network │ • No MEV protection │
│ • V4_SWAP command│ executes for you │ │
│ + Actions │ • Gasless for maker │ │
├──────────────────┼──────────────────────┼───────────────────────────────┤
│ SDK: @uniswap/ │ SDK: @1inch/ │ SDK: REST API │
│ v4-periphery │ cross-chain-sdk │ api.paraswap.io │
│ │ │ │
│ Complexity: 🔴 │ Complexity: 🔴 │ Complexity: 🟡 │
└──────────────────┴──────────────────────┴───────────────────────────────┘
If you want the best price for your users, you must integrate ALL THREE. That means:
- Learning 3 completely different APIs and execution models
- Handling on-chain transactions AND off-chain signatures
- Managing cross-chain HTLC secrets (1inch Fusion+)
- Encoding binary UniversalRouter payloads (Uniswap V4)
- Building your own MEV protection (or your users get sandwiched)
- Dealing with 3 different error handling patterns
This takes 3-5 weeks of engineering per project. Every team rebuilds it from scratch.
Even after integrating all the DEXs, there's another monster: MEV (Maximum Extractable Value).
When a user submits a swap transaction on Ethereum, it sits in the public mempool — a waiting room visible to everyone. Predatory bots watch this mempool 24/7. When they spot a large swap, they execute a Sandwich Attack:
Without MEV Protection:
User submits: "Swap 10 ETH → USDC"
│
▼
┌─────────────────────────┐
│ PUBLIC MEMPOOL │ ◄── Bot sees your transaction!
│ (visible to everyone) │
└─────────────────────────┘
│
▼
Bot FRONT-RUNS: Buys token first (pushes price UP)
│
▼
Your swap executes at WORSE price ($2,000 instead of $2,050)
│
▼
Bot BACK-RUNS: Sells token (takes profit)
│
▼
You lost ~$50 to the sandwich bot 💸
SwapKit eliminates all of this complexity. You describe what you want (an Intent), and SwapKit figures out the how.
// ❌ WITHOUT SwapKit — 200+ lines of protocol-specific code
// Step 1: Set up Uniswap V4
const poolKey = { currency0, currency1, fee: 500, tickSpacing: 10, hooks: "0x..." };
const actions = encodePacked([SWAP_EXACT_IN_SINGLE, SETTLE_ALL, TAKE_ALL]);
const params = encodeAbiParameters([...], [{ poolKey, zeroForOne, amountIn, ... }]);
const commands = "0x10"; // V4_SWAP command
const calldata = encodeFunctionData({ abi: UniversalRouterABI, ... });
// Step 2: Set up 1inch Fusion+ (completely different model!)
const fusionSdk = new SDK({ url: "https://api.1inch.dev/fusion-plus", authKey: KEY });
const quote = await fusionSdk.getQuote({ srcChainId, dstChainId, ... });
const order = fusionSdk.createOrder(quote, { walletAddress, hashLock, secretHashes, ... });
const signature = await walletClient.signTypedData(order.typedData);
await fusionSdk.submitOrder(srcChainId, order, quoteId, secretHashes);
// Step 3: Set up Paraswap (yet another API!)
const paraswapQuote = await fetch("https://api.paraswap.io/prices?...");
const txParams = await fetch("https://api.paraswap.io/transactions/1?...");
// Step 4: Compare all three, handle errors, manage MEV...
// ... another 100 lines of comparison, error handling, and retry logic// ✅ WITH SwapKit — 4 lines. That's it.
import { createSwapKit } from "@swap-kit/core";
const sdk = createSwapKit({ oneInchApiKey: process.env.ONEINCH_KEY });
const quotes = await sdk.quote({
fromToken: "0xEeee...EEeE", // ETH
toToken: "0xA0b8...eB48", // USDC
fromAmount: 1000000000000000000n, // 1 ETH
fromChainId: 1,
});
// quotes[0] is already the best route with MEV analysis applied
console.log(quotes[0].protocol); // "paraswap" or "1inch-fusion" or "uniswap-v4"
console.log(quotes[0].amountOut); // Best price across all DEXs
console.log(quotes[0].mevExposure); // MEV risk estimatenpm install @swap-kit/core
# or
pnpm add @swap-kit/core
# or
yarn add @swap-kit/coreSwapKit needs one required key (Alchemy for blockchain access) and has one optional key (1inch for intent-based swaps):
| Key | Required? | Where to Get It | Free? |
|---|---|---|---|
| Alchemy RPC | ✅ Yes | alchemy.com | Yes (free tier) |
| 1inch API | ⬡ Optional | portal.1inch.dev | Yes (free tier) |
| Paraswap | ❌ No key needed | Open API | Free |
| DefiLlama | ❌ No key needed | Open API | Free |
| Flashbots | ❌ No key needed | Public RPC | Free |
Without the 1inch key, SwapKit still works perfectly — it routes across Uniswap V4 and Paraswap. The 1inch key simply adds Fusion+ as an additional routing option for potentially better prices.
import { createSwapKit } from "@swap-kit/core";
// Minimal setup (Paraswap + Uniswap V4 only — no API key needed!)
const sdk = createSwapKit({
oneInchApiKey: "", // Leave empty to skip 1inch
});
// Full setup (all three protocols)
const sdk = createSwapKit({
oneInchApiKey: process.env.ONEINCH_API_KEY!,
rustEngineUrl: "http://localhost:3030", // Optional: for MEV protection
mevFailOpen: true, // If Rust engine is down, still execute (default: true)
});// Define what you want to swap
const quotes = await sdk.quote({
fromToken: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", // ETH
toToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
fromAmount: 1000000000000000000n, // 1 ETH (18 decimals)
fromChainId: 1, // Ethereum Mainnet
maxSlippageBps: 50, // 0.5% max slippage
});
// The SDK returns quotes sorted by best net output
console.log(`Best route: ${quotes[0].protocol}`);
console.log(`You receive: ${quotes[0].amountOut} USDC`);
console.log(`MEV risk: ${quotes[0].mevExposure}`);import { createWalletClient, createPublicClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";
// Create a wallet (in production, this comes from MetaMask/WalletConnect)
const walletClient = createWalletClient({
account: privateKeyToAccount("0xYOUR_PRIVATE_KEY"),
chain: mainnet,
transport: http(process.env.RPC_ETHEREUM),
});
const publicClient = createPublicClient({
chain: mainnet,
transport: http(process.env.RPC_ETHEREUM)
});
// Execute!
const intent = {
fromToken: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", // ETH
toToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
fromAmount: 1000000000000000000n, // 1 ETH
fromChainId: 1,
};
const result = await sdk.swap(
intent,
walletClient,
publicClient
);
console.log(`✅ Swap executed! TX: ${result.txHash}`);
console.log(`Received: ${result.actualAmountOut} USDC`);
console.log(`Gas paid: ${result.gasPaidWei} wei`);Here is exactly what happens when you call sdk.quote() and sdk.swap():
When you request a quote, SwapKit fires off simultaneous requests to all three protocols:
sdk.quote({ fromToken: ETH, toToken: USDC, amount: 1 ETH })
│
├──→ Uniswap V4 Adapter
│ └─ Calls QuoterV2 contract via eth_call (on-chain simulation)
│ └─ Returns: 2,018.47 USDC
│
├──→ 1inch Adapter
│ └─ Calls 1inch REST API (/swap/v6.0/1/quote)
│ └─ Returns: 2,017.10 USDC
│
└──→ Paraswap Adapter
└─ Calls Paraswap REST API (/prices)
└─ Returns: 2,022.15 USDC ◄── Winner!
All three run concurrently using Promise.allSettled, so the total time is only as slow as the slowest API (~200ms).
Before returning the quote, SwapKit sends the winning route to the Rust engine for safety analysis:
Best Quote (Paraswap, 2,022.15 USDC)
│
▼
Rust Engine POST /simulate
│
├─ Values the trade in the chain's NATIVE token (ETH/MATIC/…) wei
├─ Compares extractable value vs the attacker's 2-tx gas cost (same unit)
├─ Scans recent blocks for known sandwich-bot activity
├─ Calculates optimal slippage tolerance
│
▼
Returns: { sandwichRisk: "low", recommendedSlippage: 30bps }
Why native-token valuation matters: profitability is only meaningful when the value a bot can extract and the gas it must pay are in the same unit. The engine denominates both in native-token wei, so a large USDC-output trade is no longer mis-scored as "no risk" just because USDC has 6 decimals. Token→token swaps with no native leg are honestly reported as
unknownrather than guessed.
If the Rust engine detects high MEV risk, the SDK can automatically:
- Lower the slippage tolerance to make sandwich attacks unprofitable
- Route the transaction through Flashbots Protect (a private submission channel that hides your transaction from bots)
What if I don't run the Rust engine? The SDK works perfectly without it. It simply skips the MEV simulation step and uses the default slippage you set (e.g., 0.5%). Think of the Rust engine as an optional safety upgrade.
SwapKit abstracts the completely different execution models behind a single .swap() call:
sdk.swap(intent, walletClient, publicClient)
│
├─ If winner is Uniswap V4:
│ 1. Encode UniversalRouter calldata (V4_SWAP + SETTLE_ALL + TAKE_ALL)
│ 2. Build Ethereum transaction
│ 3. Send via walletClient.sendTransaction()
│ 4. Wait for on-chain confirmation
│
├─ If winner is 1inch Fusion+:
│ 1. Create EIP-712 typed data order
│ 2. Request signature from wallet (NOT a transaction!)
│ 3. Submit signed intent to 1inch Relayer API
│ 4. Resolvers execute the trade (gasless for the user!)
│
└─ If winner is Paraswap:
1. Fetch transaction params from Paraswap API
2. Build Ethereum transaction
3. Send via walletClient.sendTransaction()
4. Wait for on-chain confirmation
You don't need to know ANY of this. Just call sdk.swap() and it handles everything.
Creates a new SwapKit instance.
const sdk = createSwapKit({
oneInchApiKey: string, // Your 1inch API key (pass "" to skip)
rustEngineUrl?: string, // URL of the Rust MEV engine (optional)
mevFailOpen?: boolean, // If true, skip MEV check when engine is down (default: true)
customChains?: ChainConfig[], // Dynamically inject unsupported or new chains (e.g. Avalanche)
});Fetches quotes from all supported protocols.
const quotes: QuoteResult[] = await sdk.quote({
fromToken: Address, // Source token contract address
toToken: Address, // Destination token contract address
fromAmount: bigint, // Amount in wei (smallest unit)
fromChainId: number, // Source chain (1 = Ethereum, 8453 = Base, 42161 = Arbitrum)
toChainId?: number, // Destination chain (defaults to fromChainId)
maxSlippageBps?: number, // Max slippage in basis points (50 = 0.5%)
recipient?: Address, // Receiving address (defaults to sender)
deadline?: number, // Unix timestamp deadline
skipMEVCheck?: boolean, // Skip Rust engine simulation
});Returns: QuoteResult[] sorted by best net output (after gas + MEV estimates).
Quotes and executes the best swap in one call.
const result: SwapResult = await sdk.swap(intent, walletClient, publicClient);
// result.txHash — Transaction hash (or order hash for 1inch)
// result.protocol — Which protocol won ("uniswap-v4" | "1inch-fusion" | "paraswap")
// result.actualAmountOut — Tokens received
// result.gasPaidWei — Gas cost in weiConvenience method that returns only the single best quote.
const best: QuoteResult = await sdk.bestQuote(intent);SwapKit ships with a beautiful command-line interface for quick testing.
npm install -g @swap-kit/cli
# or run directly
npx @swap-kit/cli quote --from 0xEeee...EEeE --to 0xA0b8...eB48 --amount 1# Get the best quote across all protocols
swap-kit quote \
--from 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE \
--to 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \
--amount 1 \
--chain 1
# Output:
# ✔ Route optimized successfully!
#
# 🏆 Best Quote Found:
# Protocol: paraswap
# Amount Out: 2,022.15
# MEV Exposure: Protected 🛡️graph TB
subgraph "Developer's App"
A[Your Code] -->|"sdk.quote(intent)"| B["@swap-kit/core"]
end
subgraph "@swap-kit/core (TypeScript)"
B --> C[Intent Parser]
C --> D[Quote Engine (Promise.allSettled)]
D -->|Concurrent| E[Uniswap V4 Adapter]
D -->|Concurrent| F[1inch Fusion Adapter]
D -->|Concurrent| G[Paraswap Adapter]
E --> H[Sort by netAmountOut DESC]
F --> H
G --> H
H --> I[MEV Guard]
end
subgraph "swap-kit-engine (Rust)"
I -->|"POST /simulate"| J[MEV Simulator]
J --> K[Sandwich Risk Analyzer]
J --> L[Slippage Optimizer]
end
subgraph "Execution Layer"
I --> M[Execution Engine]
M -->|On-Chain TX| N["Uniswap V4 UniversalRouter"]
M -->|EIP-712 Signature| O["1inch Relayer API"]
M -->|On-Chain TX| P["Paraswap Augustus Router"]
end
subgraph "MEV Protection"
M -->|If high risk| Q["Flashbots Protect RPC"]
M -->|If low risk| R["Standard Alchemy RPC"]
end
style B fill:#6366f1,stroke:#4f46e5,color:#fff
style J fill:#ef4444,stroke:#dc2626,color:#fff
style H fill:#22c55e,stroke:#16a34a,color:#fff
| Chain | Chain ID | Uniswap V4 | 1inch | Paraswap | Native RPC |
|---|---|---|---|---|---|
| Ethereum | 1 | ✅ | ✅ | ✅ | eth.drpc.org |
| Base | 8453 | ✅ | ✅ | ✅ | mainnet.base.org |
| Arbitrum | 42161 | ✅ | ✅ | ✅ | arb1.arbitrum.io/rpc |
| Optimism | 10 | ❌ | ✅ | ✅ | mainnet.optimism.io |
| Polygon | 137 | ❌ | ✅ | ✅ | polygon-rpc.com |
| BNB Chain | 56 | ❌ | ✅ | ✅ | bsc-dataseed.binance.org |
| Sepolia (Testnet) | 11155111 | ❌ | ❌ | ❌ | rpc.sepolia.org |
When you install @swap-kit/core, you provide your own API keys. SwapKit never bundles any keys — you bring your own.
// Your keys, your quotas, your control
const sdk = createSwapKit({
oneInchApiKey: process.env.MY_1INCH_KEY!,
});- Go to alchemy.com and sign up (free)
- Create a new app → Select "Ethereum Mainnet"
- Copy the API key from the dashboard
- Use it in your RPC URLs:
https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY
- Go to portal.1inch.dev and sign up
- Navigate to API Keys → Create a new key
- Enable the "Swap API" and "Fusion API" permissions
- Pass it to SwapKit:
oneInchApiKey: "YOUR_KEY"
The Paraswap API is completely open. SwapKit uses it out of the box.
The codebase operates heavily via @swap-kit/core interacting with real APIs (Paraswap, 1inch, Uniswap QuoterV2) and delegating risk analysis to the swap-kit-engine (Rust).
| Variable | Description |
|---|---|
ALCHEMY_API_KEY |
Alchemy RPC key for all chains |
ONEINCH_API_KEY |
1inch Fusion+ API key |
RPC_ETHEREUM |
Custom Ethereum RPC URL |
RPC_BASE |
Custom Base RPC URL |
RPC_ARBITRUM |
Custom Arbitrum RPC URL |
RPC_OPTIMISM |
Custom Optimism RPC URL |
RPC_POLYGON |
Custom Polygon RPC URL |
RPC_BSC |
Custom BNB Chain RPC URL |
RPC_SEPOLIA |
Custom Sepolia testnet RPC URL |
CORS_ORIGIN |
Restrict CORS on Rust engine |
BIND_ADDR |
Rust engine bind address (default: 127.0.0.1:3030) |
SwapKit resolves the highest priority RPC url logic automatically:
- Programmatic
rpcUrlparameter (highest) process.env.RPC_ETHEREUM/RPC_BASE/RPC_ARBITRUMetc.- Alchemy URL (if
ALCHEMY_API_KEYset) - Public fallback RPCs (lowest)
The Rust engine has 3 endpoints. (Quoting lives entirely in the TypeScript SDK,
which calls the real Paraswap/1inch APIs and the on-chain Uniswap V4 Quoter — the
engine does not expose a /quote route.)
-
GET /health — Returns
"ok". Used for monitoring. -
POST /simulate — MEV sandwich attack risk assessment:
- Classifies risk as
none,low,medium,high, orunknown - Decides profitability in the chain's native token (wei), so the risk is correct
regardless of the output token's decimals; token→token swaps with no native
leg are reported as
unknownrather than guessed - Uses integer-based math (no floating-point precision loss)
- Recommends optimal slippage
- Request body:
{ from_token, to_token, from_amount, chain_id, protocol, amount_out, slippage_bps }
- Classifies risk as
-
POST /mine — CREATE2 vanity address mining for Uniswap V4 hooks: In Uniswap V4, the starting characters of a Hook's contract address dictate what permissions the Hook has (e.g., an address starting with
0x40...vs0x00...). If you want "BeforeSwap" permissions, you must deploy to a specific prefix. This endpoint brute-forces that deployment salt for you.How it works:
- Step 1: The Request: A developer sends a payload (
deployer,init_code_hash,prefix). - Step 2: Concurrent Mining: The engine spins up a highly optimized multi-threaded task using
rayon, utilizing all available CPU cores. - Step 3: Keccak256 Brute-forcing: It generates random salt values and hashes them to find the target Ethereum address. (e.g., Attempt 1: 0x91... Fail ❌ → Attempt 84,302: 0x40... Success! ✅)
- Step 4: Safe Concurrency: To prevent server DoS during this intense CPU work, the engine uses a
Semaphore(max 2 simultaneous jobs) and a 30-second timeout. Once the matching salt is found, it immediately halts all threads and returns the winning salt.
How to use it: Run the engine locally (it runs on port 3030 by default), then send a POST request with your hook's deployment parameters:
curl -X POST http://localhost:3030/mine \ -H "Content-Type: application/json" \ -d '{ "deployer": "0xYourWalletAddress", "init_code_hash": "0xYourCompiledBytecodeHash", "prefix": "40" }'
Response:
{ "salt": "0x000000000000000000000000000000000000000000000000000000000001494e", "address": "0x40a9...138d", "attempts": 84302, "found": true } - Step 1: The Request: A developer sends a payload (
The SDK has these modules:
- adapters/: Protocol adapters making REAL API calls
paraswap.ts→fetch("https://apiv5.paraswap.io/prices?...")one-inch.ts→fetch("https://api.1inch.dev/swap/v6.0/...")uniswap-v4.ts→client.simulateContract()on QuoterV2
- quote/engine.ts: Uses
Promise.allSettled(one failure doesn't kill all) - mev/guard.ts: POST to Rust engine
/simulate - mev/slippage.ts: Pure math slippage optimization
- execution/engine.ts: Handles approval + execution for all 3 protocols
- intent/parser.ts: Resolves token symbols (ETH, USDC, etc.) to addresses per chain
- utils/token.ts: On-chain decimal reads with known-token fallbacks (USDC=6, USDT=6, WBTC=8)
- utils/chain.ts: RPC priority: env override > Alchemy > public fallback
A second deep audit fixed three correctness bugs that made headline features silently misbehave, plus a round of cleanups. All fixes were verified against a mainnet fork (anvil) with real transactions and an exhaustive edge-case matrix.
- 🔴 Uniswap V4 quotes now work. The Quoter ABI was wrong (extra
sqrtPriceLimitX96input, array outputs), so every quote reverted on-chain and Uniswap was silently dropped from routing. Replaced with the realIV4QuoterABI ((uint256 amountOut, uint256 gasEstimate)), verified live on mainnet. Fee tiers are now quoted concurrently. - 🔴 MEV risk is no longer mis-scored. The simulator compared output-token units
(e.g. 6-decimal USDC) against gas-in-wei, so large stablecoin-output trades always read
as "no risk". Profitability is now decided in native-token wei; token→token swaps with
no native leg return
unknowninstead of a false "none". - 🔴 Uniswap V4 ERC-20 swaps now execute. Added the missing second Permit2 approval
(
Permit2.approve(token, UniversalRouter)); without it the router could not pull the token and every ERC-20-input v4 swap reverted. - 🟠 Fixed the red
pnpm typecheck(closure-narrowingneverin the gasless tests). - 🟠 CLI now reads the
1INCH_API_KEYenv var spelling shipped in.env. - 🟡 Type-safe
slippageBpson route data (removedas any); removed dead ABIs, dead Rust quote types, and the unusedACTIONS/CHAINSconstants; fixed compiler warnings. - ℹ️ Test suite expanded to 220+ checks: 34 Rust, 123 TS regression suites, 28 logic edge cases, 38 live integration tests, plus fork-based end-to-end execution.
We recently underwent an intense audit leading to 15 key fixes in v0.1.9.
- 🔴 Fixed RPC priority inversion (env vars now properly override Alchemy)
- 🔴 Fixed
netAmountOutcross-unit subtraction bug across all 3 adapters - 🔴 Fixed CLI
executecommand referencing a non-existentkit.execute. - 🟠 Fixed QuoterV2 ABI mismatch for Uniswap V4
- 🟠 Fixed
zeroForOnealways true in V4 adapter - 🟠 Fixed 1inch same-chain ERC-20 approval being skipped
- 🟠 Fixed settle/take currencies for V4 swap direction
- 🟠 Fixed Rayon thread pool starvation DoS in Rust mining
- 🟠 Replaced f64 precision loss with integer-based risk classification
- 🟡 Added graceful shutdown to Rust engine
- 🟡 Capped MEV estimate at
amount_outon overflow - 🟡 Added zero-amount rejection on all endpoints
- 🟡 Added
getTokenDecimalswith known fallbacks for USDC/USDT/WBTC - 🟡 MEV guard now clamps
netAmountOutto 0n (prevents underflow) - ℹ️ Test suite expanded from 39 → 111+ tests
We've invested heavily in Denial of Service (DoS) protections.
- Payload Bound: 64KB body size limit across the Rust Axum server.
- Concurrency Constraints: Mining API utilizes a semaphore max bounded to 2 concurrent workers to prevent thread starvation in Rayon.
- Execution Lifecycle: 30-second timeout on computationally heavy mining, combined with atomic boolean cancellation loops.
- Network Boundaries: Rust server binds to
127.0.0.1locally, preventing unwarranted global network exposure. - Integer Math Only: Total removal of
f64usage to prevent precision loss across amounts and slippage heuristics.
No! SwapKit works with zero API keys — it will route through Paraswap (which is free and open). Adding an Alchemy key enables Uniswap V4 on-chain quotes, and adding a 1inch key enables Fusion+ intent swaps.
If you are writing a quick testing script using ts-node, you might encounter CommonJS vs ESM import errors.
Solution: Use tsx instead of ts-node. It handles modern TypeScript seamlessly without configuration:
npx tsx index.tsSwapKit uses a "fail-open" design. If 1inch's API is down, the SDK silently skips it and returns quotes from the remaining protocols. Your users never see an error.
No. Without the Rust engine, SwapKit uses static slippage values (e.g., 0.5%). With the engine, it dynamically adjusts slippage based on real-time mempool analysis.
When MEV risk is high, SwapKit routes your transaction through Flashbots Protect — a private submission channel that sends your transaction directly to block builders, completely bypassing the public mempool. Bots literally cannot see your transaction to attack it.
Flashbots Protect is enabled by default. You can configure it when creating the SDK:
const sdk = createSwapKit({
oneInchApiKey: process.env.ONEINCH_API_KEY!,
rustEngineUrl: "http://localhost:3030",
// Flashbots configuration (all optional — sensible defaults are provided)
flashbotsEnabled: true, // Default: true
flashbotsProtectRpc: "https://rpc.flashbots.net", // Default: Flashbots mainnet
onFlashbotsReroute: (quote) => { // Optional callback
console.log(`🛡️ Rerouted ${quote.protocol} swap via Flashbots Protect`);
// Send alert to your monitoring system, log to analytics, etc.
},
});How it works internally:
- The SDK fetches the best quote and sends it to the Rust MEV engine for sandwich risk analysis.
- If the engine returns
sandwichRisk: "high", theExecutionEnginedynamically clones the user's wallet client with a Flashbots Protect RPC transport. - The transaction is signed identically but submitted to Flashbots' private relay instead of the public mempool.
- Bots never see the transaction. The user's swap executes safely.
Every component is validated by deterministic suites, live integration tests, and end-to-end execution against a mainnet fork (anvil):
╔══════════════════════════════════════════════════════════════╗
║ SwapKit — Full Integration & Edge Case Test Suite ║
╚══════════════════════════════════════════════════════════════╝
🦀 Rust unit + security/DoS tests ...... 34/34 ✅
📦 TS regression suites ................ 123/123 ✅
(approvals · gasless · flashbots · recipient · MEV fail-open · slippage)
🧪 TS logic edge-case suite ............ 28/28 ✅
🌐 Live integration (Alchemy + 1inch) .. 38/38 ✅
⛓️ Fork E2E execution + HTTP edge matrix . verified ✅
(Uniswap V4 ETH→USDC & USDC→WETH, 1inch ETH→USDC, /simulate · /mine · DoS)
TOTAL: 220+ checks PASSED — Ready for publication! 🎉
Reproduce the fork tests:
anvil --fork-url $RPC_ETHEREUM --port 8545 --silent & cd swap-kit/packages/core RPC_ETHEREUM=http://127.0.0.1:8545 npx tsx scripts/fork-verify.ts RPC_ETHEREUM=http://127.0.0.1:8545 npx tsx scripts/fork-edge.ts
MIT — Use SwapKit freely in commercial and open-source projects.