Skip to content

feat: add BOB Gateway swapper (BTC ↔ BOB)#12275

Merged
kaladinlight merged 16 commits into
developfrom
bob-swapper
Jun 10, 2026
Merged

feat: add BOB Gateway swapper (BTC ↔ BOB)#12275
kaladinlight merged 16 commits into
developfrom
bob-swapper

Conversation

@twblack88

@twblack88 twblack88 commented Apr 10, 2026

Copy link
Copy Markdown
Contributor

Description

Adds the BOB Gateway swapper, enabling native BTC ↔ BOB chain swaps via the BOB Gateway protocol. This is the first pass supporting BTC↔BOB routes. LayerZero cross-chain routes (other EVM chains via BOB) are tracked separately in SS-5639.

What's included:

  • BobGatewaySwapper package under packages/swapper/src/swappers/BobGatewaySwapper/
  • getTradeQuote and getTradeRate implementations using @gobob/bob-sdk
  • CSP headers for gateway-api-mainnet.gobob.xyz
  • SwapperIcon and bob-gateway-icon.png
  • Config/env wiring for BOB_GATEWAY_ENABLED feature flag
  • Slippage represented internally as decimal percentage, converted to BOB Gateway basis points at call-site

Issue (if applicable)

closes #12267

Risk

Medium — new swapper introducing a new on-chain deposit-to-address flow for BTC→BOB and BOB→BTC. Does not modify existing swappers. Gated behind a feature flag (BOB_GATEWAY_ENABLED).

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

  • BOB Gateway smart contracts (BTC bridge deposits)
  • BTC send transactions (deposit-address flow)
  • BOB EVM transactions

Testing

Engineering

  1. Set VITE_FEATURE_BOB_GATEWAY_ENABLED=true in .env.development
  2. Connect a wallet with BTC or BOB assets
  3. Navigate to the swap page and select BTC → WBTC (BOB) or BOB WBTC → BTC
  4. Verify quote is fetched from BOB Gateway API and order is created on confirmation

Operations

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

Screenshots (if applicable)

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Bob Gateway as a new swapping option for token exchanges and cross-chain transactions.
    • Implemented support for both EVM and Bitcoin (UTXO) transaction execution.
    • Introduced feature flag to control Bob Gateway availability (disabled by default).
  • Chores

    • Added Bob Gateway swapper branding and UI icon support.
    • Configured server-side API integration and authentication for gateway connectivity.

@twblack88 twblack88 requested a review from a team as a code owner April 10, 2026 18:28
@coderabbitai

coderabbitai Bot commented Apr 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9df24a01-d7f5-4af6-9bf7-f02fa05991d5

📥 Commits

Reviewing files that changed from the base of the PR and between 60bcb47 and f12ffa5.

📒 Files selected for processing (17)
  • .env
  • .env.development
  • packages/public-api/src/config.ts
  • packages/public-api/src/constants.ts
  • packages/public-api/src/env.ts
  • packages/public-api/src/routes/quote/getQuote.ts
  • packages/public-api/src/routes/rates/getRates.ts
  • packages/swapper/package.json
  • packages/swapper/src/index.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/BobGatewaySwapper.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/endpoints.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/swapperApi/getTradeRate.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/types.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/utils/constants.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/utils/helpers.ts
  • packages/swapper/src/swappers/utils/helpers/helpers.ts
💤 Files with no reviewable changes (11)
  • packages/swapper/src/swappers/BobGatewaySwapper/types.ts
  • packages/swapper/package.json
  • .env.development
  • packages/swapper/src/index.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/BobGatewaySwapper.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/utils/constants.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/swapperApi/getTradeRate.ts
  • packages/swapper/src/swappers/utils/helpers/helpers.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/utils/helpers.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/endpoints.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/public-api/src/constants.ts

📝 Walkthrough

Walkthrough

Introduces the Bob Gateway swapper supporting BTC ↔ BOB chain token swaps through quote retrieval, order creation, unsigned transaction building, and order status polling. Includes environment variables, SDK dependency, type contracts, quote/rate/execution APIs, CSP headers, feature flag, client wiring, and server-side API integration with disabled swapper gating.

Changes

Bob Gateway swapper integration

Layer / File(s) Summary
Environment, configuration, and SDK dependency
.env, .env.development, packages/public-api/src/env.ts, packages/public-api/src/config.ts, packages/swapper/package.json
Feature flag VITE_FEATURE_BOB_GATEWAY_SWAP (false in .env, true in dev), API key VITE_BOB_GATEWAY_API_KEY, env schema validation, server config exposure, and @gobob/bob-sdk@5.6.0 dependency.
Swapper type definitions and metadata contracts
packages/swapper/src/types.ts, packages/swapper/src/swappers/BobGatewaySwapper/types.ts
SwapperName.BobGateway enum variant; bobSpecific optional metadata in TradeQuoteStep and SwapperSpecificMetadata holding orderId, optional depositAddress (UTXO), and optional evmTx (EVM); BobGatewayMetadata discriminated union enforcing mutually exclusive evmTx/utxoTx shapes.
Constants, chain mappings, and primitive utilities
packages/swapper/src/swappers/BobGatewaySwapper/utils/constants.ts
Base URL, bidirectional CAIP ChainId ↔ Bob Gateway chain-name mappings, dummy EVM/BTC addresses, default gas/tx-size constants for onramp/offramp/tokenswap, decimalSlippageToBobBps converter.
Quote, order, fee, and status orchestration helpers
packages/swapper/src/swappers/BobGatewaySwapper/utils/helpers.ts
12+ exported functions: client construction, asset-to-token mapping, sender selection (EVM fast-path; UTXO queries UTXOs and selects richest address), quote fetching with Bob error-code-to-SwapError mapping, order metadata creation (onramp UTXO deposit or offramp/tokenswap EVM tx), tx registration by quote type, network fee estimation for UTXO (via chain adapter) and EVM (via evm.getFees), fallback rate fee calculation, Bob status-to-TxStatus mapping, quote parsing with per-fee-asset protocol fee aggregation, allowance contract selection, trade validation checking chain support.
Trade rate and quote API functions
packages/swapper/src/swappers/BobGatewaySwapper/swapperApi/getTradeRate.ts, packages/swapper/src/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.ts
getBobGatewayTradeRate validates asset pair, uses dummy sender/recipient by chain, fetches quote, parses results, computes rate, derives allowance, and awaits network fee; getBobGatewayTradeQuote validates addresses and asset pair, derives sender (with xpub for UTXO), fetches quote, creates order metadata, obtains fee data, parses output amounts/protocol fees, and constructs TradeQuote with single step containing bobSpecific metadata. Both return `Result<TradeRate
Swapper execution and endpoint implementation
packages/swapper/src/swappers/BobGatewaySwapper/BobGatewaySwapper.ts, packages/swapper/src/swappers/BobGatewaySwapper/endpoints.ts
bobGatewaySwapper wires executeEvmTransaction utility and executeUtxoTransaction to signAndBroadcastTransaction; bobGatewayApi wraps trade rate/quote helpers into API tuples, builds unsigned UTXO transactions via chain adapter using deposit address and sellAmountIncludingProtocolFeesCryptoBaseUnit, builds unsigned EVM transactions from bobSpecific.evmTx with computed fees, estimates both UTXO and EVM fees, and checkTradeStatus registers txHash once per swap, maps Bob Gateway order status to TxStatus, handles ORDER_NOT_FOUND as "Waiting for deposit...", and extracts buyTxHash from success response.
Swapper module exports and constants registration
packages/swapper/src/swappers/BobGatewaySwapper/index.ts, packages/swapper/src/index.ts, packages/swapper/src/constants.ts
Re-export bobGatewayApi, bobGatewaySwapper, and constants from BobGatewaySwapper module; register SwapperName.BobGateway in swappers map merging swapper and API objects; add DEFAULT_BOB_GATEWAY_SLIPPAGE_DECIMAL_PERCENTAGE to slippage defaults switch.
Content Security Policy headers
headers/csps/defi/swappers/BobGateway.ts, headers/csps/index.ts
New CSP module allowing connect-src to https://gateway-api-mainnet.gobob.xyz; registered in CSP export array.
Server-side API route integration and swapper gating
packages/public-api/src/constants.ts, packages/public-api/src/routes/quote/getQuote.ts, packages/public-api/src/routes/rates/getRates.ts
ENABLED_SWAPPER_NAMES list includes Bebop, ButterSwap, Chainflip, CowSwap, Mayachain, NearIntents, Portals, Relay, Thorchain, Zrx (BobGateway excluded); getQuote validates swapper against list; getRates imports centralized list instead of local definition.
Client-side state, feature flag, and swapper enablement
src/state/slices/preferencesSlice/preferencesSlice.ts, src/state/helpers.ts, packages/swapper/src/swappers/utils/helpers/helpers.ts, src/config.ts
BobGatewaySwap feature flag in preferences initialized from config; isCrossAccountTradeSupported returns true for BobGateway; getEnabledSwappers includes BobGateway when feature enabled and cross-account check passes; Bob mainnet treasury mapping added to helpers; client config validators added for feature flag and affiliate ID.
Client UI components and trade execution wiring
src/components/MultiHopTrade/components/TradeInput/components/SwapperIcon/SwapperIcon.tsx, src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeButtonProps.tsx, src/lib/tradeExecution.ts, src/test/mocks/store.ts
SwapperIcon maps SwapperName.BobGateway to bob-gateway-icon.png; trade confirmation wires bobSpecific from first step into swap metadata; trade execution stores bobSpecific from quote in swap state; test mock includes BobGatewaySwap: false feature flag.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • shapeshift/web#12267: This PR fully implements the Bob Gateway swapper feature including onramp (BTC→EVM), offramp (EVM→BTC), metadata handling, and all registration checklist items from the issue.

  • shapeshift/web#12271: Related PR addressing the same Bob Gateway swapper integration at code level through quote/order/metadata/status handling logic.

Possibly related PRs

  • shapeshift/web#12390: Implements BobGateway swapper end-to-end with matching env setup, CSP headers, swapper registration, and bobSpecific metadata wiring across trade execution and confirmation paths.

Poem

🐰 A gateway to Bob, with BTC in hand,
Swapping chains smoothly across the land,
From deposits to orders, through helpers so wise,
MetaData tagged, in BOB-specific guise.
No stone left unturned, this swapper takes flight—
Bob Gateway ⛩️ blazes, burning so bright!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: add BOB Gateway swapper (BTC ↔ BOB)' clearly and concisely summarizes the main change: integrating a new BOB Gateway swapper for BTC ↔ BOB chain swaps.
Linked Issues check ✅ Passed The PR successfully implements all coding requirements from issue #12267: SwapperName.BobGateway, bobSpecific metadata, CSP headers, feature flags, environment variables, icon, transaction builders, and checkTradeStatus integration.
Out of Scope Changes check ✅ Passed All changes are directly related to BOB Gateway swapper implementation. Supporting changes like ENABLED_SWAPPER_NAMES refactoring and DAO treasury mapping are minimal and necessary for the feature.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bob-swapper

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

❤️ Share

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

@twblack88

Copy link
Copy Markdown
Contributor Author

note that we are waiting on the UUID from the bob team for fees and gateway.

so, no rush here, just wanted to unblock other work.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/swapper/src/swappers/BobGatewaySwapper/endpoints.ts`:
- Around line 143-152: The current catch for api.getOrder indiscriminately
returns a Waiting for deposit state; change the error handling in the order
lookup so only a true "not found" / not-yet-indexed response maps to {
buyTxHash: undefined, status: TxStatus.Unknown, message: 'Waiting for
deposit...' } — detect this by inspecting the thrown error from api.getOrder
(e.g. error.response?.status === 404 or a NotFoundError class) and return the
waiting payload only in that case; for all other errors
(network/server/transport) either rethrow or return an explicit error
result/preserve the last known status instead of masking it as Waiting for
deposit. Ensure you reference the existing symbols orderInfo, api.getOrder,
buyTxHash, and TxStatus.Unknown when making the change.

In `@packages/swapper/src/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.ts`:
- Around line 202-208: The code calls utxoAdapter.getFeeData and assigns
networkFeeCryptoBaseUnit = fast.txFee but fails to persist the BTC fee
parameters required for execution; update the quote construction where fast is
obtained (the utxoAdapter.getFeeData call and the similar occurrence later) to
also set step.feeData.chainSpecific.satsPerByte (and any other chainSpecific fee
fields returned by fast) from fast.satsPerByte (or equivalent) so
getUnsignedUtxoTransaction() can read step.feeData.chainSpecific.satsPerByte at
execution time; ensure the same change is applied to the second getFeeData usage
mentioned so both quote paths include the chainSpecific fee params.
- Around line 150-162: The getTradeQuote function is performing a side-effect by
calling api.createOrder (see getTradeQuote and api.createOrder) which reserves
Bob Gateway orders during quoting; remove the createOrder call and any
orderResponse usage from getTradeQuote so the quote path is
stateless/deterministic, and instead invoke api.createOrder from the
execution/unsigned-tx path (e.g., in the swap execution or build/confirm flow
where orders are actually submitted) so order creation happens only at
confirmation; ensure error handling and mapping (TradeQuoteError.QueryFailed)
for createOrder are moved accordingly to the execution code.
- Around line 43-46: _wrap the entire async function body of _getTradeQuote in a
try-catch and ensure every awaited helper/async operation (not just SDK calls)
is converted to a Result using AsyncResultOf; for each AsyncResultOf check for
Err and return Err(...) (using the SwapErrorRight shape) instead of letting
exceptions propagate, and in the catch block convert the thrown error into an
Err(SwapErrorRight) return. Apply the same pattern to the other async blocks in
this file flagged by the review (the other promise/await sections around the
later trade quote logic) so no helper throws escape the Result contract._

In `@packages/swapper/src/swappers/BobGatewaySwapper/swapperApi/getTradeRate.ts`:
- Around line 42-45: _getTradeRate currently can throw uncaught exceptions
instead of returning a Result; wrap the entire async body of _getTradeRate (and
the other marked blocks around lines ~60-74 and ~129-166) in a try-catch,
convert any unexpected errors into Err(makeSwapErrorRight(...)) so the function
always returns Result<TradeRate, SwapErrorRight>, and use Ok(...) for success;
also use the AsyncResultOf utility to convert awaited helper promises to Results
and handle their Err branches rather than letting them throw; reference symbols:
_getTradeRate, GetTradeRateInput, SwapperDeps, Result, TradeRate,
SwapErrorRight, makeSwapErrorRight, Ok, Err, AsyncResultOf.

In `@packages/swapper/src/swappers/BobGatewaySwapper/utils/constants.ts`:
- Around line 28-30: The current flat BOB_GATEWAY_SUPPORTED_CHAIN_IDS and
BobGatewaySupportedChainId must be replaced with the standard SupportedChainIds
shape (an object with sell and buy arrays) used by swappers; update the exported
constant (rename to BOB_GATEWAY_SUPPORTED_CHAIN_IDS or
BOB_GATEWAY_SUPPORTED_CHAINS as you prefer) to be { sell: [ ... ], buy: [ ... ]
} using btcChainId and bobChainId in the appropriate arrays, and change the
exported type to match SupportedChainIds (or derive a type alias from that
shape) so downstream filtering that expects .sell/.buy works correctly; ensure
any code importing BobGatewaySupportedChainId or the old constant is updated to
use the new object shape.
- Around line 49-50: The decimalSlippageToBobBps function can return "NaN" for
malformed slippage input; add input validation at the top of
decimalSlippageToBobBps to parse slippageDecimal, ensure it's a non-empty string
that parses to a finite number and is within an acceptable range (e.g., >= 0 and
<= 1 or whatever project limit you prefer), and use an early return/throw with a
clear error message (e.g., throw new Error(`Invalid slippageDecimal:
"${slippageDecimal}"`)) when validation fails so downstream code never receives
"NaN".

In `@src/config.ts`:
- Around line 282-283: The feature flag name in config is wrong: replace or
alias VITE_FEATURE_BOB_GATEWAY_SWAP with the rollout name
VITE_FEATURE_BOB_GATEWAY_ENABLED so the environment flag used in the PR
activates the feature; update the config entry that currently defines
VITE_FEATURE_BOB_GATEWAY_SWAP to validate VITE_FEATURE_BOB_GATEWAY_ENABLED (or
add a second boolean key that maps to the same setting) and ensure any code
reading the flag (references to VITE_FEATURE_BOB_GATEWAY_SWAP elsewhere) is
updated to read VITE_FEATURE_BOB_GATEWAY_ENABLED or both names are kept in sync.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a3cec11b-7c8d-468a-8476-ad1cfc3c0534

📥 Commits

Reviewing files that changed from the base of the PR and between 51bf5c1 and 60bcb47.

⛔ Files ignored due to path filters (2)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • src/components/MultiHopTrade/components/TradeInput/components/SwapperIcon/bob-gateway-icon.png is excluded by !**/*.png
📒 Files selected for processing (24)
  • .env
  • .env.development
  • headers/csps/defi/swappers/BobGateway.ts
  • headers/csps/index.ts
  • packages/public-api/src/config.ts
  • packages/public-api/src/env.ts
  • packages/swapper/package.json
  • packages/swapper/src/constants.ts
  • packages/swapper/src/index.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/BobGatewaySwapper.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/endpoints.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/index.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/swapperApi/getTradeRate.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/utils/constants.ts
  • packages/swapper/src/swappers/BobGatewaySwapper/utils/helpers/helpers.ts
  • packages/swapper/src/types.ts
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeButtonProps.tsx
  • src/components/MultiHopTrade/components/TradeInput/components/SwapperIcon/SwapperIcon.tsx
  • src/config.ts
  • src/lib/tradeExecution.ts
  • src/state/helpers.ts
  • src/state/slices/preferencesSlice/preferencesSlice.ts
  • src/test/mocks/store.ts

Comment thread packages/swapper/src/swappers/BobGatewaySwapper/endpoints.ts
Comment thread packages/swapper/src/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.ts Outdated
Comment thread packages/swapper/src/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.ts Outdated
Comment thread packages/swapper/src/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.ts Outdated
Comment thread packages/swapper/src/swappers/BobGatewaySwapper/swapperApi/getTradeRate.ts Outdated
Comment thread packages/swapper/src/swappers/BobGatewaySwapper/utils/constants.ts Outdated
Comment thread packages/swapper/src/swappers/BobGatewaySwapper/utils/constants.ts
Comment thread src/config.ts Outdated
@twblack88

Copy link
Copy Markdown
Contributor Author

BOB which is in the middle of refactoring their API to just take a regular raw EVM address for payouts. No UUID needed, which is great because it fits into our swapper params perfectly. They confirmed that they work with Gnosis safes, no problem. So a simple parameter swap and then a bunch of testing to make sure the fees go in, and we should be good.

@kaladinlight kaladinlight marked this pull request as draft May 7, 2026 15:56
slavastartsev and others added 12 commits May 28, 2026 16:23
The affiliate recipient isn't a secret, so drop the
VITE_BOB_GATEWAY_AFFILIATE_ID env var and source it from treasury.ts
like the rest of the swappers. Gateway pays affiliate fees as
basis-point cuts of the swap output at settlement on BOB chain, so add
DAO_TREASURY_BOB (same DAO EOA as Monad/HyperEVM) and wire
getBobGatewayAffiliates to getTreasuryAddressFromChainId(bobChainId).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- collapse chain name/id structures into a single chainIdToBobGatewayChainName
  map (matching the debridge/across pattern) and drop telos/swell/soneium/
  optimism, which are no longer in gateway's route set (telos/swell were
  caip additions solely for gateway, so remove them there too)
- plumb affiliateBps from the quote/rate input instead of a hardcoded const
- use the shared getDefaultSlippageDecimalPercentageForSwapper instead of a
  duplicated local default
- replace generated instanceOf*OneOf* guards with semantic 'key' in checks
- support tokenSwap (EVM↔EVM and same-chain) orders: accept the tokenSwap
  createOrderV2 variant in the evm execution path, drop the same-chain route
  guard, and pick rate dummy addresses per side instead of assuming evm↔btc
- flatten utils/helpers/helpers.ts to utils/helpers.ts, drop the redundant
  BTC_TOKEN_ADDRESS alias of zeroAddress and the getBobGatewayClient
  apiKey || undefined normalization (sdk treats '' as absent)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Declare the bob gateway metadata types in BobGatewaySwapper/types.ts like
the other swappers, removing the @gobob/bob-sdk import from the shared
types.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
BOB denominates quote fees across multiple assets (e.g. the BTC inclusion
fee in the output token, affiliate/solver fees in USDT). Resolve each fee's
chain + token address to an AssetId and aggregate per asset instead of only
counting output-token-denominated fees.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Publishable key for affiliate attribution and rate limiting, committed
inline like the other swapper keys (bebop, chainflip, etc.).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Create the gateway order during getTradeQuote so quotes are executable
(including via the public api) and estimate real network fees from the
order's tx data instead of a hardcoded gas limit - UTXO deposit fees for
onramps, eth_estimateGas for the EVM gateway call. Fee estimation throws
on an unsupported chain or invalid quote rather than returning zero fees.

Collapse the two bob metadata types into a single XOR BobGatewayMetadata
(evmTx | utxoTx) and share quote/order/fee helpers between getTradeRate
and getTradeQuote. Fix checkTradeStatus to surface buyTxHash only on
success and flag refunds via the status message instead of mislabeling a
refund hash as buyTxHash.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Associate the broadcast sell tx with its BOB Gateway order via the v2
register-tx endpoint so the watchtower can track the order and progress
its status. Registers once per swap during status polling, retrying until
the tx propagates.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d funds

- add rate-time network fee estimation, since there's no order/tx to estimate
  against yet: default gas limits for EVM tokenSwap (350k) / offramp (550k)
  × live gas price, and dynamic sats/vByte × default onramp tx vsize (200) for
  the BTC onramp. quote path still computes the exact fee.
- pay affiliate fees to the BOB treasury via getTreasuryAddressFromChainId
  instead of a hardcoded address
- surface INSUFFICIENT_CONFIRMED_FUNDS as a dedicated user-facing error
  ("Funds still confirming. Try again once confirmed.") instead of a generic
  quote failure

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kaladinlight kaladinlight marked this pull request as ready for review June 10, 2026 20:05
kaladinlight and others added 3 commits June 10, 2026 14:06
BOB Gateway validates the balance of the assigned sender address at order
creation, but utxo account funds are spread across many addresses (the default
sendAddress is the next unused receive address, which never holds funds).

- select the richest utxo address as the order sender at quote time
- constrain tx building and fee estimation inputs to the validated sender
- surface an actionable FundsFragmented error directing the user to
  consolidate funds when no single address can cover the sell amount

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The rates route already gated swappers via a hardcoded allowlist, but the
quote route accepted any registered swapper name. Share the allowlist and
enforce it for quotes so new swappers (e.g. BOB Gateway) are not exposed via
the public api until fully validated in the web app.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Threshold the funds fragmented check on amount + actual getFeeData fee for
the from-constrained send instead of the sell amount alone, surfacing the
actionable error before order creation for borderline fee shortfalls.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kaladinlight kaladinlight merged commit 2777a51 into develop Jun 10, 2026
4 checks passed
@kaladinlight kaladinlight deleted the bob-swapper branch June 10, 2026 20:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BOB swapper

3 participants