Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ VITE_FEATURE_TON=true
VITE_FEATURE_EARN_TAB=true
VITE_FEATURE_ACROSS_SWAP=true
VITE_FEATURE_DEBRIDGE_SWAP=true
VITE_FEATURE_BOB_GATEWAY_SWAP=false
VITE_BOB_GATEWAY_AFFILIATE_ID=
VITE_FEATURE_USERBACK=true
VITE_FEATURE_AGENTIC_CHAT=false
VITE_FEATURE_MM_NATIVE_MULTICHAIN=false
Expand Down
2 changes: 2 additions & 0 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ VITE_FEATURE_HEMI=true
VITE_FEATURE_SONIC=true
VITE_FEATURE_UNICHAIN=true
VITE_FEATURE_BOB=true
VITE_FEATURE_BOB_GATEWAY_SWAP=true
VITE_BOB_GATEWAY_AFFILIATE_ID=
VITE_FEATURE_MODE=true
VITE_FEATURE_SONEIUM=true
VITE_FEATURE_TON=true
Expand Down
5 changes: 5 additions & 0 deletions headers/csps/defi/swappers/BobGateway.ts
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'],
}
2 changes: 2 additions & 0 deletions headers/csps/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import { csp as safe } from './defi/safe'
import { csp as zeroX } from './defi/swappers/0x'
import { csp as avnu } from './defi/swappers/Avnu'
import { csp as bebop } from './defi/swappers/Bebop'
import { csp as bobGateway } from './defi/swappers/BobGateway'
import { csp as butterSwap } from './defi/swappers/ButterSwap'
import { csp as cowSwap } from './defi/swappers/CowSwap'
import { csp as nearIntents } from './defi/swappers/NearIntents'
Expand Down Expand Up @@ -184,6 +185,7 @@ export const csps = [
safe,
zeroX,
avnu,
bobGateway,
bebop,
cowSwap,
nearIntents,
Expand Down
1 change: 1 addition & 0 deletions packages/public-api/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ export const getServerConfig = (): SwapperConfig => ({
VITE_ACROSS_API_URL: env.ACROSS_API_URL,
VITE_ACROSS_INTEGRATOR_ID: env.ACROSS_INTEGRATOR_ID,
VITE_DEBRIDGE_API_URL: env.DEBRIDGE_API_URL,
VITE_BOB_GATEWAY_AFFILIATE_ID: env.BOB_GATEWAY_AFFILIATE_ID,
})
1 change: 1 addition & 0 deletions packages/public-api/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const envSchema = z.object({
CHAINFLIP_API_KEY: z.string().default(''),
BEBOP_API_KEY: z.string().default(''),
NEAR_INTENTS_API_KEY: z.string().default(''),
BOB_GATEWAY_AFFILIATE_ID: z.string().default(''),
TENDERLY_API_KEY: z.string().default(''),
TENDERLY_ACCOUNT_SLUG: z.string().default(''),
TENDERLY_PROJECT_SLUG: z.string().default(''),
Expand Down
1 change: 1 addition & 0 deletions packages/swapper/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@coral-xyz/anchor": "0.29.0",
"@cowprotocol/app-data": "^2.3.0",
"@defuse-protocol/one-click-sdk-typescript": "^0.1.1-0.2",
"@gobob/bob-sdk": "5.3.2",
"@mysten/sui": "^1.45.2",
"@shapeshiftoss/bitcoinjs-lib": "7.0.0-shapeshift.0",
"@shapeshiftoss/caip": "workspace:^",
Expand Down
9 changes: 9 additions & 0 deletions packages/swapper/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { avnuSwapper } from './swappers/AvnuSwapper/AvnuSwapper'
import { avnuApi } from './swappers/AvnuSwapper/endpoints'
import { bebopSwapper } from './swappers/BebopSwapper/BebopSwapper'
import { bebopApi } from './swappers/BebopSwapper/endpoints'
import { bobGatewaySwapper } from './swappers/BobGatewaySwapper/BobGatewaySwapper'
import { bobGatewayApi } from './swappers/BobGatewaySwapper/endpoints'
import { butterSwap } from './swappers/ButterSwap/ButterSwap'
import { butterSwapApi } from './swappers/ButterSwap/endpoints'
import { cetusSwapper } from './swappers/CetusSwapper/CetusSwapper'
Expand Down Expand Up @@ -116,6 +118,10 @@ export const swappers: Record<SwapperName, (SwapperApi & Swapper) | undefined> =
...debridgeSwapper,
...debridgeApi,
},
[SwapperName.BobGateway]: {
...bobGatewaySwapper,
...bobGatewayApi,
},
[SwapperName.Test]: undefined,
}

Expand All @@ -135,6 +141,7 @@ const DEFAULT_AVNU_SLIPPAGE_DECIMAL_PERCENTAGE = '0.02'
const DEFAULT_STONFI_SLIPPAGE_DECIMAL_PERCENTAGE = '0.01'
// deBridge API off-chain simulation overestimates output on some chains (e.g. SEI ~2.4%), so auto slippage (1%) is insufficient
const DEFAULT_DEBRIDGE_SLIPPAGE_DECIMAL_PERCENTAGE = '0.03'
const DEFAULT_BOB_GATEWAY_SLIPPAGE_DECIMAL_PERCENTAGE = '0.005'

export const getDefaultSlippageDecimalPercentageForSwapper = (
swapperName: SwapperName | undefined,
Expand Down Expand Up @@ -175,6 +182,8 @@ export const getDefaultSlippageDecimalPercentageForSwapper = (
return DEFAULT_AVNU_SLIPPAGE_DECIMAL_PERCENTAGE
case SwapperName.Stonfi:
return DEFAULT_STONFI_SLIPPAGE_DECIMAL_PERCENTAGE
case SwapperName.BobGateway:
return DEFAULT_BOB_GATEWAY_SLIPPAGE_DECIMAL_PERCENTAGE
default:
return assertUnreachable(swapperName)
}
Expand Down
1 change: 1 addition & 0 deletions packages/swapper/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './cowswap-utils'
export * from './safe-utils'
export * from './swapper'
export * from './swappers/ArbitrumBridgeSwapper'
export * from './swappers/BobGatewaySwapper'
export * from './swappers/AvnuSwapper'
export * from './swappers/BebopSwapper'
export * from './swappers/CetusSwapper'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { Swapper } from '../../types'
import { executeEvmTransaction } from '../../utils'

export const bobGatewaySwapper: Swapper = {
executeEvmTransaction,
}
163 changes: 163 additions & 0 deletions packages/swapper/src/swappers/BobGatewaySwapper/endpoints.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { Configuration, V1Api } 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 { getTradeQuote } from './swapperApi/getTradeQuote'
import { getTradeRate } from './swapperApi/getTradeRate'
import { BOB_GATEWAY_BASE_URL } from './utils/constants'
import { mapBobGatewayOrderStatusToTxStatus } from './utils/helpers/helpers'

export const bobGatewayApi: SwapperApi = {
getTradeQuote,
getTradeRate,

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 { accountNumber, bobSpecific, sellAsset } = step

if (!bobSpecific?.depositAddress)
throw new Error('[BobGateway] missing depositAddress in step metadata')
if (!bobSpecific?.orderId) throw new Error('[BobGateway] missing orderId in step metadata')

const adapter = assertGetUtxoChainAdapter(sellAsset.chainId)

return adapter.buildSendApiTransaction({
value: step.sellAmountIncludingProtocolFeesCryptoBaseUnit,
xpub,
to: bobSpecific.depositAddress,
accountNumber,
skipToAddressValidation: true,
chainSpecific: {
accountType,
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

if (!bobSpecific?.depositAddress)
throw new Error('[BobGateway] missing depositAddress in step metadata')

const adapter = assertGetUtxoChainAdapter(sellAsset.chainId)
const { fast } = await adapter.getFeeData({
to: bobSpecific.depositAddress,
value: step.sellAmountIncludingProtocolFeesCryptoBaseUnit,
chainSpecific: { pubkey: xpub },
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

if (!bobSpecific?.evmTx) throw new Error('[BobGateway] missing evmTx in step metadata')
if (!bobSpecific?.orderId) throw new Error('[BobGateway] missing orderId in step metadata')

const adapter = assertGetEvmChainAdapter(sellAsset.chainId)
const { to, data, value } = bobSpecific.evmTx

const feeData = await evm.getFees({
adapter,
data: data || '0x',
to,
value,
from,
supportsEIP1559,
})

return adapter.buildCustomApiTx({
accountNumber,
from,
to,
value,
data: data || '0x',
...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

if (!bobSpecific?.evmTx) throw new Error('[BobGateway] missing evmTx in step metadata')

const adapter = assertGetEvmChainAdapter(sellAsset.chainId)
const { to, data, value } = bobSpecific.evmTx

const { networkFeeCryptoBaseUnit } = await evm.getFees({
adapter,
data: data || '0x',
to,
value,
from,
supportsEIP1559,
})

return networkFeeCryptoBaseUnit
},

checkTradeStatus: async ({ swap }) => {
const orderId = swap?.metadata.bobSpecific?.orderId
if (!orderId) throw new Error('[BobGateway] orderId is required for status check')

const api = new V1Api(new Configuration({ basePath: BOB_GATEWAY_BASE_URL }))

let orderInfo
try {
orderInfo = await api.getOrder({ id: orderId })
} catch {
return {
buyTxHash: undefined,
status: TxStatus.Unknown,
message: 'Waiting for deposit...',
}
}
Comment thread
kaladinlight marked this conversation as resolved.

const status = mapBobGatewayOrderStatusToTxStatus(orderInfo.status)
const buyTxHash = orderInfo.dstInfo.txHash ?? undefined

return {
buyTxHash,
status,
message: undefined,
}
},
}
3 changes: 3 additions & 0 deletions packages/swapper/src/swappers/BobGatewaySwapper/index.ts
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'
Loading
Loading