-
Notifications
You must be signed in to change notification settings - Fork 198
feat: add BOB Gateway swapper (BTC ↔ BOB) #12275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
60bcb47
adding bob swapper first pass
twblack88 f58f55c
temp: migrate to v2 api
slavastartsev 5580ff8
feat: integrate BOB Gateway swapper (BTC ↔ BOB) (#12390)
kaladinlight 123ec98
Merge branch 'develop' into bob-swapper
kaladinlight d9b2b68
feat: pay bob gateway affiliate fees to dao treasury
kaladinlight 7141166
chore: clean up bob gateway swapper
kaladinlight 5f9b076
chore: move bob gateway types into the swapper
kaladinlight 14e23c0
feat: aggregate bob gateway protocol fees by asset
kaladinlight 6af5757
chore: add bob gateway publishable api key
kaladinlight e22341d
feat: create bob gateway order at quote time with real fee estimation
kaladinlight f569a6a
feat: register bob gateway tx for order status tracking
kaladinlight f8651b2
feat: estimate bob gateway rate-time network fees + handle unconfirme…
kaladinlight 3ccde46
Merge branch 'develop' into bob-swapper
kaladinlight f2ca18e
feat: select best funded utxo sender for bob gateway orders
kaladinlight 28b2090
chore: enforce enabled swapper allowlist for public api quotes
kaladinlight f12ffa5
feat: use real coinselect fee for bob gateway sender funding check
kaladinlight File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import type { Csp } from '../../../types' | ||
|
|
||
| export const csp: Csp = { | ||
| 'connect-src': ['https://gateway-api-mainnet.gobob.xyz'], | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import { SwapperName } from '@shapeshiftoss/swapper' | ||
|
|
||
| export const ENABLED_SWAPPER_NAMES: readonly SwapperName[] = [ | ||
| SwapperName.Bebop, | ||
| SwapperName.ButterSwap, | ||
| SwapperName.Chainflip, | ||
| SwapperName.CowSwap, | ||
| SwapperName.Mayachain, | ||
| SwapperName.NearIntents, | ||
| SwapperName.Portals, | ||
| SwapperName.Relay, | ||
| SwapperName.Thorchain, | ||
| SwapperName.Zrx, | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
packages/swapper/src/swappers/BobGatewaySwapper/BobGatewaySwapper.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import type { Swapper } from '../../types' | ||
| import { executeEvmTransaction } from '../../utils' | ||
|
|
||
| export const bobGatewaySwapper: Swapper = { | ||
| executeEvmTransaction, | ||
| executeUtxoTransaction: (txToSign, { signAndBroadcastTransaction }) => | ||
| signAndBroadcastTransaction(txToSign), | ||
| } |
184 changes: 184 additions & 0 deletions
184
packages/swapper/src/swappers/BobGatewaySwapper/endpoints.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,184 @@ | ||
| import { isGatewayError } from '@gobob/bob-sdk' | ||
| import { evm } from '@shapeshiftoss/chain-adapters' | ||
| import { TxStatus } from '@shapeshiftoss/unchained-client' | ||
|
|
||
| import type { SwapperApi, UtxoFeeData } from '../../types' | ||
| import { getExecutableTradeStep, isExecutableTradeQuote } from '../../utils' | ||
| import { getBobGatewayTradeQuote } from './swapperApi/getTradeQuote' | ||
| import { getBobGatewayTradeRate } from './swapperApi/getTradeRate' | ||
| import { | ||
| getBobGatewayClient, | ||
| mapBobGatewayOrderStatusToTxStatus, | ||
| registerBobGatewayTx, | ||
| } from './utils/helpers' | ||
|
|
||
| const registeredSwapIds = new Set<string>() | ||
|
|
||
| export const bobGatewayApi: SwapperApi = { | ||
| getTradeRate: async (input, deps) => { | ||
| return (await getBobGatewayTradeRate(input, deps)).map(tradeRate => [tradeRate]) | ||
| }, | ||
| getTradeQuote: async (input, deps) => { | ||
| return (await getBobGatewayTradeQuote(input, deps)).map(tradeQuote => [tradeQuote]) | ||
| }, | ||
| getUnsignedUtxoTransaction: ({ | ||
| stepIndex, | ||
| tradeQuote, | ||
| xpub, | ||
| accountType, | ||
| assertGetUtxoChainAdapter, | ||
| }) => { | ||
| if (!isExecutableTradeQuote(tradeQuote)) { | ||
| throw new Error('[BobGateway] unable to execute a trade rate') | ||
| } | ||
|
|
||
| const step = getExecutableTradeStep(tradeQuote, stepIndex) | ||
| const { bobSpecific, sellAsset } = step | ||
|
|
||
| const adapter = assertGetUtxoChainAdapter(sellAsset.chainId) | ||
|
|
||
| if (!bobSpecific?.utxoTx) throw new Error('[BobGateway] invalid utxo transaction') | ||
| const { depositAddress, opReturnData, sender } = bobSpecific.utxoTx | ||
|
|
||
| return adapter.buildSendApiTransaction({ | ||
| value: step.sellAmountIncludingProtocolFeesCryptoBaseUnit, | ||
| xpub, | ||
| to: depositAddress, | ||
| accountNumber: step.accountNumber, | ||
| skipToAddressValidation: true, | ||
| chainSpecific: { | ||
| from: sender, | ||
| accountType, | ||
| opReturnData, | ||
| satoshiPerByte: (step.feeData.chainSpecific as UtxoFeeData).satsPerByte, | ||
| }, | ||
| }) | ||
| }, | ||
| getUtxoTransactionFees: async ({ stepIndex, tradeQuote, xpub, assertGetUtxoChainAdapter }) => { | ||
| if (!isExecutableTradeQuote(tradeQuote)) { | ||
| throw new Error('[BobGateway] unable to execute a trade rate') | ||
| } | ||
|
|
||
| const step = getExecutableTradeStep(tradeQuote, stepIndex) | ||
| const { bobSpecific, sellAsset } = step | ||
|
|
||
| const adapter = assertGetUtxoChainAdapter(sellAsset.chainId) | ||
|
|
||
| if (!bobSpecific?.utxoTx) throw new Error('[BobGateway] invalid utxo transaction') | ||
| const { depositAddress, opReturnData, sender } = bobSpecific.utxoTx | ||
|
|
||
| const { fast } = await adapter.getFeeData({ | ||
| to: depositAddress, | ||
| value: step.sellAmountIncludingProtocolFeesCryptoBaseUnit, | ||
| chainSpecific: { pubkey: xpub, opReturnData, from: sender }, | ||
| sendMax: false, | ||
| }) | ||
|
|
||
| return fast.txFee | ||
| }, | ||
| getUnsignedEvmTransaction: async ({ | ||
| from, | ||
| stepIndex, | ||
| tradeQuote, | ||
| assertGetEvmChainAdapter, | ||
| supportsEIP1559, | ||
| }) => { | ||
| if (!isExecutableTradeQuote(tradeQuote)) { | ||
| throw new Error('[BobGateway] unable to execute a trade rate') | ||
| } | ||
|
|
||
| const step = getExecutableTradeStep(tradeQuote, stepIndex) | ||
| const { accountNumber, bobSpecific, sellAsset } = step | ||
|
|
||
| const adapter = assertGetEvmChainAdapter(sellAsset.chainId) | ||
|
|
||
| if (!bobSpecific?.evmTx) throw new Error('[BobGateway] invalid evm transaction') | ||
| const { to, data, value } = bobSpecific.evmTx | ||
|
|
||
| const feeData = await evm.getFees({ adapter, data, to, value, from, supportsEIP1559 }) | ||
|
|
||
| return adapter.buildCustomApiTx({ | ||
| accountNumber, | ||
| from, | ||
| to, | ||
| value, | ||
| data, | ||
| ...feeData, | ||
| }) | ||
| }, | ||
| getEvmTransactionFees: async ({ | ||
| from, | ||
| stepIndex, | ||
| tradeQuote, | ||
| supportsEIP1559, | ||
| assertGetEvmChainAdapter, | ||
| }) => { | ||
| if (!isExecutableTradeQuote(tradeQuote)) { | ||
| throw new Error('[BobGateway] unable to execute a trade rate') | ||
| } | ||
|
|
||
| const step = getExecutableTradeStep(tradeQuote, stepIndex) | ||
| const { bobSpecific, sellAsset } = step | ||
|
|
||
| const adapter = assertGetEvmChainAdapter(sellAsset.chainId) | ||
|
|
||
| if (!bobSpecific?.evmTx) throw new Error('[BobGateway] invalid evm transaction') | ||
| const { to, data, value } = bobSpecific.evmTx | ||
|
|
||
| const feeData = await evm.getFees({ adapter, data, to, value, from, supportsEIP1559 }) | ||
|
|
||
| return feeData.networkFeeCryptoBaseUnit | ||
| }, | ||
| checkTradeStatus: async ({ swap, config, txHash }) => { | ||
| if (!swap) throw new Error('[BobGateway] swap is required for status check') | ||
|
|
||
| const orderId = swap.metadata.bobSpecific?.orderId | ||
| if (!orderId) throw new Error('[BobGateway] orderId is required for status check') | ||
|
|
||
| if (txHash && !registeredSwapIds.has(swap.id)) { | ||
| try { | ||
| await registerBobGatewayTx({ | ||
| config, | ||
| orderId, | ||
| txHash, | ||
| sellAsset: swap.sellAsset, | ||
| buyAsset: swap.buyAsset, | ||
| }) | ||
| registeredSwapIds.add(swap.id) | ||
| } catch {} | ||
| } | ||
|
|
||
| let orderInfo | ||
| try { | ||
| orderInfo = await getBobGatewayClient(config).getOrder(orderId) | ||
| } catch (err) { | ||
| if (isGatewayError(err)) { | ||
| if (err.code === 'ORDER_NOT_FOUND') { | ||
| return { | ||
| buyTxHash: undefined, | ||
| status: TxStatus.Unknown, | ||
| message: 'Waiting for deposit...', | ||
| } | ||
| } | ||
| } | ||
|
|
||
| throw err | ||
| } | ||
|
|
||
| const status = mapBobGatewayOrderStatusToTxStatus(orderInfo.status) | ||
|
|
||
| const buyTxHash = | ||
| 'success' in orderInfo.status ? orderInfo.status.success.receivedTokens[0]?.txHash : undefined | ||
|
|
||
| const refundTxHash = | ||
| 'refunded' in orderInfo.status | ||
| ? orderInfo.status.refunded.refundedTokens[0]?.txHash | ||
| : undefined | ||
|
|
||
| return { | ||
| status, | ||
| buyTxHash, | ||
| message: refundTxHash ? 'Trade refunded' : undefined, | ||
| } | ||
| }, | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| export { bobGatewayApi } from './endpoints' | ||
| export { bobGatewaySwapper } from './BobGatewaySwapper' | ||
| export * from './utils/constants' |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.