Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
41 changes: 41 additions & 0 deletions src/integration/blockchain/spark/spark-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@ export interface SparkTransaction {
fee?: number;
}

export enum SparkTransferDirection {
INCOMING = 'INCOMING',
OUTGOING = 'OUTGOING',
}

export interface SparkTransfer {
id: string;
amountSats: number;
status: string;
direction: SparkTransferDirection;
senderSparkAddress?: string;
receiverSparkAddress?: string;
createdTime?: Date;
updatedTime?: Date;
}

export interface SparkNodeInfo {
version: string;
testnet: boolean;
Expand Down Expand Up @@ -87,6 +103,31 @@ export class SparkClient extends BlockchainClient {
};
}

async getTransfers(limit = 100, offset = 0): Promise<SparkTransfer[]> {
const wallet = await this.wallet;
const result = await wallet.getTransfers(limit, offset);

return result.transfers.map((t) => ({
id: t.id,
amountSats: t.totalValue,
status: t.status,
direction: t.transferDirection as SparkTransferDirection,
senderSparkAddress: t.senderIdentityPublicKey,
receiverSparkAddress: t.receiverIdentityPublicKey,
createdTime: t.createdTime,
updatedTime: t.updatedTime,
}));
}

async getIncomingTransfers(limit = 100, offset = 0): Promise<SparkTransfer[]> {
const transfers = await this.getTransfers(limit, offset);

// Filter only completed incoming transfers
return transfers.filter(
(t) => t.status === 'TRANSFER_STATUS_COMPLETED' && t.direction === SparkTransferDirection.INCOMING,
);
}

// --- FEE METHODS (always 0 for Spark L2) --- //

async getNativeFee(): Promise<number> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export class BlockchainAdapter implements LiquidityBalanceIntegration {
break;

case Blockchain.LIGHTNING:
case Blockchain.SPARK:
case Blockchain.FIRO:
case Blockchain.MONERO:
await this.updateCoinOnlyBalance(assets);
Expand Down
6 changes: 6 additions & 0 deletions src/subdomains/supporting/dex/dex.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { DexOptimismService } from './services/dex-optimism.service';
import { DexPolygonService } from './services/dex-polygon.service';
import { DexSepoliaService } from './services/dex-sepolia.service';
import { DexSolanaService } from './services/dex-solana.service';
import { DexSparkService } from './services/dex-spark.service';
import { DexTronService } from './services/dex-tron.service';
import { DexZanoService } from './services/dex-zano.service';
import { DexService } from './services/dex.service';
Expand Down Expand Up @@ -60,6 +61,7 @@ import { SepoliaCoinStrategy as SepoliaCoinStrategyCL } from './strategies/check
import { SepoliaTokenStrategy as SepoliaTokenStrategyCL } from './strategies/check-liquidity/impl/sepolia-token.strategy';
import { SolanaCoinStrategy as SolanaCoinStrategyCL } from './strategies/check-liquidity/impl/solana-coin.strategy';
import { SolanaTokenStrategy as SolanaTokenStrategyCL } from './strategies/check-liquidity/impl/solana-token.strategy';
import { SparkStrategy as SparkStrategyCL } from './strategies/check-liquidity/impl/spark.strategy';
import { TronCoinStrategy as TronCoinStrategyCL } from './strategies/check-liquidity/impl/tron-coin.strategy';
import { TronTokenStrategy as TronTokenStrategyCL } from './strategies/check-liquidity/impl/tron-token.strategy';
import { ZanoCoinStrategy as ZanoCoinStrategyCL } from './strategies/check-liquidity/impl/zano-coin.strategy';
Expand Down Expand Up @@ -95,6 +97,7 @@ import { SepoliaCoinStrategy as SepoliaCoinStrategyPL } from './strategies/purch
import { SepoliaTokenStrategy as SepoliaTokenStrategyPL } from './strategies/purchase-liquidity/impl/sepolia-token.strategy';
import { SolanaCoinStrategy as SolanaCoinStrategyPL } from './strategies/purchase-liquidity/impl/solana-coin.strategy';
import { SolanaTokenStrategy as SolanaTokenStrategyPL } from './strategies/purchase-liquidity/impl/solana-token.strategy';
import { SparkStrategy as SparkStrategyPL } from './strategies/purchase-liquidity/impl/spark.strategy';
import { TronCoinStrategy as TronCoinStrategyPL } from './strategies/purchase-liquidity/impl/tron-coin.strategy';
import { TronTokenStrategy as TronTokenStrategyPL } from './strategies/purchase-liquidity/impl/tron-token.strategy';
import { ZanoCoinStrategy as ZanoCoinStrategyPL } from './strategies/purchase-liquidity/impl/zano-coin.strategy';
Expand Down Expand Up @@ -175,6 +178,7 @@ import { ZanoStrategy as ZanoStrategyS } from './strategies/supplementary/impl/z
DexCitreaService,
DexCitreaTestnetService,
DexLightningService,
DexSparkService,
DexFiroService,
DexMoneroService,
DexZanoService,
Expand All @@ -193,6 +197,7 @@ import { ZanoStrategy as ZanoStrategyS } from './strategies/supplementary/impl/z
BitcoinStrategyCL,
BitcoinTestnet4StrategyCL,
LightningStrategyCL,
SparkStrategyCL,
FiroCoinStrategyCL,
MoneroStrategyCL,
ZanoCoinStrategyCL,
Expand Down Expand Up @@ -227,6 +232,7 @@ import { ZanoStrategy as ZanoStrategyS } from './strategies/supplementary/impl/z
BitcoinTestnet4StrategyPL,
FiroStrategyPL,
MoneroStrategyPL,
SparkStrategyPL,
ZanoCoinStrategyPL,
ZanoTokenStrategyPL,
ArbitrumCoinStrategyPL,
Expand Down
35 changes: 35 additions & 0 deletions src/subdomains/supporting/dex/services/dex-spark.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Injectable } from '@nestjs/common';
import { Blockchain } from 'src/integration/blockchain/shared/enums/blockchain.enum';
import { SparkClient } from 'src/integration/blockchain/spark/spark-client';
import { SparkService } from 'src/integration/blockchain/spark/spark.service';
import { Util } from 'src/shared/utils/util';
import { LiquidityOrder } from '../entities/liquidity-order.entity';
import { LiquidityOrderRepository } from '../repositories/liquidity-order.repository';

@Injectable()
export class DexSparkService {
private readonly sparkClient: SparkClient;

constructor(
private readonly liquidityOrderRepo: LiquidityOrderRepository,
sparkService: SparkService,
) {
this.sparkClient = sparkService.getDefaultClient();
}

async checkAvailableTargetLiquidity(inputAmount: number): Promise<[number, number]> {
const pendingAmount = await this.getPendingAmount();
const availableAmount = await this.sparkClient.getNativeCoinBalance();

return [inputAmount, availableAmount - pendingAmount];
}

private async getPendingAmount(): Promise<number> {
const pendingOrders = await this.liquidityOrderRepo.findBy({
isComplete: false,
targetAsset: { dexName: 'BTC', blockchain: Blockchain.SPARK },
});

return Util.sumObjValue<LiquidityOrder>(pendingOrders, 'estimatedTargetAmount');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Injectable } from '@nestjs/common';
import { Blockchain } from 'src/integration/blockchain/shared/enums/blockchain.enum';
import { Asset, AssetCategory, AssetType } from 'src/shared/models/asset/asset.entity';
import { AssetService } from 'src/shared/models/asset/asset.service';
import { CheckLiquidityRequest, CheckLiquidityResult } from '../../../interfaces';
import { DexSparkService } from '../../../services/dex-spark.service';
import { CheckLiquidityUtil } from '../utils/check-liquidity.util';
import { CheckLiquidityStrategy } from './base/check-liquidity.strategy';

@Injectable()
export class SparkStrategy extends CheckLiquidityStrategy {
constructor(
private readonly assetService: AssetService,
private readonly dexSparkService: DexSparkService,
) {
super();
}

get blockchain(): Blockchain {
return Blockchain.SPARK;
}

get assetType(): AssetType {
return undefined;
}

get assetCategory(): AssetCategory {
return undefined;
}

async checkLiquidity(request: CheckLiquidityRequest): Promise<CheckLiquidityResult> {
const { context, correlationId, referenceAsset, referenceAmount: bitcoinAmount } = request;

if (referenceAsset.dexName === 'BTC') {
const [targetAmount, availableAmount] = await this.dexSparkService.checkAvailableTargetLiquidity(bitcoinAmount);

return CheckLiquidityUtil.createNonPurchasableCheckLiquidityResult(
request,
targetAmount,
availableAmount,
await this.feeAsset(),
);
}

throw new Error(
`Only native coin reference is supported by Spark CheckLiquidity strategy. Provided reference asset: ${referenceAsset.dexName} Context: ${context}. CorrelationID: ${correlationId}`,
);
}

protected getFeeAsset(): Promise<Asset> {
return this.assetService.getSparkCoin();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Injectable } from '@nestjs/common';
import { Blockchain } from 'src/integration/blockchain/shared/enums/blockchain.enum';
import { Asset, AssetCategory, AssetType } from 'src/shared/models/asset/asset.entity';
import { DfxLogger } from 'src/shared/services/dfx-logger';
import { NoPurchaseStrategy } from './base/no-purchase.strategy';

@Injectable()
export class SparkStrategy extends NoPurchaseStrategy {
protected readonly logger = new DfxLogger(SparkStrategy);

get blockchain(): Blockchain {
return Blockchain.SPARK;
}

get assetType(): AssetType {
return undefined;
}

get assetCategory(): AssetCategory {
return undefined;
}

get dexName(): string {
return undefined;
}

protected getFeeAsset(): Promise<Asset> {
return this.assetService.getSparkCoin();
}
}
Loading