diff --git a/src/config/config.ts b/src/config/config.ts index 70907aba4e..a231025fe1 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -889,6 +889,10 @@ export class Configuration { }, certificate: process.env.LIGHTNING_API_CERTIFICATE?.split('
').join('\n'), }, + boltz: { + apiUrl: process.env.BOLTZ_API_URL, + seed: process.env.BOLTZ_SEED, + }, spark: { sparkWalletSeed: process.env.SPARK_WALLET_SEED, }, diff --git a/src/integration/blockchain/blockchain.module.ts b/src/integration/blockchain/blockchain.module.ts index 34e0ca105a..25840d13c0 100644 --- a/src/integration/blockchain/blockchain.module.ts +++ b/src/integration/blockchain/blockchain.module.ts @@ -8,6 +8,7 @@ import { BlockchainApiModule } from './api/blockchain-api.module'; import { ArbitrumModule } from './arbitrum/arbitrum.module'; import { ArweaveModule } from './arweave/arweave.module'; import { BaseModule } from './base/base.module'; +import { BoltzModule } from './boltz/boltz.module'; import { BscModule } from './bsc/bsc.module'; import { CardanoModule } from './cardano/cardano.module'; import { CitreaTestnetModule } from './citrea-testnet/citrea-testnet.module'; @@ -67,6 +68,7 @@ import { ZanoModule } from './zano/zano.module'; CitreaModule, CitreaTestnetModule, ClementineModule, + BoltzModule, RealUnitBlockchainModule, Eip7702DelegationModule, PimlicoPaymasterModule, @@ -99,6 +101,7 @@ import { ZanoModule } from './zano/zano.module'; CitreaModule, CitreaTestnetModule, ClementineModule, + BoltzModule, CryptoService, BlockchainRegistryService, TxValidationService, diff --git a/src/integration/blockchain/boltz/boltz-client.ts b/src/integration/blockchain/boltz/boltz-client.ts new file mode 100644 index 0000000000..aeb81cd261 --- /dev/null +++ b/src/integration/blockchain/boltz/boltz-client.ts @@ -0,0 +1,76 @@ +import { HttpService } from 'src/shared/services/http.service'; +import { + BoltzChainSwapResponse, + BoltzConfig, + BoltzSwapStatusResponse, + ChainPairsResponse, + HelpMeClaimRequest, + HelpMeClaimResponse, +} from './dto/boltz.dto'; + +export * from './dto/boltz.dto'; + +export class BoltzClient { + constructor( + private readonly http: HttpService, + private readonly config: BoltzConfig, + ) {} + + async getChainPairs(): Promise { + return this.get('swap/v2/swap/chain/'); + } + + async getSwapStatus(swapId: string): Promise { + return this.get(`swap/v2/swap/${swapId}`); + } + + /** + * Create a Chain Swap: BTC (onchain) -> cBTC (Citrea onchain) + * For EVM destination chains, only claimAddress is needed (no claimPublicKey). + * refundPublicKey is required for BTC sender side to enable refunds on swap failure. + * preimageHash and pairHash are required by the Boltz API. + */ + async createChainSwap( + preimageHash: string, + claimAddress: string, + userLockAmount: number, + pairHash: string, + referralId: string, + refundPublicKey: string, + ): Promise { + return this.post('swap/v2/swap/chain/', { + from: 'BTC', + to: 'cBTC', + preimageHash, + claimAddress, + userLockAmount, + pairHash, + referralId, + refundPublicKey, + }); + } + + /** + * Request Boltz to claim cBTC on behalf of the user (server-side claiming). + * The preimage proves payment; Boltz uses it to release cBTC to the claim address. + */ + async claimChainSwap(preimage: string, preimageHash: string): Promise { + const body: HelpMeClaimRequest = { preimage, preimageHash }; + + return this.post('claim/help-me-claim', body); + } + + // --- HELPER METHODS --- // + + private url(path: string): string { + return `${this.config.apiUrl}/${path}`; + } + + private get(path: string): Promise { + return this.http.get(this.url(path), { tryCount: 3, retryDelay: 2000 }); + } + + private post(path: string, body: unknown): Promise { + return this.http.post(this.url(path), body, { tryCount: 3, retryDelay: 2000 }); + } +} diff --git a/src/integration/blockchain/boltz/boltz.module.ts b/src/integration/blockchain/boltz/boltz.module.ts new file mode 100644 index 0000000000..0e1d3fd988 --- /dev/null +++ b/src/integration/blockchain/boltz/boltz.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { SharedModule } from 'src/shared/shared.module'; +import { BoltzService } from './boltz.service'; + +@Module({ + imports: [SharedModule], + providers: [BoltzService], + exports: [BoltzService], +}) +export class BoltzModule {} diff --git a/src/integration/blockchain/boltz/boltz.service.ts b/src/integration/blockchain/boltz/boltz.service.ts new file mode 100644 index 0000000000..648e57ce5e --- /dev/null +++ b/src/integration/blockchain/boltz/boltz.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@nestjs/common'; +import { GetConfig } from 'src/config/config'; +import { HttpService } from 'src/shared/services/http.service'; +import { BoltzClient } from './boltz-client'; + +@Injectable() +export class BoltzService { + private readonly client: BoltzClient; + + constructor(http: HttpService) { + const config = GetConfig().blockchain.boltz; + this.client = new BoltzClient(http, config); + } + + getDefaultClient(): BoltzClient { + return this.client; + } +} diff --git a/src/integration/blockchain/boltz/dto/boltz.dto.ts b/src/integration/blockchain/boltz/dto/boltz.dto.ts new file mode 100644 index 0000000000..e4fe938d11 --- /dev/null +++ b/src/integration/blockchain/boltz/dto/boltz.dto.ts @@ -0,0 +1,102 @@ +export interface BoltzConfig { + apiUrl: string; +} + +// Boltz swap lifecycle events (from boltz-backend SwapUpdateEvent enum) +export enum BoltzSwapStatus { + CREATED = 'swap.created', + EXPIRED = 'swap.expired', + + INVOICE_SET = 'invoice.set', + INVOICE_PENDING = 'invoice.pending', + INVOICE_PAID = 'invoice.paid', + INVOICE_SETTLED = 'invoice.settled', + INVOICE_FAILEDTOPAY = 'invoice.failedToPay', + INVOICE_EXPIRED = 'invoice.expired', + + TRANSACTION_MEMPOOL = 'transaction.mempool', + TRANSACTION_CLAIM_PENDING = 'transaction.claim.pending', + TRANSACTION_CLAIMED = 'transaction.claimed', + TRANSACTION_CONFIRMED = 'transaction.confirmed', + TRANSACTION_REFUNDED = 'transaction.refunded', + TRANSACTION_FAILED = 'transaction.failed', + TRANSACTION_LOCKUP_FAILED = 'transaction.lockupFailed', + + TRANSACTION_SERVER_MEMPOOL = 'transaction.server.mempool', + TRANSACTION_SERVER_CONFIRMED = 'transaction.server.confirmed', + + MINERFEE_PAID = 'minerfee.paid', +} + +// Chain Swap final events (BTC onchain -> cBTC onchain) +export const ChainSwapSuccessStatuses = [BoltzSwapStatus.TRANSACTION_CLAIMED]; +export const ChainSwapFailedStatuses = [ + BoltzSwapStatus.EXPIRED, + BoltzSwapStatus.TRANSACTION_FAILED, + BoltzSwapStatus.TRANSACTION_LOCKUP_FAILED, + BoltzSwapStatus.TRANSACTION_REFUNDED, +]; + +export interface ChainSwapDetails { + swapTree: { + claimLeaf: { output: string; version: number }; + refundLeaf: { output: string; version: number }; + }; + lockupAddress: string; + serverPublicKey: string; + timeoutBlockHeight: number; + amount: number; + blindingKey?: string; + refundAddress?: string; + claimAddress?: string; + bip21?: string; +} + +export interface BoltzChainSwapResponse { + id: string; + claimDetails: ChainSwapDetails; + lockupDetails: ChainSwapDetails; +} + +export interface BoltzSwapStatusResponse { + status: BoltzSwapStatus; + failureReason?: string; + failureDetails?: string; + zeroConfRejected?: boolean; + transaction?: { + id: string; + hex?: string; + }; +} + +export interface ChainPairInfo { + hash: string; + rate: number; + limits: { + maximal: number; + minimal: number; + maximalZeroConf: number; + }; + fees: { + percentage: number; + minerFees: { + server: number; + user: { + claim: number; + lockup: number; + }; + }; + }; +} + +// Response: Record> +export type ChainPairsResponse = Record>; + +export interface HelpMeClaimRequest { + preimage: string; + preimageHash: string; +} + +export interface HelpMeClaimResponse { + txHash: string; +} diff --git a/src/subdomains/core/liquidity-management/adapters/actions/boltz.adapter.ts b/src/subdomains/core/liquidity-management/adapters/actions/boltz.adapter.ts new file mode 100644 index 0000000000..cfc4207574 --- /dev/null +++ b/src/subdomains/core/liquidity-management/adapters/actions/boltz.adapter.ts @@ -0,0 +1,362 @@ +import { Injectable } from '@nestjs/common'; +import { secp256k1 } from '@noble/curves/secp256k1'; +import { createHash } from 'crypto'; +import { Config } from 'src/config/config'; +import { BitcoinBasedClient } from 'src/integration/blockchain/bitcoin/node/bitcoin-based-client'; +import { BitcoinFeeService } from 'src/integration/blockchain/bitcoin/services/bitcoin-fee.service'; +import { BitcoinNodeType, BitcoinService } from 'src/integration/blockchain/bitcoin/services/bitcoin.service'; +import { BoltzClient, BoltzSwapStatus, ChainSwapFailedStatuses } from 'src/integration/blockchain/boltz/boltz-client'; +import { BoltzService } from 'src/integration/blockchain/boltz/boltz.service'; +import { CitreaClient } from 'src/integration/blockchain/citrea/citrea-client'; +import { CitreaService } from 'src/integration/blockchain/citrea/citrea.service'; +import { Blockchain } from 'src/integration/blockchain/shared/enums/blockchain.enum'; +import { LightningHelper } from 'src/integration/lightning/lightning-helper'; +import { isAsset } from 'src/shared/models/active'; +import { AssetType } from 'src/shared/models/asset/asset.entity'; +import { AssetService } from 'src/shared/models/asset/asset.service'; +import { DfxLogger } from 'src/shared/services/dfx-logger'; +import { Util } from 'src/shared/utils/util'; +import { LiquidityManagementOrder } from '../../entities/liquidity-management-order.entity'; +import { LiquidityManagementSystem } from '../../enums'; +import { OrderFailedException } from '../../exceptions/order-failed.exception'; +import { OrderNotProcessableException } from '../../exceptions/order-not-processable.exception'; +import { Command, CorrelationId } from '../../interfaces'; +import { LiquidityActionAdapter } from './base/liquidity-action.adapter'; + +const BOLTZ_REFERRAL_ID = 'DFX'; + +export enum BoltzCommands { + DEPOSIT = 'deposit', // BTC onchain -> cBTC onchain +} + +const CORRELATION_PREFIX = { + DEPOSIT: 'boltz:deposit:', +}; + +interface SwapTree { + claimLeaf: { output: string; version: number }; + refundLeaf: { output: string; version: number }; +} + +interface DepositCorrelationData { + step: 'btc_sent' | 'claiming'; + swapId: string; + claimAddress: string; + lockupAddress: string; + userLockAmountSats: number; + claimAmountSats: number; + btcTxId: string; + pairHash: string; + claimTxHash?: string; + // Refund data (required to recover funds if swap fails) + swapTree: SwapTree; + timeoutBlockHeight: number; + serverPublicKey: string; +} + +@Injectable() +export class BoltzAdapter extends LiquidityActionAdapter { + private readonly logger = new DfxLogger(BoltzAdapter); + + protected commands = new Map(); + + private readonly boltzClient: BoltzClient; + private readonly bitcoinClient: BitcoinBasedClient; + private readonly citreaClient: CitreaClient; + + constructor( + boltzService: BoltzService, + bitcoinService: BitcoinService, + citreaService: CitreaService, + private readonly assetService: AssetService, + private readonly bitcoinFeeService: BitcoinFeeService, + ) { + super(LiquidityManagementSystem.BOLTZ); + + this.boltzClient = boltzService.getDefaultClient(); + this.bitcoinClient = bitcoinService.getDefaultClient(BitcoinNodeType.BTC_OUTPUT); + this.citreaClient = citreaService.getDefaultClient(); + + this.commands.set(BoltzCommands.DEPOSIT, this.deposit.bind(this)); + } + + async checkCompletion(order: LiquidityManagementOrder): Promise { + const { + action: { command }, + } = order; + + if (command === BoltzCommands.DEPOSIT) { + return this.checkDepositCompletion(order); + } + + throw new OrderFailedException(`Unknown command: ${command}`); + } + + validateParams(_command: string, _params: Record): boolean { + return true; + } + + //*** COMMANDS ***// + + /** + * Deposit BTC -> cBTC via Boltz Chain Swap. + * 1. Fetch chain pairs to get pairHash + * 2. Generate preimage + preimageHash + * 3. Generate secp256k1 refund key pair + * 4. Create chain swap via API + * 5. Send BTC to the lockup address + * 6. Save all data in correlation ID for later claiming + */ + private async deposit(order: LiquidityManagementOrder): Promise { + const { + minAmount, + maxAmount, + pipeline: { + rule: { targetAsset: citreaAsset }, + }, + } = order; + + // Validate asset is cBTC on Citrea + if (citreaAsset.type !== AssetType.COIN || citreaAsset.blockchain !== Blockchain.CITREA) { + throw new OrderNotProcessableException('Boltz deposit only supports cBTC (native coin) on Citrea'); + } + + // check BTC balance + const btcBalance = await this.bitcoinClient.getNativeCoinBalance(); + if (btcBalance < minAmount) { + throw new OrderNotProcessableException( + `Not enough BTC (balance: ${btcBalance}, min. requested: ${minAmount}, max. requested: ${maxAmount})`, + ); + } + const amount = Math.min(btcBalance, maxAmount); + + const claimAddress = this.citreaClient.walletAddress; + const amountSats = LightningHelper.btcToSat(amount); + + // Step 1: Get chain pairs to extract pairHash + const pairs = await this.boltzClient.getChainPairs(); + const pairInfo = pairs['BTC']?.['cBTC']; + if (!pairInfo) { + throw new OrderNotProcessableException('BTC -> cBTC chain pair not available on Boltz'); + } + const pairHash = pairInfo.hash; + + // Validate amount against Boltz pair limits + if (amountSats < pairInfo.limits.minimal) { + throw new OrderNotProcessableException( + `Amount ${amountSats} sats below Boltz minimum of ${pairInfo.limits.minimal} sats`, + ); + } + if (amountSats > pairInfo.limits.maximal) { + throw new OrderNotProcessableException( + `Amount ${amountSats} sats above Boltz maximum of ${pairInfo.limits.maximal} sats`, + ); + } + + // Step 2: Derive preimage deterministically from order.id + const { preimageHash } = this.getPreimageData(order.id); + + // Step 3: Derive secp256k1 key pair for BTC refund (deterministic from seed + orderId) + const refundPublicKey = this.getRefundPublicKey(order.id); + + // Step 4: Create chain swap via Boltz API + const swap = await this.boltzClient.createChainSwap( + preimageHash, + claimAddress, + amountSats, + pairHash, + BOLTZ_REFERRAL_ID, + refundPublicKey, + ); + + this.logger.info( + `Boltz chain swap created: id=${swap.id}, lockupAmount=${swap.lockupDetails.amount} sats, ` + + `claimAmount=${swap.claimDetails.amount} sats, lockup=${swap.lockupDetails.lockupAddress}, ` + + `claim=${claimAddress}, timeoutBlockHeight=${swap.lockupDetails.timeoutBlockHeight}`, + ); + + // Step 5: Send BTC to the lockup address + const lockupAmountBtc = LightningHelper.satToBtc(swap.lockupDetails.amount); + const btcTxId = await this.sendBtcToAddress(swap.lockupDetails.lockupAddress, lockupAmountBtc); + + this.logger.info(`BTC sent to lockup address: txId=${btcTxId}, amount=${lockupAmountBtc} BTC`); + + // Set order tracking fields + const btcAsset = await this.assetService.getBtcCoin(); + + order.inputAmount = lockupAmountBtc; + order.inputAsset = btcAsset.name; + order.outputAsset = citreaAsset.name; + + // Step 6: Save correlation data + const correlationData: DepositCorrelationData = { + step: 'btc_sent', + swapId: swap.id, + claimAddress, + lockupAddress: swap.lockupDetails.lockupAddress, + userLockAmountSats: amountSats, + claimAmountSats: swap.claimDetails.amount, + btcTxId, + pairHash, + swapTree: swap.lockupDetails.swapTree, + timeoutBlockHeight: swap.lockupDetails.timeoutBlockHeight, + serverPublicKey: swap.lockupDetails.serverPublicKey, + }; + + return `${CORRELATION_PREFIX.DEPOSIT}${this.encodeCorrelation(correlationData)}`; + } + + //*** COMPLETION CHECKS ***// + + private async checkDepositCompletion(order: LiquidityManagementOrder): Promise { + const { + pipeline: { + rule: { target: asset }, + }, + } = order; + + if (!isAsset(asset)) { + throw new Error('BoltzAdapter.checkDepositCompletion(...) supports only Asset instances as an input.'); + } + + try { + const correlationData = this.decodeCorrelation(order.correlationId.replace(CORRELATION_PREFIX.DEPOSIT, '')); + + const status = await this.boltzClient.getSwapStatus(correlationData.swapId); + + this.logger.verbose( + `Boltz swap ${correlationData.swapId}: step=${correlationData.step}, status=${status.status}`, + ); + + if (ChainSwapFailedStatuses.includes(status.status)) { + const details = [status.failureReason, status.failureDetails].filter(Boolean).join(' - '); + throw new OrderFailedException(`Boltz swap failed: ${status.status}${details ? ` (${details})` : ''}`); + } + + switch (correlationData.step) { + case 'btc_sent': + return await this.handleBtcSentStep(order, correlationData, status.status); + + case 'claiming': + return await this.handleClaimingStep(order, correlationData, status.status); + + default: + throw new OrderFailedException(`Unknown step: ${correlationData.step}`); + } + } catch (e) { + throw e instanceof OrderFailedException ? e : new OrderFailedException(e.message); + } + } + + /** + * Step: btc_sent — waiting for Boltz server to confirm the lockup and prepare cBTC. + * When server confirms, call helpMeClaim to trigger claiming. + */ + private async handleBtcSentStep( + order: LiquidityManagementOrder, + correlationData: DepositCorrelationData, + status: BoltzSwapStatus, + ): Promise { + if (status === BoltzSwapStatus.TRANSACTION_SERVER_CONFIRMED) { + // Server has confirmed the lockup — request claiming (skip if already called) + if (!correlationData.claimTxHash) { + // Derive preimage from order.id + const { preimage, preimageHash } = this.getPreimageData(order.id); + + const claimResult = await this.boltzClient.claimChainSwap(preimage, `0x${preimageHash}`); + + this.logger.info(`Boltz swap ${correlationData.swapId}: claim called, claimTxHash=${claimResult.txHash}`); + + correlationData.claimTxHash = claimResult.txHash; + } + + // Advance to claiming step + correlationData.step = 'claiming'; + order.correlationId = `${CORRELATION_PREFIX.DEPOSIT}${this.encodeCorrelation(correlationData)}`; + + return false; + } + + // Still waiting for server confirmation + return false; + } + + /** + * Step: claiming — waiting for the claim transaction to be confirmed. + */ + private async handleClaimingStep( + order: LiquidityManagementOrder, + correlationData: DepositCorrelationData, + status: BoltzSwapStatus, + ): Promise { + if (status === BoltzSwapStatus.TRANSACTION_CLAIMED) { + // Use claimAmountSats (cBTC received after Boltz fees), not userLockAmountSats (BTC sent) + order.outputAmount = LightningHelper.satToBtc(correlationData.claimAmountSats); + + this.logger.info(`Boltz swap ${correlationData.swapId}: claimed successfully, output=${order.outputAmount} cBTC`); + + return true; + } + + // Still waiting for claim confirmation + return false; + } + + //*** HELPERS ***// + + private async sendBtcToAddress(address: string, amount: number): Promise { + if (!address || address.length < 26 || address.length > 90) { + throw new OrderFailedException(`Invalid Bitcoin address format: ${address}`); + } + + const feeRate = await this.bitcoinFeeService.getRecommendedFeeRate(); + const txId = await this.bitcoinClient.sendMany([{ addressTo: address, amount }], feeRate); + + if (!txId) { + throw new OrderFailedException(`Failed to send BTC to address ${address}`); + } + + return txId; + } + + /** + * Derive preimage deterministically from seed + orderId. + */ + private getPreimageData(orderId: number): { preimage: string; preimageHash: string } { + const seed = Config.blockchain.boltz.seed; + if (!seed) { + throw new OrderNotProcessableException('BOLTZ_SEED not configured'); + } + + const preimage = Util.createHmac(seed, `boltz:preimage:${orderId}`); + const preimageHash = createHash('sha256').update(Buffer.from(preimage, 'hex')).digest('hex'); + + return { preimage, preimageHash }; + } + + /** + * Derive refund private key deterministically from seed + orderId. + * This allows recovery without storing the private key in the database. + */ + private getRefundPrivateKey(orderId: number): string { + const seed = Config.blockchain.boltz.seed; + if (!seed) { + throw new OrderNotProcessableException('BOLTZ_SEED not configured'); + } + + return Util.createHmac(seed, `boltz:refund:${orderId}`); + } + + private getRefundPublicKey(orderId: number): string { + const privateKey = this.getRefundPrivateKey(orderId); + return Buffer.from(secp256k1.getPublicKey(privateKey, true)).toString('hex'); + } + + private encodeCorrelation(data: DepositCorrelationData): string { + return Buffer.from(JSON.stringify(data)).toString('base64'); + } + + private decodeCorrelation(encoded: string): DepositCorrelationData { + return JSON.parse(Buffer.from(encoded, 'base64').toString('utf-8')); + } +} diff --git a/src/subdomains/core/liquidity-management/enums/index.ts b/src/subdomains/core/liquidity-management/enums/index.ts index 5bd5c9cf74..8a7b0af4bd 100644 --- a/src/subdomains/core/liquidity-management/enums/index.ts +++ b/src/subdomains/core/liquidity-management/enums/index.ts @@ -17,6 +17,7 @@ export enum LiquidityManagementSystem { BASE_L2_BRIDGE = 'BaseL2Bridge', LAYERZERO_BRIDGE = 'LayerZeroBridge', CLEMENTINE_BRIDGE = 'ClementineBridge', + BOLTZ = 'Boltz', LIQUIDITY_PIPELINE = 'LiquidityPipeline', FRANKENCOIN = 'Frankencoin', DEURO = 'dEURO', @@ -70,4 +71,5 @@ export const LiquidityManagementBridges = [ LiquidityManagementSystem.OPTIMISM_L2_BRIDGE, LiquidityManagementSystem.LAYERZERO_BRIDGE, LiquidityManagementSystem.CLEMENTINE_BRIDGE, + LiquidityManagementSystem.BOLTZ, ]; diff --git a/src/subdomains/core/liquidity-management/factories/liquidity-action-integration.factory.ts b/src/subdomains/core/liquidity-management/factories/liquidity-action-integration.factory.ts index bab3922616..cd7b6587a8 100644 --- a/src/subdomains/core/liquidity-management/factories/liquidity-action-integration.factory.ts +++ b/src/subdomains/core/liquidity-management/factories/liquidity-action-integration.factory.ts @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'; import { ArbitrumL2BridgeAdapter } from '../adapters/actions/arbitrum-l2-bridge.adapter'; import { BaseL2BridgeAdapter } from '../adapters/actions/base-l2-bridge.adapter'; import { BinanceAdapter } from '../adapters/actions/binance.adapter'; +import { BoltzAdapter } from '../adapters/actions/boltz.adapter'; import { ClementineBridgeAdapter } from '../adapters/actions/clementine-bridge.adapter'; import { DEuroAdapter } from '../adapters/actions/deuro.adapter'; import { DfxDexAdapter } from '../adapters/actions/dfx-dex.adapter'; @@ -31,6 +32,7 @@ export class LiquidityActionIntegrationFactory { readonly baseL2BridgeAdapter: BaseL2BridgeAdapter, readonly layerZeroBridgeAdapter: LayerZeroBridgeAdapter, readonly clementineBridgeAdapter: ClementineBridgeAdapter, + readonly boltzAdapter: BoltzAdapter, readonly krakenAdapter: KrakenAdapter, readonly binanceAdapter: BinanceAdapter, readonly mexcAdapter: MexcAdapter, @@ -48,6 +50,7 @@ export class LiquidityActionIntegrationFactory { this.adapters.set(LiquidityManagementSystem.BASE_L2_BRIDGE, baseL2BridgeAdapter); this.adapters.set(LiquidityManagementSystem.LAYERZERO_BRIDGE, layerZeroBridgeAdapter); this.adapters.set(LiquidityManagementSystem.CLEMENTINE_BRIDGE, clementineBridgeAdapter); + this.adapters.set(LiquidityManagementSystem.BOLTZ, boltzAdapter); this.adapters.set(LiquidityManagementSystem.KRAKEN, krakenAdapter); this.adapters.set(LiquidityManagementSystem.BINANCE, binanceAdapter); this.adapters.set(LiquidityManagementSystem.MEXC, mexcAdapter); diff --git a/src/subdomains/core/liquidity-management/liquidity-management.module.ts b/src/subdomains/core/liquidity-management/liquidity-management.module.ts index 3773d7e876..13b11f53cc 100644 --- a/src/subdomains/core/liquidity-management/liquidity-management.module.ts +++ b/src/subdomains/core/liquidity-management/liquidity-management.module.ts @@ -13,6 +13,7 @@ import { PricingModule } from 'src/subdomains/supporting/pricing/pricing.module' import { ArbitrumL2BridgeAdapter } from './adapters/actions/arbitrum-l2-bridge.adapter'; import { BaseL2BridgeAdapter } from './adapters/actions/base-l2-bridge.adapter'; import { BinanceAdapter } from './adapters/actions/binance.adapter'; +import { BoltzAdapter } from './adapters/actions/boltz.adapter'; import { ClementineBridgeAdapter } from './adapters/actions/clementine-bridge.adapter'; import { LayerZeroBridgeAdapter } from './adapters/actions/layerzero-bridge.adapter'; import { DEuroAdapter } from './adapters/actions/deuro.adapter'; @@ -100,6 +101,7 @@ import { LiquidityManagementService } from './services/liquidity-management.serv BaseL2BridgeAdapter, LayerZeroBridgeAdapter, ClementineBridgeAdapter, + BoltzAdapter, BinanceAdapter, MexcAdapter, ScryptAdapter,