{"built":"20261006b","pages":[{"url":"/","title":"Overview","group":"Get started","heads":[{"id":"live-status","t":"Live status"},{"id":"what-do-you-want-to-build","t":"What do you want to build?"},{"id":"machine-readable-resources","t":"Machine-readable resources"},{"id":"how-these-docs-are-organized","t":"How these docs are organized"}],"text":"Integrate Bitcoin Swap (chain 482120) into a wallet, bot or app: prices, swaps and the Arbitrum ⇄ 482120 bridge. Bitcoin Swap is an EVM chain (Hyperledger Besu, QBFT consensus, chain ID 482120 ) with three things you can integrate: prices from the on-chain oracle, swaps across 346 pools (100 crypto tokens, 202 US stocks, 20 US ETFs, 2 pre-IPO trackers, 21 metal / index / commodity / FX trackers, USDC (Bitcoin Swap)) and OracleAMM, and a Hyperlane bridge to Arbitrum One. Every contract is verified on the explorer (the two bridge ISMs are minimal MetaProxies of verified implementations), and every public API works without a key. Live status Block 482120 … BTCw price (oracle) … Bridge — 482120 side … Bridge — Arbitrum side … Read directly from the chain and the API when you open this page. More detail on Status . Pool charts: WBTCw / USDC.e on GeckoTerminal ↗ — the chain's BTC-priced pool ( /pool/ ). What do you want to build? Show the price of BTCw or a …w token REST /api/price , or read the Chainlink-compatible feed on-chain. Let your wallet users swap Call one quote endpoint and get back a ready-to-sign transaction. Swap from a bot or contract Call ClpPools / OracleAMM directly — no server in between. Move funds between Arbitrum and 482120 USDC / USD₮0 ⇄ USDC (Bitcoin Swap) 1 : 1 over a Hyperlane warp route. Machine-readable resources Resource Use /developers/contracts.json addresses + ABIs of every public contract, on both chains /chain.json network info in ethereum-lists format /api/v2/swap/assets list of 348 assets: address, symbol, logo, oracle price /swap/sdk/btcw-swap.js JavaScript SDK (ES module, no dependencies) /developers/search.json full-text index of these docs /pool/ WBTCw / USDC.e Uniswap V2 pair — pool state, swap, unwrap (addresses in Contract addresses ) How these docs are organized Concepts explain how the system works; Guides walk through one specific task step by step; Reference lists every endpoint, function and error code. If you only have five minutes, read the Quickstart . Before shipping anything to real users, read Trust model & risks . There is no separate testnet. To experiment without spending real funds, run a chain fork locally — see Test on a chain fork ."},{"url":"/quickstart/","title":"Quickstart","group":"Get started","heads":[{"id":"1-read-the-btcw-price","t":"1. Read the BTCw price"},{"id":"2-list-what-you-can-swap","t":"2. List what you can swap"},{"id":"3-get-a-quote","t":"3. Get a quote"},{"id":"4-or-ask-the-contract-directly","t":"4. Or ask the contract directly"},{"id":"5-send-a-transaction","t":"5. Send a transaction"}],"text":"From zero to your first swap quote in five minutes — just curl or a few lines of JavaScript. Steps 1–4 only read data — no wallet, no fees. Step 5 sends a real transaction. 1. Read the BTCw price curl -s https://btcw.tech/api/price Returns price_usd , OracleAMM's actual buy/sell prices ( bid_usd / ask_usd ) and the price age. Always check stale : once the price is older than max_age_seconds (300), OracleAMM stops filling trades. See Read prices . 2. List what you can swap curl -s https://btcw.tech/api/v2/swap/assets 348 assets: native BTCw (placeholder address 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE ), USDC (Bitcoin Swap), ETH.e and 345 price-tracker tokens (100 crypto, 202 US stocks, 20 US ETFs, 2 pre-IPO trackers, 21 metal / index / commodity / FX trackers). Every asset has 18 decimals. 3. Get a quote # swap 0.001 BTCw for USDC (Bitcoin Swap) — amount is an integer in base units (18 decimals) curl -s \"https://btcw.tech/api/v2/swap/quote?from=native&to=0x3b5BD179CA6Aab4DAF0f842829776843ABe6e727&amount=1000000000000000\" The response includes amountOut , minAmountOut (after 1% slippage), fees and the route. Add &sender=0xYourWallet to also receive a ready-to-sign tx . Details: Wallet swap integration . 4. Or ask the contract directly If you don't want to trust any server, eth_call OracleAMM: import { JsonRpcProvider, Contract, parseEther, formatEther } from \"ethers\"; const p = new JsonRpcProvider(\"https://rpc.btcw.tech\", 482120); const amm = new Contract(\"0xd953d53414a81eb6AC5a4edE73d13992181aF51E\", [\"function quoteSellBtcw(uint256) view returns (uint256)\"], p); console.log(formatEther(await amm.quoteSellBtcw(parseEther(\"0.001\"))), \"USDC\"); cast call 0xd953d53414a81eb6AC5a4edE73d13992181aF51E \"quoteSellBtcw(uint256)(uint256)\" 1000000000000000 --rpc-url https://rpc.btcw.tech 5. Send a transaction Add the network to your wallet — parameters on Network , or use the \"Add network\" button on the home page . Hold a little BTCw for gas (minimum gas price 0.001 gwei — a swap costs less than 0.000001 BTCw). Send the tx from step 3 via eth_sendTransaction , or follow Swap via contracts . To try step 5 without spending real funds: anvil --fork-url https://rpc.btcw.tech gives you a chain fork with 10 accounts, each holding 10,000 BTCw. See Test on a chain fork ."},{"url":"/network/","title":"Network","group":"Get started","heads":[{"id":"parameters","t":"Parameters"},{"id":"gas-fees","t":"Gas fees"},{"id":"add-the-network-to-a-wallet","t":"Add the network to a wallet"},{"id":"add-the-usdc-bitcoin-swap-token","t":"Add the USDC (Bitcoin Swap) token"},{"id":"arbitrum-one","t":"Arbitrum One"}],"text":"Chain ID, RPC, WebSocket, explorer, gas and how to add the network to a wallet. Parameters Network name Bitcoin Swap Chain ID 482120 ( 0x75b48 ) — also the chain's Hyperlane domain RPC (HTTPS) https://rpc.btcw.tech — JSON-RPC over POST, batch requests supported RPC (WebSocket) wss://rpc.btcw.tech/ws — supports eth_subscribe ( newHeads , logs ) Explorer explorer.btcw.tech — Blockscout, with the /api/v2 API Native coin BTCw, 18 decimals Client · consensus Hyperledger Besu · QBFT Validators 3 (since 7 Oct 2026) — blocks need 2 of 3 online, so the chain keeps running with one validator offline. Current set: qbft_getValidatorsByBlockNumber(\"latest\") on a node with the QBFT API, or the miner field of recent blocks Block time 5 seconds Finality QBFT finalizes as soon as a block is produced — no reorgs, no need to wait for extra confirmations Block gas limit 30,000,000 Gas fees The chain has EIP-1559 enabled, but baseFeePerGas is always 0. Nodes only accept transactions with a gas price of at least 1000000 wei (0.001 gwei). eth_gasPrice and eth_maxPriorityFeePerGas both return exactly this value, so wallets that compute EIP-1559 fees themselves get maxFeePerGas and maxPriorityFeePerGas of at least 1000000 without extra settings. Example: a swap uses about 150,000 gas × 0.001 gwei ≈ 0.00000015 BTCw . Add the network to a wallet EIP-3085 — the same parameters the SDK exports as ADD_CHAIN_PARAMS : await window.ethereum.request({ method: \"wallet_addEthereumChain\", params: [{ chainId: \"0x75b48\", chainName: \"Bitcoin Swap\", nativeCurrency: { name: \"Bitcoin Swap\", symbol: \"BTCw\", decimals: 18 }, rpcUrls: [\"https://rpc.btcw.tech\"], blockExplorerUrls: [\"https://explorer.btcw.tech\"], iconUrls: [\"https://btcw.tech/logo-512.png?v=20261003\", \"https://btcw.tech/logo.svg\"], }], }); ethereum-lists format: /chain.json . Add the USDC (Bitcoin Swap) token await window.ethereum.request({ method: \"wallet_watchAsset\", params: { type: \"ERC20\", options: { address: \"0x3b5BD179CA6Aab4DAF0f842829776843ABe6e727\", symbol: \"USDC\", decimals: 18, image: \"https://btcw.tech/usdw.png\" } }, }); Addresses and logos of the 345 price-tracker tokens are in /api/v2/swap/assets (the logoURI field). Arbitrum One The other end of the bridge: chain ID 42161 (also its Hyperlane domain), public RPC https://arb1.arbitrum.io/rpc , explorer arbiscan.io . See Bridge ."},{"url":"/addresses/","title":"Contract addresses","group":"Get started","heads":[{"id":"assets","t":"Assets"},{"id":"swap","t":"Swap"},{"id":"wbtcw-usdc-e-pool-uniswap-v2","t":"WBTCw / USDC.e pool (Uniswap V2)"},{"id":"uniswap-v3","t":"Uniswap V3"},{"id":"smart-accounts-erc-4337","t":"Smart accounts (ERC-4337)"},{"id":"oracle","t":"Oracle"},{"id":"bridge","t":"Bridge"},{"id":"dedicated-core-wbtc-usdc-eth-and-btcw-on-arbitru","t":"Dedicated core — WBTC, USDC, ETH and BTCw-on-Arbitrum routes (R-52, R-66, R-68)"},{"id":"standard-infrastructure","t":"Standard infrastructure"},{"id":"owner-and-operator-wallets","t":"Owner and operator wallets"}],"text":"Every live contract, grouped by function. Machine-readable: contracts.json. All contracts on the 482120 side are verified on explorer.btcw.tech (the ISM of each bridge core — 0x6003…e817 for USDC/USD₮0, 0xf6c9…06a3 for the sealed WBTC route — is a 214-byte EIP-3448 MetaProxy with no source of its own; their implementations 0xb296e5632e2957c6fcda3efcc0fcf758ee5ddb54 and 0x1f8410baba198fa9d467bc028a199b3501a2c880 are verified), and since 7 Oct 2026 also on Sourcify (exact match: WBTCw, USDC.e, the Uniswap V2 factory, router and pair, the BTCw vault, and more). Arbitrum side: exact match on Sourcify / arbitrum.blockscout.com and on Arbiscan (BTCw). Machine-readable version (addresses + ABIs): /developers/contracts.json . Always identify assets by chainId + address . Symbols such as BTCW and USDW are already used by unrelated assets on other chains. Assets Name Address (482120) Notes BTCw native coin — the API uses 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE pays gas; paired in every pool USDC (Bitcoin Swap) 0x3b5BD179CA6Aab4DAF0f842829776843ABe6e727 ERC-20, 18 decimals; the asset of the bridge and OracleAMM TokenFactory 0xa4860BdfaE9B2881B1B593aFFC8740d926eCC1d1 creates the 345 price-tracker tokens (100 crypto, 202 US stocks, 20 US ETFs, 2 pre-IPO trackers, 21 metal / index / commodity / FX trackers); token list: /api/v2/swap/assets ETH.e 0x72a1Ee092807B58682592543Eba7b49004e30579 R-66: Bridged Ether (Bitcoin Swap), 18 decimals; minted 1:1 only against ETH locked in the Arbitrum vault below, burned when sent back — supply never exceeds the ETH locked Swap Name Address (482120) Notes ClpPools 0x557aDc3d900c471F3907cdDA3a9F5377d6F9E7e0 346 THORChain-style pools, each paired with BTCw UsdClpPools 0x78aCB6Ec7aF4cc83BF9E698706de79c08D61C13f R-61: 345 THORChain-style pools, each paired with USDC (Bitcoin Swap) (a second set beside ClpPools) UsdRebalancer 0xF9DAD09811755b8cf4863ed880AdD6F92358623D keeps the UsdClpPools pools near the PriceHub price from its own inventory; mints nothing OracleAMM 0xd953d53414a81eb6AC5a4edE73d13992181aF51E BTCw ⇄ USDC (Bitcoin Swap) at the oracle price ± 0.3% OracleTokenAMM (ETHw) 0xFd6d78A3b60175D37146793396A2FA7864039D54 ETHw ⇄ USDC (Bitcoin Swap) at the oracle price ± 0.3%; the bridge's ETHw destination SwapRouter 0x397E607eA05eF7909f84540077F3a716778031E4 chains up to 4 hops across ClpPools / OracleAMM / the ETHw vault into one transaction; ownerless OracleTokenAMM (ETH.e) 0x041C57991b772615e720A5b35F76Cfe52632398A R-66: ETH.e ⇄ USDC (Bitcoin Swap) at the ETH/USD oracle price ± 0.3%, 5 ETH.e per trade; buys only from its ETH.e inventory PriceAlias (ETH.e) 0x6E88283f25422969A73Dd8428b2120fD1Ffd0eD1 R-66: gives the ETH.e market PriceHub's ETHw price (ETH/USD); reverts for any other asset; ownerless SwapRouter (2nd) 0x7c2ad011E0C1D31E73F35460685f0B4fc1cC1e0E R-66: same code as SwapRouter, token venues ETHw (2) and ETH.e (3) — ETH.e ⇄ BTCw / any token in one transaction; ownerless. The SDK uses it only when one side is ETH.e OracleRebalancer 0x6c811003D301769575e9A8661B9197FAf2A32e69 pulls token pool prices back to the oracle (crypto and stocks); minter of all 345 price-tracker tokens WBTCw / USDC.e pool (Uniswap V2) Official, unmodified Uniswap V2 on chain 482120 — pair init code hash 0x96e8ac42…845f . UI: /pool/ . Deployed by the Owner wallet 0xB17b…d952 on 3 Oct 2026. Name Address (482120) Notes WBTCw 0xA7182E25e635108AD401E3be78f1c2A4593B8831 Wrapped BTCw, 18 decimals; minted only by the BTCw vault against WBTC locked on Arbitrum One; withdraw unwraps 1:1 any time; no owner USDC.e 0x7b56B7B06B8e586064787E7FfE466Ab6B78C31C7 Bridged USDC (Bitcoin Swap), 6 decimals; 1:1 with USDC locked in the Arbitrum router below UniswapV2Factory 0x453F946CB371a2039137453BAafFb83FF4ccf9f7 feeToSetter = Owner wallet, feeTo unset UniswapV2Router02 0x436997135b9332B2dFa1B20e6B24f0987778a246 WETH slot = WBTCw Pair WBTCw / USDC.e 0xED2967B738d98B3e4D3e6780A08Dc161A55EF304 token0 = USDC.e; 0.30% fee; opened at the Chainlink BTC/USD price; LP in the Owner wallet, unlocked Peg keeper 0xe20dA14F7A9715Ba685048292e53C05c097E766D swaps its own inventory when the pool drifts more than 0.5% from Chainlink BTC/USD; holds no other rights Uniswap V3 Official, unmodified Uniswap V3 ( @uniswap/v3-core 1.0.1, @uniswap/v3-periphery 1.4.4, @uniswap/swap-router-contracts 1.3.1): the runtime code is identical to the Ethereum deployments, and the source is verified on the explorer. Pool init code hash 0xe34f199b…f87b8b54 (the standard one), so SDKs compute pool addresses as on other chains. Deployed by the Owner wallet 0xB17b…d952 on 6 Oct 2026. Name Address (482120) Notes UniswapV3Factory 0xF92304dFe93Cb4C3bfAc5B0CE59C39A4126a172F owner = Owner wallet; fee tiers 0.01 / 0.05 / 0.3 / 1 % (tick spacing 1 / 10 / 60 / 200); protocol fee off NonfungiblePositionManager 0xc0b75e9c8b736E4e905db05Aa7E60DC9e5581A30 V3 positions as ERC-721 (UNI-V3-POS); WETH9 = WBTCw SwapRouter02 0xF0255ec02c8543DB6D549D87862B9ad1b13EF000 V3 pools and the Uniswap V2 factory above in one router; WETH9 = WBTCw QuoterV2 0xB854A84d06Cc58d6C94C34aCc8Ae8Dc4988aA7cB quotes for V3 swaps (eth_call) TickLens 0xb84D2A6C901eDe9518dce72A7925167343dAB3Ca initialized ticks of a pool NonfungibleTokenPositionDescriptor 0xE9cD5C54494021faB3481f58DD11794b96130F64 position tokenURI (on-chain SVG), native label BTCw NFTDescriptor (library) 0x807246C8AAC13d9693fF1B1965Ac8d712120a275 linked by the descriptor Pool WBTCw / USDC.e 0.05% 0x0F5b0bb07fe8dB6e4fB7AAEdC40BC7F45fAB18A0 Created 7 Oct 2026 at the V2 price (token0 = USDC.e). Kept on Chainlink BTC/USD by the same peg keeper as the V2 pair: beyond 0.3%, one price-limited swap back to the reference. Smart accounts (ERC-4337) Bundler https://btcw.tech/api/v2/4337/bundler , paymaster service https://btcw.tech/api/v2/4337/paymaster — see Gasless transactions . Name Address (482120) Notes EntryPoint v0.7 0x0000000071727De22E5E9d8BAf0edAc6f37da032 standard address (M8), code identical to Ethereum SimpleAccoun"},{"url":"/assets/","title":"Assets","group":"Concepts","heads":[{"id":"token-list","t":"Token list"},{"id":"btcw-native-coin","t":"BTCw — native coin"},{"id":"usdc-bitcoin-swap","t":"USDC (Bitcoin Swap)"},{"id":"price-tracker-tokens-w","t":"Price-tracker tokens (…w)"},{"id":"identifying-assets","t":"Identifying assets"},{"id":"logos","t":"Logos"}],"text":"BTCw, USDC (Bitcoin Swap) and the 345 price-tracker tokens (crypto, US stocks, US ETFs): what they are and how to identify them. The swap API lists 348 assets — native BTCw, USDC (Bitcoin Swap), ETH.e and 345 price-tracker tokens — all with 18 decimals ( /api/v2/swap/assets ). Two bridged tokens trade on the Uniswap V2 pair instead: WBTCw (18 decimals) and USDC.e ( 6 decimals ). Token list btcw.tech/tokenlist.json lists every ERC-20 on chain 482120 in the Uniswap Token Lists format (348 tokens, served with CORS), ordered by price. Native BTCw is not in it, because it is not an ERC-20. Tags give the asset tier: bridged (WBTCw, USDC.e), tracker with crypto or equity (the 345 trackers), unit (USDC on Bitcoin Swap) and staking (stBTCw). Names longer than 40 characters are shortened in the list; the on-chain names are unchanged. Wallets and aggregators can import the URL directly. BTCw — native coin The chain's native coin, used to pay gas and as the shared side of every pool. In the API and SDK, BTCw is represented by the placeholder address 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (the strings native , BTCw and 0x000…0 are also accepted). Price = BTC/USD rate from the oracle × OracleAMM's peg ratio ratioWad (currently 1). USDC (Bitcoin Swap) ERC-20 at 0x3b5BD179CA6Aab4DAF0f842829776843ABe6e727 . Used as the unit of account in OracleAMM and as the bridge asset. The Owner can mint USDC (Bitcoin Swap) ( mint is Owner-only). The bridge moves USDC (Bitcoin Swap) 1 : 1 against USDC / USD₮0 locked in the Arbitrum routers; withdrawals are capped at the amount locked on that side. Current total supply: the usdw_total_supply field of /api/price . Price-tracker tokens (…w) 345 tokens: crypto, US stocks, US ETFs, two pre-IPO trackers and 21 metal, index, commodity and FX trackers. Each token tracks the USD price of an external asset via the PriceHub oracle and has one pool against BTCw in ClpPools. The class field of /api/v2/pools gives the class: crypto , stock (US stocks, US ETFs and the pre-IPO trackers), metal , index , commodity , fx (since 9 Oct 2026) or stable (USDC on Bitcoin Swap). Rows of the last four classes also carry intro , the description of the Hyperliquid market they follow. Class Count Examples Tracks Crypto 100 ETHw, SOLw, BNBw top 100 tokens by market cap US stocks 202 NVDAw, AAPLw, MSFTw the share price of the 100 largest US companies by market cap, plus 102 more large companies (101 from Binance's stock list, and VinFast Auto); named \"<Company> Stock Price Tracker\" US ETFs 20 VOOw, SPYw, QQQw the share price of 20 large US-listed ETFs by assets under management; named \"<Fund> ETF Price Tracker\" Pre-IPO 2 OPENAIw, ANTHw the price of the OpenAI / Anthropic pre-IPO perpetual io:OAI / io:ANTH on Hyperliquid (see Price oracle ); class is stock ; named \"OpenAI Pre-IPO Price Tracker\" / \"Anthropic Pre-IPO Price Tracker\" Metals 5 GOLDw, SILVERw, COPPERw gold, silver, copper, platinum, palladium — Hyperliquid xyz perps; class metal Indices 10 SP500w, XYZ100w, 10Yw S&P 500, XYZ100, Nikkei 225, KOSPI 200, Bitcoin dominance, crypto OTHERS / TOTAL2, US 10 / 2 / 30-year yields — Hyperliquid xyz / para perps; class index Commodities 3 CLw, BRENTOILw, NATGASw WTI and Brent crude oil, natural gas — Hyperliquid xyz perps; class commodity FX 3 EURw, GBPw, JPYw EUR/USD, GBP/USD, USD/JPY — Hyperliquid xyz perps; class fx All classes run on the same mechanism: the same TokenFactory, PriceHub and ClpPools, and the same OracleRebalancer + keeper keeping pool prices near the oracle. The tracked price is the regular-session share price, multiplied by a split factor ( splitFactor ) so the series stays continuous across stock splits. Tokens are created by TokenFactory ; the only minter is OracleRebalancer , within each token's mint cap and a daily mint-value cap (see Swap mechanics ). Full list (address, name, logo, oracle price, pool depth): /api/v2/swap/assets . Identifying assets Always match on chainId 482120 + contract address . Do not match on symbol: BTCW , USDW and many …w symbols are already used by unrelated assets on other chains and on price-data platforms. Symbols are for display only. The quote API still accepts symbols for convenient manual testing, but production integrations must send addresses. Logos BTCw logo: https://btcw.tech/logo.svg (a logo.png version is also available). USDC (Bitcoin Swap): https://btcw.tech/usdw.png . Price-tracker tokens: the logoURI field in /api/v2/swap/assets ."},{"url":"/swap/","title":"Swap mechanics","group":"Concepts","heads":[{"id":"clppools-346-thorchain-style-pools","t":"ClpPools — 346 THORChain-style pools"},{"id":"oracleamm-btcw-usdc-bitcoin-swap-at-the-oracle-p","t":"OracleAMM — BTCw ⇄ USDC (Bitcoin Swap) at the oracle price"},{"id":"ethw-oracle-priced-vault","t":"ETHw oracle-priced vault"},{"id":"route-selection","t":"Route selection"},{"id":"how-pool-prices-are-pulled-back-to-the-oracle","t":"How pool prices are pulled back to the oracle"},{"id":"stock-pools-outside-market-hours","t":"Stock pools outside market hours"},{"id":"providing-liquidity","t":"Providing liquidity"}],"text":"THORChain-style CLP pools, oracle-priced AMMs and how pool prices are pulled back to the oracle. There are two execution venues. The Swap page, the quote API and the SDK query both and pick the one that gives the user more. ClpPools — 346 THORChain-style pools Each pool pairs one asset (USDC (Bitcoin Swap), a crypto price-tracker token or a stock price-tracker token) with BTCw. It uses THORChain's CLP (continuous liquidity pool) formula: y = x · X · Y / (x + X)² x : amount in X : input-side depth y : amount out Y : output-side depth The difference from the mid price x · Y / X is the slip fee: the larger the trade relative to pool depth, the higher the fee. The minimum fee minFeeBps is 5 bps (0.05%) — every trade pays at least this, however small. Fees stay in the pool. Token → token takes two hops through BTCw ( swapAssetForAsset ) in a single transaction and pays fees in both pools. Recipient is optional (the to parameter) — you can pay out directly to another wallet. Every swap function takes minOut ; if the price moves too far it reverts with SlippageExceeded . OracleAMM — BTCw ⇄ USDC (Bitcoin Swap) at the oracle price No curve: trades fill at the BTC/USD oracle price ± spreadBps . sell BTCw : USDC out = x · p · (1 − spread) buy BTCw : BTCw out = u / p · (1 − spread) Parameter Current Meaning spreadBps 30 (0.3%) fixed spread in each direction maxTradeBtcw 10 BTCw maximum per trade (in BTCw terms) maxAgeSec 300 seconds rejects trades when the oracle price is older ( StalePrice ) OracleAMM only pays the sender. To pay another wallet, use the ClpPools route. OracleAMM liquidity is deposited and withdrawn by the Owner. ETHw oracle-priced vault Address 0xFd6d78A3b60175D37146793396A2FA7864039D54 ( OracleTokenAMM ). Works like OracleAMM but for ETHw ⇄ USDC (Bitcoin Swap), priced at the PriceHub price of ETHw ± spreadBps : Parameter Current Meaning spreadBps 30 (0.3%) fixed spread in each direction maxTradeToken 300 ETHw maximum per trade maxAgeSec 300 seconds rejects trades when the price is older ( StalePrice ) The vault was seeded by the Owner with 12,280 ETHw + 33,100,000 USDC (Bitcoin Swap). buyToken / sellToken take a to parameter — you can pay out directly to another wallet. The Bridge page uses this vault when the user chooses to receive or send ETHw. Route selection For the BTCw ⇄ USDC (Bitcoin Swap) pair, the quote queries both the CLP pool and OracleAMM and picks the larger output ( route=best ). You can force one venue with route=clp or route=amm . All other pairs use ClpPools only. How pool prices are pulled back to the oracle Price-tracker tokens have no external market, so pool prices would drift away from the oracle if nothing pulled them back. Two mechanisms do that: OracleRebalancer (345 token pools — 100 crypto, 202 US stocks, 20 US ETFs, 2 pre-IPO trackers and 21 metal, index, commodity and FX trackers, same mechanism): when a pool deviates from the oracle by more than 30 bps , the contract trades to close 90% of the gap, at most 500 BTCw per trade. Pool above oracle → it sells tokens it holds, minting more if short; pool below oracle → it buys with the contract's BTCw. Safeguards: no action when the oracle price is older than 300 seconds; a mint-value cap of 160,000 BTCw per day (shared across all 345 tokens); a cumulative mint cap per token; pausable. The keeper reads the pool list straight from ClpPools every round and calls the Rebalancer in batches of 25 tokens — new pools are picked up automatically. Treasury bot (USDC (Bitcoin Swap) pool): trades to pull the USDC (Bitcoin Swap) pool back to the oracle price. Stock pools outside market hours Outside US regular trading hours and on weekends, the oracle holds the closing price , and the Rebalancer keeps pools near that price. Stock pools remain tradable 24/7; when BTC moves, the BTCw-denominated price of stock pools drifts too and is pulled back just like crypto pools. At market open, if the opening price is far from the close, the keeper moves the pool gradually (at most 500 BTCw per trade). A price update that moves more than 10% is blocked by the oracle — that symbol stays frozen until the Owner confirms the new price ( ownerSubmit ). What this means for integrators: pool prices usually sit within a few dozen bps of the oracle price. The volume of these two wallets is reported separately on the Dashboard and in /api/v2/stats ( of_which_treasury ). Providing liquidity Pool liquidity is currently provided by the Owner. These docs do not cover third-party liquidity provision."},{"url":"/oracle/","title":"Price oracle","group":"Concepts","heads":[{"id":"btc-usd-btcwpricefeed","t":"BTC/USD — BtcwPriceFeed"},{"id":"345-price-tracker-tokens-pricehub","t":"345 price-tracker tokens — PriceHub"},{"id":"stocks-24-7","t":"Stocks outside US hours (since 6 Oct 2026)"},{"id":"staleness-and-when-to-stop","t":"Staleness and when to stop"},{"id":"oracle-risks","t":"Oracle risks"}],"text":"How BTC/USD and the prices of the 345 tracker tokens (crypto, US stocks, US ETFs) are sourced, written and protected. BTC/USD — BtcwPriceFeed Contract 0x6E0687A5D5a5b98CC5fb05c4d8d742fBD75ba96c , Chainlink AggregatorV3Interface -compatible, 8 decimals . The feeder takes the median of 6 sources : Chainlink BSC, Chainlink ETH, Binance, Coinbase, Kraken, OKX. At least 3 sources must be live. It writes on-chain when the price deviates by at least 0.05% from the on-chain price, or at most every 30 seconds even if the price is unchanged. Price-jump guard : no single update may move the price more than 10% from the previous one ( PriceJumpTooLarge ) — even a compromised feeder key cannot move the price far in one write. Only the updater address can write ( NotUpdater ); the Owner has ownerSubmit for manual writes and can change the updater and the jump limit. BtcwPriceFeed provides the BTC/USD price. BTCw price = this price × OracleAMM's peg ratio ratioWad (currently 1). 345 price-tracker tokens — PriceHub Contract 0xE87FDdCC0b668564a20B23F3bE1EE108C805ecb4 , 18 decimals . Each token's price is the median across multiple sources (at least 3, discarding any source more than 2% from the median) — if one source goes down, others remain. Each class has its own source set: Crypto (100): multiple major crypto exchanges. US stocks and ETFs (202 + 20): during the US regular session, 6 public quote sources — Robinhood, Yahoo Finance, CNBC, TradingView, Nasdaq and Binance's stock list (Nasdaq has no ETFs, so ETFs have 5); at least 3 must agree. These are unofficial public APIs of those sites and may change or be blocked. The price is the regular-session price × splitFactor . Pre-IPO (2, since 7 Oct 2026): OPENAIw follows the OpenAI pre-IPO perpetual io:OAI and ANTHw (since 8 Oct) the Anthropic pre-IPO perpetual io:ANTH , both on Hyperliquid (HIP-3 market \"io\", traded 24/7; OPENAIw since 8 Oct 2026) — not shares of either company. Each price is its perp's mark price, used only while the perp's 24h volume is at least 250,000 USD and the mark is within 2% of that market's oracle price; it may move at most 20% per 10 minutes; otherwise the last price is kept. Before 8 Oct OPENAIw followed the \"OPENAI Pre IPO Token\" on Robinhood Chain (DEX pools via GeckoTerminal and DexScreener). Metals, indices, commodities, FX (21, since 9 Oct 2026): the markets of Himbit's Metals, Indices, Commodities and FX tabs, each following its Hyperliquid HIP-3 perpetual — xyz:GOLD , xyz:SILVER , xyz:COPPER , xyz:PLATINUM , xyz:PALLADIUM , xyz:XYZ100 , xyz:SP500 , xyz:JP225 , xyz:KR200 , para:BTCD , para:OTHERS , para:TOTAL2 , para:10Y , para:2Y , para:30Y , xyz:CL , xyz:NATGAS , xyz:BRENTOIL , xyz:JPY , xyz:EUR , xyz:GBP — with the same rules as the pre-IPO trackers, except the 24h volume floor: 250,000 USD by default, 100,000 USD for PALLADIUM, KR200, OTHERS, TOTAL2 and 10Y, and 20,000 USD for the thin BTCD, 2Y, 30Y and GBP markets. The price is the perp's own number: JPYw is USD/JPY (yen per dollar), 10Yw / 2Yw / 30Yw are yields in percent, BTCDw is Bitcoin dominance in percent, OTHERSw / TOTAL2w are market values in billion USD. Stocks outside US hours (since 6 Oct 2026) Prices keep updating after hours, overnight and at weekends. 206 of the 222 tickers have an off-hours source: 134 from equity perpetual markets (Binance, Hyperliquid HIP-3, Bitget, Gate, MEXC, Bybit, OKX), OKX spot stock tokens ( X<TICKER>-USDT , 1 token = 1 share, traded around the clock including weekends: 33 reviewed tickers, plus the token of any other ticker that already has at least 2 other markets, used while its 24h volume is at least $50k) and Robinhood extended hours; 40 from a same-index or same-sector reference, e.g. GOOG from GOOGL, IVV from SPY, ITUB from EWZ (ETFs with their own overnight quote, below, use that first and this reference as the fallback); 22 ADRs from their home listing × the FX rate (for example ICICI Bank in Mumbai × INR for IBN, Toyota in Tokyo × JPY for TM); 25 from Binance's public stock quote (its overnight session), the mid of bid and ask: 11 stocks — VFS (VinFast Auto), BRK-B, VZ, T, WM, CB, DUK, PM, NEE, UNP, SYK — and 14 ETFs — VOO, IVV, VTI, SPYM, BND, VGT, GLD, XLK, VUG, IEFA, VXUS, IEMG, AGG, VTV. BRK-B and the 14 ETFs also have a route above, so 206 counts them once. When the overnight book turns wide, the last tight quote is reused for up to 30 minutes; after that a ticker uses its other route if it has one, otherwise it keeps the close. The other 16 keep the latest close until the US session opens (their Binance overnight books are too wide). Guards on every off-hours price: Per market : a perpetual or spot stock-token market with less than $50k of 24h volume, or a spread wider than 1.5% (the same spread limit applies to the Binance stock quote), is ignored; the remaining markets still count. Per ticker : if no market is left, a reference or home quote is missing, or the price is more than 15% from the last US close, the token keeps its last regular-session close. A partial result is never used. On chain : PriceHub refuses any single update that moves the price more than 10% (a Rejected event, see below). At the US open every ticker returns to the median of the 5 regular-session sources. The feeder only prices tokens on each class's list — unknown tokens in the factory are skipped, never guessed from their symbol. It writes when the price deviates by at least 0.1% , or at most every 180 seconds . There is also a per-write jump guard; a blocked write emits a Rejected event instead of reverting the whole batch. function latestRoundData(address asset) view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) function prices(address[] assets) view returns (int256[] answers, uint256[] updatedAts) Full signatures: Contract reference . Staleness and when to stop OracleAMM and OracleRebalancer stop trading when the price is older than 300 seconds . Your application should do t"},{"url":"/bridge/","title":"Bridge","group":"Concepts","heads":[{"id":"model","t":"Model"},{"id":"lifecycle-of-a-transfer","t":"Lifecycle of a transfer"},{"id":"dedicated-hyperlane-infrastructure","t":"Dedicated Hyperlane infrastructure"},{"id":"rounding-granularity","t":"Rounding — granularity"},{"id":"limits-and-pausing","t":"Limits and pausing"},{"id":"eth-route-sealed-on-the-dedicated-core-r-66","t":"ETH route — sealed, on the dedicated core (R-66)"},{"id":"btcw-arbitrum","t":"BTCw on Arbitrum — sealed, on the dedicated core (R-68)"},{"id":"receive-btcw-or-ethw-directly","t":"Receive BTCw or ETHw directly"}],"text":"Hyperlane collateral ⇄ collateral warp routes between Arbitrum One and Bitcoin Swap. Model Hyperlane warp route of type collateral ⇄ collateral ( @hyperlane-xyz/core 12.1.0), 1 : 1 ratio, two routes: Route Arbitrum One Bitcoin Swap 482120 USDC USDC (6 decimals) locked in the router ⇄ USDC (Bitcoin Swap) (18 decimals) released from the router's vault USD₮0 USD₮0 (6 decimals) locked in the router ⇄ USDC (Bitcoin Swap) (18 decimals) released from the router's vault Nothing is minted on either side: each router only releases what it currently holds. So withdrawals from one side can never exceed the amount locked on that side . Both routes share USDC (Bitcoin Swap) on the 482120 side but have separate vaults. Lifecycle of a transfer The user calls transferRemote on the source-chain router — tokens are locked in the router and the Mailbox dispatches a message. The source chain's validator signs a checkpoint for the message. The relayer delivers the message + signature to the destination Mailbox. The ISM (Interchain Security Module) on the destination chain verifies the signature: multisig message-id with a 1/1 threshold. The destination router releases tokens to the recipient and emits ReceivedTransferRemote . Usually takes 10–30 seconds . If the relayer is down, messages wait and are delivered once it restarts — sent messages are not lost. Dedicated Hyperlane infrastructure The Mailbox, hooks and ISM on both chains are dedicated deployments for Bitcoin Swap, not the standard Mailbox of the Hyperlane network. The bridge's validator and relayer are dedicated as well. Consequences: Hyperlane Explorer and public relayers do not track or deliver these messages. There is no interchain gas payment: call transferRemote with msg.value = 0 ; the bridge relayer pays destination gas itself. Bridge security = security of the validator key and the Owner key. See Trust model . Rounding — granularity USDC/USD₮0 have 6 decimals, USDC (Bitcoin Swap) has 18. The 482120 router only accepts amounts divisible by granularity() = 10 12 (i.e. rounded to 6 decimal places); finer amounts revert with BadGranularity . Limits and pausing The routers are GuardedCollateralRouter — a standard warp route plus two Owner-controlled switches: allowlistEnabled() : when on, only allowlisted wallets can send ( NotAllowed ). Currently off on all 4 routers — any wallet can send. paused() : halts sending ( Paused ). In-flight messages are not lost and are delivered after unpausing. Each chain also has a PausableHook for emergency stops at the Mailbox level. Live state: Status . Step by step: Bridge funds . ETH route — sealed, on the dedicated core (R-66) Native ETH on Arbitrum One ⇄ ETH.e on Bitcoin Swap, 1 : 1, 18 decimals on both sides. It runs on the dedicated Hyperlane core of the WBTC and USDC.e routes (same Mailboxes, verifier and relayer), not on the USDC / USD₮0 core above. Arbitrum One Bitcoin Swap 482120 Contract GuardedNativeVault 0x0a3fD8b35593fB4f82Da4C110C356745Dd7CDce2 SealedSyntheticToken ETH.e 0x72a1Ee092807B58682592543Eba7b49004e30579 What happens ETH is locked in the vault ETH.e is minted to the recipient; sending it back burns it and the vault releases the ETH ETH.e supply never exceeds the ETH locked : there is no other way to mint it, so every holder can always send ETH.e back for ETH 1 : 1 (the destination liquidity check of the USDC / USD₮0 routes does not apply). Sealed : each end's verifier is fixed at deployment and its counterpart was enrolled once and can never be changed; no fees. The Owner wallet keeps only pause and the allowlist. The allowlist is off — any wallet can send. Deposit with msg.value equal to the amount: the vault bridges amount ; any extra value stays in the vault and is not bridged. ETH sent to the vault with a plain transfer mints nothing and cannot be recovered. Withdraw to a wallet: if the Arbitrum recipient is a contract that refuses ETH, the ETH.e is burned but the ETH cannot be delivered and stays in the vault. ETH.e trades on its own market (OracleTokenAMM, ETH/USD oracle price ± 0.3%) and through the second SwapRouter: quote API route amm-ethe , and best / router for BTCw and other tokens. Step by step: Bridge funds → ETH . BTCw on Arbitrum — sealed, on the dedicated core (R-68) WBTCw on Bitcoin Swap ⇄ BTCw (ERC-20, 18 decimals) on Arbitrum One, 1 : 1. The direction is the reverse of the other routes: the asset is locked on Bitcoin Swap and the token is minted on Arbitrum. Same dedicated core (Mailboxes, verifier, relayer) as the WBTC, USDC.e and ETH routes. Bitcoin Swap 482120 Arbitrum One Contract ReserveCollateralRouter (locks WBTCw) 0xCC7184B2cAc633f5d130C2A88688e4BF8d52eBa6 SealedSyntheticToken BTCw 0xeFf52De4F24238001fa9afAaF1aFEEf457fB8bbD To Arbitrum approve(lock, amount) on WBTCw, then transferRemote(42161, recipient, amount) on the lock router BTCw is minted to the recipient Back the lock router releases the WBTCw to the recipient transferRemote(482120, recipient, amount) on BTCw (no approval: it burns) BTCw on Arbitrum never exceeds the WBTCw locked , and WBTCw never exceeds the WBTC locked on Arbitrum (R-54): every BTCw there is backed 1 : 1 down to WBTC. Open to every wallet since 8 Oct 2026 (allowlist off on both ends). Sealed like the other routes: fixed verifier, counterpart enrolled once, no fees; the Owner wallet keeps pause and the allowlist. recipient is the address left-padded to 32 bytes. WBTCw is obtained on Bitcoin Swap, for example from the WBTCw / USDC.e pool ( btcw.tech/pool ). On Arbitrum, BTCw trades on Uniswap V3: BTCw/WBTC 0.01 % ( 0xA865…e04d ) and BTCw/USDC 0.05 % ( 0xdAD5…3526 ). Receive BTCw or ETHw directly The btcw.tech/swap/#bridge page lets you pick the asset on the Bitcoin Swap side: USDC (Bitcoin Swap) (1 : 1), BTCw (swapped via OracleAMM) or ETHw (swapped via the ETHw oracle-priced vault). On deposit, USDC (Bitcoin Swap) is then swapped to BTCw/ETHw (one more transaction on 482120, which needs a little BTCw for gas); on withdrawal, BTCw/ET"},{"url":"/trust/","title":"Trust model","group":"Concepts","heads":[{"id":"summary","t":"Summary"},{"id":"owner-permissions-by-contract","t":"Owner permissions by contract"},{"id":"what-you-can-read-before-every-action","t":"What you can read before every action"}],"text":"Who controls what and what they can do — know this before you integrate. This page lists who holds which permissions on each contract, read from the chain and the contract sources on 4 Oct 2026, so you can see exactly what each role can and cannot do. Summary Two owner wallets. Contracts deployed up to 2 Oct 2026 are owned by 0x4aFd0A931176103d704Ff0d696614d4E10d74A4a ; contracts deployed from 2 Oct 2026 (sealed bridge routes, WBTCw pool, USDC (Bitcoin Swap) hub pools, Earn) by 0xB17bdA8F14EEb9fd67B34810A2e1E82A737Ad952 . Neither is a multisig and there is no timelock. No owner at all: WBTCw, SwapRouter, Multicall3, the Uniswap V2 pair and router, and the Uniswap V3 position manager, SwapRouter02, QuoterV2 and TickLens. Bridged assets are checkable live: Proof of reserve compares WBTCw and USDC.e on this chain with the WBTC and USDC locked on Arbitrum One, straight from both chains. Owner permissions by contract Contract Owner Owner can Sealed bridge routes: BTCw native vault, USDC.e (482120); WBTC and USDC routers (Arbitrum One) 0xB17b…d952 pause the route and manage its allowlist — nothing else. The verification module is fixed at deployment, the remote router is enrolled once and cannot be changed, the hook cannot be changed, and there is no owner withdrawal WBTCw none no owner, no pause, no mint function. New WBTCw is minted only when the vault sends BTCw released against WBTC locked on Arbitrum; it goes to the beneficiary (0xB17b…d952), which has no other power. Anyone can unwrap with withdraw SimpleEarn · FixedEarn · StakedBTCw 0xB17b…d952 create or disable markets, pause new deposits, take back the part of the reward budget not yet paid out ( reclaim ), recover tokens sent by mistake ( sweep , which excludes deposits and booked rewards). FixedEarn: set term rates and the per-asset rate floor; a rate setter may move rates within [minSetterAprBps, maxSetterAprBps] . StakedBTCw: change the unstake cooldown (up to MAX_COOLDOWN , only while paused). Withdrawals, claims, redemptions and unstaking keep working while paused ; the owner has no function that moves a depositor's principal EarnPriceSource 0xB17b…d952 change the price sources and the maximum price age UsdClpPools 0xB17b…d952 create pools, enable/disable pools, change the minimum fee, pause; add or remove Owner-provided liquidity; sweep tokens sent by mistake UsdRebalancer 0xB17b…d952 change parameters, set keepers, pause, withdraw its own inventory (it mints nothing) Uniswap V2 factory feeToSetter 0xB17b…d952 turn on the protocol fee ( feeTo , 1/6 of the 0.30% fee); currently off. Pairs and router have no owner Uniswap V3 factory 0xB17b…d952 add a fee tier ( enableFeeAmount , cannot be removed); turn on the protocol fee of a pool ( setFeeProtocol , 1/4 to 1/10 of the swap fee) and collect it; transfer ownership. Protocol fee currently off on every pool. Pools, positions and the periphery have no owner; the owner cannot move liquidity USDC (Bitcoin Swap) 0x4aFd…74A4a mint without limit; change name/symbol TokenFactory · price-tracker tokens 0x4aFd…74A4a change the minter, change mint caps, change name/symbol, transfer token ownership OracleRebalancer 0x4aFd…74A4a change parameters (threshold, step, daily cap…), set the keeper, pause, withdraw the contract's assets ClpPools 0x4aFd…74A4a create pools, enable/disable individual pools, change the minimum fee (up to 10%), pause; withdraw Owner-provided liquidity. sweep only recovers funds sent by mistake — it cannot withdraw pool depth OracleAMM · OracleTokenAMM (ETHw) 0x4aFd…74A4a deposit/withdraw liquidity, change spread / per-trade cap / max price age, change the price feed, change the peg ratio, pause BtcwPriceFeed · PriceHub 0x4aFd…74A4a write prices manually ( ownerSubmit ), change the updater, change the price-jump limit USDC / USD₮0 ⇄ USDC (Bitcoin Swap) routes (R-40, 2 routers on each chain) 0x4aFd…74A4a pause, enable the allowlist, and every permission of a standard Hyperlane warp route: change the ISM, the hook and the remote routers All of these permissions can be read in the contract sources. We are not aware of any permission outside the list above. What you can read before every action paused() , allowlistEnabled() and the price age ( updatedAt ) — read them instead of hardcoding them. Parameter-change events: ParamsSet , PausedSet , UpdaterSet , MinFeeSet , AllowlistEnabledSet , TermSet , AssetFloorSet , CooldownSet . Bridged supply against the locked collateral: Proof of reserve . Self-verifiable figures (genesis, block cadence): Transparency page ."},{"url":"/guides/add-to-wallet/","title":"Add to your wallet","group":"Guides","heads":[{"id":"network-details","t":"Network details"},{"id":"wallet-by-wallet","t":"Wallet by wallet"},{"id":"for-developers","t":"For developers"}],"text":"One click from btcw.tech, or the network details to enter by hand in 16 wallets. The quickest way: open btcw.tech and press Add Bitcoin Swap network . Your wallet shows the details below and asks you to approve. If several wallet extensions are installed, the page asks which one to use. The Swap and Pool pages also add the network when you connect a wallet that does not have it yet. Network details Network name Bitcoin Swap RPC URL https://rpc.btcw.tech Chain ID 482120 Currency symbol BTCw (18 decimals) Block explorer URL https://explorer.btcw.tech Then add the USDC (Bitcoin Swap) token if your wallet does not show it: contract 0x3b5BD179CA6Aab4DAF0f842829776843ABe6e727 , symbol USDC , 18 decimals (or press Add USDC (Bitcoin Swap) token on btcw.tech ). Wallet by wallet Wallet One click from btcw.tech By hand MetaMask (extension, mobile) Yes Network menu → Add a custom network → enter the details above OneKey (extension, desktop, mobile) Yes Network selector → Add custom network (EVM) Trust Wallet Extension: yes Add custom network (mobile and extension) Rabby (extension, mobile) Yes More → Custom Network → Add Custom Network OKX Wallet — App: Custom networks ; extension: Add network Bitget Wallet Yes Custom mainnet → enter the details above SafePal (app 3.9.0 or later, extension) — Add Manually under network management TokenPocket — Add Custom Network imToken Yes Add a custom network with the details above Zerion (extension, mobile) Extension: yes Add a network by hand, or pick it from Available networks Brave Wallet Yes brave://settings/wallet/networks → Add Rainbow Extension: yes Extension only: Custom networks Enkrypt Yes Other networks → + Core Yes Manage networks → + Taho Yes Add a custom network Ledger or Trezor device Through MetaMask or Rabby Connect the device to MetaMask or Rabby, then add the network there as above For developers The button sends EIP-3085 wallet_addEthereumChain with these values (the same as the chain registry entry; see also Network ): { chainId: \"0x75b48\", chainName: \"Bitcoin Swap\", nativeCurrency: { name: \"Bitcoin Swap\", symbol: \"BTCw\", decimals: 18 }, rpcUrls: [\"https://rpc.btcw.tech\"], blockExplorerUrls: [\"https://explorer.btcw.tech\"], iconUrls: [\"https://btcw.tech/logo-512.png?v=20261003\", \"https://btcw.tech/logo.svg\"] }"},{"url":"/guides/gasless/","title":"Gasless transactions (ERC-4337)","group":"Guides","heads":[{"id":"endpoints-and-contracts","t":"Endpoints and contracts"},{"id":"what-is-sponsored","t":"What is sponsored"},{"id":"example-a-first-transaction-with-0-btcw-viem-per","t":"Example: a first transaction with 0 BTCw (viem + permissionless)"}],"text":"Smart-account wallets with gas paid by the paymaster: bundler, ERC-7677 paymaster service, what is sponsored. Chain 482120 runs the standard ERC-4337 stack: EntryPoint v0.7 and SimpleAccountFactory at their usual addresses, a public bundler, and a paymaster that pays the gas of new smart-account wallets. A user with no BTCw at all can create a wallet and trade in the first transaction. Endpoints and contracts Bundler (ERC-4337 JSON-RPC) https://btcw.tech/api/v2/4337/bundler Paymaster service (ERC-7677) https://btcw.tech/api/v2/4337/paymaster · status /api/v2/4337/paymaster/healthz EntryPoint v0.7 0x0000000071727De22E5E9d8BAf0edAc6f37da032 SimpleAccountFactory v0.7 0x91E60e0613810449d098b0b5Ec8b51A0FE8c8985 VerifyingPaymaster 0x876Be0170F5fb4Cd86b1990Bb2A34fe52F089aEd The factory and the EntryPoint have the same address and code as on Ethereum, so SDKs that use the standard 4337 addresses (viem, permissionless) work without extra configuration. The paymaster is the VerifyingPaymaster that ships with EntryPoint v0.7 ( @account-abstraction/contracts 0.7.0), source verified on the explorer. Bundler methods: eth_chainId , eth_supportedEntryPoints , eth_estimateUserOperationGas , eth_sendUserOperation , eth_getUserOperationByHash , eth_getUserOperationReceipt , pimlico_getUserOperationGasPrice . Gas price: 1000000 wei for both maxFeePerGas and maxPriorityFeePerGas (base fee is always 0). What is sponsored Wallets : SimpleAccount wallets created by the factory above, during their first 30 days (counted from their first sponsored operation). Calls : every call in the operation must go to one of the swap and Earn contracts — SwapRouter, OracleAMM, the ETHw oracle AMM, ClpPools, UsdClpPools, Uniswap V2 Router02, Uniswap V3 SwapRouter02, SimpleEarn, FixedEarn, StakedBTCw (addresses in Addresses ) — or be an approve whose spender is one of them. Transfers to other addresses are not sponsored. Limits : 10 operations per wallet per day, 50 in its first 30 days, 600,000 gas per operation; 30 per network address per day; 1,000 per day in total. Vouchers are signed for one exact operation and expire after 120 seconds; the service simulates the calls before signing. Operations outside these rules are refused with a JSON-RPC error that says why (for example call to 0x… is not covered by the sponsorship ). A wallet can always pay its own gas instead: send the operation without a paymaster once the account holds a little BTCw. Example: a first transaction with 0 BTCw (viem + permissionless) import { createPublicClient, http, encodeFunctionData, parseAbi, defineChain } from \"viem\"; import { privateKeyToAccount } from \"viem/accounts\"; import { createBundlerClient, createPaymasterClient, entryPoint07Address } from \"viem/account-abstraction\"; import { toSimpleSmartAccount } from \"permissionless/accounts\"; const chain = defineChain({ id: 482120, name: \"Bitcoin Swap\", nativeCurrency: { name: \"Bitcoin Swap\", symbol: \"BTCw\", decimals: 18 }, rpcUrls: { default: { http: [\"https://rpc.btcw.tech\"] } } }); const client = createPublicClient({ chain, transport: http() }); const owner = privateKeyToAccount(process.env.OWNER_KEY); // the user's signing key; it needs no BTCw const account = await toSimpleSmartAccount({ client, owner, entryPoint: { address: entryPoint07Address, version: \"0.7\" }, factoryAddress: \"0x91E60e0613810449d098b0b5Ec8b51A0FE8c8985\" }); const fees = { maxFeePerGas: 1_000_000n, maxPriorityFeePerGas: 1_000_000n }; const bundler = createBundlerClient({ account, client, transport: http(\"https://btcw.tech/api/v2/4337/bundler\"), paymaster: createPaymasterClient({ transport: http(\"https://btcw.tech/api/v2/4337/paymaster\") }), userOperation: { estimateFeesPerGas: async () => fees } }); // approve USDC (Bitcoin Swap) for ClpPools (an allowed spender); add the swap call to the same array to trade in one operation const approve = encodeFunctionData({ abi: parseAbi([\"function approve(address,uint256)\"]), functionName: \"approve\", args: [\"0x557aDc3d900c471F3907cdDA3a9F5377d6F9E7e0\", 10n ** 18n] }); const hash = await bundler.sendUserOperation({ calls: [{ to: \"0x3b5BD179CA6Aab4DAF0f842829776843ABe6e727\", value: 0n, data: approve }], ...fees }); const receipt = await bundler.waitForUserOperationReceipt({ hash }); console.log(account.address, receipt.success, receipt.receipt.transactionHash); The first operation also deploys the wallet (about 270,000 gas); later ones cost about 120,000 gas plus the calls. Swap transactions to put in calls come ready-built from the quote API (use the smart-account address as sender and recipient )."},{"url":"/guides/deploy/","title":"Deploy a contract","group":"Guides","heads":[{"id":"1-network-settings","t":"1. Network settings"},{"id":"2-get-a-little-btcw-for-gas","t":"2. Get a little BTCw for gas"},{"id":"3a-foundry","t":"3a. Foundry"},{"id":"3b-hardhat","t":"3b. Hardhat"},{"id":"4-verify-the-source","t":"4. Verify the source"},{"id":"5-infrastructure-already-on-the-chain","t":"5. Infrastructure already on the chain"},{"id":"6-get-listed-on-the-ecosystem-page","t":"6. Get listed on the Ecosystem page"}],"text":"Foundry or Hardhat settings for chain 482120, getting gas, verifying the source on the explorer. Bitcoin Swap is a standard EVM chain (Besu, Cancun rules), so the usual tools work unchanged. Deploying a contract costs a fraction of a cent: a 150,000-gas deployment at the network's 0.001 gwei gas price is about 0.00000016 BTCw . The steps below were run end to end against a fork of the live chain — about five minutes from an empty folder to a deployed, called contract. 1. Network settings Chain ID 482120 RPC https://rpc.btcw.tech EVM version cancun — set it explicitly; compilers that default to a newer target may emit code the chain does not run Gas price 1000000 wei (0.001 gwei); base fee is always 0 Explorer explorer.btcw.tech (Blockscout, Etherscan-compatible API at /api ) 2. Get a little BTCw for gas Swap a few USDC (Bitcoin Swap), USDC.e or any of the 348 assets for BTCw on Swap — 0.0001 BTCw covers hundreds of deployments. Bring USDC or USD₮0 from Arbitrum with the bridge , then swap. Holding tokens but no BTCw at all? The gas faucet sends a small amount once per wallet. Before using real funds, rehearse every step on a local fork — see Test on a chain fork ; the commands below work there with --rpc-url http://127.0.0.1:8545 . 3a. Foundry forge init hello && cd hello # foundry.toml, under [profile.default]: # evm_version = \"cancun\" forge create src/Counter.sol:Counter \\ --rpc-url https://rpc.btcw.tech \\ --private-key $PRIVATE_KEY \\ --broadcast cast send <deployed address> \"setNumber(uint256)\" 42 --rpc-url https://rpc.btcw.tech --private-key $PRIVATE_KEY cast call <deployed address> \"number()(uint256)\" --rpc-url https://rpc.btcw.tech forge script with --broadcast works the same way. Deterministic (CREATE2) deployments in scripts use the standard deployer 0x4e59b44847b379578588920cA78FbF26c0B4956C , which is live on this chain — so a contract gets the same address here as on other EVM chains. 3b. Hardhat npm i -D hardhat@2 @nomicfoundation/hardhat-ethers@3 ethers@6 hardhat.config.js : require(\"@nomicfoundation/hardhat-ethers\"); module.exports = { solidity: { version: \"0.8.24\", settings: { evmVersion: \"cancun\", optimizer: { enabled: true, runs: 200 } } }, networks: { bitcoinswap: { url: \"https://rpc.btcw.tech\", chainId: 482120, accounts: [process.env.PRIVATE_KEY], gasPrice: 1000000 }, }, }; scripts/deploy.js : const hre = require(\"hardhat\"); async function main() { const c = await hre.ethers.deployContract(\"Hello\"); await c.waitForDeployment(); console.log(\"deployed to\", await c.getAddress()); } main().catch((e) => { console.error(e); process.exit(1); }); npx hardhat run scripts/deploy.js --network bitcoinswap @nomicfoundation/hardhat-ethers 4.x needs Hardhat 3; with Hardhat 2 keep version 3 as above. 4. Verify the source Blockscout accepts the standard verifiers. With Foundry: forge verify-contract <address> src/Counter.sol:Counter \\ --chain 482120 \\ --verifier blockscout \\ --verifier-url https://explorer.btcw.tech/api/ You can also upload the solc standard-JSON input in the explorer (contract page → Verify & publish ). Verification is free and needs no API key. Chain 482120 is also supported by Sourcify (since 7 Oct 2026), so the same source can be published there, again without a key: forge verify-contract <address> src/Counter.sol:Counter \\ --chain 482120 \\ --verifier sourcify 5. Infrastructure already on the chain Permit2, EntryPoint v0.7 and Safe 1.3.0 are deployed at their usual addresses — see Addresses . Multicall3 is at its own address (also listed there). There is no need to deploy your own copies. 6. Get listed on the Ecosystem page Once your app is live with a working interface, send it from the List your app form at the end of the Ecosystem page: name, website, category, a short description, your contracts on 482120 (each must have code on the chain) and a contact. Every request is reviewed; verified contracts show a badge on the listing, read live from the explorer."},{"url":"/guides/read-prices/","title":"Read prices","group":"Guides","heads":[{"id":"option-1-rest-the-simplest","t":"Option 1 — REST, the simplest"},{"id":"prices-of-the-345-price-tracker-tokens-crypto-us","t":"Prices of the 345 price-tracker tokens (crypto, US stocks, US ETFs)"},{"id":"option-2-on-chain-trust-no-server","t":"Option 2 — on-chain, trust no server"},{"id":"from-a-solidity-contract-on-chain-482120","t":"From a Solidity contract on chain 482120"},{"id":"price-tracker-token-prices-pricehub","t":"Price-tracker token prices — PriceHub"},{"id":"watch-for-price-changes","t":"Watch for price changes"}],"text":"Get BTCw and tracker-token prices over REST or on-chain (Chainlink AggregatorV3 standard). Option 1 — REST, the simplest curl -s https://btcw.tech/api/price { \"symbol\": \"BTCw\", \"chain_id\": 482120, \"decimals\": 18, \"price_usd\": 83380.39, // oracle price × peg ratio \"bid_usd\": 83130.25, // OracleAMM buys your BTCw at this price \"ask_usd\": 83630.53, // OracleAMM sells you BTCw at this price \"spread_pct\": 0.3, \"updated_at\": 1790739823, \"age_seconds\": 5, \"max_age_seconds\": 300, \"stale\": false, \"paused\": false, \"tradable\": true, \"liquidity\": { \"btcw\": 1001, \"usdw\": 49916961.49, \"max_trade_btcw\": 10 }, \"oracle\": { \"address\": \"0x6E06…a96c\", \"decimals\": 8, \"sources\": \"median of 6: …\" }, \"usdw_total_supply\": 122171970.27, … } Safe to use when stale == false and paused == false . tradable combines both conditions with liquidity. Prices of the 345 price-tracker tokens (crypto, US stocks, US ETFs) curl -s https://btcw.tech/api/v2/pools # per pool: oracleUsd, poolUsd, devBps, depthBtcw, priceAgeS… curl -s https://btcw.tech/api/v2/swap/assets # 348 assets: address, symbol, decimals, logoURI, priceUsd Filter by class with the class field ( crypto · stock · stable ). oracleUsd is the oracle price (PriceHub); poolUsd is the current pool price; devBps is the deviation between the two. Staleness: check priceAgeS (a sensible threshold: 300 seconds). Responses are cached for 5 seconds ( cache-control: public, max-age=5 ) — polling more often won't return fresher data. Rate limit: 20 requests/second per IP. Option 2 — on-chain, trust no server BtcwPriceFeed follows the Chainlink interface, so any tool that reads Chainlink feeds can read it: cast call 0x6E0687A5D5a5b98CC5fb05c4d8d742fBD75ba96c \\ \"latestRoundData()(uint80,int256,uint256,uint256,uint80)\" --rpc-url https://rpc.btcw.tech import { JsonRpcProvider, Contract } from \"ethers\"; const p = new JsonRpcProvider(\"https://rpc.btcw.tech\", 482120); const feed = new Contract(\"0x6E0687A5D5a5b98CC5fb05c4d8d742fBD75ba96c\", [\"function latestRoundData() view returns (uint80,int256,uint256,uint256,uint80)\"], p); const [, answer, , updatedAt] = await feed.latestRoundData(); const age = Math.floor(Date.now() / 1000) - Number(updatedAt); if (age > 300) throw new Error(\"oracle price is stale\"); console.log(\"BTC/USD\", Number(answer) / 1e8); From a Solidity contract on chain 482120 interface AggregatorV3Interface { function latestRoundData() external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); } (, int256 answer,, uint256 updatedAt,) = AggregatorV3Interface(0x6E0687A5D5a5b98CC5fb05c4d8d742fBD75ba96c).latestRoundData(); require(block.timestamp - updatedAt <= 300, \"stale\"); // 8 decimals Price-tracker token prices — PriceHub # ETHw price (18 decimals) — substitute a token address from /api/v2/swap/assets cast call 0xE87FDdCC0b668564a20B23F3bE1EE108C805ecb4 \\ \"latestRoundData(address)(uint80,int256,uint256,uint256,uint80)\" <token-address> --rpc-url https://rpc.btcw.tech Several tokens at once: prices(address[]) returns two arrays, answers and updatedAts ; tokens without a price return (0, 0) (whereas latestRoundData reverts with NoData ). Watch for price changes Instead of polling, subscribe to events over WebSocket at wss://rpc.btcw.tech/ws : // BtcwPriceFeed: AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt) // PriceHub: AnswerUpdated(address indexed asset, int256 answer, uint256 roundId, uint256 updatedAt) const ws = new WebSocketProvider(\"wss://rpc.btcw.tech/ws\", 482120); feed.connect(ws).on(\"AnswerUpdated\", (current) => console.log(Number(current) / 1e8));"},{"url":"/guides/swap-contracts/","title":"Swap through contracts","group":"Guides","heads":[{"id":"general-flow","t":"General flow"},{"id":"oracleamm-btcw-usdc-bitcoin-swap","t":"OracleAMM — BTCw ⇄ USDC (Bitcoin Swap)"},{"id":"clppools-every-pair","t":"ClpPools — every pair"},{"id":"with-foundry-cast","t":"With Foundry cast"},{"id":"multi-hop-in-one-transaction-swaprouter","t":"Multi-hop in one transaction — SwapRouter"},{"id":"tracking-results","t":"Tracking results"}],"text":"Quote and send swaps with ethers v6 or Foundry cast, without any server in between. Call the verified contracts directly — no API, no integration fee. You need a wallet with a little BTCw for gas. If you want the API to build transactions for you, see Wallet swap integration . General flow Quote with a quote… function (view, free). Compute minOut = quote × (1 − acceptable slippage). Every swap function takes this parameter; if the price moves too far it reverts with SlippageExceeded , costing nothing but gas. If selling an ERC-20 token: approve the exact amount to the executing contract. Send the swap. Native BTCw is attached as msg.value . There is no on-chain deadline — minOut is the only protection. OracleAMM — BTCw ⇄ USDC (Bitcoin Swap) Address 0xd953d53414a81eb6AC5a4edE73d13992181aF51E . At most 10 BTCw per trade; pays the sender. function quoteSellBtcw(uint256 btcwIn) view returns (uint256 usdOut) function quoteBuyBtcw(uint256 usdIn) view returns (uint256 btcwOut) function sellBtcw(uint256 minUsdOut) payable returns (uint256 usdOut) // send BTCw as msg.value function buyBtcw(uint256 usdIn, uint256 minBtcwOut) returns (uint256 btcwOut) // approve USDC (Bitcoin Swap) to OracleAMM first import { JsonRpcProvider, Wallet, Contract, parseEther } from \"ethers\"; const p = new JsonRpcProvider(\"https://rpc.btcw.tech\", 482120); const w = new Wallet(process.env.PRIVATE_KEY, p); const amm = new Contract(\"0xd953d53414a81eb6AC5a4edE73d13992181aF51E\", [ \"function quoteSellBtcw(uint256) view returns (uint256)\", \"function sellBtcw(uint256) payable returns (uint256)\", ], w); const inAmt = parseEther(\"0.001\"); const quote = await amm.quoteSellBtcw(inAmt); // USDC (Bitcoin Swap), 18 decimals const tx = await amm.sellBtcw(quote * 99n / 100n, { value: inAmt }); // accept 1% slippage await tx.wait(); ClpPools — every pair Address 0x557aDc3d900c471F3907cdDA3a9F5377d6F9E7e0 . Every pool is paired with BTCw; token → token takes two hops in one transaction. function quoteBtcwForAsset(address token, uint256 btcwIn) view returns (uint256 out, uint256 fee) function quoteAssetForBtcw(address token, uint256 amountIn) view returns (uint256 out, uint256 fee) function swapBtcwForAsset(address token, uint256 minOut, address to) payable returns (uint256) function swapAssetForBtcw(address token, uint256 amountIn, uint256 minOut, address to) returns (uint256) function swapAssetForAsset(address tokenIn, address tokenOut, uint256 amountIn, uint256 minOut, address to) returns (uint256) Quoting token → token: call quoteAssetForBtcw(tokenIn, amountIn) , then quoteBtcwForAsset(tokenOut, result) . const clp = new Contract(\"0x557aDc3d900c471F3907cdDA3a9F5377d6F9E7e0\", [ \"function quoteBtcwForAsset(address,uint256) view returns (uint256 out, uint256 fee)\", \"function swapBtcwForAsset(address,uint256,address) payable returns (uint256)\", ], w); const token = \"0x…\"; // address from /api/v2/swap/assets const [out] = await clp.quoteBtcwForAsset(token, parseEther(\"0.01\")); await (await clp.swapBtcwForAsset(token, out * 99n / 100n, w.address, { value: parseEther(\"0.01\") })).wait(); With Foundry cast # quote 0.01 BTCw → token cast call 0x557aDc3d900c471F3907cdDA3a9F5377d6F9E7e0 \"quoteBtcwForAsset(address,uint256)(uint256,uint256)\" $TOKEN 10000000000000000 --rpc-url https://rpc.btcw.tech # sell token → BTCw: approve the exact amount, then swap cast send $TOKEN \"approve(address,uint256)\" 0x557aDc3d900c471F3907cdDA3a9F5377d6F9E7e0 $AMOUNT --rpc-url https://rpc.btcw.tech --private-key $PK cast send 0x557aDc3d900c471F3907cdDA3a9F5377d6F9E7e0 \"swapAssetForBtcw(address,uint256,uint256,address)\" $TOKEN $AMOUNT $MIN_OUT $ME --rpc-url https://rpc.btcw.tech --private-key $PK Multi-hop in one transaction — SwapRouter Address 0x397E607eA05eF7909f84540077F3a716778031E4 . The contract is ownerless , with no mutable parameters. It chains up to 4 hops, each hop being (venue, tokenOut) : venue 0 is ClpPools, 1 is OracleAMM (BTCw ⇄ USDC (Bitcoin Swap)), 2 and above are the oracle-priced token vaults in tokenAmmAt(i) order (currently venue 2 = ETHw vault). Native BTCw is written as 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE . function quote(address tokenIn, uint256 amountIn, (uint8 venue, address tokenOut)[] hops) view returns (uint256 amountOut) function swap(address tokenIn, uint256 amountIn, (uint8 venue, address tokenOut)[] hops, uint256 minOut, address to, uint256 deadline) payable returns (uint256 amountOut) BTCw in: send msg.value = amountIn . Token in: approve the exact amount to the router — the router only pulls from msg.sender . quote does not check per-trade caps, inventory or pause state — the SDK and the quote API check those beforehand. deadline is a Unix timestamp; past it, the call reverts with Expired . # 0.1 BTCw → ETHw: OracleAMM (BTCw → USDC), then the ETHw vault (USDC → ETHw), in one transaction cast call 0x397E607eA05eF7909f84540077F3a716778031E4 \"quote(address,uint256,(uint8,address)[])(uint256)\" \\ 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE 100000000000000000 \\ \"[(1,0x3b5BD179CA6Aab4DAF0f842829776843ABe6e727),(2,0xd8fA8202ecC699687182109084B9ECBb44025759)]\" --rpc-url https://rpc.btcw.tech The quote API and the SDK ( router route) find the path and return a ready-made router transaction — see Wallet swap integration . Tracking results // SwapRouter event Routed(address indexed sender, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut, address to, uint256 hops) // ClpPools event Swap(address indexed trader, address indexed token, bool btcwIn, uint256 amountIn, uint256 amountOut, uint256 fee, address to) // OracleAMM event Swap(address indexed trader, bool btcwIn, uint256 amountIn, uint256 amountOut, uint256 priceWad) Common errors and revert codes: Limits & error codes . Try it first on a chain fork: Test on a chain fork ."},{"url":"/guides/wallet-swap/","title":"Swaps for wallets","group":"Guides","heads":[{"id":"asset-list","t":"Asset list"},{"id":"quote-get-api-v2-swap-quote","t":"Quote — GET /api/v2/swap/quote"},{"id":"sdk","t":"SDK"},{"id":"deep-link","t":"Deep link"}],"text":"A THORChain-style quote API that returns ready-to-sign transactions — any pair of the 348 assets. This follows the THORChain model for opening swaps to wallets: the wallet calls one quote endpoint and gets back the amount out, fees, route and a prebuilt transaction to sign. Any pair among the 348 assets (native BTCw, USDC (Bitcoin Swap), ETH.e, 345 …w tokens) can be swapped, in both directions. Transactions call the verified ClpPools / OracleAMM contracts directly : no intermediary router, no integration fee, no API key. Integration Best for REST GET /api/v2/swap/quote wallets/apps that don't want to read contracts themselves; returns JSON with a ready tx SDK /swap/sdk/btcw-swap.js ES module, no dependencies; quotes are read straight from the contracts over RPC, so you don't have to trust any server. The API uses this same file , so both always return the same numbers Deep link /swap/?from=…&to=…&amount=… wallets with a dApp browser: opens the Swap page, wallet detected via EIP-6963 / window.ethereum Asset list GET https://btcw.tech/api/v2/swap/assets → { chainId: 482120, assets: [ { address, native, symbol, name, decimals, logoURI, priceUsd, poolDepthBtcw }, … ] } // 348 entries Native BTCw uses the conventional address 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE ( native , BTCw and 0x000…0 are also accepted). All assets have 18 decimals . Identify assets by chainId + address , not by symbol. Quote — GET /api/v2/swap/quote Parameter from , to token address or native (symbols also work, for manual testing only) amount integer, base units — 1 BTCw = 1000000000000000000 sender the signing wallet. When set, the response includes a ready-to-send tx , checks balance + approval, and simulates the transaction ( simulation ) recipient receiver (defaults to sender ). OracleAMM only pays the sender, so a different recipient leaves only the ClpPools route slippage_bps 1–5000, default 100 (1%) → minAmountOut route best (default) · clp · amm · amm-eth · router · usdclp · v2 · v3 curl -s \"https://btcw.tech/api/v2/swap/quote?from=native&to=0xd8fA8202ecC699687182109084B9ECBb44025759&amount=1000000000000000000&sender=0xYourWallet\" { \"chainId\": 482120, \"from\": \"0xEeee…EEeE\", \"to\": \"0xd8fa…5759\", \"amountIn\": \"1000000000000000000\", \"venue\": \"clp\", \"amountOut\": \"30126980820155435233\", \"minAmountOut\": \"29825711011953880880\", \"legs\": [\"0xEeee…EEeE\", \"0xd8fa…5759\"], // token → token: 3 entries, BTCw in the middle \"fees\": [{ \"asset\": \"0xd8fa…5759\", \"amount\": \"1102883046289534940\" }], \"priceImpactBps\": 353, // slippage + fee vs. the pool mid price \"oracleDeviationBps\": -333, // vs. the oracle price \"routes\": [ { \"venue\": \"clp\", \"amountOut\": \"…\" }, { \"venue\": \"amm\", \"error\": \"…\" } ], \"approval\": null, // token in: { token, spender, amount, needed, tx } \"tx\": { \"chainId\": 482120, \"from\": \"0x…\", \"to\": \"0x557a…E7e0\", \"data\": \"0x3428bb69…\", \"value\": \"0xde0b6b3a7640000\" }, \"simulation\": { \"ok\": true }, \"expiresAt\": 1790738178, \"warnings\": [] } Wallet flow: if approval.needed , send approval.tx first (approve the exact amount , not unlimited), wait for it to be mined, request a new quote, then send tx . There is no on-chain deadline — minAmountOut is the protection; if the user waits past expiresAt (30 seconds), request a new quote. If the price moves beyond the slippage tolerance, the transaction reverts with SlippageExceeded ( 0x71c4efed ) and nothing is lost except gas. Invalid input returns HTTP 400 with error ; if no route can fill the order, 422. Rate limit: 20 requests/second per IP. SDK import { getQuote, ADD_CHAIN_PARAMS, waitForReceipt } from \"https://btcw.tech/swap/sdk/btcw-swap.js\"; await ethereum.request({ method: \"wallet_addEthereumChain\", params: [ADD_CHAIN_PARAMS] }); const q = await getQuote({ from: \"native\", to: \"0xd8fA8202ecC699687182109084B9ECBb44025759\", amount: 10n ** 18n, sender: me, slippageBps: 100 }); if (q.error) throw new Error(q.error); if (q.approval?.needed) await waitForReceipt(await ethereum.request({ method: \"eth_sendTransaction\", params: [q.approval.tx] })); const hash = await ethereum.request({ method: \"eth_sendTransaction\", params: [q.tx] }); Also exported: getAssets() , decodeError(err) (maps a revert code to its reason), CONTRACTS , CHAIN . Importing directly from btcw.tech works from any domain (the file is served with CORS); for a fixed build, copy the file and pin the version ( VERSION ) — see SDK . Tested on a fork of the live chain: 7 order types (CLP single hop, token→token two hops, forced OracleAMM both directions, pay to another wallet) — amounts received matched the quote to the wei ; a stale transaction sent after the price moved was correctly blocked with SlippageExceeded . Deep link Wallets with a dApp browser can open the Swap page directly with the pair and amount prefilled: https://btcw.tech/swap/?from=BTCw&to=USDC&amount=1 # from / to: symbol or token address; amount: human-readable number (not base units) The page detects the wallet via EIP-6963 or window.ethereum . Full API parameter reference: REST API ; SDK: JavaScript SDK ."},{"url":"/guides/bridge/","title":"Bridge funds","group":"Guides","heads":[{"id":"pre-send-checks","t":"Pre-send checks"},{"id":"steps","t":"Steps"},{"id":"withdraw-482120-arbitrum","t":"Withdraw: 482120 → Arbitrum"},{"id":"deposit-arbitrum-482120","t":"Deposit: Arbitrum → 482120"},{"id":"with-ethers-v6","t":"With ethers v6"},{"id":"eth","t":"ETH ⇄ ETH.e (R-66)"},{"id":"warp-route-config-hyperlane-registry-format","t":"Warp route config (Hyperlane registry format)"}],"text":"Deposit USDC / USD₮0 from Arbitrum as USDw on 482120, and withdraw back. End users should use the UI at btcw.tech/swap/#bridge . This page is for bots, wallets and apps that call the contracts directly. How it works: Bridge . Pre-send checks paused() on the source router must be false (otherwise: revert Paused() ). allowlistEnabled() : if true , isAllowed(wallet) must also be true (otherwise: NotAllowed(address) ). Currently disabled. Destination liquidity : the destination router must hold enough tokens. Withdrawing to Arbitrum: the USDC/USD₮0 balance of that route's Arbitrum router. Depositing to 482120: the USDC (Bitcoin Swap) balance of the 482120 router. If it is short, the message arrives but cannot be delivered. From 482120: the amount must be divisible by granularity() = 10 12 . # destination liquidity when withdrawing USD₮0 to Arbitrum cast call 0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9 \"balanceOf(address)(uint256)\" 0x984fDC24D1A2Be538C7290487d0fc212635D98A5 --rpc-url https://arb1.arbitrum.io/rpc # destination liquidity when depositing USD₮0 to 482120 cast call 0x3b5BD179CA6Aab4DAF0f842829776843ABe6e727 \"balanceOf(address)(uint256)\" 0xD6d8452FdCC26B155BEc4fc878635c05CaC95FB1 --rpc-url https://rpc.btcw.tech Steps approve(router, amount) on the source-chain token — the exact amount. transferRemote(uint32 destination, bytes32 recipient, uint256 amount) on the source-chain router, msg.value = 0 . destination : 482120 to deposit, 42161 to withdraw. recipient : destination wallet address left-padded with zeros to 32 bytes (Hyperlane standard). Wait 10–30 seconds and watch for ReceivedTransferRemote on the destination router. Pad on the left : cast abi-encode \"f(address)\" 0xABC… produces the right format. Do not use cast to-bytes32 — it pads on the right, and the funds go to an address nobody holds the key for. Withdraw: 482120 → Arbitrum # withdraw 1 USDC (Bitcoin Swap) as USD₮0 to wallet 0xABC… on Arbitrum RECIPIENT=$(cast abi-encode \"f(address)\" 0xABC...) cast send 0x3b5BD179CA6Aab4DAF0f842829776843ABe6e727 \"approve(address,uint256)\" \\ 0xD6d8452FdCC26B155BEc4fc878635c05CaC95FB1 1000000000000000000 --rpc-url https://rpc.btcw.tech --private-key $PK cast send 0xD6d8452FdCC26B155BEc4fc878635c05CaC95FB1 \"transferRemote(uint32,bytes32,uint256)\" \\ 42161 $RECIPIENT 1000000000000000000 --rpc-url https://rpc.btcw.tech --private-key $PK 1 USDC (Bitcoin Swap) (18 decimals) → 1 USD₮0 (6 decimals) received on Arbitrum. Deposit: Arbitrum → 482120 # deposit 5 USDC (6 decimals) → 5 USDC (Bitcoin Swap) to wallet 0xABC… on 482120 RECIPIENT=$(cast abi-encode \"f(address)\" 0xABC...) cast send 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 \"approve(address,uint256)\" \\ 0x10B5757aC9a40E3467846e35749ae30b00ef0182 5000000 --rpc-url https://arb1.arbitrum.io/rpc --private-key $PK cast send 0x10B5757aC9a40E3467846e35749ae30b00ef0182 \"transferRemote(uint32,bytes32,uint256)\" \\ 482120 $RECIPIENT 5000000 --rpc-url https://arb1.arbitrum.io/rpc --private-key $PK The receiving wallet needs a little BTCw to do anything further on 482120 — the bridge only moves USDC (Bitcoin Swap). With ethers v6 import { Contract, AbiCoder, parseUnits } from \"ethers\"; const router = new Contract(\"0x10B5757aC9a40E3467846e35749ae30b00ef0182\", [ \"function transferRemote(uint32,bytes32,uint256) payable returns (bytes32)\", \"function paused() view returns (bool)\", ], signer); const usdc = new Contract(\"0xaf88d065e77c8cC2239327C5EDb3A432268e5831\", [\"function approve(address,uint256) returns (bool)\"], signer); const amount = parseUnits(\"5\", 6); const recipient = AbiCoder.defaultAbiCoder().encode([\"address\"], [await signer.getAddress()]); // left-padded to 32 bytes if (await router.paused()) throw new Error(\"bridge is paused\"); await (await usdc.approve(router.target, amount)).wait(); const tx = await router.transferRemote(482120, recipient, amount, { value: 0 }); const receipt = await tx.wait(); // watch ReceivedTransferRemote on the 482120 router to know the funds arrived ETH ⇄ ETH.e (R-66) A sealed route on the dedicated core: native ETH locked in the Arbitrum vault 0x0a3fD8b35593fB4f82Da4C110C356745Dd7CDce2 ⇄ ETH.e minted on 482120 0x72a1Ee092807B58682592543Eba7b49004e30579 . 18 decimals on both sides, no granularity, no approval for the deposit. Deposit : transferRemote(482120, recipient, amount) on the vault with msg.value = amount exactly — extra value is not bridged. Never send ETH to the vault with a plain transfer: it mints nothing and cannot be recovered. Withdraw : transferRemote(42161, recipient, amount) on the ETH.e contract itself, msg.value = 0 , no approval (the ETH.e is burned). Withdraw to a wallet: an Arbitrum contract that refuses ETH cannot receive it, and the ETH stays in the vault. # deposit 0.01 ETH -> 0.01 ETH.e to wallet 0xABC… on 482120 RECIPIENT=$(cast abi-encode \"f(address)\" 0xABC...) cast send 0x0a3fD8b35593fB4f82Da4C110C356745Dd7CDce2 \"transferRemote(uint32,bytes32,uint256)\" \\ 482120 $RECIPIENT 10000000000000000 --value 10000000000000000 --rpc-url https://arb1.arbitrum.io/rpc --private-key $PK # withdraw 0.01 ETH.e -> 0.01 ETH to wallet 0xABC… on Arbitrum cast send 0x72a1Ee092807B58682592543Eba7b49004e30579 \"transferRemote(uint32,bytes32,uint256)\" \\ 42161 $RECIPIENT 10000000000000000 --rpc-url https://rpc.btcw.tech --private-key $PK // ethers v6 — deposit const vault = new Contract(\"0x0a3fD8b35593fB4f82Da4C110C356745Dd7CDce2\", [ \"function transferRemote(uint32,bytes32,uint256) payable returns (bytes32)\", \"function paused() view returns (bool)\", ], signer); const amount = parseEther(\"0.01\"); const recipient = AbiCoder.defaultAbiCoder().encode([\"address\"], [await signer.getAddress()]); if (await vault.paused()) throw new Error(\"ETH route is paused\"); await (await vault.transferRemote(482120, recipient, amount, { value: amount })).wait(); // then swap on arrival: /api/v2/swap/quote?from=0x72a1Ee092807B58682592543Eba7b49004e30579&to=native (or USDC) — route amm-ethe / router Warp route config (Hyperlane registry format) "},{"url":"/guides/sandbox/","title":"Test on a chain fork","group":"Guides","heads":[{"id":"run","t":"Run"},{"id":"try-a-swap","t":"Try a swap"},{"id":"using-the-sdk-and-quote-api-with-a-fork","t":"Using the SDK and quote API with a fork"},{"id":"impersonate-any-wallet","t":"Impersonate any wallet"},{"id":"notes","t":"Notes"}],"text":"Run a copy of the live chain locally with anvil and test integrations without real funds. There is no separate testnet (a small gas faucet exists for wallets that hold tokens but no BTCw). The safe way to experiment is to run a fork of the live chain on your own machine with anvil (Foundry): same contracts, same pools, same balances as mainnet at the block you choose — but every transaction stays on your machine. Run anvil --fork-url https://rpc.btcw.tech anvil serves RPC at http://127.0.0.1:8545 , keeps chain ID 482120 , and creates 10 test wallets, 10,000 BTCw each (private keys are printed to the console — local use only, never use them on mainnet). Pin the block so every run is identical: anvil --fork-url https://rpc.btcw.tech --fork-block-number 124000 Try a swap ME=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 # anvil test wallet #0 RPC=http://127.0.0.1:8545 cast call 0xd953d53414a81eb6AC5a4edE73d13992181aF51E \"quoteSellBtcw(uint256)(uint256)\" 1000000000000000 --rpc-url $RPC cast send 0xd953d53414a81eb6AC5a4edE73d13992181aF51E \"sellBtcw(uint256)\" 82000000000000000000 \\ --value 1000000000000000 --from $ME --unlocked --rpc-url $RPC cast call 0x3b5BD179CA6Aab4DAF0f842829776843ABe6e727 \"balanceOf(address)(uint256)\" $ME --rpc-url $RPC These exact commands were run on 30 Sep 2026: sold 0.001 BTCw, received ~83 USDC (Bitcoin Swap). Adjust minUsdOut to the quote you get. Using the SDK and quote API with a fork The SDK accepts an optional RPC, so quotes and prebuilt transactions are read from your fork: import { getQuote } from \"./btcw-swap.js\"; // copy the file locally, see the SDK page const q = await getQuote({ from: \"native\", to: \"0x3b5BD179CA6Aab4DAF0f842829776843ABe6e727\", amount: 10n ** 15n, sender: \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\", rpc: \"http://127.0.0.1:8545\" }); The btcw.tech/api/v2/swap/quote API always reads mainnet — with a fork, use the SDK as above. Impersonate any wallet To test with the token balances of a real wallet (on the fork only): cast rpc anvil_impersonateAccount 0xWalletToImpersonate --rpc-url $RPC cast send … --from 0xWalletToImpersonate --unlocked --rpc-url $RPC Notes anvil reads state from rpc.btcw.tech on demand, so it is subject to the 10 requests/second per IP rate limit. If you hit 429 errors with a large test suite, lower --compute-units-per-second (default 330) so anvil throttles itself, e.g. --compute-units-per-second 150 . The oracle does not update on a fork: 300 seconds after the fork block, OracleAMM reports StalePrice . Restart anvil to fork from the latest block. The bridge does not work on a fork — there is no relayer. You can test approve + transferRemote , but not delivery. Foundry tests: forge test --fork-url https://rpc.btcw.tech runs Solidity tests against live state."},{"url":"/integrate/","title":"Integration checklist","group":"Integrate","heads":[{"id":"wallets","t":"Wallets"},{"id":"exchanges-and-aggregators","t":"Exchanges and aggregators"},{"id":"indexers-and-data-sites","t":"Indexers and data sites"},{"id":"bridges","t":"Bridges"},{"id":"standard-infrastructure","t":"Standard infrastructure"},{"id":"contact","t":"Contact"}],"text":"What wallets, exchanges, aggregators, indexers and data sites need: network, tokens, prices, contracts, events and start blocks. Everything an integrator needs to add Bitcoin Swap, grouped by who you are. Each item links to the page or file with the details; every value here is read from the chain or the public API, so you can check it. Wallets Network : chain ID 482120 ( 0x75b48 ), RPC https://rpc.btcw.tech , WebSocket wss://rpc.btcw.tech/ws , explorer https://explorer.btcw.tech , native coin BTCw with 18 decimals. Ready-made parameters: chain.json (ethereum-lists format) and ADD_CHAIN_PARAMS in the SDK . Steps for users, wallet by wallet: Add to your wallet . Gas : base fee is always 0; eth_gasPrice and eth_maxPriorityFeePerGas both return 1000000 wei. A transfer costs about 0.00000002 BTCw. See Network . Tokens and logos : tokenlist.json (Uniswap Token Lists format, 348 ERC-20s with logoURI , CORS open, regenerated every 6 hours). Native BTCw is not in it — use https://btcw.tech/logo.png . Prices : /api/price (BTCw), /api/v2/market (every asset, PriceHub oracle) — see Read prices . Prices are also readable on-chain in the Chainlink AggregatorV3 format. Swaps in the wallet : /api/v2/swap/quote returns a ready-to-sign transaction for any pair of the 348 assets — Swaps for wallets . Balances in one call : a JSON-RPC batch of balanceOf calls counts as one request; Multicall3 is at 0xA0093EA76633A983364cb2582959870eaffDdea0 . Finality : QBFT finalizes each block when it is produced (5-second blocks) — one confirmation is final. Smart accounts : EntryPoint v0.7, SimpleAccountFactory, a public bundler and a paymaster that pays new wallets' gas — Gasless transactions (ERC-4337) . Exchanges and aggregators Registry : contracts.json — every contract with its address and ABI (CORS open), including the swap venues (ClpPools, UsdClpPools, OracleAMM, OracleTokenAMM, Uniswap V2) and SwapRouter. Quote and route : use the quote API, or call the pools directly — Swap through contracts ; pricing rules in Swap mechanics . Decimals : every price-tracker token, USDC (Bitcoin Swap), WBTCw and stBTCw use 18 decimals; USDC.e uses 6 . Match assets by chain ID + address, never by symbol. Deposits and withdrawals : one confirmation is final; run your own node ( Run a node ) rather than depending on the public RPC limits. Who controls what : read the Trust model before listing an asset — it lists each contract's owner powers. Limits : rate limits and error codes in Limits & errors . Indexers and data sites Contract Address From block Event (topic0) ClpPools (BTCw hub) 0x557aDc3d900c471F3907cdDA3a9F5377d6F9E7e0 92983 Swap(address indexed trader, address indexed token, bool btcwIn, uint256 amountIn, uint256 amountOut, uint256 fee, address to) 0x3d81dab5fd0adae94dd4575fa04ee278503eb7390a0611793e57cfc76a19b97d UsdClpPools (USDC (Bitcoin Swap) hub) 0x78aCB6Ec7aF4cc83BF9E698706de79c08D61C13f 180828 Swap(address indexed trader, address indexed token, bool usdIn, uint256 amountIn, uint256 amountOut, uint256 fee, address to) 0x3d81dab5fd0adae94dd4575fa04ee278503eb7390a0611793e57cfc76a19b97d (same signature types) OracleAMM (BTCw ⇄ USDC (Bitcoin Swap)) 0xd953d53414a81eb6AC5a4edE73d13992181aF51E 91520 Swap(address indexed trader, bool btcwIn, uint256 amountIn, uint256 amountOut, uint256 priceWad) 0x176648f1f11cda284c124490086be42a926ddf0ae887ebe7b1d6b337d8942756 SwapRouter 0x397E607eA05eF7909f84540077F3a716778031E4 — Routed(address indexed sender, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut, address to, uint256 hops) 0x4def0ac4d95c951d0c151c5d1f830a4625c790c4565982a613f25e2bc298fca4 WBTCw / USDC.e (Uniswap V2 pair) 0xED2967B738d98B3e4D3e6780A08Dc161A55EF304 179882 Uniswap V2 Swap , Sync , Mint , Burn PriceHub (oracle) 0xE87FDdCC0b668564a20B23F3bE1EE108C805ecb4 92977 AnswerUpdated(address indexed asset, int256 answer, uint256 roundId, uint256 updatedAt) 0x8c0ec3bb658fc9145f07a529744298f972f32ca3f91c868abefc2e78abbf07a8 A swap that goes through SwapRouter emits one pool Swap per leg plus one Routed ; count the Routed event once if you report trades. User vs keeper : the Treasury keeper wallets are listed in treasury_addresses of /api/v2/stats . /api/v2/market reports user and keeper trades and volume per asset — see REST API . Explorer API : Blockscout /api/v2 and the Etherscan-compatible /api at explorer.btcw.tech (CORS open). Pool and market data : /api/v2/pools , /api/v2/usd-pools , /api/v2/market , /api/v2/history , /api/v2/swaps . Bridges Hyperlane warp routes between Arbitrum One and chain 482120 (Hyperlane domain = chain ID 482120): USDC and USD₮0 ⇄ USDC (Bitcoin Swap) (open to every wallet), and the sealed WBTC ⇄ BTCw and USDC ⇄ USDC.e routes (allowlisted wallets). Addresses, ISM and limits in Bridge ; how a user moves funds in Bridge funds . Locked collateral on Arbitrum can be checked against supply on 482120 at any time on Proof of reserve . Standard infrastructure Permit2, EntryPoint v0.7 and Safe 1.3.0 are at their usual addresses, deployed through the standard CREATE2 deployer — see Addresses and the contracts.canonical section of contracts.json. Contact Integration questions and listing requests: @btcwtechHQ . Security reports: see Security ."},{"url":"/api/","title":"REST API","group":"Reference","heads":[{"id":"conventions","t":"Conventions"},{"id":"prices","t":"Prices"},{"id":"swap","t":"Swap"},{"id":"stats","t":"Stats"},{"id":"market","t":"Market"},{"id":"health","t":"Health"},{"id":"static-files","t":"Static files"}],"text":"Every public endpoint: parameters, response fields, caching and examples. Conventions Base URL https://btcw.tech — the same API is served at https://app.btcw.tech Authentication no API key required Format JSON, UTF-8; GET only. CORS open ( Access-Control-Allow-Origin: * ) — callable directly from the browser Token amounts in the quote API ( /api/v2/swap/* ): integer strings, base units (18 decimals) — never parse them as floats. In the stats endpoints: floats, human units (BTCw, USD) Time /api/* and the ts , t , expiresAt fields: Unix seconds. The updated field of /api/v2/* : Unix milliseconds Caching per the cache-control header listed for each endpoint; polling faster than that returns no new data Rate limit 20 requests/second per IP, shared across /api/* , /api/v2/* and the explorer API — see Limits & error codes Prices all USD prices come from on-chain oracles (BtcwPriceFeed, PriceHub) Prices GET /api/price max-age=5 BTCw price and OracleAMM status. No parameters. Field Type Description price_usd number oracle BTC/USD price × peg ratio bid_usd / ask_usd number actual OracleAMM buy / sell price for BTCw (spread included) spread_pct number spread per side, % (0.3) updated_at , age_seconds , max_age_seconds number when the price was written, price age, staleness threshold (300) stale , paused , tradable bool price is stale; OracleAMM is paused; orders can be filled (not stale, not paused, liquidity available) liquidity object btcw , usdw held in OracleAMM; max_trade_btcw oracle object round , answer_btc_usd , decimals , address , sources contracts object amm , usdw , feed addresses usdw_total_supply , block number USDC (Bitcoin Swap) total supply; block at read time curl -s https://btcw.tech/api/price GET /api/tokens max-age=5 BTCw and USDC (Bitcoin Swap) in a compact wallet format: symbol , name , address ( null for native BTCw), native , decimals , price_usd , logo . The 345 price-tracker tokens are at /api/v2/swap/assets . GET /api/v2/pools max-age=5 The 346 ClpPools pools (BTCw hub). Returns { updated, pools: [...] } . Field Description address , symbol , name , logo the pool's token (logo is a path relative to btcw.tech) class crypto · stock (US equities) · stable (USDC on Bitcoin Swap) oracleUsd / poolUsd / devBps oracle price, pool price, deviation (bps, positive = pool is more expensive) depthBtcw / depthAsset pool depth on each side tvlUsd , vol24hUsd , fees24hUsd , swaps24h , feeTvlPct24h stats, valued at the oracle price at indexing time; includes Treasury trades priceAgeS age of the token's oracle price, seconds totalSupply , mcapUsd token supply on this chain and supply × oracle price; null when unreadable holders addresses holding the token, from the explorer, refreshed every 10 minutes; null until the first read win.{m5,m15,h1,h4,h24} trades per window: swaps , buys , sells , volUsd , volBuyUsd , volSellUsd (since 7 Oct 2026), wallets ; includes Treasury trades hub describes native BTCw: win (same windows, every trade on the BTCw-hub pools and OracleAMM), holders , totalSupply (21,000,000, fixed in genesis), circulating (total minus the balances of protocol contracts, Owner and operator wallets — the method is in circulatingMethod ), mcapUsd = circulating × price, fdvUsd = total × price, and reference : 24h volume, high and low of BTCUSDT on Binance ( null when older than 300 s). Swap GET /api/v2/swap/assets max-age=30 The 348 swappable assets: { chainId, updated, assets: [{ address, native, symbol, name, decimals, logoURI, priceUsd, poolDepthBtcw }] } . Native BTCw has address = 0xEeee…EEeE and native: true . GET /api/v2/swap/quote no-store Quote + prebuilt transaction. Full guide and example response: Wallet swap integration . Parameter Description from , to required token address or native amount required integer, base units sender when set, returns tx , approval and simulates the transaction recipient receiver; if different from sender , only the ClpPools route remains slippage_bps 100 1–5000 → minAmountOut route best best · clp · amm (BTCw ⇄ USDC (Bitcoin Swap)) · amm-eth (ETHw ⇄ USDC (Bitcoin Swap)) · amm-ethe (ETH.e ⇄ USDC (Bitcoin Swap), R-66) · router (multi-hop through SwapRouter in one transaction) · usdclp (UsdClpPools: USDC (Bitcoin Swap) ⇄ token in one hop, token ⇄ token through USDC (Bitcoin Swap)) · v2 / v3 (Uniswap V2 / V3 pools between two ERC-20 tokens, e.g. WBTCw ⇄ USDC.e, swapped through SwapRouter02; best takes the best V3 fee tier and reports it in feeTier ). Amounts are in the token's own base units — USDC.e has 6 decimals Status codes: 200 quote returned · 400 invalid input ( { error } ) · 422 no route can fill the order ( routes[].error still included) · 502 RPC read error. Stats GET /api/v2/stats max-age=5 Chain-wide figures used by the Dashboard: block , validators , btcw_usd , tvl_usd (split into tvl_clp_usd / tvl_oracleamm_usd ), volume_24h , swaps_24h , fees_24h_usd , total_swaps , wallets , oracle_assets_fresh (e.g. \"100/100\" ), network , status (per-component health), treasury_addresses . Volume includes of_which_treasury… fields — the share traded by the Treasury wallets ( treasury_addresses ) to keep pool prices close to the oracle. GET /api/v2/history?hours=48 max-age=5 Hourly series, hours up to 720. Each entry: t (start of hour), volClp , volAmm , volTreasury , swaps , swapsTreasury , fees (USD). GET /api/v2/swaps?limit=50 max-age=5 Latest swaps ( limit up to 300) and the 10 largest swaps in 24 hours: { latest, top24h } . Each swap: venue , from , to , amountIn , amountOut , usd , fee , trader , treasury (bool), block , tx , ts . GET /api/v2/usd-pools max-age=5 The 345 UsdClpPools pools (USDC (Bitcoin Swap) hub, R-61). Same fields as /api/v2/pools , with depthUsd in place of depthBtcw , plus hub ( \"USDw\" ) and contract (the UsdClpPools address). A token has one row here and one in /api/v2/pools : tell them apart by contract , not by token address. GET /api/v2/usd-swaps?limit=50 max-age=5 Swaps on UsdClpPools, in the same shape as /api"},{"url":"/json-rpc/","title":"JSON-RPC","group":"Reference","heads":[{"id":"endpoints","t":"Endpoints"},{"id":"enabled-namespaces","t":"Enabled namespaces"},{"id":"batching","t":"Batching"},{"id":"subscriptions","t":"Subscriptions"},{"id":"reading-logs","t":"Reading logs"},{"id":"fees-and-transactions","t":"Fees and transactions"},{"id":"limits","t":"Limits"}],"text":"What the public RPC supports, what it does not, and its technical limits. Endpoints HTTPS https://rpc.btcw.tech — POST to the root path / only; GET returns 405. CORS open. WebSocket wss://rpc.btcw.tech/ws — idle connections are kept open for up to 1 hour Client Hyperledger Besu 26.2.0 ( web3_clientVersion ) Enabled namespaces Only eth_* , net_* , web3_* . Other namespaces return -32604 Method not enabled ( debug_* , trace_* , admin_* …) or -32601 Method not found ( txpool_* ). To trace transactions, use the explorer or run a chain fork with anvil (which has debug_traceTransaction ) — see Testing on a chain fork . Batching Send an array of requests in a single HTTP POST. A batch counts as one request against the rate limit — the cheapest way to read many things. A batch of 101 requests has been tested and returned all 101 results. Request body limit: 256 KB ; requests running longer than 30 seconds are cut off. curl -s https://rpc.btcw.tech -H 'content-type: application/json' -d '[ {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_blockNumber\",\"params\":[]}, {\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"eth_call\",\"params\":[{\"to\":\"0xd953d53414a81eb6AC5a4edE73d13992181aF51E\",\"data\":\"0x5c975abb\"},\"latest\"]} ]' Results may come back out of order — match them by id . Subscriptions // wss://rpc.btcw.tech/ws {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_subscribe\",\"params\":[\"newHeads\"]} {\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"eth_subscribe\",\"params\":[\"logs\",{\"address\":\"0x557aDc3d900c471F3907cdDA3a9F5377d6F9E7e0\"}]} A new block every 5 seconds. Connections may close when the server restarts — reconnect automatically and backfill with eth_getLogs from the last block you processed. Reading logs eth_getLogs has no block-range cap, but the chain is log-heavy (the price-keeping bot runs continuously — about 18,000 logs per 1,000 blocks). Use small ranges (1,000–5,000 blocks) and filter by address + topics so responses stay under 30 seconds. Fees and transactions eth_gasPrice = 0xf4240 (1,000,000 wei) — the minimum the node accepts. eth_maxPriorityFeePerGas = 0; baseFeePerGas = 0. EIP-1559 transactions must set both maxFeePerGas and maxPriorityFeePerGas ≥ 1,000,000 — the base fee is zero, so the effective price is the priority fee. eth_feeHistory works normally. QBFT has instant finality: a receipt in a block is final, no extra confirmations needed. Limits 10 requests/second per IP , with bursts up to 40 (HTTPS) or 20 (WebSocket). Beyond that, HTTPS returns 429 (with CORS headers so browsers can read the error) and WebSocket refuses new connections with 503. Details: Limits & error codes . Need more? Batch requests, cache results on your side, or subscribe over WebSocket instead of polling."},{"url":"/errors/","title":"Limits & errors","group":"Reference","heads":[{"id":"rate-limits","t":"Rate limits"},{"id":"api-http-status-codes","t":"API HTTP status codes"},{"id":"json-rpc-errors","t":"JSON-RPC errors"},{"id":"contract-revert-codes","t":"Contract revert codes"}],"text":"Rate limits, HTTP codes, JSON-RPC errors and contract revert codes. Rate limits Counted per IP using a leaky-bucket algorithm: an average rate plus an allowed instant burst. Endpoint Rate Burst When exceeded rpc.btcw.tech (HTTPS) 10/second 40 HTTP 429 rpc.btcw.tech/ws (opening a connection) shares the 10/second above 20 HTTP 503 btcw.tech/api/v2/* 20/second 40 HTTP 429 btcw.tech/api/* shares the 20/second above 20 HTTP 503 explorer.btcw.tech/api/* shares the 20/second above 100 HTTP 429 Pages and static files unlimited — — HTTPS RPC and WebSocket share one quota; the three APIs on btcw.tech and the explorer share another. A JSON-RPC batch counts as one request. On 429/503: wait and retry with exponential backoff (e.g. 0.5 s → 1 s → 2 s). Batch many eth_call s together instead of sending them one by one. API HTTP status codes Code When 200 success 400 invalid parameters ( /api/v2/swap/quote ): missing parameter, amount not an integer, unknown asset… — body contains { \"error\": \"…\" } 404 path not found — /api/* and /api/v2/* list the available paths in the routes field 405 RPC received a GET — use POST only 422 quote: no route can fill the order (exceeds liquidity, pool paused, stale price…) — see routes[].error 429 / 503 rate limit exceeded (table above). /api/v2/* also returns 503 while the indexer is starting 502 the API could not read from RPC — retry later JSON-RPC errors Code Meaning -32604 Method not enabled — namespace not exposed ( debug_ , trace_ , admin_ …) -32601 Method not found 3 Execution reverted — eth_call / gas estimation reverted; the error code is in error.data (e.g. \"0x1f2a2005\" ), decode it with the table below -32004 Upfront cost exceeds account balance — the wallet doesn't have enough BTCw for value + gas -32602 Invalid call params — malformed parameters Contract revert codes The first 4 bytes of error.data . The SDK's decodeError() translates these codes into readable reasons. Selector Error Where · what to do 0x71c4efed SlippageExceeded(uint256,uint256) ClpPools, OracleAMM — price moved past minOut ; request a new quote 0xab35696f ContractPaused() ClpPools, OracleAMM — the venue is paused 0xf82ae9a5 PoolDisabled(address) ClpPools — this pool is disabled 0x01221262 HubToken() UsdClpPools — USDC (Bitcoin Swap) is the hub, not a pool token; swap it with swapUsdForAsset / swapAssetForUsd 0xb5e2025e UnknownPool(address) ClpPools — token has no pool 0x305da342 ExceedsMaxTrade(uint256,uint256) OracleAMM — over 10 BTCw per trade; split the order or use ClpPools 0xa17e11d5 InsufficientLiquidity(uint256,uint256) OracleAMM — not enough liquidity for this order size 0x6fb3b185 StalePrice(uint256) OracleAMM — oracle price older than 300 seconds; wait for the next price update 0x1f8f95a0 InvalidOraclePrice() OracleAMM — oracle returned an invalid price 0x1f2a2005 ZeroAmount() amount too small, result rounds to 0 0x201b580a SameToken() ClpPools — input and output are the same token 0xd92e233d ZeroAddress() recipient is the zero address 0xf4b3b1bc NativeTransferFailed() recipient cannot receive BTCw (contract without a receive function) 0xe450d38c ERC20InsufficientBalance token — insufficient balance 0xfb8f41b2 ERC20InsufficientAllowance token — not enough approve d for the swap contract 0xf80dbaea Expired(uint256) SwapRouter — past deadline ; request a new quote 0x20db8267 InvalidPath() SwapRouter — path is empty or longer than 4 hops 0x8e612d4b UnknownVenue(uint8) SwapRouter — venue does not exist (0 ClpPools, 1 OracleAMM, 2 + token vault index) 0x2cd1bb3d UnsupportedHop(uint8,address,address) SwapRouter — that venue does not have this pair 0x626ade30 ValueMismatch(uint256,uint256) SwapRouter — msg.value differs from amountIn when paying in BTCw 0x9c8d2cd2 InvalidRecipient() SwapRouter — invalid recipient 0xf2fb3812 UnexpectedSender() SwapRouter — BTCw sent directly to the router (not via swap ) 0x9e87fac8 Paused() bridge router — paused 0xfa5cd00f NotAllowed(address) bridge router — allowlist enabled and the wallet is not on it 0x7c98bbbc BadGranularity(uint256,uint256) 482120 router — amount not divisible by 10 12 0xf97da669 PriceJumpTooLarge(int256,int256) BtcwPriceFeed — price update changed by more than 10% (only if you are the updater) 0x9a280f39 NotUpdater() BtcwPriceFeed, PriceHub — caller is not an authorized price updater"},{"url":"/contracts/","title":"Contract reference","group":"Reference","heads":[{"id":"usdw","t":"USDC (Bitcoin Swap)"},{"id":"usdw-functions","t":"USDC (Bitcoin Swap) — functions"},{"id":"usdw-events","t":"USDC (Bitcoin Swap) — events"},{"id":"oracleamm","t":"OracleAMM"},{"id":"oracleamm-functions","t":"OracleAMM — functions"},{"id":"oracleamm-events","t":"OracleAMM — events"},{"id":"oracletokenamm-ethw","t":"OracleTokenAMM_ETHw"},{"id":"oracletokenamm-ethw-functions","t":"OracleTokenAMM_ETHw — functions"},{"id":"oracletokenamm-ethw-events","t":"OracleTokenAMM_ETHw — events"},{"id":"oracletokenamm-ethw-errors","t":"OracleTokenAMM_ETHw — errors"},{"id":"swaprouter","t":"SwapRouter"},{"id":"swaprouter-functions","t":"SwapRouter — functions"},{"id":"swaprouter-events","t":"SwapRouter — events"},{"id":"swaprouter-errors","t":"SwapRouter — errors"},{"id":"clppools","t":"ClpPools"},{"id":"clppools-functions","t":"ClpPools — functions"},{"id":"clppools-events","t":"ClpPools — events"},{"id":"usdclppools","t":"UsdClpPools"},{"id":"usdclppools-functions","t":"UsdClpPools — functions"},{"id":"usdclppools-events","t":"UsdClpPools — events"},{"id":"usdrebalancer","t":"UsdRebalancer"},{"id":"usdrebalancer-functions","t":"UsdRebalancer — functions"},{"id":"usdrebalancer-events","t":"UsdRebalancer — events"},{"id":"btcwpricefeed","t":"BtcwPriceFeed"},{"id":"btcwpricefeed-functions","t":"BtcwPriceFeed — functions"},{"id":"pricehub","t":"PriceHub"},{"id":"pricehub-functions","t":"PriceHub — functions"},{"id":"wbtcw","t":"WBTCw"},{"id":"wbtcw-functions","t":"WBTCw — functions"},{"id":"wbtcw-events","t":"WBTCw — events"},{"id":"wbtcw-errors","t":"WBTCw — errors"},{"id":"usdce","t":"USDCe"},{"id":"usdce-functions","t":"USDCe — functions"},{"id":"usdce-events","t":"USDCe — events"},{"id":"usdce-errors","t":"USDCe — errors"},{"id":"uniswapv2factory","t":"UniswapV2Factory"},{"id":"uniswapv2factory-functions","t":"UniswapV2Factory — functions"},{"id":"uniswapv2factory-events","t":"UniswapV2Factory — events"},{"id":"uniswapv2router02","t":"UniswapV2Router02"},{"id":"uniswapv2router02-functions","t":"UniswapV2Router02 — functions"},{"id":"uniswapv2pair-wbtcw-usdce","t":"UniswapV2Pair_WBTCw_USDCe"},{"id":"uniswapv2pair-wbtcw-usdce-functions","t":"UniswapV2Pair_WBTCw_USDCe — functions"},{"id":"uniswapv2pair-wbtcw-usdce-events","t":"UniswapV2Pair_WBTCw_USDCe — events"},{"id":"simpleearn","t":"SimpleEarn"},{"id":"simpleearn-functions","t":"SimpleEarn — functions"},{"id":"simpleearn-events","t":"SimpleEarn — events"},{"id":"simpleearn-errors","t":"SimpleEarn — errors"},{"id":"fixedearn","t":"FixedEarn"},{"id":"fixedearn-functions","t":"FixedEarn — functions"},{"id":"fixedearn-events","t":"FixedEarn — events"},{"id":"fixedearn-errors","t":"FixedEarn — errors"},{"id":"stakedbtcw","t":"StakedBTCw"},{"id":"stakedbtcw-functions","t":"StakedBTCw — functions"},{"id":"stakedbtcw-events","t":"StakedBTCw — events"},{"id":"stakedbtcw-errors","t":"StakedBTCw — errors"},{"id":"earnpricesource","t":"EarnPriceSource"},{"id":"earnpricesource-functions","t":"EarnPriceSource — functions"},{"id":"earnpricesource-errors","t":"EarnPriceSource — errors"},{"id":"tokenfactory","t":"TokenFactory"},{"id":"tokenfactory-functions","t":"TokenFactory — functions"},{"id":"tokenfactory-events","t":"TokenFactory — events"},{"id":"oraclerebalancer","t":"OracleRebalancer"},{"id":"oraclerebalancer-functions","t":"OracleRebalancer — functions"},{"id":"oraclerebalancer-events","t":"OracleRebalancer — events"},{"id":"multicall3","t":"Multicall3"},{"id":"multicall3-functions","t":"Multicall3 — functions"},{"id":"stakedtokenfactory","t":"StakedTokenFactory"},{"id":"stakedtokenfactory-functions","t":"StakedTokenFactory — functions"},{"id":"stakedtokenfactory-events","t":"StakedTokenFactory — events"},{"id":"stakedtokenfactory-errors","t":"StakedTokenFactory — errors"},{"id":"uniswapv3factory","t":"UniswapV3Factory"},{"id":"uniswapv3factory-functions","t":"UniswapV3Factory — functions"},{"id":"uniswapv3factory-events","t":"UniswapV3Factory — events"},{"id":"uniswapv3-nonfungiblepositionmanager","t":"UniswapV3_NonfungiblePositionManager"},{"id":"uniswapv3-nonfungiblepositionmanager-functions","t":"UniswapV3_NonfungiblePositionManager — functions"},{"id":"uniswapv3-nonfungiblepositionmanager-events","t":"UniswapV3_NonfungiblePositionManager — events"},{"id":"uniswapv3-swaprouter02","t":"UniswapV3_SwapRouter02"},{"id":"uniswapv3-swaprouter02-functions","t":"UniswapV3_SwapRouter02 — functions"},{"id":"uniswapv3-quoterv2","t":"UniswapV3_QuoterV2"},{"id":"uniswapv3-quoterv2-functions","t":"UniswapV3_QuoterV2 — functions"},{"id":"uniswapv3-ticklens","t":"UniswapV3_TickLens"},{"id":"uniswapv3-ticklens-functions","t":"UniswapV3_TickLens — functions"},{"id":"uniswapv3-nonfungibletokenpositiondescriptor","t":"UniswapV3_NonfungibleTokenPositionDescriptor"},{"id":"uniswapv3-nonfungibletokenpositiondescriptor-fun","t":"UniswapV3_NonfungibleTokenPositionDescriptor — functions"},{"id":"uniswapv3pool-wbtcw-usdce","t":"UniswapV3Pool_WBTCw_USDCe"},{"id":"uniswapv3pool-wbtcw-usdce-functions","t":"UniswapV3Pool_WBTCw_USDCe — functions"},{"id":"uniswapv3pool-wbtcw-usdce-events","t":"UniswapV3Pool_WBTCw_USDCe — events"},{"id":"ethe","t":"ETHe"},{"id":"ethe-functions","t":"ETHe — functions"},{"id":"ethe-events","t":"ETHe — events"},{"id":"ethe-errors","t":"ETHe — errors"},{"id":"oracletokenamm-ethe","t":"OracleTokenAMM_ETHe"},{"id":"oracletokenamm-ethe-functions","t":"OracleTokenAMM_ETHe — functions"},{"id":"oracletokenamm-ethe-events","t":"OracleTokenAMM_ETHe — events"},{"id":"oracletokenamm-ethe-errors","t":"OracleTokenAMM_ETHe — errors"},{"id":"pricealias-ethe","t":"PriceAlias_ETHe"},{"id":"pricealias-ethe-functions","t":"PriceAlias_ETHe — functions"},{"id":"pricealias-ethe-errors","t":"PriceAlias_ETHe — errors"},{"id":"swaprouter2","t":"SwapRouter2"},{"id":"swaprouter2-functions","t":"SwapRouter2 — functions"},{"id":"swaprouter2-events","t":"SwapRouter2 — events"},{"id":"swaprouter2-errors","t":"SwapRouter2 — errors"},{"id":"stablereserve","t":"StableReserve"},{"id":"stablereserve-functions","t":"StableReserve — functions"},{"id":"stablereserve-events","t":"StableReserve — events"},{"id":"verifyingpaymaster","t":"VerifyingPaymaster"},{"id":"verifyingpaymaster-functions","t":"VerifyingPaymaster — functions"},{"id":"bridge-router-guardedcollateralrouter","t":"Bridge router (GuardedCollateralRouter)"},{"id":"bridge-router-guardedcollateralrouter-functions","t":"Bridge router (GuardedCollateralRouter) — functions"},{"id":"bridge-router-guardedcollateralrouter-events","t":"Bridge router (GuardedCollateralRouter) — events"},{"id":"bridge-router-guardedcollateralrouter-errors","t":"Bridge router (GuardedCollateralRouter) — errors"}],"text":"Functions, events and errors of the public contracts — generated from contracts.json. This page is generated automatically from /developers/contracts.json — it covers only the public interface integrators need. Full source code (including the Owner's admin functions) is verified on the explorer ; admin permissions are summarized in Trust model . Revert codes: Limits & error codes . Compiler: Solidity 0.8.28, optimizer 200 runs (482120-side contracts). Bridge routers: @hyperlane-xyz/core 12.1.0. USDC (Bitcoin Swap) Address 0x3b5BD179CA6Aab4DAF0f842829776843ABe6e727 · chain 482120 · 18 decimals USDC (Bitcoin Swap): name() and symbol() return \"USDC\" since 6 Oct 2026 (formerly USDw; same address, decimals and balances). Redeems 1:1 for USDC.e at StableReserve. USDC (Bitcoin Swap) — functions function name() view returns (string) function symbol() view returns (string) function decimals() view returns (uint8) function totalSupply() view returns (uint256) function balanceOf(address) view returns (uint256) function allowance(address,address) view returns (uint256) function approve(address spender, uint256 amount) returns (bool) function transfer(address to, uint256 amount) returns (bool) USDC (Bitcoin Swap) — events event Transfer(address indexed from, address indexed to, uint256 value) OracleAMM Address 0xd953d53414a81eb6AC5a4edE73d13992181aF51E · chain 482120 BTCw <-> USDC (Bitcoin Swap) at the oracle price +/- spreadBps (30 = 0.3%). maxTradeBtcw per order; stops when the oracle is older than maxAgeSec. OracleAMM — functions function quoteSellBtcw(uint256 btcwIn) view returns (uint256 usdOut) function quoteBuyBtcw(uint256 usdIn) view returns (uint256 btcwOut) function sellBtcw(uint256 minUsdOut) payable returns (uint256 usdOut) function buyBtcw(uint256 usdIn, uint256 minBtcwOut) returns (uint256 btcwOut) function midPrice() view returns (uint256 priceWad, uint256 updatedAt) function spreadBps() view returns (uint256) function maxTradeBtcw() view returns (uint256) function btcwReserve() view returns (uint256) function usdReserve() view returns (uint256) function paused() view returns (bool) OracleAMM — events event Swap(address indexed trader, bool btcwIn, uint256 amountIn, uint256 amountOut, uint256 priceWad) OracleTokenAMM_ETHw Address 0xFd6d78A3b60175D37146793396A2FA7864039D54 · chain 482120 ETHw <-> USDC (Bitcoin Swap) at the PriceHub price of ETHw +/- spreadBps (30 = 0.3%). maxTradeToken 300 ETHw per order; stops when the price is older than maxAgeSec (300). buyToken/sellToken can pay another recipient. Bridge destination for ETHw (deposit USDC/USD₮0 -> USDC (Bitcoin Swap) -> ETHw). OracleTokenAMM_ETHw — functions function quoteBuyToken(uint256 usdIn) view returns (uint256 tokenOut) function quoteSellToken(uint256 tokenIn) view returns (uint256 usdOut) function buyToken(uint256 usdIn, uint256 minTokenOut, address to) returns (uint256 tokenOut) function sellToken(uint256 tokenIn, uint256 minUsdOut, address to) returns (uint256 usdOut) function midPrice() view returns (uint256 priceWad, uint256 updatedAt) function token() view returns (address) function usd() view returns (address) function hub() view returns (address) function tokenReserve() view returns (uint256) function usdReserve() view returns (uint256) function spreadBps() view returns (uint256) function maxAgeSec() view returns (uint256) function maxTradeToken() view returns (uint256) function paused() view returns (bool) OracleTokenAMM_ETHw — events event Swap(address indexed trader, address indexed to, bool tokenIn, uint256 amountIn, uint256 amountOut, uint256 priceWad) OracleTokenAMM_ETHw — errors error ContractPaused() error ZeroAmount() error ZeroAddress() error StalePrice(uint256 updatedAt) error InvalidOraclePrice() error ExceedsMaxTrade(uint256 cap, uint256 amount) error InsufficientLiquidity(uint256 available, uint256 required) error SlippageExceeded(uint256 amountOut, uint256 minAmountOut) SwapRouter Address 0x397E607eA05eF7909f84540077F3a716778031E4 · chain 482120 Ownerless router: chains up to MAX_HOPS (4) hops across venue 0 ClpPools, venue 1 OracleAMM (BTCw <-> USDC (Bitcoin Swap)), venue 2 token AMMs (ETHw kho) in one transaction. BTCw in: send msg.value = amountIn; token in: approve the router (it only pulls from msg.sender). quote() does not check caps, reserves or pause. SwapRouter — functions function swap(address tokenIn, uint256 amountIn, (uint8 venue, address tokenOut)[] hops, uint256 minOut, address to, uint256 deadline) payable returns (uint256 amountOut) function quote(address tokenIn, uint256 amountIn, (uint8 venue, address tokenOut)[] hops) view returns (uint256 amountOut) function tokenAmmCount() view returns (uint256) function tokenAmmAt(uint256 index) view returns (address amm, address token) function clp() view returns (address) function oracleAmm() view returns (address) function usdw() view returns (address) function NATIVE() view returns (address) function MAX_HOPS() view returns (uint256) SwapRouter — events event Routed(address indexed sender, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut, address to, uint256 hops) SwapRouter — errors error Expired(uint256 deadline) error InvalidRecipient() error InvalidPath() error UnknownVenue(uint8 venue) error UnsupportedHop(uint8 venue, address tokenIn, address tokenOut) error ValueMismatch(uint256 sent, uint256 expected) error SlippageExceeded(uint256 amountOut, uint256 minAmountOut) error ZeroAmount() error ZeroAddress() error UnexpectedSender() error NativeTransferFailed() ClpPools Address 0x557aDc3d900c471F3907cdDA3a9F5377d6F9E7e0 · chain 482120 346 continuous-liquidity pools (USDC (Bitcoin Swap), 100 crypto trackers, 202 US stock, 20 US ETF, 2 pre-IPO and 21 metal / index / commodity / FX trackers), every pool paired with native BTCw (THORChain-style CLP). Fee floor minFeeBps (5). ClpPools — functions function swapBtcwForAsset(address token, uint256 minOut, address to) payable returns (uint256) function swapAssetF"},{"url":"/sdk/","title":"JavaScript SDK","group":"Reference","heads":[{"id":"installation","t":"Installation"},{"id":"quick-start","t":"Quick start"},{"id":"functions","t":"Functions"},{"id":"constants","t":"Constants"},{"id":"notes","t":"Notes"}],"text":"btcw-swap.js: a dependency-free ES module shared with the quote API. /swap/sdk/btcw-swap.js — a single-file ES module with no dependencies (only fetch and BigInt ), running in the browser, Node 18+, Deno and Bun. Quotes are read straight from the contracts over RPC. The /api/v2/swap/quote API runs this same file on the server, so both always return the same numbers. Installation There is no npm package. Two options, same file: Option When to use Import directly from btcw.tech fastest — nothing to download. The file is served with CORS ( Access-Control-Allow-Origin: * ), so a page on any domain can import it in the browser; cached for 5 minutes. Always the latest version. Copy the file and pin the version when you need a fixed build: serve the file yourself and decide when to upgrade (check VERSION ). Node and Bun cannot import from an https:// URL — use this option. // Option 1 — import directly (browser: <script type=\"module\">; Deno) import { getQuote } from \"https://btcw.tech/swap/sdk/btcw-swap.js\"; // Option 2 — copy it locally, then import the local file // curl -sO https://btcw.tech/swap/sdk/btcw-swap.js // grep 'export const VERSION' btcw-swap.js # currently \"1.4.0\" import { getQuote } from \"./btcw-swap.js\"; /developers/contracts.json (addresses + ABIs) is also served with CORS — read it directly with fetch(\"https://btcw.tech/developers/contracts.json\") from your page. Quick start import { getQuote, ADD_CHAIN_PARAMS, waitForReceipt } from \"https://btcw.tech/swap/sdk/btcw-swap.js\"; await ethereum.request({ method: \"wallet_addEthereumChain\", params: [ADD_CHAIN_PARAMS] }); const q = await getQuote({ from: \"native\", to: \"0xd8fA8202ecC699687182109084B9ECBb44025759\", amount: 10n ** 18n, sender: me, slippageBps: 100 }); if (q.error) throw new Error(q.error); if (q.approval?.needed) await waitForReceipt(await ethereum.request({ method: \"eth_sendTransaction\", params: [q.approval.tx] })); const hash = await ethereum.request({ method: \"eth_sendTransaction\", params: [q.tx] }); Functions Name Description getQuote(p) quote + build the transaction. p : from , to (address or \"native\" ), amount (base units), sender? , recipient? , slippageBps? (default 100), route? ( \"best\" | \"clp\" | \"amm\" | \"amm-eth\" | \"amm-ethe\" | \"router\" | \"usdclp\" | \"v2\" | \"v3\" ), rpc? . Returns the same structure as the quote API getAssets({ api? }) the list of 323 assets from /api/v2/swap/assets waitForReceipt(hash, { rpc?, timeoutMs? }) waits for the receipt (default up to 120 seconds); status \"0x1\" means success decodeError(e) maps a revert code (hex string or RPC error object) to a readable reason, or null normalizeAsset(a) normalizes an asset id: returns NATIVE or a lowercase address; throws if invalid rpcBatch(calls, rpc?) sends a JSON-RPC batch (counts as one request against the rate limit) Constants Name Value VERSION SDK version CHAIN chainId , chainIdHex , name , rpc , explorer , nativeCurrency CONTRACTS clp , amm , usdw , ethw , ethAmm (ETHw oracle-priced vault), router (SwapRouter), ethe / etheAmm (ETH.e and its market, R-66), router2 (second SwapRouter, used when one side is ETH.e) NATIVE 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE — native BTCw DEFAULT_API https://btcw.tech/api/v2 ERRORS the selector → reason table used by decodeError ADD_CHAIN_PARAMS EIP-3085 parameters for wallet_addEthereumChain WAD 10n ** 18n Notes All amounts are BigInt or integer strings in base units (18 decimals for every asset). There is no on-chain deadline — minAmountOut is the protection; if a quote is past expiresAt (30 seconds), request a new one. Approvals are always for the exact amount of the order, never unlimited. With a chain fork: pass rpc: \"http://127.0.0.1:8545\" — see Testing on a chain fork ."},{"url":"/status/","title":"Status","group":"Operations","heads":[{"id":"right-now","t":"Right now"},{"id":"check-it-yourself","t":"Check it yourself"},{"id":"during-an-incident","t":"During an incident"}],"text":"Chain, oracle, swap and bridge health — read live when you open the page. Every tile below is read live when you open the page (public RPC and API) and refreshes every 20 seconds. If a read fails, it shows \"unavailable\" — no guessing. Right now Latest block … BTCw price (oracle) … OracleAMM … ClpPools … 345 token prices (PriceHub) … Bridge — 482120 side … Bridge — Arbitrum side … API /api/v2 … Pool charts: WBTCw / USDC.e on GeckoTerminal ↗ Check it yourself curl -s https://btcw.tech/api/health # price API: ok, block, age_seconds curl -s https://btcw.tech/api/v2/health # indexer: ok, lastBlock, builtAgoS curl -s https://btcw.tech/api/v2/stats | jq .status cast call 0x984fDC24D1A2Be538C7290487d0fc212635D98A5 \"paused()(bool)\" --rpc-url https://arb1.arbitrum.io/rpc During an incident Stale price ( stale: true ): OracleAMM and OracleRebalancer stop automatically; ClpPools keeps filling at the pool price. Chain halted (block number not increasing): everything on 482120 stops until the chain resumes. Bridge delayed : sent messages are not lost; the relayer retries automatically. When paused, paused() = true . Uptime and incident history: status.btcw.tech — every public service checked each minute from a separate server, 90 days of history, machine-readable at status.json . Detailed metrics: Dashboard ; genesis and block cadence: Transparency ."},{"url":"/run-a-node/","title":"Run a node","group":"Operations","heads":[{"id":"what-you-need","t":"What you need"},{"id":"1-files","t":"1. Files"},{"id":"2-compose-file","t":"2. Compose file"},{"id":"peers","t":"3. Peers"},{"id":"4-start-and-check","t":"4. Start and check"},{"id":"pitfalls-met-in-practice","t":"Pitfalls met in practice"},{"id":"full-node-or-validator","t":"Full node or validator"}],"text":"Add a full node to chain 482120: files, flags, peers, checks — and why the validator set never has two members. This is the procedure used to add a machine to the chain as a full node : it downloads and re-executes every block from genesis and serves its own JSON-RPC, but it does not sign blocks. It was written down while the second host was prepared on 2 Oct 2026, so the next node can be built the same way. The compose file is the one that host runs; image, genesis and gas floor are the same on every node. What you need Machine 2 vCPU, 4 GB RAM, 20 GB disk is enough today (the chain data is under 2 GB). Linux with Docker and the compose plugin. Client hyperledger/besu:26.2.0 — pin this exact version; every node of the network runs it. Genesis https://btcw.tech/genesis.json · sha256 686cc9ad2df9ba2ce9ca479cb01d551e454bd85f4b3c3707762f66d0a1385fea Genesis block hash 0x4d4c7675b66bff6e0a36a4cc628bd13ada6c83d53bc72cd8692de146604ebc9d — a node started from the right file reports exactly this for block 0. A peer The enode URL of a node that is already in sync, and a network path to its P2P port (TCP 30303). The existing nodes are not reachable from the Internet and discovery is off, so a peer is always added by hand — see Peers . 1. Files mkdir -p /opt/btcw-node/chain && cd /opt/btcw-node curl -s https://btcw.tech/genesis.json -o chain/genesis.json sha256sum chain/genesis.json # must print 686cc9ad…5fea echo '[]' > chain/static-nodes.json # peers go here, step 3 2. Compose file /opt/btcw-node/docker-compose.yml . The node uses the host network and listens on 127.0.0.1 only: Docker's published ports bypass ufw , so nothing is published at all. services: besu-node: image: hyperledger/besu:26.2.0 restart: unless-stopped network_mode: host environment: BESU_OPTS: -Xmx1536m command: - --data-path=/var/lib/besu - --genesis-file=/config/genesis.json - --profile=ENTERPRISE - --sync-mode=FULL - --min-gas-price=1000000 - --discovery-enabled=false - --static-nodes-file=/config/static-nodes.json - --p2p-host=127.0.0.1 - --p2p-interface=127.0.0.1 - --p2p-port=30303 - --rpc-http-enabled - --rpc-http-host=127.0.0.1 - --rpc-http-port=28545 - --rpc-http-api=ETH,NET,WEB3 - --host-allowlist=localhost,127.0.0.1 volumes: - ./chain/genesis.json:/config/genesis.json:ro - ./chain/static-nodes.json:/config/static-nodes.json:ro - node-data:/var/lib/besu mem_limit: 2560m logging: { driver: json-file, options: { max-size: \"20m\", max-file: \"3\" } } volumes: node-data: --sync-mode=FULL Re-executes every block. The chain is small; snapshot sync is not needed and not used by any node. --min-gas-price=1000000 The network's gas floor (0.001 gwei). A node with another value accepts or drops different transactions than its peers. --profile=ENTERPRISE Besu's profile for private networks: no assumptions about public-network peers. --rpc-http-api=ETH,NET,WEB3 Read and send only. ADMIN , DEBUG , TXPOOL and QBFT stay off on a node others can query. Storage format Default (Bonsai). Only a node that serves debug_* / trace_* to an explorer needs --data-storage-format=FOREST . 3. Peers On a node that is already in sync, read its enode URL ( net_enode is part of the NET API): curl -s -H 'content-type: application/json' \\ -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"net_enode\",\"params\":[]}' http://127.0.0.1:28545 Put it in chain/static-nodes.json on the new node, with the host and port the new node can actually reach: [\"enode://<128 hex characters>@<host>:<port>\"] The connection is one TCP stream (RLPx). It works in either direction, so only one side has to be reachable. Between two machines, carry it over a private path (a VPN or an SSH port forward restricted to that one port), not an open port. In that case <host>:<port> is the local end of the forward, e.g. 127.0.0.1:30311 . Peer with a full node, never directly with the validator: the validator has no published port and no public RPC. The 128-character node id must be the id of the node at the other end — the handshake fails otherwise. 4. Start and check docker compose up -d besu-node rpc() { curl -s -H 'content-type: application/json' -d \"{\\\"jsonrpc\\\":\\\"2.0\\\",\\\"id\\\":1,\\\"method\\\":\\\"$1\\\",\\\"params\\\":$2}\" http://127.0.0.1:28545; echo; } rpc eth_chainId '[]' # 0x75b48 rpc eth_getBlockByNumber '[\"0x0\",false]' # \"hash\":\"0x4d4c7675…bc9d\" rpc net_peerCount '[]' # 0x1 or more once a peer is configured rpc eth_blockNumber '[]' # climbs until it matches the public RPC, then +1 every 5 seconds The node is in sync when the hash of a recent block equals the one the public RPC returns for the same number: cast block 100000 --field hash --rpc-url http://127.0.0.1:28545 cast block 100000 --field hash --rpc-url https://rpc.btcw.tech With no peer configured the first two checks already pass and the block number stays at 0 — that state proves the genesis file and the flags are right before any connection is made. Pitfalls met in practice \"Supplied file does not contain valid keyPair pair\" — only for a node started with --node-private-key-file . The image's entrypoint starts as root and then drops to uid 1000, so a key file readable only by root cannot be read. Give it to uid 1000 ( chown 1000:1000 , mode 600 ). The same applies to a data volume copied from another machine. \"Host not authorized\" — the request's Host header is not in --host-allowlist . Query through localhost / 127.0.0.1 , or send -H 'Host: localhost' from a proxy. Moving a node between machines — stop it first ( docker stop -t 60 ), copy the data volume, compare a checksum of the archive on both sides, and keep the stopped container on the old machine until the new one has produced or imported blocks. Never run two nodes with the same node key at the same time — for a validator this means two signers of the same blocks. eth_getLogs — Besu limits the range to about 1,000 blocks per call; indexers must page (see JSON-RPC ). Full node or validator A full node needs nobody's approval and changes nothing for the rest of the network. A validator is di"},{"url":"/changelog/","title":"Changelog","group":"Operations","heads":[{"id":"9-oct-2026","t":"9 Oct 2026"},{"id":"8-oct-2026","t":"8 Oct 2026"},{"id":"7-oct-2026","t":"7 Oct 2026"},{"id":"6-oct-2026","t":"6 Oct 2026"},{"id":"5-oct-2026","t":"5 Oct 2026"},{"id":"4-oct-2026","t":"4 Oct 2026"},{"id":"3-oct-2026","t":"3 Oct 2026"},{"id":"2-oct-2026","t":"2 Oct 2026"},{"id":"30-sep-2026","t":"30 Sep 2026"},{"id":"29-sep-2026","t":"29 Sep 2026"},{"id":"28-sep-2026","t":"28 Sep 2026"},{"id":"25-sep-2026","t":"25 Sep 2026"},{"id":"23-sep-2026","t":"23 Sep 2026"}],"text":"Changes that affect integrators, newest first. Only changes that affect integrators are listed. R-xx ids are the project's internal decision numbers. 9 Oct 2026 21 metal, index, commodity and FX trackers (R-74): GOLDw, SILVERw, COPPERw, PLATINUMw, PALLADIUMw, XYZ100w, SP500w, JP225w, KR200w, BTCDw, OTHERSw, TOTAL2w, 10Yw, 2Yw, 30Yw, CLw, NATGASw, BRENTOILw, JPYw, EURw, GBPw, each with pools against BTCw (ClpPools) and USDC (UsdClpPools), following its Hyperliquid HIP-3 perp (see Price oracle ). New class values metal , index , commodity , fx , and an intro field on those rows of /api/v2/pools . Addresses: /api/v2/pools and tokenlist.json . Now 345 price trackers: /api/v2/pools 346, /api/v2/usd-pools 345, /api/v2/swap/assets 348. 8 Oct 2026 Anthropic pre-IPO tracker (ANTHw) (R-73) at 0x6A172b44401c6767ed13a44998EdC96f1bc9F3Cb , with pools against BTCw (ClpPools) and USDC (UsdClpPools). It follows the Anthropic pre-IPO perpetual io:ANTH on Hyperliquid, with the same rules as OPENAIw. Now 324 price trackers: /api/v2/pools 325, /api/v2/usd-pools 324, /api/v2/swap/assets 327. OPENAIw price source : OPENAIw now follows the OpenAI pre-IPO perpetual io:OAI on Hyperliquid (mark price, 24h volume ≥ 250,000 USD, mark within 2% of the market's oracle, at most 20% per 10 minutes), instead of the Robinhood Chain DEX pools. Address and pools are unchanged. BTCw ⇄ WBTCw route open to every wallet : any wallet can bridge WBTCw on 482120 to BTCw on Arbitrum One ( transferRemote(42161, recipient, amount) on the lock router 0xCC71…eBa6 after approving WBTCw) and back ( transferRemote(482120, recipient, amount) on BTCw 0xeFf5…8bbD ), 1 : 1. Backing unchanged. See Bridge . 7 Oct 2026 /api/v2/pools — holders, buy / sell volume, native BTCw supply (add-only): every pool has holders (explorer, every 10 minutes) and win.*.volBuyUsd / volSellUsd ; hub adds holders , totalSupply , circulating , mcapUsd , fdvUsd and reference (BTCUSDT on Binance). See API . OpenAI Pre-IPO tracker (OPENAIw) (R-72) at 0x095661b56E90373ab74FB1069e1E53cf16757365 , with pools against BTCw (ClpPools) and USDC (UsdClpPools). It follows the third-party \"OPENAI Pre IPO Token\" on Robinhood Chain, priced from that token's DEX pools through GeckoTerminal and DexScreener (both required, within 3%, at most 20% per 10 minutes) — a new source kind in PriceHub, see Price oracle . In /api/v2/pools its class is stock . Now 323 price trackers (100 crypto, 202 US stocks, 20 US ETFs, 1 pre-IPO): /api/v2/pools 324, /api/v2/usd-pools 323, /api/v2/swap/assets 326. Uniswap V3 pool WBTCw / USDC.e 0.05% at 0x0F5b0bb07fe8dB6e4fB7AAEdC40BC7F45fAB18A0 (token0 = USDC.e), in contracts.json as UniswapV3Pool_WBTCw_USDCe . The swap API and SDK route through it (venue v3 ) when it gives more; the peg keeper keeps it within 0.3% of Chainlink BTC/USD. See Addresses . Sourcify supports chain 482120 : the main contracts are now an exact match on Sourcify as well as on the explorer — WBTCw, USDC.e, the Uniswap V2 factory, router and pair, the BTCw vault and others. Your own contracts: forge verify-contract … --chain 482120 --verifier sourcify (no key); see Deploy a contract . ETFs priced from their own overnight market : 14 ETFs (VOO, IVV, VTI, SPYM, BND, VGT, GLD, XLK, VUG, IEFA, VXUS, IEMG, AGG, VTV) follow Binance's overnight quote for the fund itself outside the US session, with their reference fund as the fallback while the book is wide. VOO, which kept its close before, now updates overnight. 206 of 222 tickers have an off-hours price, as before. OKX stock tokens : PriceHub adds OKX spot stock tokens ( X<TICKER>-USDT , 1 token = 1 share, traded 24/7) for 33 tickers, and OKX perpetuals for BRK-B, GEV and SNOW, as more off-hours markets for those tickers (same guards). Any other OKX stock token is also used for a ticker that already has at least 2 other markets, while its 24h volume is at least $50k (19 more tickers today). The number of tickers with an off-hours price is unchanged (206 of 222). Safe interface : btcw.tech/safe creates Safe 1.3.0 multisigs (SafeL2 through the canonical SafeProxyFactory) and runs their transactions — EIP-712 signatures or on-chain approveHash , collected in a shareable link, CALL only. Standard Safe tooling (e.g. Safe CLI, protocol-kit) works the same way against the addresses in Addresses . Sixth stock price source : PriceHub also reads Binance's stock list (last trade during the US session, last regular close outside it), for 226 of the 228 stock and ETF tickers. Stocks now have 6 sources and ETFs 5; at least 3 must agree, as before. More stocks priced overnight : 10 more tickers (BRK-B, VZ, T, WM, CB, DUK, PM, NEE, UNP, SYK) follow Binance's overnight stock quote outside the US session, with the same guards (spread ≤ 1.5%, within 15% of the close); a tight quote is reused for up to 30 minutes while the book is wide. 206 of the 222 stock and ETF tickers now have an off-hours price; 16 keep the last close. List your app : the Ecosystem page has a form to send an app for review (Turnstile check; listed contracts must have code on 482120). See Deploy a contract → Get listed . VinFast Auto (VFSw) stock tracker (R-71) at 0x27bCe414c5DC75f3BC8044A7b881De01684a7A59 , with pools against BTCw (ClpPools) and USDC (UsdClpPools); outside the US session it follows Binance's overnight quote for VFS (spread ≤ 1.5%, within 15% of the close). Now 322 price trackers (100 crypto, 202 US stocks, 20 US ETFs): /api/v2/pools 323, /api/v2/usd-pools 322, /api/v2/swap/assets 325. Status page : status.btcw.tech checks the chain, RPC, explorer, website, API, oracle, swap quotes, docs, faucet and the ERC-4337 bundler every minute from a server separate from the main one, with 90-day uptime and incidents; JSON at https://status.btcw.tech/status.json (CORS open). See Status . Gas faucet : POST /api/faucet now also needs a Cloudflare Turnstile token, {\"address\":\"0x…\",\"turnstile\":\"<token>\"} ; without one it answers 403 with \"check\": true . GET /api/faucet/status return"},{"url":"/security/","title":"Security","group":"Operations","heads":[{"id":"scope","t":"Scope"},{"id":"reporting-a-vulnerability","t":"Reporting a vulnerability"},{"id":"do-not-test-on-mainnet","t":"Do not test on mainnet"},{"id":"risk-mitigations-in-place","t":"Risk mitigations in place"}],"text":"Scope, how to report a vulnerability, and what not to do on mainnet. Scope Vulnerabilities in the contracts listed under Contract addresses , the APIs and pages on btcw.tech , the rpc.btcw.tech RPC, and the Hyperlane bridge. The published trust model (the Owner permissions listed in Trust model ) does not count as a vulnerability. Reporting a vulnerability A public reporting channel has not been set up yet . In the meantime, do not publish vulnerability details before the issue is fixed. Bug bounty program: none . When reporting, include: the affected contract or endpoint, reproduction steps — ideally on a chain fork with anvil — and the estimated impact. Do not test on mainnet Do not attempt exploits on the live chain — use a chain fork ; everything on mainnet is real money and irreversible. Do not flood the RPC or API to probe the limits — they are documented in Limits & error codes . Never use private keys printed by anvil or shown in these docs for real wallets. Risk mitigations in place Source code is public and verified on the explorer and Sourcify (482120), and on Sourcify and Arbiscan (Arbitrum). Foundry tests and rehearsals on a fork of the live chain before major deployments — e.g. OracleRebalancer: 20/20 tests passed, 8/8 mutants caught. Oracle price jumps capped at ≤ 10% per update; daily token mint cap; granular pausing. No independent audit yet — see Trust model & risks ."}]}